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
4#include <qpa/qplatformwindow.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>
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
24
25using namespace Qt::StringLiterals;
26
27Q_LOGGING_CATEGORY(lcQpaInputDevices, "qt.qpa.input.devices", QtWarningMsg)
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
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>
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::isMainThread()) {
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))
103 return false;
104 } else {
105 QGuiApplicationPrivate::processWindowSystemEvent(&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(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(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(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(local, window), QHighDpi::fromNativeGlobalPosition(global, 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>(leave);
240 handleEnterEvent(enter, local, global);
241}
242
243QT_DEFINE_QPA_EVENT_HANDLER(void, handleFocusWindowChanged, QWindow *window, Qt::FocusReason r)
244{
245 handleWindowSystemEvent<QWindowSystemInterfacePrivate::FocusWindowEvent, 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(nativeGeometry, 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(newRect, 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(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(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(local, window);
416 auto globalPos = QHighDpi::fromNativeGlobalPosition(global, 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 (window,timestamp, QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode,
438 nativeVirtualKey, nativeModifiers, text, autorepeat, 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(&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, 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>(window,
495 timestamp, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, 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, 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, QPointingDevice::primaryPointingDevice(), local, global,
508 pixelDelta, angleDelta, mods, phase, source, 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>(window,
532 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
533 pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling, device);
534 }
535
536 // Simple case: horizontal deltas only:
537 if (angleDelta.y() == 0 && angleDelta.x() != 0) {
538 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
539 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
540 pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling, 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>(window,
549 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
550 pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling, 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>(window,
555 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
556 QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling, 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 QInputDevicePrivate::registerDevice(device);
580}
581
582/*!
583 \internal
584 Convert a list of \l QWindowSystemInterface::TouchPoint \a points to a list
585 of \e temporary QEventPoint instances, scaled (but not localized)
586 for delivery to the given \a window.
587
588 This is called from QWindowSystemInterface::handleTouchEvent():
589 that is too early to update the QEventPoint instances in QPointingDevice,
590 because we want those to hold "current" state from the applcation's
591 point of view. The QWindowSystemInterfacePrivate::TouchEvent, to which
592 the returned touchpoints will "belong", might go through the queue before
593 being processed; the application doesn't see the equivalent QTouchEvent
594 until later on. Therefore the responsibility to update the QEventPoint
595 instances in QPointingDevice is in QGuiApplication, not here.
596
597 QGuiApplicationPrivate::processMouseEvent() also calls this function
598 when it synthesizes a touch event from a mouse event. But that's outside
599 the normal use case.
600
601 It might be better if we change all the platform plugins to create
602 temporary instances of QEventPoint directly, and remove
603 QWindowSystemInterface::TouchPoint completely. Then we will no longer need
604 this function either. But that's only possible as long as QEventPoint
605 remains a Q_GADGET, not a QObject, so that it continues to be small and
606 suitable for temporary stack allocation. QEventPoint is a little bigger
607 than QWindowSystemInterface::TouchPoint, though.
608*/
609QList<QEventPoint>
610 QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
611 const QWindow *window, QEvent::Type *type)
612{
613 QList<QEventPoint> touchPoints;
614 QEventPoint::States states;
615
616 touchPoints.reserve(points.size());
617 QList<QWindowSystemInterface::TouchPoint>::const_iterator point = points.constBegin();
618 QList<QWindowSystemInterface::TouchPoint>::const_iterator end = points.constEnd();
619 while (point != end) {
620 QPointF globalPos = QHighDpi::fromNativePixels(point->area.center(), window);
621 QEventPoint p(point->id, point->state, globalPos, globalPos);
622 states |= point->state;
623 if (point->uniqueId >= 0)
624 QMutableEventPoint::setUniqueId(p, QPointingDeviceUniqueId::fromNumericId(point->uniqueId));
625 QMutableEventPoint::setPressure(p, point->pressure);
626 QMutableEventPoint::setRotation(p, point->rotation);
627 QMutableEventPoint::setEllipseDiameters(p, QHighDpi::fromNativePixels(point->area.size(), window));
628 QMutableEventPoint::setVelocity(p, QHighDpi::fromNativePixels(point->velocity, window));
629
630 // The local pos is not set: it will be calculated
631 // when the event gets processed by QGuiApplication.
632
633 touchPoints.append(p);
634 ++point;
635 }
636
637 // Determine the event type based on the combined point states.
638 if (type) {
639 *type = QEvent::TouchUpdate;
640 if (states == QEventPoint::State::Pressed)
641 *type = QEvent::TouchBegin;
642 else if (states == QEventPoint::State::Released)
643 *type = QEvent::TouchEnd;
644 }
645
646 return touchPoints;
647}
648
649QWindowSystemInterface::TouchPoint
650QWindowSystemInterfacePrivate::toNativeTouchPoint(const QEventPoint &pt, const QWindow *window)
651{
652 QWindowSystemInterface::TouchPoint p;
653 p.id = pt.id();
654 QRectF area(QPointF(), pt.ellipseDiameters());
655 area.moveCenter(pt.globalPosition());
656 // TODO store ellipseDiameters in QWindowSystemInterface::TouchPoint or just use QEventPoint
657 p.area = QHighDpi::toNativePixels(area, window);
658 p.pressure = pt.pressure();
659 p.state = pt.state();
660 p.velocity = QHighDpi::toNativePixels(pt.velocity(), window);
661 return p;
662}
663
664QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchEvent, QWindow *window, const QPointingDevice *device,
665 const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
666{
667 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
668 return handleTouchEvent<Delivery>(window, time, device, points, mods);
669}
670
671QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
672 const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
673{
674 if (!points.size()) // Touch events must have at least one point
675 return false;
676
677 if (!QPointingDevicePrivate::isRegistered(device)) // Disallow passing bogus, non-registered devices.
678 return false;
679
680 QEvent::Type type;
681 QList<QEventPoint> touchPoints =
682 QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
683
684 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TouchEvent, Delivery>(window,
685 timestamp, type, device, touchPoints, mods);
686}
687
688QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, const QPointingDevice *device,
689 Qt::KeyboardModifiers mods)
690{
691 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
692 return handleTouchCancelEvent<Delivery>(window, time, device, mods);
693}
694
695QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
696 Qt::KeyboardModifiers mods)
697{
698 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TouchEvent, Delivery>(window,
699 timestamp, QEvent::TouchCancel, device, QList<QEventPoint>(), mods);
700}
701
702/*!
703 Should be called by the implementation whenever a new screen is added.
704
705 The first screen added will be the primary screen, used for default-created
706 windows, GL contexts, and other resources unless otherwise specified.
707
708 This adds the screen to QGuiApplication::screens(), and emits the
709 QGuiApplication::screenAdded() signal.
710
711 The screen should be deleted by calling QWindowSystemInterface::handleScreenRemoved().
712*/
713void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *platformScreen, bool isPrimary)
714{
715 QScreen *screen = new QScreen(platformScreen);
716
717 if (isPrimary)
718 QGuiApplicationPrivate::screen_list.prepend(screen);
719 else
720 QGuiApplicationPrivate::screen_list.append(screen);
721
722 QGuiApplicationPrivate::resetCachedDevicePixelRatio();
723 QHighDpiScaling::updateHighDpiScaling();
724 screen->d_func()->updateGeometry();
725
726 emit qGuiApp->screenAdded(screen);
727
728 if (isPrimary)
729 emit qGuiApp->primaryScreenChanged(screen);
730}
731
732/*!
733 Should be called by the implementation whenever a screen is removed.
734
735 This removes the screen from QGuiApplication::screens(), and deletes it.
736
737 Failing to call this and manually deleting the QPlatformScreen instead may
738 lead to a crash due to a pure virtual call.
739*/
740void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen)
741{
742 QScreen *screen = platformScreen->screen();
743
744 // Remove screen
745 const bool wasPrimary = QGuiApplication::primaryScreen() == screen;
746 QGuiApplicationPrivate::screen_list.removeOne(screen);
747 QGuiApplicationPrivate::resetCachedDevicePixelRatio();
748
749 if (qGuiApp) {
750 QScreen *newPrimaryScreen = QGuiApplication::primaryScreen();
751 if (wasPrimary && newPrimaryScreen)
752 emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
753
754 // Allow clients to manage windows that are affected by the screen going
755 // away, before we fall back to moving them to the primary screen.
756 emit qApp->screenRemoved(screen);
757
758 if (!QGuiApplication::closingDown()) {
759 bool movingFromVirtualSibling = newPrimaryScreen
760 && newPrimaryScreen->handle()->virtualSiblings().contains(platformScreen);
761
762 // Move any leftover windows to the primary screen
763 const auto allWindows = QGuiApplication::allWindows();
764 for (QWindow *window : allWindows) {
765 if (!window->isTopLevel() || window->screen() != screen)
766 continue;
767
768 const bool wasVisible = window->isVisible();
769 window->setScreen(newPrimaryScreen);
770
771 // Re-show window if moved from a virtual sibling screen. Otherwise
772 // leave it up to the application developer to show the window.
773 if (movingFromVirtualSibling)
774 window->setVisible(wasVisible);
775 }
776 }
777 }
778
779 // Important to keep this order since the QSceen doesn't own the platform screen
780 delete screen;
781 delete platformScreen;
782}
783
784/*!
785 Should be called whenever the primary screen changes.
786
787 When the screen specified as primary changes, this method will notify
788 QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal.
789 */
790void QWindowSystemInterface::handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
791{
792 QScreen *newPrimaryScreen = newPrimary->screen();
793 qsizetype indexOfScreen = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen);
794 Q_ASSERT(indexOfScreen >= 0);
795 if (indexOfScreen == 0)
796 return;
797
798 QGuiApplicationPrivate::screen_list.swapItemsAt(0, indexOfScreen);
799 emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
800}
801
802void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation orientation)
803{
804 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenOrientationEvent>(screen, orientation);
805}
806
807void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry)
808{
809 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenGeometryEvent>(screen,
810 QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry,
811 screen, geometry.topLeft()));
812}
813
814void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY)
815{
816 // Keep QHighDpiScaling::m_active in sync with platform screen state, in
817 // order to make scaling calls made during DPI change use the new state.
818 // FIXME: Remove when QHighDpiScaling::m_active has been removed.
819 QHighDpiScaling::updateHighDpiScaling();
820
821 const QDpi effectiveDpi = QPlatformScreen::overrideDpi(QDpi{dpiX, dpiY});
822 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent>(screen,
823 effectiveDpi.first, effectiveDpi.second);
824}
825
826void QWindowSystemInterface::handleScreenRefreshRateChange(QScreen *screen, qreal newRefreshRate)
827{
828 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent>(screen, newRefreshRate);
829}
830
831QT_DEFINE_QPA_EVENT_HANDLER(void, handleThemeChange, QWindow *window)
832{
833 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ThemeChangeEvent, Delivery>(window);
834}
835
836#if QT_CONFIG(draganddrop)
837/*!
838 Drag and drop events are sent immediately.
839
840 ### FIXME? Perhaps DnD API should add some convenience APIs that are more
841 intuitive for the possible DND operations. Here passing nullptr as drop data is used to
842 indicate that drop was canceled and QDragLeaveEvent should be sent as a result.
843*/
844QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *window, const QMimeData *dropData,
845 const QPoint &p, Qt::DropActions supportedActions,
846 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
847{
848 auto pos = QHighDpi::fromNativeLocalPosition(p, window);
849 return QGuiApplicationPrivate::processDrag(window, dropData, pos, supportedActions, buttons, modifiers);
850}
851
852QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData,
853 const QPoint &p, Qt::DropActions supportedActions,
854 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
855{
856 auto pos = QHighDpi::fromNativeLocalPosition(p, window);
857 return QGuiApplicationPrivate::processDrop(window, dropData, pos, supportedActions, buttons, modifiers);
858}
859#endif // QT_CONFIG(draganddrop)
860
861/*!
862 \fn static QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
863 \brief Passes a native event identified by \a eventType to the \a window.
864
865 \note This function can only be called from the GUI thread.
866*/
867
868bool QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
869{
870 return QGuiApplicationPrivate::processNativeEvent(window, eventType, message, result);
871}
872
873void QWindowSystemInterface::handleFileOpenEvent(const QString& fileName)
874{
875 QWindowSystemInterfacePrivate::FileOpenEvent e(fileName);
876 QGuiApplicationPrivate::processWindowSystemEvent(&e);
877}
878
879void QWindowSystemInterface::handleFileOpenEvent(const QUrl &url)
880{
881 QWindowSystemInterfacePrivate::FileOpenEvent e(url);
882 QGuiApplicationPrivate::processWindowSystemEvent(&e);
883}
884
885void QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(bool v)
886{
887 platformSynthesizesMouse = v;
888}
889
890bool QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
891 const QPointF &local, const QPointF &global,
892 Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
893 qreal tangentialPressure, qreal rotation, int z,
894 Qt::KeyboardModifiers modifiers)
895{
896 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEvent>(window,
897 timestamp,
898 QHighDpi::fromNativeLocalPosition(local, window),
899 QHighDpi::fromNativeGlobalPosition(global, window),
900 device, buttons, pressure,
901 xTilt, yTilt, tangentialPressure, rotation, z, modifiers);
902}
903
904bool QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointingDevice *device,
905 const QPointF &local, const QPointF &global,
906 Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
907 qreal tangentialPressure, qreal rotation, int z,
908 Qt::KeyboardModifiers modifiers)
909{
910 const ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
911 return handleTabletEvent(window, time, device, local, global,
912 buttons, pressure, xTilt, yTilt, tangentialPressure,
913 rotation, z, modifiers);
914}
915
916bool QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global,
917 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
918 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
919 Qt::KeyboardModifiers modifiers)
920{
921 const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(device),QPointingDevice::PointerType(pointerType),
922 QPointingDeviceUniqueId::fromNumericId(uid));
923 return handleTabletEvent(window, timestamp, dev, local, global, buttons, pressure,
924 xTilt, yTilt, tangentialPressure, rotation, z, modifiers);
925}
926
927bool QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
928 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
929 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
930 Qt::KeyboardModifiers modifiers)
931{
932 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
933 return handleTabletEvent(window, time, local, global, device, pointerType, buttons, pressure,
934 xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
935}
936
937bool QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
938 bool inProximity, const QPointF &local, const QPointF &global,
939 Qt::MouseButtons buttons, qreal xTilt, qreal yTilt,
940 qreal tangentialPressure, qreal rotation, int z,
941 Qt::KeyboardModifiers modifiers)
942{
943 Q_UNUSED(window);
944 Q_UNUSED(local);
945 Q_UNUSED(global);
946 Q_UNUSED(buttons);
947 Q_UNUSED(xTilt);
948 Q_UNUSED(yTilt);
949 Q_UNUSED(tangentialPressure);
950 Q_UNUSED(rotation);
951 Q_UNUSED(z);
952 Q_UNUSED(modifiers);
953 return inProximity
954 ? handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEnterProximityEvent>(timestamp, device)
955 : handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent>(timestamp, device);
956}
957
958bool QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(QWindow *window, const QPointingDevice *device,
959 bool inProximity, const QPointF &local, const QPointF &global,
960 Qt::MouseButtons buttons, qreal xTilt, qreal yTilt,
961 qreal tangentialPressure, qreal rotation, int z,
962 Qt::KeyboardModifiers modifiers)
963{
964 const ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
965 return handleTabletEnterLeaveProximityEvent(window, time, device, inProximity,
966 local, global, buttons, xTilt, yTilt,
967 tangentialPressure, rotation, z, modifiers);
968}
969
970
971bool QWindowSystemInterface::handleTabletEnterProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
972{
973 const QPointingDevice *device = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(deviceType),
974 QPointingDevice::PointerType(pointerType),
975 QPointingDeviceUniqueId::fromNumericId(uid));
976 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEnterProximityEvent>(timestamp, device);
977}
978
979void QWindowSystemInterface::handleTabletEnterProximityEvent(int deviceType, int pointerType, qint64 uid)
980{
981 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
982 handleTabletEnterProximityEvent(time, deviceType, pointerType, uid);
983}
984
985bool QWindowSystemInterface::handleTabletLeaveProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
986{
987 const QPointingDevice *device = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(deviceType),
988 QPointingDevice::PointerType(pointerType),
989 QPointingDeviceUniqueId::fromNumericId(uid));
990 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent>(timestamp, device);
991}
992
993void QWindowSystemInterface::handleTabletLeaveProximityEvent(int deviceType, int pointerType, qint64 uid)
994{
995 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
996 handleTabletLeaveProximityEvent(time, deviceType, pointerType, uid);
997}
998
999#ifndef QT_NO_GESTURES
1000bool QWindowSystemInterface::handleGestureEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
1001 Qt::NativeGestureType type, const QPointF &local, const QPointF &global, int fingerCount)
1002{
1003 return handleGestureEventWithValueAndDelta(window, timestamp, device, type, {}, {}, local, global, fingerCount);
1004}
1005
1006bool QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, ulong timestamp, const QPointingDevice *device,
1007 Qt::NativeGestureType type, qreal value, const QPointF &local, const QPointF &global, int fingerCount)
1008{
1009 return handleGestureEventWithValueAndDelta(window, timestamp, device, type, value, {}, local, global, fingerCount);
1010}
1011
1012bool QWindowSystemInterface::handleGestureEventWithValueAndDelta(QWindow *window, ulong timestamp, const QPointingDevice *device,
1013 Qt::NativeGestureType type, qreal value, const QPointF &delta,
1014 const QPointF &local, const QPointF &global, int fingerCount)
1015{
1016 auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
1017 auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
1018
1019 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::GestureEvent>(window,
1020 timestamp, type, device, fingerCount, localPos, globalPos, value, delta);
1021}
1022#endif // QT_NO_GESTURES
1023
1024void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w)
1025{
1026 handleWindowSystemEvent<QWindowSystemInterfacePrivate::PlatformPanelEvent>(w);
1027}
1028
1029#ifndef QT_NO_CONTEXTMENU
1030QT_DEFINE_QPA_EVENT_HANDLER(bool, handleContextMenuEvent, QWindow *window, bool mouseTriggered,
1031 const QPoint &pos, const QPoint &globalPos,
1032 Qt::KeyboardModifiers modifiers)
1033{
1034 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::ContextMenuEvent, Delivery>(
1035 window, mouseTriggered, pos, globalPos, modifiers);
1036}
1037#endif
1038
1039#if QT_CONFIG(whatsthis)
1040void QWindowSystemInterface::handleEnterWhatsThisEvent()
1041{
1042 handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowSystemEvent>(
1043 QWindowSystemInterfacePrivate::EnterWhatsThisMode);
1044}
1045#endif
1046
1047#ifndef QT_NO_DEBUG_STREAM
1048Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPoint &p)
1049{
1050 QDebugStateSaver saver(dbg);
1051 dbg.nospace() << "TouchPoint(" << p.id << " @" << p.area << " normalized " << p.normalPosition
1052 << " press " << p.pressure << " vel " << p.velocity << " state " << (int)p.state;
1053 return dbg;
1054}
1055#endif
1056
1057// ------------------ Event dispatcher functionality ------------------
1058
1059/*!
1060 Make Qt Gui process all events on the event queue immediately. Return the
1061 accepted state for the last event on the queue.
1062*/
1063bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1064{
1065 const qsizetype count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
1066 if (!count)
1067 return false;
1068 if (!QGuiApplication::instance()) {
1069 qWarning().nospace()
1070 << "QWindowSystemInterface::flushWindowSystemEvents() invoked after "
1071 "QGuiApplication destruction, discarding " << count << " events.";
1072 QWindowSystemInterfacePrivate::windowSystemEventQueue.clear();
1073 return false;
1074 }
1075 if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
1076 // Post a FlushEvents event which will trigger a call back to
1077 // deferredFlushWindowSystemEvents from the Gui thread.
1078 QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
1079 handleWindowSystemEvent<QWindowSystemInterfacePrivate::FlushEventsEvent, AsynchronousDelivery>(flags);
1080 QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex);
1081 } else {
1082 sendWindowSystemEvents(flags);
1083 }
1084 return QWindowSystemInterfacePrivate::eventAccepted.loadRelaxed() > 0;
1085}
1086
1087void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1088{
1089 Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread());
1090
1091 QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
1092 sendWindowSystemEvents(flags);
1093 QWindowSystemInterfacePrivate::eventsFlushed.wakeOne();
1094}
1095
1096bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1097{
1098 int nevents = 0;
1099
1100 while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
1101 QWindowSystemInterfacePrivate::WindowSystemEvent *event =
1102 flags & QEventLoop::ExcludeUserInputEvents ?
1103 QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
1104 QWindowSystemInterfacePrivate::getWindowSystemEvent();
1105 if (!event)
1106 break;
1107
1108 if (QWindowSystemInterfacePrivate::eventHandler) {
1109 if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
1110 nevents++;
1111 } else {
1112 nevents++;
1113 QGuiApplicationPrivate::processWindowSystemEvent(event);
1114 }
1115
1116 // Record the accepted state for the processed event
1117 // (excluding flush events). This state can then be
1118 // returned by flushWindowSystemEvents().
1119 if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
1120 QWindowSystemInterfacePrivate::eventAccepted.storeRelaxed(event->eventAccepted);
1121
1122 delete event;
1123 }
1124
1125 return (nevents > 0);
1126}
1127
1128void QWindowSystemInterface::setSynchronousWindowSystemEvents(bool enable)
1129{
1130 QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = enable;
1131}
1132
1133int QWindowSystemInterface::windowSystemEventsQueued()
1134{
1135 return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
1136}
1137
1138bool QWindowSystemInterface::nonUserInputEventsQueued()
1139{
1140 return QWindowSystemInterfacePrivate::nonUserInputEventsQueued();
1141}
1142
1143// --------------------- QtTestLib support ---------------------
1144
1145// The following functions are used by testlib, and need to be synchronous to avoid
1146// race conditions with plugins delivering native events from secondary threads.
1147// FIXME: It seems unnecessary to export these wrapper functions, when qtestlib could access
1148// QWindowSystemInterface directly (by adding dependency to gui-private), see QTBUG-63146.
1149
1150Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global,
1151 Qt::MouseButtons state, Qt::MouseButton button,
1152 QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp)
1153{
1154 QPointF nativeLocal = QHighDpi::toNativeLocalPosition(local, window);
1155 QPointF nativeGlobal = QHighDpi::toNativeGlobalPosition(global, window);
1156 QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window,
1157 timestamp, nativeLocal, nativeGlobal, state, button, type, mods);
1158}
1159
1160/*
1161 Used by QTest::simulateEvent() to synthesize key events during testing
1162*/
1163Q_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)
1164{
1165#if defined(Q_OS_MACOS)
1166 // FIXME: Move into QTest::simulateEvent() and align with QGuiApplicationPrivate::processKeyEvent()
1167 auto timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed();
1168 if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, k, mods, 0, 0, 0, text, autorep, count))
1169 return;
1170#endif
1171
1172 QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(window, t, k, mods, text, autorep, count);
1173}
1174
1175Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1)
1176{
1177#if QT_CONFIG(shortcut)
1178
1179 // FIXME: This method should not allow targeting a specific object, but should
1180 // instead forward the event to a window, which then takes care of normal event
1181 // propagation. We need to fix a lot of tests before we can refactor this (the
1182 // window needs to be exposed and active and have a focus object), so we leave
1183 // it as is for now. See QTBUG-48577.
1184
1185 QGuiApplicationPrivate::modifier_buttons = mods;
1186
1187 QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count);
1188 qevent.setTimestamp(timestamp);
1189
1190 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
1191 if (shortcutMap.state() == QKeySequence::NoMatch) {
1192 // Try sending as QKeyEvent::ShortcutOverride first
1193 QCoreApplication::sendEvent(o, &qevent);
1194 if (qevent.isAccepted())
1195 return false;
1196 }
1197
1198 // Then as QShortcutEvent
1199 return shortcutMap.tryShortcut(&qevent);
1200#else
1201 Q_UNUSED(o);
1202 Q_UNUSED(timestamp);
1203 Q_UNUSED(k);
1204 Q_UNUSED(mods);
1205 Q_UNUSED(text);
1206 Q_UNUSED(autorep);
1207 Q_UNUSED(count);
1208 return false;
1209#endif
1210}
1211
1212Q_GUI_EXPORT void qt_handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global,
1213 QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods,
1214 Qt::ScrollPhase phase)
1215{
1216 QWindowSystemInterface::handleWheelEvent(window, local, global, pixelDelta, angleDelta, mods, phase);
1217}
1218
1219namespace QTest
1220{
1221 Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType,
1223 {
1224 static qint64 nextId = 0x100000000;
1225 QPointingDevice *ret = new QPointingDevice("test touch device"_L1, nextId++,
1227 caps, 8, 0);
1229 return ret;
1230 }
1231}
1232
1233Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *window, const QPointingDevice *device,
1234 const QList<QEventPoint> &points,
1235 Qt::KeyboardModifiers mods)
1236{
1237 return QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window, device,
1238 QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window), mods);
1239}
1240
1241Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *window, const QPointingDevice *device,
1242 const QList<QEventPoint> &points,
1243 Qt::KeyboardModifiers mods)
1244{
1245 qt_handleTouchEventv2(window, device, points, mods);
1246}
1247
1248QT_END_NAMESPACE
Combined button and popup list for selecting options.
Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2462
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 ...)