1 /*****************************************************************************
2 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU Lesser General Public License as *
6 * published by the Free Software Foundation; either version 2.1 of the *
7 * License, or (at your option) version 3, or any later version accepted *
8 * by the membership of KDE e.V. (or its successor approved by the *
9 * membership of KDE e.V.), which shall act as a proxy defined in *
10 * Section 6 of version 3 of the license. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with this library. If not, *
19 * see <http://www.gnu.org/licenses/>. *
20 *****************************************************************************/
21
22 #include "qtcurve_plugin.h"
23 #include "qtcurve.h"
24
25 #include "config-qt5.h"
26
27 #include <qtcurve-utils/qtprops.h>
28 #include <qtcurve-utils/x11shadow.h>
29 #include <qtcurve-utils/x11blur.h>
30
31 #include <QApplication>
32
33 #ifdef Qt5X11Extras_FOUND
34 # include <qtcurve-utils/x11base.h>
35 # include <QX11Info>
36 #endif
37
38 #ifdef QTC_QT5_ENABLE_QTQUICK2
39 # include <QQuickWindow>
40 # include <QQuickItem>
41 #endif
42 #include <QDebug>
43
44 #include <qtcurve-utils/log.h>
45
46 namespace QtCurve {
47
48 __attribute__((hot)) static void
polishQuickControl(QObject * obj)49 polishQuickControl(QObject *obj)
50 {
51 #ifdef QTC_QT5_ENABLE_QTQUICK2
52 if (QQuickWindow *window = qobject_cast<QQuickWindow*>(obj)) {
53 // QtQuickControl support
54 // This is still VERY experimental.
55 // Need a lot more testing and refactoring.
56 if (Style *style = getStyle(qApp)) {
57 if (window->inherits("QQuickPopupWindow")) {
58 if (window->inherits("QQuickMenuPopupWindow")) {
59 window->setColor(QColor(0, 0, 0, 0));
60 }
61 qtcX11ShadowInstall(window->winId());
62 } else {
63 QColor color = window->color();
64 int opacity = style->options().bgndOpacity;
65 if (color.alpha() == 255 && opacity != 100) {
66 qreal opacityF = opacity / 100.0;
67 window->setColor(QColor::fromRgbF(color.redF() * opacityF,
68 color.greenF() * opacityF,
69 color.blueF() * opacityF,
70 opacityF));
71 qtcX11BlurTrigger(window->winId(), true, 0, nullptr);
72 }
73 }
74 }
75 } else if (QQuickItem *item = qobject_cast<QQuickItem*>(obj)) {
76 if (QQuickWindow *window = item->window()) {
77 if (getStyle(qApp)) {
78 window->setColor(QColor(0, 0, 0, 0));
79 qtcX11BlurTrigger(window->winId(), true, 0, nullptr);
80 }
81 }
82 }
83 #else
84 QTC_UNUSED(obj);
85 #endif
86 }
87
88 __attribute__((hot)) static bool
qtcEventCallback(void ** cbdata)89 qtcEventCallback(void **cbdata)
90 {
91 QObject *receiver = (QObject*)cbdata[0];
92 QTC_RET_IF_FAIL(receiver, false);
93 QEvent *event = (QEvent*)cbdata[1];
94 if (qtcUnlikely(event->type() == QEvent::DynamicPropertyChange)) {
95 QDynamicPropertyChangeEvent *prop_event =
96 static_cast<QDynamicPropertyChangeEvent*>(event);
97 // eat the property change events from ourselves
98 if (prop_event->propertyName() == QTC_PROP_NAME) {
99 return true;
100 }
101 }
102 QWidget *widget = qtcToWidget(receiver);
103 if (qtcUnlikely(widget && !qtcGetWid(widget))) {
104 if (Style *style = getStyle(widget)) {
105 style->prePolish(widget);
106 }
107 } else if (widget && event->type() == QEvent::UpdateRequest) {
108 QtcQWidgetProps props(widget);
109 props->opacity = 100;
110 } else {
111 polishQuickControl(receiver);
112 }
113 return false;
114 }
115
116 static StylePlugin *firstPlInstance = nullptr;
117 static QList<Style*> *styleInstances = nullptr;
118
119 QStyle*
create(const QString & key)120 StylePlugin::create(const QString &key)
121 {
122 if (!firstPlInstance) {
123 firstPlInstance = this;
124 styleInstances = &m_styleInstances;
125 }
126
127 init();
128 Style *qtc;
129 if (key.toLower() == "qtcurve") {
130 qtc = new Style;
131 qtc->m_plugin = this;
132 m_styleInstances << qtc;
133 } else {
134 qtc = nullptr;
135 }
136 return qtc;
137 }
138
unregisterCallback()139 void StylePlugin::unregisterCallback()
140 {
141 if (m_eventNotifyCallbackInstalled) {
142 qtcInfo("Unregistering the event notify callback (for plugin %p)\n", this);
143 QInternal::unregisterCallback(QInternal::EventNotifyCallback,
144 qtcEventCallback);
145 m_eventNotifyCallbackInstalled = false;
146 }
147 }
148
~StylePlugin()149 StylePlugin::~StylePlugin()
150 {
151 qtcInfo("Deleting QtCurve plugin (%p)\n", this);
152 if (!m_styleInstances.isEmpty()) {
153 qtcWarn("there remain(s) %d Style instance(s)\n", m_styleInstances.count());
154 QList<Style*>::Iterator it = m_styleInstances.begin();
155 while (it != m_styleInstances.end()) {
156 Style *that = *it;
157 it = m_styleInstances.erase(it);
158 delete that;
159 }
160 }
161 if (firstPlInstance == this) {
162 firstPlInstance = nullptr;
163 styleInstances = nullptr;
164 }
165 }
166
167 void
init()168 StylePlugin::init()
169 {
170 std::call_once(m_ref_flag, [this] {
171 QInternal::registerCallback(QInternal::EventNotifyCallback,
172 qtcEventCallback);
173 m_eventNotifyCallbackInstalled = true;
174 if (QCoreApplication::instance()) {
175 connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &StylePlugin::unregisterCallback);
176 }
177 #ifdef QTC_QT5_ENABLE_QTQUICK2
178 QQuickWindow::setDefaultAlphaBuffer(true);
179 #endif
180 #ifdef Qt5X11Extras_FOUND
181 if (qApp->platformName() == "xcb") {
182 qtcX11InitXcb(QX11Info::connection(), QX11Info::appScreen());
183 }
184 #endif
185 });
186 }
187
atLibOpen()188 __attribute__((constructor)) int atLibOpen()
189 {
190 qtcDebug("Opening QtCurve\n");
191 return 0;
192 }
193
atLibClose()194 __attribute__((destructor)) int atLibClose()
195 {
196 qtcInfo("Closing QtCurve\n");
197 if (firstPlInstance) {
198 qtcInfo("Plugin instance %p still open with %d open Style instance(s)\n",
199 firstPlInstance, styleInstances->count());
200 }
201 return 0;
202 }
203
204 }
205