File indexing completed on 2024-05-19 16:35:26

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
0004     SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 #include "seat_interface.h"
0009 #include "abstract_data_source.h"
0010 #include "datacontroldevice_v1_interface.h"
0011 #include "datacontrolsource_v1_interface.h"
0012 #include "datadevice_interface.h"
0013 #include "datadevice_interface_p.h"
0014 #include "datasource_interface.h"
0015 #include "display.h"
0016 #include "display_p.h"
0017 #include "keyboard_interface.h"
0018 #include "keyboard_interface_p.h"
0019 #include "pointer_interface.h"
0020 #include "pointer_interface_p.h"
0021 #include "pointerconstraints_v1_interface.h"
0022 #include "pointergestures_v1_interface_p.h"
0023 #include "primaryselectiondevice_v1_interface.h"
0024 #include "primaryselectionsource_v1_interface.h"
0025 #include "relativepointer_v1_interface_p.h"
0026 #include "seat_interface_p.h"
0027 #include "surface_interface.h"
0028 #include "textinput_v1_interface_p.h"
0029 #include "textinput_v2_interface_p.h"
0030 #include "textinput_v3_interface_p.h"
0031 #include "touch_interface_p.h"
0032 #include "utils.h"
0033 #include "utils/common.h"
0034 
0035 #include <linux/input.h>
0036 
0037 #include <functional>
0038 
0039 namespace KWaylandServer
0040 {
0041 static const int s_version = 8;
0042 
0043 SeatInterfacePrivate *SeatInterfacePrivate::get(SeatInterface *seat)
0044 {
0045     return seat->d.get();
0046 }
0047 
0048 SeatInterfacePrivate::SeatInterfacePrivate(SeatInterface *q, Display *display)
0049     : QtWaylandServer::wl_seat(*display, s_version)
0050     , q(q)
0051     , display(display)
0052 {
0053     textInputV1 = new TextInputV1Interface(q);
0054     textInputV2 = new TextInputV2Interface(q);
0055     textInputV3 = new TextInputV3Interface(q);
0056     pointer.reset(new PointerInterface(q));
0057     keyboard.reset(new KeyboardInterface(q));
0058     touch.reset(new TouchInterface(q));
0059 }
0060 
0061 void SeatInterfacePrivate::seat_bind_resource(Resource *resource)
0062 {
0063     send_capabilities(resource->handle, capabilities);
0064 
0065     if (resource->version() >= WL_SEAT_NAME_SINCE_VERSION) {
0066         send_name(resource->handle, name);
0067     }
0068 }
0069 
0070 void SeatInterfacePrivate::seat_get_pointer(Resource *resource, uint32_t id)
0071 {
0072     PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer.get());
0073     pointerPrivate->add(resource->client(), id, resource->version());
0074 }
0075 
0076 void SeatInterfacePrivate::seat_get_keyboard(Resource *resource, uint32_t id)
0077 {
0078     KeyboardInterfacePrivate *keyboardPrivate = KeyboardInterfacePrivate::get(keyboard.get());
0079     keyboardPrivate->add(resource->client(), id, resource->version());
0080 }
0081 
0082 void SeatInterfacePrivate::seat_get_touch(Resource *resource, uint32_t id)
0083 {
0084     TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(touch.get());
0085     touchPrivate->add(resource->client(), id, resource->version());
0086 }
0087 
0088 void SeatInterfacePrivate::seat_release(Resource *resource)
0089 {
0090     wl_resource_destroy(resource->handle);
0091 }
0092 
0093 SeatInterface::SeatInterface(Display *display, QObject *parent)
0094     : QObject(parent)
0095     , d(new SeatInterfacePrivate(this, display))
0096 {
0097     DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display);
0098     displayPrivate->seats.append(this);
0099 }
0100 
0101 SeatInterface::~SeatInterface()
0102 {
0103     if (d->display) {
0104         DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display);
0105         displayPrivate->seats.removeOne(this);
0106     }
0107 }
0108 
0109 void SeatInterfacePrivate::updatePointerButtonSerial(quint32 button, quint32 serial)
0110 {
0111     auto it = globalPointer.buttonSerials.find(button);
0112     if (it == globalPointer.buttonSerials.end()) {
0113         globalPointer.buttonSerials.insert(button, serial);
0114         return;
0115     }
0116     it.value() = serial;
0117 }
0118 
0119 void SeatInterfacePrivate::updatePointerButtonState(quint32 button, Pointer::State state)
0120 {
0121     auto it = globalPointer.buttonStates.find(button);
0122     if (it == globalPointer.buttonStates.end()) {
0123         globalPointer.buttonStates.insert(button, state);
0124         return;
0125     }
0126     it.value() = state;
0127 }
0128 
0129 QVector<DataDeviceInterface *> SeatInterfacePrivate::dataDevicesForSurface(SurfaceInterface *surface) const
0130 {
0131     if (!surface) {
0132         return {};
0133     }
0134     QVector<DataDeviceInterface *> primarySelectionDevices;
0135     for (auto it = dataDevices.constBegin(); it != dataDevices.constEnd(); ++it) {
0136         if ((*it)->client() == *surface->client()) {
0137             primarySelectionDevices << *it;
0138         }
0139     }
0140     return primarySelectionDevices;
0141 }
0142 
0143 void SeatInterfacePrivate::registerDataDevice(DataDeviceInterface *dataDevice)
0144 {
0145     Q_ASSERT(dataDevice->seat() == q);
0146     dataDevices << dataDevice;
0147     auto dataDeviceCleanup = [this, dataDevice] {
0148         dataDevices.removeOne(dataDevice);
0149         globalKeyboard.focus.selections.removeOne(dataDevice);
0150     };
0151     QObject::connect(dataDevice, &QObject::destroyed, q, dataDeviceCleanup);
0152     QObject::connect(dataDevice, &DataDeviceInterface::selectionChanged, q, [this, dataDevice] {
0153         updateSelection(dataDevice);
0154     });
0155     QObject::connect(dataDevice,
0156                      &DataDeviceInterface::dragStarted,
0157                      q,
0158                      [this](AbstractDataSource *source, SurfaceInterface *origin, quint32 serial, DragAndDropIcon *dragIcon) {
0159                          q->startDrag(source, origin, serial, dragIcon);
0160                      });
0161     // is the new DataDevice for the current keyoard focus?
0162     if (globalKeyboard.focus.surface) {
0163         // same client?
0164         if (*globalKeyboard.focus.surface->client() == dataDevice->client()) {
0165             globalKeyboard.focus.selections.append(dataDevice);
0166             if (currentSelection) {
0167                 dataDevice->sendSelection(currentSelection);
0168             }
0169         }
0170     }
0171 }
0172 
0173 KWaylandServer::AbstractDropHandler *SeatInterface::dropHandlerForSurface(SurfaceInterface *surface) const
0174 {
0175     auto list = d->dataDevicesForSurface(surface);
0176     if (list.isEmpty()) {
0177         return nullptr;
0178     };
0179     return list.first();
0180 }
0181 
0182 void SeatInterface::cancelDrag()
0183 {
0184     if (d->drag.mode != SeatInterfacePrivate::Drag::Mode::None) {
0185         // cancel the drag, don't drop. serial does not matter
0186         d->cancelDrag();
0187     }
0188 }
0189 
0190 void SeatInterfacePrivate::registerDataControlDevice(DataControlDeviceV1Interface *dataDevice)
0191 {
0192     Q_ASSERT(dataDevice->seat() == q);
0193     dataControlDevices << dataDevice;
0194     auto dataDeviceCleanup = [this, dataDevice] {
0195         dataControlDevices.removeOne(dataDevice);
0196     };
0197     QObject::connect(dataDevice, &QObject::destroyed, q, dataDeviceCleanup);
0198 
0199     QObject::connect(dataDevice, &DataControlDeviceV1Interface::selectionChanged, q, [this, dataDevice] {
0200         // Special klipper workaround to avoid a race
0201         // If the mimetype x-kde-onlyReplaceEmpty is set, and we've had another update in the meantime, do nothing
0202         // but resend selection to mimic normal event flow upon cancel and not confuse the client
0203         // See https://github.com/swaywm/wlr-protocols/issues/92
0204         if (dataDevice->selection() && dataDevice->selection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty")) && currentSelection) {
0205             dataDevice->selection()->cancel();
0206             dataDevice->sendSelection(currentSelection);
0207             return;
0208         }
0209         q->setSelection(dataDevice->selection());
0210     });
0211 
0212     QObject::connect(dataDevice, &DataControlDeviceV1Interface::primarySelectionChanged, q, [this, dataDevice] {
0213         // Special klipper workaround to avoid a race
0214         // If the mimetype x-kde-onlyReplaceEmpty is set, and we've had another update in the meantime, do nothing
0215         // but resend selection to mimic normal event flow upon cancel and not confuse the client
0216         // See https://github.com/swaywm/wlr-protocols/issues/92
0217         if (dataDevice->primarySelection() && dataDevice->primarySelection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty"))
0218             && currentPrimarySelection) {
0219             dataDevice->primarySelection()->cancel();
0220             dataDevice->sendPrimarySelection(currentPrimarySelection);
0221             return;
0222         }
0223         q->setPrimarySelection(dataDevice->primarySelection());
0224     });
0225 
0226     dataDevice->sendSelection(currentSelection);
0227     dataDevice->sendPrimarySelection(currentPrimarySelection);
0228 }
0229 
0230 void SeatInterfacePrivate::registerPrimarySelectionDevice(PrimarySelectionDeviceV1Interface *primarySelectionDevice)
0231 {
0232     Q_ASSERT(primarySelectionDevice->seat() == q);
0233 
0234     primarySelectionDevices << primarySelectionDevice;
0235     auto dataDeviceCleanup = [this, primarySelectionDevice] {
0236         primarySelectionDevices.removeOne(primarySelectionDevice);
0237         globalKeyboard.focus.primarySelections.removeOne(primarySelectionDevice);
0238     };
0239     QObject::connect(primarySelectionDevice, &QObject::destroyed, q, dataDeviceCleanup);
0240     QObject::connect(primarySelectionDevice, &PrimarySelectionDeviceV1Interface::selectionChanged, q, [this, primarySelectionDevice] {
0241         updatePrimarySelection(primarySelectionDevice);
0242     });
0243     // is the new DataDevice for the current keyoard focus?
0244     if (globalKeyboard.focus.surface) {
0245         // same client?
0246         if (*globalKeyboard.focus.surface->client() == primarySelectionDevice->client()) {
0247             globalKeyboard.focus.primarySelections.append(primarySelectionDevice);
0248             if (currentPrimarySelection) {
0249                 primarySelectionDevice->sendSelection(currentPrimarySelection);
0250             }
0251         }
0252     }
0253 }
0254 
0255 void SeatInterfacePrivate::cancelDrag()
0256 {
0257     if (drag.target) {
0258         drag.target->updateDragTarget(nullptr, 0);
0259         drag.target = nullptr;
0260     }
0261     endDrag();
0262 }
0263 
0264 void SeatInterfacePrivate::endDrag()
0265 {
0266     QObject::disconnect(drag.dragSourceDestroyConnection);
0267 
0268     AbstractDropHandler *dragTargetDevice = drag.target.data();
0269     AbstractDataSource *dragSource = drag.source;
0270     if (dragSource) {
0271         // TODO: Also check the current drag-and-drop action.
0272         if (dragTargetDevice && dragSource->isAccepted()) {
0273             Q_EMIT q->dragDropped();
0274             dragTargetDevice->drop();
0275             dragSource->dropPerformed();
0276         } else {
0277             dragSource->dndCancelled();
0278         }
0279     }
0280 
0281     if (dragTargetDevice) {
0282         dragTargetDevice->updateDragTarget(nullptr, 0);
0283     }
0284 
0285     drag = Drag();
0286     Q_EMIT q->dragSurfaceChanged();
0287     Q_EMIT q->dragEnded();
0288 }
0289 
0290 void SeatInterfacePrivate::updateSelection(DataDeviceInterface *dataDevice)
0291 {
0292     DataSourceInterface *selection = dataDevice->selection();
0293     // if the update is from the focussed window we should inform the active client
0294     if (!(globalKeyboard.focus.surface && (*globalKeyboard.focus.surface->client() == dataDevice->client()))) {
0295         if (selection) {
0296             selection->cancel();
0297         }
0298         return;
0299     }
0300     q->setSelection(selection);
0301 }
0302 
0303 void SeatInterfacePrivate::updatePrimarySelection(PrimarySelectionDeviceV1Interface *primarySelectionDevice)
0304 {
0305     PrimarySelectionSourceV1Interface *selection = primarySelectionDevice->selection();
0306     // if the update is from the focussed window we should inform the active client
0307     if (!(globalKeyboard.focus.surface && (*globalKeyboard.focus.surface->client() == primarySelectionDevice->client()))) {
0308         if (selection) {
0309             selection->cancel();
0310         }
0311         return;
0312     }
0313     q->setPrimarySelection(selection);
0314 }
0315 
0316 void SeatInterfacePrivate::sendCapabilities()
0317 {
0318     const auto seatResources = resourceMap();
0319     for (SeatInterfacePrivate::Resource *resource : seatResources) {
0320         send_capabilities(resource->handle, capabilities);
0321     }
0322 }
0323 
0324 void SeatInterface::setHasKeyboard(bool has)
0325 {
0326     if (hasKeyboard() == has) {
0327         return;
0328     }
0329     if (has) {
0330         d->capabilities |= SeatInterfacePrivate::capability_keyboard;
0331     } else {
0332         d->capabilities &= ~SeatInterfacePrivate::capability_keyboard;
0333     }
0334 
0335     d->sendCapabilities();
0336     Q_EMIT hasKeyboardChanged(has);
0337 }
0338 
0339 void SeatInterface::setHasPointer(bool has)
0340 {
0341     if (hasPointer() == has) {
0342         return;
0343     }
0344     if (has) {
0345         d->capabilities |= SeatInterfacePrivate::capability_pointer;
0346     } else {
0347         d->capabilities &= ~SeatInterfacePrivate::capability_pointer;
0348     }
0349 
0350     d->sendCapabilities();
0351     Q_EMIT hasPointerChanged(has);
0352 }
0353 
0354 void SeatInterface::setHasTouch(bool has)
0355 {
0356     if (hasTouch() == has) {
0357         return;
0358     }
0359     if (has) {
0360         d->capabilities |= SeatInterfacePrivate::capability_touch;
0361     } else {
0362         d->capabilities &= ~SeatInterfacePrivate::capability_touch;
0363     }
0364 
0365     d->sendCapabilities();
0366     Q_EMIT hasTouchChanged(has);
0367 }
0368 
0369 void SeatInterface::setName(const QString &name)
0370 {
0371     if (d->name == name) {
0372         return;
0373     }
0374     d->name = name;
0375 
0376     const auto seatResources = d->resourceMap();
0377     for (SeatInterfacePrivate::Resource *resource : seatResources) {
0378         if (resource->version() >= WL_SEAT_NAME_SINCE_VERSION) {
0379             d->send_name(resource->handle, d->name);
0380         }
0381     }
0382 
0383     Q_EMIT nameChanged(d->name);
0384 }
0385 
0386 QString SeatInterface::name() const
0387 {
0388     return d->name;
0389 }
0390 
0391 bool SeatInterface::hasPointer() const
0392 {
0393     return d->capabilities & SeatInterfacePrivate::capability_pointer;
0394 }
0395 
0396 bool SeatInterface::hasKeyboard() const
0397 {
0398     return d->capabilities & SeatInterfacePrivate::capability_keyboard;
0399 }
0400 
0401 bool SeatInterface::hasTouch() const
0402 {
0403     return d->capabilities & SeatInterfacePrivate::capability_touch;
0404 }
0405 
0406 Display *SeatInterface::display() const
0407 {
0408     return d->display;
0409 }
0410 
0411 SeatInterface *SeatInterface::get(wl_resource *native)
0412 {
0413     if (SeatInterfacePrivate *seatPrivate = resource_cast<SeatInterfacePrivate *>(native)) {
0414         return seatPrivate->q;
0415     }
0416     return nullptr;
0417 }
0418 
0419 QPointF SeatInterface::pointerPos() const
0420 {
0421     return d->globalPointer.pos;
0422 }
0423 
0424 void SeatInterface::notifyPointerMotion(const QPointF &pos)
0425 {
0426     if (!d->pointer) {
0427         return;
0428     }
0429     if (d->globalPointer.pos == pos) {
0430         return;
0431     }
0432     d->globalPointer.pos = pos;
0433     Q_EMIT pointerPosChanged(pos);
0434 
0435     SurfaceInterface *focusedSurface = focusedPointerSurface();
0436     if (!focusedSurface) {
0437         return;
0438     }
0439     if (isDragPointer()) {
0440         // data device will handle it directly
0441         // for xwayland cases we still want to send pointer events
0442         if (!d->dataDevicesForSurface(focusedSurface).isEmpty())
0443             return;
0444     }
0445     if (focusedSurface->lockedPointer() && focusedSurface->lockedPointer()->isLocked()) {
0446         return;
0447     }
0448 
0449     QPointF localPosition = focusedPointerSurfaceTransformation().map(pos);
0450     SurfaceInterface *effectiveFocusedSurface = focusedSurface->inputSurfaceAt(localPosition);
0451     if (!effectiveFocusedSurface) {
0452         effectiveFocusedSurface = focusedSurface;
0453     }
0454     if (focusedSurface != effectiveFocusedSurface) {
0455         localPosition = focusedSurface->mapToChild(effectiveFocusedSurface, localPosition);
0456     }
0457 
0458     if (d->pointer->focusedSurface() != effectiveFocusedSurface) {
0459         d->pointer->sendEnter(effectiveFocusedSurface, localPosition, display()->nextSerial());
0460     }
0461 
0462     d->pointer->sendMotion(localPosition);
0463 }
0464 
0465 std::chrono::milliseconds SeatInterface::timestamp() const
0466 {
0467     return d->timestamp;
0468 }
0469 
0470 void SeatInterface::setTimestamp(std::chrono::microseconds time)
0471 {
0472     const auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(time);
0473     if (d->timestamp == milliseconds) {
0474         return;
0475     }
0476     d->timestamp = milliseconds;
0477     Q_EMIT timestampChanged();
0478 }
0479 
0480 void SeatInterface::setDragTarget(AbstractDropHandler *dropTarget,
0481                                   SurfaceInterface *surface,
0482                                   const QPointF &globalPosition,
0483                                   const QMatrix4x4 &inputTransformation)
0484 {
0485     if (surface == d->drag.surface) {
0486         // no change
0487         return;
0488     }
0489     const quint32 serial = d->display->nextSerial();
0490     if (d->drag.target) {
0491         d->drag.target->updateDragTarget(nullptr, serial);
0492     }
0493 
0494     // TODO: technically we can have mulitple data devices
0495     // and we should send the drag to all of them, but that seems overly complicated
0496     // in practice so far the only case for mulitple data devices is for clipboard overriding
0497     d->drag.target = dropTarget;
0498 
0499     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0500         notifyPointerMotion(globalPosition);
0501         notifyPointerFrame();
0502     } else if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->globalTouch.focus.firstTouchPos != globalPosition) {
0503         notifyTouchMotion(d->globalTouch.ids.first(), globalPosition);
0504     }
0505 
0506 
0507     if (d->drag.target) {
0508         QMatrix4x4 surfaceInputTransformation = inputTransformation;
0509         surfaceInputTransformation.scale(surface->scaleOverride());
0510         d->drag.surface = surface;
0511         d->drag.transformation = surfaceInputTransformation;
0512         d->drag.target->updateDragTarget(surface, serial);
0513     } else {
0514         d->drag.surface = nullptr;
0515     }
0516     Q_EMIT dragSurfaceChanged();
0517     return;
0518 }
0519 
0520 void SeatInterface::setDragTarget(AbstractDropHandler *target, SurfaceInterface *surface, const QMatrix4x4 &inputTransformation)
0521 {
0522     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0523         setDragTarget(target, surface, pointerPos(), inputTransformation);
0524     } else {
0525         Q_ASSERT(d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch);
0526         setDragTarget(target, surface, d->globalTouch.focus.firstTouchPos, inputTransformation);
0527     }
0528 }
0529 
0530 SurfaceInterface *SeatInterface::focusedPointerSurface() const
0531 {
0532     return d->globalPointer.focus.surface;
0533 }
0534 
0535 void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QPointF &surfacePosition)
0536 {
0537     QMatrix4x4 m;
0538     m.translate(-surfacePosition.x(), -surfacePosition.y());
0539     notifyPointerEnter(surface, position, m);
0540     if (d->globalPointer.focus.surface) {
0541         d->globalPointer.focus.offset = surfacePosition;
0542     }
0543 }
0544 
0545 void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QMatrix4x4 &transformation)
0546 {
0547     if (!d->pointer) {
0548         return;
0549     }
0550     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0551         // ignore
0552         return;
0553     }
0554 
0555     const quint32 serial = d->display->nextSerial();
0556 
0557     if (d->globalPointer.focus.surface) {
0558         disconnect(d->globalPointer.focus.destroyConnection);
0559     }
0560     d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus();
0561     d->globalPointer.focus.surface = surface;
0562     d->globalPointer.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this] {
0563         d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus();
0564     });
0565     d->globalPointer.focus.serial = serial;
0566     d->globalPointer.focus.transformation = transformation;
0567     d->globalPointer.focus.offset = QPointF();
0568 
0569     d->globalPointer.pos = position;
0570     QPointF localPosition = focusedPointerSurfaceTransformation().map(position);
0571     SurfaceInterface *effectiveFocusedSurface = surface->inputSurfaceAt(localPosition);
0572     if (!effectiveFocusedSurface) {
0573         effectiveFocusedSurface = surface;
0574     }
0575     if (surface != effectiveFocusedSurface) {
0576         localPosition = surface->mapToChild(effectiveFocusedSurface, localPosition);
0577     }
0578     d->pointer->sendEnter(effectiveFocusedSurface, localPosition, serial);
0579 }
0580 
0581 void SeatInterface::notifyPointerLeave()
0582 {
0583     if (!d->pointer) {
0584         return;
0585     }
0586     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0587         // ignore
0588         return;
0589     }
0590 
0591     if (d->globalPointer.focus.surface) {
0592         disconnect(d->globalPointer.focus.destroyConnection);
0593     }
0594     d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus();
0595 
0596     const quint32 serial = d->display->nextSerial();
0597     d->pointer->sendLeave(serial);
0598 }
0599 
0600 void SeatInterface::setFocusedPointerSurfacePosition(const QPointF &surfacePosition)
0601 {
0602     if (d->globalPointer.focus.surface) {
0603         d->globalPointer.focus.offset = surfacePosition;
0604         d->globalPointer.focus.transformation = QMatrix4x4();
0605         d->globalPointer.focus.transformation.translate(-surfacePosition.x(), -surfacePosition.y());
0606     }
0607 }
0608 
0609 QPointF SeatInterface::focusedPointerSurfacePosition() const
0610 {
0611     return d->globalPointer.focus.offset;
0612 }
0613 
0614 void SeatInterface::setFocusedPointerSurfaceTransformation(const QMatrix4x4 &transformation)
0615 {
0616     if (d->globalPointer.focus.surface) {
0617         d->globalPointer.focus.transformation = transformation;
0618     }
0619 }
0620 
0621 QMatrix4x4 SeatInterface::focusedPointerSurfaceTransformation() const
0622 {
0623     return d->globalPointer.focus.transformation;
0624 }
0625 
0626 PointerInterface *SeatInterface::pointer() const
0627 {
0628     return d->pointer.get();
0629 }
0630 
0631 static quint32 qtToWaylandButton(Qt::MouseButton button)
0632 {
0633     static const QHash<Qt::MouseButton, quint32> s_buttons({
0634         {Qt::LeftButton, BTN_LEFT},
0635         {Qt::RightButton, BTN_RIGHT},
0636         {Qt::MiddleButton, BTN_MIDDLE},
0637         {Qt::ExtraButton1, BTN_BACK}, // note: QtWayland maps BTN_SIDE
0638         {Qt::ExtraButton2, BTN_FORWARD}, // note: QtWayland maps BTN_EXTRA
0639         {Qt::ExtraButton3, BTN_TASK}, // note: QtWayland maps BTN_FORWARD
0640         {Qt::ExtraButton4, BTN_EXTRA}, // note: QtWayland maps BTN_BACK
0641         {Qt::ExtraButton5, BTN_SIDE}, // note: QtWayland maps BTN_TASK
0642         {Qt::ExtraButton6, BTN_TASK + 1},
0643         {Qt::ExtraButton7, BTN_TASK + 2},
0644         {Qt::ExtraButton8, BTN_TASK + 3},
0645         {Qt::ExtraButton9, BTN_TASK + 4},
0646         {Qt::ExtraButton10, BTN_TASK + 5},
0647         {Qt::ExtraButton11, BTN_TASK + 6},
0648         {Qt::ExtraButton12, BTN_TASK + 7},
0649         {Qt::ExtraButton13, BTN_TASK + 8}
0650         // further mapping not possible, 0x120 is BTN_JOYSTICK
0651     });
0652     return s_buttons.value(button, 0);
0653 }
0654 
0655 bool SeatInterface::isPointerButtonPressed(Qt::MouseButton button) const
0656 {
0657     return isPointerButtonPressed(qtToWaylandButton(button));
0658 }
0659 
0660 bool SeatInterface::isPointerButtonPressed(quint32 button) const
0661 {
0662     auto it = d->globalPointer.buttonStates.constFind(button);
0663     if (it == d->globalPointer.buttonStates.constEnd()) {
0664         return false;
0665     }
0666     return it.value() == SeatInterfacePrivate::Pointer::State::Pressed;
0667 }
0668 
0669 void SeatInterface::notifyPointerAxis(Qt::Orientation orientation, qreal delta, qint32 deltaV120, PointerAxisSource source)
0670 {
0671     if (!d->pointer) {
0672         return;
0673     }
0674     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0675         // ignore
0676         return;
0677     }
0678     d->pointer->sendAxis(orientation, delta, deltaV120, source);
0679 }
0680 
0681 void SeatInterface::notifyPointerButton(Qt::MouseButton button, PointerButtonState state)
0682 {
0683     const quint32 nativeButton = qtToWaylandButton(button);
0684     if (nativeButton == 0) {
0685         return;
0686     }
0687     notifyPointerButton(nativeButton, state);
0688 }
0689 
0690 void SeatInterface::notifyPointerButton(quint32 button, PointerButtonState state)
0691 {
0692     if (!d->pointer) {
0693         return;
0694     }
0695     const quint32 serial = d->display->nextSerial();
0696 
0697     if (state == PointerButtonState::Pressed) {
0698         d->updatePointerButtonSerial(button, serial);
0699         d->updatePointerButtonState(button, SeatInterfacePrivate::Pointer::State::Pressed);
0700         if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0701             // ignore
0702             return;
0703         }
0704     } else {
0705         const quint32 currentButtonSerial = pointerButtonSerial(button);
0706         d->updatePointerButtonSerial(button, serial);
0707         d->updatePointerButtonState(button, SeatInterfacePrivate::Pointer::State::Released);
0708         if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
0709             if (d->drag.dragImplicitGrabSerial != currentButtonSerial) {
0710                 // not our drag button - ignore
0711                 return;
0712             }
0713             d->endDrag();
0714             return;
0715         }
0716     }
0717 
0718     d->pointer->sendButton(button, state, serial);
0719 }
0720 
0721 void SeatInterface::notifyPointerFrame()
0722 {
0723     if (!d->pointer) {
0724         return;
0725     }
0726     d->pointer->sendFrame();
0727 }
0728 
0729 quint32 SeatInterface::pointerButtonSerial(Qt::MouseButton button) const
0730 {
0731     return pointerButtonSerial(qtToWaylandButton(button));
0732 }
0733 
0734 quint32 SeatInterface::pointerButtonSerial(quint32 button) const
0735 {
0736     auto it = d->globalPointer.buttonSerials.constFind(button);
0737     if (it == d->globalPointer.buttonSerials.constEnd()) {
0738         return 0;
0739     }
0740     return it.value();
0741 }
0742 
0743 void SeatInterface::relativePointerMotion(const QPointF &delta, const QPointF &deltaNonAccelerated, std::chrono::microseconds time)
0744 {
0745     if (!d->pointer) {
0746         return;
0747     }
0748 
0749     auto relativePointer = RelativePointerV1Interface::get(pointer());
0750     if (relativePointer) {
0751         relativePointer->sendRelativeMotion(delta, deltaNonAccelerated, time);
0752     }
0753 }
0754 
0755 void SeatInterface::startPointerSwipeGesture(quint32 fingerCount)
0756 {
0757     if (!d->pointer) {
0758         return;
0759     }
0760 
0761     auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
0762     if (swipeGesture) {
0763         swipeGesture->sendBegin(d->display->nextSerial(), fingerCount);
0764     }
0765 }
0766 
0767 void SeatInterface::updatePointerSwipeGesture(const QPointF &delta)
0768 {
0769     if (!d->pointer) {
0770         return;
0771     }
0772 
0773     auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
0774     if (swipeGesture) {
0775         swipeGesture->sendUpdate(delta);
0776     }
0777 }
0778 
0779 void SeatInterface::endPointerSwipeGesture()
0780 {
0781     if (!d->pointer) {
0782         return;
0783     }
0784 
0785     auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
0786     if (swipeGesture) {
0787         swipeGesture->sendEnd(d->display->nextSerial());
0788     }
0789 }
0790 
0791 void SeatInterface::cancelPointerSwipeGesture()
0792 {
0793     if (!d->pointer) {
0794         return;
0795     }
0796 
0797     auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
0798     if (swipeGesture) {
0799         swipeGesture->sendCancel(d->display->nextSerial());
0800     }
0801 }
0802 
0803 void SeatInterface::startPointerPinchGesture(quint32 fingerCount)
0804 {
0805     if (!d->pointer) {
0806         return;
0807     }
0808 
0809     auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
0810     if (pinchGesture) {
0811         pinchGesture->sendBegin(d->display->nextSerial(), fingerCount);
0812     }
0813 }
0814 
0815 void SeatInterface::updatePointerPinchGesture(const QPointF &delta, qreal scale, qreal rotation)
0816 {
0817     if (!d->pointer) {
0818         return;
0819     }
0820 
0821     auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
0822     if (pinchGesture) {
0823         pinchGesture->sendUpdate(delta, scale, rotation);
0824     }
0825 }
0826 
0827 void SeatInterface::endPointerPinchGesture()
0828 {
0829     if (!d->pointer) {
0830         return;
0831     }
0832 
0833     auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
0834     if (pinchGesture) {
0835         pinchGesture->sendEnd(d->display->nextSerial());
0836     }
0837 }
0838 
0839 void SeatInterface::cancelPointerPinchGesture()
0840 {
0841     if (!d->pointer) {
0842         return;
0843     }
0844 
0845     auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
0846     if (pinchGesture) {
0847         pinchGesture->sendCancel(d->display->nextSerial());
0848     }
0849 }
0850 
0851 void SeatInterface::startPointerHoldGesture(quint32 fingerCount)
0852 {
0853     if (!d->pointer) {
0854         return;
0855     }
0856 
0857     auto holdGesture = PointerHoldGestureV1Interface::get(pointer());
0858     if (holdGesture) {
0859         holdGesture->sendBegin(d->display->nextSerial(), fingerCount);
0860     }
0861 }
0862 
0863 void SeatInterface::endPointerHoldGesture()
0864 {
0865     if (!d->pointer) {
0866         return;
0867     }
0868 
0869     auto holdGesture = PointerHoldGestureV1Interface::get(pointer());
0870     if (holdGesture) {
0871         holdGesture->sendEnd(d->display->nextSerial());
0872     }
0873 }
0874 
0875 void SeatInterface::cancelPointerHoldGesture()
0876 {
0877     if (!d->pointer) {
0878         return;
0879     }
0880 
0881     auto holdGesture = PointerHoldGestureV1Interface::get(pointer());
0882     if (holdGesture) {
0883         holdGesture->sendCancel(d->display->nextSerial());
0884     }
0885 }
0886 
0887 SurfaceInterface *SeatInterface::focusedKeyboardSurface() const
0888 {
0889     return d->globalKeyboard.focus.surface;
0890 }
0891 
0892 void SeatInterface::setFocusedKeyboardSurface(SurfaceInterface *surface)
0893 {
0894     if (!d->keyboard) {
0895         return;
0896     }
0897 
0898     Q_EMIT focusedKeyboardSurfaceAboutToChange(surface);
0899     const quint32 serial = d->display->nextSerial();
0900 
0901     if (d->globalKeyboard.focus.surface) {
0902         disconnect(d->globalKeyboard.focus.destroyConnection);
0903     }
0904     d->globalKeyboard.focus = SeatInterfacePrivate::Keyboard::Focus();
0905     d->globalKeyboard.focus.surface = surface;
0906 
0907     d->keyboard->setFocusedSurface(surface, serial);
0908 
0909     if (d->globalKeyboard.focus.surface) {
0910         d->globalKeyboard.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this]() {
0911             d->globalKeyboard.focus = SeatInterfacePrivate::Keyboard::Focus();
0912         });
0913         d->globalKeyboard.focus.serial = serial;
0914         // selection?
0915         const QVector<DataDeviceInterface *> dataDevices = d->dataDevicesForSurface(surface);
0916         d->globalKeyboard.focus.selections = dataDevices;
0917         for (auto dataDevice : dataDevices) {
0918             dataDevice->sendSelection(d->currentSelection);
0919         }
0920         // primary selection
0921         QVector<PrimarySelectionDeviceV1Interface *> primarySelectionDevices;
0922         for (auto it = d->primarySelectionDevices.constBegin(); it != d->primarySelectionDevices.constEnd(); ++it) {
0923             if ((*it)->client() == *surface->client()) {
0924                 primarySelectionDevices << *it;
0925             }
0926         }
0927 
0928         d->globalKeyboard.focus.primarySelections = primarySelectionDevices;
0929         for (auto primaryDataDevice : primarySelectionDevices) {
0930             primaryDataDevice->sendSelection(d->currentPrimarySelection);
0931         }
0932     }
0933 
0934     // focused text input surface follows keyboard
0935     if (hasKeyboard()) {
0936         setFocusedTextInputSurface(surface);
0937     }
0938 }
0939 
0940 KeyboardInterface *SeatInterface::keyboard() const
0941 {
0942     return d->keyboard.get();
0943 }
0944 
0945 void SeatInterface::notifyKeyboardKey(quint32 keyCode, KeyboardKeyState state)
0946 {
0947     if (!d->keyboard) {
0948         return;
0949     }
0950     d->keyboard->sendKey(keyCode, state);
0951 }
0952 
0953 void SeatInterface::notifyKeyboardModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group)
0954 {
0955     if (!d->keyboard) {
0956         return;
0957     }
0958     d->keyboard->sendModifiers(depressed, latched, locked, group);
0959 }
0960 
0961 void SeatInterface::notifyTouchCancel()
0962 {
0963     if (!d->touch) {
0964         return;
0965     }
0966     d->touch->sendCancel();
0967 
0968     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch) {
0969         // cancel the drag, don't drop. serial does not matter
0970         d->cancelDrag();
0971     }
0972     d->globalTouch.ids.clear();
0973 }
0974 
0975 SurfaceInterface *SeatInterface::focusedTouchSurface() const
0976 {
0977     return d->globalTouch.focus.surface;
0978 }
0979 
0980 QPointF SeatInterface::focusedTouchSurfacePosition() const
0981 {
0982     return d->globalTouch.focus.offset;
0983 }
0984 
0985 bool SeatInterface::isTouchSequence() const
0986 {
0987     return !d->globalTouch.ids.isEmpty();
0988 }
0989 
0990 TouchInterface *SeatInterface::touch() const
0991 {
0992     return d->touch.get();
0993 }
0994 
0995 QPointF SeatInterface::firstTouchPointPosition() const
0996 {
0997     return d->globalTouch.focus.firstTouchPos;
0998 }
0999 
1000 void SeatInterface::setFocusedTouchSurface(SurfaceInterface *surface, const QPointF &surfacePosition)
1001 {
1002     if (!d->touch) {
1003         return;
1004     }
1005     if (isTouchSequence()) {
1006         // changing surface not allowed during a touch sequence
1007         return;
1008     }
1009     if (isDragTouch()) {
1010         return;
1011     }
1012     if (d->globalTouch.focus.surface) {
1013         disconnect(d->globalTouch.focus.destroyConnection);
1014     }
1015     d->globalTouch.focus = SeatInterfacePrivate::Touch::Focus();
1016     d->globalTouch.focus.surface = surface;
1017     setFocusedTouchSurfacePosition(surfacePosition);
1018 
1019     if (d->globalTouch.focus.surface) {
1020         d->globalTouch.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this]() {
1021             if (isTouchSequence()) {
1022                 // Surface destroyed during touch sequence - send a cancel
1023                 d->touch->sendCancel();
1024             }
1025             d->globalTouch.focus = SeatInterfacePrivate::Touch::Focus();
1026         });
1027     }
1028 }
1029 
1030 void SeatInterface::setFocusedTouchSurfacePosition(const QPointF &surfacePosition)
1031 {
1032     d->globalTouch.focus.offset = surfacePosition;
1033     d->globalTouch.focus.transformation = QMatrix4x4();
1034     d->globalTouch.focus.transformation.translate(-surfacePosition.x(), -surfacePosition.y());
1035 }
1036 
1037 void SeatInterface::notifyTouchDown(qint32 id, const QPointF &globalPosition)
1038 {
1039     if (!d->touch || !focusedTouchSurface()) {
1040         return;
1041     }
1042     const qint32 serial = display()->nextSerial();
1043     auto pos = globalPosition - d->globalTouch.focus.offset;
1044 
1045     SurfaceInterface *effectiveFocusedSurface = focusedTouchSurface()->inputSurfaceAt(pos);
1046     if (effectiveFocusedSurface && effectiveFocusedSurface != focusedTouchSurface()) {
1047         pos = focusedTouchSurface()->mapToChild(effectiveFocusedSurface, pos);
1048     } else if (!effectiveFocusedSurface) {
1049         effectiveFocusedSurface = focusedTouchSurface();
1050     }
1051     d->touch->sendDown(id, serial, pos, effectiveFocusedSurface);
1052 
1053     if (id == 0) {
1054         d->globalTouch.focus.firstTouchPos = globalPosition;
1055     }
1056 
1057     if (id == 0 && hasPointer() && focusedTouchSurface()) {
1058         TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
1059         if (!touchPrivate->hasTouchesForClient(effectiveFocusedSurface->client())) {
1060             // If the client did not bind the touch interface fall back
1061             // to at least emulating touch through pointer events.
1062             d->pointer->sendEnter(effectiveFocusedSurface, pos, serial);
1063             d->pointer->sendMotion(pos);
1064             d->pointer->sendFrame();
1065         }
1066     }
1067 
1068     d->globalTouch.ids[id] = serial;
1069 }
1070 
1071 void SeatInterface::notifyTouchMotion(qint32 id, const QPointF &globalPosition)
1072 {
1073     if (!d->touch) {
1074         return;
1075     }
1076     auto itTouch = d->globalTouch.ids.constFind(id);
1077     if (itTouch == d->globalTouch.ids.constEnd()) {
1078         // This can happen in cases where the interaction started while the device was asleep
1079         qCWarning(KWIN_CORE) << "Detected a touch move that never has been down, discarding";
1080         return;
1081     }
1082 
1083     auto pos = globalPosition - d->globalTouch.focus.offset;
1084     SurfaceInterface *effectiveFocusedSurface = d->touch->focusedSurface();
1085     if (effectiveFocusedSurface && focusedTouchSurface() != effectiveFocusedSurface) {
1086         pos = focusedTouchSurface()->mapToChild(effectiveFocusedSurface, pos);
1087     }
1088 
1089     if (isDragTouch()) {
1090         // handled by DataDevice
1091     } else {
1092         d->touch->sendMotion(id, pos);
1093     }
1094 
1095     if (id == 0) {
1096         d->globalTouch.focus.firstTouchPos = globalPosition;
1097 
1098         if (hasPointer() && focusedTouchSurface()) {
1099             TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
1100             if (!touchPrivate->hasTouchesForClient(focusedTouchSurface()->client())) {
1101                 // Client did not bind touch, fall back to emulating with pointer events.
1102                 d->pointer->sendMotion(pos);
1103                 d->pointer->sendFrame();
1104             }
1105         }
1106     }
1107     Q_EMIT touchMoved(id, *itTouch, globalPosition);
1108 }
1109 
1110 void SeatInterface::notifyTouchUp(qint32 id)
1111 {
1112     if (!d->touch) {
1113         return;
1114     }
1115 
1116     auto itTouch = d->globalTouch.ids.find(id);
1117     if (itTouch == d->globalTouch.ids.end()) {
1118         // This can happen in cases where the interaction started while the device was asleep
1119         qCWarning(KWIN_CORE) << "Detected a touch that never started, discarding";
1120         return;
1121     }
1122     const qint32 serial = d->display->nextSerial();
1123     if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->drag.dragImplicitGrabSerial == d->globalTouch.ids.value(id)) {
1124         // the implicitly grabbing touch point has been upped
1125         d->endDrag();
1126     }
1127     d->touch->sendUp(id, serial);
1128 
1129     if (id == 0 && hasPointer() && focusedTouchSurface()) {
1130         TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.get());
1131         if (!touchPrivate->hasTouchesForClient(focusedTouchSurface()->client())) {
1132             // Client did not bind touch, fall back to emulating with pointer events.
1133             const quint32 serial = display()->nextSerial();
1134             d->pointer->sendButton(BTN_LEFT, PointerButtonState::Released, serial);
1135             d->pointer->sendFrame();
1136         }
1137     }
1138 
1139     d->globalTouch.ids.erase(itTouch);
1140 }
1141 
1142 void SeatInterface::notifyTouchFrame()
1143 {
1144     if (!d->touch) {
1145         return;
1146     }
1147     d->touch->sendFrame();
1148 }
1149 
1150 bool SeatInterface::hasImplicitTouchGrab(quint32 serial) const
1151 {
1152     if (!d->globalTouch.focus.surface) {
1153         // origin surface has been destroyed
1154         return false;
1155     }
1156     return d->globalTouch.ids.key(serial, -1) != -1;
1157 }
1158 
1159 bool SeatInterface::isDrag() const
1160 {
1161     return d->drag.mode != SeatInterfacePrivate::Drag::Mode::None;
1162 }
1163 
1164 bool SeatInterface::isDragPointer() const
1165 {
1166     return d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer;
1167 }
1168 
1169 bool SeatInterface::isDragTouch() const
1170 {
1171     return d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch;
1172 }
1173 
1174 bool SeatInterface::hasImplicitPointerGrab(quint32 serial) const
1175 {
1176     const auto &serials = d->globalPointer.buttonSerials;
1177     for (auto it = serials.constBegin(), end = serials.constEnd(); it != end; it++) {
1178         if (it.value() == serial) {
1179             return isPointerButtonPressed(it.key());
1180         }
1181     }
1182     return false;
1183 }
1184 
1185 QMatrix4x4 SeatInterface::dragSurfaceTransformation() const
1186 {
1187     return d->drag.transformation;
1188 }
1189 
1190 SurfaceInterface *SeatInterface::dragSurface() const
1191 {
1192     return d->drag.surface;
1193 }
1194 
1195 AbstractDataSource *SeatInterface::dragSource() const
1196 {
1197     return d->drag.source;
1198 }
1199 
1200 void SeatInterface::setFocusedTextInputSurface(SurfaceInterface *surface)
1201 {
1202     const quint32 serial = d->display->nextSerial();
1203 
1204     if (d->focusedTextInputSurface == surface) {
1205         return;
1206     }
1207 
1208     if (d->focusedTextInputSurface) {
1209         disconnect(d->focusedSurfaceDestroyConnection);
1210         d->textInputV1->d->sendLeave(d->focusedTextInputSurface);
1211         d->textInputV2->d->sendLeave(serial, d->focusedTextInputSurface);
1212         d->textInputV3->d->sendLeave(d->focusedTextInputSurface);
1213     }
1214     d->focusedTextInputSurface = surface;
1215 
1216     if (surface) {
1217         d->focusedSurfaceDestroyConnection = connect(surface, &SurfaceInterface::aboutToBeDestroyed, this, [this] {
1218             setFocusedTextInputSurface(nullptr);
1219         });
1220         d->textInputV1->d->sendEnter(surface);
1221         d->textInputV2->d->sendEnter(surface, serial);
1222         d->textInputV3->d->sendEnter(surface);
1223     }
1224 
1225     Q_EMIT focusedTextInputSurfaceChanged();
1226 }
1227 
1228 SurfaceInterface *SeatInterface::focusedTextInputSurface() const
1229 {
1230     return d->focusedTextInputSurface;
1231 }
1232 
1233 TextInputV1Interface *SeatInterface::textInputV1() const
1234 {
1235     return d->textInputV1;
1236 }
1237 
1238 TextInputV2Interface *SeatInterface::textInputV2() const
1239 {
1240     return d->textInputV2;
1241 }
1242 
1243 TextInputV3Interface *SeatInterface::textInputV3() const
1244 {
1245     return d->textInputV3;
1246 }
1247 AbstractDataSource *SeatInterface::selection() const
1248 {
1249     return d->currentSelection;
1250 }
1251 
1252 void SeatInterface::setSelection(AbstractDataSource *selection)
1253 {
1254     if (d->currentSelection == selection) {
1255         return;
1256     }
1257 
1258     if (d->currentSelection) {
1259         d->currentSelection->cancel();
1260         disconnect(d->currentSelection, nullptr, this, nullptr);
1261     }
1262 
1263     if (selection) {
1264         auto cleanup = [this]() {
1265             setSelection(nullptr);
1266         };
1267         connect(selection, &AbstractDataSource::aboutToBeDestroyed, this, cleanup);
1268     }
1269 
1270     d->currentSelection = selection;
1271 
1272     for (auto focussedSelection : std::as_const(d->globalKeyboard.focus.selections)) {
1273         focussedSelection->sendSelection(selection);
1274     }
1275 
1276     for (auto control : std::as_const(d->dataControlDevices)) {
1277         control->sendSelection(selection);
1278     }
1279 
1280     Q_EMIT selectionChanged(selection);
1281 }
1282 
1283 AbstractDataSource *SeatInterface::primarySelection() const
1284 {
1285     return d->currentPrimarySelection;
1286 }
1287 
1288 void SeatInterface::setPrimarySelection(AbstractDataSource *selection)
1289 {
1290     if (d->currentPrimarySelection == selection) {
1291         return;
1292     }
1293     if (d->currentPrimarySelection) {
1294         d->currentPrimarySelection->cancel();
1295         disconnect(d->currentPrimarySelection, nullptr, this, nullptr);
1296     }
1297 
1298     if (selection) {
1299         auto cleanup = [this]() {
1300             setPrimarySelection(nullptr);
1301         };
1302         connect(selection, &AbstractDataSource::aboutToBeDestroyed, this, cleanup);
1303     }
1304 
1305     d->currentPrimarySelection = selection;
1306 
1307     for (auto focussedSelection : std::as_const(d->globalKeyboard.focus.primarySelections)) {
1308         focussedSelection->sendSelection(selection);
1309     }
1310     for (auto control : std::as_const(d->dataControlDevices)) {
1311         control->sendPrimarySelection(selection);
1312     }
1313 
1314     Q_EMIT primarySelectionChanged(selection);
1315 }
1316 
1317 void SeatInterface::startDrag(AbstractDataSource *dragSource, SurfaceInterface *originSurface, int dragSerial, DragAndDropIcon *dragIcon)
1318 {
1319     if (hasImplicitPointerGrab(dragSerial)) {
1320         d->drag.mode = SeatInterfacePrivate::Drag::Mode::Pointer;
1321         d->drag.transformation = d->globalPointer.focus.transformation;
1322     } else if (hasImplicitTouchGrab(dragSerial)) {
1323         d->drag.mode = SeatInterfacePrivate::Drag::Mode::Touch;
1324         d->drag.transformation = d->globalTouch.focus.transformation;
1325     } else {
1326         // no implicit grab, abort drag
1327         return;
1328     }
1329     d->drag.dragImplicitGrabSerial = dragSerial;
1330 
1331     // set initial drag target to ourself
1332     d->drag.surface = originSurface;
1333 
1334     d->drag.source = dragSource;
1335     if (dragSource) {
1336         d->drag.dragSourceDestroyConnection = QObject::connect(dragSource, &AbstractDataSource::aboutToBeDestroyed, this, [this] {
1337             d->cancelDrag();
1338         });
1339     }
1340     d->drag.dragIcon = dragIcon;
1341 
1342     if (!d->dataDevicesForSurface(originSurface).isEmpty()) {
1343         d->drag.target = d->dataDevicesForSurface(originSurface)[0];
1344     }
1345     if (d->drag.target) {
1346         d->drag.target->updateDragTarget(originSurface, dragSerial);
1347     }
1348     Q_EMIT dragStarted();
1349     Q_EMIT dragSurfaceChanged();
1350 }
1351 
1352 DragAndDropIcon *SeatInterface::dragIcon() const
1353 {
1354     return d->drag.dragIcon;
1355 }
1356 }