Allow granular synchronous and asynchronous delivery of QPA events

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 <jan-arve.saether@theqtcompany.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Tor Arne Vestbø 2015-09-10 16:15:35 +02:00 committed by Tor Arne Vestbø
parent 76f53791a1
commit 33d748bb88
3 changed files with 132 additions and 74 deletions

View File

@ -69,6 +69,63 @@ QWindowSystemInterfacePrivate::WindowSystemEventList QWindowSystemInterfacePriva
extern QPointer<QWindow> qt_last_mouse_receiver;
/*!
Handles a window system event asynchronously by posting the event to Qt Gui.
\sa postWindowSystemEvent()
*/
template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(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<QWindowSystemInterface::SynchronousDelivery>(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<QWindowSystemInterface::DefaultDelivery>(QWindowSystemInterfacePrivate::WindowSystemEvent *ev)
{
if (synchronousWindowSystemEvents)
return handleWindowSystemEvent<QWindowSystemInterface::SynchronousDelivery>(ev);
else
return handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(ev);
}
#define QT_DEFINE_QPA_EVENT_HANDLER(ReturnType, HandlerName, ...) \
template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::DefaultDelivery>(__VA_ARGS__); \
template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::SynchronousDelivery>(__VA_ARGS__); \
template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::AsynchronousDelivery>(__VA_ARGS__); \
template<typename Delivery> ReturnType QWindowSystemInterface::HandlerName(__VA_ARGS__)
/*!
\class QWindowSystemInterface
\since 5.0
@ -81,18 +138,18 @@ extern QPointer<QWindow> 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<Delivery>(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<Delivery>(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<AsynchronousDelivery>(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<Delivery>(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<Delivery>(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<bool> syncRollback(QWindowSystemInterfacePrivate::synchronousWindowSystemEvents);
QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = true;
if (QWindowSystemInterfacePrivate::handleWindowSystemEvent(shortcutOverrideEvent))
if (QWindowSystemInterfacePrivate::handleWindowSystemEvent<SynchronousDelivery>(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<Delivery>(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<Delivery>(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<TouchPoint> &points, Qt::KeyboardModifiers mods)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleTouchEvent(w, time, device, points, mods);
}
QList<QTouchEvent::TouchPoint>
QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
const QWindow *window,
@ -530,7 +572,14 @@ QList<QWindowSystemInterface::TouchPoint>
return newList;
}
void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTouchDevice *device,
QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *w, QTouchDevice *device,
const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleTouchEvent<Delivery>(w, time, device, points, mods);
}
QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *tlw, ulong timestamp, QTouchDevice *device,
const QList<TouchPoint> &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<Delivery>(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<SynchronousDelivery>(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<QWindowSystemInterface::SynchronousDelivery>(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<QWindowSystemInterface::SynchronousDelivery>(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<QTouchEvent::TouchPoint> &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<QWindowSystemInterface::SynchronousDelivery>(w, device,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, w), mods);
}
QWindowSystemEventHandler::~QWindowSystemEventHandler()

View File

@ -72,9 +72,15 @@ class QPlatformDropQtResponse;
class Q_GUI_EXPORT QWindowSystemInterface
{
public:
struct SynchronousDelivery {};
struct AsynchronousDelivery {};
struct DefaultDelivery {};
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
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<typename Delivery = QWindowSystemInterface::DefaultDelivery>
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<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static bool handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
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<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleTouchEvent(QWindow *w, QTouchDevice *device,
const QList<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device,
const QList<struct TouchPoint> &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<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF());
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
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);

View File

@ -491,9 +491,14 @@ public:
static WindowSystemEvent *getNonUserInputWindowSystemEvent();
static WindowSystemEvent *peekWindowSystemEvent(EventType t);
static void removeWindowSystemEvent(WindowSystemEvent *event);
static void postWindowSystemEvent(WindowSystemEvent *ev);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static bool handleWindowSystemEvent(WindowSystemEvent *ev);
private:
static void postWindowSystemEvent(WindowSystemEvent *ev);
static bool processWindowSystemEvent(WindowSystemEvent *ev);
public:
static QElapsedTimer eventTime;
static bool synchronousWindowSystemEvents;