From 33d748bb88676b69e596ae77badfeaf5a69a33d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 10 Sep 2015 16:15:35 +0200 Subject: [PATCH] Allow granular synchronous and asynchronous delivery of QPA events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setSynchronousWindowSystemEvents() API of QWindowSystemInterface is supposed to be set globally by the platform plugin, not switched on and off to trigger async/sync deliver of events for a specific event. We introduce processWindowSystemEvent() in QWindowSystemInterfacePrivate to match postWindowSystemEvent(), where the former is synchronous and the latter is asynchronous. This is then coupled with a templated version of handleWindowSystemEvent() that then calls out to one of the two depending on the specialization that's used. The default specialization will decide based on the state set by setSynchronousWindowSystemEvents(), as before. This allows templated versions of handleMouseEvent, handleKeyEvent, etc to be added without maintaining two code paths, one for synchronous and one for asynchronous delivery, which in the end allows us to get away from using setSynchronousWindowSystemEvents() as a temporary switch to synchronous mode. The templates are defined in the QWindowSystemInterface source file, with explicit instantiations of the three supported modes of delivery, as having the definition in the header file would both require inlining, as well as qwindowsysteminterface.h having access to the private parts of QWindowSystemInterfacePrivate for the template function bodies. Task-number: QTBUG-56274 Change-Id: I54c34da1ad90ff243f11905529874695f556cfcd Reviewed-by: Jan Arve Sæther Reviewed-by: Shawn Rutledge Reviewed-by: Lars Knoll --- src/gui/kernel/qwindowsysteminterface.cpp | 185 +++++++++++++--------- src/gui/kernel/qwindowsysteminterface.h | 14 ++ src/gui/kernel/qwindowsysteminterface_p.h | 7 +- 3 files changed, 132 insertions(+), 74 deletions(-) diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index bb778bc5fc..b799f75090 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -69,6 +69,63 @@ QWindowSystemInterfacePrivate::WindowSystemEventList QWindowSystemInterfacePriva extern QPointer qt_last_mouse_receiver; +/*! + Handles a window system event asynchronously by posting the event to Qt Gui. + + \sa postWindowSystemEvent() +*/ +template<> +bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(WindowSystemEvent *ev) +{ + QWindowSystemInterfacePrivate::postWindowSystemEvent(ev); + return true; +} + +/*! + Handles a window system event synchronously. + + If the event is delivered from another thread than the Qt main thread the + window system event queue is flushed, which may deliver other events as + well. + + \sa processWindowSystemEvent() +*/ +template<> +bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(WindowSystemEvent *ev) +{ + return QWindowSystemInterfacePrivate::processWindowSystemEvent(ev); +} + +/*! + Handles a window system event. + + By default this function posts the event on the window system event queue and + wakes the Gui event dispatcher. Qt Gui will then handle the event asynchonously + at a later point. The return value is not used in asynchronous mode and will + always be true. + + In synchronous mode Qt Gui will process the event immediately. The return value + indicates if Qt accepted the event. If the event is delivered from another thread + than the Qt main thread the window system event queue is flushed, which may deliver + other events as well. + + \sa flushWindowSystemEvents(), processWindowSystemEvent(), setSynchronousWindowSystemEvents() +*/ +template<> +bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) +{ + if (synchronousWindowSystemEvents) + return handleWindowSystemEvent(ev); + else + return handleWindowSystemEvent(ev); +} + +#define QT_DEFINE_QPA_EVENT_HANDLER(ReturnType, HandlerName, ...) \ + template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName(__VA_ARGS__); \ + template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName(__VA_ARGS__); \ + template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName(__VA_ARGS__); \ + template ReturnType QWindowSystemInterface::HandlerName(__VA_ARGS__) + /*! \class QWindowSystemInterface \since 5.0 @@ -81,18 +138,18 @@ extern QPointer qt_last_mouse_receiver; until sendWindowSystemEvents() is called by the event dispatcher. */ -void QWindowSystemInterface::handleEnterEvent(QWindow *tlw, const QPointF &local, const QPointF &global) +QT_DEFINE_QPA_EVENT_HANDLER(void, handleEnterEvent, QWindow *tlw, const QPointF &local, const QPointF &global) { if (tlw) { QWindowSystemInterfacePrivate::EnterEvent *e = new QWindowSystemInterfacePrivate::EnterEvent(tlw, local, global); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } } -void QWindowSystemInterface::handleLeaveEvent(QWindow *tlw) +QT_DEFINE_QPA_EVENT_HANDLER(void, handleLeaveEvent, QWindow *tlw) { QWindowSystemInterfacePrivate::LeaveEvent *e = new QWindowSystemInterfacePrivate::LeaveEvent(tlw); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } /*! @@ -104,15 +161,8 @@ void QWindowSystemInterface::handleLeaveEvent(QWindow *tlw) */ void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local, const QPointF& global) { - bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; - if (wasSynchronous) - setSynchronousWindowSystemEvents(false); - handleLeaveEvent(leave); + handleLeaveEvent(leave); handleEnterEvent(enter, local, global); - if (wasSynchronous) { - flushWindowSystemEvents(); - setSynchronousWindowSystemEvents(true); - } } void QWindowSystemInterface::handleWindowActivated(QWindow *tlw, Qt::FocusReason r) @@ -167,19 +217,19 @@ void QWindowSystemInterface::handleCloseEvent(QWindow *tlw, bool *accepted) \a w == 0 means that the event is in global coords only, \a local will be ignored in this case */ -void QWindowSystemInterface::handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, +QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleMouseEvent(w, time, local, global, b, mods, source); + handleMouseEvent(w, time, local, global, b, mods, source); } -void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, +QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { QWindowSystemInterfacePrivate::MouseEvent * e = new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, @@ -217,11 +267,7 @@ bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestam QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorepeat, count); { - // FIXME: Template handleWindowSystemEvent to support both sync and async delivery - QScopedValueRollback syncRollback(QWindowSystemInterfacePrivate::synchronousWindowSystemEvents); - QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = true; - - if (QWindowSystemInterfacePrivate::handleWindowSystemEvent(shortcutOverrideEvent)) + if (QWindowSystemInterfacePrivate::handleWindowSystemEvent(shortcutOverrideEvent)) return false; } } @@ -248,13 +294,12 @@ bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestam #endif } - -bool QWindowSystemInterface::handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { +QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - return handleKeyEvent(w, time, t, k, mods, text, autorep, count); + return handleKeyEvent(w, time, t, k, mods, text, autorep, count); } -bool QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) +QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { #if defined(Q_OS_OSX) if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(tlw, timestamp, k, mods, 0, 0, 0, text, autorep, count)) @@ -263,7 +308,7 @@ bool QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEven QWindowSystemInterfacePrivate::KeyEvent * e = new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, t, k, mods, text, autorep, count); - return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, @@ -394,6 +439,15 @@ void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *e windowSystemEventQueue.remove(event); } +/*! + Posts a window system event to be handled asynchronously by Qt Gui. + + This function posts the event on the window system event queue and wakes the + Gui event dispatcher. Qt Gui will then handle the event asynchonously at a + later point. + + \sa flushWindowSystemEvents(), processWindowSystemEvent(), handleWindowSystemEvent() +*/ void QWindowSystemInterfacePrivate::postWindowSystemEvent(WindowSystemEvent *ev) { windowSystemEventQueue.append(ev); @@ -403,37 +457,32 @@ void QWindowSystemInterfacePrivate::postWindowSystemEvent(WindowSystemEvent *ev) } /*! - Handles a window system event. + Processes a window system event synchronously. - By default this function posts the event on the window system event queue and - wakes the Gui event dispatcher. Qt Gui will then handle the event asynchonously - at a later point. The return value is not used in asynchronous mode and will - always be true. + Qt Gui will process the event immediately. The return value indicates if Qt + accepted the event. - In synchronous mode Qt Gui will process the event immediately. The return value - indicates if Qt accepted the event. + If the event is delivered from another thread than the Qt main thread the + window system event queue is flushed, which may deliver other events as + well. - \sa flushWindowSystemEvents(), setSynchronousWindowSystemEvents() + \sa flushWindowSystemEvents(), postWindowSystemEvent(), handleWindowSystemEvent() */ -bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) +bool QWindowSystemInterfacePrivate::processWindowSystemEvent(WindowSystemEvent *ev) { bool accepted = true; - if (synchronousWindowSystemEvents) { - if (QThread::currentThread() == QGuiApplication::instance()->thread()) { - // Process the event immediately on the current thread and return the accepted state. - QGuiApplicationPrivate::processWindowSystemEvent(ev); - accepted = ev->eventAccepted; - delete ev; - } else { - // Post the event on the Qt main thread queue and flush the queue. - // This will wake up the Gui thread which will process the event. - // Return the accepted state for the last event on the queue, - // which is the event posted by this function. - postWindowSystemEvent(ev); - accepted = QWindowSystemInterface::flushWindowSystemEvents(); - } + if (QThread::currentThread() == QGuiApplication::instance()->thread()) { + // Process the event immediately on the current thread and return the accepted state. + QGuiApplicationPrivate::processWindowSystemEvent(ev); + accepted = ev->eventAccepted; + delete ev; } else { + // Post the event on the Qt main thread queue and flush the queue. + // This will wake up the Gui thread which will process the event. + // Return the accepted state for the last event on the queue, + // which is the event posted by this function. postWindowSystemEvent(ev); + accepted = QWindowSystemInterface::flushWindowSystemEvents(); } return accepted; } @@ -453,13 +502,6 @@ bool QWindowSystemInterface::isTouchDeviceRegistered(const QTouchDevice *device) return QTouchDevicePrivate::isRegistered(device); } -void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, - const QList &points, Qt::KeyboardModifiers mods) -{ - unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleTouchEvent(w, time, device, points, mods); -} - QList QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList &points, const QWindow *window, @@ -530,7 +572,14 @@ QList return newList; } -void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTouchDevice *device, +QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *w, QTouchDevice *device, + const QList &points, Qt::KeyboardModifiers mods) +{ + unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); + handleTouchEvent(w, time, device, points, mods); +} + +QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *tlw, ulong timestamp, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods) { if (!points.size()) // Touch events must have at least one point @@ -544,7 +593,7 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo QWindowSystemInterfacePrivate::TouchEvent *e = new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleTouchCancelEvent(QWindow *w, QTouchDevice *device, @@ -634,7 +683,7 @@ bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFl // deferredFlushWindowSystemEvents from the Gui thread. QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex); QWindowSystemInterfacePrivate::FlushEventsEvent *e = new QWindowSystemInterfacePrivate::FlushEventsEvent(flags); - QWindowSystemInterfacePrivate::postWindowSystemEvent(e); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex); } else { sendWindowSystemEvents(flags); @@ -872,20 +921,13 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPo Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp) { - bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; - QWindowSystemInterface::setSynchronousWindowSystemEvents(true); const qreal factor = QHighDpiScaling::factor(w); - QWindowSystemInterface::handleMouseEvent(w, timestamp, local * factor, - global * factor, b, mods); - QWindowSystemInterface::setSynchronousWindowSystemEvents(wasSynchronous); + QWindowSystemInterface::handleMouseEvent(w, timestamp, local * factor, global * factor, b, mods); } Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1) { - bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; - QWindowSystemInterface::setSynchronousWindowSystemEvents(true); - QWindowSystemInterface::handleKeyEvent(w, t, k, mods, text, autorep, count); - QWindowSystemInterface::setSynchronousWindowSystemEvents(wasSynchronous); + QWindowSystemInterface::handleKeyEvent(w, t, k, mods, text, autorep, count); } Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1) @@ -940,11 +982,8 @@ Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods = Qt::NoModifier) { - bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; - QWindowSystemInterface::setSynchronousWindowSystemEvents(true); - QWindowSystemInterface::handleTouchEvent(w, device, - QWindowSystemInterfacePrivate::toNativeTouchPoints(points, w), mods); - QWindowSystemInterface::setSynchronousWindowSystemEvents(wasSynchronous); + QWindowSystemInterface::handleTouchEvent(w, device, + QWindowSystemInterfacePrivate::toNativeTouchPoints(points, w), mods); } QWindowSystemEventHandler::~QWindowSystemEventHandler() diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index e7e47ac6d9..6fade3cc4c 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -72,9 +72,15 @@ class QPlatformDropQtResponse; class Q_GUI_EXPORT QWindowSystemInterface { public: + struct SynchronousDelivery {}; + struct AsynchronousDelivery {}; + struct DefaultDelivery {}; + + template static void handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + template static void handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); @@ -88,7 +94,9 @@ public: static bool handleShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString & text = QString(), bool autorep = false, ushort count = 1); + template static bool handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); + template static bool handleKeyEvent(QWindow *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); static bool handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, @@ -135,8 +143,11 @@ public: static void registerTouchDevice(const QTouchDevice *device); static void unregisterTouchDevice(const QTouchDevice *device); static bool isTouchDeviceRegistered(const QTouchDevice *device); + + template static void handleTouchEvent(QWindow *w, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods = Qt::NoModifier); + template static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleTouchCancelEvent(QWindow *w, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier); @@ -145,7 +156,10 @@ public: // rect is relative to parent static void handleGeometryChange(QWindow *w, const QRect &newRect, const QRect &oldRect = QRect()); static void handleCloseEvent(QWindow *w, bool *accepted = Q_NULLPTR); + + template static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF()); + template static void handleLeaveEvent(QWindow *w); static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local = QPointF(), const QPointF& global = QPointF()); static void handleWindowActivated(QWindow *w, Qt::FocusReason r = Qt::OtherFocusReason); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index f471e1f550..7c9b1f2852 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -491,9 +491,14 @@ public: static WindowSystemEvent *getNonUserInputWindowSystemEvent(); static WindowSystemEvent *peekWindowSystemEvent(EventType t); static void removeWindowSystemEvent(WindowSystemEvent *event); - static void postWindowSystemEvent(WindowSystemEvent *ev); + template static bool handleWindowSystemEvent(WindowSystemEvent *ev); +private: + static void postWindowSystemEvent(WindowSystemEvent *ev); + static bool processWindowSystemEvent(WindowSystemEvent *ev); + +public: static QElapsedTimer eventTime; static bool synchronousWindowSystemEvents;