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)
76struct wl_cursor_image;
77#endif
78
79QT_BEGIN_NAMESPACE
80
81namespace QtWayland {
82class zwp_primary_selection_device_v1;
83} //namespace QtWayland
84
85namespace QtWaylandClient {
86
87class QWaylandDataDevice;
88class QWaylandDisplay;
89#if QT_CONFIG(wayland_client_primary_selection)
90class QWaylandPrimarySelectionDeviceV1;
91#endif
92#if QT_CONFIG(tabletevent)
93class QWaylandTabletSeatV2;
94#endif
95class QWaylandTextInput;
96#if QT_CONFIG(cursor)
97class QWaylandCursorTheme;
98class CursorSurface;
99#endif
100
101class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice
102 : public QObject
103 , public QtWayland::wl_seat
104{
105 Q_OBJECT
106public:
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
163private:
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
210inline uint32_t QWaylandInputDevice::serial() const
211{
212 return mSerial;
213}
214
215
216class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Keyboard : public QObject, public QtWayland::wl_keyboard
217{
218 Q_OBJECT
219
220public:
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
268private slots:
269 void handleFocusDestroyed();
270 void handleFocusLost();
271
272private:
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
287class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Pointer : public QObject, public QtWayland::wl_pointer
288{
289 Q_OBJECT
290public:
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
308protected:
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
324private slots:
325 void handleFocusDestroyed() { invalidateFocus(); }
326
327private:
328 void invalidateFocus();
329
330public:
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();
375private: //TODO: should other methods be private as well?
376 bool isDefinitelyTerminated(axis_source source) const;
377};
378
379class Q_WAYLAND_CLIENT_EXPORT QWaylandInputDevice::Touch : public QtWayland::wl_touch
380{
381public:
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
411class QWaylandPointerEvent
412{
413 Q_GADGET
414public:
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
462QT_END_NAMESPACE
463
464#endif
465

source code of qtwayland/src/client/qwaylandinputdevice_p.h