diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index bd5e21c485..976d89b30a 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -592,6 +592,36 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, return rect; } +/*! + Requests an QEvent::UpdateRequest event. The event will be + delivered to the QWindow. + + QPlatformWindow subclasses can re-implement this function to + provide display refresh synchronized updates. The event + should be delivered using QWindowPrivate::deliverUpdateRequest() + to not get out of sync with the the internal state of QWindow. + + The default implementation posts an UpdateRequest event to the + window after 5 ms. The additional time is there to give the event + loop a bit of idle time to gather system events. + +*/ +void QPlatformWindow::requestUpdate() +{ + static int timeout = -1; + if (timeout == -1) { + bool ok = false; + timeout = qEnvironmentVariableIntValue("QT_QPA_UPDATE_IDLE_TIME", &ok); + if (!ok) + timeout = 5; + } + + QWindow *w = window(); + QWindowPrivate *wp = (QWindowPrivate *) QObjectPrivate::get(w); + Q_ASSERT(wp->updateTimer == 0); + wp->updateTimer = w->startTimer(timeout, Qt::PreciseTimer); +} + /*! \class QPlatformWindow \since 4.8 diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 5c351a69d2..87781caf8b 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -129,6 +129,7 @@ public: static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight); + virtual void requestUpdate(); protected: static QString formatWindowTitle(const QString &title, const QString &separator); QPlatformScreen *screenForGeometry(const QRect &newGeometry) const; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 03425f5c0f..8dca5c63b6 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2043,12 +2043,56 @@ bool QWindow::event(QEvent *ev) break; #endif + case QEvent::Timer: { + Q_D(QWindow); + if (static_cast(ev)->timerId() == d->updateTimer) { + killTimer(d->updateTimer); + d->updateTimer = 0; + d->deliverUpdateRequest(); + } else { + QObject::event(ev); + } + break; + } + default: return QObject::event(ev); } return true; } +void QWindowPrivate::deliverUpdateRequest() +{ + Q_Q(QWindow); + updateRequestPending = false; + QEvent request(QEvent::UpdateRequest); + QCoreApplication::sendEvent(q, &request); +} + +/*! + Schedules a QEvent::UpdateRequest event to be delivered to this window. + + The event is delivered in sync with the display vsync on platforms + where this is possible. When driving animations, this function should + be called once after drawing has completed. + + Calling this function multiple times will result in a single event + being delivered to the window. + + Subclasses of QWindow should reimplement QWindow::event(), intercept + the event and call the application's rendering code, then call the + base class implementation. +*/ + +void QWindow::requestUpdate() +{ + Q_D(QWindow); + if (d->updateRequestPending || !d->platformWindow) + return; + d->updateRequestPending = true; + d->platformWindow->requestUpdate(); +} + /*! Override this to handle key press events (\a ev). diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 7cd25b010f..6d9793ae3f 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -286,6 +286,8 @@ public Q_SLOTS: Q_REVISION(1) void alert(int msec); + Q_REVISION(3) void requestUpdate(); + Q_SIGNALS: void screenChanged(QScreen *screen); void modalityChanged(Qt::WindowModality modality); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 46dc2e463c..ea0bb75d85 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -86,6 +86,8 @@ public: , maximumSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX) , modality(Qt::NonModal) , blockedByModalWindow(false) + , updateRequestPending(false) + , updateTimer(0) , transientParent(0) , topLevelScreen(0) #ifndef QT_NO_CURSOR @@ -109,6 +111,8 @@ public: void applyCursor(); #endif + void deliverUpdateRequest(); + QPoint globalPosition() const { Q_Q(const QWindow); QPoint offset = q->position(); @@ -162,6 +166,9 @@ public: Qt::WindowModality modality; bool blockedByModalWindow; + bool updateRequestPending; + int updateTimer; + QPointer transientParent; QScreen *topLevelScreen;