From b08cc0ec6f096d0e6764486c81264c24a406bee1 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 28 Jul 2014 15:55:56 +0200 Subject: [PATCH] Make the expose region local on all platforms QExposeEvent::region() reports a region in a random coordinate system. The behavior is undocumented and the platform plugins do different things. xcb, offscreen and ios are correct. These set the region in local coordinates, which is the most logical interpretation of the expose region. windows is almost correct, except for one occurrence. cocoa and others need changes: passing in geometry() as the exposed region is always wrong. The patch documents the expected behavior both for QExposeEvent and internally in QWindowSystemInterface. The problematic plugins are fixed to use local coordinates. Task-number: QTBUG-40470 Change-Id: I6ded3154d14254fa71d4292d8e1b5e6cf696c81a Reviewed-by: Gunnar Sletta --- src/gui/kernel/qevent.cpp | 5 +++-- src/gui/kernel/qwindowsysteminterface.h | 2 ++ .../android/qandroidplatformopenglwindow.cpp | 2 +- .../android/qandroidplatformscreen.cpp | 2 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 6 +++--- .../platforms/directfb/qdirectfbwindow.cpp | 2 +- src/plugins/platforms/eglfs/qeglfswindow.cpp | 20 +++++++++++-------- src/plugins/platforms/qnx/qqnxwindow.cpp | 6 +++--- .../platforms/windows/qwindowswindow.cpp | 2 +- tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 16 +++++++++++++++ 10 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a002aad3878..1b853411f8f 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1307,7 +1307,8 @@ QMoveEvent::~QMoveEvent() */ /*! - Constructs an expose event for the given \a exposeRegion. + Constructs an expose event for the given \a exposeRegion which must be + in local coordinates. */ QExposeEvent::QExposeEvent(const QRegion &exposeRegion) : QEvent(Expose) @@ -1325,7 +1326,7 @@ QExposeEvent::~QExposeEvent() /*! \fn const QRegion &QExposeEvent::region() const - Returns the window area that has been exposed. + Returns the window area that has been exposed. The region is given in local coordinates. */ /*! diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 1462c62e2b6..580f1f86faf 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -138,6 +138,7 @@ public: static void handleTouchCancelEvent(QWindow *w, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier); + // rect is relative to parent static void handleGeometryChange(QWindow *w, const QRect &newRect, const QRect &oldRect = QRect()); static void handleCloseEvent(QWindow *w, bool *accepted = 0); static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF()); @@ -150,6 +151,7 @@ public: static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate = false); + // region is in local coordinates, do not confuse with geometry which is parent-relative static void handleExposeEvent(QWindow *tlw, const QRegion ®ion); #ifndef QT_NO_DRAGANDDROP diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index 7c39cb718d8..d821145973c 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -86,7 +86,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) && rect.height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) { - QWindowSystemInterface::handleExposeEvent(window(), QRegion(rect)); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); } } diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 529ae0a80de..433461f6288 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -243,7 +243,7 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect) if (w->handle()) { QRect geometry = w->handle()->geometry(); if (geometry.width() > 0 && geometry.height() > 0) - QWindowSystemInterface::handleExposeEvent(w, QRegion(geometry)); + QWindowSystemInterface::handleExposeEvent(w, QRect(QPoint(0, 0), geometry.size())); } } } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 29b983cd895..7e223518183 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -516,7 +516,7 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) // call this here: updateGeometry in qnsview.mm is a no-op for this case QWindowSystemInterface::handleGeometryChange(window(), rect); - QWindowSystemInterface::handleExposeEvent(window(), rect); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); } else if (m_nsWindow) { NSRect bounds = qt_mac_flipRect(rect); [m_nsWindow setFrame:[m_nsWindow frameRectForContentRect:bounds] display:YES animate:NO]; @@ -1749,7 +1749,7 @@ void QCocoaWindow::exposeWindow() m_isExposed = true; m_exposedGeometry = geometry(); m_exposedDevicePixelRatio = devicePixelRatio(); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), m_exposedGeometry.size())); } } @@ -1780,7 +1780,7 @@ void QCocoaWindow::updateExposedGeometry() m_isExposed = true; m_exposedGeometry = geometry(); m_exposedDevicePixelRatio = devicePixelRatio(); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), m_exposedGeometry.size())); } QWindow *QCocoaWindow::childWindowAt(QPoint windowPoint) diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.cpp b/src/plugins/platforms/directfb/qdirectfbwindow.cpp index 670a955bd61..8d7eeb3cd9c 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindow.cpp +++ b/src/plugins/platforms/directfb/qdirectfbwindow.cpp @@ -137,7 +137,7 @@ void QDirectFbWindow::setVisible(bool visible) } if (window()->isTopLevel() && visible) - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry())); } void QDirectFbWindow::setWindowFlags(Qt::WindowFlags flags) diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index a0150b7adea..1f67170efc4 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -98,7 +98,7 @@ void QEglFSWindow::create() m_flags |= HasNativeWindow; setGeometry(QRect()); // will become fullscreen - QWindowSystemInterface::handleExposeEvent(window(), geometry()); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size())); EGLDisplay display = static_cast(screen)->display(); QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat()); @@ -168,8 +168,9 @@ void QEglFSWindow::resetSurface() void QEglFSWindow::setVisible(bool visible) { QList windows = screen()->windows(); + QWindow *wnd = window(); - if (window()->type() != Qt::Desktop) { + if (wnd->type() != Qt::Desktop) { if (visible) { screen()->addWindow(this); } else { @@ -180,7 +181,7 @@ void QEglFSWindow::setVisible(bool visible) } } - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); + QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size())); if (visible) QWindowSystemInterface::flushWindowSystemEvents(); @@ -218,15 +219,17 @@ void QEglFSWindow::requestActivateWindow() if (window()->type() != Qt::Desktop) screen()->moveToTop(this); - QWindowSystemInterface::handleWindowActivated(window()); - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); + QWindow *wnd = window(); + QWindowSystemInterface::handleWindowActivated(wnd); + QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size())); } void QEglFSWindow::raise() { - if (window()->type() != Qt::Desktop) { + QWindow *wnd = window(); + if (wnd->type() != Qt::Desktop) { screen()->moveToTop(this); - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); + QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size())); } } @@ -237,7 +240,8 @@ void QEglFSWindow::lower() int idx = windows.indexOf(this); if (idx > 0) { screen()->changeWindowIndex(this, idx - 1); - QWindowSystemInterface::handleExposeEvent(windows.last()->window(), windows.last()->geometry()); + QWindowSystemInterface::handleExposeEvent(windows.last()->window(), + QRect(QPoint(0, 0), windows.last()->geometry().size())); } } } diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 5a405f95779..56f17e6d117 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -252,7 +252,7 @@ void QQnxWindow::setGeometry(const QRect &rect) setGeometryHelper(newGeometry); if (isExposed()) - QWindowSystemInterface::handleExposeEvent(window(), newGeometry); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), newGeometry.size())); } void QQnxWindow::setGeometryHelper(const QRect &rect) @@ -306,7 +306,7 @@ void QQnxWindow::setVisible(bool visible) root->updateVisibility(root->m_visible); - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size())); if (visible) { applyWindowState(); @@ -345,7 +345,7 @@ void QQnxWindow::setExposed(bool exposed) if (m_exposed != exposed) { m_exposed = exposed; - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size())); } } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index c5978c125cf..3b54feabbf1 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1389,7 +1389,7 @@ void QWindowsWindow::handleGeometryChange() // expose events when shrinking, synthesize. if (!testFlag(OpenGL_ES2) && isExposed() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { - fireExpose(QRegion(m_data.geometry), true); + fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 02f39598026..b4659b7cafa 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -164,6 +164,8 @@ public: { m_received[event->type()]++; m_order << event->type(); + if (event->type() == QEvent::Expose) + m_exposeRegion = static_cast(event)->region(); return QWindow::event(event); } @@ -178,9 +180,15 @@ public: return m_order.indexOf(type); } + QRegion exposeRegion() const + { + return m_exposeRegion; + } + private: QHash m_received; QVector m_order; + QRegion m_exposeRegion; }; void tst_QWindow::eventOrderOnShow() @@ -358,6 +366,14 @@ void tst_QWindow::isExposed() QTRY_VERIFY(window.received(QEvent::Expose) > 0); QTRY_VERIFY(window.isExposed()); + // This is a top-level window so assuming it is completely exposed, the + // expose region must be (0, 0), (width, height). If this is not the case, + // the platform plugin is sending expose events with a region in an + // incorrect coordinate system. + QRect r = window.exposeRegion().boundingRect(); + r = QRect(window.mapToGlobal(r.topLeft()), r.size()); + QCOMPARE(r, window.geometry()); + window.hide(); QCoreApplication::processEvents();