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
Girish Ramakrishnan 2012-04-09 14:16:19 -07:00 committed by Qt by Nokia
parent 420b62f202
commit ce2b46daea
9 changed files with 381 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>cursor-atlas.png</file>
</qresource>
</RCC>

View File

@ -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

View File

@ -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 &region, 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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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