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#ifndef QWINDOWSYSTEMINTERFACE_P_H
40#define QWINDOWSYSTEMINTERFACE_P_H
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists purely as an
47// implementation detail. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51//
52
53#include <QtGui/private/qevent_p.h>
54#include <QtGui/private/qtguiglobal_p.h>
55#include "qwindowsysteminterface.h"
56
57#include <QElapsedTimer>
58#include <QPointer>
59#include <QMutex>
60#include <QList>
61#include <QWaitCondition>
62#include <QAtomicInt>
63
64QT_BEGIN_NAMESPACE
65
66class QWindowSystemEventHandler;
67
68class Q_GUI_EXPORT QWindowSystemInterfacePrivate {
69public:
70 enum EventType {
71 UserInputEvent = 0x100,
72 Close = UserInputEvent | 0x01,
73 GeometryChange = 0x02,
74 Enter = UserInputEvent | 0x03,
75 Leave = UserInputEvent | 0x04,
76 ActivatedWindow = 0x05,
77 WindowStateChanged = 0x06,
78 Mouse = UserInputEvent | 0x07,
79 Wheel = UserInputEvent | 0x09,
80 Key = UserInputEvent | 0x0a,
81 Touch = UserInputEvent | 0x0b,
82 ScreenOrientation = 0x0c,
83 ScreenGeometry = 0x0d,
84 ScreenAvailableGeometry = 0x0e,
85 ScreenLogicalDotsPerInch = 0x0f,
86 ScreenRefreshRate = 0x10,
87 ThemeChange = 0x11,
88 Expose = 0x12,
89 FileOpen = UserInputEvent | 0x13,
90 Tablet = UserInputEvent | 0x14,
91 TabletEnterProximity = UserInputEvent | 0x15,
92 TabletLeaveProximity = UserInputEvent | 0x16,
93 PlatformPanel = UserInputEvent | 0x17,
94 ContextMenu = UserInputEvent | 0x18,
95 EnterWhatsThisMode = UserInputEvent | 0x19,
96#ifndef QT_NO_GESTURES
97 Gesture = UserInputEvent | 0x1a,
98#endif
99 ApplicationStateChanged = 0x19,
100 FlushEvents = 0x20,
101 WindowScreenChanged = 0x21,
102 SafeAreaMarginsChanged = 0x22,
103 ApplicationTermination = 0x23,
104 Paint = 0x24
105 };
106
107 class WindowSystemEvent {
108 public:
109 enum {
110 Synthetic = 0x1,
111 NullWindow = 0x2
112 };
113
114 explicit WindowSystemEvent(EventType t)
115 : type(t), flags(0), eventAccepted(true) { }
116 virtual ~WindowSystemEvent() { }
117
118 bool synthetic() const { return flags & Synthetic; }
119 bool nullWindow() const { return flags & NullWindow; }
120
121 EventType type;
122 int flags;
123 bool eventAccepted;
124 };
125
126 class CloseEvent : public WindowSystemEvent {
127 public:
128 explicit CloseEvent(QWindow *w)
129 : WindowSystemEvent(Close), window(w)
130 { }
131 QPointer<QWindow> window;
132 };
133
134 class GeometryChangeEvent : public WindowSystemEvent {
135 public:
136 GeometryChangeEvent(QWindow *window, const QRect &newGeometry);
137 QPointer<QWindow> window;
138 QRect requestedGeometry;
139 QRect newGeometry;
140 };
141
142 class EnterEvent : public WindowSystemEvent {
143 public:
144 explicit EnterEvent(QWindow *enter, const QPointF &local, const QPointF &global)
145 : WindowSystemEvent(Enter), enter(enter), localPos(local), globalPos(global)
146 { }
147 QPointer<QWindow> enter;
148 const QPointF localPos;
149 const QPointF globalPos;
150 };
151
152 class LeaveEvent : public WindowSystemEvent {
153 public:
154 explicit LeaveEvent(QWindow *leave)
155 : WindowSystemEvent(Leave), leave(leave)
156 { }
157 QPointer<QWindow> leave;
158 };
159
160 class ActivatedWindowEvent : public WindowSystemEvent {
161 public:
162 explicit ActivatedWindowEvent(QWindow *activatedWindow, Qt::FocusReason r)
163 : WindowSystemEvent(ActivatedWindow), activated(activatedWindow), reason(r)
164 { }
165 QPointer<QWindow> activated;
166 Qt::FocusReason reason;
167 };
168
169 class WindowStateChangedEvent : public WindowSystemEvent {
170 public:
171 WindowStateChangedEvent(QWindow *_window, Qt::WindowStates _newState, Qt::WindowStates _oldState)
172 : WindowSystemEvent(WindowStateChanged), window(_window), newState(_newState), oldState(_oldState)
173 { }
174
175 QPointer<QWindow> window;
176 Qt::WindowStates newState;
177 Qt::WindowStates oldState;
178 };
179
180 class WindowScreenChangedEvent : public WindowSystemEvent {
181 public:
182 WindowScreenChangedEvent(QWindow *w, QScreen *s)
183 : WindowSystemEvent(WindowScreenChanged), window(w), screen(s)
184 { }
185
186 QPointer<QWindow> window;
187 QPointer<QScreen> screen;
188 };
189
190 class SafeAreaMarginsChangedEvent : public WindowSystemEvent {
191 public:
192 SafeAreaMarginsChangedEvent(QWindow *w)
193 : WindowSystemEvent(SafeAreaMarginsChanged), window(w)
194 { }
195
196 QPointer<QWindow> window;
197 };
198
199 class ApplicationStateChangedEvent : public WindowSystemEvent {
200 public:
201 ApplicationStateChangedEvent(Qt::ApplicationState newState, bool forcePropagate = false)
202 : WindowSystemEvent(ApplicationStateChanged), newState(newState), forcePropagate(forcePropagate)
203 { }
204
205 Qt::ApplicationState newState;
206 bool forcePropagate;
207 };
208
209 class FlushEventsEvent : public WindowSystemEvent {
210 public:
211 FlushEventsEvent(QEventLoop::ProcessEventsFlags f = QEventLoop::AllEvents)
212 : WindowSystemEvent(FlushEvents)
213 , flags(f)
214 { }
215 QEventLoop::ProcessEventsFlags flags;
216 };
217
218 class UserEvent : public WindowSystemEvent {
219 public:
220 UserEvent(QWindow * w, ulong time, EventType t)
221 : WindowSystemEvent(t), window(w), timestamp(time)
222 {
223 if (!w)
224 flags |= NullWindow;
225 }
226 QPointer<QWindow> window;
227 unsigned long timestamp;
228 };
229
230 class InputEvent: public UserEvent {
231 public:
232 InputEvent(QWindow *w, ulong time, EventType t, Qt::KeyboardModifiers mods, const QInputDevice *dev)
233 : UserEvent(w, time, t), modifiers(mods), device(dev) {}
234 Qt::KeyboardModifiers modifiers;
235 const QInputDevice *device;
236 };
237
238 class PointerEvent : public InputEvent {
239 public:
240 PointerEvent(QWindow * w, ulong time, EventType t, Qt::KeyboardModifiers mods, const QPointingDevice *device)
241 : InputEvent(w, time, t, mods, device) {}
242 };
243
244 class MouseEvent : public PointerEvent {
245 public:
246 MouseEvent(QWindow *w, ulong time, const QPointF &local, const QPointF &global,
247 Qt::MouseButtons state, Qt::KeyboardModifiers mods,
248 Qt::MouseButton b, QEvent::Type type,
249 Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool frame = false,
250 const QPointingDevice *device = QPointingDevice::primaryPointingDevice())
251 : PointerEvent(w, time, Mouse, mods, device), localPos(local), globalPos(global),
252 buttons(state), source(src), nonClientArea(frame), button(b), buttonType(type) { }
253
254 // ### In Qt6 this method can be removed as there won't be need for compatibility code path
255 bool enhancedMouseEvent() const
256 {
257 static const bool disableEnhanced = qEnvironmentVariableIsSet("QT_QPA_DISABLE_ENHANCED_MOUSE");
258 return !disableEnhanced && buttonType != QEvent::None;
259 }
260
261 QPointF localPos;
262 QPointF globalPos;
263 Qt::MouseButtons buttons;
264 Qt::MouseEventSource source;
265 bool nonClientArea;
266 Qt::MouseButton button;
267 QEvent::Type buttonType;
268 };
269
270 class WheelEvent : public PointerEvent {
271 public:
272 WheelEvent(QWindow *w, ulong time, const QPointF &local, const QPointF &global, QPoint pixelD, QPoint angleD, int qt4D, Qt::Orientation qt4O,
273 Qt::KeyboardModifiers mods, Qt::ScrollPhase phase = Qt::NoScrollPhase, Qt::MouseEventSource src = Qt::MouseEventNotSynthesized,
274 bool inverted = false, const QPointingDevice *device = QPointingDevice::primaryPointingDevice())
275 : PointerEvent(w, time, Wheel, mods, device), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D),
276 qt4Orientation(qt4O), localPos(local), globalPos(global), phase(phase), source(src), inverted(inverted) { }
277 QPoint pixelDelta;
278 QPoint angleDelta;
279 int qt4Delta;
280 Qt::Orientation qt4Orientation;
281 QPointF localPos;
282 QPointF globalPos;
283 Qt::ScrollPhase phase;
284 Qt::MouseEventSource source;
285 bool inverted;
286 };
287
288 class KeyEvent : public InputEvent {
289 public:
290 KeyEvent(QWindow *w, ulong time, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(),
291 bool autorep = false, ushort count = 1, const QInputDevice *device = QInputDevice::primaryKeyboard())
292 : InputEvent(w, time, Key, mods, device), key(k), unicode(text), repeat(autorep),
293 repeatCount(count), keyType(t),
294 nativeScanCode(0), nativeVirtualKey(0), nativeModifiers(0) { }
295 KeyEvent(QWindow *w, ulong time, QEvent::Type t, int k, Qt::KeyboardModifiers mods,
296 quint32 nativeSC, quint32 nativeVK, quint32 nativeMods,
297 const QString & text = QString(), bool autorep = false, ushort count = 1, const QInputDevice *device = QInputDevice::primaryKeyboard())
298 : InputEvent(w, time, Key, mods, device), key(k), unicode(text), repeat(autorep),
299 repeatCount(count), keyType(t),
300 nativeScanCode(nativeSC), nativeVirtualKey(nativeVK), nativeModifiers(nativeMods) { }
301 const QInputDevice *source;
302 int key;
303 QString unicode;
304 bool repeat;
305 ushort repeatCount;
306 QEvent::Type keyType;
307 quint32 nativeScanCode;
308 quint32 nativeVirtualKey;
309 quint32 nativeModifiers;
310 };
311
312 class TouchEvent : public PointerEvent {
313 public:
314 TouchEvent(QWindow *w, ulong time, QEvent::Type t, const QPointingDevice *device,
315 const QList<QEventPoint> &p, Qt::KeyboardModifiers mods)
316 : PointerEvent(w, time, Touch, mods, device), points(p), touchType(t) { }
317 QList<QEventPoint> points;
318 QEvent::Type touchType;
319 };
320
321 class ScreenOrientationEvent : public WindowSystemEvent {
322 public:
323 ScreenOrientationEvent(QScreen *s, Qt::ScreenOrientation o)
324 : WindowSystemEvent(ScreenOrientation), screen(s), orientation(o) { }
325 QPointer<QScreen> screen;
326 Qt::ScreenOrientation orientation;
327 };
328
329 class ScreenGeometryEvent : public WindowSystemEvent {
330 public:
331 ScreenGeometryEvent(QScreen *s, const QRect &g, const QRect &ag)
332 : WindowSystemEvent(ScreenGeometry), screen(s), geometry(g), availableGeometry(ag) { }
333 QPointer<QScreen> screen;
334 QRect geometry;
335 QRect availableGeometry;
336 };
337
338 class ScreenLogicalDotsPerInchEvent : public WindowSystemEvent {
339 public:
340 ScreenLogicalDotsPerInchEvent(QScreen *s, qreal dx, qreal dy)
341 : WindowSystemEvent(ScreenLogicalDotsPerInch), screen(s), dpiX(dx), dpiY(dy) { }
342 QPointer<QScreen> screen;
343 qreal dpiX;
344 qreal dpiY;
345 };
346
347 class ScreenRefreshRateEvent : public WindowSystemEvent {
348 public:
349 ScreenRefreshRateEvent(QScreen *s, qreal r)
350 : WindowSystemEvent(ScreenRefreshRate), screen(s), rate(r) { }
351 QPointer<QScreen> screen;
352 qreal rate;
353 };
354
355 class ThemeChangeEvent : public WindowSystemEvent {
356 public:
357 explicit ThemeChangeEvent(QWindow * w)
358 : WindowSystemEvent(ThemeChange), window(w) { }
359 QPointer<QWindow> window;
360 };
361
362 class ExposeEvent : public WindowSystemEvent {
363 public:
364 ExposeEvent(QWindow *window, const QRegion &region);
365 QPointer<QWindow> window;
366 bool isExposed;
367 QRegion region;
368 };
369
370 class PaintEvent : public WindowSystemEvent {
371 public:
372 PaintEvent(QWindow *window, const QRegion &region)
373 : WindowSystemEvent(Paint), window(window), region(region) {}
374 QPointer<QWindow> window;
375 QRegion region;
376 };
377
378 class FileOpenEvent : public WindowSystemEvent {
379 public:
380 FileOpenEvent(const QString& fileName)
381 : WindowSystemEvent(FileOpen), url(QUrl::fromLocalFile(fileName))
382 { }
383 FileOpenEvent(const QUrl &url)
384 : WindowSystemEvent(FileOpen), url(url)
385 { }
386 QUrl url;
387 };
388
389 class Q_GUI_EXPORT TabletEvent : public PointerEvent {
390 public:
391 // TODO take QPointingDevice* instead of types and IDs
392 static void handleTabletEvent(QWindow *w, const QPointF &local, const QPointF &global,
393 int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
394 qreal tangentialPressure, qreal rotation, int z, qint64 uid,
395 Qt::KeyboardModifiers modifiers = Qt::NoModifier);
396 static void setPlatformSynthesizesMouse(bool v);
397
398 TabletEvent(QWindow *w, ulong time, const QPointF &local, const QPointF &global,
399 const QPointingDevice *device, Qt::MouseButtons b, qreal pressure, int xTilt, int yTilt, qreal tpressure,
400 qreal rotation, int z, Qt::KeyboardModifiers mods)
401 : PointerEvent(w, time, Tablet, mods, device),
402 buttons(b), local(local), global(global),
403 pressure(pressure), xTilt(xTilt), yTilt(yTilt), tangentialPressure(tpressure),
404 rotation(rotation), z(z) { }
405 Qt::MouseButtons buttons;
406 QPointF local;
407 QPointF global;
408 qreal pressure;
409 int xTilt;
410 int yTilt;
411 qreal tangentialPressure;
412 qreal rotation;
413 int z;
414 static bool platformSynthesizesMouse;
415 };
416
417 class TabletEnterProximityEvent : public PointerEvent {
418 public:
419 // TODO store more info: position and whatever else we can get on most platforms
420 TabletEnterProximityEvent(ulong time, const QPointingDevice *device)
421 : PointerEvent(nullptr, time, TabletEnterProximity, Qt::NoModifier, device) { }
422 };
423
424 class TabletLeaveProximityEvent : public PointerEvent {
425 public:
426 // TODO store more info: position and whatever else we can get on most platforms
427 TabletLeaveProximityEvent(ulong time, const QPointingDevice *device)
428 : PointerEvent(nullptr, time, TabletLeaveProximity, Qt::NoModifier, device) { }
429 };
430
431 class PlatformPanelEvent : public WindowSystemEvent {
432 public:
433 explicit PlatformPanelEvent(QWindow *w)
434 : WindowSystemEvent(PlatformPanel), window(w) { }
435 QPointer<QWindow> window;
436 };
437
438#ifndef QT_NO_CONTEXTMENU
439 class ContextMenuEvent : public WindowSystemEvent {
440 public:
441 explicit ContextMenuEvent(QWindow *w, bool mouseTriggered, const QPoint &pos,
442 const QPoint &globalPos, Qt::KeyboardModifiers modifiers)
443 : WindowSystemEvent(ContextMenu), window(w), mouseTriggered(mouseTriggered), pos(pos),
444 globalPos(globalPos), modifiers(modifiers) { }
445 QPointer<QWindow> window;
446 bool mouseTriggered;
447 QPoint pos; // Only valid if triggered by mouse
448 QPoint globalPos; // Only valid if triggered by mouse
449 Qt::KeyboardModifiers modifiers;
450 };
451#endif
452
453#ifndef QT_NO_GESTURES
454 class GestureEvent : public PointerEvent {
455 public:
456 GestureEvent(QWindow *window, ulong time, Qt::NativeGestureType type, const QPointingDevice *dev, QPointF pos, QPointF globalPos)
457 : PointerEvent(window, time, Gesture, Qt::NoModifier, dev), type(type), pos(pos), globalPos(globalPos),
458 realValue(0), sequenceId(0), intValue(0) { }
459 Qt::NativeGestureType type;
460 QPointF pos;
461 QPointF globalPos;
462 // Mac
463 qreal realValue;
464 // Windows
465 ulong sequenceId;
466 quint64 intValue;
467 };
468#endif
469
470 class WindowSystemEventList {
471 QList<WindowSystemEvent *> impl;
472 mutable QMutex mutex;
473 public:
474 WindowSystemEventList() : impl(), mutex() {}
475 ~WindowSystemEventList() { clear(); }
476
477 void clear()
478 { const QMutexLocker locker(&mutex); qDeleteAll(impl); impl.clear(); }
479 void prepend(WindowSystemEvent *e)
480 { const QMutexLocker locker(&mutex); impl.prepend(e); }
481 WindowSystemEvent *takeFirstOrReturnNull()
482 { const QMutexLocker locker(&mutex); return impl.empty() ? nullptr : impl.takeFirst(); }
483 WindowSystemEvent *takeFirstNonUserInputOrReturnNull()
484 {
485 const QMutexLocker locker(&mutex);
486 for (int i = 0; i < impl.size(); ++i)
487 if (!(impl.at(i)->type & QWindowSystemInterfacePrivate::UserInputEvent))
488 return impl.takeAt(i);
489 return nullptr;
490 }
491 bool nonUserInputEventsQueued()
492 {
493 const QMutexLocker locker(&mutex);
494 for (int i = 0; i < impl.size(); ++i)
495 if (!(impl.at(i)->type & QWindowSystemInterfacePrivate::UserInputEvent))
496 return true;
497 return false;
498 }
499 void append(WindowSystemEvent *e)
500 { const QMutexLocker locker(&mutex); impl.append(e); }
501 int count() const
502 { const QMutexLocker locker(&mutex); return impl.count(); }
503 WindowSystemEvent *peekAtFirstOfType(EventType t) const
504 {
505 const QMutexLocker locker(&mutex);
506 for (int i = 0; i < impl.size(); ++i) {
507 if (impl.at(i)->type == t)
508 return impl.at(i);
509 }
510 return nullptr;
511 }
512 void remove(const WindowSystemEvent *e)
513 {
514 const QMutexLocker locker(&mutex);
515 for (int i = 0; i < impl.size(); ++i) {
516 if (impl.at(i) == e) {
517 delete impl.takeAt(i);
518 break;
519 }
520 }
521 }
522 private:
523 Q_DISABLE_COPY_MOVE(WindowSystemEventList)
524 };
525
526 static WindowSystemEventList windowSystemEventQueue;
527
528 static int windowSystemEventsQueued();
529 static bool nonUserInputEventsQueued();
530 static WindowSystemEvent *getWindowSystemEvent();
531 static WindowSystemEvent *getNonUserInputWindowSystemEvent();
532 static WindowSystemEvent *peekWindowSystemEvent(EventType t);
533 static void removeWindowSystemEvent(WindowSystemEvent *event);
534 template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
535 static bool handleWindowSystemEvent(WindowSystemEvent *ev);
536
537public:
538 static QElapsedTimer eventTime;
539 static bool synchronousWindowSystemEvents;
540 static bool platformFiltersEvents;
541
542 static QWaitCondition eventsFlushed;
543 static QMutex flushEventMutex;
544 static QAtomicInt eventAccepted;
545
546 static QList<QEventPoint>
547 fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
548 const QWindow *window, QEvent::Type *type = nullptr);
549 template<class EventPointList>
550 static QList<QWindowSystemInterface::TouchPoint>
551 toNativeTouchPoints(const EventPointList &pointList, const QWindow *window)
552 {
553 QList<QWindowSystemInterface::TouchPoint> newList;
554 newList.reserve(pointList.size());
555 for (const auto &point : pointList) {
556 newList.append(toNativeTouchPoint(point, window));
557 }
558 return newList;
559 }
560 static QWindowSystemInterface::TouchPoint
561 toNativeTouchPoint(const QEventPoint &point, const QWindow *window);
562
563 static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler);
564 static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler);
565 static QWindowSystemEventHandler *eventHandler;
566};
567
568class Q_GUI_EXPORT QWindowSystemEventHandler
569{
570public:
571 virtual ~QWindowSystemEventHandler();
572 virtual bool sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *event);
573};
574
575QT_END_NAMESPACE
576
577#endif // QWINDOWSYSTEMINTERFACE_P_H
578