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 }