File indexing completed on 2024-11-10 04:57:32

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