summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/qeglfscursor.cpp
diff options
context:
space:
mode:
authorGiulio Camuffo <giulio.camuffo@kdab.com>2016-05-27 11:04:03 +0300
committerGiulio Camuffo <giulio.camuffo@kdab.com>2016-06-03 09:19:05 +0000
commitec4eb4db61094179bc6a9ec26ec68fb710177053 (patch)
treec593d4e815ff6f1cc149ad5eaf206b825c316b0b /src/plugins/platforms/eglfs/qeglfscursor.cpp
parent3ec57107cedb154f256e3ad001ea5475cc64fa94 (diff)
Install some eglfsdeviceintegration headers, as a private module
This allows external integrations to be developed against it. Also uniforms all class names as QEglFSFoo. Change-Id: I72ff37c0fcdf1ccd37110b4c36874d6c99b2e743 Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms/eglfs/qeglfscursor.cpp')
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.cpp509
1 files changed, 0 insertions, 509 deletions
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp
deleted file mode 100644
index 6c8c35b1dc..0000000000
--- a/src/plugins/platforms/eglfs/qeglfscursor.cpp
+++ /dev/null
@@ -1,509 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qeglfscursor.h"
-#include "qeglfsintegration.h"
-#include "qeglfsscreen.h"
-
-#include <qpa/qwindowsysteminterface.h>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QOpenGLShaderProgram>
-#include <QtCore/QFile>
-#include <QtCore/QJsonDocument>
-#include <QtCore/QJsonArray>
-#include <QtCore/QJsonObject>
-
-#include <QtGui/private/qguiapplication_p.h>
-#include <QtGui/private/qopenglvertexarrayobject_p.h>
-
-#ifndef GL_VERTEX_ARRAY_BINDING
-#define GL_VERTEX_ARRAY_BINDING 0x85B5
-#endif
-
-QT_BEGIN_NAMESPACE
-
-QEglFSCursor::QEglFSCursor(QPlatformScreen *screen)
- : m_visible(true),
- m_screen(static_cast<QEglFSScreen *>(screen)),
- m_program(0),
- m_textureEntry(0),
- m_deviceListener(0),
- m_updateRequested(false)
-{
- QByteArray hideCursorVal = qgetenv("QT_QPA_EGLFS_HIDECURSOR");
- if (!hideCursorVal.isEmpty())
- m_visible = hideCursorVal.toInt() == 0;
- if (!m_visible)
- return;
-
- // Try to load the cursor atlas. If this fails, m_visible is set to false and
- // paintOnScreen() and setCurrentCursor() become no-ops.
- initCursorAtlas();
-
- // initialize the cursor
-#ifndef QT_NO_CURSOR
- QCursor cursor(Qt::ArrowCursor);
- setCurrentCursor(&cursor);
-#endif
-
- m_deviceListener = new QEglFSCursorDeviceListener(this);
- connect(QGuiApplicationPrivate::inputDeviceManager(), &QInputDeviceManager::deviceListChanged,
- m_deviceListener, &QEglFSCursorDeviceListener::onDeviceListChanged);
- updateMouseStatus();
-}
-
-QEglFSCursor::~QEglFSCursor()
-{
- resetResources();
- delete m_deviceListener;
-}
-
-void QEglFSCursor::updateMouseStatus()
-{
- m_visible = m_deviceListener->hasMouse();
-}
-
-bool QEglFSCursorDeviceListener::hasMouse() const
-{
- return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(QInputDeviceManager::DeviceTypePointer) > 0;
-}
-
-void QEglFSCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::DeviceType type)
-{
- if (type == QInputDeviceManager::DeviceTypePointer)
- m_cursor->updateMouseStatus();
-}
-
-void QEglFSCursor::resetResources()
-{
- if (QOpenGLContext::currentContext()) {
- delete m_program;
- glDeleteTextures(1, &m_cursor.customCursorTexture);
- glDeleteTextures(1, &m_cursorAtlas.texture);
- }
- m_program = 0;
- m_cursor.customCursorTexture = 0;
- m_cursor.customCursorPending = !m_cursor.customCursorImage.isNull();
- m_cursorAtlas.texture = 0;
-}
-
-void QEglFSCursor::createShaderPrograms()
-{
- static const char *textureVertexProgram =
- "attribute highp vec2 vertexCoordEntry;\n"
- "attribute highp vec2 textureCoordEntry;\n"
- "varying highp vec2 textureCoord;\n"
- "void main() {\n"
- " textureCoord = textureCoordEntry;\n"
- " gl_Position = vec4(vertexCoordEntry, 1.0, 1.0);\n"
- "}\n";
-
- static const char *textureFragmentProgram =
- "uniform sampler2D texture;\n"
- "varying highp vec2 textureCoord;\n"
- "void main() {\n"
- " gl_FragColor = texture2D(texture, textureCoord).bgra;\n"
- "}\n";
-
- m_program = new QOpenGLShaderProgram;
- m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
- m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
- m_program->bindAttributeLocation("vertexCoordEntry", 0);
- m_program->bindAttributeLocation("textureCoordEntry", 1);
- m_program->link();
-
- m_textureEntry = m_program->uniformLocation("texture");
-}
-
-void QEglFSCursor::createCursorTexture(uint *texture, const QImage &image)
-{
- if (!*texture)
- glGenTextures(1, texture);
- glBindTexture(GL_TEXTURE_2D, *texture);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */,
- GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
-}
-
-void QEglFSCursor::initCursorAtlas()
-{
- static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR");
- if (json.isEmpty())
- json = ":/cursor.json";
-
- QFile file(QString::fromUtf8(json));
- if (!file.open(QFile::ReadOnly)) {
- m_visible = false;
- return;
- }
-
- QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
- QJsonObject object = doc.object();
-
- QString atlas = object.value(QLatin1String("image")).toString();
- Q_ASSERT(!atlas.isEmpty());
-
- const int cursorsPerRow = object.value(QLatin1String("cursorsPerRow")).toDouble();
- Q_ASSERT(cursorsPerRow);
- m_cursorAtlas.cursorsPerRow = cursorsPerRow;
-
- const QJsonArray hotSpots = object.value(QLatin1String("hotSpots")).toArray();
- Q_ASSERT(hotSpots.count() == Qt::LastCursor + 1);
- for (int i = 0; i < hotSpots.count(); i++) {
- QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble());
- m_cursorAtlas.hotSpots << hotSpot;
- }
-
- QImage image = QImage(atlas).convertToFormat(QImage::Format_ARGB32_Premultiplied);
- m_cursorAtlas.cursorWidth = image.width() / m_cursorAtlas.cursorsPerRow;
- m_cursorAtlas.cursorHeight = image.height() / ((Qt::LastCursor + cursorsPerRow) / cursorsPerRow);
- m_cursorAtlas.width = image.width();
- m_cursorAtlas.height = image.height();
- m_cursorAtlas.image = image;
-}
-
-#ifndef QT_NO_CURSOR
-void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window)
-{
- Q_UNUSED(window);
- const QRect oldCursorRect = cursorRect();
- if (setCurrentCursor(cursor))
- update(oldCursorRect | cursorRect());
-}
-
-bool QEglFSCursor::setCurrentCursor(QCursor *cursor)
-{
- if (!m_visible)
- return false;
-
- const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
- if (m_cursor.shape == newShape && newShape != Qt::BitmapCursor)
- return false;
-
- if (m_cursor.shape == Qt::BitmapCursor) {
- m_cursor.customCursorImage = QImage();
- m_cursor.customCursorPending = false;
- }
- m_cursor.shape = newShape;
- if (newShape != Qt::BitmapCursor) { // standard cursor
- const float ws = (float)m_cursorAtlas.cursorWidth / m_cursorAtlas.width,
- hs = (float)m_cursorAtlas.cursorHeight / m_cursorAtlas.height;
- m_cursor.textureRect = QRectF(ws * (m_cursor.shape % m_cursorAtlas.cursorsPerRow),
- hs * (m_cursor.shape / m_cursorAtlas.cursorsPerRow),
- ws, hs);
- m_cursor.hotSpot = m_cursorAtlas.hotSpots[m_cursor.shape];
- m_cursor.texture = m_cursorAtlas.texture;
- m_cursor.size = QSize(m_cursorAtlas.cursorWidth, m_cursorAtlas.cursorHeight);
- } else {
- QImage image = cursor->pixmap().toImage();
- m_cursor.textureRect = QRectF(0, 0, 1, 1);
- m_cursor.hotSpot = cursor->hotSpot();
- m_cursor.texture = 0; // will get updated in the next render()
- m_cursor.size = image.size();
- m_cursor.customCursorImage = image;
- m_cursor.customCursorPending = true;
- }
-
- return true;
-}
-#endif
-
-class CursorUpdateEvent : public QEvent
-{
-public:
- CursorUpdateEvent(const QPoint &pos, const QRegion &rgn)
- : QEvent(QEvent::Type(QEvent::User + 1)),
- m_pos(pos),
- m_region(rgn)
- { }
- QPoint pos() const { return m_pos; }
- QRegion region() const { return m_region; }
-
-private:
- QPoint m_pos;
- QRegion m_region;
-};
-
-bool QEglFSCursor::event(QEvent *e)
-{
- if (e->type() == QEvent::User + 1) {
- CursorUpdateEvent *ev = static_cast<CursorUpdateEvent *>(e);
- m_updateRequested = false;
- QWindowSystemInterface::handleExposeEvent(m_screen->topLevelAt(ev->pos()), ev->region());
- QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
- return true;
- }
- return QPlatformCursor::event(e);
-}
-
-void QEglFSCursor::update(const QRegion &rgn)
-{
- if (!m_updateRequested) {
- // Must not flush the window system events directly from here since we are likely to
- // be a called directly from QGuiApplication's processMouseEvents. Flushing events
- // could cause reentering by dispatching more queued mouse events.
- m_updateRequested = true;
- QCoreApplication::postEvent(this, new CursorUpdateEvent(m_cursor.pos, rgn));
- }
-}
-
-QRect QEglFSCursor::cursorRect() const
-{
- return QRect(m_cursor.pos - m_cursor.hotSpot, m_cursor.size);
-}
-
-QPoint QEglFSCursor::pos() const
-{
- return m_cursor.pos;
-}
-
-void QEglFSCursor::setPos(const QPoint &pos)
-{
- QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos);
- const QRect oldCursorRect = cursorRect();
- m_cursor.pos = pos;
- update(oldCursorRect | cursorRect());
- m_screen->handleCursorMove(m_cursor.pos);
-}
-
-void QEglFSCursor::pointerEvent(const QMouseEvent &event)
-{
- if (event.type() != QEvent::MouseMove)
- return;
- const QRect oldCursorRect = cursorRect();
- m_cursor.pos = event.screenPos().toPoint();
- update(oldCursorRect | cursorRect());
- m_screen->handleCursorMove(m_cursor.pos);
-}
-
-void QEglFSCursor::paintOnScreen()
-{
- if (!m_visible)
- return;
-
- const QRectF cr = cursorRect();
- const QRect screenRect(m_screen->geometry());
- const GLfloat x1 = 2 * (cr.left() / screenRect.width()) - 1;
- const GLfloat x2 = 2 * (cr.right() / screenRect.width()) - 1;
- const GLfloat y1 = 1 - (cr.top() / screenRect.height()) * 2;
- const GLfloat y2 = 1 - (cr.bottom() / screenRect.height()) * 2;
- QRectF r(QPointF(x1, y1), QPointF(x2, y2));
-
- draw(r);
-}
-
-// In order to prevent breaking code doing custom OpenGL rendering while
-// expecting the state in the context unchanged, save and restore all the state
-// we touch. The exception is Qt Quick where the scenegraph is known to be able
-// to deal with the changes we make.
-struct StateSaver
-{
- StateSaver() {
- f = QOpenGLContext::currentContext()->functions();
- vaoHelper = new QOpenGLVertexArrayObjectHelper(QOpenGLContext::currentContext());
-
- static bool windowsChecked = false;
- static bool shouldSave = true;
- if (!windowsChecked) {
- windowsChecked = true;
- QWindowList windows = QGuiApplication::allWindows();
- if (!windows.isEmpty() && windows[0]->inherits("QQuickWindow"))
- shouldSave = false;
- }
- saved = shouldSave;
- if (!shouldSave)
- return;
-
- f->glGetIntegerv(GL_CURRENT_PROGRAM, &program);
- f->glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
- f->glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
- f->glGetIntegerv(GL_FRONT_FACE, &frontFace);
- cull = f->glIsEnabled(GL_CULL_FACE);
- depthTest = f->glIsEnabled(GL_DEPTH_TEST);
- blend = f->glIsEnabled(GL_BLEND);
- f->glGetIntegerv(GL_BLEND_SRC_RGB, blendFunc);
- f->glGetIntegerv(GL_BLEND_SRC_ALPHA, blendFunc + 1);
- f->glGetIntegerv(GL_BLEND_DST_RGB, blendFunc + 2);
- f->glGetIntegerv(GL_BLEND_DST_ALPHA, blendFunc + 3);
- f->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBuf);
- if (vaoHelper->isValid())
- f->glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao);
- for (int i = 0; i < 2; ++i) {
- f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &va[i].enabled);
- f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &va[i].size);
- f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &va[i].type);
- f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &va[i].normalized);
- f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &va[i].stride);
- f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &va[i].buffer);
- f->glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &va[i].pointer);
- }
- }
- ~StateSaver() {
- if (saved) {
- f->glUseProgram(program);
- f->glBindTexture(GL_TEXTURE_2D, texture);
- f->glActiveTexture(activeTexture);
- f->glFrontFace(frontFace);
- if (cull)
- f->glEnable(GL_CULL_FACE);
- else
- f->glDisable(GL_CULL_FACE);
- if (depthTest)
- f->glEnable(GL_DEPTH_TEST);
- else
- f->glDisable(GL_DEPTH_TEST);
- if (blend)
- f->glEnable(GL_BLEND);
- else
- f->glDisable(GL_BLEND);
- f->glBlendFuncSeparate(blendFunc[0], blendFunc[1], blendFunc[2], blendFunc[3]);
- f->glBindBuffer(GL_ARRAY_BUFFER, arrayBuf);
- if (vaoHelper->isValid())
- vaoHelper->glBindVertexArray(vao);
- for (int i = 0; i < 2; ++i) {
- if (va[i].enabled)
- f->glEnableVertexAttribArray(i);
- else
- f->glDisableVertexAttribArray(i);
- f->glBindBuffer(GL_ARRAY_BUFFER, va[i].buffer);
- f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer);
- }
- }
- delete vaoHelper;
- }
- QOpenGLFunctions *f;
- QOpenGLVertexArrayObjectHelper *vaoHelper;
- bool saved;
- GLint program;
- GLint texture;
- GLint activeTexture;
- GLint frontFace;
- bool cull;
- bool depthTest;
- bool blend;
- GLint blendFunc[4];
- GLint vao;
- GLint arrayBuf;
- struct { GLint enabled, type, size, normalized, stride, buffer; GLvoid *pointer; } va[2];
-};
-
-void QEglFSCursor::draw(const QRectF &r)
-{
- StateSaver stateSaver;
-
- if (!m_program) {
- // one time initialization
- initializeOpenGLFunctions();
-
- createShaderPrograms();
-
- if (!m_cursorAtlas.texture) {
- createCursorTexture(&m_cursorAtlas.texture, m_cursorAtlas.image);
-
- if (m_cursor.shape != Qt::BitmapCursor)
- m_cursor.texture = m_cursorAtlas.texture;
- }
- }
-
- if (m_cursor.shape == Qt::BitmapCursor && m_cursor.customCursorPending) {
- // upload the custom cursor
- createCursorTexture(&m_cursor.customCursorTexture, m_cursor.customCursorImage);
- m_cursor.texture = m_cursor.customCursorTexture;
- m_cursor.customCursorPending = false;
- }
-
- Q_ASSERT(m_cursor.texture);
-
- m_program->bind();
-
- const GLfloat x1 = r.left();
- const GLfloat x2 = r.right();
- const GLfloat y1 = r.top();
- const GLfloat y2 = r.bottom();
- const GLfloat cursorCoordinates[] = {
- x1, y2,
- x2, y2,
- x1, y1,
- x2, y1
- };
-
- const GLfloat s1 = m_cursor.textureRect.left();
- const GLfloat s2 = m_cursor.textureRect.right();
- const GLfloat t1 = m_cursor.textureRect.top();
- const GLfloat t2 = m_cursor.textureRect.bottom();
- const GLfloat textureCoordinates[] = {
- s1, t2,
- s2, t2,
- s1, t1,
- s2, t1
- };
-
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, m_cursor.texture);
-
- if (stateSaver.vaoHelper->isValid())
- stateSaver.vaoHelper->glBindVertexArray(0);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- m_program->enableAttributeArray(0);
- m_program->enableAttributeArray(1);
- m_program->setAttributeArray(0, cursorCoordinates, 2);
- m_program->setAttributeArray(1, textureCoordinates, 2);
-
- m_program->setUniformValue(m_textureEntry, 0);
-
- glDisable(GL_CULL_FACE);
- glFrontFace(GL_CCW);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- m_program->disableAttributeArray(0);
- m_program->disableAttributeArray(1);
- m_program->release();
-}
-
-QT_END_NAMESPACE