Got rid of Map / Unmap events in favor of Expose event.

Since change 2e4d8f67a8 the need for Map and Unmap events has
gone away, as now the Expose event is used to notify the application
about when it can start rendering.

The Map and Unmap events weren't really used except by QWidget to set
the WA_Mapped flag, which we now set based on the expose / unexpose.

Also guarantee that a Resize event is always sent before the first
Expose, by re-introducing an asynchronous expose event handler. Since
an expose is required before rendering to a QWindow, show a warning if
QOpenGLContext::swapBuffers() or QBackingStore::flush() if called on a
window that has not received its first expose.

Change-Id: Ia6b609aa275d5b463b5011a96f2fd9bbe52e9bc4
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
bb10
Samuel Rødal 2012-03-14 17:55:43 +01:00 committed by Qt by Nokia
parent 9c7cdce672
commit 55fa3c189f
26 changed files with 322 additions and 164 deletions

View File

@ -103,9 +103,9 @@ void Window::mouseMoveEvent(QMouseEvent *event)
p.setRenderHint(QPainter::Antialiasing);
p.drawLine(m_lastPos, event->pos());
m_lastPos = event->pos();
}
scheduleRender();
scheduleRender();
}
}
void Window::mouseReleaseEvent(QMouseEvent *event)
@ -115,9 +115,9 @@ void Window::mouseReleaseEvent(QMouseEvent *event)
p.setRenderHint(QPainter::Antialiasing);
p.drawLine(m_lastPos, event->pos());
m_lastPos = QPoint(-1, -1);
}
scheduleRender();
scheduleRender();
}
}
void Window::exposeEvent(QExposeEvent *)
@ -139,8 +139,7 @@ void Window::resizeEvent(QResizeEvent *)
QPainter p(&m_image);
p.drawImage(0, 0, old);
}
render();
scheduleRender();
}
void Window::keyPressEvent(QKeyEvent *event)
@ -168,7 +167,8 @@ void Window::scheduleRender()
void Window::timerEvent(QTimerEvent *)
{
render();
if (isExposed())
render();
killTimer(m_renderTimer);
m_renderTimer = 0;
}

View File

@ -268,17 +268,14 @@ public:
ScrollPrepare = 204,
Scroll = 205,
Map = 206,
Unmap = 207,
Expose = 206,
Expose = 208,
InputMethodQuery = 207,
OrientationChange = 208, // Screen orientation has changed
InputMethodQuery = 209,
OrientationChange = 210, // Screen orientation has changed
TouchCancel = 209,
TouchCancel = 211,
ThemeChange = 212,
ThemeChange = 210,
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event

View File

@ -971,12 +971,6 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
QGuiApplicationPrivate::processThemeChanged(
static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Map:
QGuiApplicationPrivate::processMapEvent(static_cast<QWindowSystemInterfacePrivate::MapEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Unmap:
QGuiApplicationPrivate::processUnmapEvent(static_cast<QWindowSystemInterfacePrivate::UnmapEvent *>(e));
break;
case QWindowSystemInterfacePrivate::Expose:
QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
break;
@ -1589,30 +1583,28 @@ void QGuiApplicationPrivate::reportLogicalDotsPerInchChange(QWindowSystemInterfa
emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
}
void QGuiApplicationPrivate::processMapEvent(QWindowSystemInterfacePrivate::MapEvent *e)
{
if (!e->mapped)
return;
QEvent event(QEvent::Map);
QCoreApplication::sendSpontaneousEvent(e->mapped.data(), &event);
}
void QGuiApplicationPrivate::processUnmapEvent(QWindowSystemInterfacePrivate::UnmapEvent *e)
{
if (!e->unmapped)
return;
QEvent event(QEvent::Unmap);
QCoreApplication::sendSpontaneousEvent(e->unmapped.data(), &event);
}
void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
{
if (!e->exposed)
return;
QWindow *window = e->exposed.data();
QWindowPrivate *p = qt_window_private(window);
if (!p->receivedExpose) {
if (p->resizeEventPending) {
// as a convenience for plugins, send a resize event before the first expose event if they haven't done so
QSize size = p->geometry.size();
QResizeEvent e(size, size);
QGuiApplication::sendSpontaneousEvent(window, &e);
p->resizeEventPending = false;
}
p->receivedExpose = true;
}
p->exposed = e->isExposed;
QExposeEvent exposeEvent(e->region);
QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);

View File

@ -118,9 +118,6 @@ public:
static void reportLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e);
static void processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce);
static void processMapEvent(QWindowSystemInterfacePrivate::MapEvent *e);
static void processUnmapEvent(QWindowSystemInterfacePrivate::UnmapEvent *e);
static void processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e);
static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);

View File

@ -49,6 +49,7 @@
#include <QtCore/QThread>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qwindow_p.h>
#include <QtGui/QScreen>
#include <private/qopenglextensions_p.h>
@ -502,7 +503,13 @@ void QOpenGLContext::swapBuffers(QSurface *surface)
if (surface->surfaceType() != QSurface::OpenGLSurface) {
qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
return;
}
}
if (surface->surfaceClass() == QSurface::Window
&& !qt_window_private(static_cast<QWindow *>(surface))->receivedExpose)
{
qWarning() << "QOpenGLContext::swapBuffers() called with non-exposed window, behavior is undefined";
}
QPlatformSurface *surfaceHandle = surface->surfaceHandle();
if (!surfaceHandle)

View File

@ -142,11 +142,13 @@ QMargins QPlatformWindow::frameMargins() const
/*!
Reimplemented in subclasses to show the surface
if \a visible is \c true, and hide it if \a visible is \c false.
The default implementation sends a synchronous expose event.
*/
void QPlatformWindow::setVisible(bool visible)
{
Q_UNUSED(visible);
QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size()));
QRect rect(QPoint(), geometry().size());
QWindowSystemInterface::handleSynchronousExposeEvent(window(), rect);
}
/*!
Requests setting the window flags of this surface

View File

@ -108,6 +108,18 @@ QT_BEGIN_NAMESPACE
called whenever the windows exposure in the windowing system changes. On
windowing systems that do not make this information visible to the
application, isExposed() will simply return the same value as isVisible().
\section1 Rendering
There are two Qt APIs that can be used to render content into a window,
QBackingStore for rendering with a QPainter and flushing the contents
to a window with type QSurface::RasterSurface, and QOpenGLContext for
rendering with OpenGL to a window with type QSurface::OpenGLSurface.
The application can start rendering as soon as isExposed() returns true,
and can keep rendering until it isExposed() returns false. To find out when
isExposed() changes, reimplement exposeEvent(). The window will always get
a resize event before the first expose event.
*/
/*!
@ -578,9 +590,7 @@ void QWindow::requestActivateWindow()
bool QWindow::isExposed() const
{
Q_D(const QWindow);
if (d->platformWindow)
return d->platformWindow->isExposed();
return false;
return d->exposed;
}
/*!
@ -1077,6 +1087,9 @@ void QWindow::destroy()
}
setVisible(false);
delete d->platformWindow;
d->resizeEventPending = true;
d->receivedExpose = false;
d->exposed = false;
d->platformWindow = 0;
}
@ -1336,12 +1349,19 @@ bool QWindow::close()
The expose event is sent by the window system whenever the window's
exposure on screen changes.
The application can start rendering into the window with QBackingStore
and QOpenGLContext as soon as it gets an exposeEvent() such that
isExposed() is true.
If the window is moved off screen, is made totally obscured by another
window, iconified or similar, this function might be called and the
value of isExposed() might change to false. When this happens,
an application should stop its rendering as it is no longer visible
to the user.
A resize event will always be sent before the expose event the first time
a window is shown.
\sa isExposed()
*/
void QWindow::exposeEvent(QExposeEvent *ev)
@ -1372,7 +1392,10 @@ void QWindow::resizeEvent(QResizeEvent *ev)
/*!
Override this to handle show events.
The show event is called when the window becomes visible in the windowing system.
The show event is called when the window has requested becoming visible.
If the window is successfully shown by the windowing system, this will
be followed by a resize and an expose event.
*/
void QWindow::showEvent(QShowEvent *ev)
{
@ -1380,9 +1403,10 @@ void QWindow::showEvent(QShowEvent *ev)
}
/*!
Override this to handle show events.
Override this to handle hide evens.
The show event is called when the window becomes hidden in the windowing system.
The hide event is called when the window has requested being hidden in the
windowing system.
*/
void QWindow::hideEvent(QHideEvent *ev)
{

View File

@ -72,8 +72,10 @@ public:
, parentWindow(0)
, platformWindow(0)
, visible(false)
, exposed(false)
, windowState(Qt::WindowNoState)
, resizeEventPending(true)
, receivedExpose(false)
, positionPolicy(WindowFrameExclusive)
, contentOrientation(Qt::PrimaryOrientation)
, windowOrientation(Qt::PrimaryOrientation)
@ -99,17 +101,18 @@ public:
return offset;
}
QWindow::SurfaceType surfaceType;
Qt::WindowFlags windowFlags;
QWindow *parentWindow;
QPlatformWindow *platformWindow;
bool visible;
bool exposed;
QSurfaceFormat requestedFormat;
QString windowTitle;
QRect geometry;
Qt::WindowState windowState;
bool resizeEventPending;
bool receivedExpose;
PositionPolicy positionPolicy;
Qt::ScreenOrientation contentOrientation;
Qt::ScreenOrientation windowOrientation;

View File

@ -39,6 +39,7 @@
**
****************************************************************************/
#include "qwindowsysteminterface_qpa.h"
#include "qplatformwindow_qpa.h"
#include "qwindowsysteminterface_qpa_p.h"
#include "private/qguiapplication_p.h"
#include "private/qevent_p.h"
@ -274,6 +275,15 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
QWindowSystemInterfacePrivate::ExposeEvent::ExposeEvent(QWindow *exposed, const QRegion &region)
: WindowSystemEvent(Expose)
, exposed(exposed)
, isExposed(exposed && exposed->handle() ? exposed->handle()->isExposed() : false)
, region(region)
{
}
int QWindowSystemInterfacePrivate::windowSystemEventsQueued()
{
queueMutex.lock();
@ -426,15 +436,9 @@ void QWindowSystemInterface::handleThemeChange(QWindow *tlw)
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleMapEvent(QWindow *tlw)
void QWindowSystemInterface::handleExposeEvent(QWindow *tlw, const QRegion &region)
{
QWindowSystemInterfacePrivate::MapEvent *e = new QWindowSystemInterfacePrivate::MapEvent(tlw);
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
void QWindowSystemInterface::handleUnmapEvent(QWindow *tlw)
{
QWindowSystemInterfacePrivate::UnmapEvent *e = new QWindowSystemInterfacePrivate::UnmapEvent(tlw);
QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, region);
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}

View File

@ -130,9 +130,7 @@ public:
static void handleWindowActivated(QWindow *w);
static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState);
static void handleMapEvent(QWindow *w);
static void handleUnmapEvent(QWindow *w);
static void handleExposeEvent(QWindow *tlw, const QRegion &region);
static void handleSynchronousExposeEvent(QWindow *tlw, const QRegion &region);
// Drag and drop. These events are sent immediately.

View File

@ -42,6 +42,7 @@
#define QWINDOWSYSTEMINTERFACE_QPA_P_H
#include "qwindowsysteminterface_qpa.h"
#include <QElapsedTimer>
QT_BEGIN_HEADER
@ -66,8 +67,6 @@ public:
ScreenAvailableGeometry,
ScreenLogicalDotsPerInch,
ThemeChange,
Map,
Unmap,
Expose
};
@ -241,28 +240,11 @@ public:
QWeakPointer<QWindow> window;
};
class MapEvent : public WindowSystemEvent {
public:
MapEvent(QWindow *mapped)
: WindowSystemEvent(Map), mapped(mapped)
{ }
QWeakPointer<QWindow> mapped;
};
class UnmapEvent : public WindowSystemEvent {
public:
UnmapEvent(QWindow *unmapped)
: WindowSystemEvent(Unmap), unmapped(unmapped)
{ }
QWeakPointer<QWindow> unmapped;
};
class ExposeEvent : public WindowSystemEvent {
public:
ExposeEvent(QWindow *exposed, const QRegion &region)
: WindowSystemEvent(Expose), exposed(exposed), region(region)
{ }
ExposeEvent(QWindow *exposed, const QRegion &region);
QWeakPointer<QWindow> exposed;
bool isExposed;
QRegion region;
};

View File

@ -82,6 +82,10 @@ void QBackingStore::flush(const QRegion &region, QWindow *win, const QPoint &off
{
if (!win)
win = window();
if (win && !qt_window_private(win)->receivedExpose)
qWarning("QBackingStore::flush() called with non-exposed window, behavior is undefined");
d_ptr->platformBackingStore->flush(win, region, offset);
}

View File

@ -3770,7 +3770,7 @@ void QGLWidget::setFormat(const QGLFormat &format)
void QGLWidget::updateGL()
{
if (updatesEnabled())
if (updatesEnabled() && testAttribute(Qt::WA_Mapped))
glDraw();
}

View File

@ -708,7 +708,6 @@ void QWindowsWindow::setVisible(bool visible)
hide_sys();
}
}
QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size()));
}
bool QWindowsWindow::isVisible() const
@ -804,12 +803,12 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
void QWindowsWindow::handleShown()
{
QWindowSystemInterface::handleMapEvent(window());
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
}
void QWindowsWindow::handleHidden()
{
QWindowSystemInterface::handleUnmapEvent(window());
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
}
void QWindowsWindow::setGeometry(const QRect &rectIn)

View File

@ -160,6 +160,8 @@ void QXcbWindow::create()
{
destroy();
m_deferredExpose = false;
m_configureNotifyPending = true;
m_windowState = Qt::WindowNoState;
Qt::WindowType type = window()->windowType();
@ -1260,7 +1262,7 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
// if count is non-zero there are more expose events pending
if (event->count == 0) {
QWindowSystemInterface::handleSynchronousExposeEvent(window(), m_exposeRegion);
QWindowSystemInterface::handleExposeEvent(window(), m_exposeRegion);
m_exposeRegion = QRegion();
}
}
@ -1327,6 +1329,13 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
m_configureNotifyPending = false;
if (m_deferredExpose) {
m_deferredExpose = false;
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
}
m_dirtyFrameMargins = true;
#if XCB_USE_DRI2
@ -1335,13 +1344,21 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
#endif
}
bool QXcbWindow::isExposed() const
{
return m_mapped;
}
void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
{
if (event->window == m_window) {
m_mapped = true;
if (m_deferredActivation)
requestActivateWindow();
QWindowSystemInterface::handleMapEvent(window());
if (m_configureNotifyPending)
m_deferredExpose = true;
else
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
}
}
@ -1349,7 +1366,7 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
{
if (event->window == m_window) {
m_mapped = false;
QWindowSystemInterface::handleUnmapEvent(window());
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
}
}

View File

@ -72,6 +72,8 @@ public:
WId winId() const;
void setParent(const QPlatformWindow *window);
bool isExposed() const;
void setWindowTitle(const QString &title);
void raise();
void lower();
@ -155,6 +157,8 @@ private:
bool m_mapped;
bool m_transparent;
bool m_deferredActivation;
bool m_deferredExpose;
bool m_configureNotifyPending;
xcb_window_t m_netWmUserTimeWindow;
QSurfaceFormat m_format;

View File

@ -440,9 +440,9 @@ static inline QRect positionTopLevelWindow(QRect geometry, const QScreen *screen
void QWidgetPrivate::show_sys()
{
Q_Q(QWidget);
q->setAttribute(Qt::WA_Mapped);
if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
invalidateBuffer(q->rect());
q->setAttribute(Qt::WA_Mapped);
return;
}
@ -483,8 +483,8 @@ void QWidgetPrivate::show_sys()
void QWidgetPrivate::hide_sys()
{
Q_Q(QWidget);
q->setAttribute(Qt::WA_Mapped, false);
deactivateWidgetCleanup();
if (!q->isWindow()) {
QWidget *p = q->parentWidget();
if (p &&p->isVisible()) {
@ -492,7 +492,12 @@ void QWidgetPrivate::hide_sys()
}
return;
}
if (QWindow *window = q->windowHandle()) {
invalidateBuffer(q->rect());
if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
q->setAttribute(Qt::WA_Mapped, false);
} else if (QWindow *window = q->windowHandle()) {
window->setVisible(false);
}
}

View File

@ -914,29 +914,7 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra)
{
if (!tlw || !tlwExtra)
return true;
#ifdef Q_WS_X11
// Delay the sync until we get an Expose event from X11 (initial show).
// Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred.
// However, we must repaint immediately regardless of the state if someone calls repaint().
if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint)
return true;
#endif
if (!tlw->testAttribute(Qt::WA_Mapped))
return true;
if (!tlw->isVisible()
#ifndef Q_WS_X11
// If we're minimized on X11, WA_Mapped will be false and we
// will return in the case above. Some window managers on X11
// sends us the PropertyNotify to change the minimized state
// *AFTER* we've received the expose event, which is baaad.
|| tlw->isMinimized()
#endif
)
if (!tlw || !tlwExtra || !tlw->testAttribute(Qt::WA_Mapped) || !tlw->isVisible())
return true;
return false;
@ -1345,6 +1323,9 @@ void QWidgetPrivate::repaint_sys(const QRegion &rgn)
return;
Q_Q(QWidget);
if (discardSyncRequest(q, maybeTopData()))
return;
if (q->testAttribute(Qt::WA_StaticContents)) {
if (!extra)
createExtra();

View File

@ -137,15 +137,6 @@ bool QWidgetWindow::event(QEvent *event)
handleDragEvent(event);
break;
case QEvent::Map:
m_widget->setAttribute(Qt::WA_Mapped);
m_widget->d_func()->syncBackingStore();
return true;
case QEvent::Unmap:
m_widget->setAttribute(Qt::WA_Mapped, false);
return true;
case QEvent::Expose:
handleExposeEvent(static_cast<QExposeEvent *>(event));
return true;
@ -432,7 +423,13 @@ void QWidgetWindow::handleDragEvent(QEvent *event)
void QWidgetWindow::handleExposeEvent(QExposeEvent *event)
{
m_widget->d_func()->syncBackingStore(event->region());
if (isExposed()) {
m_widget->setAttribute(Qt::WA_Mapped);
if (!event->region().isNull())
m_widget->d_func()->syncBackingStore(event->region());
} else {
m_widget->setAttribute(Qt::WA_Mapped, false);
}
}
void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event)

View File

@ -1,5 +1,6 @@
TEMPLATE=subdirs
SUBDIRS=\
qbackingstore \
qclipboard \
qdrag \
qevent \

View File

@ -0,0 +1,9 @@
CONFIG += testcase
TARGET = tst_qbackingstore
QT += core-private gui-private testlib
SOURCES += tst_qbackingstore.cpp
mac: CONFIG += insignificant_test # QTBUG-23059
win32: CONFIG += insignificant_test # QTBUG-24885

View File

@ -0,0 +1,103 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qwindow.h>
#include <qbackingstore.h>
#include <qpainter.h>
#include <QtTest/QtTest>
#include <QEvent>
// For QSignalSpy slot connections.
Q_DECLARE_METATYPE(Qt::ScreenOrientation)
class tst_QBackingStore : public QObject
{
Q_OBJECT
private slots:
void flush();
};
class Window : public QWindow
{
public:
Window()
: backingStore(this)
{
}
void resizeEvent(QResizeEvent *)
{
backingStore.resize(size());
}
void exposeEvent(QExposeEvent *event)
{
QRect rect(QPoint(), size());
backingStore.beginPaint(rect);
QPainter p(backingStore.paintDevice());
p.fillRect(rect, Qt::white);
p.end();
backingStore.endPaint();
backingStore.flush(event->region().boundingRect());
}
private:
QBackingStore backingStore;
};
void tst_QBackingStore::flush()
{
Window window;
window.setGeometry(20, 20, 200, 200);
window.showMaximized();
QTRY_VERIFY(window.isExposed());
}
#include <tst_qbackingstore.moc>
QTEST_MAIN(tst_QBackingStore);

View File

@ -6,4 +6,5 @@ QT += core-private gui-private testlib
SOURCES += tst_qwindow.cpp
mac: CONFIG += insignificant_test # QTBUG-23059
win32: CONFIG += insignificant_test # QTBUG-24904

View File

@ -53,8 +53,10 @@ class tst_QWindow: public QObject
Q_OBJECT
private slots:
void eventOrderOnShow();
void mapGlobal();
void positioning();
void isExposed();
void isActive();
void testInputEvents();
void touchToMouseTranslation();
@ -114,6 +116,7 @@ public:
bool event(QEvent *event)
{
m_received[event->type()]++;
m_order << event->type();
return QWindow::event(event);
}
@ -123,10 +126,32 @@ public:
return m_received.value(type, 0);
}
int eventIndex(QEvent::Type type)
{
return m_order.indexOf(type);
}
private:
QHash<QEvent::Type, int> m_received;
QVector<QEvent::Type> m_order;
};
void tst_QWindow::eventOrderOnShow()
{
QRect geometry(80, 80, 40, 40);
Window window;
window.setGeometry(geometry);
window.show();
QTRY_COMPARE(window.received(QEvent::Show), 1);
QTRY_COMPARE(window.received(QEvent::Resize), 1);
QTRY_VERIFY(window.isExposed());
QVERIFY(window.eventIndex(QEvent::Show) < window.eventIndex(QEvent::Resize));
QVERIFY(window.eventIndex(QEvent::Resize) < window.eventIndex(QEvent::Expose));
}
void tst_QWindow::positioning()
{
QRect geometry(80, 80, 40, 40);
@ -137,7 +162,7 @@ void tst_QWindow::positioning()
window.show();
QTRY_COMPARE(window.received(QEvent::Resize), 1);
QTRY_COMPARE(window.received(QEvent::Map), 1);
QTRY_VERIFY(window.received(QEvent::Expose) > 0);
QMargins originalMargins = window.frameMargins();
@ -148,6 +173,9 @@ void tst_QWindow::positioning()
QPoint originalFramePos = window.framePos();
window.setWindowState(Qt::WindowFullScreen);
#ifdef Q_OS_WIN
QEXPECT_FAIL("", "QTBUG-24904 - Too many resize events on setting window state", Continue);
#endif
QTRY_COMPARE(window.received(QEvent::Resize), 2);
window.setWindowState(Qt::WindowNoState);
@ -179,13 +207,32 @@ void tst_QWindow::positioning()
}
}
void tst_QWindow::isExposed()
{
QRect geometry(80, 80, 40, 40);
Window window;
window.setGeometry(geometry);
QCOMPARE(window.geometry(), geometry);
window.show();
QTRY_VERIFY(window.received(QEvent::Expose) > 0);
QTRY_VERIFY(window.isExposed());
window.hide();
QTRY_VERIFY(window.received(QEvent::Expose) > 1);
QTRY_VERIFY(!window.isExposed());
}
void tst_QWindow::isActive()
{
Window window;
window.setGeometry(80, 80, 40, 40);
window.show();
QTRY_COMPARE(window.received(QEvent::Map), 1);
QTRY_VERIFY(window.isExposed());
QTRY_COMPARE(window.received(QEvent::Resize), 1);
QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
QVERIFY(window.isActive());
@ -195,15 +242,14 @@ void tst_QWindow::isActive()
child.setGeometry(10, 10, 20, 20);
child.show();
QTRY_COMPARE(child.received(QEvent::Map), 1);
QTRY_VERIFY(child.isExposed());
child.requestActivateWindow();
QTRY_VERIFY(QGuiApplication::focusWindow() == &child);
QVERIFY(child.isActive());
// parent shouldn't receive new map or resize events from child being shown
QTRY_COMPARE(window.received(QEvent::Map), 1);
// parent shouldn't receive new resize events from child being shown
QTRY_COMPARE(window.received(QEvent::Resize), 1);
QTRY_COMPARE(window.received(QEvent::FocusIn), 1);
QTRY_COMPARE(window.received(QEvent::FocusOut), 1);
@ -219,7 +265,7 @@ void tst_QWindow::isActive()
dialog.requestActivateWindow();
QTRY_COMPARE(dialog.received(QEvent::Map), 1);
QTRY_VERIFY(dialog.isExposed());
QTRY_COMPARE(dialog.received(QEvent::Resize), 1);
QTRY_VERIFY(QGuiApplication::focusWindow() == &dialog);
QVERIFY(dialog.isActive());

View File

@ -11116,20 +11116,23 @@ void tst_QGraphicsItem::doNotMarkFullUpdateIfNotInScene()
view.showFullScreen();
else
view.show();
QTest::qWaitForWindowShown(&view);
QEXPECT_FAIL("", "QTBUG-22434", Abort);
QTRY_COMPARE(view.repaints, 1);
QTRY_COMPARE(item->painted, 1);
QTest::qWaitForWindowShown(view.windowHandle());
view.activateWindow();
QTRY_VERIFY(view.isActiveWindow());
QTRY_VERIFY(view.repaints >= 1);
int count = view.repaints;
QTRY_COMPARE(item->painted, count);
// cached as graphics effects, not painted multiple times
QTRY_COMPARE(item2->painted, 1);
QTRY_COMPARE(item3->painted, 1);
item2->update();
QApplication::processEvents();
QTRY_COMPARE(item->painted, 2);
QTRY_COMPARE(item->painted, count + 1);
QTRY_COMPARE(item2->painted, 2);
QTRY_COMPARE(item3->painted, 2);
item2->update();
QApplication::processEvents();
QTRY_COMPARE(item->painted, 3);
QTRY_COMPARE(item->painted, count + 2);
QTRY_COMPARE(item2->painted, 3);
QTRY_COMPARE(item3->painted, 3);
}

View File

@ -1078,19 +1078,14 @@ void tst_QGraphicsScene::addItem()
CustomView view;
view.setScene(&scene);
view.show();
#ifdef Q_WS_X11
qt_x11_wait_for_window_manager(&view);
#endif
QTest::qWaitForWindowShown(view.windowHandle());
qApp->processEvents();
view.repaints = 0;
scene.addItem(path);
// Adding an item should always issue a repaint.
qApp->processEvents(); // <- delayed update is called
qApp->processEvents(); // <- scene schedules pending update
qApp->processEvents(); // <- pending update is sent to view
QVERIFY(view.repaints > 0);
QTRY_VERIFY(view.repaints > 0);
view.repaints = 0;
QCOMPARE(scene.itemAt(0, 0), path);
@ -1103,10 +1098,7 @@ void tst_QGraphicsScene::addItem()
scene.addItem(path2);
// Adding an item should always issue a repaint.
qApp->processEvents(); // <- delayed update is called
qApp->processEvents(); // <- scene schedules pending update
qApp->processEvents(); // <- pending update is sent to view
QVERIFY(view.repaints > 0);
QTRY_VERIFY(view.repaints > 0);
QCOMPARE(scene.itemAt(100, 100), path2);
}
@ -1285,9 +1277,7 @@ void tst_QGraphicsScene::removeItem()
QGraphicsView view(&scene);
view.setFixedSize(150, 150);
view.show();
#ifdef Q_WS_X11
qt_x11_wait_for_window_manager(&view);
#endif
QTest::qWaitForWindowShown(view.windowHandle());
QTest::mouseMove(view.viewport(), QPoint(-1, -1));
{
QMouseEvent moveEvent(QEvent::MouseMove, view.mapFromScene(hoverItem->scenePos() + QPointF(20, 20)), Qt::NoButton, 0, 0);
@ -1615,9 +1605,7 @@ void tst_QGraphicsScene::hoverEvents_siblings()
view.rotate(10);
view.scale(1.7, 1.7);
view.show();
#ifdef Q_WS_X11
qt_x11_wait_for_window_manager(&view);
#endif
QTest::qWaitForWindowShown(view.windowHandle());
qApp->setActiveWindow(&view);
view.activateWindow();
QTest::qWait(70);
@ -2748,11 +2736,8 @@ void tst_QGraphicsScene::contextMenuEvent()
QGraphicsView view(&scene);
view.show();
QTest::qWaitForWindowShown(&view);
QTest::qWaitForWindowShown(view.windowHandle());
view.activateWindow();
#ifdef Q_WS_X11
qt_x11_wait_for_window_manager(&view);
#endif
view.centerOn(item);
{
@ -2785,10 +2770,7 @@ void tst_QGraphicsScene::contextMenuEvent_ItemIgnoresTransformations()
QGraphicsView view(&scene, &topLevel);
view.resize(200, 200);
topLevel.show();
#ifdef Q_WS_X11
qt_x11_wait_for_window_manager(&view);
#endif
QTest::qWaitForWindowShown(&topLevel);
QTest::qWaitForWindowShown(topLevel.windowHandle());
{
QPoint pos(50, 50);