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