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 }