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

KDE's Doxygen guidelines are available online.