/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtWaylandCompositor module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL3$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPLv3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or later as published by the Free ** Software Foundation and appearing in the file LICENSE.GPL included in ** the packaging of this file. Please review the following information to ** ensure the GNU General Public License version 2.0 requirements will be ** met: http://www.gnu.org/licenses/gpl-2.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwaylandpointer.h" #include "qwaylandpointer_p.h" #include #include QT_BEGIN_NAMESPACE QWaylandSurfaceRole QWaylandPointerPrivate::s_role("wl_pointer"); QWaylandPointerPrivate::QWaylandPointerPrivate(QWaylandPointer *pointer, QWaylandInputDevice *seat) : QObjectPrivate() , wl_pointer() , seat(seat) , output() , focusResource() , hasSentEnter(false) , buttonCount() { Q_UNUSED(pointer); } void QWaylandPointerPrivate::pointer_destroy_resource(wl_pointer::Resource *resource) { if (focusResource == resource->handle) focusResource = 0; } void QWaylandPointerPrivate::pointer_release(wl_pointer::Resource *resource) { wl_resource_destroy(resource->handle); } void QWaylandPointerPrivate::pointer_set_cursor(wl_pointer::Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) { Q_UNUSED(resource); Q_UNUSED(serial); if (!surface) { seat->cursorSurfaceRequest(Q_NULLPTR, 0, 0); return; } QWaylandSurface *s = QWaylandSurface::fromResource(surface); // XXX FIXME // The role concept was formalized in wayland 1.7, so that release adds one error // code for each interface that implements a role, and we are supposed to pass here // the newly constructed resource and the correct error code so that if setting the // role fails, a proper error can be sent to the client. // However we're still using wayland 1.4, which doesn't have interface specific role // errors, so the best we can do is to use wl_display's object_id error. wl_resource *displayRes = wl_client_get_object(resource->client(), 1); if (s->setRole(&QWaylandPointerPrivate::s_role, displayRes, WL_DISPLAY_ERROR_INVALID_OBJECT)) { s->markAsCursorSurface(true); seat->cursorSurfaceRequest(s, hotspot_x, hotspot_y); } } /*! * \class QWaylandPointer * \inmodule QtWaylandCompositor * \brief The QWaylandPointer class provides access to a pointer device. * * This class provides access to the pointer device in a QWaylandInputDevice. It corresponds to * the Wayland interface wl_pointer. */ /*! * Constructs a QWaylandPointer for the given \a inputDevice and with the given \a parent. */ QWaylandPointer::QWaylandPointer(QWaylandInputDevice *inputDevice, QObject *parent) : QWaylandObject(* new QWaylandPointerPrivate(this, inputDevice), parent) { connect(&d_func()->focusDestroyListener, &QWaylandDestroyListener::fired, this, &QWaylandPointer::focusDestroyed); connect(inputDevice, &QWaylandInputDevice::mouseFocusChanged, this, &QWaylandPointer::pointerFocusChanged); } /*! * Returns the input device for this QWaylandPointer. */ QWaylandInputDevice *QWaylandPointer::inputDevice() const { Q_D(const QWaylandPointer); return d->seat; } /*! * Returns the compositor for this QWaylandPointer. */ QWaylandCompositor *QWaylandPointer::compositor() const { Q_D(const QWaylandPointer); return d->compositor(); } /*! * Returns the output for this QWaylandPointer. */ QWaylandOutput *QWaylandPointer::output() const { Q_D(const QWaylandPointer); return d->output; } /*! * Sets the output for this QWaylandPointer to \a output. */ void QWaylandPointer::setOutput(QWaylandOutput *output) { Q_D(QWaylandPointer); if (d->output == output) return; d->output = output; outputChanged(); } /*! * Sends a mouse press event for \a button to the view currently holding mouse focus. */ void QWaylandPointer::sendMousePressEvent(Qt::MouseButton button) { Q_D(QWaylandPointer); uint32_t time = d->compositor()->currentTimeMsecs(); d->buttonCount++; if (d->focusResource) sendButton(d->focusResource, time, button, WL_POINTER_BUTTON_STATE_PRESSED); if (d->buttonCount == 1) { emit buttonPressedChanged(); } } /*! * Sends a mouse release event for \a button to the view currently holding mouse focus. */ void QWaylandPointer::sendMouseReleaseEvent(Qt::MouseButton button) { Q_D(QWaylandPointer); uint32_t time = d->compositor()->currentTimeMsecs(); d->buttonCount--; if (d->focusResource) sendButton(d->focusResource, time, button, WL_POINTER_BUTTON_STATE_RELEASED); if (d->buttonCount == 0) emit buttonPressedChanged(); } /*! * Sets the current mouse focus to \a view and sends a mouse move event to it with the * local position \a localPos and output space position \a outputSpacePos. */ void QWaylandPointer::sendMouseMoveEvent(QWaylandView *view, const QPointF &localPos, const QPointF &outputSpacePos) { Q_D(QWaylandPointer); if (view && (!view->surface() || view->surface()->isCursorSurface())) view = Q_NULLPTR; d->seat->setMouseFocus(view); d->localPosition = localPos; d->spacePosition = outputSpacePos; //we adjust if the mouse position is on the edge //to work around Qt's event propagation if (view && view->surface()) { QSizeF size(view->surface()->size()); if (d->localPosition.x() == size.width()) d->localPosition.rx() -= 0.01; if (d->localPosition.y() == size.height()) d->localPosition.ry() -= 0.01; } QWaylandPointerPrivate::Resource *resource = view ? d->resourceMap().value(view->surface()->waylandClient()) : 0; if (resource && !d->hasSentEnter) { uint32_t serial = d->compositor()->nextSerial(); QWaylandKeyboard *keyboard = d->seat->keyboard(); if (keyboard) { keyboard->sendKeyModifiers(view->surface()->client(), serial); } d->send_enter(resource->handle, serial, view->surface()->resource(), wl_fixed_from_double(d->localPosition.x()), wl_fixed_from_double(d->localPosition.y())); d->focusDestroyListener.listenForDestruction(view->surface()->resource()); d->hasSentEnter = true; } d->focusResource = resource ? resource->handle : 0; if (view && view->output()) setOutput(view->output()); uint32_t time = d->compositor()->currentTimeMsecs(); if (d->focusResource) { wl_fixed_t x = wl_fixed_from_double(currentLocalPosition().x()); wl_fixed_t y = wl_fixed_from_double(currentLocalPosition().y()); wl_pointer_send_motion(d->focusResource, time, x, y); } } /*! * Sends a mouse wheel event with the given \a orientation and \a delta to the view that currently holds mouse focus. */ void QWaylandPointer::sendMouseWheelEvent(Qt::Orientation orientation, int delta) { Q_D(QWaylandPointer); if (!d->focusResource) return; uint32_t time = d->compositor()->currentTimeMsecs(); uint32_t axis = orientation == Qt::Horizontal ? WL_POINTER_AXIS_HORIZONTAL_SCROLL : WL_POINTER_AXIS_VERTICAL_SCROLL; d->send_axis(d->focusResource, time, axis, wl_fixed_from_int(-delta / 12)); } /*! * Returns the view that currently holds mouse focus. */ QWaylandView *QWaylandPointer::mouseFocus() const { Q_D(const QWaylandPointer); return d->seat->mouseFocus(); } /*! * Returns the current local position of the QWaylandPointer. */ QPointF QWaylandPointer::currentLocalPosition() const { Q_D(const QWaylandPointer); return d->localPosition; } /*! * Returns the current output space position of the QWaylandPointer. */ QPointF QWaylandPointer::currentSpacePosition() const { Q_D(const QWaylandPointer); return d->spacePosition; } /*! * Returns true if any button is currently pressed. Otherwise returns false. */ bool QWaylandPointer::isButtonPressed() const { Q_D(const QWaylandPointer); return d->buttonCount > 0; } /*! * \internal */ void QWaylandPointer::addClient(QWaylandClient *client, uint32_t id, uint32_t version) { Q_D(QWaylandPointer); d->add(client->client(), id, qMin(QtWaylandServer::wl_pointer::interfaceVersion(), version)); } /*! * Returns the Wayland resource for this QWaylandPointer. */ struct wl_resource *QWaylandPointer::focusResource() const { Q_D(const QWaylandPointer); if (!d->focusResource) return Q_NULLPTR; return d->focusResource; } /*! * \internal */ void QWaylandPointer::sendButton(struct wl_resource *resource, uint32_t time, Qt::MouseButton button, uint32_t state) { Q_D(QWaylandPointer); uint32_t serial = d->compositor()->nextSerial(); d->send_button(resource, serial, time, toWaylandButton(button), state); } /*! * \internal */ uint32_t QWaylandPointer::toWaylandButton(Qt::MouseButton button) { #ifndef BTN_LEFT uint32_t BTN_LEFT = 0x110; #endif // the range of valid buttons (evdev module) is from 0x110 // through 0x11f. 0x120 is the first 'Joystick' button. switch (button) { case Qt::LeftButton: return BTN_LEFT; case Qt::RightButton: return uint32_t(0x111); case Qt::MiddleButton: return uint32_t(0x112); case Qt::ExtraButton1: return uint32_t(0x113); // AKA Qt::BackButton, Qt::XButton1 case Qt::ExtraButton2: return uint32_t(0x114); // AKA Qt::ForwardButton, Qt::XButton2 case Qt::ExtraButton3: return uint32_t(0x115); case Qt::ExtraButton4: return uint32_t(0x116); case Qt::ExtraButton5: return uint32_t(0x117); case Qt::ExtraButton6: return uint32_t(0x118); case Qt::ExtraButton7: return uint32_t(0x119); case Qt::ExtraButton8: return uint32_t(0x11a); case Qt::ExtraButton9: return uint32_t(0x11b); case Qt::ExtraButton10: return uint32_t(0x11c); case Qt::ExtraButton11: return uint32_t(0x11d); case Qt::ExtraButton12: return uint32_t(0x11e); case Qt::ExtraButton13: return uint32_t(0x11f); // default should not occur; but if it does, then return Wayland's highest possible button number. default: return uint32_t(0x11f); } } /*! * \internal */ void QWaylandPointer::focusDestroyed(void *data) { Q_D(QWaylandPointer); Q_UNUSED(data) d->focusDestroyListener.reset(); d->seat->setMouseFocus(Q_NULLPTR); d->focusResource = 0; d->buttonCount = 0; } /*! * \internal */ void QWaylandPointer::pointerFocusChanged(QWaylandView *newFocus, QWaylandView *oldFocus) { Q_UNUSED(newFocus); Q_D(QWaylandPointer); d->localPosition = QPointF(); d->hasSentEnter = false; if (d->focusResource && oldFocus) { uint32_t serial = d->compositor()->nextSerial(); d->send_leave(d->focusResource, serial, oldFocus->surfaceResource()); d->focusDestroyListener.reset(); d->focusResource = 0; } } QT_END_NAMESPACE