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