KWaylandServer

seat_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3  SPDX-FileCopyrightText: 2020 David Edmundson <[email protected]>
4  SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 #include "seat_interface.h"
9 #include "abstract_data_source.h"
10 #include "datacontroldevice_v1_interface.h"
11 #include "datacontrolsource_v1_interface.h"
12 #include "datadevice_interface.h"
13 #include "datadevice_interface_p.h"
14 #include "datasource_interface.h"
15 #include "display.h"
16 #include "display_p.h"
17 #include "keyboard_interface.h"
18 #include "keyboard_interface_p.h"
19 #include "logging.h"
20 #include "pointer_interface.h"
21 #include "pointer_interface_p.h"
22 #include "pointerconstraints_v1_interface.h"
23 #include "pointergestures_v1_interface_p.h"
24 #include "primaryselectiondevice_v1_interface.h"
25 #include "primaryselectionsource_v1_interface.h"
26 #include "relativepointer_v1_interface_p.h"
27 #include "seat_interface_p.h"
28 #include "surface_interface.h"
29 #include "textinput_v2_interface_p.h"
30 #include "textinput_v3_interface_p.h"
31 #include "touch_interface_p.h"
32 #include "utils.h"
33 // linux
34 #include <config-kwaylandserver.h>
35 #if HAVE_LINUX_INPUT_H
36 #include <linux/input.h>
37 #endif
38 
39 #include <functional>
40 
41 namespace KWaylandServer
42 {
43 static const int s_version = 7;
44 
45 SeatInterfacePrivate *SeatInterfacePrivate::get(SeatInterface *seat)
46 {
47  return seat->d.data();
48 }
49 
50 SeatInterfacePrivate::SeatInterfacePrivate(SeatInterface *q, Display *display)
51  : QtWaylandServer::wl_seat(*display, s_version)
52  , q(q)
53  , display(display)
54 {
55  textInputV2 = new TextInputV2Interface(q);
56  textInputV3 = new TextInputV3Interface(q);
57 }
58 
59 void SeatInterfacePrivate::seat_bind_resource(Resource *resource)
60 {
61  send_capabilities(resource->handle, capabilities);
62 
63  if (resource->version() >= WL_SEAT_NAME_SINCE_VERSION) {
64  send_name(resource->handle, name);
65  }
66 }
67 
68 void SeatInterfacePrivate::seat_get_pointer(Resource *resource, uint32_t id)
69 {
70  if (!(accumulatedCapabilities & capability_pointer)) {
71  wl_resource_post_error(resource->handle, 0, "wl_pointer capability is missing");
72  return;
73  }
74  if (pointer) {
75  PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer.data());
76  pointerPrivate->add(resource->client(), id, resource->version());
77  }
78 }
79 
80 void SeatInterfacePrivate::seat_get_keyboard(Resource *resource, uint32_t id)
81 {
82  if (!(accumulatedCapabilities & capability_keyboard)) {
83  wl_resource_post_error(resource->handle, 0, "wl_keyboard capability is missing");
84  return;
85  }
86  if (keyboard) {
87  KeyboardInterfacePrivate *keyboardPrivate = KeyboardInterfacePrivate::get(keyboard.data());
88  keyboardPrivate->add(resource->client(), id, resource->version());
89  }
90 }
91 
92 void SeatInterfacePrivate::seat_get_touch(Resource *resource, uint32_t id)
93 {
94  if (!(accumulatedCapabilities & capability_touch)) {
95  wl_resource_post_error(resource->handle, 0, "wl_touch capability is missing");
96  return;
97  }
98  if (touch) {
99  TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(touch.data());
100  touchPrivate->add(resource->client(), id, resource->version());
101  }
102 }
103 
104 void SeatInterfacePrivate::seat_release(Resource *resource)
105 {
106  wl_resource_destroy(resource->handle);
107 }
108 
109 SeatInterface::SeatInterface(Display *display, QObject *parent)
110  : QObject(parent)
111  , d(new SeatInterfacePrivate(this, display))
112 {
113  DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display);
114  displayPrivate->seats.append(this);
115 }
116 
117 SeatInterface::~SeatInterface()
118 {
119  if (d->display) {
120  DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display);
121  displayPrivate->seats.removeOne(this);
122  }
123 }
124 
125 void SeatInterfacePrivate::updatePointerButtonSerial(quint32 button, quint32 serial)
126 {
127  auto it = globalPointer.buttonSerials.find(button);
128  if (it == globalPointer.buttonSerials.end()) {
129  globalPointer.buttonSerials.insert(button, serial);
130  return;
131  }
132  it.value() = serial;
133 }
134 
135 void SeatInterfacePrivate::updatePointerButtonState(quint32 button, Pointer::State state)
136 {
137  auto it = globalPointer.buttonStates.find(button);
138  if (it == globalPointer.buttonStates.end()) {
139  globalPointer.buttonStates.insert(button, state);
140  return;
141  }
142  it.value() = state;
143 }
144 
145 QVector<DataDeviceInterface *> SeatInterfacePrivate::dataDevicesForSurface(SurfaceInterface *surface) const
146 {
147  if (!surface) {
148  return {};
149  }
150  QVector<DataDeviceInterface *> primarySelectionDevices;
151  for (auto it = dataDevices.constBegin(); it != dataDevices.constEnd(); ++it) {
152  if ((*it)->client() == *surface->client()) {
153  primarySelectionDevices << *it;
154  }
155  }
156  return primarySelectionDevices;
157 }
158 
159 void SeatInterfacePrivate::registerDataDevice(DataDeviceInterface *dataDevice)
160 {
161  Q_ASSERT(dataDevice->seat() == q);
162  dataDevices << dataDevice;
163  auto dataDeviceCleanup = [this, dataDevice] {
164  dataDevices.removeOne(dataDevice);
165  globalKeyboard.focus.selections.removeOne(dataDevice);
166  };
167  QObject::connect(dataDevice, &QObject::destroyed, q, dataDeviceCleanup);
168  QObject::connect(dataDevice, &DataDeviceInterface::selectionChanged, q, [this, dataDevice] {
169  updateSelection(dataDevice);
170  });
171  QObject::connect(dataDevice, &DataDeviceInterface::selectionCleared, q, [this, dataDevice] {
172  updateSelection(dataDevice);
173  });
174  QObject::connect(dataDevice,
175  &DataDeviceInterface::dragStarted,
176  q,
177  [this](AbstractDataSource *source, SurfaceInterface *origin, quint32 serial, DragAndDropIcon *dragIcon) {
178  q->startDrag(source, origin, serial, dragIcon);
179  });
180  // is the new DataDevice for the current keyoard focus?
181  if (globalKeyboard.focus.surface) {
182  // same client?
183  if (*globalKeyboard.focus.surface->client() == dataDevice->client()) {
184  globalKeyboard.focus.selections.append(dataDevice);
185  if (currentSelection) {
186  dataDevice->sendSelection(currentSelection);
187  }
188  }
189  }
190 }
191 
192 KWaylandServer::AbstractDropHandler *SeatInterface::dropHandlerForSurface(SurfaceInterface *surface) const
193 {
194  auto list = d->dataDevicesForSurface(surface);
195  if (list.isEmpty()) {
196  return nullptr;
197  };
198  return list.first();
199 }
200 
201 void SeatInterfacePrivate::registerDataControlDevice(DataControlDeviceV1Interface *dataDevice)
202 {
203  Q_ASSERT(dataDevice->seat() == q);
204  dataControlDevices << dataDevice;
205  auto dataDeviceCleanup = [this, dataDevice] {
206  dataControlDevices.removeOne(dataDevice);
207  };
208  QObject::connect(dataDevice, &QObject::destroyed, q, dataDeviceCleanup);
209 
210  QObject::connect(dataDevice, &DataControlDeviceV1Interface::selectionChanged, q, [this, dataDevice] {
211  // Special klipper workaround to avoid a race
212  // If the mimetype x-kde-onlyReplaceEmpty is set, and we've had another update in the meantime, do nothing
213  // See https://github.com/swaywm/wlr-protocols/issues/92
214  if (dataDevice->selection() && dataDevice->selection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty")) && currentSelection) {
215  dataDevice->selection()->cancel();
216  return;
217  }
218  q->setSelection(dataDevice->selection());
219  });
220 
221  QObject::connect(dataDevice, &DataControlDeviceV1Interface::selectionCleared, q, [this, dataDevice] {
222  Q_UNUSED(dataDevice);
223  q->setSelection(nullptr);
224  });
225 
226  QObject::connect(dataDevice, &DataControlDeviceV1Interface::primarySelectionChanged, q, [this, dataDevice] {
227  // Special klipper workaround to avoid a race
228  // If the mimetype x-kde-onlyReplaceEmpty is set, and we've had another update in the meantime, do nothing
229  // See https://github.com/swaywm/wlr-protocols/issues/92
230  if (dataDevice->primarySelection() && dataDevice->primarySelection()->mimeTypes().contains(QLatin1String("application/x-kde-onlyReplaceEmpty"))
231  && currentPrimarySelection) {
232  dataDevice->primarySelection()->cancel();
233  return;
234  }
235  q->setPrimarySelection(dataDevice->primarySelection());
236  });
237 
238  if (currentSelection) {
239  dataDevice->sendSelection(currentSelection);
240  }
241  if (currentPrimarySelection) {
242  dataDevice->sendPrimarySelection(currentPrimarySelection);
243  }
244 }
245 
246 void SeatInterfacePrivate::registerPrimarySelectionDevice(PrimarySelectionDeviceV1Interface *primarySelectionDevice)
247 {
248  Q_ASSERT(primarySelectionDevice->seat() == q);
249 
250  primarySelectionDevices << primarySelectionDevice;
251  auto dataDeviceCleanup = [this, primarySelectionDevice] {
252  primarySelectionDevices.removeOne(primarySelectionDevice);
253  globalKeyboard.focus.primarySelections.removeOne(primarySelectionDevice);
254  };
255  QObject::connect(primarySelectionDevice, &QObject::destroyed, q, dataDeviceCleanup);
256  QObject::connect(primarySelectionDevice, &PrimarySelectionDeviceV1Interface::selectionChanged, q, [this, primarySelectionDevice] {
257  updatePrimarySelection(primarySelectionDevice);
258  });
259  QObject::connect(primarySelectionDevice, &PrimarySelectionDeviceV1Interface::selectionCleared, q, [this, primarySelectionDevice] {
260  updatePrimarySelection(primarySelectionDevice);
261  });
262  // is the new DataDevice for the current keyoard focus?
263  if (globalKeyboard.focus.surface) {
264  // same client?
265  if (*globalKeyboard.focus.surface->client() == primarySelectionDevice->client()) {
266  globalKeyboard.focus.primarySelections.append(primarySelectionDevice);
267  if (currentPrimarySelection) {
268  primarySelectionDevice->sendSelection(currentPrimarySelection);
269  }
270  }
271  }
272 }
273 
274 void SeatInterfacePrivate::cancelDrag(quint32 serial)
275 {
276  if (drag.target) {
277  drag.target->updateDragTarget(nullptr, serial);
278  drag.target = nullptr;
279  }
280  endDrag(serial);
281 }
282 
283 void SeatInterfacePrivate::endDrag(quint32 serial)
284 {
285  QObject::disconnect(drag.dragSourceDestroyConnection);
286 
287  AbstractDropHandler *dragTargetDevice = drag.target.data();
288  AbstractDataSource *dragSource = drag.source;
289  if (dragSource) {
290  // TODO: Also check the current drag-and-drop action.
291  if (dragTargetDevice && dragSource->isAccepted()) {
292  Q_EMIT q->dragDropped();
293  dragTargetDevice->drop();
294  dragSource->dropPerformed();
295  } else {
296  dragSource->dndCancelled();
297  }
298  }
299 
300  if (dragTargetDevice) {
301  dragTargetDevice->updateDragTarget(nullptr, serial);
302  }
303 
304  drag = Drag();
305  Q_EMIT q->dragSurfaceChanged();
306  Q_EMIT q->dragEnded();
307 }
308 
309 void SeatInterfacePrivate::updateSelection(DataDeviceInterface *dataDevice)
310 {
311  // if the update is from the focussed window we should inform the active client
312  if (!(globalKeyboard.focus.surface && (*globalKeyboard.focus.surface->client() == dataDevice->client()))) {
313  return;
314  }
315  q->setSelection(dataDevice->selection());
316 }
317 
318 void SeatInterfacePrivate::updatePrimarySelection(PrimarySelectionDeviceV1Interface *primarySelectionDevice)
319 {
320  // if the update is from the focussed window we should inform the active client
321  if (!(globalKeyboard.focus.surface && (*globalKeyboard.focus.surface->client() == primarySelectionDevice->client()))) {
322  return;
323  }
324  q->setPrimarySelection(primarySelectionDevice->selection());
325 }
326 
327 void SeatInterfacePrivate::sendCapabilities()
328 {
329  const auto seatResources = resourceMap();
330  for (SeatInterfacePrivate::Resource *resource : seatResources) {
331  send_capabilities(resource->handle, capabilities);
332  }
333 }
334 
335 void SeatInterface::setHasKeyboard(bool has)
336 {
337  if (d->keyboard.isNull() != has) {
338  return;
339  }
340  if (has) {
341  d->capabilities |= SeatInterfacePrivate::capability_keyboard;
342  d->keyboard.reset(new KeyboardInterface(this));
343  } else {
344  d->capabilities &= ~SeatInterfacePrivate::capability_keyboard;
345  d->keyboard.reset();
346  }
347  d->accumulatedCapabilities |= d->capabilities;
348 
349  d->sendCapabilities();
350  Q_EMIT hasKeyboardChanged(d->keyboard);
351 }
352 
353 void SeatInterface::setHasPointer(bool has)
354 {
355  if (d->pointer.isNull() != has) {
356  return;
357  }
358  if (has) {
359  d->capabilities |= SeatInterfacePrivate::capability_pointer;
360  d->pointer.reset(new PointerInterface(this));
361  } else {
362  d->capabilities &= ~SeatInterfacePrivate::capability_pointer;
363  d->pointer.reset();
364  }
365  d->accumulatedCapabilities |= d->capabilities;
366 
367  d->sendCapabilities();
368  Q_EMIT hasPointerChanged(d->pointer);
369 }
370 
371 void SeatInterface::setHasTouch(bool has)
372 {
373  if (d->touch.isNull() != has) {
374  return;
375  }
376  if (has) {
377  d->capabilities |= SeatInterfacePrivate::capability_touch;
378  d->touch.reset(new TouchInterface(this));
379  } else {
380  d->capabilities &= ~SeatInterfacePrivate::capability_touch;
381  d->touch.reset();
382  }
383  d->accumulatedCapabilities |= d->capabilities;
384 
385  d->sendCapabilities();
386  Q_EMIT hasTouchChanged(d->touch);
387 }
388 
389 void SeatInterface::setName(const QString &name)
390 {
391  if (d->name == name) {
392  return;
393  }
394  d->name = name;
395 
396  const auto seatResources = d->resourceMap();
397  for (SeatInterfacePrivate::Resource *resource : seatResources) {
398  if (resource->version() >= WL_SEAT_NAME_SINCE_VERSION) {
399  d->send_name(resource->handle, d->name);
400  }
401  }
402 
403  Q_EMIT nameChanged(d->name);
404 }
405 
406 QString SeatInterface::name() const
407 {
408  return d->name;
409 }
410 
411 bool SeatInterface::hasPointer() const
412 {
413  return d->pointer;
414 }
415 
416 bool SeatInterface::hasKeyboard() const
417 {
418  return d->keyboard;
419 }
420 
421 bool SeatInterface::hasTouch() const
422 {
423  return d->touch;
424 }
425 
426 Display *SeatInterface::display() const
427 {
428  return d->display;
429 }
430 
431 SeatInterface *SeatInterface::get(wl_resource *native)
432 {
433  if (SeatInterfacePrivate *seatPrivate = resource_cast<SeatInterfacePrivate *>(native)) {
434  return seatPrivate->q;
435  }
436  return nullptr;
437 }
438 
440 {
441  return d->globalPointer.pos;
442 }
443 
445 {
446  if (!d->pointer) {
447  return;
448  }
449  if (d->globalPointer.pos == pos) {
450  return;
451  }
452  d->globalPointer.pos = pos;
453  Q_EMIT pointerPosChanged(pos);
454 
455  SurfaceInterface *focusedSurface = focusedPointerSurface();
456  if (!focusedSurface) {
457  return;
458  }
459  if (isDragPointer()) {
460  // data device will handle it directly
461  // for xwayland cases we still want to send pointer events
462  if (!d->dataDevicesForSurface(focusedSurface).isEmpty())
463  return;
464  }
465  if (focusedSurface->lockedPointer() && focusedSurface->lockedPointer()->isLocked()) {
466  return;
467  }
468 
469  QPointF localPosition = focusedPointerSurfaceTransformation().map(pos);
470  SurfaceInterface *effectiveFocusedSurface = focusedSurface->inputSurfaceAt(localPosition);
471  if (!effectiveFocusedSurface) {
472  effectiveFocusedSurface = focusedSurface;
473  }
474  if (focusedSurface != effectiveFocusedSurface) {
475  localPosition = focusedSurface->mapToChild(effectiveFocusedSurface, localPosition);
476  }
477 
478  if (d->pointer->focusedSurface() != effectiveFocusedSurface) {
479  d->pointer->setFocusedSurface(effectiveFocusedSurface, localPosition, display()->nextSerial());
480  }
481 
482  d->pointer->sendMotion(localPosition);
483 }
484 
485 quint32 SeatInterface::timestamp() const
486 {
487  return d->timestamp;
488 }
489 
490 void SeatInterface::setTimestamp(quint32 time)
491 {
492  if (d->timestamp == time) {
493  return;
494  }
495  d->timestamp = time;
496  Q_EMIT timestampChanged(time);
497 }
498 
499 void SeatInterface::setDragTarget(AbstractDropHandler *dropTarget,
500  SurfaceInterface *surface,
501  const QPointF &globalPosition,
502  const QMatrix4x4 &inputTransformation)
503 {
504  if (surface == d->drag.surface) {
505  // no change
506  return;
507  }
508  const quint32 serial = d->display->nextSerial();
509  if (d->drag.target) {
510  d->drag.target->updateDragTarget(nullptr, serial);
511  }
512 
513  // TODO: technically we can have mulitple data devices
514  // and we should send the drag to all of them, but that seems overly complicated
515  // in practice so far the only case for mulitple data devices is for clipboard overriding
516  d->drag.target = dropTarget;
517 
518  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
519  notifyPointerMotion(globalPosition);
520  notifyPointerFrame();
521  } else if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->globalTouch.focus.firstTouchPos != globalPosition) {
522  notifyTouchMotion(d->globalTouch.ids.first(), globalPosition);
523  }
524  if (d->drag.target) {
525  d->drag.surface = surface;
526  d->drag.transformation = inputTransformation;
527  d->drag.target->updateDragTarget(surface, serial);
528  } else {
529  d->drag.surface = nullptr;
530  }
531  Q_EMIT dragSurfaceChanged();
532  return;
533 }
534 
535 void SeatInterface::setDragTarget(AbstractDropHandler *target, SurfaceInterface *surface, const QMatrix4x4 &inputTransformation)
536 {
537  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
538  setDragTarget(target, surface, pointerPos(), inputTransformation);
539  } else {
540  Q_ASSERT(d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch);
541  setDragTarget(target, surface, d->globalTouch.focus.firstTouchPos, inputTransformation);
542  }
543 }
544 
546 {
547  return d->globalPointer.focus.surface;
548 }
549 
551 {
552  QMatrix4x4 m;
553  m.translate(-surfacePosition.x(), -surfacePosition.y());
554  setFocusedPointerSurface(surface, m);
555  if (d->globalPointer.focus.surface) {
556  d->globalPointer.focus.offset = surfacePosition;
557  }
558 }
559 
561 {
562  if (!d->pointer) {
563  return;
564  }
565  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
566  // ignore
567  return;
568  }
569 
570  const quint32 serial = d->display->nextSerial();
571 
572  if (d->globalPointer.focus.surface) {
573  disconnect(d->globalPointer.focus.destroyConnection);
574  }
575  d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus();
576  d->globalPointer.focus.surface = surface;
577  if (d->globalPointer.focus.surface) {
578  d->globalPointer.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this] {
579  d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus();
580  });
581  d->globalPointer.focus.serial = serial;
582  d->globalPointer.focus.transformation = transformation;
583  d->globalPointer.focus.offset = QPointF();
584  }
585 
586  if (surface) {
587  QPointF localPosition = focusedPointerSurfaceTransformation().map(pointerPos());
588  SurfaceInterface *effectiveFocusedSurface = surface->inputSurfaceAt(localPosition);
589  if (!effectiveFocusedSurface) {
590  effectiveFocusedSurface = surface;
591  }
592  if (surface != effectiveFocusedSurface) {
593  localPosition = surface->mapToChild(effectiveFocusedSurface, localPosition);
594  }
595  d->pointer->setFocusedSurface(effectiveFocusedSurface, localPosition, serial);
596  } else {
597  d->pointer->setFocusedSurface(nullptr, QPointF(), serial);
598  }
599 }
600 
602 {
603  if (d->globalPointer.focus.surface) {
604  d->globalPointer.focus.offset = surfacePosition;
605  d->globalPointer.focus.transformation = QMatrix4x4();
606  d->globalPointer.focus.transformation.translate(-surfacePosition.x(), -surfacePosition.y());
607  }
608 }
609 
611 {
612  return d->globalPointer.focus.offset;
613 }
614 
616 {
617  if (d->globalPointer.focus.surface) {
618  d->globalPointer.focus.transformation = transformation;
619  }
620 }
621 
623 {
624  return d->globalPointer.focus.transformation;
625 }
626 
627 PointerInterface *SeatInterface::pointer() const
628 {
629  return d->pointer.data();
630 }
631 
632 static quint32 qtToWaylandButton(Qt::MouseButton button)
633 {
634 #if HAVE_LINUX_INPUT_H
635  static const QHash<Qt::MouseButton, quint32> s_buttons({
636  {Qt::LeftButton, BTN_LEFT},
637  {Qt::RightButton, BTN_RIGHT},
638  {Qt::MiddleButton, BTN_MIDDLE},
639  {Qt::ExtraButton1, BTN_BACK}, // note: QtWayland maps BTN_SIDE
640  {Qt::ExtraButton2, BTN_FORWARD}, // note: QtWayland maps BTN_EXTRA
641  {Qt::ExtraButton3, BTN_TASK}, // note: QtWayland maps BTN_FORWARD
642  {Qt::ExtraButton4, BTN_EXTRA}, // note: QtWayland maps BTN_BACK
643  {Qt::ExtraButton5, BTN_SIDE}, // note: QtWayland maps BTN_TASK
644  {Qt::ExtraButton6, BTN_TASK + 1},
645  {Qt::ExtraButton7, BTN_TASK + 2},
646  {Qt::ExtraButton8, BTN_TASK + 3},
647  {Qt::ExtraButton9, BTN_TASK + 4},
648  {Qt::ExtraButton10, BTN_TASK + 5},
649  {Qt::ExtraButton11, BTN_TASK + 6},
650  {Qt::ExtraButton12, BTN_TASK + 7},
651  {Qt::ExtraButton13, BTN_TASK + 8}
652  // further mapping not possible, 0x120 is BTN_JOYSTICK
653  });
654  return s_buttons.value(button, 0);
655 #else
656  Q_UNUSED(button)
657  return 0;
658 #endif
659 }
660 
662 {
663  return isPointerButtonPressed(qtToWaylandButton(button));
664 }
665 
666 bool SeatInterface::isPointerButtonPressed(quint32 button) const
667 {
668  auto it = d->globalPointer.buttonStates.constFind(button);
669  if (it == d->globalPointer.buttonStates.constEnd()) {
670  return false;
671  }
672  return it.value() == SeatInterfacePrivate::Pointer::State::Pressed;
673 }
674 
675 void SeatInterface::notifyPointerAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source)
676 {
677  if (!d->pointer) {
678  return;
679  }
680  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
681  // ignore
682  return;
683  }
684  d->pointer->sendAxis(orientation, delta, discreteDelta, source);
685 }
686 
687 void SeatInterface::notifyPointerButton(Qt::MouseButton button, PointerButtonState state)
688 {
689  const quint32 nativeButton = qtToWaylandButton(button);
690  if (nativeButton == 0) {
691  return;
692  }
693  notifyPointerButton(nativeButton, state);
694 }
695 
696 void SeatInterface::notifyPointerButton(quint32 button, PointerButtonState state)
697 {
698  if (!d->pointer) {
699  return;
700  }
701  const quint32 serial = d->display->nextSerial();
702 
703  if (state == PointerButtonState::Pressed) {
704  d->updatePointerButtonSerial(button, serial);
705  d->updatePointerButtonState(button, SeatInterfacePrivate::Pointer::State::Pressed);
706  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
707  // ignore
708  return;
709  }
710  } else {
711  const quint32 currentButtonSerial = pointerButtonSerial(button);
712  d->updatePointerButtonSerial(button, serial);
713  d->updatePointerButtonState(button, SeatInterfacePrivate::Pointer::State::Released);
714  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) {
715  if (d->drag.dragImplicitGrabSerial != currentButtonSerial) {
716  // not our drag button - ignore
717  return;
718  }
719  d->endDrag(serial);
720  return;
721  }
722  }
723 
724  d->pointer->sendButton(button, state, serial);
725 }
726 
727 void SeatInterface::notifyPointerFrame()
728 {
729  if (!d->pointer) {
730  return;
731  }
732  d->pointer->sendFrame();
733 }
734 
736 {
737  return pointerButtonSerial(qtToWaylandButton(button));
738 }
739 
740 quint32 SeatInterface::pointerButtonSerial(quint32 button) const
741 {
742  auto it = d->globalPointer.buttonSerials.constFind(button);
743  if (it == d->globalPointer.buttonSerials.constEnd()) {
744  return 0;
745  }
746  return it.value();
747 }
748 
749 void SeatInterface::relativePointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
750 {
751  if (!d->pointer) {
752  return;
753  }
754 
755  auto relativePointer = RelativePointerV1Interface::get(pointer());
756  if (relativePointer) {
757  relativePointer->sendRelativeMotion(delta, deltaNonAccelerated, microseconds);
758  }
759 }
760 
762 {
763  if (!d->pointer) {
764  return;
765  }
766 
767  auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
768  if (swipeGesture) {
769  swipeGesture->sendBegin(d->display->nextSerial(), fingerCount);
770  }
771 }
772 
774 {
775  if (!d->pointer) {
776  return;
777  }
778 
779  auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
780  if (swipeGesture) {
781  swipeGesture->sendUpdate(delta);
782  }
783 }
784 
786 {
787  if (!d->pointer) {
788  return;
789  }
790 
791  auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
792  if (swipeGesture) {
793  swipeGesture->sendEnd(d->display->nextSerial());
794  }
795 }
796 
798 {
799  if (!d->pointer) {
800  return;
801  }
802 
803  auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer());
804  if (swipeGesture) {
805  swipeGesture->sendCancel(d->display->nextSerial());
806  }
807 }
808 
810 {
811  if (!d->pointer) {
812  return;
813  }
814 
815  auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
816  if (pinchGesture) {
817  pinchGesture->sendBegin(d->display->nextSerial(), fingerCount);
818  }
819 }
820 
821 void SeatInterface::updatePointerPinchGesture(const QSizeF &delta, qreal scale, qreal rotation)
822 {
823  if (!d->pointer) {
824  return;
825  }
826 
827  auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
828  if (pinchGesture) {
829  pinchGesture->sendUpdate(delta, scale, rotation);
830  }
831 }
832 
834 {
835  if (!d->pointer) {
836  return;
837  }
838 
839  auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
840  if (pinchGesture) {
841  pinchGesture->sendEnd(d->display->nextSerial());
842  }
843 }
844 
846 {
847  if (!d->pointer) {
848  return;
849  }
850 
851  auto pinchGesture = PointerPinchGestureV1Interface::get(pointer());
852  if (pinchGesture) {
853  pinchGesture->sendCancel(d->display->nextSerial());
854  }
855 }
856 
857 SurfaceInterface *SeatInterface::focusedKeyboardSurface() const
858 {
859  return d->globalKeyboard.focus.surface;
860 }
861 
863 {
864  if (!d->keyboard) {
865  return;
866  }
867 
868  const quint32 serial = d->display->nextSerial();
869 
870  if (d->globalKeyboard.focus.surface) {
871  disconnect(d->globalKeyboard.focus.destroyConnection);
872  }
873  d->globalKeyboard.focus = SeatInterfacePrivate::Keyboard::Focus();
874  d->globalKeyboard.focus.surface = surface;
875 
876  d->keyboard->setFocusedSurface(surface, serial);
877 
878  if (d->globalKeyboard.focus.surface) {
879  d->globalKeyboard.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this]() {
880  d->globalKeyboard.focus = SeatInterfacePrivate::Keyboard::Focus();
881  });
882  d->globalKeyboard.focus.serial = serial;
883  // selection?
884  const QVector<DataDeviceInterface *> dataDevices = d->dataDevicesForSurface(surface);
885  d->globalKeyboard.focus.selections = dataDevices;
886  for (auto dataDevice : dataDevices) {
887  if (d->currentSelection) {
888  dataDevice->sendSelection(d->currentSelection);
889  } else {
890  dataDevice->sendClearSelection();
891  }
892  }
893  // primary selection
894  QVector<PrimarySelectionDeviceV1Interface *> primarySelectionDevices;
895  for (auto it = d->primarySelectionDevices.constBegin(); it != d->primarySelectionDevices.constEnd(); ++it) {
896  if ((*it)->client() == *surface->client()) {
897  primarySelectionDevices << *it;
898  }
899  }
900 
901  d->globalKeyboard.focus.primarySelections = primarySelectionDevices;
902  for (auto primaryDataDevice : primarySelectionDevices) {
903  if (d->currentPrimarySelection) {
904  primaryDataDevice->sendSelection(d->currentPrimarySelection);
905  } else {
906  primaryDataDevice->sendClearSelection();
907  }
908  }
909  }
910 
911  // focused text input surface follows keyboard
912  if (hasKeyboard()) {
913  setFocusedTextInputSurface(surface);
914  }
915 }
916 
917 KeyboardInterface *SeatInterface::keyboard() const
918 {
919  return d->keyboard.data();
920 }
921 
922 void SeatInterface::notifyKeyboardKey(quint32 keyCode, KeyboardKeyState state)
923 {
924  if (!d->keyboard) {
925  return;
926  }
927  d->keyboard->sendKey(keyCode, state);
928 }
929 
930 void SeatInterface::notifyKeyboardModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group)
931 {
932  if (!d->keyboard) {
933  return;
934  }
935  d->keyboard->sendModifiers(depressed, latched, locked, group);
936 }
937 
938 void SeatInterface::notifyTouchCancel()
939 {
940  if (!d->touch) {
941  return;
942  }
943  d->touch->sendCancel();
944 
945  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch) {
946  // cancel the drag, don't drop. serial does not matter
947  d->cancelDrag(0);
948  }
949  d->globalTouch.ids.clear();
950 }
951 
952 SurfaceInterface *SeatInterface::focusedTouchSurface() const
953 {
954  return d->globalTouch.focus.surface;
955 }
956 
957 QPointF SeatInterface::focusedTouchSurfacePosition() const
958 {
959  return d->globalTouch.focus.offset;
960 }
961 
962 bool SeatInterface::isTouchSequence() const
963 {
964  return !d->globalTouch.ids.isEmpty();
965 }
966 
967 TouchInterface *SeatInterface::touch() const
968 {
969  return d->touch.data();
970 }
971 
972 void SeatInterface::setFocusedTouchSurface(SurfaceInterface *surface, const QPointF &surfacePosition)
973 {
974  if (!d->touch) {
975  return;
976  }
977  if (isTouchSequence()) {
978  // changing surface not allowed during a touch sequence
979  return;
980  }
981  if (isDragTouch()) {
982  return;
983  }
984  if (d->globalTouch.focus.surface) {
985  disconnect(d->globalTouch.focus.destroyConnection);
986  }
987  d->globalTouch.focus = SeatInterfacePrivate::Touch::Focus();
988  d->globalTouch.focus.surface = surface;
989  d->globalTouch.focus.offset = surfacePosition;
990  if (d->globalTouch.focus.surface) {
991  d->globalTouch.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this]() {
992  if (isTouchSequence()) {
993  // Surface destroyed during touch sequence - send a cancel
994  d->touch->sendCancel();
995  }
996  d->globalTouch.focus = SeatInterfacePrivate::Touch::Focus();
997  });
998  }
999  d->touch->setFocusedSurface(surface);
1000 }
1001 
1002 void SeatInterface::setFocusedTouchSurfacePosition(const QPointF &surfacePosition)
1003 {
1004  d->globalTouch.focus.offset = surfacePosition;
1005 }
1006 
1007 void SeatInterface::notifyTouchDown(qint32 id, const QPointF &globalPosition)
1008 {
1009  if (!d->touch) {
1010  return;
1011  }
1012  const qint32 serial = display()->nextSerial();
1013  const auto pos = globalPosition - d->globalTouch.focus.offset;
1014  d->touch->sendDown(id, serial, pos);
1015 
1016  if (id == 0) {
1017  d->globalTouch.focus.firstTouchPos = globalPosition;
1018  }
1019 
1020 #if HAVE_LINUX_INPUT_H
1021  if (id == 0 && hasPointer() && focusedTouchSurface()) {
1022  TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.data());
1023  if (touchPrivate->touchesForClient(focusedTouchSurface()->client()).isEmpty()) {
1024  // If the client did not bind the touch interface fall back
1025  // to at least emulating touch through pointer events.
1026  d->pointer->setFocusedSurface(focusedTouchSurface(), pos, serial);
1027  d->pointer->sendMotion(pos);
1028  d->pointer->sendFrame();
1029  }
1030  }
1031 #endif
1032 
1033  d->globalTouch.ids[id] = serial;
1034 }
1035 
1036 void SeatInterface::notifyTouchMotion(qint32 id, const QPointF &globalPosition)
1037 {
1038  if (!d->touch) {
1039  return;
1040  }
1041  Q_ASSERT(d->globalTouch.ids.contains(id));
1042 
1043  const auto pos = globalPosition - d->globalTouch.focus.offset;
1044  if (isDragTouch()) {
1045  // handled by DataDevice
1046  } else {
1047  d->touch->sendMotion(id, pos);
1048  }
1049 
1050  if (id == 0) {
1051  d->globalTouch.focus.firstTouchPos = globalPosition;
1052 
1053  if (hasPointer() && focusedTouchSurface()) {
1054  TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.data());
1055  if (touchPrivate->touchesForClient(focusedTouchSurface()->client()).isEmpty()) {
1056  // Client did not bind touch, fall back to emulating with pointer events.
1057  d->pointer->sendMotion(pos);
1058  d->pointer->sendFrame();
1059  }
1060  }
1061  }
1062  Q_EMIT touchMoved(id, d->globalTouch.ids[id], globalPosition);
1063 }
1064 
1065 void SeatInterface::notifyTouchUp(qint32 id)
1066 {
1067  if (!d->touch) {
1068  return;
1069  }
1070  Q_ASSERT(d->globalTouch.ids.contains(id));
1071  const qint32 serial = d->display->nextSerial();
1072  if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch && d->drag.dragImplicitGrabSerial == d->globalTouch.ids.value(id)) {
1073  // the implicitly grabbing touch point has been upped
1074  d->endDrag(serial);
1075  }
1076  d->touch->sendUp(id, serial);
1077 
1078 #if HAVE_LINUX_INPUT_H
1079  if (id == 0 && hasPointer() && focusedTouchSurface()) {
1080  TouchInterfacePrivate *touchPrivate = TouchInterfacePrivate::get(d->touch.data());
1081  if (touchPrivate->touchesForClient(focusedTouchSurface()->client()).isEmpty()) {
1082  // Client did not bind touch, fall back to emulating with pointer events.
1083  const quint32 serial = display()->nextSerial();
1084  d->pointer->sendButton(BTN_LEFT, PointerButtonState::Released, serial);
1085  d->pointer->sendFrame();
1086  }
1087  }
1088 #endif
1089 
1090  d->globalTouch.ids.remove(id);
1091 }
1092 
1093 void SeatInterface::notifyTouchFrame()
1094 {
1095  if (!d->touch) {
1096  return;
1097  }
1098  d->touch->sendFrame();
1099 }
1100 
1101 bool SeatInterface::hasImplicitTouchGrab(quint32 serial) const
1102 {
1103  if (!d->globalTouch.focus.surface) {
1104  // origin surface has been destroyed
1105  return false;
1106  }
1107  return d->globalTouch.ids.key(serial, -1) != -1;
1108 }
1109 
1111 {
1112  return d->drag.mode != SeatInterfacePrivate::Drag::Mode::None;
1113 }
1114 
1116 {
1117  return d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer;
1118 }
1119 
1121 {
1122  return d->drag.mode == SeatInterfacePrivate::Drag::Mode::Touch;
1123 }
1124 
1125 bool SeatInterface::hasImplicitPointerGrab(quint32 serial) const
1126 {
1127  const auto &serials = d->globalPointer.buttonSerials;
1128  for (auto it = serials.constBegin(), end = serials.constEnd(); it != end; it++) {
1129  if (it.value() == serial) {
1130  return isPointerButtonPressed(it.key());
1131  }
1132  }
1133  return false;
1134 }
1135 
1137 {
1138  return d->drag.transformation;
1139 }
1140 
1142 {
1143  return d->drag.surface;
1144 }
1145 
1147 {
1148  return d->drag.source;
1149 }
1150 
1152 {
1153  const quint32 serial = d->display->nextSerial();
1154 
1155  if (d->focusedTextInputSurface) {
1156  disconnect(d->focusedSurfaceDestroyConnection);
1157  }
1158 
1159  if (d->focusedTextInputSurface != surface) {
1160  d->textInputV2->d->sendLeave(serial, d->focusedTextInputSurface);
1161  d->textInputV3->d->sendLeave(d->focusedTextInputSurface);
1162  d->focusedTextInputSurface = surface;
1163  Q_EMIT focusedTextInputSurfaceChanged();
1164  }
1165 
1166  if (d->focusedTextInputSurface) {
1167  d->focusedSurfaceDestroyConnection = connect(surface, &SurfaceInterface::aboutToBeDestroyed, this, [this] {
1168  setFocusedTextInputSurface(nullptr);
1169  });
1170  }
1171 
1172  d->textInputV2->d->sendEnter(surface, serial);
1173  d->textInputV3->d->sendEnter(surface);
1174  // TODO: setFocusedSurface like in other interfaces
1175 }
1176 
1178 {
1179  return d->focusedTextInputSurface;
1180 }
1181 
1183 {
1184  return d->textInputV2;
1185 }
1186 
1187 TextInputV3Interface *SeatInterface::textInputV3() const
1188 {
1189  return d->textInputV3;
1190 }
1192 {
1193  return d->currentSelection;
1194 }
1195 
1197 {
1198  if (d->currentSelection == selection) {
1199  return;
1200  }
1201 
1202  if (d->currentSelection) {
1203  d->currentSelection->cancel();
1204  disconnect(d->currentSelection, nullptr, this, nullptr);
1205  }
1206 
1207  if (selection) {
1208  auto cleanup = [this]() {
1209  setSelection(nullptr);
1210  };
1211  connect(selection, &DataSourceInterface::aboutToBeDestroyed, this, cleanup);
1212  }
1213 
1214  d->currentSelection = selection;
1215 
1216  for (auto focussedSelection : qAsConst(d->globalKeyboard.focus.selections)) {
1217  if (selection) {
1218  focussedSelection->sendSelection(selection);
1219  } else {
1220  focussedSelection->sendClearSelection();
1221  }
1222  }
1223 
1224  for (auto control : qAsConst(d->dataControlDevices)) {
1225  if (selection) {
1226  control->sendSelection(selection);
1227  } else {
1228  control->sendClearSelection();
1229  }
1230  }
1231 
1232  Q_EMIT selectionChanged(selection);
1233 }
1234 
1235 AbstractDataSource *SeatInterface::primarySelection() const
1236 {
1237  return d->currentPrimarySelection;
1238 }
1239 
1240 void SeatInterface::setPrimarySelection(AbstractDataSource *selection)
1241 {
1242  if (d->currentPrimarySelection == selection) {
1243  return;
1244  }
1245  if (d->currentPrimarySelection) {
1246  d->currentPrimarySelection->cancel();
1247  disconnect(d->currentPrimarySelection, nullptr, this, nullptr);
1248  }
1249 
1250  if (selection) {
1251  auto cleanup = [this]() {
1252  setPrimarySelection(nullptr);
1253  };
1254  connect(selection, &DataSourceInterface::aboutToBeDestroyed, this, cleanup);
1255  }
1256 
1257  d->currentPrimarySelection = selection;
1258 
1259  for (auto focussedSelection : qAsConst(d->globalKeyboard.focus.primarySelections)) {
1260  if (selection) {
1261  focussedSelection->sendSelection(selection);
1262  } else {
1263  focussedSelection->sendClearSelection();
1264  }
1265  }
1266  for (auto control : qAsConst(d->dataControlDevices)) {
1267  if (selection) {
1268  control->sendPrimarySelection(selection);
1269  } else {
1270  control->sendClearPrimarySelection();
1271  }
1272  }
1273 
1274  Q_EMIT primarySelectionChanged(selection);
1275 }
1276 
1277 void SeatInterface::startDrag(AbstractDataSource *dragSource, SurfaceInterface *originSurface, int dragSerial, DragAndDropIcon *dragIcon)
1278 {
1279  if (hasImplicitPointerGrab(dragSerial)) {
1280  d->drag.mode = SeatInterfacePrivate::Drag::Mode::Pointer;
1281  d->drag.transformation = d->globalPointer.focus.transformation;
1282  } else if (hasImplicitTouchGrab(dragSerial)) {
1283  d->drag.mode = SeatInterfacePrivate::Drag::Mode::Touch;
1284  // TODO: touch transformation
1285  } else {
1286  // no implicit grab, abort drag
1287  return;
1288  }
1289  d->drag.dragImplicitGrabSerial = dragSerial;
1290 
1291  // set initial drag target to ourself
1292  d->drag.surface = originSurface;
1293  // TODO: transformation needs to be either pointer or touch
1294  d->drag.transformation = d->globalPointer.focus.transformation;
1295 
1296  d->drag.source = dragSource;
1297  if (dragSource) {
1298  d->drag.dragSourceDestroyConnection = QObject::connect(dragSource, &AbstractDataSource::aboutToBeDestroyed, this, [this] {
1299  d->cancelDrag(d->display->nextSerial());
1300  });
1301  }
1302  d->drag.dragIcon = dragIcon;
1303 
1304  if (!d->dataDevicesForSurface(originSurface).isEmpty()) {
1305  d->drag.target = d->dataDevicesForSurface(originSurface)[0];
1306  }
1307  if (d->drag.target) {
1308  d->drag.target->updateDragTarget(originSurface, dragSerial);
1309  }
1310  Q_EMIT dragStarted();
1311  Q_EMIT dragSurfaceChanged();
1312 }
1313 
1315 {
1316  return d->drag.dragIcon;
1317 }
1318 }
The AbstractDataSource class abstracts the data that can be transferred to another client...
void notifyPointerMotion(const QPointF &pos)
Updates the global pointer pos.
void translate(const QVector3D &vector)
QPointF focusedPointerSurfacePosition() const
void relativePointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
A relative motion is in the same dimension as regular motion events, except they do not represent an ...
DragAndDropIcon * dragIcon() const
Returns the additional icon attached to the cursor during a drag-and-drop operation.
bool isPointerButtonPressed(quint32 button) const
SurfaceInterface * focusedTextInputSurface() const
void setFocusedTextInputSurface(SurfaceInterface *surface)
Passes text input focus to surface.
void cancelPointerSwipeGesture()
The multi-finger swipe gestures ended and got cancelled by the Wayland compositor.
ClientConnection * client() const
Returns the Wayland client that owns this SurfaceInterface.
void setFocusedPointerSurfaceTransformation(const QMatrix4x4 &transformation)
Sets the transformation for going from global to local coordinates.
MouseButton
bool hasImplicitTouchGrab(quint32 serial) const
bool hasImplicitPointerGrab(quint32 serial) const
void setDragTarget(AbstractDropHandler *dropTarget, SurfaceInterface *surface, const QPointF &globalPosition, const QMatrix4x4 &inputTransformation)
Sets the current drag target to surface.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
KWaylandServer::AbstractDataSource * dragSource() const
The TouchInterface class repserents a touchscreen associated with a wl_seat.
void reset(T *other)
bool isLocked() const
Whether the Compositor set this pointer lock to be active.
The PointerInterface class represents one or more input devices such as mice, which control the point...
SurfaceInterface * focusedPointerSurface() const
qreal x() const const
qreal y() const const
SurfaceInterface * inputSurfaceAt(const QPointF &position)
Finds the input receiving SurfaceInterface at the given position in surface-local coordinates...
TextInputV2Interface * textInputV2() const
The currently focused text input, may be null even if there is a focused text input surface set...
KWaylandServer::AbstractDataSource * selection() const
bool isEmpty() const const
void updatePointerSwipeGesture(const QSizeF &delta)
The position of the logical center of the currently active multi-finger swipe gesture changes...
T & first()
void startPointerSwipeGesture(quint32 fingerCount)
Starts a multi-finger swipe gesture for the currently focused pointer surface.
Resource for the wl_keyboard interface.
bool removeOne(const T &t)
T * data() const const
const T value(const Key &key) const const
void setSelection(AbstractDataSource *selection)
This method allows to manually set the dataDevice for the current clipboard selection.
QPointF mapToChild(SurfaceInterface *child, const QPointF &point) const
Maps the specified point in this surface&#39;s coordinate system to the equivalent point within the child...
bool isNull() const const
void setFocusedPointerSurfacePosition(const QPointF &surfacePosition)
Updates the global position of the currently focused pointer surface.
void notifyPointerButton(quint32 button, PointerButtonState state)
Marks the specified button as pressed or released based on state.
QMatrix4x4 focusedPointerSurfaceTransformation() const
void endPointerSwipeGesture()
The multi-finger swipe gesture ended.
void startPointerPinchGesture(quint32 fingerCount)
Starts a multi-finch pinch gesture for the currently focused pointer surface.
void notifyPointerAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source)
Sends axis events to the currently focused pointer surface.
SurfaceInterface * dragSurface() const
Resource representing a wl_surface.
Orientation
quint32 pointerButtonSerial(quint32 button) const
void setFocusedKeyboardSurface(SurfaceInterface *surface)
Passes keyboard focus to surface.
QMatrix4x4 dragSurfaceTransformation() const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void aboutToBeDestroyed()
This signal is emitted when the underlying wl_surface resource is about to be freed.
QObject * parent() const const
void setFocusedPointerSurface(SurfaceInterface *surface, const QPointF &surfacePosition=QPoint())
Sets the focused pointer surface.
The DragAndDropIcon class represents a drag-and-drop icon.
void destroyed(QObject *obj)
Q_EMITQ_EMIT
LockedPointerV1Interface * lockedPointer() const
Pointer lock installed on this SurfaceInterface.
void updatePointerPinchGesture(const QSizeF &delta, qreal scale, qreal rotation)
The position of the logical center, the rotation or the relative scale of this multi-finger pinch ges...
Represents a generic Resource for a text input object.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
Represents a generic Resource for a text input object.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Oct 24 2021 23:08:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.