Got rid of Map / Unmap events in favor of Expose event.
authorSamuel Rødal <samuel.rodal@nokia.com>
Wed, 14 Mar 2012 16:55:43 +0000 (17:55 +0100)
committerQt by Nokia <qt-info@nokia.com>
Thu, 22 Mar 2012 10:43:36 +0000 (11:43 +0100)
Since change 2e4d8f67a871f2033 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>
26 files changed:
examples/qpa/windows/window.cpp
src/corelib/kernel/qcoreevent.h
src/gui/kernel/qguiapplication.cpp
src/gui/kernel/qguiapplication_p.h
src/gui/kernel/qopenglcontext.cpp
src/gui/kernel/qplatformwindow_qpa.cpp
src/gui/kernel/qwindow.cpp
src/gui/kernel/qwindow_p.h
src/gui/kernel/qwindowsysteminterface_qpa.cpp
src/gui/kernel/qwindowsysteminterface_qpa.h
src/gui/kernel/qwindowsysteminterface_qpa_p.h
src/gui/painting/qbackingstore.cpp
src/opengl/qgl.cpp
src/plugins/platforms/windows/qwindowswindow.cpp
src/plugins/platforms/xcb/qxcbwindow.cpp
src/plugins/platforms/xcb/qxcbwindow.h
src/widgets/kernel/qwidget_qpa.cpp
src/widgets/kernel/qwidgetbackingstore.cpp
src/widgets/kernel/qwidgetwindow_qpa.cpp
tests/auto/gui/kernel/kernel.pro
tests/auto/gui/kernel/qbackingstore/qbackingstore.pro [new file with mode: 0644]
tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp [new file with mode: 0644]
tests/auto/gui/kernel/qwindow/qwindow.pro
tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp

index 3ea2f61..f0eba15 100644 (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;
 }
index 1d54b32..a207849 100644 (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
index c6ff5bb..0fd18e7 100644 (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)
+void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
 {
-    if (!e->mapped)
+    if (!e->exposed)
         return;
 
-    QEvent event(QEvent::Map);
-    QCoreApplication::sendSpontaneousEvent(e->mapped.data(), &event);
-}
+    QWindow *window = e->exposed.data();
+    QWindowPrivate *p = qt_window_private(window);
 
-void QGuiApplicationPrivate::processUnmapEvent(QWindowSystemInterfacePrivate::UnmapEvent *e)
-{
-    if (!e->unmapped)
-        return;
+    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);
 
-    QEvent event(QEvent::Unmap);
-    QCoreApplication::sendSpontaneousEvent(e->unmapped.data(), &event);
-}
+            p->resizeEventPending = false;
+        }
 
-void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
-{
-    if (!e->exposed)
-        return;
+        p->receivedExpose = true;
+    }
 
-    QWindow *window = e->exposed.data();
+    p->exposed = e->isExposed;
 
     QExposeEvent exposeEvent(e->region);
     QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);
index f30a2bb..6792e93 100644 (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);
index eaff417..29f46ae 100644 (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)
index e12228d..c8e2776 100644 (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
index 78b6f6f..ab1e8f7 100644 (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)
 {
index 7f3958b..03b3b92 100644 (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;
index 9ab91d6..fcffd75 100644 (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)
-{
-    QWindowSystemInterfacePrivate::MapEvent *e = new QWindowSystemInterfacePrivate::MapEvent(tlw);
-    QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
-}
-
-void QWindowSystemInterface::handleUnmapEvent(QWindow *tlw)
+void QWindowSystemInterface::handleExposeEvent(QWindow *tlw, const QRegion &region)
 {
-    QWindowSystemInterfacePrivate::UnmapEvent *e = new QWindowSystemInterfacePrivate::UnmapEvent(tlw);
+    QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, region);
     QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
 }
 
index 560f47d..1fbf430 100644 (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.
index fe97b48..d7be769 100644 (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;
     };
 
index 03c2fc8..63f7ba5 100644 (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);
 }
 
index eb27e86..2c683f7 100644 (file)
@@ -3770,7 +3770,7 @@ void QGLWidget::setFormat(const QGLFormat &format)
 
 void QGLWidget::updateGL()
 {
-    if (updatesEnabled())
+    if (updatesEnabled() && testAttribute(Qt::WA_Mapped))
         glDraw();
 }
 
index fa3661d..6ff8548 100644 (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)
index 4de3734..3e63ab0 100644 (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());
     }
 }
 
index c212095..37e0bdb 100644 (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;
index 3d23b04..0f55646 100644 (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);
     }
 }
index b331356..2e9f072 100644 (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();
index f58dddb..498908f 100644 (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)
index 48d94b9..0bd988b 100644 (file)
@@ -1,5 +1,6 @@
 TEMPLATE=subdirs
 SUBDIRS=\
+   qbackingstore \
    qclipboard \
    qdrag \
    qevent \
diff --git a/tests/auto/gui/kernel/qbackingstore/qbackingstore.pro b/tests/auto/gui/kernel/qbackingstore/qbackingstore.pro
new file mode 100644 (file)
index 0000000..cc0a2c6
--- /dev/null
@@ -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
diff --git a/tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp b/tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp
new file mode 100644 (file)
index 0000000..678e616
--- /dev/null
@@ -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);
index 363f7dd..fb8132a 100644 (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
 
index f4556f7..ebd8823 100644 (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());
index 98c3866..639a1f6 100644 (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);
 }
index daa06d0..d7b1ef9 100644 (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);