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

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