Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/plugins/platforms/eglfs/qeglfscursor.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||
2 | ** | - | ||||||||||||
3 | ** Copyright (C) 2015 The Qt Company Ltd. | - | ||||||||||||
4 | ** Contact: http://www.qt.io/licensing/ | - | ||||||||||||
5 | ** | - | ||||||||||||
6 | ** This file is part of the plugins of the Qt Toolkit. | - | ||||||||||||
7 | ** | - | ||||||||||||
8 | ** $QT_BEGIN_LICENSE:LGPL21$ | - | ||||||||||||
9 | ** Commercial License Usage | - | ||||||||||||
10 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||
11 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||
12 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||
13 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||
14 | ** and conditions see http://www.qt.io/terms-conditions. For further | - | ||||||||||||
15 | ** information use the contact form at http://www.qt.io/contact-us. | - | ||||||||||||
16 | ** | - | ||||||||||||
17 | ** GNU Lesser General Public License Usage | - | ||||||||||||
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||
19 | ** General Public License version 2.1 or version 3 as published by the Free | - | ||||||||||||
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and | - | ||||||||||||
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the | - | ||||||||||||
22 | ** following information to ensure the GNU Lesser General Public License | - | ||||||||||||
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and | - | ||||||||||||
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | - | ||||||||||||
25 | ** | - | ||||||||||||
26 | ** As a special exception, The Qt Company gives you certain additional | - | ||||||||||||
27 | ** rights. These rights are described in The Qt Company LGPL Exception | - | ||||||||||||
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | - | ||||||||||||
29 | ** | - | ||||||||||||
30 | ** $QT_END_LICENSE$ | - | ||||||||||||
31 | ** | - | ||||||||||||
32 | ****************************************************************************/ | - | ||||||||||||
33 | - | |||||||||||||
34 | #include "qeglfscursor.h" | - | ||||||||||||
35 | #include "qeglfsintegration.h" | - | ||||||||||||
36 | #include "qeglfsscreen.h" | - | ||||||||||||
37 | - | |||||||||||||
38 | #include <qpa/qwindowsysteminterface.h> | - | ||||||||||||
39 | #include <QtGui/QOpenGLContext> | - | ||||||||||||
40 | #include <QtGui/QOpenGLShaderProgram> | - | ||||||||||||
41 | #include <QtCore/QJsonDocument> | - | ||||||||||||
42 | #include <QtCore/QJsonArray> | - | ||||||||||||
43 | #include <QtCore/QJsonObject> | - | ||||||||||||
44 | - | |||||||||||||
45 | #include <QtGui/private/qguiapplication_p.h> | - | ||||||||||||
46 | #include <QtGui/private/qopenglvertexarrayobject_p.h> | - | ||||||||||||
47 | - | |||||||||||||
48 | #ifndef GL_VERTEX_ARRAY_BINDING | - | ||||||||||||
49 | #define GL_VERTEX_ARRAY_BINDING 0x85B5 | - | ||||||||||||
50 | #endif | - | ||||||||||||
51 | - | |||||||||||||
52 | QT_BEGIN_NAMESPACE | - | ||||||||||||
53 | - | |||||||||||||
54 | QEglFSCursor::QEglFSCursor(QPlatformScreen *screen) | - | ||||||||||||
55 | : m_visible(true), | - | ||||||||||||
56 | m_screen(static_cast<QEglFSScreen *>(screen)), | - | ||||||||||||
57 | m_program(0), | - | ||||||||||||
58 | m_textureEntry(0), | - | ||||||||||||
59 | m_deviceListener(0), | - | ||||||||||||
60 | m_updateRequested(false) | - | ||||||||||||
61 | { | - | ||||||||||||
62 | QByteArray hideCursorVal = qgetenv("QT_QPA_EGLFS_HIDECURSOR"); | - | ||||||||||||
63 | if (!hideCursorVal.isEmpty())
| 0 | ||||||||||||
64 | m_visible = hideCursorVal.toInt() == 0; never executed: m_visible = hideCursorVal.toInt() == 0; | 0 | ||||||||||||
65 | if (!m_visible)
| 0 | ||||||||||||
66 | return; never executed: return; | 0 | ||||||||||||
67 | - | |||||||||||||
68 | // Try to load the cursor atlas. If this fails, m_visible is set to false and | - | ||||||||||||
69 | // paintOnScreen() and setCurrentCursor() become no-ops. | - | ||||||||||||
70 | initCursorAtlas(); | - | ||||||||||||
71 | - | |||||||||||||
72 | // initialize the cursor | - | ||||||||||||
73 | #ifndef QT_NO_CURSOR | - | ||||||||||||
74 | QCursor cursor(Qt::ArrowCursor); | - | ||||||||||||
75 | setCurrentCursor(&cursor); | - | ||||||||||||
76 | #endif | - | ||||||||||||
77 | - | |||||||||||||
78 | m_deviceListener = new QEglFSCursorDeviceListener(this); | - | ||||||||||||
79 | connect(QGuiApplicationPrivate::inputDeviceManager(), &QInputDeviceManager::deviceListChanged, | - | ||||||||||||
80 | m_deviceListener, &QEglFSCursorDeviceListener::onDeviceListChanged); | - | ||||||||||||
81 | updateMouseStatus(); | - | ||||||||||||
82 | } never executed: end of block | 0 | ||||||||||||
83 | - | |||||||||||||
84 | QEglFSCursor::~QEglFSCursor() | - | ||||||||||||
85 | { | - | ||||||||||||
86 | resetResources(); | - | ||||||||||||
87 | delete m_deviceListener; | - | ||||||||||||
88 | } never executed: end of block | 0 | ||||||||||||
89 | - | |||||||||||||
90 | void QEglFSCursor::updateMouseStatus() | - | ||||||||||||
91 | { | - | ||||||||||||
92 | m_visible = m_deviceListener->hasMouse(); | - | ||||||||||||
93 | } never executed: end of block | 0 | ||||||||||||
94 | - | |||||||||||||
95 | bool QEglFSCursorDeviceListener::hasMouse() const | - | ||||||||||||
96 | { | - | ||||||||||||
97 | return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(QInputDeviceManager::DeviceTypePointer) > 0; never executed: return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(QInputDeviceManager::DeviceTypePointer) > 0; | 0 | ||||||||||||
98 | } | - | ||||||||||||
99 | - | |||||||||||||
100 | void QEglFSCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::DeviceType type) | - | ||||||||||||
101 | { | - | ||||||||||||
102 | if (type == QInputDeviceManager::DeviceTypePointer)
| 0 | ||||||||||||
103 | m_cursor->updateMouseStatus(); never executed: m_cursor->updateMouseStatus(); | 0 | ||||||||||||
104 | } never executed: end of block | 0 | ||||||||||||
105 | - | |||||||||||||
106 | void QEglFSCursor::resetResources() | - | ||||||||||||
107 | { | - | ||||||||||||
108 | if (QOpenGLContext::currentContext()) {
| 0 | ||||||||||||
109 | delete m_program; | - | ||||||||||||
110 | glDeleteTextures(1, &m_cursor.customCursorTexture); | - | ||||||||||||
111 | glDeleteTextures(1, &m_cursorAtlas.texture); | - | ||||||||||||
112 | } never executed: end of block | 0 | ||||||||||||
113 | m_program = 0; | - | ||||||||||||
114 | m_cursor.customCursorTexture = 0; | - | ||||||||||||
115 | m_cursor.customCursorPending = !m_cursor.customCursorImage.isNull(); | - | ||||||||||||
116 | m_cursorAtlas.texture = 0; | - | ||||||||||||
117 | } never executed: end of block | 0 | ||||||||||||
118 | - | |||||||||||||
119 | void QEglFSCursor::createShaderPrograms() | - | ||||||||||||
120 | { | - | ||||||||||||
121 | static const char *textureVertexProgram = | - | ||||||||||||
122 | "attribute highp vec2 vertexCoordEntry;\n" | - | ||||||||||||
123 | "attribute highp vec2 textureCoordEntry;\n" | - | ||||||||||||
124 | "varying highp vec2 textureCoord;\n" | - | ||||||||||||
125 | "void main() {\n" | - | ||||||||||||
126 | " textureCoord = textureCoordEntry;\n" | - | ||||||||||||
127 | " gl_Position = vec4(vertexCoordEntry, 1.0, 1.0);\n" | - | ||||||||||||
128 | "}\n"; | - | ||||||||||||
129 | - | |||||||||||||
130 | static const char *textureFragmentProgram = | - | ||||||||||||
131 | "uniform sampler2D texture;\n" | - | ||||||||||||
132 | "varying highp vec2 textureCoord;\n" | - | ||||||||||||
133 | "void main() {\n" | - | ||||||||||||
134 | " gl_FragColor = texture2D(texture, textureCoord).bgra;\n" | - | ||||||||||||
135 | "}\n"; | - | ||||||||||||
136 | - | |||||||||||||
137 | m_program = new QOpenGLShaderProgram; | - | ||||||||||||
138 | m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); | - | ||||||||||||
139 | m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); | - | ||||||||||||
140 | m_program->bindAttributeLocation("vertexCoordEntry", 0); | - | ||||||||||||
141 | m_program->bindAttributeLocation("textureCoordEntry", 1); | - | ||||||||||||
142 | m_program->link(); | - | ||||||||||||
143 | - | |||||||||||||
144 | m_textureEntry = m_program->uniformLocation("texture"); | - | ||||||||||||
145 | } never executed: end of block | 0 | ||||||||||||
146 | - | |||||||||||||
147 | void QEglFSCursor::createCursorTexture(uint *texture, const QImage &image) | - | ||||||||||||
148 | { | - | ||||||||||||
149 | if (!*texture)
| 0 | ||||||||||||
150 | glGenTextures(1, texture); never executed: glGenTextures(1, texture); | 0 | ||||||||||||
151 | glBindTexture(GL_TEXTURE_2D, *texture); | - | ||||||||||||
152 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | - | ||||||||||||
153 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | - | ||||||||||||
154 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | - | ||||||||||||
155 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | - | ||||||||||||
156 | - | |||||||||||||
157 | glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */, | - | ||||||||||||
158 | GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); | - | ||||||||||||
159 | } never executed: end of block | 0 | ||||||||||||
160 | - | |||||||||||||
161 | void QEglFSCursor::initCursorAtlas() | - | ||||||||||||
162 | { | - | ||||||||||||
163 | static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR"); | - | ||||||||||||
164 | if (json.isEmpty())
| 0 | ||||||||||||
165 | json = ":/cursor.json"; never executed: json = ":/cursor.json"; | 0 | ||||||||||||
166 | - | |||||||||||||
167 | QFile file(QString::fromUtf8(json)); | - | ||||||||||||
168 | if (!file.open(QFile::ReadOnly)) {
| 0 | ||||||||||||
169 | m_visible = false; | - | ||||||||||||
170 | return; never executed: return; | 0 | ||||||||||||
171 | } | - | ||||||||||||
172 | - | |||||||||||||
173 | QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); | - | ||||||||||||
174 | QJsonObject object = doc.object(); | - | ||||||||||||
175 | - | |||||||||||||
176 | QString atlas = object.value(QLatin1String("image")).toString(); | - | ||||||||||||
177 | Q_ASSERT(!atlas.isEmpty()); | - | ||||||||||||
178 | - | |||||||||||||
179 | const int cursorsPerRow = object.value(QLatin1String("cursorsPerRow")).toDouble(); | - | ||||||||||||
180 | Q_ASSERT(cursorsPerRow); | - | ||||||||||||
181 | m_cursorAtlas.cursorsPerRow = cursorsPerRow; | - | ||||||||||||
182 | - | |||||||||||||
183 | const QJsonArray hotSpots = object.value(QLatin1String("hotSpots")).toArray(); | - | ||||||||||||
184 | Q_ASSERT(hotSpots.count() == Qt::LastCursor + 1); | - | ||||||||||||
185 | for (int i = 0; i < hotSpots.count(); i++) {
| 0 | ||||||||||||
186 | QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble()); | - | ||||||||||||
187 | m_cursorAtlas.hotSpots << hotSpot; | - | ||||||||||||
188 | } never executed: end of block | 0 | ||||||||||||
189 | - | |||||||||||||
190 | QImage image = QImage(atlas).convertToFormat(QImage::Format_ARGB32_Premultiplied); | - | ||||||||||||
191 | m_cursorAtlas.cursorWidth = image.width() / m_cursorAtlas.cursorsPerRow; | - | ||||||||||||
192 | m_cursorAtlas.cursorHeight = image.height() / ((Qt::LastCursor + cursorsPerRow) / cursorsPerRow); | - | ||||||||||||
193 | m_cursorAtlas.width = image.width(); | - | ||||||||||||
194 | m_cursorAtlas.height = image.height(); | - | ||||||||||||
195 | m_cursorAtlas.image = image; | - | ||||||||||||
196 | } never executed: end of block | 0 | ||||||||||||
197 | - | |||||||||||||
198 | #ifndef QT_NO_CURSOR | - | ||||||||||||
199 | void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window) | - | ||||||||||||
200 | { | - | ||||||||||||
201 | Q_UNUSED(window); | - | ||||||||||||
202 | const QRect oldCursorRect = cursorRect(); | - | ||||||||||||
203 | if (setCurrentCursor(cursor))
| 0 | ||||||||||||
204 | update(oldCursorRect | cursorRect()); never executed: update(oldCursorRect | cursorRect()); | 0 | ||||||||||||
205 | } never executed: end of block | 0 | ||||||||||||
206 | - | |||||||||||||
207 | bool QEglFSCursor::setCurrentCursor(QCursor *cursor) | - | ||||||||||||
208 | { | - | ||||||||||||
209 | if (!m_visible)
| 0 | ||||||||||||
210 | return false; never executed: return false; | 0 | ||||||||||||
211 | - | |||||||||||||
212 | const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
| 0 | ||||||||||||
213 | if (m_cursor.shape == newShape && newShape != Qt::BitmapCursor)
| 0 | ||||||||||||
214 | return false; never executed: return false; | 0 | ||||||||||||
215 | - | |||||||||||||
216 | if (m_cursor.shape == Qt::BitmapCursor) {
| 0 | ||||||||||||
217 | m_cursor.customCursorImage = QImage(); | - | ||||||||||||
218 | m_cursor.customCursorPending = false; | - | ||||||||||||
219 | } never executed: end of block | 0 | ||||||||||||
220 | m_cursor.shape = newShape; | - | ||||||||||||
221 | if (newShape != Qt::BitmapCursor) { // standard cursor
| 0 | ||||||||||||
222 | const float ws = (float)m_cursorAtlas.cursorWidth / m_cursorAtlas.width, | - | ||||||||||||
223 | hs = (float)m_cursorAtlas.cursorHeight / m_cursorAtlas.height; | - | ||||||||||||
224 | m_cursor.textureRect = QRectF(ws * (m_cursor.shape % m_cursorAtlas.cursorsPerRow), | - | ||||||||||||
225 | hs * (m_cursor.shape / m_cursorAtlas.cursorsPerRow), | - | ||||||||||||
226 | ws, hs); | - | ||||||||||||
227 | m_cursor.hotSpot = m_cursorAtlas.hotSpots[m_cursor.shape]; | - | ||||||||||||
228 | m_cursor.texture = m_cursorAtlas.texture; | - | ||||||||||||
229 | m_cursor.size = QSize(m_cursorAtlas.cursorWidth, m_cursorAtlas.cursorHeight); | - | ||||||||||||
230 | } else { never executed: end of block | 0 | ||||||||||||
231 | QImage image = cursor->pixmap().toImage(); | - | ||||||||||||
232 | m_cursor.textureRect = QRectF(0, 0, 1, 1); | - | ||||||||||||
233 | m_cursor.hotSpot = cursor->hotSpot(); | - | ||||||||||||
234 | m_cursor.texture = 0; // will get updated in the next render() | - | ||||||||||||
235 | m_cursor.size = image.size(); | - | ||||||||||||
236 | m_cursor.customCursorImage = image; | - | ||||||||||||
237 | m_cursor.customCursorPending = true; | - | ||||||||||||
238 | } never executed: end of block | 0 | ||||||||||||
239 | - | |||||||||||||
240 | return true; never executed: return true; | 0 | ||||||||||||
241 | } | - | ||||||||||||
242 | #endif | - | ||||||||||||
243 | - | |||||||||||||
244 | class CursorUpdateEvent : public QEvent | - | ||||||||||||
245 | { | - | ||||||||||||
246 | public: | - | ||||||||||||
247 | CursorUpdateEvent(const QPoint &pos, const QRegion &rgn) | - | ||||||||||||
248 | : QEvent(QEvent::Type(QEvent::User + 1)), | - | ||||||||||||
249 | m_pos(pos), | - | ||||||||||||
250 | m_region(rgn) | - | ||||||||||||
251 | { } never executed: end of block | 0 | ||||||||||||
252 | QPoint pos() const { return m_pos; } never executed: return m_pos; | 0 | ||||||||||||
253 | QRegion region() const { return m_region; } never executed: return m_region; | 0 | ||||||||||||
254 | - | |||||||||||||
255 | private: | - | ||||||||||||
256 | QPoint m_pos; | - | ||||||||||||
257 | QRegion m_region; | - | ||||||||||||
258 | }; | - | ||||||||||||
259 | - | |||||||||||||
260 | bool QEglFSCursor::event(QEvent *e) | - | ||||||||||||
261 | { | - | ||||||||||||
262 | if (e->type() == QEvent::User + 1) {
| 0 | ||||||||||||
263 | CursorUpdateEvent *ev = static_cast<CursorUpdateEvent *>(e); | - | ||||||||||||
264 | m_updateRequested = false; | - | ||||||||||||
265 | QWindowSystemInterface::handleExposeEvent(m_screen->topLevelAt(ev->pos()), ev->region()); | - | ||||||||||||
266 | QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); | - | ||||||||||||
267 | return true; never executed: return true; | 0 | ||||||||||||
268 | } | - | ||||||||||||
269 | return QPlatformCursor::event(e); never executed: return QPlatformCursor::event(e); | 0 | ||||||||||||
270 | } | - | ||||||||||||
271 | - | |||||||||||||
272 | void QEglFSCursor::update(const QRegion &rgn) | - | ||||||||||||
273 | { | - | ||||||||||||
274 | if (!m_updateRequested) {
| 0 | ||||||||||||
275 | // Must not flush the window system events directly from here since we are likely to | - | ||||||||||||
276 | // be a called directly from QGuiApplication's processMouseEvents. Flushing events | - | ||||||||||||
277 | // could cause reentering by dispatching more queued mouse events. | - | ||||||||||||
278 | m_updateRequested = true; | - | ||||||||||||
279 | QCoreApplication::postEvent(this, new CursorUpdateEvent(m_cursor.pos, rgn)); | - | ||||||||||||
280 | } never executed: end of block | 0 | ||||||||||||
281 | } never executed: end of block | 0 | ||||||||||||
282 | - | |||||||||||||
283 | QRect QEglFSCursor::cursorRect() const | - | ||||||||||||
284 | { | - | ||||||||||||
285 | return QRect(m_cursor.pos - m_cursor.hotSpot, m_cursor.size); never executed: return QRect(m_cursor.pos - m_cursor.hotSpot, m_cursor.size); | 0 | ||||||||||||
286 | } | - | ||||||||||||
287 | - | |||||||||||||
288 | QPoint QEglFSCursor::pos() const | - | ||||||||||||
289 | { | - | ||||||||||||
290 | return m_cursor.pos; never executed: return m_cursor.pos; | 0 | ||||||||||||
291 | } | - | ||||||||||||
292 | - | |||||||||||||
293 | void QEglFSCursor::setPos(const QPoint &pos) | - | ||||||||||||
294 | { | - | ||||||||||||
295 | QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos); | - | ||||||||||||
296 | const QRect oldCursorRect = cursorRect(); | - | ||||||||||||
297 | m_cursor.pos = pos; | - | ||||||||||||
298 | update(oldCursorRect | cursorRect()); | - | ||||||||||||
299 | m_screen->handleCursorMove(m_cursor.pos); | - | ||||||||||||
300 | } never executed: end of block | 0 | ||||||||||||
301 | - | |||||||||||||
302 | void QEglFSCursor::pointerEvent(const QMouseEvent &event) | - | ||||||||||||
303 | { | - | ||||||||||||
304 | if (event.type() != QEvent::MouseMove)
| 0 | ||||||||||||
305 | return; never executed: return; | 0 | ||||||||||||
306 | const QRect oldCursorRect = cursorRect(); | - | ||||||||||||
307 | m_cursor.pos = event.screenPos().toPoint(); | - | ||||||||||||
308 | update(oldCursorRect | cursorRect()); | - | ||||||||||||
309 | m_screen->handleCursorMove(m_cursor.pos); | - | ||||||||||||
310 | } never executed: end of block | 0 | ||||||||||||
311 | - | |||||||||||||
312 | void QEglFSCursor::paintOnScreen() | - | ||||||||||||
313 | { | - | ||||||||||||
314 | if (!m_visible)
| 0 | ||||||||||||
315 | return; never executed: return; | 0 | ||||||||||||
316 | - | |||||||||||||
317 | const QRectF cr = cursorRect(); | - | ||||||||||||
318 | const QRect screenRect(m_screen->geometry()); | - | ||||||||||||
319 | const GLfloat x1 = 2 * (cr.left() / screenRect.width()) - 1; | - | ||||||||||||
320 | const GLfloat x2 = 2 * (cr.right() / screenRect.width()) - 1; | - | ||||||||||||
321 | const GLfloat y1 = 1 - (cr.top() / screenRect.height()) * 2; | - | ||||||||||||
322 | const GLfloat y2 = 1 - (cr.bottom() / screenRect.height()) * 2; | - | ||||||||||||
323 | QRectF r(QPointF(x1, y1), QPointF(x2, y2)); | - | ||||||||||||
324 | - | |||||||||||||
325 | draw(r); | - | ||||||||||||
326 | } never executed: end of block | 0 | ||||||||||||
327 | - | |||||||||||||
328 | // In order to prevent breaking code doing custom OpenGL rendering while | - | ||||||||||||
329 | // expecting the state in the context unchanged, save and restore all the state | - | ||||||||||||
330 | // we touch. The exception is Qt Quick where the scenegraph is known to be able | - | ||||||||||||
331 | // to deal with the changes we make. | - | ||||||||||||
332 | struct StateSaver | - | ||||||||||||
333 | { | - | ||||||||||||
334 | StateSaver() { | - | ||||||||||||
335 | f = QOpenGLContext::currentContext()->functions(); | - | ||||||||||||
336 | vaoHelper = new QOpenGLVertexArrayObjectHelper(QOpenGLContext::currentContext()); | - | ||||||||||||
337 | - | |||||||||||||
338 | static bool windowsChecked = false; | - | ||||||||||||
339 | static bool shouldSave = true; | - | ||||||||||||
340 | if (!windowsChecked) {
| 0 | ||||||||||||
341 | windowsChecked = true; | - | ||||||||||||
342 | QWindowList windows = QGuiApplication::allWindows(); | - | ||||||||||||
343 | if (!windows.isEmpty() && windows[0]->inherits("QQuickWindow"))
| 0 | ||||||||||||
344 | shouldSave = false; never executed: shouldSave = false; | 0 | ||||||||||||
345 | } never executed: end of block | 0 | ||||||||||||
346 | saved = shouldSave; | - | ||||||||||||
347 | if (!shouldSave)
| 0 | ||||||||||||
348 | return; never executed: return; | 0 | ||||||||||||
349 | - | |||||||||||||
350 | f->glGetIntegerv(GL_CURRENT_PROGRAM, &program); | - | ||||||||||||
351 | f->glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); | - | ||||||||||||
352 | f->glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture); | - | ||||||||||||
353 | f->glGetIntegerv(GL_FRONT_FACE, &frontFace); | - | ||||||||||||
354 | cull = f->glIsEnabled(GL_CULL_FACE); | - | ||||||||||||
355 | depthTest = f->glIsEnabled(GL_DEPTH_TEST); | - | ||||||||||||
356 | blend = f->glIsEnabled(GL_BLEND); | - | ||||||||||||
357 | f->glGetIntegerv(GL_BLEND_SRC_RGB, blendFunc); | - | ||||||||||||
358 | f->glGetIntegerv(GL_BLEND_SRC_ALPHA, blendFunc + 1); | - | ||||||||||||
359 | f->glGetIntegerv(GL_BLEND_DST_RGB, blendFunc + 2); | - | ||||||||||||
360 | f->glGetIntegerv(GL_BLEND_DST_ALPHA, blendFunc + 3); | - | ||||||||||||
361 | f->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBuf); | - | ||||||||||||
362 | if (vaoHelper->isValid())
| 0 | ||||||||||||
363 | f->glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao); never executed: f->glGetIntegerv(0x85B5, &vao); | 0 | ||||||||||||
364 | for (int i = 0; i < 2; ++i) {
| 0 | ||||||||||||
365 | f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &va[i].enabled); | - | ||||||||||||
366 | f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &va[i].size); | - | ||||||||||||
367 | f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &va[i].type); | - | ||||||||||||
368 | f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &va[i].normalized); | - | ||||||||||||
369 | f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &va[i].stride); | - | ||||||||||||
370 | f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &va[i].buffer); | - | ||||||||||||
371 | f->glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &va[i].pointer); | - | ||||||||||||
372 | } never executed: end of block | 0 | ||||||||||||
373 | } never executed: end of block | 0 | ||||||||||||
374 | ~StateSaver() { | - | ||||||||||||
375 | if (saved) {
| 0 | ||||||||||||
376 | f->glUseProgram(program); | - | ||||||||||||
377 | f->glBindTexture(GL_TEXTURE_2D, texture); | - | ||||||||||||
378 | f->glActiveTexture(activeTexture); | - | ||||||||||||
379 | f->glFrontFace(frontFace); | - | ||||||||||||
380 | if (cull)
| 0 | ||||||||||||
381 | f->glEnable(GL_CULL_FACE); never executed: f->glEnable(0x0B44); | 0 | ||||||||||||
382 | else | - | ||||||||||||
383 | f->glDisable(GL_CULL_FACE); never executed: f->glDisable(0x0B44); | 0 | ||||||||||||
384 | if (depthTest)
| 0 | ||||||||||||
385 | f->glEnable(GL_DEPTH_TEST); never executed: f->glEnable(0x0B71); | 0 | ||||||||||||
386 | else | - | ||||||||||||
387 | f->glDisable(GL_DEPTH_TEST); never executed: f->glDisable(0x0B71); | 0 | ||||||||||||
388 | if (blend)
| 0 | ||||||||||||
389 | f->glEnable(GL_BLEND); never executed: f->glEnable(0x0BE2); | 0 | ||||||||||||
390 | else | - | ||||||||||||
391 | f->glDisable(GL_BLEND); never executed: f->glDisable(0x0BE2); | 0 | ||||||||||||
392 | f->glBlendFuncSeparate(blendFunc[0], blendFunc[1], blendFunc[2], blendFunc[3]); | - | ||||||||||||
393 | f->glBindBuffer(GL_ARRAY_BUFFER, arrayBuf); | - | ||||||||||||
394 | if (vaoHelper->isValid())
| 0 | ||||||||||||
395 | vaoHelper->glBindVertexArray(vao); never executed: vaoHelper->glBindVertexArray(vao); | 0 | ||||||||||||
396 | for (int i = 0; i < 2; ++i) {
| 0 | ||||||||||||
397 | if (va[i].enabled)
| 0 | ||||||||||||
398 | f->glEnableVertexAttribArray(i); never executed: f->glEnableVertexAttribArray(i); | 0 | ||||||||||||
399 | else | - | ||||||||||||
400 | f->glDisableVertexAttribArray(i); never executed: f->glDisableVertexAttribArray(i); | 0 | ||||||||||||
401 | f->glBindBuffer(GL_ARRAY_BUFFER, va[i].buffer); | - | ||||||||||||
402 | f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer); | - | ||||||||||||
403 | } never executed: end of block | 0 | ||||||||||||
404 | } never executed: end of block | 0 | ||||||||||||
405 | delete vaoHelper; | - | ||||||||||||
406 | } never executed: end of block | 0 | ||||||||||||
407 | QOpenGLFunctions *f; | - | ||||||||||||
408 | QOpenGLVertexArrayObjectHelper *vaoHelper; | - | ||||||||||||
409 | bool saved; | - | ||||||||||||
410 | GLint program; | - | ||||||||||||
411 | GLint texture; | - | ||||||||||||
412 | GLint activeTexture; | - | ||||||||||||
413 | GLint frontFace; | - | ||||||||||||
414 | bool cull; | - | ||||||||||||
415 | bool depthTest; | - | ||||||||||||
416 | bool blend; | - | ||||||||||||
417 | GLint blendFunc[4]; | - | ||||||||||||
418 | GLint vao; | - | ||||||||||||
419 | GLint arrayBuf; | - | ||||||||||||
420 | struct { GLint enabled, type, size, normalized, stride, buffer; GLvoid *pointer; } va[2]; | - | ||||||||||||
421 | }; | - | ||||||||||||
422 | - | |||||||||||||
423 | void QEglFSCursor::draw(const QRectF &r) | - | ||||||||||||
424 | { | - | ||||||||||||
425 | StateSaver stateSaver; | - | ||||||||||||
426 | - | |||||||||||||
427 | if (!m_program) {
| 0 | ||||||||||||
428 | // one time initialization | - | ||||||||||||
429 | initializeOpenGLFunctions(); | - | ||||||||||||
430 | - | |||||||||||||
431 | createShaderPrograms(); | - | ||||||||||||
432 | - | |||||||||||||
433 | if (!m_cursorAtlas.texture) {
| 0 | ||||||||||||
434 | createCursorTexture(&m_cursorAtlas.texture, m_cursorAtlas.image); | - | ||||||||||||
435 | - | |||||||||||||
436 | if (m_cursor.shape != Qt::BitmapCursor)
| 0 | ||||||||||||
437 | m_cursor.texture = m_cursorAtlas.texture; never executed: m_cursor.texture = m_cursorAtlas.texture; | 0 | ||||||||||||
438 | } never executed: end of block | 0 | ||||||||||||
439 | } never executed: end of block | 0 | ||||||||||||
440 | - | |||||||||||||
441 | if (m_cursor.shape == Qt::BitmapCursor && m_cursor.customCursorPending) {
| 0 | ||||||||||||
442 | // upload the custom cursor | - | ||||||||||||
443 | createCursorTexture(&m_cursor.customCursorTexture, m_cursor.customCursorImage); | - | ||||||||||||
444 | m_cursor.texture = m_cursor.customCursorTexture; | - | ||||||||||||
445 | m_cursor.customCursorPending = false; | - | ||||||||||||
446 | } never executed: end of block | 0 | ||||||||||||
447 | - | |||||||||||||
448 | Q_ASSERT(m_cursor.texture); | - | ||||||||||||
449 | - | |||||||||||||
450 | m_program->bind(); | - | ||||||||||||
451 | - | |||||||||||||
452 | const GLfloat x1 = r.left(); | - | ||||||||||||
453 | const GLfloat x2 = r.right(); | - | ||||||||||||
454 | const GLfloat y1 = r.top(); | - | ||||||||||||
455 | const GLfloat y2 = r.bottom(); | - | ||||||||||||
456 | const GLfloat cursorCoordinates[] = { | - | ||||||||||||
457 | x1, y2, | - | ||||||||||||
458 | x2, y2, | - | ||||||||||||
459 | x1, y1, | - | ||||||||||||
460 | x2, y1 | - | ||||||||||||
461 | }; | - | ||||||||||||
462 | - | |||||||||||||
463 | const GLfloat s1 = m_cursor.textureRect.left(); | - | ||||||||||||
464 | const GLfloat s2 = m_cursor.textureRect.right(); | - | ||||||||||||
465 | const GLfloat t1 = m_cursor.textureRect.top(); | - | ||||||||||||
466 | const GLfloat t2 = m_cursor.textureRect.bottom(); | - | ||||||||||||
467 | const GLfloat textureCoordinates[] = { | - | ||||||||||||
468 | s1, t2, | - | ||||||||||||
469 | s2, t2, | - | ||||||||||||
470 | s1, t1, | - | ||||||||||||
471 | s2, t1 | - | ||||||||||||
472 | }; | - | ||||||||||||
473 | - | |||||||||||||
474 | glActiveTexture(GL_TEXTURE0); | - | ||||||||||||
475 | glBindTexture(GL_TEXTURE_2D, m_cursor.texture); | - | ||||||||||||
476 | - | |||||||||||||
477 | if (stateSaver.vaoHelper->isValid())
| 0 | ||||||||||||
478 | stateSaver.vaoHelper->glBindVertexArray(0); never executed: stateSaver.vaoHelper->glBindVertexArray(0); | 0 | ||||||||||||
479 | - | |||||||||||||
480 | glBindBuffer(GL_ARRAY_BUFFER, 0); | - | ||||||||||||
481 | - | |||||||||||||
482 | m_program->enableAttributeArray(0); | - | ||||||||||||
483 | m_program->enableAttributeArray(1); | - | ||||||||||||
484 | m_program->setAttributeArray(0, cursorCoordinates, 2); | - | ||||||||||||
485 | m_program->setAttributeArray(1, textureCoordinates, 2); | - | ||||||||||||
486 | - | |||||||||||||
487 | m_program->setUniformValue(m_textureEntry, 0); | - | ||||||||||||
488 | - | |||||||||||||
489 | glDisable(GL_CULL_FACE); | - | ||||||||||||
490 | glFrontFace(GL_CCW); | - | ||||||||||||
491 | glEnable(GL_BLEND); | - | ||||||||||||
492 | glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); | - | ||||||||||||
493 | glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top | - | ||||||||||||
494 | - | |||||||||||||
495 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | - | ||||||||||||
496 | - | |||||||||||||
497 | m_program->disableAttributeArray(0); | - | ||||||||||||
498 | m_program->disableAttributeArray(1); | - | ||||||||||||
499 | m_program->release(); | - | ||||||||||||
500 | } never executed: end of block | 0 | ||||||||||||
501 | - | |||||||||||||
502 | QT_END_NAMESPACE | - | ||||||||||||
Source code | Switch to Preprocessed file |