1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
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 General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29
30 #include "qwaylandpointer.h"
31 #include "qwaylandpointer_p.h"
32 #include <QtWaylandCompositor/QWaylandClient>
33 #include <QtWaylandCompositor/QWaylandCompositor>
34
35 QT_BEGIN_NAMESPACE
36
37 QWaylandSurfaceRole QWaylandPointerPrivate::s_role("wl_pointer");
38
QWaylandPointerPrivate(QWaylandPointer * pointer,QWaylandSeat * seat)39 QWaylandPointerPrivate::QWaylandPointerPrivate(QWaylandPointer *pointer, QWaylandSeat *seat)
40 : seat(seat)
41 {
42 Q_UNUSED(pointer);
43 }
44
sendButton(Qt::MouseButton button,uint32_t state)45 uint QWaylandPointerPrivate::sendButton(Qt::MouseButton button, uint32_t state)
46 {
47 Q_Q(QWaylandPointer);
48 if (!q->mouseFocus() || !q->mouseFocus()->surface())
49 return 0;
50
51 wl_client *client = q->mouseFocus()->surface()->waylandClient();
52 uint32_t time = compositor()->currentTimeMsecs();
53 uint32_t serial = compositor()->nextSerial();
54 for (auto resource : resourceMap().values(client))
55 send_button(resource->handle, serial, time, q->toWaylandButton(button), state);
56 return serial;
57 }
58
sendMotion()59 void QWaylandPointerPrivate::sendMotion()
60 {
61 Q_ASSERT(enteredSurface);
62 uint32_t time = compositor()->currentTimeMsecs();
63 wl_fixed_t x = wl_fixed_from_double(localPosition.x());
64 wl_fixed_t y = wl_fixed_from_double(localPosition.y());
65 for (auto resource : resourceMap().values(enteredSurface->waylandClient()))
66 wl_pointer_send_motion(resource->handle, time, x, y);
67 }
68
sendEnter(QWaylandSurface * surface)69 void QWaylandPointerPrivate::sendEnter(QWaylandSurface *surface)
70 {
71 Q_ASSERT(surface && !enteredSurface);
72 enterSerial = compositor()->nextSerial();
73
74 QWaylandKeyboard *keyboard = seat->keyboard();
75 if (keyboard)
76 keyboard->sendKeyModifiers(surface->client(), enterSerial);
77
78 wl_fixed_t x = wl_fixed_from_double(localPosition.x());
79 wl_fixed_t y = wl_fixed_from_double(localPosition.y());
80 for (auto resource : resourceMap().values(surface->waylandClient()))
81 send_enter(resource->handle, enterSerial, surface->resource(), x, y);
82
83 enteredSurface = surface;
84 enteredSurfaceDestroyListener.listenForDestruction(surface->resource());
85 }
86
sendLeave()87 void QWaylandPointerPrivate::sendLeave()
88 {
89 Q_ASSERT(enteredSurface);
90 uint32_t serial = compositor()->nextSerial();
91 for (auto resource : resourceMap().values(enteredSurface->waylandClient()))
92 send_leave(resource->handle, serial, enteredSurface->resource());
93 enteredSurface = nullptr;
94 localPosition = QPointF();
95 enteredSurfaceDestroyListener.reset();
96 seat->cursorSurfaceRequest(nullptr, 0, 0);
97 }
98
ensureEntered(QWaylandSurface * surface)99 void QWaylandPointerPrivate::ensureEntered(QWaylandSurface *surface)
100 {
101 if (enteredSurface == surface)
102 return;
103
104 if (enteredSurface)
105 sendLeave();
106
107 if (surface)
108 sendEnter(surface);
109 }
110
pointer_release(wl_pointer::Resource * resource)111 void QWaylandPointerPrivate::pointer_release(wl_pointer::Resource *resource)
112 {
113 wl_resource_destroy(resource->handle);
114 }
115
pointer_set_cursor(wl_pointer::Resource * resource,uint32_t serial,wl_resource * surface,int32_t hotspot_x,int32_t hotspot_y)116 void QWaylandPointerPrivate::pointer_set_cursor(wl_pointer::Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y)
117 {
118 Q_UNUSED(resource);
119 Q_UNUSED(serial);
120
121 if (!surface) {
122 seat->cursorSurfaceRequest(nullptr, 0, 0);
123 return;
124 }
125
126 QWaylandSurface *s = QWaylandSurface::fromResource(surface);
127 // XXX FIXME
128 // The role concept was formalized in wayland 1.7, so that release adds one error
129 // code for each interface that implements a role, and we are supposed to pass here
130 // the newly constructed resource and the correct error code so that if setting the
131 // role fails, a proper error can be sent to the client.
132 // However we're still using wayland 1.4, which doesn't have interface specific role
133 // errors, so the best we can do is to use wl_display's object_id error.
134 wl_resource *displayRes = wl_client_get_object(resource->client(), 1);
135 if (s->setRole(&QWaylandPointerPrivate::s_role, displayRes, WL_DISPLAY_ERROR_INVALID_OBJECT)) {
136 s->markAsCursorSurface(true);
137 seat->cursorSurfaceRequest(s, hotspot_x, hotspot_y);
138 }
139 }
140
141 /*!
142 * \class QWaylandPointer
143 * \inmodule QtWaylandCompositor
144 * \since 5.8
145 * \brief The QWaylandPointer class represents a pointer device.
146 *
147 * This class provides access to the pointer device in a QWaylandSeat. It corresponds to
148 * the Wayland interface wl_pointer.
149 */
150
151 /*!
152 * Constructs a QWaylandPointer for the given \a seat and with the given \a parent.
153 */
QWaylandPointer(QWaylandSeat * seat,QObject * parent)154 QWaylandPointer::QWaylandPointer(QWaylandSeat *seat, QObject *parent)
155 : QWaylandObject(* new QWaylandPointerPrivate(this, seat), parent)
156 {
157 connect(&d_func()->enteredSurfaceDestroyListener, &QWaylandDestroyListener::fired, this, &QWaylandPointer::enteredSurfaceDestroyed);
158 connect(seat, &QWaylandSeat::mouseFocusChanged, this, &QWaylandPointer::pointerFocusChanged);
159 }
160
161 /*!
162 * Returns the input device for this QWaylandPointer.
163 */
seat() const164 QWaylandSeat *QWaylandPointer::seat() const
165 {
166 Q_D(const QWaylandPointer);
167 return d->seat;
168 }
169
170 /*!
171 * Returns the compositor for this QWaylandPointer.
172 */
compositor() const173 QWaylandCompositor *QWaylandPointer::compositor() const
174 {
175 Q_D(const QWaylandPointer);
176 return d->compositor();
177 }
178
179 /*!
180 * Returns the output for this QWaylandPointer.
181 */
output() const182 QWaylandOutput *QWaylandPointer::output() const
183 {
184 Q_D(const QWaylandPointer);
185 return d->output;
186 }
187
188 /*!
189 * Sets the output for this QWaylandPointer to \a output.
190 */
setOutput(QWaylandOutput * output)191 void QWaylandPointer::setOutput(QWaylandOutput *output)
192 {
193 Q_D(QWaylandPointer);
194 if (d->output == output) return;
195 d->output = output;
196 outputChanged();
197 }
198
199 /*!
200 * Sends a mouse press event for \a button to the view currently holding mouse focus.
201 *
202 * Returns the serial number of the press event.
203 */
sendMousePressEvent(Qt::MouseButton button)204 uint QWaylandPointer::sendMousePressEvent(Qt::MouseButton button)
205 {
206 Q_D(QWaylandPointer);
207 d->buttonCount++;
208
209 if (d->buttonCount == 1)
210 emit buttonPressedChanged();
211
212 return d->sendButton(button, WL_POINTER_BUTTON_STATE_PRESSED);
213 }
214
215 /*!
216 * Sends a mouse release event for \a button to the view currently holding mouse focus.
217 *
218 * Returns the serial number of the release event.
219 */
sendMouseReleaseEvent(Qt::MouseButton button)220 uint QWaylandPointer::sendMouseReleaseEvent(Qt::MouseButton button)
221 {
222 Q_D(QWaylandPointer);
223 d->buttonCount--;
224
225 if (d->buttonCount == 0)
226 emit buttonPressedChanged();
227
228 return d->sendButton(button, WL_POINTER_BUTTON_STATE_RELEASED);
229 }
230
231 /*!
232 * Sets the current mouse focus to \a view and sends a mouse move event to it with the
233 * local position \a localPos in surface coordinates and output space position \a outputSpacePos.
234 */
sendMouseMoveEvent(QWaylandView * view,const QPointF & localPos,const QPointF & outputSpacePos)235 void QWaylandPointer::sendMouseMoveEvent(QWaylandView *view, const QPointF &localPos, const QPointF &outputSpacePos)
236 {
237 Q_D(QWaylandPointer);
238 if (view && (!view->surface() || view->surface()->isCursorSurface()))
239 view = nullptr;
240 d->seat->setMouseFocus(view);
241 d->localPosition = localPos;
242 d->spacePosition = outputSpacePos;
243
244 if (view) {
245 // We adjust if the mouse position is on the edge
246 // to work around Qt's event propagation
247 QSizeF size(view->surface()->destinationSize());
248 if (d->localPosition.x() == size.width())
249 d->localPosition.rx() -= 0.01;
250 if (d->localPosition.y() == size.height())
251 d->localPosition.ry() -= 0.01;
252
253 d->ensureEntered(view->surface());
254 d->sendMotion();
255
256 if (view->output())
257 setOutput(view->output());
258 }
259 }
260
261 /*!
262 * Sends a mouse wheel event with the given \a orientation and \a delta to the view that currently holds mouse focus.
263 */
sendMouseWheelEvent(Qt::Orientation orientation,int delta)264 void QWaylandPointer::sendMouseWheelEvent(Qt::Orientation orientation, int delta)
265 {
266 Q_D(QWaylandPointer);
267 if (!d->enteredSurface)
268 return;
269
270 uint32_t time = d->compositor()->currentTimeMsecs();
271 uint32_t axis = orientation == Qt::Horizontal ? WL_POINTER_AXIS_HORIZONTAL_SCROLL
272 : WL_POINTER_AXIS_VERTICAL_SCROLL;
273
274 for (auto resource : d->resourceMap().values(d->enteredSurface->waylandClient()))
275 d->send_axis(resource->handle, time, axis, wl_fixed_from_int(-delta / 12));
276 }
277
278 /*!
279 * Returns the view that currently holds mouse focus.
280 */
mouseFocus() const281 QWaylandView *QWaylandPointer::mouseFocus() const
282 {
283 Q_D(const QWaylandPointer);
284 return d->seat->mouseFocus();
285 }
286
287 /*!
288 * Returns the current local position of the QWaylandPointer in surface coordinates.
289 */
currentLocalPosition() const290 QPointF QWaylandPointer::currentLocalPosition() const
291 {
292 Q_D(const QWaylandPointer);
293 return d->localPosition;
294 }
295
296 /*!
297 * Returns the current output space position of the QWaylandPointer.
298 */
currentSpacePosition() const299 QPointF QWaylandPointer::currentSpacePosition() const
300 {
301 Q_D(const QWaylandPointer);
302 return d->spacePosition;
303 }
304
305 /*!
306 * Returns true if any button is currently pressed. Otherwise returns false.
307 */
isButtonPressed() const308 bool QWaylandPointer::isButtonPressed() const
309 {
310 Q_D(const QWaylandPointer);
311 return d->buttonCount > 0;
312 }
313
314 /*!
315 * \internal
316 */
addClient(QWaylandClient * client,uint32_t id,uint32_t version)317 void QWaylandPointer::addClient(QWaylandClient *client, uint32_t id, uint32_t version)
318 {
319 Q_D(QWaylandPointer);
320 wl_resource *resource = d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_pointer::interfaceVersion(), version))->handle;
321 if (d->enteredSurface && client == d->enteredSurface->client()) {
322 d->send_enter(resource, d->enterSerial, d->enteredSurface->resource(),
323 wl_fixed_from_double(d->localPosition.x()),
324 wl_fixed_from_double(d->localPosition.y()));
325 }
326 }
327
328 /*!
329 * Returns a Wayland resource for this QWaylandPointer.
330 *
331 * This API doesn't actually make sense, since there may be many pointer resources per client
332 * It's here for compatibility reasons.
333 */
focusResource() const334 struct wl_resource *QWaylandPointer::focusResource() const
335 {
336 Q_D(const QWaylandPointer);
337 QWaylandView *focus = d->seat->mouseFocus();
338 if (!focus)
339 return nullptr;
340
341 // Just return the first resource we can find.
342 return d->resourceMap().value(focus->surface()->waylandClient())->handle;
343 }
344
345 /*!
346 * \internal
347 */
sendButton(struct wl_resource * resource,uint32_t time,Qt::MouseButton button,uint32_t state)348 uint QWaylandPointer::sendButton(struct wl_resource *resource, uint32_t time, Qt::MouseButton button, uint32_t state)
349 {
350 // This method is here for compatibility reasons only, since it usually doesn't make sense to
351 // send button events to just one of the pointer resources for a client.
352 Q_D(QWaylandPointer);
353 uint32_t serial = d->compositor()->nextSerial();
354 d->send_button(resource, serial, time, toWaylandButton(button), state);
355 return serial;
356 }
357
358 /*!
359 * \internal
360 */
toWaylandButton(Qt::MouseButton button)361 uint32_t QWaylandPointer::toWaylandButton(Qt::MouseButton button)
362 {
363 #ifndef BTN_LEFT
364 uint32_t BTN_LEFT = 0x110;
365 #endif
366 // the range of valid buttons (evdev module) is from 0x110
367 // through 0x11f. 0x120 is the first 'Joystick' button.
368 switch (button) {
369 case Qt::LeftButton: return BTN_LEFT;
370 case Qt::RightButton: return uint32_t(0x111);
371 case Qt::MiddleButton: return uint32_t(0x112);
372 case Qt::ExtraButton1: return uint32_t(0x113); // AKA Qt::BackButton, Qt::XButton1
373 case Qt::ExtraButton2: return uint32_t(0x114); // AKA Qt::ForwardButton, Qt::XButton2
374 case Qt::ExtraButton3: return uint32_t(0x115);
375 case Qt::ExtraButton4: return uint32_t(0x116);
376 case Qt::ExtraButton5: return uint32_t(0x117);
377 case Qt::ExtraButton6: return uint32_t(0x118);
378 case Qt::ExtraButton7: return uint32_t(0x119);
379 case Qt::ExtraButton8: return uint32_t(0x11a);
380 case Qt::ExtraButton9: return uint32_t(0x11b);
381 case Qt::ExtraButton10: return uint32_t(0x11c);
382 case Qt::ExtraButton11: return uint32_t(0x11d);
383 case Qt::ExtraButton12: return uint32_t(0x11e);
384 case Qt::ExtraButton13: return uint32_t(0x11f);
385 // default should not occur; but if it does, then return Wayland's highest possible button number.
386 default: return uint32_t(0x11f);
387 }
388 }
389
390 /*!
391 * \internal
392 */
enteredSurfaceDestroyed(void * data)393 void QWaylandPointer::enteredSurfaceDestroyed(void *data)
394 {
395 Q_D(QWaylandPointer);
396 Q_UNUSED(data)
397 d->enteredSurfaceDestroyListener.reset();
398 d->enteredSurface = nullptr;
399
400 d->seat->setMouseFocus(nullptr);
401
402 if (d->buttonCount != 0) {
403 d->buttonCount = 0;
404 emit buttonPressedChanged();
405 }
406 }
407
408 /*!
409 * \internal
410 */
pointerFocusChanged(QWaylandView * newFocus,QWaylandView * oldFocus)411 void QWaylandPointer::pointerFocusChanged(QWaylandView *newFocus, QWaylandView *oldFocus)
412 {
413 Q_D(QWaylandPointer);
414 Q_UNUSED(oldFocus);
415 bool wasSameSurface = newFocus && newFocus->surface() == d->enteredSurface;
416 if (d->enteredSurface && !wasSameSurface)
417 d->sendLeave();
418 }
419
420 QT_END_NAMESPACE
421