summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/api
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/api
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/api')
-rw-r--r--src/plugins/platforms/eglfs/api/api.pri15
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor.cpp509
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor_p.h147
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp382
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h133
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsglobal.h69
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks.cpp136
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfshooks_p.h67
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen.cpp206
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen_p.h105
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp336
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow_p.h129
12 files changed, 2234 insertions, 0 deletions
diff --git a/src/plugins/platforms/eglfs/api/api.pri b/src/plugins/platforms/eglfs/api/api.pri
new file mode 100644
index 0000000000..957dee554c
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/api.pri
@@ -0,0 +1,15 @@
+
+SOURCES += $$PWD/qeglfswindow.cpp \
+ $$PWD/qeglfsscreen.cpp \
+ $$PWD/qeglfscursor.cpp \
+ $$PWD/qeglfshooks.cpp \
+ $$PWD/qeglfsdeviceintegration.cpp
+
+HEADERS += $$PWD/qeglfswindow_p.h \
+ $$PWD/qeglfsscreen_p.h \
+ $$PWD/qeglfscursor_p.h \
+ $$PWD/qeglfshooks_p.h \
+ $$PWD/qeglfsdeviceintegration_p.h \
+ $$PWD/qeglfsglobal.h
+
+INCLUDEPATH += $$PWD
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
new file mode 100644
index 0000000000..ffee21a9b0
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** 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_p.h"
+#include "qeglfsintegration.h"
+#include "qeglfsscreen_p.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
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
new file mode 100644
index 0000000000..bb30d53d6c
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEGLFSCURSOR_H
+#define QEGLFSCURSOR_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qeglfsglobal.h"
+#include <qpa/qplatformcursor.h>
+#include <qpa/qplatformscreen.h>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/private/qinputdevicemanager_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLShaderProgram;
+class QEglFSCursor;
+class QEglFSScreen;
+
+class QEglFSCursorDeviceListener : public QObject
+{
+ Q_OBJECT
+
+public:
+ QEglFSCursorDeviceListener(QEglFSCursor *cursor) : m_cursor(cursor) { }
+ bool hasMouse() const;
+
+public slots:
+ void onDeviceListChanged(QInputDeviceManager::DeviceType type);
+
+private:
+ QEglFSCursor *m_cursor;
+};
+
+class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor, protected QOpenGLFunctions
+{
+ Q_OBJECT
+public:
+ QEglFSCursor(QPlatformScreen *screen);
+ ~QEglFSCursor();
+
+#ifndef QT_NO_CURSOR
+ void changeCursor(QCursor *cursor, QWindow *widget) Q_DECL_OVERRIDE;
+#endif
+ void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE;
+ QPoint pos() const Q_DECL_OVERRIDE;
+ void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
+
+ QRect cursorRect() const;
+ void paintOnScreen();
+ void resetResources();
+
+ void updateMouseStatus();
+
+private:
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
+#ifndef QT_NO_CURSOR
+ bool setCurrentCursor(QCursor *cursor);
+#endif
+ void draw(const QRectF &rect);
+ void update(const QRegion &region);
+ void createShaderPrograms();
+ void createCursorTexture(uint *texture, const QImage &image);
+ void initCursorAtlas();
+
+ // current cursor information
+ struct Cursor {
+ Cursor() : texture(0), shape(Qt::BlankCursor), customCursorTexture(0), customCursorPending(false) { }
+ 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;
+ QImage customCursorImage;
+ QPoint pos; // current cursor position
+ uint customCursorTexture;
+ bool customCursorPending;
+ } m_cursor;
+
+ // cursor atlas information
+ struct CursorAtlas {
+ CursorAtlas() : cursorsPerRow(0), texture(0), cursorWidth(0), cursorHeight(0) { }
+ int cursorsPerRow;
+ uint texture;
+ int width, height; // width and height of the atlas
+ int cursorWidth, cursorHeight; // width and height of cursors inside the atlas
+ QList<QPoint> hotSpots;
+ QImage image; // valid until it's uploaded
+ } m_cursorAtlas;
+
+ bool m_visible;
+ QEglFSScreen *m_screen;
+ QOpenGLShaderProgram *m_program;
+ int m_textureEntry;
+ QEglFSCursorDeviceListener *m_deviceListener;
+ bool m_updateRequested;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSCURSOR_H
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
new file mode 100644
index 0000000000..a735f4dba4
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** 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 "qeglfsdeviceintegration_p.h"
+#include "qeglfsintegration.h"
+#include "qeglfscursor_p.h"
+#include "qeglfswindow_p.h"
+#include "qeglfshooks_p.h"
+
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+#include <QGuiApplication>
+#include <private/qguiapplication_p.h>
+#include <QScreen>
+#include <QDir>
+#include <QRegularExpression>
+#include <QLoggingCategory>
+
+#if defined(Q_OS_LINUX)
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#endif
+
+#include <private/qfactoryloader_p.h>
+#include <private/qcore_unix_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcEglDevDebug, "qt.qpa.egldeviceintegration")
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QEglFSDeviceIntegrationFactoryInterface_iid, QLatin1String("/egldeviceintegrations"), Qt::CaseInsensitive))
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader,
+ (QEglFSDeviceIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
+
+static inline QEglFSDeviceIntegration *loadIntegration(QFactoryLoader *loader, const QString &key)
+{
+ const int index = loader->indexOf(key);
+ if (index != -1) {
+ QObject *plugin = loader->instance(index);
+ if (QEglFSDeviceIntegrationPlugin *factory = qobject_cast<QEglFSDeviceIntegrationPlugin *>(plugin)) {
+ if (QEglFSDeviceIntegration *result = factory->create())
+ return result;
+ }
+ }
+ return Q_NULLPTR;
+}
+
+#endif // QT_NO_LIBRARY
+
+QStringList QEglFSDeviceIntegrationFactory::keys(const QString &pluginPath)
+{
+ QStringList list;
+#ifndef QT_NO_LIBRARY
+ if (!pluginPath.isEmpty()) {
+ QCoreApplication::addLibraryPath(pluginPath);
+ list = directLoader()->keyMap().values();
+ if (!list.isEmpty()) {
+ const QString postFix = QStringLiteral(" (from ")
+ + QDir::toNativeSeparators(pluginPath)
+ + QLatin1Char(')');
+ const QStringList::iterator end = list.end();
+ for (QStringList::iterator it = list.begin(); it != end; ++it)
+ (*it).append(postFix);
+ }
+ }
+#else
+ Q_UNUSED(pluginPath);
+#endif
+ list.append(loader()->keyMap().values());
+ qCDebug(qLcEglDevDebug) << "EGL device integration plugin keys:" << list;
+ return list;
+}
+
+QEglFSDeviceIntegration *QEglFSDeviceIntegrationFactory::create(const QString &key, const QString &pluginPath)
+{
+ QEglFSDeviceIntegration *integration = Q_NULLPTR;
+#ifndef QT_NO_LIBRARY
+ if (!pluginPath.isEmpty()) {
+ QCoreApplication::addLibraryPath(pluginPath);
+ integration = qLoadPlugin<QEglFSDeviceIntegration, QEglFSDeviceIntegrationPlugin>(directLoader(), key);
+ }
+#else
+ Q_UNUSED(pluginPath);
+#endif
+ if (!integration)
+ integration = qLoadPlugin<QEglFSDeviceIntegration, QEglFSDeviceIntegrationPlugin>(loader(), key);
+ if (integration)
+ qCDebug(qLcEglDevDebug) << "Using EGL device integration" << key;
+ else
+ qCWarning(qLcEglDevDebug) << "Failed to load EGL device integration" << key;
+
+ return integration;
+}
+
+static int framebuffer = -1;
+
+QByteArray QEglFSDeviceIntegration::fbDeviceName() const
+{
+#ifdef Q_OS_LINUX
+ QByteArray fbDev = qgetenv("QT_QPA_EGLFS_FB");
+ if (fbDev.isEmpty())
+ fbDev = QByteArrayLiteral("/dev/fb0");
+
+ return fbDev;
+#else
+ return QByteArray();
+#endif
+}
+
+int QEglFSDeviceIntegration::framebufferIndex() const
+{
+ int fbIndex = 0;
+#ifndef QT_NO_REGULAREXPRESSION
+ QRegularExpression fbIndexRx(QLatin1String("fb(\\d+)"));
+ QRegularExpressionMatch match = fbIndexRx.match(QString::fromLocal8Bit(fbDeviceName()));
+ if (match.hasMatch())
+ fbIndex = match.captured(1).toInt();
+#endif
+ return fbIndex;
+}
+
+void QEglFSDeviceIntegration::platformInit()
+{
+#ifdef Q_OS_LINUX
+ QByteArray fbDev = fbDeviceName();
+
+ framebuffer = qt_safe_open(fbDev, O_RDONLY);
+
+ if (Q_UNLIKELY(framebuffer == -1)) {
+ qWarning("EGLFS: Failed to open %s", fbDev.constData());
+ qFatal("EGLFS: Can't continue without a display");
+ }
+
+#ifdef FBIOBLANK
+ ioctl(framebuffer, FBIOBLANK, VESA_NO_BLANKING);
+#endif
+#endif
+}
+
+void QEglFSDeviceIntegration::platformDestroy()
+{
+#ifdef Q_OS_LINUX
+ if (framebuffer != -1)
+ close(framebuffer);
+#endif
+}
+
+EGLNativeDisplayType QEglFSDeviceIntegration::platformDisplay() const
+{
+ return EGL_DEFAULT_DISPLAY;
+}
+
+EGLDisplay QEglFSDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
+{
+ return eglGetDisplay(nativeDisplay);
+}
+
+bool QEglFSDeviceIntegration::usesDefaultScreen()
+{
+ return true;
+}
+
+void QEglFSDeviceIntegration::screenInit()
+{
+ // Nothing to do here. Called only when usesDefaultScreen is false.
+}
+
+void QEglFSDeviceIntegration::screenDestroy()
+{
+ QGuiApplication *app = qGuiApp;
+ QEglFSIntegration *platformIntegration = static_cast<QEglFSIntegration *>(
+ QGuiApplicationPrivate::platformIntegration());
+ while (!app->screens().isEmpty())
+ platformIntegration->removeScreen(app->screens().last()->handle());
+}
+
+QSizeF QEglFSDeviceIntegration::physicalScreenSize() const
+{
+ return q_physicalScreenSizeFromFb(framebuffer, screenSize());
+}
+
+QSize QEglFSDeviceIntegration::screenSize() const
+{
+ return q_screenSizeFromFb(framebuffer);
+}
+
+QDpi QEglFSDeviceIntegration::logicalDpi() const
+{
+ const QSizeF ps = physicalScreenSize();
+ const QSize s = screenSize();
+
+ if (!ps.isEmpty() && !s.isEmpty())
+ return QDpi(25.4 * s.width() / ps.width(),
+ 25.4 * s.height() / ps.height());
+ else
+ return QDpi(100, 100);
+}
+
+qreal QEglFSDeviceIntegration::pixelDensity() const
+{
+ return qRound(logicalDpi().first / qreal(100));
+}
+
+Qt::ScreenOrientation QEglFSDeviceIntegration::nativeOrientation() const
+{
+ return Qt::PrimaryOrientation;
+}
+
+Qt::ScreenOrientation QEglFSDeviceIntegration::orientation() const
+{
+ return Qt::PrimaryOrientation;
+}
+
+int QEglFSDeviceIntegration::screenDepth() const
+{
+ return q_screenDepthFromFb(framebuffer);
+}
+
+QImage::Format QEglFSDeviceIntegration::screenFormat() const
+{
+ return screenDepth() == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
+}
+
+qreal QEglFSDeviceIntegration::refreshRate() const
+{
+ return q_refreshRateFromFb(framebuffer);
+}
+
+EGLint QEglFSDeviceIntegration::surfaceType() const
+{
+ return EGL_WINDOW_BIT;
+}
+
+QSurfaceFormat QEglFSDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
+{
+ QSurfaceFormat format = inputFormat;
+
+ static const bool force888 = qEnvironmentVariableIntValue("QT_QPA_EGLFS_FORCE888");
+ if (force888) {
+ format.setRedBufferSize(8);
+ format.setGreenBufferSize(8);
+ format.setBlueBufferSize(8);
+ }
+
+ return format;
+}
+
+bool QEglFSDeviceIntegration::filterConfig(EGLDisplay, EGLConfig) const
+{
+ return true;
+}
+
+QEglFSWindow *QEglFSDeviceIntegration::createWindow(QWindow *window) const
+{
+ return new QEglFSWindow(window);
+}
+
+EGLNativeWindowType QEglFSDeviceIntegration::createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format)
+{
+ Q_UNUSED(platformWindow);
+ Q_UNUSED(size);
+ Q_UNUSED(format);
+ return 0;
+}
+
+EGLNativeWindowType QEglFSDeviceIntegration::createNativeOffscreenWindow(const QSurfaceFormat &format)
+{
+ Q_UNUSED(format);
+ return 0;
+}
+
+void QEglFSDeviceIntegration::destroyNativeWindow(EGLNativeWindowType window)
+{
+ Q_UNUSED(window);
+}
+
+bool QEglFSDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ Q_UNUSED(cap);
+ return false;
+}
+
+QPlatformCursor *QEglFSDeviceIntegration::createCursor(QPlatformScreen *screen) const
+{
+ return new QEglFSCursor(screen);
+}
+
+void QEglFSDeviceIntegration::waitForVSync(QPlatformSurface *surface) const
+{
+ Q_UNUSED(surface);
+
+#if defined(Q_OS_LINUX) && defined(FBIO_WAITFORVSYNC)
+ static const bool forceSync = qEnvironmentVariableIntValue("QT_QPA_EGLFS_FORCEVSYNC");
+ if (forceSync && framebuffer != -1) {
+ int arg = 0;
+ if (ioctl(framebuffer, FBIO_WAITFORVSYNC, &arg) == -1)
+ qWarning("Could not wait for vsync.");
+ }
+#endif
+}
+
+void QEglFSDeviceIntegration::presentBuffer(QPlatformSurface *surface)
+{
+ Q_UNUSED(surface);
+}
+
+bool QEglFSDeviceIntegration::supportsPBuffers() const
+{
+ return true;
+}
+
+bool QEglFSDeviceIntegration::supportsSurfacelessContexts() const
+{
+ return true;
+}
+
+void *QEglFSDeviceIntegration::wlDisplay() const
+{
+ return Q_NULLPTR;
+}
+
+EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
+{
+ class Chooser : public QEglConfigChooser {
+ public:
+ Chooser(EGLDisplay display)
+ : QEglConfigChooser(display) { }
+ bool filterConfig(EGLConfig config) const Q_DECL_OVERRIDE {
+ return qt_egl_device_integration()->filterConfig(display(), config)
+ && QEglConfigChooser::filterConfig(config);
+ }
+ };
+
+ Chooser chooser(display);
+ chooser.setSurfaceType(qt_egl_device_integration()->surfaceType());
+ chooser.setSurfaceFormat(format);
+ return chooser.chooseConfig();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
new file mode 100644
index 0000000000..819e4818ab
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEGLFSDEVICEINTEGRATION_H
+#define QEGLFSDEVICEINTEGRATION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qeglfsglobal.h"
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformscreen.h>
+#include <QtCore/QString>
+#include <QtGui/QSurfaceFormat>
+#include <QtGui/QImage>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformSurface;
+class QEglFSWindow;
+
+#define QEglFSDeviceIntegrationFactoryInterface_iid "org.qt-project.qt.qpa.egl.QEglFSDeviceIntegrationFactoryInterface.5.5"
+
+class Q_EGLFS_EXPORT QEglFSDeviceIntegration
+{
+public:
+ virtual ~QEglFSDeviceIntegration() { }
+
+ virtual void platformInit();
+ virtual void platformDestroy();
+ virtual EGLNativeDisplayType platformDisplay() const;
+ virtual EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay);
+ virtual bool usesDefaultScreen();
+ virtual void screenInit();
+ virtual void screenDestroy();
+ virtual QSizeF physicalScreenSize() const;
+ virtual QSize screenSize() const;
+ virtual QDpi logicalDpi() const;
+ virtual qreal pixelDensity() const;
+ virtual Qt::ScreenOrientation nativeOrientation() const;
+ virtual Qt::ScreenOrientation orientation() const;
+ virtual int screenDepth() const;
+ virtual QImage::Format screenFormat() const;
+ virtual qreal refreshRate() const;
+ virtual QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
+ virtual EGLint surfaceType() const;
+ virtual QEglFSWindow *createWindow(QWindow *window) const;
+ virtual EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format);
+ virtual EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format);
+ virtual void destroyNativeWindow(EGLNativeWindowType window);
+ virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
+ virtual QPlatformCursor *createCursor(QPlatformScreen *screen) const;
+ virtual bool filterConfig(EGLDisplay display, EGLConfig config) const;
+ virtual void waitForVSync(QPlatformSurface *surface) const;
+ virtual void presentBuffer(QPlatformSurface *surface);
+ virtual QByteArray fbDeviceName() const;
+ virtual int framebufferIndex() const;
+ virtual bool supportsPBuffers() const;
+ virtual bool supportsSurfacelessContexts() const;
+
+ virtual void *wlDisplay() const;
+
+ static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
+};
+
+class Q_EGLFS_EXPORT QEglFSDeviceIntegrationPlugin : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QEglFSDeviceIntegration *create() = 0;
+
+ // the pattern expected by qLoadPlugin calls for a QString argument.
+ // we don't need it, so don't bother subclasses with it:
+ QEglFSDeviceIntegration *create(const QString &) { return create(); }
+};
+
+class Q_EGLFS_EXPORT QEglFSDeviceIntegrationFactory
+{
+public:
+ static QStringList keys(const QString &pluginPath = QString());
+ static QEglFSDeviceIntegration *create(const QString &name, const QString &platformPluginPath = QString());
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLDEVICEINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/api/qeglfsglobal.h b/src/plugins/platforms/eglfs/api/qeglfsglobal.h
new file mode 100644
index 0000000000..2b5effc2f1
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfsglobal.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEGLFSGLOBAL_H
+#define QEGLFSGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef QT_BUILD_EGL_DEVICE_LIB
+#define Q_EGLFS_EXPORT Q_DECL_EXPORT
+#else
+#define Q_EGLFS_EXPORT Q_DECL_IMPORT
+#endif
+
+#undef Status
+#undef None
+#undef Bool
+#undef CursorShape
+#undef KeyPress
+#undef KeyRelease
+#undef FocusIn
+#undef FocusOut
+#undef FontChange
+#undef Expose
+#undef Unsorted
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/eglfs/api/qeglfshooks.cpp b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
new file mode 100644
index 0000000000..b67d8fab54
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the qmake spec 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 "qeglfshooks_p.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug)
+
+#ifdef EGLFS_PLATFORM_HOOKS
+
+QEglFSDeviceIntegration *qt_egl_device_integration()
+{
+ extern QEglFSHooks *platformHooks;
+ return platformHooks;
+}
+
+#else
+
+class DeviceIntegration
+{
+public:
+ DeviceIntegration();
+ ~DeviceIntegration() { delete m_integration; }
+ QEglFSDeviceIntegration *integration() { return m_integration; }
+private:
+ QEglFSDeviceIntegration *m_integration;
+};
+
+Q_GLOBAL_STATIC(DeviceIntegration, deviceIntegration)
+
+DeviceIntegration::DeviceIntegration() : m_integration(0)
+{
+ QStringList pluginKeys = QEglFSDeviceIntegrationFactory::keys();
+ if (!pluginKeys.isEmpty()) {
+ // Some built-in logic: Prioritize either X11 or KMS/DRM.
+ if (qEnvironmentVariableIsSet("DISPLAY")) {
+ const QString x11key = QStringLiteral("eglfs_x11");
+ if (pluginKeys.contains(x11key)) {
+ pluginKeys.removeOne(x11key);
+ pluginKeys.prepend(x11key);
+ }
+ } else {
+ const QString kmskey = QStringLiteral("eglfs_kms");
+ if (pluginKeys.contains(kmskey)) {
+ pluginKeys.removeOne(kmskey);
+ pluginKeys.prepend(kmskey);
+ }
+ }
+
+ QByteArray requested;
+
+ // The environment variable can override everything.
+ if (qEnvironmentVariableIsSet("QT_QPA_EGLFS_INTEGRATION")) {
+ requested = qgetenv("QT_QPA_EGLFS_INTEGRATION");
+ } else {
+ // Device-specific makespecs may define a preferred plugin.
+#ifdef EGLFS_PREFERRED_PLUGIN
+#define DEFAULT_PLUGIN EGLFS_PREFERRED_PLUGIN
+#define STR(s) #s
+#define STRQ(s) STR(s)
+ requested = STRQ(DEFAULT_PLUGIN);
+#endif
+ }
+
+ // Treat "none" as special. There has to be a way to indicate
+ // that plugins must be ignored when the device is known to be
+ // functional with the default, non-specialized integration.
+ if (requested != QByteArrayLiteral("none")) {
+ if (!requested.isEmpty()) {
+ QString reqStr = QString::fromLocal8Bit(requested);
+ pluginKeys.removeOne(reqStr);
+ pluginKeys.prepend(reqStr);
+ }
+ qCDebug(qLcEglDevDebug) << "EGL device integration plugin keys (sorted):" << pluginKeys;
+ while (!m_integration && !pluginKeys.isEmpty()) {
+ QString key = pluginKeys.takeFirst();
+ qCDebug(qLcEglDevDebug) << "Trying to load device EGL integration" << key;
+ m_integration = QEglFSDeviceIntegrationFactory::create(key);
+ }
+ }
+ }
+
+ if (!m_integration) {
+ // Use a default, non-specialized device integration when no plugin is available.
+ // For some systems this is sufficient.
+ qCDebug(qLcEglDevDebug) << "Using base device integration";
+ m_integration = new QEglFSDeviceIntegration;
+ }
+}
+
+QEglFSDeviceIntegration *qt_egl_device_integration()
+{
+ return deviceIntegration()->integration();
+}
+
+#endif // EGLFS_PLATFORM_HOOKS
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfshooks_p.h b/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
new file mode 100644
index 0000000000..e379f7a76d
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfshooks_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEGLFSHOOKS_H
+#define QEGLFSHOOKS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qeglfsglobal.h"
+#include "qeglfsdeviceintegration_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSHooks : public QEglFSDeviceIntegration
+{
+};
+
+Q_EGLFS_EXPORT QEglFSDeviceIntegration *qt_egl_device_integration();
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSHOOKS_H
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
new file mode 100644
index 0000000000..d636a783ec
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** 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 <QtCore/qtextstream.h>
+#include <QtGui/qwindow.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qplatformcursor.h>
+#include <QtPlatformSupport/private/qopenglcompositor_p.h>
+
+#include "qeglfsscreen_p.h"
+#include "qeglfswindow_p.h"
+#include "qeglfshooks_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
+ : m_dpy(dpy),
+ m_surface(EGL_NO_SURFACE),
+ m_cursor(0)
+{
+ m_cursor = qt_egl_device_integration()->createCursor(this);
+}
+
+QEglFSScreen::~QEglFSScreen()
+{
+ delete m_cursor;
+ QOpenGLCompositor::destroy();
+}
+
+QRect QEglFSScreen::geometry() const
+{
+ return QRect(QPoint(0, 0), qt_egl_device_integration()->screenSize());
+}
+
+int QEglFSScreen::depth() const
+{
+ return qt_egl_device_integration()->screenDepth();
+}
+
+QImage::Format QEglFSScreen::format() const
+{
+ return qt_egl_device_integration()->screenFormat();
+}
+
+QSizeF QEglFSScreen::physicalSize() const
+{
+ return qt_egl_device_integration()->physicalScreenSize();
+}
+
+QDpi QEglFSScreen::logicalDpi() const
+{
+ return qt_egl_device_integration()->logicalDpi();
+}
+
+qreal QEglFSScreen::pixelDensity() const
+{
+ return qt_egl_device_integration()->pixelDensity();
+}
+
+Qt::ScreenOrientation QEglFSScreen::nativeOrientation() const
+{
+ return qt_egl_device_integration()->nativeOrientation();
+}
+
+Qt::ScreenOrientation QEglFSScreen::orientation() const
+{
+ return qt_egl_device_integration()->orientation();
+}
+
+QPlatformCursor *QEglFSScreen::cursor() const
+{
+ return m_cursor;
+}
+
+qreal QEglFSScreen::refreshRate() const
+{
+ return qt_egl_device_integration()->refreshRate();
+}
+
+void QEglFSScreen::setPrimarySurface(EGLSurface surface)
+{
+ m_surface = surface;
+}
+
+void QEglFSScreen::handleCursorMove(const QPoint &pos)
+{
+ const QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
+
+ // Generate enter and leave events like a real windowing system would do.
+ if (windows.isEmpty())
+ return;
+
+ // First window is always fullscreen.
+ if (windows.count() == 1) {
+ QWindow *window = windows[0]->sourceWindow();
+ if (m_pointerWindow != window) {
+ m_pointerWindow = window;
+ QWindowSystemInterface::handleEnterEvent(window, window->mapFromGlobal(pos), pos);
+ }
+ return;
+ }
+
+ QWindow *enter = 0, *leave = 0;
+ for (int i = windows.count() - 1; i >= 0; --i) {
+ QWindow *window = windows[i]->sourceWindow();
+ const QRect geom = window->geometry();
+ if (geom.contains(pos)) {
+ if (m_pointerWindow != window) {
+ leave = m_pointerWindow;
+ m_pointerWindow = window;
+ enter = window;
+ }
+ break;
+ }
+ }
+
+ if (enter && leave)
+ QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos);
+}
+
+QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) const
+{
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
+ Q_ASSERT(!windows.isEmpty());
+
+ QImage img;
+
+ if (static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle())->isRaster()) {
+ // Request the compositor to render everything into an FBO and read it back. This
+ // is of course slow, but it's safe and reliable. It will not include the mouse
+ // cursor, which is a plus.
+ img = compositor->grab();
+ } else {
+ // Just a single OpenGL window without compositing. Do not support this case for now. Doing
+ // glReadPixels is not an option since it would read from the back buffer which may have
+ // undefined content when calling right after a swapBuffers (unless preserved swap is
+ // available and enabled, but we have no support for that).
+ qWarning("grabWindow: Not supported for non-composited OpenGL content. Use QQuickWindow::grabWindow() instead.");
+ return QPixmap();
+ }
+
+ if (!wid) {
+ const QSize screenSize = geometry().size();
+ if (width < 0)
+ width = screenSize.width() - x;
+ if (height < 0)
+ height = screenSize.height() - y;
+ return QPixmap::fromImage(img).copy(x, y, width, height);
+ }
+
+ foreach (QOpenGLCompositorWindow *w, windows) {
+ const QWindow *window = w->sourceWindow();
+ if (window->winId() == wid) {
+ const QRect geom = window->geometry();
+ if (width < 0)
+ width = geom.width() - x;
+ if (height < 0)
+ height = geom.height() - y;
+ QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
+ rect &= window->geometry();
+ return QPixmap::fromImage(img).copy(rect);
+ }
+ }
+
+ return QPixmap();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
new file mode 100644
index 0000000000..092d853ffd
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEGLFSSCREEN_H
+#define QEGLFSSCREEN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qeglfsglobal.h"
+#include <QtCore/QPointer>
+
+#include <qpa/qplatformscreen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSWindow;
+class QOpenGLContext;
+
+class Q_EGLFS_EXPORT QEglFSScreen : public QPlatformScreen
+{
+public:
+ QEglFSScreen(EGLDisplay display);
+ ~QEglFSScreen();
+
+ QRect geometry() const Q_DECL_OVERRIDE;
+ int depth() const Q_DECL_OVERRIDE;
+ QImage::Format format() const Q_DECL_OVERRIDE;
+
+ QSizeF physicalSize() const Q_DECL_OVERRIDE;
+ QDpi logicalDpi() const Q_DECL_OVERRIDE;
+ qreal pixelDensity() const Q_DECL_OVERRIDE;
+ Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE;
+ Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE;
+
+ QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+
+ qreal refreshRate() const Q_DECL_OVERRIDE;
+
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
+
+ EGLSurface primarySurface() const { return m_surface; }
+
+ EGLDisplay display() const { return m_dpy; }
+
+ void handleCursorMove(const QPoint &pos);
+
+private:
+ void setPrimarySurface(EGLSurface surface);
+
+ EGLDisplay m_dpy;
+ QPointer<QWindow> m_pointerWindow;
+ EGLSurface m_surface;
+ QPlatformCursor *m_cursor;
+
+ friend class QEglFSWindow;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSSCREEN_H
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
new file mode 100644
index 0000000000..f602c1b976
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** 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 <QtCore/qtextstream.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qplatformintegration.h>
+#include <private/qguiapplication_p.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/QOpenGLContext>
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+#include <QtPlatformSupport/private/qopenglcompositorbackingstore_p.h>
+
+#include "qeglfswindow_p.h"
+#include "qeglfscursor_p.h"
+#include "qeglfshooks_p.h"
+#include "qeglfsdeviceintegration_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QEglFSWindow::QEglFSWindow(QWindow *w)
+ : QPlatformWindow(w),
+ m_backingStore(0),
+ m_raster(false),
+ m_winId(0),
+ m_surface(EGL_NO_SURFACE),
+ m_window(0),
+ m_flags(0)
+{
+}
+
+QEglFSWindow::~QEglFSWindow()
+{
+ destroy();
+}
+
+static WId newWId()
+{
+ static WId id = 0;
+
+ if (id == std::numeric_limits<WId>::max())
+ qWarning("QEGLPlatformWindow: Out of window IDs");
+
+ return ++id;
+}
+
+void QEglFSWindow::create()
+{
+ if (m_flags.testFlag(Created))
+ return;
+
+ m_winId = newWId();
+
+ // Save the original surface type before changing to OpenGLSurface.
+ m_raster = (window()->surfaceType() == QSurface::RasterSurface);
+ if (m_raster) // change to OpenGL, but not for RasterGLSurface
+ window()->setSurfaceType(QSurface::OpenGLSurface);
+
+ if (window()->type() == Qt::Desktop) {
+ QRect fullscreenRect(QPoint(), screen()->availableGeometry().size());
+ QPlatformWindow::setGeometry(fullscreenRect);
+ QWindowSystemInterface::handleGeometryChange(window(), fullscreenRect);
+ return;
+ }
+
+ m_flags = Created;
+
+ if (window()->type() == Qt::Desktop)
+ return;
+
+ // Stop if there is already a window backed by a native window and surface. Additional
+ // raster windows will not have their own native window, surface and context. Instead,
+ // they will be composited onto the root window's surface.
+ QEglFSScreen *screen = this->screen();
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ if (screen->primarySurface() != EGL_NO_SURFACE) {
+ if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) {
+#if !defined(Q_OS_ANDROID)
+ // We can have either a single OpenGL window or multiple raster windows.
+ // Other combinations cannot work.
+ qFatal("EGLFS: OpenGL windows cannot be mixed with others.");
+#endif
+ return;
+ }
+ m_format = compositor->targetWindow()->format();
+ return;
+ }
+
+ m_flags |= HasNativeWindow;
+ setGeometry(QRect()); // will become fullscreen
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+
+ resetSurface();
+
+ if (Q_UNLIKELY(m_surface == EGL_NO_SURFACE)) {
+ EGLint error = eglGetError();
+ eglTerminate(screen->display());
+ qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error);
+ }
+
+ screen->setPrimarySurface(m_surface);
+
+ if (isRaster()) {
+ QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance());
+ context->setShareContext(qt_gl_global_share_context());
+ context->setFormat(m_format);
+ context->setScreen(window()->screen());
+ if (Q_UNLIKELY(!context->create()))
+ qFatal("EGLFS: Failed to create compositing context");
+ compositor->setTarget(context, window());
+ // If there is a "root" window into which raster and QOpenGLWidget content is
+ // composited, all other contexts must share with its context.
+ if (!qt_gl_global_share_context()) {
+ qt_gl_set_global_share_context(context);
+ // What we set up here is in effect equivalent to the application setting
+ // AA_ShareOpenGLContexts. Set the attribute to be fully consistent.
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
+ }
+ }
+}
+
+void QEglFSWindow::destroy()
+{
+ QEglFSScreen *screen = this->screen();
+ if (m_flags.testFlag(HasNativeWindow)) {
+ QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(screen->cursor());
+ if (cursor)
+ cursor->resetResources();
+
+ if (screen->primarySurface() == m_surface)
+ screen->setPrimarySurface(EGL_NO_SURFACE);
+
+ invalidateSurface();
+ }
+
+ m_flags = 0;
+ QOpenGLCompositor::instance()->removeWindow(this);
+}
+
+void QEglFSWindow::invalidateSurface()
+{
+ if (m_surface != EGL_NO_SURFACE) {
+ eglDestroySurface(screen()->display(), m_surface);
+ m_surface = EGL_NO_SURFACE;
+ }
+ qt_egl_device_integration()->destroyNativeWindow(m_window);
+ m_window = 0;
+}
+
+void QEglFSWindow::resetSurface()
+{
+ EGLDisplay display = screen()->display();
+ QSurfaceFormat platformFormat = qt_egl_device_integration()->surfaceFormatFor(window()->requestedFormat());
+
+ m_config = QEglFSDeviceIntegration::chooseConfig(display, platformFormat);
+ m_format = q_glFormatFromConfig(display, m_config, platformFormat);
+ m_window = qt_egl_device_integration()->createNativeWindow(this, screen()->geometry().size(), m_format);
+ m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
+}
+
+void QEglFSWindow::setVisible(bool visible)
+{
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ QList<QOpenGLCompositorWindow *> windows = compositor->windows();
+ QWindow *wnd = window();
+
+ if (wnd->type() != Qt::Desktop) {
+ if (visible) {
+ compositor->addWindow(this);
+ } else {
+ compositor->removeWindow(this);
+ windows = compositor->windows();
+ if (windows.size())
+ windows.last()->sourceWindow()->requestActivate();
+ }
+ }
+
+ QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
+
+ if (visible)
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+void QEglFSWindow::setGeometry(const QRect &r)
+{
+ QRect rect;
+ bool forceFullscreen = m_flags.testFlag(HasNativeWindow);
+ if (forceFullscreen)
+ rect = screen()->availableGeometry();
+ else
+ rect = r;
+
+ QPlatformWindow::setGeometry(rect);
+
+ // if we corrected the size, trigger a resize event
+ if (rect != r)
+ QWindowSystemInterface::handleGeometryChange(window(), rect, r);
+}
+
+QRect QEglFSWindow::geometry() const
+{
+ // For yet-to-become-fullscreen windows report the geometry covering the entire
+ // screen. This is particularly important for Quick where the root object may get
+ // sized to some geometry queried before calling create().
+ if (!m_flags.testFlag(Created) && screen()->primarySurface() == EGL_NO_SURFACE)
+ return screen()->availableGeometry();
+
+ return QPlatformWindow::geometry();
+}
+
+void QEglFSWindow::requestActivateWindow()
+{
+ if (window()->type() != Qt::Desktop)
+ QOpenGLCompositor::instance()->moveToTop(this);
+
+ QWindow *wnd = window();
+ QWindowSystemInterface::handleWindowActivated(wnd);
+ QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
+}
+
+void QEglFSWindow::raise()
+{
+ QWindow *wnd = window();
+ if (wnd->type() != Qt::Desktop) {
+ QOpenGLCompositor::instance()->moveToTop(this);
+ QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
+ }
+}
+
+void QEglFSWindow::lower()
+{
+ QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
+ QList<QOpenGLCompositorWindow *> windows = compositor->windows();
+ if (window()->type() != Qt::Desktop && windows.count() > 1) {
+ int idx = windows.indexOf(this);
+ if (idx > 0) {
+ compositor->changeWindowIndex(this, idx - 1);
+ QWindowSystemInterface::handleExposeEvent(windows.last()->sourceWindow(),
+ QRect(QPoint(0, 0), windows.last()->sourceWindow()->geometry().size()));
+ }
+ }
+}
+
+EGLSurface QEglFSWindow::surface() const
+{
+ return m_surface != EGL_NO_SURFACE ? m_surface : screen()->primarySurface();
+}
+
+QSurfaceFormat QEglFSWindow::format() const
+{
+ return m_format;
+}
+
+EGLNativeWindowType QEglFSWindow::eglWindow() const
+{
+ return m_window;
+}
+
+QEglFSScreen *QEglFSWindow::screen() const
+{
+ return static_cast<QEglFSScreen *>(QPlatformWindow::screen());
+}
+
+bool QEglFSWindow::isRaster() const
+{
+ return m_raster || window()->surfaceType() == QSurface::RasterGLSurface;
+}
+
+QWindow *QEglFSWindow::sourceWindow() const
+{
+ return window();
+}
+
+const QPlatformTextureList *QEglFSWindow::textures() const
+{
+ if (m_backingStore)
+ return m_backingStore->textures();
+
+ return 0;
+}
+
+void QEglFSWindow::endCompositing()
+{
+ if (m_backingStore)
+ m_backingStore->notifyComposited();
+}
+
+WId QEglFSWindow::winId() const
+{
+ return m_winId;
+}
+
+void QEglFSWindow::setOpacity(qreal)
+{
+ if (!isRaster())
+ qWarning("QEglFSWindow: Cannot set opacity for non-raster windows");
+
+ // Nothing to do here. The opacity is stored in the QWindow.
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
new file mode 100644
index 0000000000..aea4ed4806
--- /dev/null
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QEGLFSWINDOW_H
+#define QEGLFSWINDOW_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qeglfsglobal.h"
+#include "qeglfsintegration.h"
+#include "qeglfsscreen_p.h"
+
+#include <qpa/qplatformwindow.h>
+#include <QtPlatformSupport/private/qopenglcompositor_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLCompositorBackingStore;
+class QPlatformTextureList;
+
+class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow, public QOpenGLCompositorWindow
+{
+public:
+ QEglFSWindow(QWindow *w);
+ ~QEglFSWindow();
+
+ void create();
+ void destroy();
+
+ void setGeometry(const QRect &) Q_DECL_OVERRIDE;
+ QRect geometry() const Q_DECL_OVERRIDE;
+ void setVisible(bool visible) Q_DECL_OVERRIDE;
+ void requestActivateWindow() Q_DECL_OVERRIDE;
+ void raise() Q_DECL_OVERRIDE;
+ void lower() Q_DECL_OVERRIDE;
+
+ void propagateSizeHints() Q_DECL_OVERRIDE { }
+ void setMask(const QRegion &) Q_DECL_OVERRIDE { }
+ bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; }
+ bool setMouseGrabEnabled(bool) Q_DECL_OVERRIDE { return false; }
+ void setOpacity(qreal) Q_DECL_OVERRIDE;
+ WId winId() const Q_DECL_OVERRIDE;
+
+ QSurfaceFormat format() const Q_DECL_OVERRIDE;
+
+ EGLNativeWindowType eglWindow() const;
+ EGLSurface surface() const;
+ QEglFSScreen *screen() const;
+
+ bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); }
+
+ virtual void invalidateSurface() Q_DECL_OVERRIDE;
+ virtual void resetSurface();
+
+ QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; }
+ void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; }
+ bool isRaster() const;
+
+ QWindow *sourceWindow() const Q_DECL_OVERRIDE;
+ const QPlatformTextureList *textures() const Q_DECL_OVERRIDE;
+ void endCompositing() Q_DECL_OVERRIDE;
+
+protected:
+ QOpenGLCompositorBackingStore *m_backingStore;
+ bool m_raster;
+ WId m_winId;
+
+ EGLSurface m_surface;
+ EGLNativeWindowType m_window;
+
+ EGLConfig m_config;
+ QSurfaceFormat m_format;
+
+ enum Flag {
+ Created = 0x01,
+ HasNativeWindow = 0x02
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+ Flags m_flags;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSWINDOW_H