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"