From 688d4d44d937bc658f628cd97a95bd636df9e412 Mon Sep 17 00:00:00 2001 From: reionwong Date: Sun, 30 Aug 2026 20:25:25 -0400 Subject: [PATCH] refactor(qt-plugins): remove X11 integrations --- README.md | 2 +- debian/control | 4 - platformtheme/CMakeLists.txt | 8 - platformtheme/platformtheme.cpp | 8 - platformtheme/platformtheme.h | 3 - platformtheme/x11integration.cpp | 136 ---------- platformtheme/x11integration.h | 47 ---- widgetstyle/CMakeLists.txt | 10 - widgetstyle/basestyle.cpp | 27 +- widgetstyle/basestyle.h | 5 - widgetstyle/blurhelper.cpp | 170 ------------ widgetstyle/blurhelper.h | 59 ----- widgetstyle/boxshadowrenderer.cpp | 348 ------------------------- widgetstyle/boxshadowrenderer.h | 97 ------- widgetstyle/shadowhelper.cpp | 414 ------------------------------ widgetstyle/shadowhelper.h | 148 ----------- widgetstyle/tileset.cpp | 183 ------------- widgetstyle/tileset.h | 121 --------- x11utils.h | 21 -- 19 files changed, 2 insertions(+), 1809 deletions(-) delete mode 100644 platformtheme/x11integration.cpp delete mode 100644 platformtheme/x11integration.h delete mode 100644 widgetstyle/blurhelper.cpp delete mode 100644 widgetstyle/blurhelper.h delete mode 100644 widgetstyle/boxshadowrenderer.cpp delete mode 100644 widgetstyle/boxshadowrenderer.h delete mode 100644 widgetstyle/shadowhelper.cpp delete mode 100644 widgetstyle/shadowhelper.h delete mode 100644 widgetstyle/tileset.cpp delete mode 100644 widgetstyle/tileset.h delete mode 100644 x11utils.h diff --git a/README.md b/README.md index b499af5..f8f24a4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Unify Qt application style of CutefishOS. ## Dependencies -`sudo pacman -S gcc extra-cmake-modules qt5-base qt5-tools qt5-x11extras libqtxdg libdbusmenu-qt5 libxcb` +`sudo pacman -S gcc extra-cmake-modules qt6-base qt6-tools libqtxdg` ## Build diff --git a/debian/control b/debian/control index c660bc4..ce00e6a 100644 --- a/debian/control +++ b/debian/control @@ -5,12 +5,8 @@ Maintainer: CutefishOS Build-Depends: cmake, debhelper (>= 9), extra-cmake-modules, - libkf6windowsystem-dev, libqt6xdg-dev, pkg-config, - libxcb-shape0-dev, - libxcb-icccm4-dev, - libxcb1-dev, qt6-base-dev, qt6-base-private-dev, qt6-declarative-dev diff --git a/platformtheme/CMakeLists.txt b/platformtheme/CMakeLists.txt index 4805d05..1603194 100644 --- a/platformtheme/CMakeLists.txt +++ b/platformtheme/CMakeLists.txt @@ -10,7 +10,6 @@ find_package(Qt6Gui CONFIG QUIET COMPONENTS Private) if(NOT TARGET Qt6::GuiPrivate) find_package(Qt6 REQUIRED COMPONENTS GuiPrivate) endif() -find_package(KF6WindowSystem REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(Qt6XdgIconLoader REQUIRED IMPORTED_TARGET Qt6XdgIconLoader) find_path(QT6XDGICONLOADER_PRIVATE_INCLUDE_DIR @@ -20,9 +19,6 @@ find_path(QT6XDGICONLOADER_PRIVATE_INCLUDE_DIR REQUIRED ) -# xcb-ewmh was never used by this plugin and is no longer pulled in by Qt. -pkg_check_modules(XCB REQUIRED IMPORTED_TARGET xcb x11) - set (SRCS main.cpp platformtheme.h @@ -31,8 +27,6 @@ set (SRCS hintsettings.cpp systemtrayicon.h systemtrayicon.cpp - x11integration.h - x11integration.cpp statusnotifier/dbustypes.h statusnotifier/dbustypes.cpp statusnotifier/statusnotifieritem.h @@ -63,8 +57,6 @@ target_link_libraries(cutefishplatformtheme PRIVATE Qt6::DBus PkgConfig::Qt6XdgIconLoader - KF6::WindowSystem - PkgConfig::XCB ) target_include_directories(cutefishplatformtheme PRIVATE "${QT6XDGICONLOADER_PRIVATE_INCLUDE_DIR}") diff --git a/platformtheme/platformtheme.cpp b/platformtheme/platformtheme.cpp index 0e3a62e..dea449c 100644 --- a/platformtheme/platformtheme.cpp +++ b/platformtheme/platformtheme.cpp @@ -1,5 +1,4 @@ #include "platformtheme.h" -#include "x11integration.h" #include #include @@ -17,8 +16,6 @@ #include #include -#include - extern void updateXdgIconSystemTheme(); void onDarkModeChanged() @@ -40,11 +37,6 @@ PlatformTheme::PlatformTheme() { // qApp->setProperty("_hints_settings_object", (quintptr)m_hints); - if (KWindowSystem::isPlatformX11()) { - m_x11Integration.reset(new X11Integration()); - m_x11Integration->init(); - } - connect(m_hints, &HintsSettings::systemFontChanged, this, &PlatformTheme::onFontChanged); connect(m_hints, &HintsSettings::systemFontPointSizeChanged, this, &PlatformTheme::onFontChanged); connect(m_hints, &HintsSettings::iconThemeChanged, this, &PlatformTheme::onIconThemeChanged); diff --git a/platformtheme/platformtheme.h b/platformtheme/platformtheme.h index e9e7216..02efb75 100644 --- a/platformtheme/platformtheme.h +++ b/platformtheme/platformtheme.h @@ -16,8 +16,6 @@ class QIconEngine; class QWindow; -class X11Integration; - class PlatformTheme : public QObject, public QGenericUnixTheme { Q_OBJECT @@ -47,7 +45,6 @@ private: private: HintsSettings *m_hints; - QScopedPointer m_x11Integration; }; #endif // PLATFORMTHEME_H diff --git a/platformtheme/x11integration.cpp b/platformtheme/x11integration.cpp deleted file mode 100644 index fc8b5df..0000000 --- a/platformtheme/x11integration.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* This file is part of the KDE libraries - * Copyright 2015 Martin Gräßlin - * Copyright 2016 Marco Martin - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License or ( at - * your option ) version 3 or, at the discretion of KDE e.V. ( which shall - * act as a proxy as in section 14 of the GPLv3 ), any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "x11integration.h" -#include "x11utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -static const char s_schemePropertyName[] = "KDE_COLOR_SCHEME_PATH"; -static const QByteArray s_blurBehindPropertyName = QByteArrayLiteral("ENABLE_BLUR_BEHIND_HINT"); -static const QByteArray s_blurRegionPropertyName = QByteArrayLiteral("BLUR_REGION"); - -X11Integration::X11Integration() - : QObject() -{ -} - -X11Integration::~X11Integration() = default; - -void X11Integration::init() -{ - QCoreApplication::instance()->installEventFilter(this); -} - -bool X11Integration::eventFilter(QObject *watched, QEvent *event) -{ - //the drag and drop window should NOT be a tooltip - //https://bugreports.qt.io/browse/QTBUG-52560 - if (event->type() == QEvent::Show && watched->inherits("QShapedPixmapWindow")) { - //static cast should be safe there - QWindow *w = static_cast(watched); - NETWinInfo info(qGuiApp->nativeInterface()->connection(), w->winId(), Cutefish::X11::rootWindow(), NET::WMWindowType, NET::Properties2()); - info.setWindowType(NET::DNDIcon); - // TODO: does this flash the xcb connection? - } - - // if (event->type() == QEvent::PlatformSurface) { - // if (QWindow *w = qobject_cast(watched)) { - // QPlatformSurfaceEvent *pe = static_cast(event); - // if (!w->flags().testFlag(Qt::ForeignWindow)) { - // if (pe->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { - // const auto blurBehindProperty = w->property(s_blurBehindPropertyName.constData()); - // if (blurBehindProperty.isValid()) { - // KWindowEffects::enableBlurBehind(w->winId(), blurBehindProperty.toBool()); - // } - // installDesktopFileName(w); - // } - // } - // } - // } - - // if (event->type() == QEvent::ApplicationPaletteChange) { - // const auto topLevelWindows = QGuiApplication::topLevelWindows(); - // for (QWindow *w : topLevelWindows) { - // installColorScheme(w); - // } - // } - - return false; -} - -void X11Integration::installDesktopFileName(QWindow *w) -{ - if (!w->isTopLevel()) { - return; - } - - QString desktopFileName = QGuiApplication::desktopFileName(); - if (desktopFileName.isEmpty()) { - return; - } - // handle apps which set the desktopFileName property with filename suffix, - // due to unclear API dox (https://bugreports.qt.io/browse/QTBUG-75521) - if (desktopFileName.endsWith(QLatin1String(".desktop"))) { - desktopFileName.chop(8); - } - NETWinInfo info(qGuiApp->nativeInterface()->connection(), w->winId(), Cutefish::X11::rootWindow(), NET::Properties(), NET::Properties2()); - info.setDesktopFileName(desktopFileName.toUtf8().constData()); -} - -void X11Integration::setWindowProperty(QWindow *window, const QByteArray &name, const QByteArray &value) -{ - auto *c = qGuiApp->nativeInterface()->connection(); - - xcb_atom_t atom; - auto it = m_atoms.find(name); - if (it == m_atoms.end()) { - const xcb_intern_atom_cookie_t cookie = xcb_intern_atom(c, false, name.length(), name.constData()); - QScopedPointer reply(xcb_intern_atom_reply(c, cookie, nullptr)); - if (!reply.isNull()) { - atom = reply->atom; - m_atoms[name] = atom; - } else { - return; - } - } else { - atom = *it; - } - - if (value.isEmpty()) { - xcb_delete_property(c, window->winId(), atom); - } else { - xcb_change_property(c, XCB_PROP_MODE_REPLACE, window->winId(), atom, XCB_ATOM_STRING, - 8, value.length(), value.constData()); - } -} diff --git a/platformtheme/x11integration.h b/platformtheme/x11integration.h deleted file mode 100644 index a216789..0000000 --- a/platformtheme/x11integration.h +++ /dev/null @@ -1,47 +0,0 @@ -/* This file is part of the KDE libraries - * Copyright 2015 Martin Gräßlin - * Copyright 2016 Marco Martin - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License or ( at - * your option ) version 3 or, at the discretion of KDE e.V. ( which shall - * act as a proxy as in section 14 of the GPLv3 ), any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#ifndef X11INTEGRATION_H -#define X11INTEGRATION_H - -#include -#include -#include - -class QWindow; - -class X11Integration : public QObject -{ - Q_OBJECT -public: - explicit X11Integration(); - ~X11Integration() override; - void init(); - - void setWindowProperty(QWindow *window, const QByteArray &name, const QByteArray &value); - - bool eventFilter(QObject *watched, QEvent *event) override; - -private: - void installDesktopFileName(QWindow *w); - QHash m_atoms; -}; - -#endif diff --git a/widgetstyle/CMakeLists.txt b/widgetstyle/CMakeLists.txt index 1c39ce2..3a5a78e 100644 --- a/widgetstyle/CMakeLists.txt +++ b/widgetstyle/CMakeLists.txt @@ -16,23 +16,14 @@ if(NOT TARGET Qt6::GuiPrivate) find_package(Qt6 REQUIRED COMPONENTS GuiPrivate) endif() find_package(PkgConfig REQUIRED) -find_package(KF6WindowSystem REQUIRED) set (SRCS - blurhelper.cpp - blurhelper.h pstyleplugin.cpp pstyleplugin.h basestyle.h basestyle.cpp phantomcolor.h phantomcolor.cpp - shadowhelper.h - shadowhelper.cpp - tileset.h - tileset.cpp - boxshadowrenderer.h - boxshadowrenderer.cpp ) add_library(${TARGET} MODULE ${SRCS}) @@ -42,7 +33,6 @@ target_link_libraries(${TARGET} Qt6::Gui Qt6::Widgets Qt6::DBus - KF6::WindowSystem ) find_program(QT_PATHS_EXECUTABLE NAMES qtpaths6 REQUIRED) diff --git a/widgetstyle/basestyle.cpp b/widgetstyle/basestyle.cpp index e3acf70..48c4d69 100644 --- a/widgetstyle/basestyle.cpp +++ b/widgetstyle/basestyle.cpp @@ -22,8 +22,6 @@ #include "basestyle.h" #include "phantomcolor.h" -#include "shadowhelper.h" -#include "blurhelper.h" #include #include @@ -1405,13 +1403,9 @@ BaseStylePrivate::BaseStylePrivate() } BaseStyle::BaseStyle() - : d(new BaseStylePrivate), - m_shadowHelper(new ShadowHelper(this)), - m_blurHelper(new BlurHelper(this)) + : d(new BaseStylePrivate) { setObjectName(QLatin1String("Phantom")); - - m_shadowHelper->setFrameRadius(Phantom::DefaultFrame_Radius); } BaseStyle::~BaseStyle() @@ -1578,11 +1572,6 @@ void BaseStyle::drawPrimitive(PrimitiveElement elem, break; } case PE_PanelTipLabel: { - // force registration of widget - if (widget && widget->window()) { - m_shadowHelper->registerWidget(widget->window(), true); - } - const auto &palette = option->palette; const auto &background = palette.color(QPalette::ToolTipBase); const qreal radius = Phantom::DefaultFrame_Radius; @@ -2168,16 +2157,6 @@ void BaseStyle::drawPrimitive(PrimitiveElement elem, QRectF frameRect = strokedRect(option->rect, 1); painter->drawRoundedRect(frameRect, Phantom::DefaultFrame_Radius, Phantom::DefaultFrame_Radius); - // blur - if (widget && widget->window()) { -// QPainterPath path; -// path.addRoundedRect(option->rect, Phantom::DefaultFrame_Radius, Phantom::DefaultFrame_Radius); -// const_cast(widget)->setMask(path.toFillPolygon().toPolygon()); -// m_blurHelper->update(const_cast(widget)); - - m_blurHelper->enableBlurBehind(const_cast(widget), true, Phantom::DefaultFrame_Radius); - } - painter->restore(); break; } @@ -4483,14 +4462,12 @@ void BaseStyle::polish(QWidget *widget) if (qobject_cast(widget)) { widget->setAttribute(Qt::WA_TranslucentBackground, true); - // m_blurHelper->registerWidget(widget); } if (widget->inherits("QTipLabel") || widget->inherits("QComboBoxPrivateContainer")) { widget->setAttribute(Qt::WA_TranslucentBackground, true); } - m_shadowHelper->registerWidget(widget); } void BaseStyle::unpolish(QWidget *widget) @@ -4512,14 +4489,12 @@ void BaseStyle::unpolish(QWidget *widget) if (qobject_cast(widget)) { widget->setAttribute(Qt::WA_TranslucentBackground, false); - // m_blurHelper->unregisterWidget(widget); } if (widget->inherits("QTipLabel")) { widget->setAttribute(Qt::WA_TranslucentBackground, false); } - m_shadowHelper->unregisterWidget(widget); } bool BaseStyle::isDarkMode() const diff --git a/widgetstyle/basestyle.h b/widgetstyle/basestyle.h index 42d0722..adebd05 100644 --- a/widgetstyle/basestyle.h +++ b/widgetstyle/basestyle.h @@ -26,8 +26,6 @@ #include class BaseStylePrivate; -class ShadowHelper; -class BlurHelper; class BaseStyle : public QCommonStyle { Q_OBJECT @@ -106,9 +104,6 @@ protected: BaseStylePrivate* d; -private: - ShadowHelper *m_shadowHelper; - BlurHelper *m_blurHelper; }; #endif diff --git a/widgetstyle/blurhelper.cpp b/widgetstyle/blurhelper.cpp deleted file mode 100644 index c3de7c7..0000000 --- a/widgetstyle/blurhelper.cpp +++ /dev/null @@ -1,170 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// breezeblurhelper.cpp -// handle regions passed to kwin for blurring -// ------------------- -// -// Copyright (C) 2021 Reion Wong -// Copyright (C) 2018 Alex Nemeth -// -// Largely rewritten from Oxygen widget style -// Copyright (C) 2007 Thomas Luebking -// Copyright (c) 2010 Hugo Pereira Da Costa -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -////////////////////////////////////////////////////////////////////////////// - -#include "blurhelper.h" -#include "x11utils.h" - -// KDE Frameworks -#include -#include - -// Qt -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// XCB -#include -#include -#include - -BlurHelper::BlurHelper(QObject *parent) - : QObject(parent) -{ -} - -void BlurHelper::registerWidget(QWidget *widget) -{ - // install event filter - addEventFilter(widget); - - // schedule shadow area repaint - update(widget); -} - -void BlurHelper::unregisterWidget(QWidget *widget) -{ - // remove event filter - widget->removeEventFilter(this); -} - -bool BlurHelper::eventFilter(QObject *object, QEvent *event) -{ - switch (event->type()) { - case QEvent::Hide: - case QEvent::Show: - case QEvent::Resize: { - // cast to widget and check - QWidget *widget(qobject_cast(object)); - - if (!widget) - break; - - update(widget); - break; - } - - default: break; - } - - // never eat events - return false; -} - - -void BlurHelper::update(QWidget *widget) const -{ - // KWindowEffects is an X11/EWMH integration. On Wayland there is no X11 - // native interface to pass the blur region to, and calling it can crash - // while a QMenu is being painted. - if (!KWindowSystem::isPlatformX11()) - return; - - /* - directly from bespin code. Supposedly prevent playing with some 'pseudo-widgets' - that have winId matching some other -random- window - */ - if (!(widget->testAttribute(Qt::WA_WState_Created) || widget->internalWinId())) - return; - - QWindow *window = widget->windowHandle(); - if (!window) - return; - - if (widget->mask().isEmpty()) { - KWindowEffects::enableBlurBehind(window, true); - } else { - KWindowEffects::enableBlurBehind(window, true, widget->mask()); - } - - // force update - if (widget->isVisible()) { - widget->update(); - } -} - -void BlurHelper::enableBlurBehind(QWidget *widget, bool enable, qreal windowRadius) -{ - if (!widget || !KWindowSystem::isPlatformX11()) - return; - - const auto native = qGuiApp->nativeInterface(); - if (!native) - return; - - xcb_connection_t *c = native->connection(); - if (!c) - return; - - const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"); - xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); - QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); - if (!atom) - return; - - if (enable) { - qreal devicePixelRatio = qApp->devicePixelRatio(); - QPainterPath path; - path.addRoundedRect(QRectF(QPoint(0, 0), widget->size() * devicePixelRatio), - windowRadius * devicePixelRatio, - windowRadius * devicePixelRatio); - QVector data; - for (const QPolygonF &polygon : path.toFillPolygons()) { - QRegion region = polygon.toPolygon(); - for (auto i = region.begin(); i != region.end(); ++i) { - data << i->x() << i->y() << i->width() << i->height(); - } - } - - xcb_change_property(c, XCB_PROP_MODE_REPLACE, widget->winId(), - atom->atom, XCB_ATOM_CARDINAL, - 32, data.size(), data.constData()); - - } else { - xcb_delete_property(c, widget->winId(), atom->atom); - } -} diff --git a/widgetstyle/blurhelper.h b/widgetstyle/blurhelper.h deleted file mode 100644 index 99b45b9..0000000 --- a/widgetstyle/blurhelper.h +++ /dev/null @@ -1,59 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// breezeblurhelper.h -// handle regions passed to kwin for blurring -// ------------------- -// -// Copyright (C) 2018 Alex Nemeth -// -// Largely rewritten from Oxygen widget style -// Copyright (C) 2007 Thomas Luebking -// Copyright (c) 2010 Hugo Pereira Da Costa -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -////////////////////////////////////////////////////////////////////////////// - -#ifndef BLURHELPER_H -#define BLURHELPER_H - -#include - -class BlurHelper : public QObject -{ - Q_OBJECT - -public: - explicit BlurHelper(QObject *parent = nullptr); - - void registerWidget(QWidget *); - void unregisterWidget(QWidget *); - bool eventFilter(QObject *, QEvent *) override; - - void update(QWidget *) const; - - void enableBlurBehind(QWidget *widget, bool enable = true, qreal windowRadius = 0.0); - -protected: - void addEventFilter(QObject *object) { - object->removeEventFilter(this); - object->installEventFilter(this); - } - -}; - -#endif // BLURHELPER_H diff --git a/widgetstyle/boxshadowrenderer.cpp b/widgetstyle/boxshadowrenderer.cpp deleted file mode 100644 index fa91853..0000000 --- a/widgetstyle/boxshadowrenderer.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2018 Vlad Zahorodnii - * - * The box blur implementation is based on AlphaBoxBlur from Firefox. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -// own -#include "boxshadowrenderer.h" - -// Qt -#include -#include - -static inline int calculateBlurRadius(qreal stdDev) -{ - // See https://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement - const qreal gaussianScaleFactor = (3.0 * qSqrt(2.0 * M_PI) / 4.0) * 1.5; - return qMax(2, qFloor(stdDev * gaussianScaleFactor + 0.5)); -} - -static inline qreal calculateBlurStdDev(int radius) -{ - // See https://www.w3.org/TR/css-backgrounds-3/#shadow-blur - return radius * 0.5; -} - -static inline QSize calculateBlurExtent(int radius) -{ - const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius)); - return QSize(blurRadius, blurRadius); -} - -struct BoxLobes -{ - int left; ///< how many pixels sample to the left - int right; ///< how many pixels sample to the right -}; - -/** - * Compute box filter parameters. - * - * @param radius The blur radius. - * @returns Parameters for three box filters. - **/ -static QVector computeLobes(int radius) -{ - const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius)); - const int z = blurRadius / 3; - - int major; - int minor; - int final; - - switch (blurRadius % 3) { - case 0: - major = z; - minor = z; - final = z; - break; - - case 1: - major = z + 1; - minor = z; - final = z; - break; - - case 2: - major = z + 1; - minor = z; - final = z + 1; - break; - - default: - Q_UNREACHABLE(); - } - - Q_ASSERT(major + minor + final == blurRadius); - - return { - {major, minor}, - {minor, major}, - {final, final} - }; -} - -/** - * Process a row with a box filter. - * - * @param src The start of the row. - * @param dst The destination. - * @param width The width of the row, in pixels. - * @param horizontalStride The number of bytes from one alpha value to the - * next alpha value. - * @param verticalStride The number of bytes from one row to the next row. - * @param lobes Params of the box filter. - * @param transposeInput Whether the input is transposed. - * @param transposeOutput Whether the output should be transposed. - **/ -static inline void boxBlurRowAlpha(const uint8_t *src, uint8_t *dst, int width, int horizontalStride, - int verticalStride, const BoxLobes &lobes, bool transposeInput, - bool transposeOutput) -{ - const int inputStep = transposeInput ? verticalStride : horizontalStride; - const int outputStep = transposeOutput ? verticalStride : horizontalStride; - - const int boxSize = lobes.left + 1 + lobes.right; - const int reciprocal = (1 << 24) / boxSize; - - uint32_t alphaSum = (boxSize + 1) / 2; - - const uint8_t *left = src; - const uint8_t *right = src; - uint8_t *out = dst; - - const uint8_t firstValue = src[0]; - const uint8_t lastValue = src[(width - 1) * inputStep]; - - alphaSum += firstValue * lobes.left; - - const uint8_t *initEnd = src + (boxSize - lobes.left) * inputStep; - while (right < initEnd) { - alphaSum += *right; - right += inputStep; - } - - const uint8_t *leftEnd = src + boxSize * inputStep; - while (right < leftEnd) { - *out = (alphaSum * reciprocal) >> 24; - alphaSum += *right - firstValue; - right += inputStep; - out += outputStep; - } - - const uint8_t *centerEnd = src + width * inputStep; - while (right < centerEnd) { - *out = (alphaSum * reciprocal) >> 24; - alphaSum += *right - *left; - left += inputStep; - right += inputStep; - out += outputStep; - } - - const uint8_t *rightEnd = dst + width * outputStep; - while (out < rightEnd) { - *out = (alphaSum * reciprocal) >> 24; - alphaSum += lastValue - *left; - left += inputStep; - out += outputStep; - } -} - -/** - * Blur the alpha channel of a given image. - * - * @param image The input image. - * @param radius The blur radius. - * @param rect Specifies what part of the image to blur. If nothing is provided, then - * the whole alpha channel of the input image will be blurred. - **/ -static inline void boxBlurAlpha(QImage &image, int radius, const QRect &rect = {}) -{ - if (radius < 2) { - return; - } - - const QVector lobes = computeLobes(radius); - - const QRect blurRect = rect.isNull() ? image.rect() : rect; - - const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3; - const int width = blurRect.width(); - const int height = blurRect.height(); - const int rowStride = image.bytesPerLine(); - const int pixelStride = image.depth() >> 3; - - const int bufferStride = qMax(width, height) * pixelStride; - QScopedPointer > buf(new uint8_t[2 * bufferStride]); - uint8_t *buf1 = buf.data(); - uint8_t *buf2 = buf1 + bufferStride; - - // Blur the image in horizontal direction. - for (int i = 0; i < height; ++i) { - uint8_t *row = image.scanLine(blurRect.y() + i) + blurRect.x() * pixelStride + alphaOffset; - boxBlurRowAlpha(row, buf1, width, pixelStride, rowStride, lobes[0], false, false); - boxBlurRowAlpha(buf1, buf2, width, pixelStride, rowStride, lobes[1], false, false); - boxBlurRowAlpha(buf2, row, width, pixelStride, rowStride, lobes[2], false, false); - } - - // Blur the image in vertical direction. - for (int i = 0; i < width; ++i) { - uint8_t *column = image.scanLine(blurRect.y()) + (blurRect.x() + i) * pixelStride + alphaOffset; - boxBlurRowAlpha(column, buf1, height, pixelStride, rowStride, lobes[0], true, false); - boxBlurRowAlpha(buf1, buf2, height, pixelStride, rowStride, lobes[1], false, false); - boxBlurRowAlpha(buf2, column, height, pixelStride, rowStride, lobes[2], false, true); - } -} - -static inline void mirrorTopLeftQuadrant(QImage &image) -{ - const int width = image.width(); - const int height = image.height(); - - const int centerX = qCeil(width * 0.5); - const int centerY = qCeil(height * 0.5); - - const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3; - const int stride = image.depth() >> 3; - - for (int y = 0; y < centerY; ++y) { - uint8_t *in = image.scanLine(y) + alphaOffset; - uint8_t *out = in + (width - 1) * stride; - - for (int x = 0; x < centerX; ++x, in += stride, out -= stride) { - *out = *in; - } - } - - for (int y = 0; y < centerY; ++y) { - const uint8_t *in = image.scanLine(y) + alphaOffset; - uint8_t *out = image.scanLine(width - y - 1) + alphaOffset; - - for (int x = 0; x < width; ++x, in += stride, out += stride) { - *out = *in; - } - } -} - -static void renderShadow(QPainter *painter, const QRect &rect, qreal borderRadius, const QPoint &offset, int radius, const QColor &color) -{ - const QSize inflation = calculateBlurExtent(radius); - const QSize size = rect.size() + 2 * inflation; - - const qreal dpr = painter->device()->devicePixelRatioF(); - - QImage shadow(size * dpr, QImage::Format_ARGB32_Premultiplied); - shadow.setDevicePixelRatio(dpr); - shadow.fill(Qt::transparent); - - QRect boxRect(QPoint(0, 0), rect.size()); - boxRect.moveCenter(QRect(QPoint(0, 0), size).center()); - - const qreal xRadius = 2.0 * borderRadius / boxRect.width(); - const qreal yRadius = 2.0 * borderRadius / boxRect.height(); - - QPainter shadowPainter; - shadowPainter.begin(&shadow); - shadowPainter.setRenderHint(QPainter::Antialiasing); - shadowPainter.setPen(Qt::NoPen); - shadowPainter.setBrush(Qt::black); - shadowPainter.drawRoundedRect(boxRect, xRadius, yRadius); - shadowPainter.end(); - - // Because the shadow texture is symmetrical, that's enough to blur - // only the top-left quadrant and then mirror it. - const QRect blurRect(0, 0, qCeil(shadow.width() * 0.5), qCeil(shadow.height() * 0.5)); - const int scaledRadius = qRound(radius * dpr); - boxBlurAlpha(shadow, scaledRadius, blurRect); - mirrorTopLeftQuadrant(shadow); - - // Give the shadow a tint of the desired color. - shadowPainter.begin(&shadow); - shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); - shadowPainter.fillRect(shadow.rect(), color); - shadowPainter.end(); - - // Actually, present the shadow. - QRect shadowRect = shadow.rect(); - shadowRect.setSize(shadowRect.size() / dpr); - shadowRect.moveCenter(rect.center() + offset); - painter->drawImage(shadowRect, shadow); -} - -void BoxShadowRenderer::setBoxSize(const QSize &size) -{ - m_boxSize = size; -} - -void BoxShadowRenderer::setBorderRadius(qreal radius) -{ - m_borderRadius = radius; -} - -void BoxShadowRenderer::setDevicePixelRatio(qreal dpr) -{ - m_dpr = dpr; -} - -void BoxShadowRenderer::addShadow(const QPoint &offset, int radius, const QColor &color) -{ - Shadow shadow = {}; - shadow.offset = offset; - shadow.radius = radius; - shadow.color = color; - m_shadows.append(shadow); -} - -QImage BoxShadowRenderer::render() const -{ - if (m_shadows.isEmpty()) { - return {}; - } - - QSize canvasSize; - for (const Shadow &shadow : qAsConst(m_shadows)) { - canvasSize = canvasSize.expandedTo( - calculateMinimumShadowTextureSize(m_boxSize, shadow.radius, shadow.offset)); - } - - QImage canvas(canvasSize * m_dpr, QImage::Format_ARGB32_Premultiplied); - canvas.setDevicePixelRatio(m_dpr); - canvas.fill(Qt::transparent); - - QRect boxRect(QPoint(0, 0), m_boxSize); - boxRect.moveCenter(QRect(QPoint(0, 0), canvasSize).center()); - - QPainter painter(&canvas); - for (const Shadow &shadow : qAsConst(m_shadows)) { - renderShadow(&painter, boxRect, m_borderRadius, shadow.offset, shadow.radius, shadow.color); - } - painter.end(); - - return canvas; -} - -QSize BoxShadowRenderer::calculateMinimumBoxSize(int radius) -{ - const QSize blurExtent = calculateBlurExtent(radius); - return 2 * blurExtent + QSize(1, 1); -} - -QSize BoxShadowRenderer::calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset) -{ - return boxSize + 2 * calculateBlurExtent(radius) + QSize(qAbs(offset.x()), qAbs(offset.y())); -} \ No newline at end of file diff --git a/widgetstyle/boxshadowrenderer.h b/widgetstyle/boxshadowrenderer.h deleted file mode 100644 index 6211a73..0000000 --- a/widgetstyle/boxshadowrenderer.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2018 Vlad Zahorodnii - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -// Qt -#include -#include -#include -#include - -class BoxShadowRenderer -{ -public: - // Compiler generated constructors & destructor are fine. - - /** - * Set the size of the box. - * @param size The size of the box. - **/ - void setBoxSize(const QSize &size); - - /** - * Set the radius of box' corners. - * @param radius The border radius, in pixels. - **/ - void setBorderRadius(qreal radius); - - /** - * Set the device pixel ratio of the resulting shadow texture. - * @param dpr The device pixel ratio. - **/ - void setDevicePixelRatio(qreal dpr); - - /** - * Add a shadow. - * @param offset The offset of the shadow. - * @param radius The blur radius. - * @param color The color of the shadow. - **/ - void addShadow(const QPoint &offset, int radius, const QColor &color); - - /** - * Render the shadow. - **/ - QImage render() const; - - /** - * Calculate the minimum size of the box. - * - * This helper computes the minimum size of the box so the shadow behind it has - * full its strength. - * - * @param radius The blur radius of the shadow. - **/ - static QSize calculateMinimumBoxSize(int radius); - - /** - * Calculate the minimum size of the shadow texture. - * - * This helper computes the minimum size of the resulting texture so the shadow - * is not clipped. - * - * @param boxSize The size of the box. - * @param radius The blur radius. - * @param offset The offset of the shadow. - **/ - static QSize calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset); - -private: - QSize m_boxSize; - qreal m_borderRadius = 0.0; - qreal m_dpr = 1.0; - - struct Shadow { - QPoint offset; - int radius; - QColor color; - }; - - QVector m_shadows; -}; diff --git a/widgetstyle/shadowhelper.cpp b/widgetstyle/shadowhelper.cpp deleted file mode 100644 index 5134890..0000000 --- a/widgetstyle/shadowhelper.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/************************************************************************* - * Copyright (C) 2014 by Hugo Pereira Da Costa * - * Copyright (C) 2018, 2020 by Vlad Zahorodnii * - * Copyright (C) 2020, 2020 by Reven Martin * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * - *************************************************************************/ - -#include "shadowhelper.h" -#include "boxshadowrenderer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -const char netWMSkipShadow[] = "_CUTEFISH_NET_WM_SKIP_SHADOW"; -const char netWMForceShadow[] = "_CUTEFISH_NET_WM_FORCE_SHADOW"; -const char netWMFrameRadius[] = "_CUTEFISH_NET_WM_FRAME_RADIUS"; - -enum { - ShadowNone, - ShadowSmall, - ShadowMedium, - ShadowLarge, - ShadowVeryLarge -}; - -const CompositeShadowParams s_shadowParams[] = { - // None - CompositeShadowParams(), - // Small - CompositeShadowParams( - QPoint(0, 3), - ShadowParams(QPoint(0, 0), 16, 0.26), - ShadowParams(QPoint(0, -2), 8, 0.16)), - // Medium - CompositeShadowParams( - QPoint(0, 4), - ShadowParams(QPoint(0, 0), 20, 0.24), - ShadowParams(QPoint(0, -2), 10, 0.14)), - // Large - CompositeShadowParams( - QPoint(0, 5), - ShadowParams(QPoint(0, 0), 24, 0.22), - ShadowParams(QPoint(0, -3), 12, 0.12)), - // Very Large - CompositeShadowParams( - QPoint(0, 6), - ShadowParams(QPoint(0, 0), 32, 0.2), - ShadowParams(QPoint(0, -3), 16, 0.1)) -}; - - -ShadowHelper::ShadowHelper(QObject * parent) - : QObject(parent), - m_frameRadius(12) -{ -} - -ShadowHelper::~ShadowHelper() -{ -} - -CompositeShadowParams ShadowHelper::lookupShadowParams(int shadowSizeEnum) -{ - switch (shadowSizeEnum) { - case ShadowNone: - return s_shadowParams[0]; - case ShadowSmall: - return s_shadowParams[1]; - case ShadowMedium: - return s_shadowParams[2]; - case ShadowLarge: - return s_shadowParams[3]; - case ShadowVeryLarge: - return s_shadowParams[4]; - default: - // Fallback to the Large size. - return s_shadowParams[3]; - } -} - -bool ShadowHelper::registerWidget(QWidget *widget, bool force) -{ - // make sure widget is not already registered - if (m_widgets.contains(widget)) - return false; - - // check if widget qualifies - if (!(force || acceptWidget(widget))) - return false; - - qreal frameRadius = m_frameRadius; - const auto frameRadiusProperty = widget->property(netWMFrameRadius); - if (frameRadiusProperty.isValid()) - frameRadius = frameRadiusProperty.toReal(); - - installShadows(widget, shadowTiles(frameRadius)); - m_widgets.insert(widget); - - // install event filter - widget->removeEventFilter(this); - widget->installEventFilter(this); - - // connect destroy signal - connect(widget, &QObject::destroyed, this, &ShadowHelper::objectDeleted); - - return true; -} - -void ShadowHelper::unregisterWidget(QWidget *widget) -{ - if (m_widgets.remove(widget)) { - // uninstall the event filter - widget->removeEventFilter(this); - - // disconnect all signals - disconnect(widget, nullptr, this, nullptr); - - // uninstall the shadow - uninstallShadows(widget); - } -} - -bool ShadowHelper::eventFilter(QObject *object, QEvent *event) -{ - if (KWindowSystem::isPlatformX11()) { - // check event type - if (event->type() == QEvent::WinIdChange) { - QWidget *widget = static_cast(object); - - qreal frameRadius = m_frameRadius; - const auto frameRadiusProperty = widget->property(netWMFrameRadius); - if (frameRadiusProperty.isValid()) - frameRadius = frameRadiusProperty.toReal(); - TileSet shadowTileSet = shadowTiles(frameRadius); - installShadows(widget, shadowTileSet); - } - } else { - if (event->type() != QEvent::PlatformSurface) - return false; - - // QWidget *widget(static_cast(object)); - QPlatformSurfaceEvent* surfaceEvent(static_cast(event)); - - switch (surfaceEvent->surfaceEventType()) { - case QPlatformSurfaceEvent::SurfaceCreated: - //installShadows(widget); - break; - case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: - // Don't care. - break; - } - } - - return false; -} - -TileSet ShadowHelper::shadowTiles(const qreal frameRadius) -{ - const CompositeShadowParams params = lookupShadowParams(ShadowVeryLarge); - - if (params.isNone()) - return TileSet(); - // } else if (_shadowTiles.isValid()) { - // return _shadowTiles; - // } - - auto withOpacity = [](const QColor &color, qreal opacity) -> QColor { - QColor c(color); - c.setAlphaF(opacity); - return c; - }; - - const QColor color = Qt::black; - // const qreal strength = static_cast(255) / 255.0; - const qreal strength = 1.5; - - const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius) - .expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius)); - - const qreal dpr = qApp->devicePixelRatio(); - - BoxShadowRenderer shadowRenderer; - shadowRenderer.setBorderRadius(frameRadius); - shadowRenderer.setBoxSize(boxSize); - shadowRenderer.setDevicePixelRatio(dpr); - - shadowRenderer.addShadow(params.shadow1.offset, params.shadow1.radius, - withOpacity(color, params.shadow1.opacity * strength)); - shadowRenderer.addShadow(params.shadow2.offset, params.shadow2.radius, - withOpacity(color, params.shadow2.opacity * strength)); - - QImage shadowTexture = shadowRenderer.render(); - - const QRect outerRect(QPoint(0, 0), shadowTexture.size() / dpr); - - QRect boxRect(QPoint(0, 0), boxSize); - boxRect.moveCenter(outerRect.center()); - - // Mask out inner rect. - QPainter painter(&shadowTexture); - painter.setRenderHint(QPainter::Antialiasing); - - int Shadow_Overlap = 3; - const QMargins margins = QMargins( - boxRect.left() - outerRect.left() - Shadow_Overlap - params.offset.x(), - boxRect.top() - outerRect.top() - Shadow_Overlap - params.offset.y(), - outerRect.right() - boxRect.right() - Shadow_Overlap + params.offset.x(), - outerRect.bottom() - boxRect.bottom() - Shadow_Overlap + params.offset.y()); - - painter.setPen(Qt::NoPen); - painter.setBrush(Qt::black); - painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); - painter.drawRoundedRect( - outerRect - margins, - frameRadius, - frameRadius); - - // We're done. - painter.end(); - - const QPoint innerRectTopLeft = outerRect.center(); - TileSet tiles = TileSet( - QPixmap::fromImage(shadowTexture), - innerRectTopLeft.x(), - innerRectTopLeft.y(), - 1, 1); - - return tiles; -} - -void ShadowHelper::objectDeleted(QObject *object) -{ - QWidget *widget(static_cast(object)); - m_widgets.remove(widget); - m_shadows.remove(widget); -} - -bool ShadowHelper::isMenu(QWidget *widget) const -{ - return qobject_cast(widget); -} - -bool ShadowHelper::isToolTip(QWidget *widget) const -{ - return widget->inherits("QTipLabel") || (widget->windowFlags() & Qt::WindowType_Mask) == Qt::ToolTip; -} - -bool ShadowHelper::isDockWidget(QWidget *widget) const -{ - return qobject_cast(widget); -} - -bool ShadowHelper::isToolBar(QWidget *widget) const -{ - return qobject_cast(widget); -} - -bool ShadowHelper::acceptWidget(QWidget *widget) const -{ - // flags - if (widget->property(netWMSkipShadow).toBool()) - return false; - if (widget->property(netWMForceShadow).toBool()) - return true; - - // menus - if (isMenu(widget)) - return true; - - // combobox dropdown lists - if (widget->inherits("QComboBoxPrivateContainer")) - return true; - - // tooltips - if (isToolTip(widget) && !widget->inherits("Plasma::ToolTip")) - return true; - - // detached widgets - if (isDockWidget(widget) || isToolBar(widget)) - return true; - - // reject - return false; -} - -KWindowShadowTile::Ptr ShadowHelper::createTile(const QPixmap& source) -{ - KWindowShadowTile::Ptr tile = KWindowShadowTile::Ptr::create(); - tile->setImage(source.toImage()); - return tile; -} - -void ShadowHelper::installShadows(QWidget *widget, TileSet shadowTiles) -{ - if (!widget) - return; - - // only toplevel widgets can cast drop-shadows - if (!widget->isWindow()) - return; - - // widget must have valid native window - if (!widget->testAttribute(Qt::WA_WState_Created)) - return; - - // create platform shadow tiles - QVector tiles = { - createTile(shadowTiles.pixmap(1)), - createTile(shadowTiles.pixmap(2)), - createTile(shadowTiles.pixmap(5)), - createTile(shadowTiles.pixmap(8)), - createTile(shadowTiles.pixmap(7)), - createTile(shadowTiles.pixmap(6)), - createTile(shadowTiles.pixmap(3)), - createTile(shadowTiles.pixmap(0)) - }; - if (tiles.count() != numTiles) - return; - - // find a shadow associated with the widget - KWindowShadow*& shadow = m_shadows[ widget ]; - - if (!shadow) - shadow = new KWindowShadow(widget); - - if (shadow->isCreated()) - shadow->destroy(); - - shadow->setTopTile(tiles[ 0 ]); - shadow->setTopRightTile(tiles[ 1 ]); - shadow->setRightTile(tiles[ 2 ]); - shadow->setBottomRightTile(tiles[ 3 ]); - shadow->setBottomTile(tiles[ 4 ]); - shadow->setBottomLeftTile(tiles[ 5 ]); - shadow->setLeftTile(tiles[ 6 ]); - shadow->setTopLeftTile(tiles[ 7 ]); - shadow->setPadding(shadowMargins(widget, shadowTiles)); - shadow->setWindow(widget->windowHandle()); - shadow->create(); -} - -QMargins ShadowHelper::shadowMargins(QWidget *widget, TileSet shadowTiles) const -{ - const CompositeShadowParams params = lookupShadowParams(ShadowVeryLarge); - if (params.isNone()) - return QMargins(); - - const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius) - .expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius)); - - const QSize shadowSize = BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow1.radius, params.shadow1.offset) - .expandedTo(BoxShadowRenderer::calculateMinimumShadowTextureSize(boxSize, params.shadow2.radius, params.shadow2.offset)); - - const QRect shadowRect(QPoint(0, 0), shadowSize); - - QRect boxRect(QPoint(0, 0), boxSize); - boxRect.moveCenter(shadowRect.center()); - - int Shadow_Overlap = 4; - QMargins margins( - boxRect.left() - shadowRect.left() - Shadow_Overlap - params.offset.x(), - boxRect.top() - shadowRect.top() - Shadow_Overlap - params.offset.y(), - shadowRect.right() - boxRect.right() - Shadow_Overlap + params.offset.x(), - shadowRect.bottom() - boxRect.bottom() - Shadow_Overlap + params.offset.y()); - - if (widget->inherits("QBalloonTip")) { - // Balloon tip needs special margins to deal with the arrow. - int top = widget->contentsMargins().top(); - int bottom = widget->contentsMargins().bottom(); - - // Need to decrement default size further due to extra hard coded round corner. - margins -= 1; - - // Arrow can be either to the top or the bottom. Adjust margins accordingly. - const int diff = qAbs(top - bottom); - if (top > bottom) { - margins.setTop(margins.top() - diff); - } else { - margins.setBottom(margins.bottom() - diff); - } - } - - margins *= shadowTiles.pixmap(0).devicePixelRatio(); - - return margins; -} - -void ShadowHelper::uninstallShadows(QWidget *widget) -{ - delete m_shadows.take(widget); -} diff --git a/widgetstyle/shadowhelper.h b/widgetstyle/shadowhelper.h deleted file mode 100644 index 6bc123c..0000000 --- a/widgetstyle/shadowhelper.h +++ /dev/null @@ -1,148 +0,0 @@ -/************************************************************************* - * Copyright (C) 2014 by Hugo Pereira Da Costa * - * Copyright (C) 2020 by Vlad Zahorodnii * - * Copyright (C) 2020, 2020 by Reven Martin * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * - *************************************************************************/ - -#ifndef SHADOWHELPER_H -#define SHADOWHELPER_H - -#include "tileset.h" -#include - -#include -#include -#include -#include -#include - -struct ShadowParams -{ - ShadowParams() = default; - - ShadowParams(const QPoint &offset, int radius, qreal opacity): - offset(offset), - radius(radius), - opacity(opacity) - {} - - QPoint offset; - int radius = 0; - qreal opacity = 0; -}; - -struct CompositeShadowParams -{ - CompositeShadowParams() = default; - - CompositeShadowParams( - const QPoint &offset, - const ShadowParams &shadow1, - const ShadowParams &shadow2) - : offset(offset) - , shadow1(shadow1) - , shadow2(shadow2) {} - - bool isNone() const - { return qMax(shadow1.radius, shadow2.radius) == 0; } - - QPoint offset; - ShadowParams shadow1; - ShadowParams shadow2; -}; - -//* handle shadow pixmaps passed to window manager via X property -class ShadowHelper: public QObject -{ - Q_OBJECT - -public: - //* constructor - ShadowHelper(QObject *); - - //* destructor - ~ShadowHelper() override; - - //* shadow params from size enum - static CompositeShadowParams lookupShadowParams(int shadowSizeEnum); - - //* register widget - bool registerWidget(QWidget *, bool force = false); - - //* unregister widget - void unregisterWidget(QWidget *); - - //* event filter - bool eventFilter(QObject *, QEvent *) override; - - void setFrameRadius(qreal radius) { m_frameRadius = radius; } - - //* shadow tiles - /** is public because it is also needed for mdi windows */ - // TileSet shadowTiles(); - - TileSet shadowTiles(const qreal frameRadius); - -protected Q_SLOTS: - //* unregister widget - void objectDeleted(QObject *); - -protected: - //* true if widget is a menu - bool isMenu(QWidget *) const; - - //* true if widget is a tooltip - bool isToolTip(QWidget *) const; - - //* dock widget - bool isDockWidget(QWidget *) const; - - //* toolbar - bool isToolBar(QWidget *) const; - - //* accept widget - bool acceptWidget(QWidget *) const; - - // create shadow tile from pixmap - KWindowShadowTile::Ptr createTile(const QPixmap &); - - //* installs shadow on given widget in a platform independent way - // void installShadows( QWidget * ); - - void installShadows(QWidget *widget, TileSet shadowTiles); - - //* uninstalls shadow on given widget in a platform independent way - void uninstallShadows(QWidget *); - - //* gets the shadow margins for the given widget - QMargins shadowMargins(QWidget*, TileSet) const; - -private: - //* registered widgets - QSet m_widgets; - - //* managed shadows - QMap m_shadows; - - qreal m_frameRadius; - - //* number of tiles - enum { numTiles = 8 }; -}; - -#endif diff --git a/widgetstyle/tileset.cpp b/widgetstyle/tileset.cpp deleted file mode 100644 index b53f7c8..0000000 --- a/widgetstyle/tileset.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/************************************************************************* - * Copyright (C) 2014 by Hugo Pereira Da Costa * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * - *************************************************************************/ - -#include "tileset.h" - -#include - -//___________________________________________________________ -inline bool bits(TileSet::Tiles flags, TileSet::Tiles testFlags) -{ return (flags & testFlags) == testFlags; } - -//______________________________________________________________________________________ -inline qreal devicePixelRatio( const QPixmap& pixmap ) -{ - return pixmap.devicePixelRatio(); -} - -//______________________________________________________________________________________ -inline void setDevicePixelRatio( QPixmap& pixmap, qreal value ) -{ - return pixmap.setDevicePixelRatio( value ); -} - -//______________________________________________________________ -void TileSet::initPixmap( PixmapList& pixmaps, const QPixmap &source, int width, int height, const QRect &rect) -{ - QSize size( width, height ); - if( !( size.isValid() && rect.isValid() ) ) - { - pixmaps.append( QPixmap() ); - - } else if( size != rect.size() ) { - - const qreal dpiRatio( devicePixelRatio( source ) ); - const QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio ); - const QSize scaledSize( size*dpiRatio ); - const QPixmap tile( source.copy(scaledRect) ); - QPixmap pixmap( scaledSize ); - - pixmap.fill(Qt::transparent); - QPainter painter(&pixmap); - painter.drawTiledPixmap(0, 0, scaledSize.width(), scaledSize.height(), tile); - setDevicePixelRatio( pixmap, dpiRatio ); - pixmaps.append( pixmap ); - - } else { - - const qreal dpiRatio( devicePixelRatio( source ) ); - const QRect scaledRect( rect.topLeft()*dpiRatio, rect.size()*dpiRatio ); - QPixmap pixmap( source.copy( scaledRect ) ); - setDevicePixelRatio( pixmap, dpiRatio ); - pixmaps.append( pixmap ); - - } - -} - -//______________________________________________________________ -TileSet::TileSet(): - _w1(0), - _h1(0), - _w3(0), - _h3(0) -{ _pixmaps.reserve(9); } - -//______________________________________________________________ -TileSet::TileSet(const QPixmap &source, int w1, int h1, int w2, int h2 ): - _w1(w1), - _h1(h1), - _w3(0), - _h3(0) -{ - _pixmaps.reserve(9); - if( source.isNull() ) return; - - _w3 = source.width()/devicePixelRatio( source ) - (w1 + w2); - _h3 = source.height()/devicePixelRatio( source ) - (h1 + h2); - int w = w2; - int h = h2; - - // initialise pixmap array - initPixmap( _pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1) ); - initPixmap( _pixmaps, source, w, _h1, QRect(_w1, 0, w2, _h1) ); - initPixmap( _pixmaps, source, _w3, _h1, QRect(_w1+w2, 0, _w3, _h1) ); - initPixmap( _pixmaps, source, _w1, h, QRect(0, _h1, _w1, h2) ); - initPixmap( _pixmaps, source, w, h, QRect(_w1, _h1, w2, h2) ); - initPixmap( _pixmaps, source, _w3, h, QRect(_w1+w2, _h1, _w3, h2) ); - initPixmap( _pixmaps, source, _w1, _h3, QRect(0, _h1+h2, _w1, _h3) ); - initPixmap( _pixmaps, source, w, _h3, QRect(_w1, _h1+h2, w2, _h3) ); - initPixmap( _pixmaps, source, _w3, _h3, QRect(_w1+w2, _h1+h2, _w3, _h3) ); -} - -//___________________________________________________________ -void TileSet::render(const QRect &constRect, QPainter *painter, Tiles tiles) const -{ - - const bool oldHint( painter->testRenderHint( QPainter::SmoothPixmapTransform ) ); - painter->setRenderHint( QPainter::SmoothPixmapTransform, true ); - - // check initialization - if( _pixmaps.size() < 9 ) return; - - // copy source rect - QRect rect( constRect ); - - // get rect dimensions - int x0, y0, w, h; - rect.getRect(&x0, &y0, &w, &h); - - // calculate pixmaps widths - int wLeft(0); - int wRight(0); - if( _w1+_w3 > 0 ) - { - qreal wRatio( qreal( _w1 )/qreal( _w1 + _w3 ) ); - wLeft = (tiles&Right) ? qMin( _w1, int(w*wRatio) ):_w1; - wRight = (tiles&Left) ? qMin( _w3, int(w*(1.0-wRatio)) ):_w3; - } - - // calculate pixmap heights - int hTop(0); - int hBottom(0); - if( _h1+_h3 > 0 ) - { - qreal hRatio( qreal( _h1 )/qreal( _h1 + _h3 ) ); - hTop = (tiles&Bottom) ? qMin( _h1, int(h*hRatio) ):_h1; - hBottom = (tiles&Top) ? qMin( _h3, int(h*(1.0-hRatio)) ):_h3; - } - - // calculate corner locations - w -= wLeft + wRight; - h -= hTop + hBottom; - const int x1 = x0 + wLeft; - const int x2 = x1 + w; - const int y1 = y0 + hTop; - const int y2 = y1 + h; - - const int w2 = _pixmaps.at(7).width()/devicePixelRatio( _pixmaps.at(7) ); - const int h2 = _pixmaps.at(5).height()/devicePixelRatio( _pixmaps.at(5) ); - - // corner - if( bits( tiles, Top|Left) ) painter->drawPixmap(x0, y0, _pixmaps.at(0), 0, 0, wLeft*devicePixelRatio( _pixmaps.at(0) ), hTop*devicePixelRatio( _pixmaps.at(0) )); - if( bits( tiles, Top|Right) ) painter->drawPixmap(x2, y0, _pixmaps.at(2), (_w3-wRight)*devicePixelRatio( _pixmaps.at(2) ), 0, wRight*devicePixelRatio( _pixmaps.at(2) ), hTop*devicePixelRatio( _pixmaps.at(2) ) ); - if( bits( tiles, Bottom|Left) ) painter->drawPixmap(x0, y2, _pixmaps.at(6), 0, (_h3-hBottom)*devicePixelRatio( _pixmaps.at(6) ), wLeft*devicePixelRatio( _pixmaps.at(6) ), hBottom*devicePixelRatio( _pixmaps.at(6) )); - if( bits( tiles, Bottom|Right) ) painter->drawPixmap(x2, y2, _pixmaps.at(8), (_w3-wRight)*devicePixelRatio( _pixmaps.at(8) ), (_h3-hBottom)*devicePixelRatio( _pixmaps.at(8) ), wRight*devicePixelRatio( _pixmaps.at(8) ), hBottom*devicePixelRatio( _pixmaps.at(8) ) ); - - // top and bottom - if( w > 0 ) - { - if( tiles&Top ) painter->drawPixmap(x1, y0, w, hTop, _pixmaps.at(1), 0, 0, w2*devicePixelRatio( _pixmaps.at(1) ), hTop*devicePixelRatio( _pixmaps.at(1) ) ); - if( tiles&Bottom ) painter->drawPixmap(x1, y2, w, hBottom, _pixmaps.at(7), 0, (_h3-hBottom)*devicePixelRatio( _pixmaps.at(7) ), w2*devicePixelRatio( _pixmaps.at(7) ), hBottom*devicePixelRatio( _pixmaps.at(7) ) ); - } - - // left and right - if( h > 0 ) - { - if( tiles&Left ) painter->drawPixmap(x0, y1, wLeft, h, _pixmaps.at(3), 0, 0, wLeft*devicePixelRatio( _pixmaps.at(3) ), h2*devicePixelRatio( _pixmaps.at(3) ) ); - if( tiles&Right ) painter->drawPixmap(x2, y1, wRight, h, _pixmaps.at(5), (_w3-wRight)*devicePixelRatio( _pixmaps.at(5) ), 0, wRight*devicePixelRatio( _pixmaps.at(5) ), h2*devicePixelRatio( _pixmaps.at(5) ) ); - } - - // center - if( (tiles&Center) && h > 0 && w > 0 ) painter->drawPixmap(x1, y1, w, h, _pixmaps.at(4)); - - // restore - painter->setRenderHint( QPainter::SmoothPixmapTransform, oldHint ); - -} diff --git a/widgetstyle/tileset.h b/widgetstyle/tileset.h deleted file mode 100644 index 4f16f8c..0000000 --- a/widgetstyle/tileset.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef TILESET_H -#define TILESET_H - -/************************************************************************* - * Copyright (C) 2014 by Hugo Pereira Da Costa * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * - *************************************************************************/ - - -#include -#include -#include - -//* handles proper scaling of pixmap to match widget rect. -/** -tilesets are collections of stretchable pixmaps corresponding to a given widget corners, sides, and center. -corner pixmaps are never stretched. center pixmaps are -*/ -class TileSet -{ - public: - /** - Create a TileSet from a pixmap. The size of the bottom/right chunks is - whatever is left over from the other chunks, whose size is specified - in the required parameters. - - @param w1 width of the left chunks - @param h1 height of the top chunks - @param w2 width of the not-left-or-right chunks - @param h2 height of the not-top-or-bottom chunks - */ - TileSet(const QPixmap&, int w1, int h1, int w2, int h2 ); - - //* empty constructor - TileSet(); - - //* destructor - virtual ~TileSet() - {} - - /** - Flags specifying what sides to draw in ::render. Corners are drawn when - the sides forming that corner are drawn, e.g. Top|Left draws the - top-center, center-left, and top-left chunks. The center-center chunk is - only drawn when Center is requested. - */ - enum Tile { - Top = 0x1, - Left = 0x2, - Bottom = 0x4, - Right = 0x8, - Center = 0x10, - TopLeft = Top|Left, - TopRight = Top|Right, - BottomLeft = Bottom|Left, - BottomRight = Bottom|Right, - Ring = Top|Left|Bottom|Right, - Horizontal = Left|Right|Center, - Vertical = Top|Bottom|Center, - Full = Ring|Center - }; - Q_DECLARE_FLAGS(Tiles, Tile) - - /** - Fills the specified rect with tiled chunks. Corners are never tiled, - edges are tiled in one direction, and the center chunk is tiled in both - directions. Partial tiles are used as needed so that the entire rect is - perfectly filled. Filling is performed as if all chunks are being drawn. - */ - void render(const QRect&, QPainter*, Tiles = Ring) const; - - //* return size associated to this tileset - QSize size() const - { return QSize( _w1 + _w3, _h1 + _h3 ); } - - //* is valid - bool isValid() const - { return _pixmaps.size() == 9; } - - //* returns pixmap for given index - QPixmap pixmap( int index ) const - { return _pixmaps[index]; } - - protected: - - //* shortcut to pixmap list - using PixmapList = QVector; - - //* initialize pixmap - void initPixmap( PixmapList&, const QPixmap&, int w, int h, const QRect& ); - - private: - - //* pixmap arry - PixmapList _pixmaps; - - // dimensions - int _w1; - int _h1; - int _w3; - int _h3; - -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(TileSet::Tiles) - -#endif //TILESET_H diff --git a/x11utils.h b/x11utils.h deleted file mode 100644 index d3546ee..0000000 --- a/x11utils.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace Cutefish::X11 -{ -inline xcb_window_t rootWindow() -{ - const auto native = qGuiApp ? qGuiApp->nativeInterface() : nullptr; - const auto c = native ? native->connection() : nullptr; - if (!c) - return XCB_WINDOW_NONE; - - const auto *setup = xcb_get_setup(c); - const auto iterator = xcb_setup_roots_iterator(setup); - return iterator.data ? iterator.data->root : XCB_WINDOW_NONE; -} -}