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