KWayland

surface_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "surface_interface.h"
7 #include "buffer_interface.h"
8 #include "clientconnection.h"
9 #include "compositor_interface.h"
10 #include "idleinhibit_interface_p.h"
11 #include "pointerconstraints_interface_p.h"
12 #include "region_interface.h"
13 #include "subcompositor_interface.h"
14 #include "subsurface_interface_p.h"
15 #include "surface_interface_p.h"
16 #include "surfacerole_p.h"
17 // Qt
18 #include <QListIterator>
19 // Wayland
20 #include <wayland-server.h>
21 // std
22 #include <algorithm>
23 
24 namespace KWayland
25 {
26 namespace Server
27 {
28 SurfaceInterface::Private::Private(SurfaceInterface *q, CompositorInterface *c, wl_resource *parentResource)
29  : Resource::Private(q, c, parentResource, &wl_surface_interface, &s_interface)
30 {
31 }
32 
33 SurfaceInterface::Private::~Private()
34 {
35  destroy();
36 }
37 
38 void SurfaceInterface::Private::addChild(QPointer<SubSurfaceInterface> child)
39 {
40  // protocol is not precise on how to handle the addition of new sub surfaces
41  pending.children.append(child);
42  subSurfacePending.children.append(child);
43  current.children.append(child);
44  Q_Q(SurfaceInterface);
45  Q_EMIT q->childSubSurfaceAdded(child);
46  Q_EMIT q->subSurfaceTreeChanged();
47  QObject::connect(child.data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
48  QObject::connect(child->surface().data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
49  QObject::connect(child->surface().data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
50  QObject::connect(child->surface().data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
51 }
52 
53 void SurfaceInterface::Private::removeChild(QPointer<SubSurfaceInterface> child)
54 {
55  // protocol is not precise on how to handle the addition of new sub surfaces
56  pending.children.removeAll(child);
57  subSurfacePending.children.removeAll(child);
58  current.children.removeAll(child);
59  Q_Q(SurfaceInterface);
60  Q_EMIT q->childSubSurfaceRemoved(child);
61  Q_EMIT q->subSurfaceTreeChanged();
62  QObject::disconnect(child.data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
63  if (!child->surface().isNull()) {
64  QObject::disconnect(child->surface().data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
65  QObject::disconnect(child->surface().data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
66  QObject::disconnect(child->surface().data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
67  }
68 }
69 
70 bool SurfaceInterface::Private::raiseChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling)
71 {
72  Q_Q(SurfaceInterface);
73  auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
74  if (it == pending.children.end()) {
75  return false;
76  }
77  if (pending.children.count() == 1) {
78  // nothing to do
79  return true;
80  }
81  if (sibling == q) {
82  // it's to the parent, so needs to become last item
83  pending.children.append(*it);
84  pending.children.erase(it);
85  pending.childrenChanged = true;
86  return true;
87  }
88  if (!sibling->subSurface()) {
89  // not a sub surface
90  return false;
91  }
92  auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
93  if (siblingIt == pending.children.end() || siblingIt == it) {
94  // not a sibling
95  return false;
96  }
97  auto value = (*it);
98  pending.children.erase(it);
99  // find the iterator again
100  siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
101  pending.children.insert(++siblingIt, value);
102  pending.childrenChanged = true;
103  return true;
104 }
105 
106 bool SurfaceInterface::Private::lowerChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling)
107 {
108  Q_Q(SurfaceInterface);
109  auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
110  if (it == pending.children.end()) {
111  return false;
112  }
113  if (pending.children.count() == 1) {
114  // nothing to do
115  return true;
116  }
117  if (sibling == q) {
118  // it's to the parent, so needs to become first item
119  auto value = *it;
120  pending.children.erase(it);
121  pending.children.prepend(value);
122  pending.childrenChanged = true;
123  return true;
124  }
125  if (!sibling->subSurface()) {
126  // not a sub surface
127  return false;
128  }
129  auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
130  if (siblingIt == pending.children.end() || siblingIt == it) {
131  // not a sibling
132  return false;
133  }
134  auto value = (*it);
135  pending.children.erase(it);
136  // find the iterator again
137  siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
138  pending.children.insert(siblingIt, value);
139  pending.childrenChanged = true;
140  return true;
141 }
142 
143 void SurfaceInterface::Private::setShadow(const QPointer<ShadowInterface> &shadow)
144 {
145  pending.shadow = shadow;
146  pending.shadowIsSet = true;
147 }
148 
149 void SurfaceInterface::Private::setBlur(const QPointer<BlurInterface> &blur)
150 {
151  pending.blur = blur;
152  pending.blurIsSet = true;
153 }
154 
155 void SurfaceInterface::Private::setSlide(const QPointer<SlideInterface> &slide)
156 {
157  pending.slide = slide;
158  pending.slideIsSet = true;
159 }
160 
161 void SurfaceInterface::Private::setContrast(const QPointer<ContrastInterface> &contrast)
162 {
163  pending.contrast = contrast;
164  pending.contrastIsSet = true;
165 }
166 
167 void SurfaceInterface::Private::installPointerConstraint(LockedPointerInterface *lock)
168 {
169  Q_ASSERT(lockedPointer.isNull());
170  Q_ASSERT(confinedPointer.isNull());
171  lockedPointer = QPointer<LockedPointerInterface>(lock);
172 
173  auto cleanUp = [this]() {
174  lockedPointer.clear();
175  disconnect(constrainsOneShotConnection);
176  constrainsOneShotConnection = QMetaObject::Connection();
177  disconnect(constrainsUnboundConnection);
178  constrainsUnboundConnection = QMetaObject::Connection();
179  Q_EMIT q_func()->pointerConstraintsChanged();
180  };
181 
182  if (lock->lifeTime() == LockedPointerInterface::LifeTime::OneShot) {
183  constrainsOneShotConnection = QObject::connect(lock, &LockedPointerInterface::lockedChanged, q_func(), [this, cleanUp] {
184  if (lockedPointer.isNull() || lockedPointer->isLocked()) {
185  return;
186  }
187  cleanUp();
188  });
189  }
190  constrainsUnboundConnection = QObject::connect(lock, &LockedPointerInterface::unbound, q_func(), [this, cleanUp] {
191  if (lockedPointer.isNull()) {
192  return;
193  }
194  cleanUp();
195  });
196  Q_EMIT q_func()->pointerConstraintsChanged();
197 }
198 
199 void SurfaceInterface::Private::installPointerConstraint(ConfinedPointerInterface *confinement)
200 {
201  Q_ASSERT(lockedPointer.isNull());
202  Q_ASSERT(confinedPointer.isNull());
203  confinedPointer = QPointer<ConfinedPointerInterface>(confinement);
204 
205  auto cleanUp = [this]() {
206  confinedPointer.clear();
207  disconnect(constrainsOneShotConnection);
208  constrainsOneShotConnection = QMetaObject::Connection();
209  disconnect(constrainsUnboundConnection);
210  constrainsUnboundConnection = QMetaObject::Connection();
211  Q_EMIT q_func()->pointerConstraintsChanged();
212  };
213 
214  if (confinement->lifeTime() == ConfinedPointerInterface::LifeTime::OneShot) {
215  constrainsOneShotConnection = QObject::connect(confinement, &ConfinedPointerInterface::confinedChanged, q_func(), [this, cleanUp] {
216  if (confinedPointer.isNull() || confinedPointer->isConfined()) {
217  return;
218  }
219  cleanUp();
220  });
221  }
222  constrainsUnboundConnection = QObject::connect(confinement, &ConfinedPointerInterface::unbound, q_func(), [this, cleanUp] {
223  if (confinedPointer.isNull()) {
224  return;
225  }
226  cleanUp();
227  });
228  Q_EMIT q_func()->pointerConstraintsChanged();
229 }
230 
231 void SurfaceInterface::Private::installIdleInhibitor(IdleInhibitorInterface *inhibitor)
232 {
233  idleInhibitors << inhibitor;
234  QObject::connect(inhibitor, &IdleInhibitorInterface::aboutToBeUnbound, q, [this, inhibitor] {
235  idleInhibitors.removeOne(inhibitor);
236  if (idleInhibitors.isEmpty()) {
237  Q_EMIT q_func()->inhibitsIdleChanged();
238  }
239  });
240  if (idleInhibitors.count() == 1) {
241  Q_EMIT q_func()->inhibitsIdleChanged();
242  }
243 }
244 
245 #ifndef K_DOXYGEN
246 const struct wl_surface_interface SurfaceInterface::Private::s_interface = {resourceDestroyedCallback,
247  attachCallback,
248  damageCallback,
249  frameCallback,
250  opaqueRegionCallback,
251  inputRegionCallback,
252  commitCallback,
253  bufferTransformCallback,
254  bufferScaleCallback,
255  damageBufferCallback};
256 #endif
257 
258 SurfaceInterface::SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource)
259  : Resource(new Private(this, parent, parentResource))
260 {
261 }
262 
263 SurfaceInterface::~SurfaceInterface() = default;
264 
265 void SurfaceInterface::frameRendered(quint32 msec)
266 {
267  Q_D();
268  // notify all callbacks
269  const bool needsFlush = !d->current.callbacks.isEmpty();
270  while (!d->current.callbacks.isEmpty()) {
271  wl_resource *r = d->current.callbacks.takeFirst();
272  wl_callback_send_done(r, msec);
273  wl_resource_destroy(r);
274  }
275  for (auto it = d->current.children.constBegin(); it != d->current.children.constEnd(); ++it) {
276  const auto &subSurface = *it;
277  if (subSurface.isNull() || subSurface->d_func()->surface.isNull()) {
278  continue;
279  }
280  subSurface->d_func()->surface->frameRendered(msec);
281  }
282  if (needsFlush) {
283  client()->flush();
284  }
285 }
286 
287 void SurfaceInterface::Private::destroy()
288 {
289  // copy all existing callbacks to new list and clear existing lists
290  // the wl_resource_destroy on the callback resource goes into destroyFrameCallback
291  // which would modify the list we are iterating on
292  QList<wl_resource *> callbacksToDestroy;
293  callbacksToDestroy << current.callbacks;
294  current.callbacks.clear();
295  callbacksToDestroy << pending.callbacks;
296  pending.callbacks.clear();
297  callbacksToDestroy << subSurfacePending.callbacks;
298  subSurfacePending.callbacks.clear();
299  for (auto it = callbacksToDestroy.constBegin(), end = callbacksToDestroy.constEnd(); it != end; it++) {
300  wl_resource_destroy(*it);
301  }
302  if (current.buffer) {
303  current.buffer->unref();
304  }
305 }
306 
307 void SurfaceInterface::Private::swapStates(State *source, State *target, bool emitChanged)
308 {
309  Q_Q(SurfaceInterface);
310  bool bufferChanged = source->bufferIsSet;
311  const bool opaqueRegionChanged = source->opaqueIsSet;
312  const bool inputRegionChanged = source->inputIsSet;
313  const bool scaleFactorChanged = source->scaleIsSet && (target->scale != source->scale);
314  const bool transformChanged = source->transformIsSet && (target->transform != source->transform);
315  const bool shadowChanged = source->shadowIsSet;
316  const bool blurChanged = source->blurIsSet;
317  const bool contrastChanged = source->contrastIsSet;
318  const bool slideChanged = source->slideIsSet;
319  const bool childrenChanged = source->childrenChanged;
320  bool sizeChanged = false;
321  auto buffer = target->buffer;
322  if (bufferChanged) {
323  // TODO: is the reffing correct for subsurfaces?
324  QSize oldSize;
325  if (target->buffer) {
326  oldSize = target->buffer->size();
327  if (emitChanged) {
328  target->buffer->unref();
329  QObject::disconnect(target->buffer, &BufferInterface::sizeChanged, q, &SurfaceInterface::sizeChanged);
330  } else {
331  delete target->buffer;
332  target->buffer = nullptr;
333  }
334  }
335  if (source->buffer) {
336  if (emitChanged) {
337  source->buffer->ref();
338  QObject::connect(source->buffer, &BufferInterface::sizeChanged, q, &SurfaceInterface::sizeChanged);
339  }
340  const QSize newSize = source->buffer->size();
341  sizeChanged = newSize.isValid() && newSize != oldSize;
342  }
343  if (!target->buffer && !source->buffer && emitChanged) {
344  // null buffer set on a not mapped surface, don't emit unmapped
345  bufferChanged = false;
346  }
347  buffer = source->buffer;
348  }
349  // copy values
350  if (bufferChanged) {
351  target->buffer = buffer;
352  target->offset = source->offset;
353  target->damage = source->damage;
354  target->bufferDamage = source->bufferDamage;
355  target->bufferIsSet = source->bufferIsSet;
356  }
357  if (childrenChanged) {
358  target->childrenChanged = source->childrenChanged;
359  target->children = source->children;
360  }
361  target->callbacks.append(source->callbacks);
362 
363  if (shadowChanged) {
364  target->shadow = source->shadow;
365  target->shadowIsSet = true;
366  }
367  if (blurChanged) {
368  target->blur = source->blur;
369  target->blurIsSet = true;
370  }
371  if (contrastChanged) {
372  target->contrast = source->contrast;
373  target->contrastIsSet = true;
374  }
375  if (slideChanged) {
376  target->slide = source->slide;
377  target->slideIsSet = true;
378  }
379  if (inputRegionChanged) {
380  target->input = source->input;
381  target->inputIsInfinite = source->inputIsInfinite;
382  target->inputIsSet = true;
383  }
384  if (opaqueRegionChanged) {
385  target->opaque = source->opaque;
386  target->opaqueIsSet = true;
387  }
388  if (scaleFactorChanged) {
389  target->scale = source->scale;
390  target->scaleIsSet = true;
391  }
392  if (transformChanged) {
393  target->transform = source->transform;
394  target->transformIsSet = true;
395  }
396  if (!lockedPointer.isNull()) {
397  lockedPointer->d_func()->commit();
398  }
399  if (!confinedPointer.isNull()) {
400  confinedPointer->d_func()->commit();
401  }
402 
403  *source = State{};
404  source->children = target->children;
405  if (opaqueRegionChanged) {
406  Q_EMIT q->opaqueChanged(target->opaque);
407  }
408  if (inputRegionChanged) {
409  Q_EMIT q->inputChanged(target->input);
410  }
411  if (scaleFactorChanged) {
412  Q_EMIT q->scaleChanged(target->scale);
413  if (buffer && !sizeChanged) {
414  Q_EMIT q->sizeChanged();
415  }
416  }
417  if (transformChanged) {
418  Q_EMIT q->transformChanged(target->transform);
419  }
420  if (bufferChanged && emitChanged) {
421  if (target->buffer && (!target->damage.isEmpty() || !target->bufferDamage.isEmpty())) {
422  const QRegion windowRegion = QRegion(0, 0, q->size().width(), q->size().height());
423  if (!windowRegion.isEmpty()) {
424  QRegion bufferDamage;
425  if (!target->bufferDamage.isEmpty()) {
426  typedef OutputInterface::Transform Tr;
427  const Tr tr = target->transform;
428  const qint32 sc = target->scale;
429  if (tr == Tr::Rotated90 || tr == Tr::Rotated270 || tr == Tr::Flipped90 || tr == Tr::Flipped270) {
430  // calculate transformed + scaled buffer damage
431  for (const auto &rect : target->bufferDamage) {
432  const auto add = QRegion(rect.x() / sc, rect.y() / sc, rect.height() / sc, rect.width() / sc);
433  bufferDamage = bufferDamage.united(add);
434  }
435  } else if (sc != 1) {
436  // calculate scaled buffer damage
437  for (const auto &rect : target->bufferDamage) {
438  const auto add = QRegion(rect.x() / sc, rect.y() / sc, rect.width() / sc, rect.height() / sc);
439  bufferDamage = bufferDamage.united(add);
440  }
441  } else {
442  bufferDamage = target->bufferDamage;
443  }
444  }
445  target->damage = windowRegion.intersected(target->damage.united(bufferDamage));
446  if (emitChanged) {
447  subSurfaceIsMapped = true;
448  trackedDamage = trackedDamage.united(target->damage);
449  Q_EMIT q->damaged(target->damage);
450  // workaround for https://bugreports.qt.io/browse/QTBUG-52092
451  // if the surface is a sub-surface, but the main surface is not yet mapped, fake frame rendered
452  if (subSurface) {
453  const auto mainSurface = subSurface->mainSurface();
454  if (!mainSurface || !mainSurface->buffer()) {
455  q->frameRendered(0);
456  }
457  }
458  }
459  }
460  } else if (!target->buffer && emitChanged) {
461  subSurfaceIsMapped = false;
462  Q_EMIT q->unmapped();
463  }
464  }
465  if (!emitChanged) {
466  return;
467  }
468  if (sizeChanged) {
469  Q_EMIT q->sizeChanged();
470  }
471  if (shadowChanged) {
472  Q_EMIT q->shadowChanged();
473  }
474  if (blurChanged) {
475  Q_EMIT q->blurChanged();
476  }
477  if (contrastChanged) {
478  Q_EMIT q->contrastChanged();
479  }
480  if (slideChanged) {
481  Q_EMIT q->slideOnShowHideChanged();
482  }
483  if (childrenChanged) {
484  Q_EMIT q->subSurfaceTreeChanged();
485  }
486 }
487 
488 void SurfaceInterface::Private::commit()
489 {
490  Q_Q(SurfaceInterface);
491  if (!subSurface.isNull() && subSurface->isSynchronized()) {
492  swapStates(&pending, &subSurfacePending, false);
493  } else {
494  swapStates(&pending, &current, true);
495  if (!subSurface.isNull()) {
496  subSurface->d_func()->commit();
497  }
498  // commit all subSurfaces to apply position changes
499  // "The cached state is applied to the sub-surface immediately after the parent surface's state is applied"
500  for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
501  const auto &subSurface = *it;
502  if (subSurface.isNull()) {
503  continue;
504  }
505  subSurface->d_func()->commit();
506  }
507  }
508  if (role) {
509  role->commit();
510  }
511  Q_EMIT q->committed();
512 }
513 
514 void SurfaceInterface::Private::commitSubSurface()
515 {
516  if (subSurface.isNull() || !subSurface->isSynchronized()) {
517  return;
518  }
519  swapStates(&subSurfacePending, &current, true);
520  // "The cached state is applied to the sub-surface immediately after the parent surface's state is applied"
521  for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
522  const auto &subSurface = *it;
523  if (subSurface.isNull() || !subSurface->isSynchronized()) {
524  continue;
525  }
526  subSurface->d_func()->commit();
527  }
528 }
529 
530 void SurfaceInterface::Private::damage(const QRect &rect)
531 {
532  pending.damage = pending.damage.united(rect);
533 }
534 
535 void SurfaceInterface::Private::damageBuffer(const QRect &rect)
536 {
537  pending.bufferDamage = pending.bufferDamage.united(rect);
538 }
539 
540 void SurfaceInterface::Private::setScale(qint32 scale)
541 {
542  pending.scale = scale;
543  pending.scaleIsSet = true;
544 }
545 
546 void SurfaceInterface::Private::setTransform(OutputInterface::Transform transform)
547 {
548  pending.transform = transform;
549 }
550 
551 void SurfaceInterface::Private::addFrameCallback(uint32_t callback)
552 {
553  wl_resource *r = client->createResource(&wl_callback_interface, 1, callback);
554  if (!r) {
555  wl_resource_post_no_memory(resource);
556  return;
557  }
558  wl_resource_set_implementation(r, nullptr, this, destroyFrameCallback);
559  pending.callbacks << r;
560 }
561 
562 void SurfaceInterface::Private::attachBuffer(wl_resource *buffer, const QPoint &offset)
563 {
564  pending.bufferIsSet = true;
565  pending.offset = offset;
566  if (pending.buffer) {
567  delete pending.buffer;
568  }
569  if (!buffer) {
570  // got a null buffer, deletes content in next frame
571  pending.buffer = nullptr;
572  pending.damage = QRegion();
573  pending.bufferDamage = QRegion();
574  return;
575  }
576  Q_Q(SurfaceInterface);
577  pending.buffer = new BufferInterface(buffer, q);
578  QObject::connect(pending.buffer, &BufferInterface::aboutToBeDestroyed, q, [this](BufferInterface *buffer) {
579  if (pending.buffer == buffer) {
580  pending.buffer = nullptr;
581  }
582  if (subSurfacePending.buffer == buffer) {
583  subSurfacePending.buffer = nullptr;
584  }
585  if (current.buffer == buffer) {
586  current.buffer->unref();
587  current.buffer = nullptr;
588  }
589  });
590 }
591 
592 void SurfaceInterface::Private::destroyFrameCallback(wl_resource *r)
593 {
594  auto s = cast<Private>(r);
595  s->current.callbacks.removeAll(r);
596  s->pending.callbacks.removeAll(r);
597  s->subSurfacePending.callbacks.removeAll(r);
598 }
599 
600 void SurfaceInterface::Private::attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy)
601 {
602  Q_UNUSED(client)
603  cast<Private>(resource)->attachBuffer(buffer, QPoint(sx, sy));
604 }
605 
606 void SurfaceInterface::Private::damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
607 {
608  Q_UNUSED(client)
609  cast<Private>(resource)->damage(QRect(x, y, width, height));
610 }
611 
612 void SurfaceInterface::Private::damageBufferCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
613 {
614  Q_UNUSED(client)
615  cast<Private>(resource)->damageBuffer(QRect(x, y, width, height));
616 }
617 
618 void SurfaceInterface::Private::frameCallback(wl_client *client, wl_resource *resource, uint32_t callback)
619 {
620  auto s = cast<Private>(resource);
621  Q_ASSERT(client == *s->client);
622  s->addFrameCallback(callback);
623 }
624 
625 void SurfaceInterface::Private::opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
626 {
627  auto s = cast<Private>(resource);
628  Q_ASSERT(client == *s->client);
629  auto r = RegionInterface::get(region);
630  s->setOpaque(r ? r->region() : QRegion());
631 }
632 
633 void SurfaceInterface::Private::setOpaque(const QRegion &region)
634 {
635  pending.opaqueIsSet = true;
636  pending.opaque = region;
637 }
638 
639 void SurfaceInterface::Private::inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
640 {
641  auto s = cast<Private>(resource);
642  Q_ASSERT(client == *s->client);
643  auto r = RegionInterface::get(region);
644  s->setInput(r ? r->region() : QRegion(), !r);
645 }
646 
647 void SurfaceInterface::Private::setInput(const QRegion &region, bool isInfinite)
648 {
649  pending.inputIsSet = true;
650  pending.inputIsInfinite = isInfinite;
651  pending.input = region;
652 }
653 
654 void SurfaceInterface::Private::commitCallback(wl_client *client, wl_resource *resource)
655 {
656  Q_UNUSED(client)
657  cast<Private>(resource)->commit();
658 }
659 
660 void SurfaceInterface::Private::bufferTransformCallback(wl_client *client, wl_resource *resource, int32_t transform)
661 {
662  Q_UNUSED(client)
663  cast<Private>(resource)->setTransform(OutputInterface::Transform(transform));
664 }
665 
666 void SurfaceInterface::Private::bufferScaleCallback(wl_client *client, wl_resource *resource, int32_t scale)
667 {
668  Q_UNUSED(client)
669  cast<Private>(resource)->setScale(scale);
670 }
671 
672 QRegion SurfaceInterface::damage() const
673 {
674  Q_D();
675  return d->current.damage;
676 }
677 
678 QRegion SurfaceInterface::opaque() const
679 {
680  Q_D();
681  return d->current.opaque;
682 }
683 
684 QRegion SurfaceInterface::input() const
685 {
686  Q_D();
687  return d->current.input;
688 }
689 
690 bool SurfaceInterface::inputIsInfitine() const
691 {
692  return inputIsInfinite();
693 }
694 
695 bool SurfaceInterface::inputIsInfinite() const
696 {
697  Q_D();
698  return d->current.inputIsInfinite;
699 }
700 
701 qint32 SurfaceInterface::scale() const
702 {
703  Q_D();
704  return d->current.scale;
705 }
706 
707 OutputInterface::Transform SurfaceInterface::transform() const
708 {
709  Q_D();
710  return d->current.transform;
711 }
712 
713 BufferInterface *SurfaceInterface::buffer()
714 {
715  Q_D();
716  return d->current.buffer;
717 }
718 
719 QPoint SurfaceInterface::offset() const
720 {
721  Q_D();
722  return d->current.offset;
723 }
724 
725 SurfaceInterface *SurfaceInterface::get(wl_resource *native)
726 {
727  return Private::get<SurfaceInterface>(native);
728 }
729 
730 SurfaceInterface *SurfaceInterface::get(quint32 id, const ClientConnection *client)
731 {
732  return Private::get<SurfaceInterface>(id, client);
733 }
734 
735 QList<QPointer<SubSurfaceInterface>> SurfaceInterface::childSubSurfaces() const
736 {
737  Q_D();
738  return d->current.children;
739 }
740 
741 QPointer<SubSurfaceInterface> SurfaceInterface::subSurface() const
742 {
743  Q_D();
744  return d->subSurface;
745 }
746 
747 QSize SurfaceInterface::size() const
748 {
749  Q_D();
750  // TODO: apply transform to the buffer size
751  if (d->current.buffer) {
752  return d->current.buffer->size() / scale();
753  }
754  return QSize();
755 }
756 
757 QRect SurfaceInterface::boundingRect() const
758 {
759  QRect rect(QPoint(0, 0), size());
760 
761  const QList<QPointer<SubSurfaceInterface>> subSurfaces = childSubSurfaces();
762  for (const SubSurfaceInterface *subSurface : subSurfaces) {
763  const SurfaceInterface *childSurface = subSurface->surface();
764  rect |= childSurface->boundingRect().translated(subSurface->position());
765  }
766 
767  return rect;
768 }
769 
770 QPointer<ShadowInterface> SurfaceInterface::shadow() const
771 {
772  Q_D();
773  return d->current.shadow;
774 }
775 
776 QPointer<BlurInterface> SurfaceInterface::blur() const
777 {
778  Q_D();
779  return d->current.blur;
780 }
781 
782 QPointer<ContrastInterface> SurfaceInterface::contrast() const
783 {
784  Q_D();
785  return d->current.contrast;
786 }
787 
788 QPointer<SlideInterface> SurfaceInterface::slideOnShowHide() const
789 {
790  Q_D();
791  return d->current.slide;
792 }
793 
794 bool SurfaceInterface::isMapped() const
795 {
796  Q_D();
797  if (d->subSurface) {
798  // from spec:
799  // "A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and the parent surface is mapped."
800  return d->subSurfaceIsMapped && !d->subSurface->parentSurface().isNull() && d->subSurface->parentSurface()->isMapped();
801  }
802  return d->current.buffer != nullptr;
803 }
804 
805 QRegion SurfaceInterface::trackedDamage() const
806 {
807  Q_D();
808  return d->trackedDamage;
809 }
810 
811 void SurfaceInterface::resetTrackedDamage()
812 {
813  Q_D();
814  d->trackedDamage = QRegion();
815 }
816 
817 QVector<OutputInterface *> SurfaceInterface::outputs() const
818 {
819  Q_D();
820  return d->outputs;
821 }
822 
823 void SurfaceInterface::setOutputs(const QVector<OutputInterface *> &outputs)
824 {
825  Q_D();
826  QVector<OutputInterface *> removedOutputs = d->outputs;
827  for (auto it = outputs.constBegin(), end = outputs.constEnd(); it != end; ++it) {
828  const auto o = *it;
829  removedOutputs.removeOne(o);
830  }
831  for (auto it = removedOutputs.constBegin(), end = removedOutputs.constEnd(); it != end; ++it) {
832  const auto resources = (*it)->clientResources(client());
833  for (wl_resource *r : resources) {
834  wl_surface_send_leave(d->resource, r);
835  }
836  disconnect(d->outputDestroyedConnections.take(*it));
837  }
838  QVector<OutputInterface *> addedOutputsOutputs = outputs;
839  for (auto it = d->outputs.constBegin(), end = d->outputs.constEnd(); it != end; ++it) {
840  const auto o = *it;
841  addedOutputsOutputs.removeOne(o);
842  }
843  for (auto it = addedOutputsOutputs.constBegin(), end = addedOutputsOutputs.constEnd(); it != end; ++it) {
844  const auto o = *it;
845  const auto resources = o->clientResources(client());
846  for (wl_resource *r : resources) {
847  wl_surface_send_enter(d->resource, r);
848  }
849  d->outputDestroyedConnections[o] = connect(o, &Global::aboutToDestroyGlobal, this, [this, o] {
850  Q_D();
851  auto outputs = d->outputs;
852  if (outputs.removeOne(o)) {
853  setOutputs(outputs);
854  }
855  });
856  }
857  // TODO: send enter when the client binds the OutputInterface another time
858 
859  d->outputs = outputs;
860 }
861 
862 SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position)
863 {
864  if (!isMapped()) {
865  return nullptr;
866  }
867  Q_D();
868  // go from top to bottom. Top most child is last in list
869  QListIterator<QPointer<SubSurfaceInterface>> it(d->current.children);
870  it.toBack();
871  while (it.hasPrevious()) {
872  const auto &current = it.previous();
873  auto surface = current->surface();
874  if (surface.isNull()) {
875  continue;
876  }
877  if (auto s = surface->surfaceAt(position - current->position())) {
878  return s;
879  }
880  }
881  // check whether the geometry contains the pos
882  if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position)) {
883  return this;
884  }
885  return nullptr;
886 }
887 
888 SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position)
889 {
890  // TODO: Most of this is very similar to SurfaceInterface::surfaceAt
891  // Is there a way to reduce the code duplication?
892  if (!isMapped()) {
893  return nullptr;
894  }
895  Q_D();
896  // go from top to bottom. Top most child is last in list
897  QListIterator<QPointer<SubSurfaceInterface>> it(d->current.children);
898  it.toBack();
899  while (it.hasPrevious()) {
900  const auto &current = it.previous();
901  auto surface = current->surface();
902  if (surface.isNull()) {
903  continue;
904  }
905  if (auto s = surface->inputSurfaceAt(position - current->position())) {
906  return s;
907  }
908  }
909  // check whether the geometry and input region contain the pos
910  if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position) && (inputIsInfinite() || input().contains(position.toPoint()))) {
911  return this;
912  }
913  return nullptr;
914 }
915 
916 QPointer<LockedPointerInterface> SurfaceInterface::lockedPointer() const
917 {
918  Q_D();
919  return d->lockedPointer;
920 }
921 
922 QPointer<ConfinedPointerInterface> SurfaceInterface::confinedPointer() const
923 {
924  Q_D();
925  return d->confinedPointer;
926 }
927 
928 bool SurfaceInterface::inhibitsIdle() const
929 {
930  Q_D();
931  return !d->idleInhibitors.isEmpty();
932 }
933 
934 void SurfaceInterface::setDataProxy(SurfaceInterface *surface)
935 {
936  Q_D();
937  d->dataProxy = surface;
938 }
939 
940 SurfaceInterface *SurfaceInterface::dataProxy() const
941 {
942  Q_D();
943  return d->dataProxy;
944 }
945 
946 SurfaceInterface::Private *SurfaceInterface::d_func() const
947 {
948  return reinterpret_cast<Private *>(d.data());
949 }
950 
951 }
952 }
void clear()
void damageBuffer(const QRect &rect)
Mark rect in buffer coordinates as damaged for the next frame.
Definition: surface.cpp:227
bool isValid() const const
T * data() const const
const T & previous()
bool isEmpty() const const
void destroy()
Destroys the data held by this Surface.
Definition: surface.cpp:115
QVector::const_iterator constEnd() const const
bool contains(const QRectF &rectangle) const const
KIOFILEWIDGETS_EXPORT void add(const QString &fileClass, const QString &directory)
void clear()
void scale(int width, int height, Qt::AspectRatioMode mode)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString tr(const char *sourceText, const char *disambiguation, int n)
void setScale(qint32 scale)
The purpose of this method is to allow to supply higher resolution buffer data for use on high resolu...
Definition: surface.cpp:325
qint32 scale() const
Definition: surface.cpp:320
bool isNull() const const
Resource representing a wl_surface.
QRegion intersected(const QRegion &r) const const
QRect translated(int dx, int dy) const const
Reference counted representation of a Wayland buffer on Server side.
bool removeOne(const T &t)
QVector< Output * > outputs() const
Definition: surface.cpp:331
T * data() const const
quint32 id() const
Definition: surface.cpp:314
if(recurs()&&!first)
bool isNull() const const
const QList< QKeySequence > & end()
QVector::const_iterator constBegin() const const
bool hasPrevious() const const
QPoint toPoint() const const
QRect boundingRect() const
Returns the rectangle that bounds this surface and all of its sub-surfaces.
void damage(const QRect &rect)
Mark rect as damaged for the next frame.
Definition: surface.cpp:214
Convenient Class which represents a wl_client.
void attachBuffer(wl_buffer *buffer, const QPoint &offset=QPoint())
Attaches the buffer to this Surface for the next frame.
Definition: surface.cpp:233
bool isEmpty() const const
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
State
QRegion united(const QRegion &r) const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Thu Sep 23 2021 22:51:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.