Revision control

++ // Copyright (C) 2017 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:critical reason:network-protocol
++
++ #include "qwaylandseat.h"
++ #include "qwaylandseat_p.h"
++
++ #include "qwaylandcompositor.h"
++ #include "qwaylandinputmethodcontrol.h"
++ #include "qwaylandview.h"
++ #if QT_CONFIG(draganddrop)
++ #include <QtWaylandCompositor/QWaylandDrag>
++ #endif
++ #include <QtWaylandCompositor/QWaylandTouch>
++ #include <QtWaylandCompositor/QWaylandPointer>
++ #include <QtWaylandCompositor/QWaylandKeymap>
++ #include <QtWaylandCompositor/private/qwaylandseat_p.h>
++ #include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
++ #include <QtWaylandCompositor/private/qwaylandkeyboard_p.h>
++ #if QT_CONFIG(wayland_datadevice)
++ #include <QtWaylandCompositor/private/qwldatadevice_p.h>
++ #endif
++ #include <QtWaylandCompositor/private/qwaylandutils_p.h>
++
++ #include "extensions/qwaylandtextinput.h"
++ #include "extensions/qwaylandtextinputv3.h"
++ #include "extensions/qwaylandqttextinputmethod.h"
++
++ QT_BEGIN_NAMESPACE
++
++ int QWaylandSeatPrivate::max_name = 0;
++
++ QWaylandSeatPrivate::QWaylandSeatPrivate(QWaylandSeat *seat) :
++ #if QT_CONFIG(wayland_datadevice)
++ drag_handle(new QWaylandDrag(seat)),
++ #endif
++ keymap(new QWaylandKeymap())
++ {
++ }
++
++ QWaylandSeatPrivate::~QWaylandSeatPrivate()
++ {
++ }
++
++ void QWaylandSeatPrivate::setCapabilities(QWaylandSeat::CapabilityFlags caps)
++ {
++ Q_Q(QWaylandSeat);
++ if (capabilities != caps) {
++ QWaylandSeat::CapabilityFlags changed = caps ^ capabilities;
++
++ if (changed & QWaylandSeat::Pointer) {
++ pointer.reset(pointer.isNull() ? QWaylandCompositorPrivate::get(compositor)->callCreatePointerDevice(q) : nullptr);
++ }
++
++ if (changed & QWaylandSeat::Keyboard) {
++ keyboard.reset(keyboard.isNull() ? QWaylandCompositorPrivate::get(compositor)->callCreateKeyboardDevice(q) : nullptr);
++ }
++
++ if (changed & QWaylandSeat::Touch) {
++ touch.reset(touch.isNull() ? QWaylandCompositorPrivate::get(compositor)->callCreateTouchDevice(q) : nullptr);
++ }
++
++ capabilities = caps;
++ QList<Resource *> resources = resourceMap().values();
++ for (int i = 0; i < resources.size(); i++) {
++ wl_seat::send_capabilities(resources.at(i)->handle, (uint32_t)capabilities);
++ }
++
++ if ((changed & caps & QWaylandSeat::Keyboard) && keyboardFocus != nullptr)
++ keyboard->setFocus(keyboardFocus);
++ }
++ }
++
++ #if QT_CONFIG(wayland_datadevice)
++ void QWaylandSeatPrivate::clientRequestedDataDevice(QtWayland::DataDeviceManager *, struct wl_client *client, uint32_t id)
++ {
++ Q_Q(QWaylandSeat);
++ if (!data_device)
++ data_device.reset(new QtWayland::DataDevice(q));
++ data_device->add(client, id, 1);
++ }
++ #endif
++
++ void QWaylandSeatPrivate::seat_destroy_resource(wl_seat::Resource *)
++ {
++ // cleanupDataDeviceForClient(resource->client(), true);
++ }
++
++ void QWaylandSeatPrivate::seat_bind_resource(wl_seat::Resource *resource)
++ {
++ if (resource->version() >= WL_SEAT_NAME_SINCE_VERSION)
++ wl_seat::send_name(resource->handle, QLatin1String("seat") + QString::number(name));
++ // The order of capabilities matches the order defined in the wayland protocol
++ wl_seat::send_capabilities(resource->handle, (uint32_t)capabilities);
++ }
++
++ void QWaylandSeatPrivate::seat_get_pointer(wl_seat::Resource *resource, uint32_t id)
++ {
++ if (!pointer.isNull()) {
++ pointer->addClient(QWaylandClient::fromWlClient(compositor, resource->client()), id, resource->version());
++ }
++ }
++
++ void QWaylandSeatPrivate::seat_get_keyboard(wl_seat::Resource *resource, uint32_t id)
++ {
++ if (!keyboard.isNull()) {
++ keyboard->addClient(QWaylandClient::fromWlClient(compositor, resource->client()), id, resource->version());
++ }
++ }
++
++ void QWaylandSeatPrivate::seat_get_touch(wl_seat::Resource *resource, uint32_t id)
++ {
++ if (!touch.isNull()) {
++ touch->addClient(QWaylandClient::fromWlClient(compositor, resource->client()), id, resource->version());
++ }
++ }
++
++ /*!
++ * \qmltype WaylandSeat
++ * \nativetype QWaylandSeat
++ * \inqmlmodule QtWayland.Compositor
++ * \since 5.8
++ * \brief Provides access to keyboard, mouse, and touch input.
++ *
++ * The WaylandSeat type provides access to different types of user input and maintains
++ * a keyboard focus and a mouse pointer. It corresponds to the wl_seat interface in the Wayland
++ * protocol.
++ */
++
++ /*!
++ * \class QWaylandSeat
++ * \inmodule QtWaylandCompositor
++ * \since 5.8
++ * \brief The QWaylandSeat class provides access to keyboard, mouse, and touch input.
++ *
++ * The QWaylandSeat provides access to different types of user input and maintains
++ * a keyboard focus and a mouse pointer. It corresponds to the wl_seat interface in the Wayland protocol.
++ */
++
++ /*!
++ * \enum QWaylandSeat::CapabilityFlag
++ *
++ * This enum type describes the capabilities of a QWaylandSeat.
++ *
++ * \value Pointer The QWaylandSeat supports pointer input.
++ * \value Keyboard The QWaylandSeat supports keyboard input.
++ * \value Touch The QWaylandSeat supports touch input.
++ * \value DefaultCapabilities The QWaylandSeat has the default capabilities.
++ */
++
++ /*!
++ * Constructs a QWaylandSeat for the given \a compositor and \a capabilityFlags.
++ */
++ QWaylandSeat::QWaylandSeat(QWaylandCompositor *compositor, CapabilityFlags capabilityFlags)
++ : QWaylandObject(*new QWaylandSeatPrivate(this))
++ {
++ Q_D(QWaylandSeat);
++
++ d->name = d->max_name++;
++ d->compositor = compositor;
++ d->capabilities = capabilityFlags;
++ if (compositor->isCreated())
++ initialize();
++
++ #if QT_DEPRECATED_SINCE(6, 1)
++ // Support deprecated signal for backward compatibility
++ connect(this, &QWaylandSeat::cursorSurfaceRequested, this, &QWaylandSeat::cursorSurfaceRequest);
++ #endif
++ }
++
++ /*!
++ * Destroys the QWaylandSeat
++ */
++ QWaylandSeat::~QWaylandSeat()
++ {
++ }
++
++ /*!
++ * Initializes parts of the seat corresponding to the capabilities set in the constructor, or
++ * through setCapabilities().
++ *
++ * \note Normally, this function is called automatically after the seat and compositor have been
++ * created, so calling it manually is usually unnecessary.
++ */
++
++ void QWaylandSeat::initialize()
++ {
++ Q_D(QWaylandSeat);
++ d->init(d->compositor->display(), 4);
++
++ if (d->capabilities & QWaylandSeat::Pointer)
++ d->pointer.reset(QWaylandCompositorPrivate::get(d->compositor)->callCreatePointerDevice(this));
++ if (d->capabilities & QWaylandSeat::Touch)
++ d->touch.reset(QWaylandCompositorPrivate::get(d->compositor)->callCreateTouchDevice(this));
++ if (d->capabilities & QWaylandSeat::Keyboard)
++ d->keyboard.reset(QWaylandCompositorPrivate::get(d->compositor)->callCreateKeyboardDevice(this));
++
++ d->isInitialized = true;
++ }
++
++ /*!
++ * Returns true if the QWaylandSeat is initialized; false otherwise.
++ *
++ * The value \c true indicates that it's now possible for clients to start using the seat.
++ */
++ bool QWaylandSeat::isInitialized() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->isInitialized;
++ }
++
++ /*!
++ * Sends a mouse press event for \a button to the QWaylandSeat's pointer device.
++ */
++ void QWaylandSeat::sendMousePressEvent(Qt::MouseButton button)
++ {
++ Q_D(QWaylandSeat);
++ d->pointer->sendMousePressEvent(button);
++ }
++
++ /*!
++ * Sends a mouse release event for \a button to the QWaylandSeat's pointer device.
++ */
++ void QWaylandSeat::sendMouseReleaseEvent(Qt::MouseButton button)
++ {
++ Q_D(QWaylandSeat);
++ d->pointer->sendMouseReleaseEvent(button);
++ }
++
++ /*!
++ * Sets the mouse focus to \a view and sends a mouse move event to the pointer device with the
++ * local position \a localPos and output space position \a outputSpacePos.
++ **/
++ void QWaylandSeat::sendMouseMoveEvent(QWaylandView *view, const QPointF &localPos, const QPointF &outputSpacePos)
++ {
++ Q_D(QWaylandSeat);
++ d->pointer->sendMouseMoveEvent(view, localPos, outputSpacePos);
++ }
++
++ /*!
++ * Sends a mouse wheel event to the QWaylandSeat's pointer device with the given \a orientation and \a delta.
++ */
++ void QWaylandSeat::sendMouseWheelEvent(Qt::Orientation orientation, int delta)
++ {
++ Q_D(QWaylandSeat);
++ d->pointer->sendMouseWheelEvent(orientation, delta);
++ }
++
++ /*!
++ * Sends a key press event with the key \a code to the keyboard device.
++ */
++ void QWaylandSeat::sendKeyPressEvent(uint code)
++ {
++ Q_D(QWaylandSeat);
++ d->keyboard->sendKeyPressEvent(code);
++ }
++
++ /*!
++ * Sends a key release event with the key \a code to the keyboard device.
++ */
++ void QWaylandSeat::sendKeyReleaseEvent(uint code)
++ {
++ Q_D(QWaylandSeat);
++ d->keyboard->sendKeyReleaseEvent(code);
++ }
++
++ /*!
++ * Sends a touch point event to the \a surface on a touch device with the given
++ * \a id, \a point and \a state.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
++ * as it might lead to conflicting touch ids.
++ *
++ * Returns the serial for the touch up or touch down event.
++ */
++ uint QWaylandSeat::sendTouchPointEvent(QWaylandSurface *surface, int id, const QPointF &point, Qt::TouchPointState state)
++ {
++ Q_D(QWaylandSeat);
++
++ if (d->touch.isNull())
++ return 0;
++
++ return d->touch->sendTouchPointEvent(surface, id, point,state);
++ }
++
++ /*!
++ * \qmlmethod uint QtWayland.Compositor::WaylandSeat::sendTouchPointPressed(WaylandSurface surface, int id, point position)
++ *
++ * Sends a touch pressed event for the touch point \a id on \a surface with
++ * position \a position.
++ *
++ * \note You need to send a touch frame event when you are done sending touch
++ * events.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l WaylandQuickItem::touchEventsEnabled, as it might lead to
++ * conflicting touch ids.
++ *
++ * Returns the serial for the touch down event.
++ */
++
++ /*!
++ * Sends a touch pressed event for the touch point \a id on \a surface with
++ * position \a position.
++ *
++ * \note You need to send a touch frame event when you are done sending touch
++ * events.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
++ * as it might lead to conflicting touch ids.
++ *
++ * Returns the serial for the touch down event.
++ */
++ uint QWaylandSeat::sendTouchPointPressed(QWaylandSurface *surface, int id, const QPointF &position)
++ {
++ return sendTouchPointEvent(surface, id, position, Qt::TouchPointPressed);
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchPointReleased(WaylandSurface surface, int id, point position)
++ *
++ * Sends a touch released event for the touch point \a id on \a surface with
++ * position \a position.
++ *
++ * \note You need to send a touch frame event when you are done sending touch
++ * events.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l WaylandQuickItem::touchEventsEnabled, as it might lead to
++ * conflicting touch ids.
++ *
++ * Returns the serial for the touch up event.
++ */
++
++ /*!
++ * Sends a touch released event for the touch point \a id on \a surface with
++ * position \a position.
++ *
++ * \note You need to send a touch frame event when you are done sending touch
++ * events.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
++ * as it might lead to conflicting touch ids.
++ *
++ * Returns the serial for the touch up event.
++ */
++ uint QWaylandSeat::sendTouchPointReleased(QWaylandSurface *surface, int id, const QPointF &position)
++ {
++ return sendTouchPointEvent(surface, id, position, Qt::TouchPointReleased);
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchPointMoved(WaylandSurface surface, int id, point position)
++ *
++ * Sends a touch moved event for the touch point \a id on \a surface with
++ * position \a position.
++ *
++ * \note You need to send a touch frame event when you are done sending touch
++ * events.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l WaylandQuickItem::touchEventsEnabled, as it might lead to
++ * conflicting touch ids.
++ *
++ * Returns the serial for the touch motion event.
++ */
++
++ /*!
++ * Sends a touch moved event for the touch point \a id on \a surface with
++ * position \a position.
++ *
++ * \note You need to send a touch frame event when you are done sending touch
++ * events.
++ *
++ * \warning This API should not be used in combination with forwarding of touch
++ * events using \l QWaylandQuickItem::touchEventsEnabled or \l sendFullTouchEvent,
++ * as it might lead to conflicting touch ids.
++ *
++ * Returns the serial for the touch motion event.
++ */
++ uint QWaylandSeat::sendTouchPointMoved(QWaylandSurface *surface, int id, const QPointF &position)
++ {
++ return sendTouchPointEvent(surface, id, position, Qt::TouchPointMoved);
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchFrameEvent(WaylandClient client)
++ *
++ * Sends a frame event to the touch device of a \a client to indicate the end
++ * of a series of touch up, down, and motion events.
++ */
++
++ /*!
++ * Sends a frame event to the touch device of a \a client to indicate the end
++ * of a series of touch up, down, and motion events.
++ */
++ void QWaylandSeat::sendTouchFrameEvent(QWaylandClient *client)
++ {
++ Q_D(QWaylandSeat);
++ if (!d->touch.isNull())
++ d->touch->sendFrameEvent(client);
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendTouchCancelEvent(WaylandClient client)
++ *
++ * Sends a cancel event to the touch device of a \a client.
++ */
++
++ /*!
++ * Sends a cancel event to the touch device of a \a client.
++ */
++ void QWaylandSeat::sendTouchCancelEvent(QWaylandClient *client)
++ {
++ Q_D(QWaylandSeat);
++ if (!d->touch.isNull())
++ d->touch->sendCancelEvent(client);
++ }
++
++ /*!
++ * Sends the \a event to the specified \a surface on the touch device.
++ *
++ * \warning This API will automatically map \l QEventPoint::id() to a
++ * sequential id before sending it to the client. It should therefore not be
++ * used in combination with the other API using explicit ids, as collisions
++ * might occur.
++ */
++ void QWaylandSeat::sendFullTouchEvent(QWaylandSurface *surface, QTouchEvent *event)
++ {
++ Q_D(QWaylandSeat);
++
++ if (!d->touch)
++ return;
++
++ d->touch->sendFullTouchEvent(surface, event);
++ }
++
++ /*!
++ * Sends the \a event to the keyboard device.
++ *
++ * \note The \a event should correspond to an actual keyboard key in the current mapping.
++ * For example, \c Qt::Key_Exclam is normally not a separate key: with most keyboards the
++ * exclamation mark is produced with Shift + 1. In that case, to send an exclamation mark
++ * key press event, use \c{QKeyEvent(QEvent::KeyPress, Qt::Key_1, Qt::ShiftModifier)}.
++ */
++ void QWaylandSeat::sendFullKeyEvent(QKeyEvent *event)
++ {
++ Q_D(QWaylandSeat);
++
++ if (!keyboardFocus()) {
++ qWarning("Cannot send key event, no keyboard focus, fix the compositor");
++ return;
++ }
++
++ #if QT_CONFIG(im)
++ if (keyboardFocus()->inputMethodControl()->enabled()
++ && event->nativeScanCode() == 0) {
++ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV2)) {
++ QWaylandTextInput *textInput = QWaylandTextInput::findIn(this);
++ if (textInput) {
++ textInput->sendKeyEvent(event);
++ return;
++ }
++ }
++
++ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::QtTextInputMethodV1)) {
++ QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(this);
++ if (textInputMethod) {
++ textInputMethod->sendKeyEvent(event);
++ return;
++ }
++ }
++
++ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV3)) {
++ QWaylandTextInputV3 *textInputV3 = QWaylandTextInputV3::findIn(this);
++ if (textInputV3 && !event->text().isEmpty()) {
++ // it will just commit the text for text-input-unstable-v3 when keyPress
++ if (event->type() == QEvent::KeyPress)
++ textInputV3->sendKeyEvent(event);
++ return;
++ }
++ }
++ }
++ #endif
++
++ if (!d->keyboard.isNull() && !event->isAutoRepeat()) {
++
++ uint scanCode = event->nativeScanCode();
++ if (scanCode == 0)
++ scanCode = d->keyboard->keyToScanCode(event->key());
++
++ if (scanCode == 0) {
++ qWarning() << "Can't send Wayland key event: Unable to get a valid scan code";
++ return;
++ }
++
++ if (event->type() == QEvent::KeyPress) {
++ QWaylandKeyboardPrivate::get(d->keyboard.data())->checkAndRepairModifierState(event);
++ d->keyboard->sendKeyPressEvent(scanCode);
++ } else if (event->type() == QEvent::KeyRelease) {
++ d->keyboard->sendKeyReleaseEvent(scanCode);
++ }
++ }
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendKeyEvent(int qtKey, bool pressed)
++ * \since 5.12
++ *
++ * Sends a key press (if \a pressed is \c true) or release (if \a pressed is \c false)
++ * event of a key \a qtKey to the keyboard device.
++ */
++
++ /*!
++ * Sends a key press (if \a pressed is \c true) or release (if \a pressed is \c false)
++ * event of a key \a qtKey to the keyboard device.
++ *
++ * \note This function does not support key events that require modifiers, such as \c Qt::Key_Exclam.
++ * Use \l{sendFullKeyEvent} instead.
++ *
++ * \since 5.12
++ */
++ void QWaylandSeat::sendKeyEvent(int qtKey, bool pressed)
++ {
++ Q_D(QWaylandSeat);
++ if (!keyboardFocus()) {
++ qWarning("Cannot send Wayland key event, no keyboard focus, fix the compositor");
++ return;
++ }
++
++ if (auto scanCode = d->keyboard->keyToScanCode(qtKey)) {
++ if (pressed)
++ d->keyboard->sendKeyPressEvent(scanCode);
++ else
++ d->keyboard->sendKeyReleaseEvent(scanCode);
++ } else {
++ qWarning() << "Can't send Wayland key event: Unable to get scan code for" << Qt::Key(qtKey);
++ }
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendUnicodeKeyPressEvent(uint unicode)
++ * \since 6.7
++ *
++ * Sends a key press event of a UCS4 \a unicode through a text-input protocol.
++ *
++ * \note This function will not work properly if the client does not support the
++ * text-input protocol that the compositor supports.
++ */
++
++ /*!
++ * Sends a key press event of a UCS4 \a unicode through a text-input protocol.
++ *
++ * \note This function will not work properly if the client does not support the
++ * text-input protocol that the compositor supports.
++ *
++ * \sa {sendFullKeyEvent} {sendKeyEvent}
++ *
++ * \since 6.7
++ */
++ void QWaylandSeat::sendUnicodeKeyPressEvent(uint unicode)
++ {
++ sendUnicodeKeyEvent(unicode, QEvent::KeyPress);
++ }
++
++ /*!
++ * \qmlmethod void QtWayland.Compositor::WaylandSeat::sendUnicodeKeyReleaseEvent(uint unicode)
++ * \since 6.7
++ *
++ * Sends a key release event of a UCS4 \a unicode through a text-input protocol.
++ *
++ * \note This function will not work properly if the client does not support the
++ * text-input protocol that the compositor supports.
++ */
++
++ /*!
++ * Sends a key release event of a UCS4 \a unicode through a text-input protocol.
++ *
++ * \note This function will not work properly if the client does not support the
++ * text-input protocol that the compositor supports.
++ *
++ * \sa {sendFullKeyEvent} {sendKeyEvent}
++ *
++ * \since 6.7
++ */
++ void QWaylandSeat::sendUnicodeKeyReleaseEvent(uint unicode)
++ {
++ sendUnicodeKeyEvent(unicode, QEvent::KeyRelease);
++ }
++
++ /*!
++ * \internal
++ *
++ * Sends an \a eventType for the UCS4 \a unicode through a text-input protocol.
++ */
++ void QWaylandSeat::sendUnicodeKeyEvent(uint unicode, QEvent::Type eventType)
++ {
++ if (!keyboardFocus()) {
++ qWarning("Can't send a unicode key event, no keyboard focus, fix the compositor");
++ return;
++ }
++ #if QT_CONFIG(im)
++ QString text;
++ text += QChar::fromUcs4(static_cast<char32_t>(unicode));
++
++ QKeyEvent event(eventType, Qt::Key_unknown, Qt::KeyboardModifiers{}, text);
++ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV2)) {
++ QWaylandTextInput *textInput = QWaylandTextInput::findIn(this);
++ if (textInput) {
++ textInput->sendKeyEvent(&event);
++ return;
++ }
++ }
++
++ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::QtTextInputMethodV1)) {
++ QWaylandQtTextInputMethod *textInputMethod = QWaylandQtTextInputMethod::findIn(this);
++ if (textInputMethod) {
++ textInputMethod->sendKeyEvent(&event);
++ return;
++ }
++ }
++
++ if (keyboardFocus()->client()->textInputProtocols().testFlag(QWaylandClient::TextInputProtocol::TextInputV3)) {
++ QWaylandTextInputV3 *textInputV3 = QWaylandTextInputV3::findIn(this);
++ if (textInputV3 && !text.isEmpty()) {
++ // it will just commit the text for text-input-unstable-v3 when keyPress
++ if (eventType == QEvent::KeyPress)
++ textInputV3->sendKeyEvent(&event);
++ return;
++ }
++ }
++ #else
++ Q_UNUSED(unicode);
++ Q_UNUSED(eventType);
++ qWarning() << "Can't send a unicode key event: Unable to find a text-input protocol.";
++ #endif
++ }
++
++ /*!
++ * Returns the keyboard for this input device.
++ */
++ QWaylandKeyboard *QWaylandSeat::keyboard() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->keyboard.data();
++ }
++
++ /*!
++ * Returns the current focused surface for keyboard input.
++ */
++ QWaylandSurface *QWaylandSeat::keyboardFocus() const
++ {
++ Q_D(const QWaylandSeat);
++ if (d->keyboard.isNull() || !d->keyboard->focus())
++ return nullptr;
++
++ return d->keyboard->focus();
++ }
++
++ /*!
++ * Sets the current keyboard focus to \a surface.
++ * Returns a boolean indicating if the operation
++ * was successful.
++ */
++ bool QWaylandSeat::setKeyboardFocus(QWaylandSurface *surface)
++ {
++ Q_D(QWaylandSeat);
++ if (surface && surface->isDestroyed())
++ return false;
++
++ QWaylandSurface *oldSurface = keyboardFocus();
++ if (surface == oldSurface)
++ return true;
++
++ d->keyboardFocus = surface;
++ if (!d->keyboard.isNull())
++ d->keyboard->setFocus(surface);
++ #if QT_CONFIG(wayland_datadevice)
++ if (d->data_device)
++ d->data_device->setFocus(surface ? surface->client() : nullptr);
++ #endif
++ emit keyboardFocusChanged(surface, oldSurface);
++ return true;
++ }
++
++
++ /*!
++ * Returns the keymap object for this QWaylandSeat.
++ */
++
++ QWaylandKeymap *QWaylandSeat::keymap()
++ {
++ Q_D(const QWaylandSeat);
++ return d->keymap.data();
++ }
++
++ /*!
++ * Returns the pointer device for this QWaylandSeat.
++ */
++ QWaylandPointer *QWaylandSeat::pointer() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->pointer.data();
++ }
++
++ /*!
++ * Returns the touch device for this QWaylandSeat.
++ */
++ QWaylandTouch *QWaylandSeat::touch() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->touch.data();
++ }
++
++ /*!
++ * Returns the view that currently has mouse focus.
++ */
++ QWaylandView *QWaylandSeat::mouseFocus() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->mouseFocus;
++ }
++
++ /*!
++ * Sets the current mouse focus to \a view.
++ */
++ void QWaylandSeat::setMouseFocus(QWaylandView *view)
++ {
++ Q_D(QWaylandSeat);
++ if (view == d->mouseFocus)
++ return;
++
++ QWaylandView *oldFocus = d->mouseFocus;
++ d->mouseFocus = view;
++
++ if (oldFocus)
++ disconnect(oldFocus, &QObject::destroyed, this, &QWaylandSeat::handleMouseFocusDestroyed);
++ if (d->mouseFocus)
++ connect(d->mouseFocus, &QObject::destroyed, this, &QWaylandSeat::handleMouseFocusDestroyed);
++
++ emit mouseFocusChanged(d->mouseFocus, oldFocus);
++ }
++
++ /*!
++ * Returns the compositor for this QWaylandSeat.
++ */
++ QWaylandCompositor *QWaylandSeat::compositor() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->compositor;
++ }
++
++ /*!
++ * Returns the drag object for this QWaylandSeat.
++ */
++ #if QT_CONFIG(draganddrop)
++ QWaylandDrag *QWaylandSeat::drag() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->drag_handle.data();
++ }
++ #endif
++
++ /*!
++ * Returns the capability flags for this QWaylandSeat.
++ */
++ QWaylandSeat::CapabilityFlags QWaylandSeat::capabilities() const
++ {
++ Q_D(const QWaylandSeat);
++ return d->capabilities;
++ }
++
++ /*!
++ * \internal
++ */
++ bool QWaylandSeat::isOwner(QInputEvent *inputEvent) const
++ {
++ Q_UNUSED(inputEvent);
++ return true;
++ }
++
++ /*!
++ * Returns the QWaylandSeat corresponding to the \a resource. The \a resource is expected
++ * to have the type wl_seat.
++ */
++ QWaylandSeat *QWaylandSeat::fromSeatResource(struct ::wl_resource *resource)
++ {
++ if (auto p = QtWayland::fromResource<QWaylandSeatPrivate *>(resource))
++ return p->q_func();
++ return nullptr;
++ }
++
++ /*!
++ * \fn void QWaylandSeat::mouseFocusChanged(QWaylandView *newFocus, QWaylandView *oldFocus)
++ *
++ * This signal is emitted when the mouse focus has changed from \a oldFocus to \a newFocus.
++ */
++
++ void QWaylandSeat::handleMouseFocusDestroyed()
++ {
++ // This is triggered when the QWaylandView is destroyed, NOT the surface.
++ // ... so this is for the rare case when the view that currently holds the mouse focus is
++ // destroyed before its surface
++ Q_D(QWaylandSeat);
++ d->mouseFocus = nullptr;
++ QWaylandView *oldFocus = nullptr; // we have to send nullptr because the old focus is already destroyed at this point
++ emit mouseFocusChanged(d->mouseFocus, oldFocus);
++ }
++
++
++ /*! \qmlsignal void QtWayland.Compositor::WaylandSeat::keyboardFocusChanged(QWaylandSurface newFocus, QWaylandSurface oldFocus)
++ *
++ * This signal is emitted when setKeyboardFocus() is called or when a WaylandQuickItem has focus
++ * and the user starts pressing keys.
++ *
++ * \a newFocus has the surface that received keyboard focus; or \c nullptr if no surface has
++ * focus.
++ * \a oldFocus has the surface that lost keyboard focus; or \c nullptr if no surface had focus.
++ */
++
++ /*!
++ * \fn void QWaylandSeat::keyboardFocusChanged(QWaylandSurface *newFocus, QWaylandSurface *oldFocus)
++ *
++ * This signal is emitted when setKeyboardFocus() is called.
++ *
++ * \a newFocus has the surface that received keyboard focus; or \c nullptr if no surface has
++ * focus.
++ * \a oldFocus has the surface that lost keyboard focus; or \c nullptr if no surface had focus.
++ */
++
++ /*! \qmlsignal void QtWayland.Compositor::WaylandSeat::cursorSurfaceRequest(QWaylandSurface surface, int hotspotX, int hotspotY)
++ *
++ * This signal is emitted when the client has requested for a specific \a surface to be the mouse
++ * cursor. For example, when the user hovers over a particular surface, and you want the cursor
++ * to change into a resize arrow.
++ *
++ * Both \a hotspotX and \a hotspotY are offsets from the top-left of a pointer surface, where a
++ * click should happen. For example, if the requested cursor surface is an arrow, the parameters
++ * indicate where the arrow's tip is, on that surface.
++ */
++
++
++ /*!
++ * \fn void QWaylandSeat::cursorSurfaceRequest(QWaylandSurface *surface, int hotspotX, int hotspotY)
++ *
++ * This signal is emitted when the client has requested for a specific \a surface to be the mouse
++ * cursor. For example, when the user hovers over a particular surface, and you want the cursor
++ * to change into a resize arrow.
++ *
++ * Both \a hotspotX and \a hotspotY are offsets from the top-left of a pointer surface, where a
++ * click should happen. For example, if the requested cursor surface is an arrow, the parameters
++ * indicate where the arrow's tip is, on that surface.
++ */
++
++ /*!
++ * \property QWaylandSeat::drag
++ *
++ * This property holds the drag and drop operations and sends signals when they start and end.
++ * The property stores details like what image should be under the mouse cursor when the user
++ * drags it.
++ */
++
++ /*!
++ * \property QWaylandSeat::keymap
++ * This property holds the keymap object.
++ *
++ * A keymap provides a way to translate actual key scan codes into a meaningful value.
++ * For example, if you use a keymap with a Norwegian layout, the key to the right of
++ * the letter L produces an Ø.
++ *
++ * Keymaps can also be used to customize key functions, such as to specify whether
++ * Control and CAPS lock should be swapped, and so on.
++ */
++
++ QT_END_NAMESPACE
++
++ #include "moc_qwaylandseat.cpp"