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

0001 /*****************************************************************************
0002  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0003  *                                                                           *
0004  *   This program is free software; you can redistribute it and/or modify    *
0005  *   it under the terms of the GNU Lesser General Public License as          *
0006  *   published by the Free Software Foundation; either version 2.1 of the    *
0007  *   License, or (at your option) version 3, or any later version accepted   *
0008  *   by the membership of KDE e.V. (or its successor approved by the         *
0009  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0010  *   Section 6 of version 3 of the license.                                  *
0011  *                                                                           *
0012  *   This program is distributed in the hope that it will be useful,         *
0013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0015  *   Lesser General Public License for more details.                         *
0016  *                                                                           *
0017  *   You should have received a copy of the GNU Lesser General Public        *
0018  *   License along with this library. If not,                                *
0019  *   see <http://www.gnu.org/licenses/>.                                     *
0020  *****************************************************************************/
0021 
0022 #include "qtcurve_plugin.h"
0023 #include "qtcurve.h"
0024 
0025 #include "config-qt5.h"
0026 
0027 #include <qtcurve-utils/qtprops.h>
0028 #include <qtcurve-utils/x11shadow.h>
0029 #include <qtcurve-utils/x11blur.h>
0030 
0031 #include <QApplication>
0032 
0033 #ifdef Qt5X11Extras_FOUND
0034 #  include <qtcurve-utils/x11base.h>
0035 #  include <QX11Info>
0036 #endif
0037 
0038 #ifdef QTC_QT5_ENABLE_QTQUICK2
0039 #  include <QQuickWindow>
0040 #  include <QQuickItem>
0041 #endif
0042 #include <QDebug>
0043 
0044 #include <qtcurve-utils/log.h>
0045 
0046 namespace QtCurve {
0047 
0048 __attribute__((hot)) static void
0049 polishQuickControl(QObject *obj)
0050 {
0051 #ifdef QTC_QT5_ENABLE_QTQUICK2
0052     if (QQuickWindow *window = qobject_cast<QQuickWindow*>(obj)) {
0053         // QtQuickControl support
0054         // This is still VERY experimental.
0055         // Need a lot more testing and refactoring.
0056         if (Style *style = getStyle(qApp)) {
0057             if (window->inherits("QQuickPopupWindow")) {
0058                 if (window->inherits("QQuickMenuPopupWindow")) {
0059                     window->setColor(QColor(0, 0, 0, 0));
0060                 }
0061                 qtcX11ShadowInstall(window->winId());
0062             } else {
0063                 QColor color = window->color();
0064                 int opacity = style->options().bgndOpacity;
0065                 if (color.alpha() == 255 && opacity != 100) {
0066                     qreal opacityF = opacity / 100.0;
0067                     window->setColor(QColor::fromRgbF(color.redF() * opacityF,
0068                                                       color.greenF() * opacityF,
0069                                                       color.blueF() * opacityF,
0070                                                       opacityF));
0071                     qtcX11BlurTrigger(window->winId(), true, 0, nullptr);
0072                 }
0073             }
0074         }
0075     } else if (QQuickItem *item = qobject_cast<QQuickItem*>(obj)) {
0076         if (QQuickWindow *window = item->window()) {
0077             if (getStyle(qApp)) {
0078                 window->setColor(QColor(0, 0, 0, 0));
0079                 qtcX11BlurTrigger(window->winId(), true, 0, nullptr);
0080             }
0081         }
0082     }
0083 #else
0084     QTC_UNUSED(obj);
0085 #endif
0086 }
0087 
0088 __attribute__((hot)) static bool
0089 qtcEventCallback(void **cbdata)
0090 {
0091     QObject *receiver = (QObject*)cbdata[0];
0092     QTC_RET_IF_FAIL(receiver, false);
0093     QEvent *event = (QEvent*)cbdata[1];
0094     if (qtcUnlikely(event->type() == QEvent::DynamicPropertyChange)) {
0095         QDynamicPropertyChangeEvent *prop_event =
0096             static_cast<QDynamicPropertyChangeEvent*>(event);
0097         // eat the property change events from ourselves
0098         if (prop_event->propertyName() == QTC_PROP_NAME) {
0099             return true;
0100         }
0101     }
0102     QWidget *widget = qtcToWidget(receiver);
0103     if (qtcUnlikely(widget && !qtcGetWid(widget))) {
0104         if (Style *style = getStyle(widget)) {
0105             style->prePolish(widget);
0106         }
0107     } else if (widget && event->type() == QEvent::UpdateRequest) {
0108         QtcQWidgetProps props(widget);
0109         props->opacity = 100;
0110     } else {
0111         polishQuickControl(receiver);
0112     }
0113     return false;
0114 }
0115 
0116 static StylePlugin *firstPlInstance = nullptr;
0117 static QList<Style*> *styleInstances = nullptr;
0118 
0119 QStyle*
0120 StylePlugin::create(const QString &key)
0121 {
0122     if (!firstPlInstance) {
0123         firstPlInstance = this;
0124         styleInstances = &m_styleInstances;
0125     }
0126 
0127     init();
0128     Style *qtc;
0129     if (key.toLower() == "qtcurve") {
0130         qtc = new Style;
0131         qtc->m_plugin = this;
0132         // keep track of all style instances we allocate, for instance
0133         // for KLineEdit widgets which apparently insist on overriding
0134         // certain things (cf. KLineEditStyle). We want to be able to
0135         // delete those instances as properly and as early as
0136         // possible during the global destruction phase.
0137         m_styleInstances << qtc;
0138     } else {
0139         qtc = nullptr;
0140     }
0141     return qtc;
0142 }
0143 
0144 void StylePlugin::unregisterCallback()
0145 {
0146     if (m_eventNotifyCallbackInstalled) {
0147         qtcInfo("Unregistering the event notify callback (for plugin %p)\n", this);
0148         QInternal::unregisterCallback(QInternal::EventNotifyCallback,
0149                                     qtcEventCallback);
0150         m_eventNotifyCallbackInstalled = false;
0151     }
0152 }
0153 
0154 StylePlugin::~StylePlugin()
0155 {
0156     qtcInfo("Deleting QtCurve plugin (%p)\n", this);
0157     if (!m_styleInstances.isEmpty()) {
0158         qtcWarn("there remain(s) %d Style instance(s)\n", m_styleInstances.count());
0159         foreach (Style *that, m_styleInstances) {
0160             // don't let ~Style() touch m_styleInstances from here.
0161             that->m_plugin = nullptr;
0162             // each instance should already have disconnected from the D-Bus
0163             // and disconnected from receiving select signals.
0164             if (that->parent()) {
0165                 qtcDebug("Taking back ownership of instance %p from parent %p\n", that, that->parent());
0166                 that->setParent(nullptr);
0167             }
0168             delete that;
0169         }
0170         m_styleInstances.clear();
0171     }
0172     if (firstPlInstance == this) {
0173         firstPlInstance = nullptr;
0174         styleInstances = nullptr;
0175     }
0176 }
0177 
0178 void
0179 StylePlugin::init()
0180 {
0181     std::call_once(m_ref_flag, [this] {
0182             QInternal::registerCallback(QInternal::EventNotifyCallback,
0183                                         qtcEventCallback);
0184             m_eventNotifyCallbackInstalled = true;
0185             if (QCoreApplication::instance()) {
0186                 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &StylePlugin::unregisterCallback);
0187             }
0188 #ifdef QTC_QT5_ENABLE_QTQUICK2
0189             QQuickWindow::setDefaultAlphaBuffer(true);
0190 #endif
0191 #ifdef Qt5X11Extras_FOUND
0192             if (qApp->platformName() == "xcb") {
0193                 qtcX11InitXcb(QX11Info::connection(), QX11Info::appScreen());
0194             }
0195 #endif
0196         });
0197 }
0198 
0199 __attribute__((constructor)) int atLibOpen()
0200 {
0201     qtcDebug("Opening QtCurve\n");
0202     return 0;
0203 }
0204 
0205 __attribute__((destructor)) int atLibClose()
0206 {
0207     qtcInfo("Closing QtCurve\n");
0208     if (firstPlInstance) {
0209         qtcInfo("Plugin instance %p still open with %d open Style instance(s)\n",
0210             firstPlInstance, styleInstances->count());
0211     }
0212     return 0;
0213 }
0214 
0215 }