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