Add eglfs cursor support
cursor-atlas.png was generated from existing cursor images (qttools/src/shared/qtpropertybrowser/images/) Change-Id: Ic4b396590eaec93e14a4b0915b15f735f5b1a5f5 Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>bb10
parent
420b62f202
commit
ce2b46daea
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>cursor-atlas.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
|
|
@ -19,12 +19,15 @@ SOURCES = main.cpp \
|
|||
qeglfswindow.cpp \
|
||||
qeglfsbackingstore.cpp \
|
||||
qeglfsscreen.cpp \
|
||||
qeglfshooks_stub.cpp
|
||||
qeglfshooks_stub.cpp \
|
||||
qeglfscursor.cpp
|
||||
|
||||
HEADERS = qeglfsintegration.h \
|
||||
qeglfswindow.h \
|
||||
qeglfsbackingstore.h \
|
||||
qeglfsscreen.h \
|
||||
qeglfshooks.h \
|
||||
qeglfscursor.h \
|
||||
qeglfshooks.h
|
||||
|
||||
QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
|
||||
|
|
@ -40,5 +43,7 @@ CONFIG += egl qpa/genericunixfontdatabase
|
|||
target.path += $$[QT_INSTALL_PLUGINS]/platforms
|
||||
INSTALLS += target
|
||||
|
||||
RESOURCES += cursor.qrc
|
||||
|
||||
OTHER_FILES += \
|
||||
eglfs.json
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include "qeglfsbackingstore.h"
|
||||
#include "qeglfscursor.h"
|
||||
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QOpenGLPaintDevice>
|
||||
|
|
@ -185,6 +186,10 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo
|
|||
glDisableVertexAttribArray(m_textureCoordEntry);
|
||||
#endif
|
||||
|
||||
// draw the cursor
|
||||
if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->handle()->cursor()))
|
||||
cursor->render();
|
||||
|
||||
m_context->swapBuffers(window);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,222 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qeglfscursor.h"
|
||||
#include <QtGui/qwindowsysteminterface_qpa.h>
|
||||
#include <QtGui/QOpenGLShaderProgram>
|
||||
#include <QtDebug>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#define CURSORS_PER_ROW 8
|
||||
|
||||
QEglFSCursor::QEglFSCursor(QEglFSScreen *screen)
|
||||
: m_screen(screen), m_pos(0, 0), m_program(0), m_vertexCoordEntry(0), m_textureCoordEntry(0), m_textureEntry(0)
|
||||
{
|
||||
createShaderPrograms();
|
||||
initCursorAtlas();
|
||||
|
||||
// ## this shouldn't be required
|
||||
QCursor cursor(Qt::ArrowCursor);
|
||||
changeCursor(&cursor, 0);
|
||||
}
|
||||
|
||||
QEglFSCursor::~QEglFSCursor()
|
||||
{
|
||||
// destroy atlas?
|
||||
}
|
||||
|
||||
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->link();
|
||||
|
||||
m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry");
|
||||
m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry");
|
||||
m_textureEntry = m_program->uniformLocation("texture");
|
||||
}
|
||||
|
||||
void QEglFSCursor::createCursorTexture(uint *texture, const QImage &image)
|
||||
{
|
||||
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()
|
||||
{
|
||||
QImage image = QImage(":/cursor-atlas.png").convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
m_cursorAtlas.cursorWidth = image.width() / CURSORS_PER_ROW;
|
||||
m_cursorAtlas.cursorHeight = image.height() / ((Qt::LastCursor + CURSORS_PER_ROW - 1) / CURSORS_PER_ROW);
|
||||
m_cursorAtlas.hotSpot = QPoint(m_cursorAtlas.cursorWidth/2, m_cursorAtlas.cursorHeight/2); // ## be smarter
|
||||
m_cursorAtlas.width = image.width();
|
||||
m_cursorAtlas.height = image.height();
|
||||
createCursorTexture(&m_cursorAtlas.texture, image);
|
||||
}
|
||||
|
||||
void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window)
|
||||
{
|
||||
const QRect oldCursorRect = cursorRect();
|
||||
|
||||
if (m_cursor.shape == Qt::BitmapCursor && m_cursor.texture)
|
||||
glDeleteTextures(1, &m_cursor.texture);
|
||||
|
||||
m_cursor.shape = cursor->shape();
|
||||
if (cursor->shape() != 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 % CURSORS_PER_ROW),
|
||||
hs * (m_cursor.shape / CURSORS_PER_ROW),
|
||||
ws, hs);
|
||||
m_cursor.hotSpot = m_cursorAtlas.hotSpot;
|
||||
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.size = image.size();
|
||||
createCursorTexture(&m_cursor.texture, image);
|
||||
}
|
||||
|
||||
QRegion rgn = oldCursorRect | cursorRect();
|
||||
QWindowSystemInterface::handleSynchronousExposeEvent(window, rgn);
|
||||
}
|
||||
|
||||
QPoint QEglFSCursor::pos() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
void QEglFSCursor::setPos(const QPoint &pos)
|
||||
{
|
||||
const QRect oldCursorRect = cursorRect();
|
||||
m_pos = pos;
|
||||
QRegion rgn = oldCursorRect | cursorRect();
|
||||
QWindowSystemInterface::handleSynchronousExposeEvent(m_screen->topLevelAt(m_pos), rgn);
|
||||
}
|
||||
|
||||
void QEglFSCursor::pointerEvent(const QMouseEvent &event)
|
||||
{
|
||||
const QRect oldCursorRect = cursorRect();
|
||||
m_pos = event.pos();
|
||||
QRegion rgn = oldCursorRect | cursorRect();
|
||||
QWindowSystemInterface::handleSynchronousExposeEvent(m_screen->topLevelAt(m_pos), rgn);
|
||||
}
|
||||
|
||||
void QEglFSCursor::render()
|
||||
{
|
||||
m_program->bind();
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_cursor.texture);
|
||||
|
||||
glEnableVertexAttribArray(m_vertexCoordEntry);
|
||||
glEnableVertexAttribArray(m_textureCoordEntry);
|
||||
|
||||
glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, cursorCoordinates);
|
||||
glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
|
||||
|
||||
glUniform1f(m_textureEntry, 0);
|
||||
|
||||
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);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisableVertexAttribArray(m_vertexCoordEntry);
|
||||
glDisableVertexAttribArray(m_textureCoordEntry);
|
||||
|
||||
m_program->release();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QEGLFSCURSOR_H
|
||||
#define QEGLFSCURSOR_H
|
||||
|
||||
#include <qpa/qplatformcursor.h>
|
||||
#include "qeglfsscreen.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QOpenGLShaderProgram;
|
||||
|
||||
class QEglFSCursor : public QPlatformCursor
|
||||
{
|
||||
public:
|
||||
QEglFSCursor(QEglFSScreen *screen);
|
||||
~QEglFSCursor();
|
||||
|
||||
void changeCursor(QCursor *cursor, QWindow *widget);
|
||||
void pointerEvent(const QMouseEvent &event);
|
||||
|
||||
QPoint pos() const;
|
||||
void setPos(const QPoint &pos);
|
||||
|
||||
QRect cursorRect() const { return QRect(m_pos, m_cursor.size); }
|
||||
|
||||
void render();
|
||||
|
||||
private:
|
||||
void createShaderPrograms();
|
||||
static void createCursorTexture(uint *texture, const QImage &image);
|
||||
void initCursorAtlas();
|
||||
|
||||
QPlatformScreen *m_screen;
|
||||
|
||||
// cursor atlas information
|
||||
struct CursorAtlas {
|
||||
CursorAtlas() : texture(0), cursorWidth(0), cursorHeight(0) { }
|
||||
uint texture;
|
||||
int width, height; // width and height of the the atlas
|
||||
int cursorWidth, cursorHeight; // width and height of cursors inside the atlas
|
||||
QPoint hotSpot;
|
||||
} m_cursorAtlas;
|
||||
|
||||
// current cursor information
|
||||
struct Cursor {
|
||||
Cursor() : texture(0), shape(Qt::BlankCursor) { }
|
||||
uint texture; // a texture from 'image' or the atlas
|
||||
Qt::CursorShape shape;
|
||||
QRectF textureRect; // normalized rect inside texture
|
||||
QSize size; // size of the cursor
|
||||
QPoint hotSpot;
|
||||
} m_cursor;
|
||||
|
||||
QPoint m_pos;
|
||||
|
||||
QOpenGLShaderProgram *m_program;
|
||||
int m_vertexCoordEntry;
|
||||
int m_textureCoordEntry;
|
||||
int m_textureEntry;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QEGLFSCURSOR_H
|
||||
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
#include <QtGui/QSurfaceFormat>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QPlatformCursor>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
|
|||
#endif
|
||||
QPlatformWindow *w = new QEglFSWindow(window);
|
||||
w->requestActivateWindow();
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qeglfscursor.h"
|
||||
#include "qeglfsscreen.h"
|
||||
#include "qeglfswindow.h"
|
||||
#include "qeglfshooks.h"
|
||||
|
|
@ -98,6 +99,16 @@ public:
|
|||
QEglFSScreen *screen = static_cast<QEglFSScreen *>(window->screen());
|
||||
return screen->surface();
|
||||
}
|
||||
|
||||
void swapBuffers(QPlatformSurface *surface)
|
||||
{
|
||||
QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
|
||||
QEglFSScreen *screen = static_cast<QEglFSScreen *>(window->screen());
|
||||
if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(screen->cursor()))
|
||||
cursor->render();
|
||||
|
||||
QEGLPlatformContext::swapBuffers(surface);
|
||||
}
|
||||
};
|
||||
|
||||
QEglFSScreen::QEglFSScreen()
|
||||
|
|
@ -106,6 +117,7 @@ QEglFSScreen::QEglFSScreen()
|
|||
, m_platformContext(0)
|
||||
, m_surface(0)
|
||||
, m_window(0)
|
||||
, m_cursor(0)
|
||||
{
|
||||
#ifdef QEGL_EXTRA_DEBUG
|
||||
qWarning("QEglScreen %p\n", this);
|
||||
|
|
@ -148,6 +160,8 @@ QEglFSScreen::QEglFSScreen()
|
|||
|
||||
QEglFSScreen::~QEglFSScreen()
|
||||
{
|
||||
delete m_cursor;
|
||||
|
||||
if (m_surface)
|
||||
eglDestroySurface(m_dpy, m_surface);
|
||||
|
||||
|
|
@ -246,6 +260,23 @@ QImage::Format QEglFSScreen::format() const
|
|||
createAndSetPlatformContext();
|
||||
return m_format;
|
||||
}
|
||||
|
||||
QPlatformCursor *QEglFSScreen::cursor() const
|
||||
{
|
||||
static int hideCursor = qgetenv("QT_QPA_EGLFS_HIDECURSOR").toInt();
|
||||
if (hideCursor)
|
||||
return 0;
|
||||
|
||||
if (!m_cursor) {
|
||||
QEglFSScreen *that = const_cast<QEglFSScreen *>(this);
|
||||
// cursor requires a gl context
|
||||
if (!m_platformContext)
|
||||
that->createAndSetPlatformContext();
|
||||
that->m_cursor = new QEglFSCursor(that);
|
||||
}
|
||||
return m_cursor;
|
||||
}
|
||||
|
||||
QPlatformOpenGLContext *QEglFSScreen::platformContext() const
|
||||
{
|
||||
if (!m_platformContext) {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@
|
|||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QPlatformOpenGLContext;
|
||||
class QEglFSCursor;
|
||||
|
||||
class QEglFSScreen : public QPlatformScreen //huh: FullScreenScreen ;) just to follow namespace
|
||||
{
|
||||
|
|
@ -62,6 +63,8 @@ public:
|
|||
int depth() const;
|
||||
QImage::Format format() const;
|
||||
|
||||
QPlatformCursor *cursor() const;
|
||||
|
||||
QPlatformOpenGLContext *platformContext() const;
|
||||
|
||||
EGLSurface surface() const { return m_surface; }
|
||||
|
|
@ -77,6 +80,7 @@ private:
|
|||
EGLDisplay m_dpy;
|
||||
EGLSurface m_surface;
|
||||
EGLNativeWindowType m_window;
|
||||
QEglFSCursor *m_cursor;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in New Issue