summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGirish Ramakrishnan <girish.1.ramakrishnan@nokia.com>2012-04-09 14:16:19 -0700
committerQt by Nokia <qt-info@nokia.com>2012-05-16 19:36:19 +0200
commitce2b46daea5815df1070463b6bc379e1b4573dae (patch)
tree285476dfe393748b414362975c31af8dc68dc008
parent420b62f2028d2331a729ef800b40dfc762d1613c (diff)
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>
-rw-r--r--src/plugins/platforms/eglfs/cursor-atlas.pngbin0 -> 2735 bytes
-rw-r--r--src/plugins/platforms/eglfs/cursor.qrc6
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pro7
-rw-r--r--src/plugins/platforms/eglfs/qeglfsbackingstore.cpp5
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.cpp222
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.h105
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.cpp31
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.h4
9 files changed, 381 insertions, 1 deletions
diff --git a/src/plugins/platforms/eglfs/cursor-atlas.png b/src/plugins/platforms/eglfs/cursor-atlas.png
new file mode 100644
index 0000000000..8d89a7ab86
--- /dev/null
+++ b/src/plugins/platforms/eglfs/cursor-atlas.png
Binary files differ
diff --git a/src/plugins/platforms/eglfs/cursor.qrc b/src/plugins/platforms/eglfs/cursor.qrc
new file mode 100644
index 0000000000..64d9b2b478
--- /dev/null
+++ b/src/plugins/platforms/eglfs/cursor.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>cursor-atlas.png</file>
+</qresource>
+</RCC>
+
diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro
index b3bbc4e3e4..137c5c1ff7 100644
--- a/src/plugins/platforms/eglfs/eglfs.pro
+++ b/src/plugins/platforms/eglfs/eglfs.pro
@@ -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
diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
index 5c1919a4f3..c3f3d4f34e 100644
--- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
@@ -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);
}
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp
new file mode 100644
index 0000000000..a6e1a320e9
--- /dev/null
+++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp
@@ -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
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/qeglfscursor.h
new file mode 100644
index 0000000000..a580404ab8
--- /dev/null
+++ b/src/plugins/platforms/eglfs/qeglfscursor.h
@@ -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
+
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index 7025aed4a8..257c3cd3dc 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -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;
}
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
index 78f9e13150..0a97a932cb 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
@@ -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) {
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h
index 8c67bf1956..ca1a3ef91b 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.h
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.h
@@ -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