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