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

source code of qtbase/src/gui/kernel/qwindowsysteminterface.cpp