1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QWAYLANDINPUTDEVICE_H |
5 | #define QWAYLANDINPUTDEVICE_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtWaylandClient/private/qtwaylandclientglobal_p.h> |
19 | #include <QtWaylandClient/private/qwaylandwindow_p.h> |
20 | |
21 | #include <QtCore/QScopedPointer> |
22 | #include <QSocketNotifier> |
23 | #include <QObject> |
24 | #include <QTimer> |
25 | #include <qpa/qplatformintegration.h> |
26 | #include <qpa/qplatformscreen.h> |
27 | #include <qpa/qwindowsysteminterface.h> |
28 | |
29 | #include <QtWaylandClient/private/qwayland-wayland.h> |
30 | #include <QtWaylandClient/private/qwayland-pointer-gestures-unstable-v1.h> |
31 | |
32 | #if QT_CONFIG(xkbcommon) |
33 | #include <QtGui/private/qxkbcommon_p.h> |
34 | #endif |
35 | |
36 | #include <QtCore/QDebug> |
37 | #include <QtCore/QElapsedTimer> |
38 | #include <QtCore/QPointer> |
39 | |
40 | #if QT_CONFIG(cursor) |
41 | struct wl_cursor_image; |
42 | #endif |
43 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | namespace QtWayland { |
47 | class zwp_primary_selection_device_v1; |
48 | } //namespace QtWayland |
49 | |
50 | namespace QtWaylandClient { |
51 | |
52 | class QWaylandDataDevice; |
53 | class QWaylandDisplay; |
54 | #if QT_CONFIG(wayland_client_primary_selection) |
55 | class QWaylandPrimarySelectionDeviceV1; |
56 | #endif |
57 | #if QT_CONFIG(tabletevent) |
58 | class QWaylandTabletSeatV2; |
59 | #endif |
60 | class QWaylandPointerGestures; |
61 | class QWaylandPointerGestureSwipe; |
62 | class QWaylandPointerGesturePinch; |
63 | class QWaylandTextInputInterface; |
64 | class QWaylandTextInputMethod; |
65 | #if QT_CONFIG(cursor) |
66 | class QWaylandCursorTheme; |
67 | class QWaylandCursorShape; |
68 | class CursorSurface; |
69 | #endif |
70 | |
71 | Q_DECLARE_LOGGING_CATEGORY(lcQpaWaylandInput); |
72 | |
73 | class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice |
74 | : public QObject |
75 | , public QtWayland::wl_seat |
76 | { |
77 | Q_OBJECT |
78 | public: |
79 | class Keyboard; |
80 | class Pointer; |
81 | class Touch; |
82 | |
83 | QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id); |
84 | ~QWaylandInputDevice() override; |
85 | |
86 | uint32_t capabilities() const { return mCaps; } |
87 | |
88 | QWaylandDisplay *display() const { return mQDisplay; } |
89 | struct ::wl_seat *wl_seat() { return QtWayland::wl_seat::object(); } |
90 | |
91 | #if QT_CONFIG(cursor) |
92 | void setCursor(const QCursor *cursor, const QSharedPointer<QWaylandBuffer> &cachedBuffer = {}, int fallbackOutputScale = 1); |
93 | #endif |
94 | void handleEndDrag(); |
95 | |
96 | #if QT_CONFIG(wayland_datadevice) |
97 | void setDataDevice(QWaylandDataDevice *device); |
98 | QWaylandDataDevice *dataDevice() const; |
99 | #endif |
100 | |
101 | #if QT_CONFIG(wayland_client_primary_selection) |
102 | void setPrimarySelectionDevice(QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice); |
103 | QWaylandPrimarySelectionDeviceV1 *primarySelectionDevice() const; |
104 | #endif |
105 | |
106 | #if QT_CONFIG(tabletevent) |
107 | void setTabletSeat(QWaylandTabletSeatV2 *tabletSeat); |
108 | QWaylandTabletSeatV2* tabletSeat() const; |
109 | #endif |
110 | |
111 | void setTextInput(QWaylandTextInputInterface *textInput); |
112 | QWaylandTextInputInterface *textInput() const; |
113 | |
114 | void setTextInputMethod(QWaylandTextInputMethod *textInputMethod); |
115 | QWaylandTextInputMethod *textInputMethod() const; |
116 | |
117 | void removeMouseButtonFromState(Qt::MouseButton button); |
118 | |
119 | QWaylandWindow *pointerFocus() const; |
120 | QWaylandWindow *keyboardFocus() const; |
121 | QWaylandWindow *touchFocus() const; |
122 | |
123 | QList<int> possibleKeys(const QKeyEvent *event) const; |
124 | |
125 | QPointF pointerSurfacePosition() const; |
126 | |
127 | Qt::KeyboardModifiers modifiers() const; |
128 | |
129 | uint32_t serial() const; |
130 | |
131 | virtual Keyboard *createKeyboard(QWaylandInputDevice *device); |
132 | virtual Pointer *createPointer(QWaylandInputDevice *device); |
133 | virtual Touch *createTouch(QWaylandInputDevice *device); |
134 | |
135 | Keyboard *keyboard() const; |
136 | Pointer *pointer() const; |
137 | QWaylandPointerGestureSwipe *pointerGestureSwipe() const; |
138 | QWaylandPointerGesturePinch *pointerGesturePinch() const; |
139 | Touch *touch() const; |
140 | |
141 | protected: |
142 | QWaylandDisplay *mQDisplay = nullptr; |
143 | struct wl_display *mDisplay = nullptr; |
144 | |
145 | uint32_t mCaps = 0; |
146 | |
147 | #if QT_CONFIG(cursor) |
148 | struct CursorState { |
149 | QSharedPointer<QWaylandBuffer> bitmapBuffer; // not used with shape cursors |
150 | int bitmapScale = 1; |
151 | Qt::CursorShape shape = Qt::ArrowCursor; |
152 | int fallbackOutputScale = 1; |
153 | QPoint hotspot; |
154 | QElapsedTimer animationTimer; |
155 | } mCursor; |
156 | #endif |
157 | |
158 | #if QT_CONFIG(wayland_datadevice) |
159 | QWaylandDataDevice *mDataDevice = nullptr; |
160 | #endif |
161 | |
162 | #if QT_CONFIG(wayland_client_primary_selection) |
163 | QScopedPointer<QWaylandPrimarySelectionDeviceV1> mPrimarySelectionDevice; |
164 | #endif |
165 | |
166 | QScopedPointer<Keyboard> mKeyboard; |
167 | QScopedPointer<Pointer> mPointer; |
168 | QScopedPointer<QWaylandPointerGestureSwipe> mPointerGestureSwipe; |
169 | QScopedPointer<QWaylandPointerGesturePinch> mPointerGesturePinch; |
170 | QScopedPointer<Touch> mTouch; |
171 | |
172 | QScopedPointer<QWaylandTextInputInterface> mTextInput; |
173 | QScopedPointer<QWaylandTextInputMethod> mTextInputMethod; |
174 | #if QT_CONFIG(tabletevent) |
175 | QScopedPointer<QWaylandTabletSeatV2> mTabletSeat; |
176 | #endif |
177 | |
178 | uint32_t mTime = 0; |
179 | uint32_t mSerial = 0; |
180 | |
181 | void seat_capabilities(uint32_t caps) override; |
182 | void handleTouchPoint(int id, QEventPoint::State state, const QPointF &surfacePosition = QPoint()); |
183 | |
184 | QPointingDevice *mTouchDevice = nullptr; |
185 | QPointingDevice *mTouchPadDevice = nullptr; |
186 | |
187 | friend class QWaylandTouchExtension; |
188 | friend class QWaylandQtKeyExtension; |
189 | friend class QWaylandPointerGestureSwipe; |
190 | friend class QWaylandPointerGesturePinch; |
191 | friend class QWaylandWindow; |
192 | }; |
193 | |
194 | inline uint32_t QWaylandInputDevice::serial() const |
195 | { |
196 | return mSerial; |
197 | } |
198 | |
199 | |
200 | class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice::Keyboard : public QObject, public QtWayland::wl_keyboard |
201 | { |
202 | Q_OBJECT |
203 | |
204 | public: |
205 | Keyboard(QWaylandInputDevice *p); |
206 | ~Keyboard() override; |
207 | |
208 | QWaylandWindow *focusWindow() const; |
209 | |
210 | void keyboard_keymap(uint32_t format, |
211 | int32_t fd, |
212 | uint32_t size) override; |
213 | void keyboard_enter(uint32_t time, |
214 | struct wl_surface *surface, |
215 | struct wl_array *keys) override; |
216 | void keyboard_leave(uint32_t time, |
217 | struct wl_surface *surface) override; |
218 | void keyboard_key(uint32_t serial, uint32_t time, |
219 | uint32_t key, uint32_t state) override; |
220 | void keyboard_modifiers(uint32_t serial, |
221 | uint32_t mods_depressed, |
222 | uint32_t mods_latched, |
223 | uint32_t mods_locked, |
224 | uint32_t group) override; |
225 | void keyboard_repeat_info(int32_t rate, int32_t delay) override; |
226 | |
227 | QWaylandInputDevice *mParent = nullptr; |
228 | QPointer<QWaylandSurface> mFocus; |
229 | |
230 | uint32_t mNativeModifiers = 0; |
231 | |
232 | struct repeatKey { |
233 | int key; |
234 | uint32_t code; |
235 | uint32_t time; |
236 | QString text; |
237 | Qt::KeyboardModifiers modifiers; |
238 | uint32_t nativeVirtualKey; |
239 | uint32_t nativeModifiers; |
240 | } mRepeatKey; |
241 | |
242 | QTimer mRepeatTimer; |
243 | int mRepeatRate = 25; |
244 | int mRepeatDelay = 400; |
245 | |
246 | uint32_t mKeymapFormat = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1; |
247 | |
248 | Qt::KeyboardModifiers modifiers() const; |
249 | |
250 | struct ::wl_keyboard *wl_keyboard() { return QtWayland::wl_keyboard::object(); } |
251 | |
252 | #if QT_CONFIG(xkbcommon) |
253 | virtual int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers, xkb_state *state, xkb_keycode_t code) { |
254 | return QXkbCommon::keysymToQtKey(keysym, modifiers, state, code); |
255 | } |
256 | #endif |
257 | |
258 | private slots: |
259 | void handleFocusDestroyed(); |
260 | void handleFocusLost(); |
261 | |
262 | private: |
263 | #if QT_CONFIG(xkbcommon) |
264 | bool createDefaultKeymap(); |
265 | #endif |
266 | void handleKey(ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, |
267 | quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, |
268 | const QString &text, bool autorepeat = false, ushort count = 1); |
269 | |
270 | #if QT_CONFIG(xkbcommon) |
271 | QXkbCommon::ScopedXKBKeymap mXkbKeymap; |
272 | QXkbCommon::ScopedXKBState mXkbState; |
273 | #endif |
274 | friend class QWaylandInputDevice; |
275 | }; |
276 | |
277 | class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer |
278 | { |
279 | Q_OBJECT |
280 | public: |
281 | explicit Pointer(QWaylandInputDevice *seat); |
282 | ~Pointer() override; |
283 | QWaylandWindow *focusWindow() const; |
284 | #if QT_CONFIG(cursor) |
285 | int idealCursorScale() const; |
286 | void updateCursorTheme(); |
287 | void updateCursor(); |
288 | void cursorTimerCallback(); |
289 | void cursorFrameCallback(); |
290 | CursorSurface *getOrCreateCursorSurface(); |
291 | #endif |
292 | QWaylandInputDevice *seat() const { return mParent; } |
293 | |
294 | struct ::wl_pointer *wl_pointer() { return QtWayland::wl_pointer::object(); } |
295 | |
296 | protected: |
297 | void pointer_enter(uint32_t serial, struct wl_surface *surface, |
298 | wl_fixed_t sx, wl_fixed_t sy) override; |
299 | void pointer_leave(uint32_t time, struct wl_surface *surface) override; |
300 | void pointer_motion(uint32_t time, |
301 | wl_fixed_t sx, wl_fixed_t sy) override; |
302 | void pointer_button(uint32_t serial, uint32_t time, |
303 | uint32_t button, uint32_t state) override; |
304 | void pointer_axis(uint32_t time, |
305 | uint32_t axis, |
306 | wl_fixed_t value) override; |
307 | void pointer_axis_source(uint32_t source) override; |
308 | void pointer_axis_stop(uint32_t time, uint32_t axis) override; |
309 | void pointer_axis_discrete(uint32_t axis, int32_t value) override; |
310 | void pointer_frame() override; |
311 | void pointer_axis_value120(uint32_t axis, int32_t value120) override; |
312 | |
313 | private slots: |
314 | void handleFocusDestroyed() { invalidateFocus(); } |
315 | |
316 | private: |
317 | void invalidateFocus(); |
318 | |
319 | public: |
320 | void releaseButtons(); |
321 | |
322 | QWaylandInputDevice *mParent = nullptr; |
323 | QPointer<QWaylandSurface> mFocus; |
324 | uint32_t mEnterSerial = 0; |
325 | #if QT_CONFIG(cursor) |
326 | struct { |
327 | QScopedPointer<QWaylandCursorShape> shape; |
328 | QWaylandCursorTheme *theme = nullptr; |
329 | int themeBufferScale = 0; |
330 | QScopedPointer<CursorSurface> surface; |
331 | QTimer frameTimer; |
332 | bool gotFrameCallback = false; |
333 | bool gotTimerCallback = false; |
334 | } mCursor; |
335 | #endif |
336 | QPointF mSurfacePos; |
337 | QPointF mGlobalPos; |
338 | Qt::MouseButtons mButtons = Qt::NoButton; |
339 | #if QT_CONFIG(cursor) |
340 | wl_buffer *mCursorBuffer = nullptr; |
341 | Qt::CursorShape mCursorShape = Qt::BitmapCursor; |
342 | #endif |
343 | |
344 | struct FrameData { |
345 | QWaylandPointerEvent *event = nullptr; |
346 | |
347 | QPointF delta; |
348 | QPoint delta120; |
349 | axis_source axisSource = axis_source_wheel; |
350 | |
351 | void resetScrollData(); |
352 | bool hasPixelDelta() const; |
353 | QPoint pixelDeltaAndError(QPointF *accumulatedError) const; |
354 | QPoint pixelDelta() const { return hasPixelDelta() ? delta.toPoint() : QPoint(); } |
355 | QPoint angleDelta() const; |
356 | Qt::MouseEventSource wheelEventSource() const; |
357 | } mFrameData; |
358 | |
359 | bool mScrollBeginSent = false; |
360 | QPointF mScrollDeltaRemainder; |
361 | |
362 | void setFrameEvent(QWaylandPointerEvent *event); |
363 | void flushScrollEvent(); |
364 | void flushFrameEvent(); |
365 | private: //TODO: should other methods be private as well? |
366 | bool isDefinitelyTerminated(axis_source source) const; |
367 | }; |
368 | |
369 | class Q_WAYLANDCLIENT_EXPORT QWaylandInputDevice::Touch : public QtWayland::wl_touch |
370 | { |
371 | public: |
372 | Touch(QWaylandInputDevice *p); |
373 | ~Touch() override; |
374 | |
375 | void touch_down(uint32_t serial, |
376 | uint32_t time, |
377 | struct wl_surface *surface, |
378 | int32_t id, |
379 | wl_fixed_t x, |
380 | wl_fixed_t y) override; |
381 | void touch_up(uint32_t serial, |
382 | uint32_t time, |
383 | int32_t id) override; |
384 | void touch_motion(uint32_t time, |
385 | int32_t id, |
386 | wl_fixed_t x, |
387 | wl_fixed_t y) override; |
388 | void touch_frame() override; |
389 | void touch_cancel() override; |
390 | |
391 | bool allTouchPointsReleased(); |
392 | void releasePoints(); |
393 | |
394 | struct ::wl_touch *wl_touch() { return QtWayland::wl_touch::object(); } |
395 | |
396 | QWaylandInputDevice *mParent = nullptr; |
397 | QPointer<QWaylandWindow> mFocus; |
398 | QList<QWindowSystemInterface::TouchPoint> mPendingTouchPoints; |
399 | }; |
400 | |
401 | class QWaylandPointerEvent |
402 | { |
403 | Q_GADGET |
404 | public: |
405 | inline QWaylandPointerEvent(QEvent::Type type, Qt::ScrollPhase phase, QWaylandWindow *surface, |
406 | ulong timestamp, const QPointF &localPos, const QPointF &globalPos, |
407 | Qt::MouseButtons buttons, Qt::MouseButton button, |
408 | Qt::KeyboardModifiers modifiers) |
409 | : type(type) |
410 | , phase(phase) |
411 | , timestamp(timestamp) |
412 | , local(localPos) |
413 | , global(globalPos) |
414 | , buttons(buttons) |
415 | , button(button) |
416 | , modifiers(modifiers) |
417 | , surface(surface) |
418 | {} |
419 | inline QWaylandPointerEvent(QEvent::Type type, Qt::ScrollPhase phase, QWaylandWindow *surface, |
420 | ulong timestamp, const QPointF &local, const QPointF &global, |
421 | const QPoint &pixelDelta, const QPoint &angleDelta, |
422 | Qt::MouseEventSource source, |
423 | Qt::KeyboardModifiers modifiers) |
424 | : type(type) |
425 | , phase(phase) |
426 | , timestamp(timestamp) |
427 | , local(local) |
428 | , global(global) |
429 | , modifiers(modifiers) |
430 | , pixelDelta(pixelDelta) |
431 | , angleDelta(angleDelta) |
432 | , source(source) |
433 | , surface(surface) |
434 | {} |
435 | |
436 | QEvent::Type type = QEvent::None; |
437 | Qt::ScrollPhase phase = Qt::NoScrollPhase; |
438 | ulong timestamp = 0; |
439 | QPointF local; |
440 | QPointF global; |
441 | Qt::MouseButtons buttons; |
442 | Qt::MouseButton button = Qt::NoButton; // Button that caused the event (QMouseEvent::button) |
443 | Qt::KeyboardModifiers modifiers; |
444 | QPoint pixelDelta; |
445 | QPoint angleDelta; |
446 | Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; |
447 | QPointer<QWaylandWindow> surface; |
448 | }; |
449 | |
450 | #ifndef QT_NO_GESTURES |
451 | class QWaylandPointerGestureSwipeEvent |
452 | { |
453 | Q_GADGET |
454 | public: |
455 | inline QWaylandPointerGestureSwipeEvent(QWaylandWindow *surface, Qt::GestureState state, |
456 | ulong timestamp, const QPointF &local, |
457 | const QPointF &global, uint fingers, const QPointF& delta) |
458 | : surface(surface) |
459 | , state(state) |
460 | , timestamp(timestamp) |
461 | , local(local) |
462 | , global(global) |
463 | , fingers(fingers) |
464 | , delta(delta) |
465 | {} |
466 | |
467 | QPointer<QWaylandWindow> surface; |
468 | Qt::GestureState state = Qt::GestureState::NoGesture; |
469 | ulong timestamp = 0; |
470 | QPointF local; |
471 | QPointF global; |
472 | uint fingers = 0; |
473 | QPointF delta; |
474 | }; |
475 | |
476 | class QWaylandPointerGesturePinchEvent |
477 | { |
478 | Q_GADGET |
479 | public: |
480 | inline QWaylandPointerGesturePinchEvent(QWaylandWindow *surface, Qt::GestureState state, |
481 | ulong timestamp, const QPointF &local, |
482 | const QPointF &global, uint fingers, const QPointF& delta, |
483 | qreal scale_delta, qreal rotation_delta) |
484 | : surface(surface) |
485 | , state(state) |
486 | , timestamp(timestamp) |
487 | , local(local) |
488 | , global(global) |
489 | , fingers(fingers) |
490 | , delta(delta) |
491 | , scale_delta(scale_delta) |
492 | , rotation_delta(rotation_delta) |
493 | {} |
494 | |
495 | QPointer<QWaylandWindow> surface; |
496 | Qt::GestureState state = Qt::GestureState::NoGesture; |
497 | ulong timestamp = 0; |
498 | QPointF local; |
499 | QPointF global; |
500 | uint fingers = 0; |
501 | QPointF delta; |
502 | qreal scale_delta = 0; |
503 | qreal rotation_delta = 0; |
504 | }; |
505 | #endif // #ifndef QT_NO_GESTURES |
506 | |
507 | } |
508 | |
509 | QT_END_NAMESPACE |
510 | |
511 | #endif |
512 | |