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,
286 QRect requestedGeometry,
287 QRect newGeometry)
288 : WindowSystemEvent(GeometryChange)
289 , window(window)
290 , requestedGeometry(requestedGeometry)
291 , newGeometry(newGeometry)
292{
293}
294
295QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect)
296{
297 Q_ASSERT(window);
298 const auto newRectDi = QHighDpi::fromNativeWindowGeometry(newRect, window);
299 QRect requestedGeometry;
300 if (auto *handle = window->handle()) {
301 requestedGeometry = QHighDpi::fromNativeWindowGeometry(handle->QPlatformWindow::geometry(),
302 window);
303 // Persist the new geometry so that QWindow::geometry() can be queried in the resize event
304 handle->QPlatformWindow::setGeometry(newRect);
305 // FIXME: This does not work during platform window creation, where the QWindow does not
306 // have its handle set up yet. Platforms that deliver events during window creation need
307 // to handle the persistence manually, e.g. by overriding geometry().
308 }
309 handleWindowSystemEvent<QWindowSystemInterfacePrivate::GeometryChangeEvent, Delivery>(window,
310 requestedGeometry,
311 newRectDi);
312}
313
314QWindowSystemInterfacePrivate::ExposeEvent::ExposeEvent(QWindow *window, const QRegion &region)
315 : WindowSystemEvent(Expose)
316 , window(window)
317 , isExposed(window && window->handle() ? window->handle()->isExposed() : false)
318 , region(region)
319{
320}
321
322/*! \internal
323 Handles an expose event.
324
325 The platform plugin sends expose events when an area of the window
326 is invalidated or window exposure changes. \a region is in window
327 local coordinates. An empty region indicates that the window is
328 obscured, but note that the exposed property of the QWindow will be set
329 based on what QPlatformWindow::isExposed() returns at the time of this call,
330 not based on what the region is. // FIXME: this should probably be fixed.
331
332 The platform plugin may omit sending expose events (or send obscure
333 events) for windows that are on screen but where the client area is
334 completely covered by other windows or otherwise not visible. Expose
335 event consumers can then use this to disable updates for such windows.
336 This is required behavior on platforms where OpenGL swapbuffers stops
337 blocking for obscured windows (like macOS).
338*/
339QT_DEFINE_QPA_EVENT_HANDLER(bool, handleExposeEvent, QWindow *window, const QRegion &region)
340{
341 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::ExposeEvent, Delivery>(window,
342 QHighDpi::fromNativeLocalExposedRegion(region, window));
343}
344
345QT_DEFINE_QPA_EVENT_HANDLER(bool, handlePaintEvent, QWindow *window, const QRegion &region)
346{
347 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::PaintEvent, Delivery>(window,
348 QHighDpi::fromNativeLocalExposedRegion(region, window));
349}
350
351
352QT_DEFINE_QPA_EVENT_HANDLER(bool, handleCloseEvent, QWindow *window)
353{
354 Q_ASSERT(window);
355 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::CloseEvent, Delivery>(window);
356}
357
358/*!
359
360\a w == 0 means that the event is in global coords only, \a local will be ignored in this case
361
362*/
363
364QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window,
365 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
366 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
367 Qt::MouseEventSource source)
368{
369 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
370 return handleMouseEvent<Delivery>(window, time, local, global, state, button, type, mods, source);
371}
372
373QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, const QPointingDevice *device,
374 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
375 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
376 Qt::MouseEventSource source)
377{
378 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
379 return handleMouseEvent<Delivery>(window, time, device, local, global, state, button, type, mods, source);
380}
381
382QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, ulong timestamp,
383 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
384 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
385 Qt::MouseEventSource source)
386{
387 return handleMouseEvent<Delivery>(window, timestamp, QPointingDevice::primaryPointingDevice(),
388 local, global, state, button, type, mods, source);
389}
390
391QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
392 const QPointF &local, const QPointF &global, Qt::MouseButtons state,
393 Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
394 Qt::MouseEventSource source)
395{
396
397 bool isNonClientArea = {};
398
399 switch (type) {
400 case QEvent::MouseButtonDblClick:
401 case QEvent::NonClientAreaMouseButtonDblClick:
402 Q_ASSERT_X(false, "QWindowSystemInterface::handleMouseEvent",
403 "QTBUG-71263: Native double clicks are not implemented.");
404 return false;
405 case QEvent::MouseMove:
406 case QEvent::MouseButtonPress:
407 case QEvent::MouseButtonRelease:
408 isNonClientArea = false;
409 break;
410 case QEvent::NonClientAreaMouseMove:
411 case QEvent::NonClientAreaMouseButtonPress:
412 case QEvent::NonClientAreaMouseButtonRelease:
413 isNonClientArea = true;
414 break;
415 default:
416 Q_UNREACHABLE();
417 }
418
419 auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
420 auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
421
422 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::MouseEvent, Delivery>(window,
423 timestamp, localPos, globalPos, state, mods, button, type, source, isNonClientArea, device);
424}
425
426bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestamp, int keyCode, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode,
427 quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text, bool autorepeat, ushort count)
428{
429#if QT_CONFIG(shortcut)
430 if (!window)
431 window = QGuiApplication::focusWindow();
432
433 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
434 if (shortcutMap.state() == QKeySequence::NoMatch) {
435 // Check if the shortcut is overridden by some object in the event delivery path (typically the focus object).
436 // If so, we should not look up the shortcut in the shortcut map, but instead deliver the event as a regular
437 // key event, so that the target that accepted the shortcut override event can handle it. Note that we only
438 // do this if the shortcut map hasn't found a partial shortcut match yet. If it has, the shortcut can not be
439 // overridden.
440 bool overridden = handleWindowSystemEvent<QWindowSystemInterfacePrivate::KeyEvent, SynchronousDelivery>
441 (window,timestamp, QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode,
442 nativeVirtualKey, nativeModifiers, text, autorepeat, count);
443 if (overridden)
444 return false;
445 }
446
447 // The shortcut event is dispatched as a QShortcutEvent, not a QKeyEvent, but we use
448 // the QKeyEvent as a container for the various properties that the shortcut map needs
449 // to inspect to determine if a shortcut matched the keys that were pressed.
450 QKeyEvent keyEvent(QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode,
451 nativeVirtualKey, nativeModifiers, text, autorepeat, count);
452
453 return shortcutMap.tryShortcut(&keyEvent);
454#else
455 Q_UNUSED(window);
456 Q_UNUSED(timestamp);
457 Q_UNUSED(keyCode);
458 Q_UNUSED(modifiers);
459 Q_UNUSED(nativeScanCode);
460 Q_UNUSED(nativeVirtualKey);
461 Q_UNUSED(nativeModifiers);
462 Q_UNUSED(text);
463 Q_UNUSED(autorepeat);
464 Q_UNUSED(count);
465 return false;
466#endif
467}
468
469QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) {
470 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
471 return handleKeyEvent<Delivery>(window, time, t, k, mods, text, autorep, count);
472}
473
474QT_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)
475{
476 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::KeyEvent, Delivery>(window,
477 timestamp, t, k, mods, text, autorep, count);
478}
479
480bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
481 quint32 nativeScanCode, quint32 nativeVirtualKey,
482 quint32 nativeModifiers,
483 const QString& text, bool autorep,
484 ushort count)
485{
486 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
487 return handleExtendedKeyEvent(window, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
488 text, autorep, count);
489}
490
491bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
492 Qt::KeyboardModifiers modifiers,
493 quint32 nativeScanCode, quint32 nativeVirtualKey,
494 quint32 nativeModifiers,
495 const QString& text, bool autorep,
496 ushort count)
497{
498 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::KeyEvent>(window,
499 timestamp, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
500}
501
502bool QWindowSystemInterface::handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource source)
503{
504 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
505 return handleWheelEvent(window, time, local, global, pixelDelta, angleDelta, mods, phase, source);
506}
507
508bool QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
509 Qt::MouseEventSource source, bool invertedScrolling)
510{
511 return handleWheelEvent(window, timestamp, QPointingDevice::primaryPointingDevice(), local, global,
512 pixelDelta, angleDelta, mods, phase, source, invertedScrolling);
513}
514
515bool QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
516 const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta,
517 Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
518 Qt::MouseEventSource source, bool invertedScrolling)
519{
520 // Qt 4 sends two separate wheel events for horizontal and vertical
521 // deltas. For Qt 5 we want to send the deltas in one event, but at the
522 // same time preserve source and behavior compatibility with Qt 4.
523 //
524 // In addition high-resolution pixel-based deltas are also supported.
525 // Platforms that does not support these may pass a null point here.
526 // Angle deltas must always be sent in addition to pixel deltas.
527
528 // Pass Qt::ScrollBegin and Qt::ScrollEnd through
529 // even if the wheel delta is null.
530 if (angleDelta.isNull() && phase == Qt::ScrollUpdate)
531 return false;
532
533 // Simple case: vertical deltas only:
534 if (angleDelta.y() != 0 && angleDelta.x() == 0) {
535 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
536 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
537 pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling, device);
538 }
539
540 // Simple case: horizontal deltas only:
541 if (angleDelta.y() == 0 && angleDelta.x() != 0) {
542 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
543 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
544 pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling, device);
545 }
546
547 bool acceptVert;
548 bool acceptHorz;
549 // Both horizontal and vertical deltas: Send two wheel events.
550 // The first event contains the Qt 5 pixel and angle delta as points,
551 // and in addition the Qt 4 compatibility vertical angle delta.
552 acceptVert = handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
553 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
554 pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling, device);
555
556 // The second event contains null pixel and angle points and the
557 // Qt 4 compatibility horizontal angle delta.
558 acceptHorz = handleWindowSystemEvent<QWindowSystemInterfacePrivate::WheelEvent>(window,
559 timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativeGlobalPosition(global, window),
560 QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling, device);
561
562 return acceptVert || acceptHorz;
563}
564
565/*!
566 \internal
567 Register a new input \a device.
568
569 It is expected that every platform plugin will discover available input
570 devices at startup, and whenever a new device is plugged in, if possible.
571 If that's not possible, then it at least must call this function before
572 sending an event whose QInputEvent::source() is this device.
573
574 When a device is unplugged, the platform plugin should destroy the
575 corresponding QInputDevice instance. There is no unregisterInputDevice()
576 function, because it's enough for the destructor to call
577 QInputDevicePrivate::unregisterDevice(); while other parts of Qt can
578 connect to the QObject::destroyed() signal to be notified when a device is
579 unplugged or otherwise destroyed.
580*/
581void QWindowSystemInterface::registerInputDevice(const QInputDevice *device)
582{
583 QInputDevicePrivate::registerDevice(device);
584}
585
586/*!
587 \internal
588 Convert a list of \l QWindowSystemInterface::TouchPoint \a points to a list
589 of \e temporary QEventPoint instances, scaled (but not localized)
590 for delivery to the given \a window.
591
592 This is called from QWindowSystemInterface::handleTouchEvent():
593 that is too early to update the QEventPoint instances in QPointingDevice,
594 because we want those to hold "current" state from the applcation's
595 point of view. The QWindowSystemInterfacePrivate::TouchEvent, to which
596 the returned touchpoints will "belong", might go through the queue before
597 being processed; the application doesn't see the equivalent QTouchEvent
598 until later on. Therefore the responsibility to update the QEventPoint
599 instances in QPointingDevice is in QGuiApplication, not here.
600
601 QGuiApplicationPrivate::processMouseEvent() also calls this function
602 when it synthesizes a touch event from a mouse event. But that's outside
603 the normal use case.
604
605 It might be better if we change all the platform plugins to create
606 temporary instances of QEventPoint directly, and remove
607 QWindowSystemInterface::TouchPoint completely. Then we will no longer need
608 this function either. But that's only possible as long as QEventPoint
609 remains a Q_GADGET, not a QObject, so that it continues to be small and
610 suitable for temporary stack allocation. QEventPoint is a little bigger
611 than QWindowSystemInterface::TouchPoint, though.
612*/
613QList<QEventPoint>
614 QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
615 const QWindow *window, QEvent::Type *type)
616{
617 QList<QEventPoint> touchPoints;
618 QEventPoint::States states;
619
620 touchPoints.reserve(points.size());
621 QList<QWindowSystemInterface::TouchPoint>::const_iterator point = points.constBegin();
622 QList<QWindowSystemInterface::TouchPoint>::const_iterator end = points.constEnd();
623 while (point != end) {
624 QPointF globalPos = QHighDpi::fromNativePixels(point->area.center(), window);
625 QEventPoint p(point->id, point->state, globalPos, globalPos);
626 states |= point->state;
627 if (point->uniqueId >= 0)
628 QMutableEventPoint::setUniqueId(p, QPointingDeviceUniqueId::fromNumericId(point->uniqueId));
629 QMutableEventPoint::setPressure(p, point->pressure);
630 QMutableEventPoint::setRotation(p, point->rotation);
631 QMutableEventPoint::setEllipseDiameters(p, QHighDpi::fromNativePixels(point->area.size(), window));
632 QMutableEventPoint::setVelocity(p, QHighDpi::fromNativePixels(point->velocity, window));
633
634 // The local pos is not set: it will be calculated
635 // when the event gets processed by QGuiApplication.
636
637 touchPoints.append(p);
638 ++point;
639 }
640
641 // Determine the event type based on the combined point states.
642 if (type) {
643 *type = QEvent::TouchUpdate;
644 if (states == QEventPoint::State::Pressed)
645 *type = QEvent::TouchBegin;
646 else if (states == QEventPoint::State::Released)
647 *type = QEvent::TouchEnd;
648 }
649
650 return touchPoints;
651}
652
653QWindowSystemInterface::TouchPoint
654QWindowSystemInterfacePrivate::toNativeTouchPoint(const QEventPoint &pt, const QWindow *window)
655{
656 QWindowSystemInterface::TouchPoint p;
657 p.id = pt.id();
658 QRectF area(QPointF(), pt.ellipseDiameters());
659 area.moveCenter(pt.globalPosition());
660 // TODO store ellipseDiameters in QWindowSystemInterface::TouchPoint or just use QEventPoint
661 p.area = QHighDpi::toNativePixels(area, window);
662 p.pressure = pt.pressure();
663 p.state = pt.state();
664 p.velocity = QHighDpi::toNativePixels(pt.velocity(), window);
665 return p;
666}
667
668QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchEvent, QWindow *window, const QPointingDevice *device,
669 const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
670{
671 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
672 return handleTouchEvent<Delivery>(window, time, device, points, mods);
673}
674
675QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
676 const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
677{
678 if (!points.size()) // Touch events must have at least one point
679 return false;
680
681 if (!QPointingDevicePrivate::isRegistered(device)) // Disallow passing bogus, non-registered devices.
682 return false;
683
684 QEvent::Type type;
685 QList<QEventPoint> touchPoints =
686 QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
687
688 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TouchEvent, Delivery>(window,
689 timestamp, type, device, touchPoints, mods);
690}
691
692QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, const QPointingDevice *device,
693 Qt::KeyboardModifiers mods)
694{
695 unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
696 return handleTouchCancelEvent<Delivery>(window, time, device, mods);
697}
698
699QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, ulong timestamp, const QPointingDevice *device,
700 Qt::KeyboardModifiers mods)
701{
702 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TouchEvent, Delivery>(window,
703 timestamp, QEvent::TouchCancel, device, QList<QEventPoint>(), mods);
704}
705
706/*!
707 Should be called by the implementation whenever a new screen is added.
708
709 The first screen added will be the primary screen, used for default-created
710 windows, GL contexts, and other resources unless otherwise specified.
711
712 This adds the screen to QGuiApplication::screens(), and emits the
713 QGuiApplication::screenAdded() signal.
714
715 The screen should be deleted by calling QWindowSystemInterface::handleScreenRemoved().
716*/
717void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *platformScreen, bool isPrimary)
718{
719 QScreen *screen = new QScreen(platformScreen);
720
721 if (isPrimary)
722 QGuiApplicationPrivate::screen_list.prepend(screen);
723 else
724 QGuiApplicationPrivate::screen_list.append(screen);
725
726 QGuiApplicationPrivate::resetCachedDevicePixelRatio();
727 QHighDpiScaling::updateHighDpiScaling();
728 screen->d_func()->updateGeometry();
729
730 emit qGuiApp->screenAdded(screen);
731
732 if (isPrimary)
733 emit qGuiApp->primaryScreenChanged(screen);
734}
735
736/*!
737 Should be called by the implementation whenever a screen is removed.
738
739 This removes the screen from QGuiApplication::screens(), and deletes it.
740
741 Failing to call this and manually deleting the QPlatformScreen instead may
742 lead to a crash due to a pure virtual call.
743*/
744void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen)
745{
746 QScreen *screen = platformScreen->screen();
747
748 // Remove screen
749 const bool wasPrimary = QGuiApplication::primaryScreen() == screen;
750 QGuiApplicationPrivate::screen_list.removeOne(screen);
751 QGuiApplicationPrivate::resetCachedDevicePixelRatio();
752
753 if (qGuiApp) {
754 QScreen *newPrimaryScreen = QGuiApplication::primaryScreen();
755 if (wasPrimary && newPrimaryScreen)
756 emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
757
758 // Allow clients to manage windows that are affected by the screen going
759 // away, before we fall back to moving them to the primary screen.
760 emit qApp->screenRemoved(screen);
761
762 if (!QGuiApplication::closingDown()) {
763 bool movingFromVirtualSibling = newPrimaryScreen
764 && newPrimaryScreen->handle()->virtualSiblings().contains(platformScreen);
765
766 // Move any leftover windows to the primary screen
767 const auto allWindows = QGuiApplication::allWindows();
768 for (QWindow *window : allWindows) {
769 if (!window->isTopLevel() || window->screen() != screen)
770 continue;
771
772 const bool wasVisible = window->isVisible();
773 window->setScreen(newPrimaryScreen);
774
775 // Re-show window if moved from a virtual sibling screen. Otherwise
776 // leave it up to the application developer to show the window.
777 if (movingFromVirtualSibling)
778 window->setVisible(wasVisible);
779 }
780 }
781 }
782
783 // Important to keep this order since the QSceen doesn't own the platform screen
784 delete screen;
785 delete platformScreen;
786}
787
788/*!
789 Should be called whenever the primary screen changes.
790
791 When the screen specified as primary changes, this method will notify
792 QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal.
793 */
794void QWindowSystemInterface::handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
795{
796 QScreen *newPrimaryScreen = newPrimary->screen();
797 qsizetype indexOfScreen = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen);
798 Q_ASSERT(indexOfScreen >= 0);
799 if (indexOfScreen == 0)
800 return;
801
802 QGuiApplicationPrivate::screen_list.swapItemsAt(0, indexOfScreen);
803 emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
804}
805
806void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation orientation)
807{
808 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenOrientationEvent>(screen, orientation);
809}
810
811void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry)
812{
813 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenGeometryEvent>(screen,
814 QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry,
815 screen, geometry.topLeft()));
816}
817
818void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY)
819{
820 // Keep QHighDpiScaling::m_active in sync with platform screen state, in
821 // order to make scaling calls made during DPI change use the new state.
822 // FIXME: Remove when QHighDpiScaling::m_active has been removed.
823 QHighDpiScaling::updateHighDpiScaling();
824
825 const QDpi effectiveDpi = QPlatformScreen::overrideDpi(QDpi{dpiX, dpiY});
826 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent>(screen,
827 effectiveDpi.first, effectiveDpi.second);
828}
829
830void QWindowSystemInterface::handleScreenRefreshRateChange(QScreen *screen, qreal newRefreshRate)
831{
832 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent>(screen, newRefreshRate);
833}
834
835QT_DEFINE_QPA_EVENT_HANDLER(void, handleThemeChange)
836{
837 handleWindowSystemEvent<QWindowSystemInterfacePrivate::ThemeChangeEvent, Delivery>();
838}
839
840#if QT_CONFIG(draganddrop)
841/*!
842 Drag and drop events are sent immediately.
843
844 ### FIXME? Perhaps DnD API should add some convenience APIs that are more
845 intuitive for the possible DND operations. Here passing nullptr as drop data is used to
846 indicate that drop was canceled and QDragLeaveEvent should be sent as a result.
847*/
848QPlatformDragQtResponse QWindowSystemInterface::handleDrag(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(p, window);
853 return QGuiApplicationPrivate::processDrag(window, dropData, pos, supportedActions, buttons, modifiers);
854}
855
856QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData,
857 const QPoint &p, Qt::DropActions supportedActions,
858 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
859{
860 auto pos = QHighDpi::fromNativeLocalPosition(p, window);
861 return QGuiApplicationPrivate::processDrop(window, dropData, pos, supportedActions, buttons, modifiers);
862}
863#endif // QT_CONFIG(draganddrop)
864
865/*!
866 \fn static QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
867 \brief Passes a native event identified by \a eventType to the \a window.
868
869 \note This function can only be called from the GUI thread.
870*/
871
872bool QWindowSystemInterface::handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
873{
874 return QGuiApplicationPrivate::processNativeEvent(window, eventType, message, result);
875}
876
877void QWindowSystemInterface::handleFileOpenEvent(const QString& fileName)
878{
879 QWindowSystemInterfacePrivate::FileOpenEvent e(fileName);
880 QGuiApplicationPrivate::processWindowSystemEvent(&e);
881}
882
883void QWindowSystemInterface::handleFileOpenEvent(const QUrl &url)
884{
885 QWindowSystemInterfacePrivate::FileOpenEvent e(url);
886 QGuiApplicationPrivate::processWindowSystemEvent(&e);
887}
888
889void QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(bool v)
890{
891 platformSynthesizesMouse = v;
892}
893
894bool QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
895 const QPointF &local, const QPointF &global,
896 Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
897 qreal tangentialPressure, qreal rotation, int z,
898 Qt::KeyboardModifiers modifiers)
899{
900 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEvent>(window,
901 timestamp,
902 QHighDpi::fromNativeLocalPosition(local, window),
903 QHighDpi::fromNativeGlobalPosition(global, window),
904 device, buttons, pressure,
905 xTilt, yTilt, tangentialPressure, rotation, z, modifiers);
906}
907
908bool QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointingDevice *device,
909 const QPointF &local, const QPointF &global,
910 Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
911 qreal tangentialPressure, qreal rotation, int z,
912 Qt::KeyboardModifiers modifiers)
913{
914 const ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
915 return handleTabletEvent(window, time, device, local, global,
916 buttons, pressure, xTilt, yTilt, tangentialPressure,
917 rotation, z, modifiers);
918}
919
920bool QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global,
921 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
922 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
923 Qt::KeyboardModifiers modifiers)
924{
925 const QPointingDevice *dev = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(device),QPointingDevice::PointerType(pointerType),
926 QPointingDeviceUniqueId::fromNumericId(uid));
927 return handleTabletEvent(window, timestamp, dev, local, global, buttons, pressure,
928 xTilt, yTilt, tangentialPressure, rotation, z, modifiers);
929}
930
931bool QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
932 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, qreal xTilt, qreal yTilt,
933 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
934 Qt::KeyboardModifiers modifiers)
935{
936 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
937 return handleTabletEvent(window, time, local, global, device, pointerType, buttons, pressure,
938 xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
939}
940
941bool QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
942 bool inProximity, const QPointF &local, const QPointF &global,
943 Qt::MouseButtons buttons, qreal xTilt, qreal yTilt,
944 qreal tangentialPressure, qreal rotation, int z,
945 Qt::KeyboardModifiers modifiers)
946{
947 Q_UNUSED(window);
948 Q_UNUSED(local);
949 Q_UNUSED(global);
950 Q_UNUSED(buttons);
951 Q_UNUSED(xTilt);
952 Q_UNUSED(yTilt);
953 Q_UNUSED(tangentialPressure);
954 Q_UNUSED(rotation);
955 Q_UNUSED(z);
956 Q_UNUSED(modifiers);
957 return inProximity
958 ? handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEnterProximityEvent>(timestamp, device)
959 : handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent>(timestamp, device);
960}
961
962bool QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(QWindow *window, const QPointingDevice *device,
963 bool inProximity, const QPointF &local, const QPointF &global,
964 Qt::MouseButtons buttons, qreal xTilt, qreal yTilt,
965 qreal tangentialPressure, qreal rotation, int z,
966 Qt::KeyboardModifiers modifiers)
967{
968 const ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
969 return handleTabletEnterLeaveProximityEvent(window, time, device, inProximity,
970 local, global, buttons, xTilt, yTilt,
971 tangentialPressure, rotation, z, modifiers);
972}
973
974
975bool QWindowSystemInterface::handleTabletEnterProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
976{
977 const QPointingDevice *device = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(deviceType),
978 QPointingDevice::PointerType(pointerType),
979 QPointingDeviceUniqueId::fromNumericId(uid));
980 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletEnterProximityEvent>(timestamp, device);
981}
982
983void QWindowSystemInterface::handleTabletEnterProximityEvent(int deviceType, int pointerType, qint64 uid)
984{
985 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
986 handleTabletEnterProximityEvent(time, deviceType, pointerType, uid);
987}
988
989bool QWindowSystemInterface::handleTabletLeaveProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid)
990{
991 const QPointingDevice *device = QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType(deviceType),
992 QPointingDevice::PointerType(pointerType),
993 QPointingDeviceUniqueId::fromNumericId(uid));
994 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent>(timestamp, device);
995}
996
997void QWindowSystemInterface::handleTabletLeaveProximityEvent(int deviceType, int pointerType, qint64 uid)
998{
999 ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
1000 handleTabletLeaveProximityEvent(time, deviceType, pointerType, uid);
1001}
1002
1003#ifndef QT_NO_GESTURES
1004bool QWindowSystemInterface::handleGestureEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
1005 Qt::NativeGestureType type, const QPointF &local, const QPointF &global, int fingerCount)
1006{
1007 return handleGestureEventWithValueAndDelta(window, timestamp, device, type, {}, {}, local, global, fingerCount);
1008}
1009
1010bool QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, ulong timestamp, const QPointingDevice *device,
1011 Qt::NativeGestureType type, qreal value, const QPointF &local, const QPointF &global, int fingerCount)
1012{
1013 return handleGestureEventWithValueAndDelta(window, timestamp, device, type, value, {}, local, global, fingerCount);
1014}
1015
1016bool QWindowSystemInterface::handleGestureEventWithValueAndDelta(QWindow *window, ulong timestamp, const QPointingDevice *device,
1017 Qt::NativeGestureType type, qreal value, const QPointF &delta,
1018 const QPointF &local, const QPointF &global, int fingerCount)
1019{
1020 auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
1021 auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
1022
1023 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::GestureEvent>(window,
1024 timestamp, type, device, fingerCount, localPos, globalPos, value, delta);
1025}
1026#endif // QT_NO_GESTURES
1027
1028void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w)
1029{
1030 handleWindowSystemEvent<QWindowSystemInterfacePrivate::PlatformPanelEvent>(w);
1031}
1032
1033#ifndef QT_NO_CONTEXTMENU
1034QT_DEFINE_QPA_EVENT_HANDLER(bool, handleContextMenuEvent, QWindow *window, bool mouseTriggered,
1035 const QPoint &pos, const QPoint &globalPos,
1036 Qt::KeyboardModifiers modifiers)
1037{
1038 return handleWindowSystemEvent<QWindowSystemInterfacePrivate::ContextMenuEvent, Delivery>(
1039 window, mouseTriggered, pos, globalPos, modifiers);
1040}
1041#endif
1042
1043#if QT_CONFIG(whatsthis)
1044void QWindowSystemInterface::handleEnterWhatsThisEvent()
1045{
1046 handleWindowSystemEvent<QWindowSystemInterfacePrivate::WindowSystemEvent>(
1047 QWindowSystemInterfacePrivate::EnterWhatsThisMode);
1048}
1049#endif
1050
1051#ifndef QT_NO_DEBUG_STREAM
1052Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPoint &p)
1053{
1054 QDebugStateSaver saver(dbg);
1055 dbg.nospace() << "TouchPoint(" << p.id << " @" << p.area << " normalized " << p.normalPosition
1056 << " press " << p.pressure << " vel " << p.velocity << " state " << (int)p.state;
1057 return dbg;
1058}
1059#endif
1060
1061// ------------------ Event dispatcher functionality ------------------
1062
1063/*!
1064 Make Qt Gui process all events on the event queue immediately. Return the
1065 accepted state for the last event on the queue.
1066*/
1067bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1068{
1069 const qsizetype count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
1070 if (!count)
1071 return false;
1072 if (!QGuiApplication::instance()) {
1073 qWarning().nospace()
1074 << "QWindowSystemInterface::flushWindowSystemEvents() invoked after "
1075 "QGuiApplication destruction, discarding " << count << " events.";
1076 QWindowSystemInterfacePrivate::windowSystemEventQueue.clear();
1077 return false;
1078 }
1079 if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
1080 // Post a FlushEvents event which will trigger a call back to
1081 // deferredFlushWindowSystemEvents from the Gui thread.
1082 QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
1083 handleWindowSystemEvent<QWindowSystemInterfacePrivate::FlushEventsEvent, AsynchronousDelivery>(flags);
1084 QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex);
1085 } else {
1086 sendWindowSystemEvents(flags);
1087 }
1088 return QWindowSystemInterfacePrivate::eventAccepted.loadRelaxed() > 0;
1089}
1090
1091void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1092{
1093 Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread());
1094
1095 QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
1096 sendWindowSystemEvents(flags);
1097 QWindowSystemInterfacePrivate::eventsFlushed.wakeOne();
1098}
1099
1100bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
1101{
1102 int nevents = 0;
1103
1104 while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
1105 QWindowSystemInterfacePrivate::WindowSystemEvent *event =
1106 flags & QEventLoop::ExcludeUserInputEvents ?
1107 QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
1108 QWindowSystemInterfacePrivate::getWindowSystemEvent();
1109 if (!event)
1110 break;
1111
1112 if (QWindowSystemInterfacePrivate::eventHandler) {
1113 if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
1114 nevents++;
1115 } else {
1116 nevents++;
1117 QGuiApplicationPrivate::processWindowSystemEvent(event);
1118 }
1119
1120 // Record the accepted state for the processed event
1121 // (excluding flush events). This state can then be
1122 // returned by flushWindowSystemEvents().
1123 if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
1124 QWindowSystemInterfacePrivate::eventAccepted.storeRelaxed(event->eventAccepted);
1125
1126 delete event;
1127 }
1128
1129 return (nevents > 0);
1130}
1131
1132void QWindowSystemInterface::setSynchronousWindowSystemEvents(bool enable)
1133{
1134 QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = enable;
1135}
1136
1137int QWindowSystemInterface::windowSystemEventsQueued()
1138{
1139 return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
1140}
1141
1142bool QWindowSystemInterface::nonUserInputEventsQueued()
1143{
1144 return QWindowSystemInterfacePrivate::nonUserInputEventsQueued();
1145}
1146
1147// --------------------- QtTestLib support ---------------------
1148
1149// The following functions are used by testlib, and need to be synchronous to avoid
1150// race conditions with plugins delivering native events from secondary threads.
1151// FIXME: It seems unnecessary to export these wrapper functions, when qtestlib could access
1152// QWindowSystemInterface directly (by adding dependency to gui-private), see QTBUG-63146.
1153
1154Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global,
1155 Qt::MouseButtons state, Qt::MouseButton button,
1156 QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp)
1157{
1158 QPointF nativeLocal = QHighDpi::toNativeLocalPosition(local, window);
1159 QPointF nativeGlobal = QHighDpi::toNativeGlobalPosition(global, window);
1160 QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window,
1161 timestamp, nativeLocal, nativeGlobal, state, button, type, mods);
1162}
1163
1164/*
1165 Used by QTest::simulateEvent() to synthesize key events during testing
1166*/
1167Q_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)
1168{
1169#if defined(Q_OS_MACOS)
1170 // FIXME: Move into QTest::simulateEvent() and align with QGuiApplicationPrivate::processKeyEvent()
1171 auto timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed();
1172 if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, k, mods, 0, 0, 0, text, autorep, count))
1173 return;
1174#endif
1175
1176 QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(window, t, k, mods, text, autorep, count);
1177}
1178
1179Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1)
1180{
1181#if QT_CONFIG(shortcut)
1182
1183 // FIXME: This method should not allow targeting a specific object, but should
1184 // instead forward the event to a window, which then takes care of normal event
1185 // propagation. We need to fix a lot of tests before we can refactor this (the
1186 // window needs to be exposed and active and have a focus object), so we leave
1187 // it as is for now. See QTBUG-48577.
1188
1189 QGuiApplicationPrivate::modifier_buttons = mods;
1190
1191 QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count);
1192 qevent.setTimestamp(timestamp);
1193
1194 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
1195 if (shortcutMap.state() == QKeySequence::NoMatch) {
1196 // Try sending as QKeyEvent::ShortcutOverride first
1197 QCoreApplication::sendEvent(o, &qevent);
1198 if (qevent.isAccepted())
1199 return false;
1200 }
1201
1202 // Then as QShortcutEvent
1203 return shortcutMap.tryShortcut(&qevent);
1204#else
1205 Q_UNUSED(o);
1206 Q_UNUSED(timestamp);
1207 Q_UNUSED(k);
1208 Q_UNUSED(mods);
1209 Q_UNUSED(text);
1210 Q_UNUSED(autorep);
1211 Q_UNUSED(count);
1212 return false;
1213#endif
1214}
1215
1216Q_GUI_EXPORT void qt_handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global,
1217 QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods,
1218 Qt::ScrollPhase phase)
1219{
1220 QWindowSystemInterface::handleWheelEvent(window, local, global, pixelDelta, angleDelta, mods, phase);
1221}
1222
1223namespace QTest
1224{
1225 Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType,
1227 {
1228 static qint64 nextId = 0x100000000;
1229 QPointingDevice *ret = new QPointingDevice("test touch device"_L1, nextId++,
1231 caps, 8, 0);
1233 return ret;
1234 }
1235}
1236
1237Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *window, const QPointingDevice *device,
1238 const QList<QEventPoint> &points,
1239 Qt::KeyboardModifiers mods)
1240{
1241 return QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window, device,
1242 QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window), mods);
1243}
1244
1245Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *window, const QPointingDevice *device,
1246 const QList<QEventPoint> &points,
1247 Qt::KeyboardModifiers mods)
1248{
1249 qt_handleTouchEventv2(window, device, points, mods);
1250}
1251
1252QT_END_NAMESPACE
Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2568
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 ...)