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 <gunnar.sletta@jollamobile.com>
This commit is contained in:
Laszlo Agocs 2014-07-28 15:55:56 +02:00
parent 611558d877
commit b08cc0ec6f
10 changed files with 43 additions and 20 deletions

View File

@ -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.
*/
/*!

View File

@ -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 &region);
#ifndef QT_NO_DRAGANDDROP

View File

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

View File

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

View File

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

View File

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

View File

@ -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<QEglFSScreen *>(screen)->display();
QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat());
@ -168,8 +168,9 @@ void QEglFSWindow::resetSurface()
void QEglFSWindow::setVisible(bool visible)
{
QList<QEGLPlatformWindow *> 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()));
}
}
}

View File

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

View File

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

View File

@ -164,6 +164,8 @@ public:
{
m_received[event->type()]++;
m_order << event->type();
if (event->type() == QEvent::Expose)
m_exposeRegion = static_cast<QExposeEvent *>(event)->region();
return QWindow::event(event);
}
@ -178,9 +180,15 @@ public:
return m_order.indexOf(type);
}
QRegion exposeRegion() const
{
return m_exposeRegion;
}
private:
QHash<QEvent::Type, int> m_received;
QVector<QEvent::Type> 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();