diff options
-rw-r--r-- | src/plugins/platforms/eglfs/eglfs.pri | 9 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfsbackingstore.cpp | 232 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfsbackingstore.h | 28 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfscursor.cpp | 21 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfscursor.h | 5 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfshooks_x11.cpp | 7 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfsintegration.cpp | 25 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfsintegration.h | 6 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfsscreen.cpp | 22 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfsscreen.h | 9 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfswindow.cpp | 152 | ||||
-rw-r--r-- | src/plugins/platforms/eglfs/qeglfswindow.h | 25 |
12 files changed, 386 insertions, 155 deletions
diff --git a/src/plugins/platforms/eglfs/eglfs.pri b/src/plugins/platforms/eglfs/eglfs.pri index 44455ed3d8..4c066d6f26 100644 --- a/src/plugins/platforms/eglfs/eglfs.pri +++ b/src/plugins/platforms/eglfs/eglfs.pri @@ -2,12 +2,13 @@ QT += core-private gui-private platformsupport-private #DEFINES += QEGL_EXTRA_DEBUG -#Avoid X11 header collision +# Avoid X11 header collision DEFINES += MESA_EGL_NO_X11_HEADERS -#To test the hooks on x11 (xlib), comment the above define too -#EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp -#LIBS += -lX11 -lX11-xcb -lxcb +# Uncomment these to enable the X hooks, allowing to test the platform +# plugin in a regular X11 environment (as long as EGL is available). +# EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp +# LIBS += -lX11 -lX11-xcb -lxcb SOURCES += $$PWD/qeglfsintegration.cpp \ $$PWD/qeglfswindow.cpp \ diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp index 35f699d975..ec2f4f9d91 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp @@ -51,104 +51,123 @@ QT_BEGIN_NAMESPACE -QEglFSBackingStore::QEglFSBackingStore(QWindow *window) - : QPlatformBackingStore(window) - , m_context(new QOpenGLContext) - , m_texture(0) - , m_program(0) +QEglFSCompositor::QEglFSCompositor() + : m_rootWindow(0) { - m_context->setFormat(window->requestedFormat()); - m_context->setScreen(window->screen()); - m_context->create(); + m_updateTimer.setSingleShot(true); + m_updateTimer.setInterval(0); + connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll())); } -QEglFSBackingStore::~QEglFSBackingStore() +void QEglFSCompositor::schedule(QEglFSWindow *rootWindow) { - delete m_program; - delete m_context; + m_rootWindow = rootWindow; + if (!m_updateTimer.isActive()) + m_updateTimer.start(); } -QPaintDevice *QEglFSBackingStore::paintDevice() +void QEglFSCompositor::renderAll() { - return &m_image; + Q_ASSERT(m_rootWindow); + QOpenGLContext *context = QEglFSBackingStore::makeRootCurrent(m_rootWindow); + + QEglFSScreen *screen = m_rootWindow->screen(); + QList<QEglFSWindow *> windows = screen->windows(); + for (int i = 0; i < windows.size(); ++i) { + if (windows.at(i)->backingStore()) + render(windows.at(i), m_rootWindow); + } + + context->swapBuffers(m_rootWindow->window()); + context->doneCurrent(); } -void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +void QEglFSCompositor::render(QEglFSWindow *window, QEglFSWindow *rootWindow) { - Q_UNUSED(region); - Q_UNUSED(offset); + QEglFSBackingStore *rootBackingStore = rootWindow->backingStore(); + rootBackingStore->m_program->bind(); - makeCurrent(); + const GLfloat textureCoordinates[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1 + }; QRectF sr = window->screen()->geometry(); - glViewport(0, 0, sr.width(), sr.height()); + QRect r = window->window()->geometry(); + QPoint tl = r.topLeft(); + QPoint br = r.bottomRight(); -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglBackingStore::flush %p", window); -#endif + GLfloat x1 = (tl.x() / sr.width()) * 2 - 1; + GLfloat x2 = (br.x() / sr.width()) * 2 - 1; + GLfloat y1 = ((sr.height() - tl.y()) / sr.height()) * 2 - 1; + GLfloat y2 = ((sr.height() - br.y()) / sr.height()) * 2 - 1; - if (!m_program) { - 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, 0.0, 1.0);\n" - "}\n"; + const GLfloat vertexCoordinates[] = { + x1, y1, + x2, y1, + x2, y2, + x1, y2 + }; - static const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord).bgra;\n" - "}\n"; + glViewport(0, 0, sr.width(), sr.height()); - m_program = new QOpenGLShaderProgram; + glEnableVertexAttribArray(rootBackingStore->m_vertexCoordEntry); + glEnableVertexAttribArray(rootBackingStore->m_textureCoordEntry); - m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); - m_program->link(); + glVertexAttribPointer(rootBackingStore->m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); + glVertexAttribPointer(rootBackingStore->m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry"); - m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry"); - } + glBindTexture(GL_TEXTURE_2D, window->backingStore()->m_texture); - m_program->bind(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - const GLfloat textureCoordinates[] = { - 0, 1, - 1, 1, - 1, 0, - 0, 0 - }; + rootBackingStore->m_program->release(); + glBindTexture(GL_TEXTURE_2D, 0); + glDisableVertexAttribArray(rootBackingStore->m_vertexCoordEntry); + glDisableVertexAttribArray(rootBackingStore->m_textureCoordEntry); +} - QRectF r = window->geometry(); +static QEglFSCompositor *compositor = 0; - GLfloat x1 = (r.left() / sr.width()) * 2 - 1; - GLfloat x2 = (r.right() / sr.width()) * 2 - 1; - GLfloat y1 = (r.top() / sr.height()) * 2 - 1; - GLfloat y2 = (r.bottom() / sr.height()) * 2 - 1; +QEglFSCompositor *QEglFSCompositor::instance() +{ + if (!compositor) + compositor = new QEglFSCompositor; + return compositor; +} - const GLfloat vertexCoordinates[] = { - x1, y1, - x2, y1, - x2, y2, - x1, y2 - }; +QEglFSBackingStore::QEglFSBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , m_window(static_cast<QEglFSWindow *>(window->handle())) + , m_context(0) + , m_texture(0) + , m_program(0) +{ + m_window->setBackingStore(this); +} - glEnableVertexAttribArray(m_vertexCoordEntry); - glEnableVertexAttribArray(m_textureCoordEntry); +QEglFSBackingStore::~QEglFSBackingStore() +{ + delete m_program; + delete m_context; +} - glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); - glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); +QPaintDevice *QEglFSBackingStore::paintDevice() +{ + return &m_image; +} +void QEglFSBackingStore::updateTexture() +{ glBindTexture(GL_TEXTURE_2D, m_texture); if (!m_dirty.isNull()) { + QRegion fixed; QRect imageRect = m_image.rect(); + m_dirty |= imageRect; - QRegion fixed; foreach (const QRect &rect, m_dirty.rects()) { // intersect with image rect to be sure QRect r = imageRect & rect; @@ -176,32 +195,80 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo m_dirty = QRegion(); } +} - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(region); + Q_UNUSED(offset); - m_program->release(); - glBindTexture(GL_TEXTURE_2D, 0); - glDisableVertexAttribArray(m_vertexCoordEntry); - glDisableVertexAttribArray(m_textureCoordEntry); +#ifdef QEGL_EXTRA_DEBUG + qWarning("QEglBackingStore::flush %p", window); +#endif - // draw the cursor - if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->handle()->cursor())) - cursor->paintOnScreen(); + m_window->create(); + QEglFSWindow *rootWin = m_window->screen()->rootWindow(); + if (rootWin) { + makeRootCurrent(rootWin); + updateTexture(); + QEglFSCompositor::instance()->schedule(rootWin); + } +} - m_context->swapBuffers(window); +void QEglFSBackingStore::makeCurrent() +{ + Q_ASSERT(m_window->hasNativeWindow()); + + QWindow *wnd = window(); + if (!m_context) { + m_context = new QOpenGLContext; + m_context->setFormat(wnd->requestedFormat()); + m_context->setScreen(wnd->screen()); + m_context->create(); + } - m_context->doneCurrent(); + m_context->makeCurrent(wnd); } -void QEglFSBackingStore::makeCurrent() +QOpenGLContext *QEglFSBackingStore::makeRootCurrent(QEglFSWindow *rootWin) { - (static_cast<QEglFSWindow *>(window()->handle()))->create(); - m_context->makeCurrent(window()); + Q_ASSERT(rootWin->hasNativeWindow() && rootWin->isRasterRoot()); + + QEglFSBackingStore *rootBackingStore = rootWin->backingStore(); + rootBackingStore->makeCurrent(); + if (!rootBackingStore->m_program) { + 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, 0.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"; + + rootBackingStore->m_program = new QOpenGLShaderProgram; + + rootBackingStore->m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); + rootBackingStore->m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); + rootBackingStore->m_program->link(); + + rootBackingStore->m_vertexCoordEntry = rootBackingStore->m_program->attributeLocation("vertexCoordEntry"); + rootBackingStore->m_textureCoordEntry = rootBackingStore->m_program->attributeLocation("textureCoordEntry"); + } + return rootBackingStore->m_context; } void QEglFSBackingStore::beginPaint(const QRegion &rgn) { - m_dirty = m_dirty | rgn; + m_dirty |= rgn; } void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents) @@ -209,9 +276,12 @@ void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents Q_UNUSED(staticContents); m_image = QImage(size, QImage::Format_RGB32); - makeCurrent(); + m_window->create(); + makeRootCurrent(m_window->screen()->rootWindow()); + if (m_texture) glDeleteTextures(1, &m_texture); + glGenTextures(1, &m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.h b/src/plugins/platforms/eglfs/qeglfsbackingstore.h index 5d86814df9..39bdab1563 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.h +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.h @@ -46,12 +46,35 @@ #include <QImage> #include <QRegion> +#include <QTimer> QT_BEGIN_NAMESPACE class QOpenGLContext; class QOpenGLPaintDevice; class QOpenGLShaderProgram; +class QEglFSWindow; + +class QEglFSCompositor : public QObject +{ + Q_OBJECT + +public: + QEglFSCompositor(); + + void schedule(QEglFSWindow *rootWindow); + + static QEglFSCompositor *instance(); + +private slots: + void renderAll(); + +private: + void render(QEglFSWindow *window, QEglFSWindow *rootWindow); + + QEglFSWindow *m_rootWindow; + QTimer m_updateTimer; +}; class QEglFSBackingStore : public QPlatformBackingStore { @@ -68,7 +91,10 @@ public: private: void makeCurrent(); + static QOpenGLContext *makeRootCurrent(QEglFSWindow *rootWin); + void updateTexture(); + QEglFSWindow *m_window; QOpenGLContext *m_context; QImage m_image; uint m_texture; @@ -76,6 +102,8 @@ private: QOpenGLShaderProgram *m_program; int m_vertexCoordEntry; int m_textureCoordEntry; + + friend class QEglFSCompositor; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp index f54e077311..c00e86de35 100644 --- a/src/plugins/platforms/eglfs/qeglfscursor.cpp +++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp @@ -63,11 +63,20 @@ QEglFSCursor::QEglFSCursor(QEglFSScreen *screen) QEglFSCursor::~QEglFSCursor() { + resetResources(); +} + +void QEglFSCursor::resetResources() +{ if (QOpenGLContext::currentContext()) { glDeleteProgram(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; } static GLuint createShader(GLenum shaderType, const char *program) @@ -201,9 +210,9 @@ bool QEglFSCursor::setCurrentCursor(QCursor *cursor) return false; if (m_cursor.shape == Qt::BitmapCursor) { - m_cursor.customCursorImage = QImage(); // in case render() never uploaded it + 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, @@ -221,6 +230,7 @@ bool QEglFSCursor::setCurrentCursor(QCursor *cursor) 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; @@ -255,7 +265,7 @@ void QEglFSCursor::pointerEvent(const QMouseEvent &event) if (event.type() != QEvent::MouseMove) return; const QRect oldCursorRect = cursorRect(); - m_cursor.pos = event.pos(); + m_cursor.pos = event.screenPos().toPoint(); update(oldCursorRect | cursorRect()); } @@ -280,18 +290,17 @@ void QEglFSCursor::draw(const QRectF &r) if (!m_cursorAtlas.texture) { createCursorTexture(&m_cursorAtlas.texture, m_cursorAtlas.image); - m_cursorAtlas.image = QImage(); if (m_cursor.shape != Qt::BitmapCursor) m_cursor.texture = m_cursorAtlas.texture; } } - if (m_cursor.shape == Qt::BitmapCursor && !m_cursor.customCursorImage.isNull()) { + 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.customCursorImage = QImage(); + m_cursor.customCursorPending = false; } Q_ASSERT(m_cursor.texture); diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/qeglfscursor.h index fdbffde14b..51a34e041d 100644 --- a/src/plugins/platforms/eglfs/qeglfscursor.h +++ b/src/plugins/platforms/eglfs/qeglfscursor.h @@ -69,6 +69,8 @@ public: virtual void paintOnScreen(); + void resetResources(); + protected: #ifndef QT_NO_CURSOR bool setCurrentCursor(QCursor *cursor); @@ -80,7 +82,7 @@ protected: // current cursor information struct Cursor { - Cursor() : texture(0), shape(Qt::BlankCursor), customCursorTexture(0) { } + 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 @@ -89,6 +91,7 @@ protected: QImage customCursorImage; QPoint pos; // current cursor position uint customCursorTexture; + bool customCursorPending; } m_cursor; private: diff --git a/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp b/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp index 50f8d0acb6..a3f94fb5b4 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks_x11.cpp @@ -194,8 +194,11 @@ void EventReader::run() const xcb_atom_t *atoms = m_hooks->atoms(); if (client->format == 32 && client->type == atoms[Atoms::WM_PROTOCOLS] - && client->data.data32[0] == atoms[Atoms::WM_DELETE_WINDOW]) - QWindowSystemInterface::handleCloseEvent(m_hooks->platformWindow()->window()); + && client->data.data32[0] == atoms[Atoms::WM_DELETE_WINDOW]) { + QWindow *window = m_hooks->platformWindow() ? m_hooks->platformWindow()->window() : 0; + if (window) + QWindowSystemInterface::handleCloseEvent(window); + } break; } default: diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 487a2a15ec..12658e6d01 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -49,6 +49,7 @@ #include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixservices_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> @@ -77,7 +78,9 @@ QT_BEGIN_NAMESPACE static void *eglContextForContext(QOpenGLContext *context); QEglFSIntegration::QEglFSIntegration() - : mEventDispatcher(createUnixEventDispatcher()), mFontDb(new QGenericUnixFontDatabase()) + : mEventDispatcher(createUnixEventDispatcher()), + mFontDb(new QGenericUnixFontDatabase), + mServices(new QGenericUnixServices) { QGuiApplicationPrivate::instance()->setEventDispatcher(mEventDispatcher); @@ -161,7 +164,7 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const { - return mFontDb; + return mFontDb.data(); } QAbstractEventDispatcher *QEglFSIntegration::guiThreadEventDispatcher() const @@ -171,10 +174,18 @@ QAbstractEventDispatcher *QEglFSIntegration::guiThreadEventDispatcher() const QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { - if (hint == QPlatformIntegration::ShowIsFullScreen) - return true; + switch (hint) + { + case QPlatformIntegration::ShowIsFullScreen: + return mScreen->rootWindow() == 0; + default: + return QPlatformIntegration::styleHint(hint); + } +} - return QPlatformIntegration::styleHint(hint); +QPlatformServices *QEglFSIntegration::services() const +{ + return mServices.data(); } QPlatformNativeInterface *QEglFSIntegration::nativeInterface() const @@ -187,7 +198,7 @@ void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource QByteArray lowerCaseResource = resource.toLower(); if (lowerCaseResource == "egldisplay") - return static_cast<QEglFSScreen *>(mScreen)->display(); + return mScreen->display(); return 0; } @@ -200,7 +211,7 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi if (window && window->handle()) return static_cast<QEglFSScreen *>(window->handle()->screen())->display(); else - return static_cast<QEglFSScreen *>(mScreen)->display(); + return mScreen->display(); } return 0; diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index dd85788bd8..c6265bb970 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -65,6 +65,7 @@ public: QPlatformNativeInterface *nativeInterface() const; QPlatformFontDatabase *fontDatabase() const; + QPlatformServices *services() const; QAbstractEventDispatcher *guiThreadEventDispatcher() const; @@ -87,8 +88,9 @@ public: private: EGLDisplay mDisplay; QAbstractEventDispatcher *mEventDispatcher; - QPlatformFontDatabase *mFontDb; - QPlatformScreen *mScreen; + QScopedPointer<QPlatformFontDatabase> mFontDb; + QScopedPointer<QPlatformServices> mServices; + QEglFSScreen *mScreen; QPlatformInputContext *mInputContext; }; diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index a726215e67..62f764b392 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QEglFSScreen::QEglFSScreen(EGLDisplay dpy) : m_dpy(dpy) - , m_surface(0) + , m_surface(EGL_NO_SURFACE) , m_cursor(0) { #ifdef QEGL_EXTRA_DEBUG @@ -110,4 +110,24 @@ void QEglFSScreen::setPrimarySurface(EGLSurface surface) m_surface = surface; } +void QEglFSScreen::addWindow(QEglFSWindow *window) +{ + if (!m_windows.contains(window)) + m_windows.append(window); +} + +void QEglFSScreen::removeWindow(QEglFSWindow *window) +{ + m_windows.removeOne(window); +} + +QEglFSWindow *QEglFSScreen::rootWindow() +{ + Q_FOREACH (QEglFSWindow *window, m_windows) { + if (window->isRasterRoot()) + return window; + } + return 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 06cafa20c8..bf7e88bd50 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -52,8 +52,9 @@ QT_BEGIN_NAMESPACE class QPlatformOpenGLContext; class QEglFSCursor; +class QEglFSWindow; -class QEglFSScreen : public QPlatformScreen //huh: FullScreenScreen ;) just to follow namespace +class QEglFSScreen : public QPlatformScreen { public: QEglFSScreen(EGLDisplay display); @@ -73,6 +74,11 @@ public: EGLDisplay display() const { return m_dpy; } EGLSurface primarySurface() const { return m_surface; } + QList<QEglFSWindow *> windows() const { return m_windows; } + void addWindow(QEglFSWindow *window); + void removeWindow(QEglFSWindow *window); + QEglFSWindow *rootWindow(); + protected: void setPrimarySurface(EGLSurface surface); @@ -82,6 +88,7 @@ private: EGLDisplay m_dpy; EGLSurface m_surface; QEglFSCursor *m_cursor; + QList<QEglFSWindow *> m_windows; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index d66f175920..888de058ad 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -41,6 +41,7 @@ #include "qeglfswindow.h" #include "qeglfshooks.h" +#include "qeglfscursor.h" #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformintegration.h> #include <private/qguiapplication_p.h> @@ -55,12 +56,13 @@ QEglFSWindow::QEglFSWindow(QWindow *w) : QPlatformWindow(w) , m_surface(0) , m_window(0) - , has_window(false) + , m_wid(0) + , m_backingStore(0) + , m_flags(0) { #ifdef QEGL_EXTRA_DEBUG qWarning("QEglWindow %p: %p 0x%x\n", this, w, uint(m_window)); #endif - w->setSurfaceType(QSurface::OpenGLSurface); } QEglFSWindow::~QEglFSWindow() @@ -68,17 +70,23 @@ QEglFSWindow::~QEglFSWindow() destroy(); } -static inline bool supportsMultipleWindows() +static WId newWId() { - return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows); + static WId id = 0; + + if (id == std::numeric_limits<WId>::max()) + qWarning("EGLFS: Out of window IDs"); + + return ++id; } void QEglFSWindow::create() { - if (has_window) + if (m_flags.testFlag(Created)) return; - setWindowState(Qt::WindowFullScreen); + m_flags = Created; + m_wid = newWId(); if (window()->type() == Qt::Desktop) { QRect rect(QPoint(), QEglFSHooks::hooks()->screenSize()); @@ -87,94 +95,142 @@ void QEglFSWindow::create() return; } - if (!supportsMultipleWindows() && screen()->primarySurface()) { - qFatal("EGLFS: Multiple windows are not supported"); - return; + // Save the original surface type before changing to OpenGLSurface. + if (window()->surfaceType() == QSurface::RasterSurface) + m_flags |= IsRaster; + + // Stop if there is already a raster root window backed by a native window and + // surface. Other raster windows will not have their own native window, surface and + // context. Instead, they will be composited onto the root window's surface. + if (screen()->primarySurface() != EGL_NO_SURFACE) { + if (m_flags.testFlag(IsRaster) && screen()->rootWindow()->m_flags.testFlag(IsRaster)) + return; + +#ifndef 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 } - EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display(); + window()->setSurfaceType(QSurface::OpenGLSurface); + setGeometry(screen()->availableGeometry()); + QWindowSystemInterface::handleExposeEvent(window(), QRegion(screen()->availableGeometry())); + + EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat()); m_config = QEglFSIntegration::chooseConfig(display, platformFormat); m_format = q_glFormatFromConfig(display, m_config); + resetSurface(); + + m_flags |= HasNativeWindow; + if (screen()->primarySurface() == EGL_NO_SURFACE) { + screen()->setPrimarySurface(m_surface); + m_flags |= IsRasterRoot; + } +} + +void QEglFSWindow::destroy() +{ + if (m_flags.testFlag(HasNativeWindow)) { + QEglFSCursor *cursor = static_cast<QEglFSCursor *>(screen()->cursor()); + if (cursor) + cursor->resetResources(); + if (screen()->primarySurface() == m_surface) + screen()->setPrimarySurface(EGL_NO_SURFACE); + invalidateSurface(); + } + m_flags = 0; + screen()->removeWindow(this); } +// The virtual functions resetSurface and invalidateSurface may get overridden +// in derived classes, for example in the Android port, to perform the native +// window and surface creation differently. + void QEglFSWindow::invalidateSurface() { - // Native surface has been deleted behind our backs - has_window = false; - if (m_surface != 0) { - EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display(); + if (m_surface != EGL_NO_SURFACE) { + EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); eglDestroySurface(display, m_surface); - m_surface = 0; + m_surface = EGL_NO_SURFACE; } + QEglFSHooks::hooks()->destroyNativeWindow(m_window); + m_window = 0; } void QEglFSWindow::resetSurface() { EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); - m_window = QEglFSHooks::hooks()->createNativeWindow(this, QEglFSHooks::hooks()->screenSize(), m_format); - has_window = true; m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL); - if (m_surface == EGL_NO_SURFACE) { EGLint error = eglGetError(); eglTerminate(display); qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error); } - - screen()->setPrimarySurface(m_surface); } -void QEglFSWindow::destroy() +void QEglFSWindow::setVisible(bool visible) { - if (m_surface) { - EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display(); - eglDestroySurface(display, m_surface); - - if (!supportsMultipleWindows()) { - // ours must be the primary surface - screen()->setPrimarySurface(0); + QList<QEglFSWindow *> windows = screen()->windows(); + + if (window()->type() != Qt::Desktop) { + if (visible) { + screen()->addWindow(this); + } else { + screen()->removeWindow(this); + windows = screen()->windows(); + // try activating the window below + if (windows.size()) + windows.last()->requestActivateWindow(); } - - m_surface = 0; } - if (has_window) { - QEglFSHooks::hooks()->destroyNativeWindow(m_window); - has_window = false; + // trigger an update + QEglFSWindow *rootWin = screen()->rootWindow(); + if (rootWin) { + QWindowSystemInterface::handleExposeEvent(rootWin->window(), rootWin->window()->geometry()); + QWindowSystemInterface::flushWindowSystemEvents(); } + + QPlatformWindow::setVisible(visible); } -void QEglFSWindow::setGeometry(const QRect &) +void QEglFSWindow::setGeometry(const QRect &r) { - // We only support full-screen windows - QRect rect(screen()->availableGeometry()); + QRect rect; + if (m_flags.testFlag(HasNativeWindow)) + rect = screen()->availableGeometry(); + else + rect = r; + QPlatformWindow::setGeometry(rect); - QWindowSystemInterface::handleGeometryChange(window(), rect); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(rect)); + + if (rect != r) + QWindowSystemInterface::handleGeometryChange(window(), rect); } -void QEglFSWindow::setWindowState(Qt::WindowState) +WId QEglFSWindow::winId() const { - setGeometry(QRect()); + return m_wid; } -WId QEglFSWindow::winId() const +void QEglFSWindow::requestActivateWindow() { - // Return a fake WId for desktop windows. - if (window()->type() == Qt::Desktop) - return std::numeric_limits<WId>::max(); + if (window()->type() != Qt::Desktop) { + // move to the end of the list, to be on top + screen()->removeWindow(this); + screen()->addWindow(this); + } - return WId(m_window); + QWindowSystemInterface::handleWindowActivated(window()); } EGLSurface QEglFSWindow::surface() const { - if (!supportsMultipleWindows()) - return screen()->primarySurface(); - return m_surface; + return m_surface != EGL_NO_SURFACE ? m_surface : screen()->primarySurface(); } QSurfaceFormat QEglFSWindow::format() const diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index 936537807a..783ae414d6 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE +class QEglFSBackingStore; + class QEglFSWindow : public QPlatformWindow { public: @@ -56,8 +58,9 @@ public: ~QEglFSWindow(); void setGeometry(const QRect &); - void setWindowState(Qt::WindowState state); WId winId() const; + void setVisible(bool visible); + void requestActivateWindow(); EGLSurface surface() const; QSurfaceFormat format() const; @@ -67,6 +70,12 @@ public: void create(); void destroy(); + bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); } + bool isRasterRoot() const { return m_flags.testFlag(IsRasterRoot); } + + QEglFSBackingStore *backingStore() { return m_backingStore; } + void setBackingStore(QEglFSBackingStore *backingStore) { m_backingStore = backingStore; } + virtual void invalidateSurface(); virtual void resetSurface(); @@ -77,7 +86,19 @@ protected: private: EGLConfig m_config; QSurfaceFormat m_format; - bool has_window; + WId m_wid; + QEglFSBackingStore *m_backingStore; + + enum Flag { + Created = 0x01, + HasNativeWindow = 0x02, + IsRaster = 0x04, + IsRasterRoot = 0x08 + }; + Q_DECLARE_FLAGS(Flags, Flag); + Flags m_flags; }; + QT_END_NAMESPACE + #endif // QEGLFSWINDOW_H |