Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwindowsysteminterface.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
5#include <qpa/qplatformwindow.h>
7#include "private/qguiapplication_p.h"
8#include "private/qevent_p.h"
9#include "private/qeventpoint_p.h"
10#include "private/qpointingdevice_p.h"
11#include "private/qscreen_p.h"
12#include <QAbstractEventDispatcher>
13#include <qpa/qplatformintegration.h>
14#include <qdebug.h>
16
17#include <QtCore/qscopedvaluerollback.h>
18#include <QtCore/private/qlocking_p.h>
19
20#if QT_CONFIG(draganddrop)
21#include <qpa/qplatformdrag.h>
22#endif
23
25
26using namespace Qt::StringLiterals;
27
28Q_LOGGING_CATEGORY(lcQpaInputDevices, "qt.qpa.input.devices", QtWarningMsg)
29
30Q_CONSTINIT QElapsedTimer QWindowSystemInterfacePrivate::eventTime;
31bool QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = false;
32bool QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse = true;
33QWaitCondition QWindowSystemInterfacePrivate::eventsFlushed;
34Q_CONSTINIT QMutex QWindowSystemInterfacePrivate::flushEventMutex;
35Q_CONSTINIT QAtomicInt QWindowSystemInterfacePrivate::eventAccepted;
36QWindowSystemEventHandler *QWindowSystemInterfacePrivate::eventHandler;
37QWindowSystemInterfacePrivate::WindowSystemEventList QWindowSystemInterfacePrivate::windowSystemEventQueue;
38
40
41
42// ------------------- QWindowSystemInterfacePrivate -------------------
43
44/*!
45 \internal
46
47 The QWindowSystemHelper creates synchronously delivered events on the stack, unless
48 the calling thread is not the Gui thread.
49
50 Asynchronously delivered events, and events created outside the Gui thread are
51 allocated on the heap.
52*/
53
54template<typename Delivery>
56{
57 template<typename EventType, typename ...Args>
58 static bool handleEvent(Args ...);
59};
60
61/*
62 Handles a window system event.
63
64 By default this function posts the event on the window system event queue and
65 wakes the Gui event dispatcher. Qt Gui will then handle the event asynchronously
66 at a later point. The return value is not used in asynchronous mode and will
67 always be true.
68
69 In synchronous mode Qt Gui will process the event immediately. The return value
70 indicates if Qt accepted the event. If the event is delivered from another thread
71 than the Qt main thread the window system event queue is flushed, which may deliver
72 other events as well.
73
74 \sa flushWindowSystemEvents(), setSynchronousWindowSystemEvents()
75*/
76template<>
77template<typename EventType, typename ...Args>
78bool QWindowSystemHelper<QWindowSystemInterface::DefaultDelivery>::handleEvent(Args ...args)
79{
80 return QWindowSystemInterfacePrivate::synchronousWindowSystemEvents
81 ? QWindowSystemHelper<QWindowSystemInterface::SynchronousDelivery>::handleEvent<EventType>(args...)
82 : QWindowSystemHelper<QWindowSystemInterface::AsynchronousDelivery>::handleEvent<EventType>(args...);
83}
84
85/*
86 Handles a window system event synchronously.
87
88 Qt Gui will process the event immediately. The return value indicates if Qt
89 accepted the event.
90
91 If the event is delivered from another thread than the Qt main thread the
92 window system event queue is flushed, which may deliver other events as
93 well.
94*/
95template<>
96template<typename EventType, typename ...Args>
97bool QWindowSystemHelper<QWindowSystemInterface::SynchronousDelivery>::handleEvent(Args ...args)
98{
99 if (QThread::isMainThread()) {
100 EventType event(args...);
101 // Process the event immediately on the Gui thread and return the accepted state
102 if (QWindowSystemInterfacePrivate::eventHandler) {
103 if (!QWindowSystemInterfacePrivate::eventHandler->sendEvent(&event))
104 return false;
105 } else {
106 QGuiApplicationPrivate::processWindowSystemEvent(&event);
107 }
108 return event.eventAccepted;
109 } else {
110 // Post the event on the Qt main thread queue and flush the queue.
111 // This will wake up the Gui thread which will process the event.
112 // Return the accepted state for the last event on the queue,
113 // which is the event posted by this function.
114 QWindowSystemHelper<QWindowSystemInterface::AsynchronousDelivery>::handleEvent<EventType>(args...);
115 return QWindowSystemInterface::flushWindowSystemEvents();
116 }
117}
118
119/*
120 Handles a window system event asynchronously by posting the event to Qt Gui.
121
122 This function posts the event on the window system event queue and wakes the
123 Gui event dispatcher. Qt Gui will then handle the event asynchronously at a
124 later point.
125*/
126template<>
127template<typename EventType, typename ...Args>
128bool QWindowSystemHelper<QWindowSystemInterface::AsynchronousDelivery>::handleEvent(Args ...args)
129{
130 QWindowSystemInterfacePrivate::windowSystemEventQueue.append(new EventType(args...));
131 if (QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher())
132 dispatcher->wakeUp();
133 return true;
134}
135
136template <typename EventType, typename Delivery = QWindowSystemInterface::DefaultDelivery, typename ...Args>
137static bool handleWindowSystemEvent(Args ...args)
138{
139 return QWindowSystemHelper<Delivery>::template handleEvent<EventType>(args...);
140}
141
142qsizetype QWindowSystemInterfacePrivate::windowSystemEventsQueued()
143{
144 return windowSystemEventQueue.count();
145}
146
147bool QWindowSystemInterfacePrivate::nonUserInputEventsQueued()
148{
149 return windowSystemEventQueue.nonUserInputEventsQueued();
150}
151
152QWindowSystemInterfacePrivate::WindowSystemEvent * QWindowSystemInterfacePrivate::getWindowSystemEvent()
153{
154 return windowSystemEventQueue.takeFirstOrReturnNull();
155}
156
157QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent()
158{
159 return windowSystemEventQueue.takeFirstNonUserInputOrReturnNull();
160}
161
162QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::peekWindowSystemEvent(EventType t)
163{
164 return windowSystemEventQueue.peekAtFirstOfType(t);
165}
166
167void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *event)
168{
169 windowSystemEventQueue.remove(event);
170}
171
172void QWindowSystemInterfacePrivate::installWindowSystemEventHandler(QWindowSystemEventHandler *handler)
173{
174 if (!eventHandler)
175 eventHandler = handler;
176}
177
178void QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(QWindowSystemEventHandler *handler)
179{
180 if (eventHandler == handler)
181 eventHandler = nullptr;
182}
183
184QWindowSystemEventHandler::~QWindowSystemEventHandler()
185{
186 QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(this);
187}
188
189bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
190{
191 QGuiApplicationPrivate::processWindowSystemEvent(e);
192 return true;
193}
194
195//------------------------------------------------------------
196//
197// Callback functions for plugins:
198//
199
200#define QT_DEFINE_QPA_EVENT_HANDLER(ReturnType, HandlerName, ...)
201 template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::DefaultDelivery>(__VA_ARGS__);
202 template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::SynchronousDelivery>(__VA_ARGS__);
203 template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::AsynchronousDelivery>(__VA_ARGS__);
204 template<typename Delivery> ReturnType QWindowSystemInterface::HandlerName(__VA_ARGS__)
205
206/*!
207 \class QWindowSystemInterface
208 \since 5.0
209 \internal
210 \preliminary
211 \ingroup qpa
212 \brief The QWindowSystemInterface provides an event queue for the QPA platform.
213
214 The platform plugins call the various functions to notify about events. The events are queued
215 until sendWindowSystemEvents() is called by the event dispatcher.
216*/
217
218QT_DEFINE_QPA_EVENT_HANDLER(void, handleEnterEvent, QWindow *window, const QPointF &local, const QPointF &global)
219{
220 if (window) {
221 handleWindowSystemEvent<QWindowSystemInterfacePrivate::EnterEvent, Delivery>(window,
222 QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window));
223 }
224}
225
226QT_DEFINE_QPA_EVENT_HANDLER(void, handleLeaveEvent, QWindow *window)
227{
228 handleWindowSystemEvent<QWindowSystemInterfacePrivate::LeaveEvent, Delivery>(window);
229}
230
231/*!
232 This method can be used to ensure leave and enter events are both in queue when moving from
233 one QWindow to another. This allows QWindow subclasses to check for a queued enter event
234 when handling the leave event (\c QWindowSystemInterfacePrivate::peekWindowSystemEvent) to
235 determine where mouse went and act accordingly. E.g. QWidgetWindow needs to know if mouse
236 cursor moves between windows in same window hierarchy.
237*/
238void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local, const QPointF& global)
239{
240 handleLeaveEvent<AsynchronousDelivery>(leave);
241 handleEnterEvent(enter, local, global);
242}
243
244QT_DEFINE_QPA_EVENT_HANDLER(void, handleFocusWindowChanged, QWindow *window, Qt::FocusReason r)
245{
246 handleWindowSystemEvent<QWindowSystemInterfacePrivate::FocusWindowEvent, Delivery>(window, r);
247}
248
249QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowStateChanged, QWindow *window, Qt::WindowStates newState, int oldState)
250{
251 Q_ASSERT(window);
252 if (oldState < Qt::WindowNoState)
253 oldState = window->windowStates();
254
255 handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowStateChangedEvent, Delivery>(window, newState, Qt::WindowStates(oldState));
256}
257
258QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowScreenChanged, QWindow *window, QScreen *screen)
259{
260 handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowScreenChangedEvent, Delivery>(window, screen);
261}
262
263QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowDevicePixelRatioChanged, QWindow *window)
264{
265 handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent, Delivery>(window);
266}
267
268
269QT_DEFINE_QPA_EVENT_HANDLER(void, handleSafeAreaMarginsChanged, QWindow *window)
270{
271 handleWindowSystemEvent<QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent, Delivery>(window);
272}
273
274QT_DEFINE_QPA_EVENT_HANDLER(void, handleApplicationStateChanged, Qt::ApplicationState newState, bool forcePropagate)
275{
276 Q_ASSERT(QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState));
277 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent, Delivery>(newState, forcePropagate);
278}
279
280QT_DEFINE_QPA_EVENT_HANDLER(bool, handleApplicationTermination)
281{
282 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowSystemEvent, Delivery>(
283 QWindowSystemInterfacePrivate::ApplicationTermination);
284}
285
286QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow *window,
287 QRect requestedGeometry,
288 QRect newGeometry)
289 : WindowSystemEvent(GeometryChange)
290 , window(window)
291 , requestedGeometry(requestedGeometry)
292 , newGeometry(newGeometry)
293{
294}
295
296QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect)
297{
298 Q_ASSERT(window);
299 const auto newRectDi = QHighDpi::fromNativeWindowGeometry(newRect, window);
300 QRect requestedGeometry;
301 if (auto *handle = window->handle()) {
302 requestedGeometry = QHighDpi::fromNativeWindowGeometry(handle->QPlatformWindow::geometry(),
303 window);
304 // Persist the new geometry so that QWindow::geometry() can be queried in the resize event
305 handle->QPlatformWindow::setGeometry(newRect);
306 // FIXME: This does not work during platform window creation, where the QWindow does not
307 // have its handle set up yet. Platforms that deliver events during window creation need
308 // to handle the persistence manually, e.g. by overriding geometry().
309 }
310 handleWindowSystemEvent<QWindowSystemInterfacePrivate::GeometryChangeEvent, Delivery>(window,
311 requestedGeometry,
312 newRectDi);
313}
314
315QWindowSystemInterfacePrivate::ExposeEvent::ExposeEvent(QWindow *window, const QRegion &region)
316 : WindowSystemEvent(Expose)
317 , window(window)
318 , isExposed(window && window->handle() ? window->handle()->isExposed() : false)
319 , region(region)
320{
321}
322
323/*! \internal
324 Handles an expose event.
325
326 The platform plugin sends expose events when an area of the window
327 is invalidated or window exposure changes. \a region is in window
328 local coordinates. An empty region indicates that the window is
329 obscured, but note that the exposed property of the QWindow will be set
330 based on what QPlatformWindow::isExposed() returns at the time of this call,
331 not based on what the region is. // FIXME: this should probably be fixed.
332
333 The platform plugin may omit sending expose events (or send obscure
334 events) for windows that are on screen but where the client area is
335 completely covered by other windows or otherwise not visible. Expose
336 event consumers can then use this to disable updates for such windows.
337 This is required behavior on platforms where OpenGL swapbuffers stops
338 blocking for obscured windows (like macOS).
339*/
340QT_DEFINE_QPA_EVENT_HANDLER(bool, handleExposeEvent, QWindow *window, const QRegion &region)
341{
342 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::ExposeEvent, Delivery>(window,
343 QHighDpi::fromNativeLocalExposedRegion(region, window));
344}
345
346QT_DEFINE_QPA_EVENT_HANDLER(bool, handlePaintEvent, QWindow *window, const QRegion &region)
347{
348 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::PaintEvent, Delivery>(window,
349 QHighDpi::fromNativeLocalExposedRegion(region, window));
350}
351
352
353QT_DEFINE_QPA_EVENT_HANDLER(bool, handleCloseEvent, QWindow *window)
354{
355 Q_ASSERT(window);
356 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::CloseEvent, Delivery>(window);
357}
358
359/*!
360
361\a w == 0 means that the event is in global coords only, \a local will be ignored in this case
362
363*/
364
365QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window,
366 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
367 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
368 Qt::MouseEventSource source)
369{
370 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
371 return handleMouseEvent<Delivery>(window, time, local, global, state, button, type, mods, source);
372}
373
374QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, const QPointingDevice *device,
375 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
376 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
377 Qt::MouseEventSource source)
378{
379 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
380 return handleMouseEvent<Delivery>(window, time, device, local, global, state, button, type, mods, source);
381}
382
383QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, ulong timestamp,
384 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
385 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
386 Qt::MouseEventSource source)
387{
388 return handleMouseEvent<Delivery>(window, timestamp, QPointingDevice::primaryPointingDevice(),
389 local, global, state, button, type, mods, source);
390}
391
392QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
393 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
394 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
395 Qt::MouseEventSource source)
396{
397
398 bool isNonClientArea = {};
399
400 switch (type) {
401 case QEvent::MouseButtonDblClick:
402 case QEvent::NonClientAreaMouseButtonDblClick:
403 Q_ASSERT_X(false, "QWindowSystemInterface::handleMouseEvent",
404 "QTBUG-71263: Native double clicks are not implemented.");
405 return false;
406 case QEvent::MouseMove:
407 case QEvent::MouseButtonPress:
408 case QEvent::MouseButtonRelease:
409 isNonClientArea = false;
410 break;
411 case QEvent::NonClientAreaMouseMove:
412 case QEvent::NonClientAreaMouseButtonPress:
413 case QEvent::NonClientAreaMouseButtonRelease:
414 isNonClientArea = true;
415 break;
416 default:
417 Q_UNREACHABLE();
418 }
419
420 auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
421 auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
422
423 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::MouseEvent, Delivery>(window,
424 timestamp, localPos, globalPos, state, mods, button, type, source, isNonClientArea, device);
425}
426
427bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestamp, int keyCode, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode,
428 quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text, bool autorepeat, ushort count)
429{
430#if QT_CONFIG(shortcut)
431 if (!window)
432 window = QGuiApplication::focusWindow();
433
434 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
435 if (shortcutMap.state() == QKeySequence::NoMatch) {
436 // Check if the shortcut is overridden by some object in the event delivery path (typically the focus object).
437 // If so, we should not look up the shortcut in the shortcut map, but instead deliver the event as a regular
438 // key event, so that the target that accepted the shortcut override event can handle it. Note that we only
439 // do this if the shortcut map hasn't found a partial shortcut match yet. If it has, the shortcut can not be
440 // overridden.
441 bool overridden = handleWindowSystemEvent<QWindowSystemInterfacePrivate::KeyEvent, SynchronousDelivery>
442 (window,timestamp, QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode,
443 nativeVirtualKey, nativeModifiers, text, autorepeat, count);
444 if (overridden)
445 return false;
446 }
447
448 // The shortcut event is dispatched as a QShortcutEvent, not a QKeyEvent, but we use
449 // the QKeyEvent as a container for the various properties that the shortcut map needs
450 // to inspect to determine if a shortcut matched the keys that were pressed.
451 QKeyEvent keyEvent(QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode,
452 nativeVirtualKey, nativeModifiers, text, autorepeat, count);
453
454 return shortcutMap.tryShortcut(&keyEvent);
455#else
456 Q_UNUSED(window);
457 Q_UNUSED(timestamp);
458 Q_UNUSED(keyCode);
459 Q_UNUSED(modifiers);
460 Q_UNUSED(nativeScanCode);
461 Q_UNUSED(nativeVirtualKey);
462 Q_UNUSED(nativeModifiers);
463 Q_UNUSED(text);
464 Q_UNUSED(autorepeat);
465 Q_UNUSED(count);
466 return false;
467#endif
468}
469
470QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) {
471 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
472 return handleKeyEvent<Delivery>(window, time, t, k, mods, text, autorep, count);
473}
474
475QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count)
476{
477 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::KeyEvent, Delivery>(window,
478 timestamp, t, k, mods, text, autorep, count);
479}
480
481bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
482 quint32 nativeScanCode, quint32 nativeVirtualKey,
483 quint32 nativeModifiers,
484 const QString& text, bool autorep,
485 ushort count)
486{
487 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
488 return handleExtendedKeyEvent(window, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
489 text, autorep, count);
490}
491
492bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
493 Qt::KeyboardModifiers modifiers,
494 quint32 nativeScanCode, quint32 nativeVirtualKey,
495 quint32 nativeModifiers,
496 const QString& text, bool autorep,
497 ushort count)
498{
499 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::KeyEvent>(window,
500 timestamp, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
501}
502
503bool QWindowSystemInterface::handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource source)
504{
505 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
506 return handleWheelEvent(window, time, local, global, pixelDelta, angleDelta, mods, phase, source);
507}
508
509bool QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
510 Qt::MouseEventSource source, bool invertedScrolling)
511{
512 return handleWheelEvent(window, timestamp, QPointingDevice::primaryPointingDevice(), local, global,
513 pixelDelta, angleDelta, mods, phase, source, invertedScrolling);
514}
515
516bool QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
517 const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta,
518 Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
519 Qt::MouseEventSource source, bool invertedScrolling)
520{
521 // Qt 4 sends two separate wheel events for horizontal and vertical
522 // deltas. For Qt 5 we want to send the deltas in one event, but at the
523 // same time preserve source and behavior compatibility with Qt 4.
524 //
525 // In addition high-resolution pixel-based deltas are also supported.
526 // Platforms that does not support these may pass a null point here.
527 // Angle deltas must always be sent in addition to pixel deltas.
528
529 // Pass Qt::ScrollBegin and Qt::ScrollEnd through
530 // even if the wheel delta is null.
531 if (angleDelta.isNull() && phase == Qt::ScrollUpdate)
532 return false;
533
534 // Simple case: vertical deltas only:
535 if (angleDelta.y() != 0 && angleDelta.x() == 0) {
536 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
537 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
538 pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling, device);
539 }
540
541 // Simple case: horizontal deltas only:
542 if (angleDelta.y() == 0 && angleDelta.x() != 0) {
543 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
544 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
545 pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling, device);
546 }
547
548 bool acceptVert;
549 bool acceptHorz;
550 // Both horizontal and vertical deltas: Send two wheel events.
551 // The first event contains the Qt 5 pixel and angle delta as points,
552 // and in addition the Qt 4 compatibility vertical angle delta.
553 acceptVert = handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
554 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
555 pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling, device);
556
557 // The second event contains null pixel and angle points and the
558 // Qt 4 compatibility horizontal angle delta.
559 acceptHorz = handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
560 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
561 QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling, device);
562
563 return acceptVert || acceptHorz;
564}
565
566/*!
567 \internal
568 Register a new input \a device.
569
570 It is expected that every platform plugin will discover available input
571 devices at startup, and whenever a new device is plugged in, if possible.
572 If that's not possible, then it at least must call this function before
573 sending an event whose QInputEvent::source() is this device.
574
575 When a device is unplugged, the platform plugin should destroy the
576 corresponding QInputDevice instance. There is no unregisterInputDevice()
577 function, because it's enough for the destructor to call
578 QInputDevicePrivate::unregisterDevice(); while other parts of Qt can
579 connect to the QObject::destroyed() signal to be notified when a device is
580 unplugged or otherwise destroyed.
581*/
582void QWindowSystemInterface::registerInputDevice(const QInputDevice *device)
583{
584 QInputDevicePrivate::registerDevice(device);
585}
586
587/*!
588 \internal
589 Convert a list of \l QWindowSystemInterface::TouchPoint \a points to a list
590 of \e temporary QEventPoint instances, scaled (but not localized)
591 for delivery to the given \a window.
592
593 This is called from QWindowSystemInterface::handleTouchEvent():
594 that is too early to update the QEventPoint instances in QPointingDevice,
595 because we want those to hold "current" state from the applcation's
596 point of view. The QWindowSystemInterfacePrivate::TouchEvent, to which
597 the returned touchpoints will "belong", might go through the queue before
598 being processed; the application doesn't see the equivalent QTouchEvent
599 until later on. Therefore the responsibility to update the QEventPoint
600 instances in QPointingDevice is in QGuiApplication, not here.
601
602 QGuiApplicationPrivate::processMouseEvent() also calls this function
603 when it synthesizes a touch event from a mouse event. But that's outside
604 the normal use case.
605
606 It might be better if we change all the platform plugins to create
607 temporary instances of QEventPoint directly, and remove
608 QWindowSystemInterface::TouchPoint completely. Then we will no longer need
609 this function either. But that's only possible as long as QEventPoint
610 remains a Q_GADGET, not a QObject, so that it continues to be small and
611 suitable for temporary stack allocation. QEventPoint is a little bigger
612 than QWindowSystemInterface::TouchPoint, though.
613*/
614QList<QEventPoint>
615 QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
616 const QWindow *window, QEvent::Type *type)
617{
618 QList<QEventPoint> touchPoints;
619 QEventPoint::States states;
620
621 touchPoints.reserve(points.size());
622 QList<QWindowSystemInterface::TouchPoint>::const_iterator point = points.constBegin();
623 QList<QWindowSystemInterface::TouchPoint>::const_iterator end = points.constEnd();
624 while (point != end) {
625 QPointF globalPos = QHighDpi::fromNativePixels(point->area.center(), window);
626 QEventPoint p(point->id, point->state, globalPos, globalPos);
627 states |= point->state;
628 if (point->uniqueId >= 0)
629 QMutableEventPoint::setUniqueId(p, QPointingDeviceUniqueId::fromNumericId(point->uniqueId));
630 QMutableEventPoint::setPressure(p, point->pressure);
631 QMutableEventPoint::setRotation(p, point->rotation);
632 QMutableEventPoint::setEllipseDiameters(p, QHighDpi::fromNativePixels(point->area.size(), window));
633 QMutableEventPoint::setVelocity(p, QHighDpi::fromNativePixels(point->velocity, window));
634
635 // The local pos is not set: it will be calculated
636 // when the event gets processed by QGuiApplication.
637
638 touchPoints.append(p);
639 ++point;
640 }
641
642 // Determine the event type based on the combined point states.
643 if (type) {
644 *type = QEvent::TouchUpdate;
645 if (states == QEventPoint::State::Pressed)
646 *type = QEvent::TouchBegin;
647 else if (states == QEventPoint::State::Released)
648 *type = QEvent::TouchEnd;
649 }
650
651 return touchPoints;
652}
653
654QWindowSystemInterface::TouchPoint
655QWindowSystemInterfacePrivate::toNativeTouchPoint(const QEventPoint &pt, const QWindow *window)
656{
657 QWindowSystemInterface::TouchPoint p;
658 p.id = pt.id();
659 QRectF area(QPointF(), pt.ellipseDiameters());
660 area.moveCenter(pt.globalPosition());
661 // TODO store ellipseDiameters in QWindowSystemInterface::TouchPoint or just use QEventPoint
662 p.area = QHighDpi::toNativePixels(area, window);
663 p.pressure = pt.pressure();
664 p.state = pt.state();
665 p.velocity = QHighDpi::toNativePixels(pt.velocity(), window);
666 return p;
667}
668
669QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchEvent, QWindow *window, const QPointingDevice *device,
670 const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
671{
672 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
673 return handleTouchEvent<Delivery>(window, time, device, points, mods);
674}
675
676QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
677 const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
678{
679 if (!points.size()) // Touch events must have at least one point
680 return false;
681
682 if (!QPointingDevicePrivate::isRegistered(device)) // Disallow passing bogus, non-registered devices.
683 return false;
684
685 QEvent::Type type;
686 QList<QEventPoint> touchPoints =
687 QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
688
689 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TouchEvent, Delivery>(window,
690 timestamp, type, device, touchPoints, mods);
691}
692
693QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, const QPointingDevice *device,
694 Qt::KeyboardModifiers mods)
695{
696 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
697 return handleTouchCancelEvent<Delivery>(window, time, device, mods);
698}
699
700QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
701 Qt::KeyboardModifiers mods)
702{
703 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TouchEvent, Delivery>(window,
704 timestamp, QEvent::TouchCancel, device, QList<QEventPoint>(), mods);
705}
706
707/*!
708 Should be called by the implementation whenever a new screen is added.
709
710 The first screen added will be the primary screen, used for default-created
711 windows, GL contexts, and other resources unless otherwise specified.
712
713 This adds the screen to QGuiApplication::screens(), and emits the
714 QGuiApplication::screenAdded() signal.
715
716 The screen should be deleted by calling QWindowSystemInterface::handleScreenRemoved().
717*/
718void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *platformScreen, bool isPrimary)
719{
720 QScreen *screen = new QScreen(platformScreen);
721
722 if (isPrimary)
723 QGuiApplicationPrivate::screen_list.prepend(screen);
724 else
725 QGuiApplicationPrivate::screen_list.append(screen);
726
727 QGuiApplicationPrivate::resetCachedDevicePixelRatio();
728 QHighDpiScaling::updateHighDpiScaling();
729 screen->d_func()->updateGeometry();
730
731 emit qGuiApp->screenAdded(screen);
732
733 if (isPrimary)
734 emit qGuiApp->primaryScreenChanged(screen);
735}
736
737/*!
738 Should be called by the implementation whenever a screen is removed.
739
740 This removes the screen from QGuiApplication::screens(), and deletes it.
741
742 Failing to call this and manually deleting the QPlatformScreen instead may
743 lead to a crash due to a pure virtual call.
744*/
745void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen)
746{
747 QScreen *screen = platformScreen->screen();
748
749 // Remove screen
750 const bool wasPrimary = QGuiApplication::primaryScreen() == screen;
751 QGuiApplicationPrivate::screen_list.removeOne(screen);
752 QGuiApplicationPrivate::resetCachedDevicePixelRatio();
753
754 if (qGuiApp) {
755 QScreen *newPrimaryScreen = QGuiApplication::primaryScreen();
756 if (wasPrimary && newPrimaryScreen)
757 emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
758
759 // Allow clients to manage windows that are affected by the screen going
760 // away, before we fall back to moving them to the primary screen.
761 emit qApp->screenRemoved(screen);
762
763 if (!QGuiApplication::closingDown()) {
764 bool movingFromVirtualSibling = newPrimaryScreen
765 && newPrimaryScreen->handle()->virtualSiblings().contains(platformScreen);
766
767 // Move any leftover windows to the primary screen
768 const auto allWindows = QGuiApplication::allWindows();
769 for (QWindow *window : allWindows) {
770 if (!window->isTopLevel() || window->screen() != screen)
771 continue;
772
773 const bool wasVisible = window->isVisible();
774 window->setScreen(newPrimaryScreen);
775
776 // Re-show window if moved from a virtual sibling screen. Otherwise
777 // leave it up to the application developer to show the window.
778 if (movingFromVirtualSibling)
779 window->setVisible(wasVisible);
780 }
781 }
782 }
783
784 // Important to keep this order since the QSceen doesn't own the platform screen
785 delete screen;
786 delete platformScreen;
787}
788
789/*!
790 Should be called whenever the primary screen changes.
791
792 When the screen specified as primary changes, this method will notify
793 QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal.
794 */
795void QWindowSystemInterface::handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
796{
797 QScreen *newPrimaryScreen = newPrimary->screen();
798 qsizetype indexOfScreen = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen);
799 Q_ASSERT(indexOfScreen >= 0);
800 if (indexOfScreen == 0)
801 return;
802
803 QGuiApplicationPrivate::screen_list.swapItemsAt(0, indexOfScreen);
804 emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
805}
806
807void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation orientation)
808{
809 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenOrientationEvent>(screen, orientation);
810}
811
812void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry)
813{
814 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenGeometryEvent>(screen,
815 QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry,
816 screen, geometry.topLeft()));
817}
818
819void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY)
820{
821 // Keep QHighDpiScaling::m_active in sync with platform screen state, in
822 // order to make scaling calls made during DPI change use the new state.
823 // FIXME: Remove when QHighDpiScaling::m_active has been removed.
824 QHighDpiScaling::updateHighDpiScaling();
825
826 const QDpi effectiveDpi = QPlatformScreen::overrideDpi(QDpi{dpiX, dpiY});
827 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent>(screen,
828 effectiveDpi.first, effectiveDpi.second);
829}
830
831void QWindowSystemInterface::handleScreenRefreshRateChange(QScreen *screen, qreal newRefreshRate)
832{
833 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent>(screen, newRefreshRate);
834}
835
836QT_DEFINE_QPA_EVENT_HANDLER(void, handleThemeChange)
837{
838 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ThemeChangeEvent, Delivery>();
839}
840
841#if QT_CONFIG(draganddrop)
842/*!
843 Drag and drop events are sent immediately.
844
845 ### FIXME? Perhaps DnD API should add some convenience APIs that are more
846 intuitive for the possible DND operations. Here passing nullptr as drop data is used to
847 indicate that drop was canceled and QDragLeaveEvent should be sent as a result.
848*/
849QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *window, const QMimeData *dropData,
850 const QPoint &p, Qt::DropActions supportedActions,
851 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
852{
853 auto pos = QHighDpi::fromNativeLocalPosition(p, window);
854 return QGuiApplicationPrivate::processDrag(window, dropData, pos, supportedActions, buttons, modifiers);
855}
856
857QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData,
858 const QPoint &p, Qt::DropActions supportedActions,
859 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
860{
861 auto pos = QHighDpi::fromNativeLocalPosition(p, window);
862 return QGuiApplicationPrivate::processDrop(window, dropData, pos, supportedActions, buttons, modifiers);
863}
864#endif // QT_CONFIG(draganddrop)
865
866/*!
867 \fn static QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
868 \brief Passes a native event identified by \a eventType to the \a window.
869
870 \note This function can only be called from the GUI thread.
871*/
872
873bool QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
874{
875 return QGuiApplicationPrivate::processNativeEvent(window, eventType, message, result);
876}
877
878void QWindowSystemInterface::handleFileOpenEvent(const QString& fileName)
879{
880 QWindowSystemInterfacePrivate::FileOpenEvent e(fileName);
881 QGuiApplicationPrivate::processWindowSystemEvent(&e);
882}
883
884void QWindowSystemInterface::handleFileOpenEvent(const QUrl &url)
885{
886 QWindowSystemInterfacePrivate::FileOpenEvent e(url);
887 QGuiApplicationPrivate::processWindowSystemEvent(&e);
888}
889
890void QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(bool v)
891{
892 platformSynthesizesMouse = v;
893}
894
895bool QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
896 const QPointF &local, const QPointF &global,
897 Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
898 qreal tangentialPressure, qreal rotation, int z,
899 Qt::KeyboardModifiers modifiers)
900{
901 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEvent>(window,
902 timestamp,
903 QHighDpi::fromNativeLocalPosition(local, window),
904 QHighDpi::fromNativeGlobalPosition(global, window),
905 device, buttons, pressure,
906 xTilt, yTilt, tangentialPressure, rotation, z, modifiers);
907}
908
909bool QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointingDevice *device,
910 const QPointF &local, const QPointF &global,
911 Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
912 qreal tangentialPressure, qreal rotation, int z,
913 Qt::KeyboardModifiers modifiers)
914{
915 const ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
916 return handleTabletEvent(window, time, device, local, global,
917 buttons, pressure, xTilt, yTilt, tangentialPressure,
918 rotation, z, modifiers);
919}
920
921bool QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global,
922 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
923 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
924 Qt::KeyboardModifiers modifiers)
925{
926 const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(device),QPointingDevice::PointerType(pointerType),
927 QPointingDeviceUniqueId::fromNumericId(uid));
928 return handleTabletEvent(window, timestamp, dev, local, global, buttons, pressure,
929 xTilt, yTilt, tangentialPressure, rotation, z, modifiers);
930}
931
932bool QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
933 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
934 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
935 Qt::KeyboardModifiers modifiers)
936{
937 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
938 return handleTabletEvent(window, time, local, global, device, pointerType, buttons, pressure,
939 xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
940}
941
942bool QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
943 bool inProximity, const QPointF &local, const QPointF &global,
944 Qt::MouseButtons buttons, qreal xTilt, qreal yTilt,
945 qreal tangentialPressure, qreal rotation, int z,
946 Qt::KeyboardModifiers modifiers)
947{
948 Q_UNUSED(window);
949 Q_UNUSED(local);
950 Q_UNUSED(global);
951 Q_UNUSED(buttons);
952 Q_UNUSED(xTilt);
953 Q_UNUSED(yTilt);
954 Q_UNUSED(tangentialPressure);
955 Q_UNUSED(rotation);
956 Q_UNUSED(z);
957 Q_UNUSED(modifiers);
958 return inProximity
959 ? handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEnterProximityEvent>(timestamp, device)
960 : handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent>(timestamp, device);
961}
962
963bool QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(QWindow *window, const QPointingDevice *device,
964 bool inProximity, const QPointF &local, const QPointF &global,
965 Qt::MouseButtons buttons, qreal xTilt, qreal yTilt,
966 qreal tangentialPressure, qreal rotation, int z,
967 Qt::KeyboardModifiers modifiers)
968{
969 const ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
970 return handleTabletEnterLeaveProximityEvent(window, time, device, inProximity,
971 local, global, buttons, xTilt, yTilt,
972 tangentialPressure, rotation, z, modifiers);
973}
974
975
976bool QWindowSystemInterface::handleTabletEnterProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
977{
978 const QPointingDevice *device = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(deviceType),
979 QPointingDevice::PointerType(pointerType),
980 QPointingDeviceUniqueId::fromNumericId(uid));
981 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEnterProximityEvent>(timestamp, device);
982}
983
984void QWindowSystemInterface::handleTabletEnterProximityEvent(int deviceType, int pointerType, qint64 uid)
985{
986 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
987 handleTabletEnterProximityEvent(time, deviceType, pointerType, uid);
988}
989
990bool QWindowSystemInterface::handleTabletLeaveProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
991{
992 const QPointingDevice *device = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(deviceType),
993 QPointingDevice::PointerType(pointerType),
994 QPointingDeviceUniqueId::fromNumericId(uid));
995 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent>(timestamp, device);
996}
997
998void QWindowSystemInterface::handleTabletLeaveProximityEvent(int deviceType, int pointerType, qint64 uid)
999{
1000 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
1001 handleTabletLeaveProximityEvent(time, deviceType, pointerType, uid);
1002}
1003
1004#ifndef QT_NO_GESTURES
1005bool QWindowSystemInterface::handleGestureEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
1006 Qt::NativeGestureType type, const QPointF &local, const QPointF &global, int fingerCount)
1007{
1008 return handleGestureEventWithValueAndDelta(window, timestamp, device, type, {}, {}, local, global, fingerCount);
1009}
1010
1011bool QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, ulong timestamp, const QPointingDevice *device,
1012 Qt::NativeGestureType type, qreal value, const QPointF &local, const QPointF &global, int fingerCount)
1013{
1014 return handleGestureEventWithValueAndDelta(window, timestamp, device, type, value, {}, local, global, fingerCount);
1015}
1016
1017bool QWindowSystemInterface::handleGestureEventWithValueAndDelta(QWindow *window, ulong timestamp, const QPointingDevice *device,
1018 Qt::NativeGestureType type, qreal value, const QPointF &delta,
1019 const QPointF &local, const QPointF &global, int fingerCount)
1020{
1021 auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
1022 auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
1023
1024 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::GestureEvent>(window,
1025 timestamp, type, device, fingerCount, localPos, globalPos, value, delta);
1026}
1027#endif // QT_NO_GESTURES
1028
1029void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w)
1030{
1031 handleWindowSystemEvent<QWindowSystemInterfacePrivate::PlatformPanelEvent>(w);
1032}
1033
1034#ifndef QT_NO_CONTEXTMENU
1035QT_DEFINE_QPA_EVENT_HANDLER(bool, handleContextMenuEvent, QWindow *window, bool mouseTriggered,
1036 const QPoint &pos, const QPoint &globalPos,
1037 Qt::KeyboardModifiers modifiers)
1038{
1039 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::ContextMenuEvent, Delivery>(
1040 window, mouseTriggered, pos, globalPos, modifiers);
1041}
1042#endif
1043
1044#if QT_CONFIG(whatsthis)
1045void QWindowSystemInterface::handleEnterWhatsThisEvent()
1046{
1047 handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowSystemEvent>(
1048 QWindowSystemInterfacePrivate::EnterWhatsThisMode);
1049}
1050#endif
1051
1052#ifndef QT_NO_DEBUG_STREAM
1053Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPoint &p)
1054{
1055 QDebugStateSaver saver(dbg);
1056 dbg.nospace() << "TouchPoint(" << p.id << " @" << p.area << " normalized " << p.normalPosition
1057 << " press " << p.pressure << " vel " << p.velocity << " state " << (int)p.state;
1058 return dbg;
1059}
1060#endif
1061
1062// ------------------ Event dispatcher functionality ------------------
1063
1064/*!
1065 Make Qt Gui process all events on the event queue immediately. Return the
1066 accepted state for the last event on the queue.
1067*/
1068bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1069{
1070 const qsizetype count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
1071 if (!count)
1072 return false;
1073 if (!QGuiApplication::instance()) {
1074 qWarning().nospace()
1075 << "QWindowSystemInterface::flushWindowSystemEvents() invoked after "
1076 "QGuiApplication destruction, discarding " << count << " events.";
1077 QWindowSystemInterfacePrivate::windowSystemEventQueue.clear();
1078 return false;
1079 }
1080 if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
1081 // Post a FlushEvents event which will trigger a call back to
1082 // deferredFlushWindowSystemEvents from the Gui thread.
1083 QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
1084 handleWindowSystemEvent<QWindowSystemInterfacePrivate::FlushEventsEvent, AsynchronousDelivery>(flags);
1085 QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex);
1086 } else {
1087 sendWindowSystemEvents(flags);
1088 }
1089 return QWindowSystemInterfacePrivate::eventAccepted.loadRelaxed() > 0;
1090}
1091
1092void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1093{
1094 Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread());
1095
1096 QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
1097 sendWindowSystemEvents(flags);
1098 QWindowSystemInterfacePrivate::eventsFlushed.wakeOne();
1099}
1100
1101bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1102{
1103 int nevents = 0;
1104
1105 while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
1106 QWindowSystemInterfacePrivate::WindowSystemEvent *event =
1107 flags & QEventLoop::ExcludeUserInputEvents ?
1108 QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
1109 QWindowSystemInterfacePrivate::getWindowSystemEvent();
1110 if (!event)
1111 break;
1112
1113 if (QWindowSystemInterfacePrivate::eventHandler) {
1114 if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
1115 nevents++;
1116 } else {
1117 nevents++;
1118 QGuiApplicationPrivate::processWindowSystemEvent(event);
1119 }
1120
1121 // Record the accepted state for the processed event
1122 // (excluding flush events). This state can then be
1123 // returned by flushWindowSystemEvents().
1124 if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
1125 QWindowSystemInterfacePrivate::eventAccepted.storeRelaxed(event->eventAccepted);
1126
1127 delete event;
1128 }
1129
1130 return (nevents > 0);
1131}
1132
1133void QWindowSystemInterface::setSynchronousWindowSystemEvents(bool enable)
1134{
1135 QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = enable;
1136}
1137
1138int QWindowSystemInterface::windowSystemEventsQueued()
1139{
1140 return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
1141}
1142
1143bool QWindowSystemInterface::nonUserInputEventsQueued()
1144{
1145 return QWindowSystemInterfacePrivate::nonUserInputEventsQueued();
1146}
1147
1148// --------------------- QtTestLib support ---------------------
1149
1150// The following functions are used by testlib, and need to be synchronous to avoid
1151// race conditions with plugins delivering native events from secondary threads.
1152// FIXME: It seems unnecessary to export these wrapper functions, when qtestlib could access
1153// QWindowSystemInterface directly (by adding dependency to gui-private), see QTBUG-63146.
1154
1155Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global,
1156 Qt::MouseButtons state, Qt::MouseButton button,
1157 QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp)
1158{
1159 QPointF nativeLocal = QHighDpi::toNativeLocalPosition(local, window);
1160 QPointF nativeGlobal = QHighDpi::toNativeGlobalPosition(global, window);
1161 QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window,
1162 timestamp, nativeLocal, nativeGlobal, state, button, type, mods);
1163}
1164
1165/*
1166 Used by QTest::simulateEvent() to synthesize key events during testing
1167*/
1168Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1)
1169{
1170#if defined(Q_OS_MACOS)
1171 // FIXME: Move into QTest::simulateEvent() and align with QGuiApplicationPrivate::processKeyEvent()
1172 auto timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed();
1173 if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, k, mods, 0, 0, 0, text, autorep, count))
1174 return;
1175#endif
1176
1177 QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(window, t, k, mods, text, autorep, count);
1178}
1179
1180Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1)
1181{
1182#if QT_CONFIG(shortcut)
1183
1184 // FIXME: This method should not allow targeting a specific object, but should
1185 // instead forward the event to a window, which then takes care of normal event
1186 // propagation. We need to fix a lot of tests before we can refactor this (the
1187 // window needs to be exposed and active and have a focus object), so we leave
1188 // it as is for now. See QTBUG-48577.
1189
1190 QGuiApplicationPrivate::modifier_buttons = mods;
1191
1192 QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count);
1193 qevent.setTimestamp(timestamp);
1194
1195 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
1196 if (shortcutMap.state() == QKeySequence::NoMatch) {
1197 // Try sending as QKeyEvent::ShortcutOverride first
1198 QCoreApplication::sendEvent(o, &qevent);
1199 if (qevent.isAccepted())
1200 return false;
1201 }
1202
1203 // Then as QShortcutEvent
1204 return shortcutMap.tryShortcut(&qevent);
1205#else
1206 Q_UNUSED(o);
1207 Q_UNUSED(timestamp);
1208 Q_UNUSED(k);
1209 Q_UNUSED(mods);
1210 Q_UNUSED(text);
1211 Q_UNUSED(autorep);
1212 Q_UNUSED(count);
1213 return false;
1214#endif
1215}
1216
1217Q_GUI_EXPORT void qt_handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global,
1218 QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods,
1219 Qt::ScrollPhase phase)
1220{
1221 QWindowSystemInterface::handleWheelEvent(window, local, global, pixelDelta, angleDelta, mods, phase);
1222}
1223
1224namespace QTest
1225{
1226 Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType,
1228 {
1229 static qint64 nextId = 0x100000000;
1230 QPointingDevice *ret = new QPointingDevice("test touch device"_L1, nextId++,
1232 caps, 8, 0);
1234 return ret;
1235 }
1236}
1237
1238Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *window, const QPointingDevice *device,
1239 const QList<QEventPoint> &points,
1240 Qt::KeyboardModifiers mods)
1241{
1242 return QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window, device,
1243 QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window), mods);
1244}
1245
1246Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *window, const QPointingDevice *device,
1247 const QList<QEventPoint> &points,
1248 Qt::KeyboardModifiers mods)
1249{
1250 qt_handleTouchEventv2(window, device, points, mods);
1251}
1252
1253QT_END_NAMESPACE
Combined button and popup list for selecting options.
Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2582
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString &text=QString(), bool autorep=false, ushort count=1)
Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *window, const QPointingDevice *device, const QList< QEventPoint > &points, Qt::KeyboardModifiers mods)
Q_GUI_EXPORT void qt_handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase)
static bool handleWindowSystemEvent(Args ...args)
Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *window, const QPointingDevice *device, const QList< QEventPoint > &points, Qt::KeyboardModifiers mods)
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)
#define QT_DEFINE_QPA_EVENT_HANDLER(ReturnType, HandlerName,...)
QPointer< QWindow > qt_last_mouse_receiver
Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp)
static bool handleEvent(Args ...)