KWaylandServer

surface_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3  SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 #include "surface_interface.h"
8 #include "clientbuffer.h"
9 #include "clientconnection.h"
10 #include "compositor_interface.h"
11 #include "display.h"
12 #include "idleinhibit_v1_interface_p.h"
13 #include "pointerconstraints_v1_interface_p.h"
14 #include "region_interface_p.h"
15 #include "subcompositor_interface.h"
16 #include "subsurface_interface_p.h"
17 #include "surface_interface_p.h"
18 #include "surfacerole_p.h"
19 #include "utils.h"
20 // std
21 #include <algorithm>
22 
23 namespace KWaylandServer
24 {
25 SurfaceInterfacePrivate::SurfaceInterfacePrivate(SurfaceInterface *q)
26  : q(q)
27 {
28  wl_list_init(&current.frameCallbacks);
29  wl_list_init(&pending.frameCallbacks);
30  wl_list_init(&cached.frameCallbacks);
31 }
32 
33 SurfaceInterfacePrivate::~SurfaceInterfacePrivate()
34 {
35  wl_resource *resource;
36  wl_resource *tmp;
37 
38  wl_resource_for_each_safe(resource, tmp, &current.frameCallbacks)
39  {
40  wl_resource_destroy(resource);
41  }
42  wl_resource_for_each_safe(resource, tmp, &pending.frameCallbacks)
43  {
44  wl_resource_destroy(resource);
45  }
46  wl_resource_for_each_safe(resource, tmp, &cached.frameCallbacks)
47  {
48  wl_resource_destroy(resource);
49  }
50 
51  if (current.buffer) {
52  current.buffer->unref();
53  }
54 }
55 
56 void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child)
57 {
58  // protocol is not precise on how to handle the addition of new sub surfaces
59  pending.above.append(child);
60  cached.above.append(child);
61  current.above.append(child);
62  child->surface()->setOutputs(outputs);
63  Q_EMIT q->childSubSurfaceAdded(child);
64  Q_EMIT q->childSubSurfacesChanged();
65 }
66 
67 void SurfaceInterfacePrivate::removeChild(SubSurfaceInterface *child)
68 {
69  // protocol is not precise on how to handle the addition of new sub surfaces
70  pending.below.removeAll(child);
71  pending.above.removeAll(child);
72  cached.below.removeAll(child);
73  cached.above.removeAll(child);
74  current.below.removeAll(child);
75  current.above.removeAll(child);
76  Q_EMIT q->childSubSurfaceRemoved(child);
77  Q_EMIT q->childSubSurfacesChanged();
78 }
79 
80 bool SurfaceInterfacePrivate::raiseChild(SubSurfaceInterface *subsurface, SurfaceInterface *anchor)
81 {
82  Q_ASSERT(subsurface->parentSurface() == q);
83 
84  QList<SubSurfaceInterface *> *anchorList;
85  int anchorIndex;
86 
87  pending.below.removeOne(subsurface);
88  pending.above.removeOne(subsurface);
89 
90  if (anchor == q) {
91  // Pretend as if the parent surface were before the first child in the above list.
92  anchorList = &pending.above;
93  anchorIndex = -1;
94  } else if (anchorIndex = pending.above.indexOf(anchor->subSurface()); anchorIndex != -1) {
95  anchorList = &pending.above;
96  } else if (anchorIndex = pending.below.indexOf(anchor->subSurface()); anchorIndex != -1) {
97  anchorList = &pending.below;
98  } else {
99  return false; // The anchor belongs to other sub-surface tree.
100  }
101 
102  anchorList->insert(anchorIndex + 1, subsurface);
103  pending.childrenChanged = true;
104  return true;
105 }
106 
107 bool SurfaceInterfacePrivate::lowerChild(SubSurfaceInterface *subsurface, SurfaceInterface *anchor)
108 {
109  Q_ASSERT(subsurface->parentSurface() == q);
110 
111  QList<SubSurfaceInterface *> *anchorList;
112  int anchorIndex;
113 
114  pending.below.removeOne(subsurface);
115  pending.above.removeOne(subsurface);
116 
117  if (anchor == q) {
118  // Pretend as if the parent surface were after the last child in the below list.
119  anchorList = &pending.below;
120  anchorIndex = pending.below.count();
121  } else if (anchorIndex = pending.above.indexOf(anchor->subSurface()); anchorIndex != -1) {
122  anchorList = &pending.above;
123  } else if (anchorIndex = pending.below.indexOf(anchor->subSurface()); anchorIndex != -1) {
124  anchorList = &pending.below;
125  } else {
126  return false; // The anchor belongs to other sub-surface tree.
127  }
128 
129  anchorList->insert(anchorIndex, subsurface);
130  pending.childrenChanged = true;
131  return true;
132 }
133 
134 void SurfaceInterfacePrivate::setShadow(const QPointer<ShadowInterface> &shadow)
135 {
136  pending.shadow = shadow;
137  pending.shadowIsSet = true;
138 }
139 
140 void SurfaceInterfacePrivate::setBlur(const QPointer<BlurInterface> &blur)
141 {
142  pending.blur = blur;
143  pending.blurIsSet = true;
144 }
145 
146 void SurfaceInterfacePrivate::setSlide(const QPointer<SlideInterface> &slide)
147 {
148  pending.slide = slide;
149  pending.slideIsSet = true;
150 }
151 
152 void SurfaceInterfacePrivate::setContrast(const QPointer<ContrastInterface> &contrast)
153 {
154  pending.contrast = contrast;
155  pending.contrastIsSet = true;
156 }
157 
158 void SurfaceInterfacePrivate::installPointerConstraint(LockedPointerV1Interface *lock)
159 {
160  Q_ASSERT(!lockedPointer);
161  Q_ASSERT(!confinedPointer);
162 
163  lockedPointer = lock;
164 
165  auto cleanUp = [this]() {
166  lockedPointer = nullptr;
167  QObject::disconnect(constrainsOneShotConnection);
168  constrainsOneShotConnection = QMetaObject::Connection();
169  QObject::disconnect(constrainsUnboundConnection);
170  constrainsUnboundConnection = QMetaObject::Connection();
171  Q_EMIT q->pointerConstraintsChanged();
172  };
173 
174  if (lock->lifeTime() == LockedPointerV1Interface::LifeTime::OneShot) {
175  constrainsOneShotConnection = QObject::connect(lock, &LockedPointerV1Interface::lockedChanged, q, [this, cleanUp] {
176  if (lockedPointer->isLocked()) {
177  return;
178  }
179  cleanUp();
180  });
181  }
182  constrainsUnboundConnection = QObject::connect(lock, &LockedPointerV1Interface::destroyed, q, cleanUp);
183  Q_EMIT q->pointerConstraintsChanged();
184 }
185 
186 void SurfaceInterfacePrivate::installPointerConstraint(ConfinedPointerV1Interface *confinement)
187 {
188  Q_ASSERT(!lockedPointer);
189  Q_ASSERT(!confinedPointer);
190 
191  confinedPointer = confinement;
192 
193  auto cleanUp = [this]() {
194  confinedPointer = nullptr;
195  QObject::disconnect(constrainsOneShotConnection);
196  constrainsOneShotConnection = QMetaObject::Connection();
197  QObject::disconnect(constrainsUnboundConnection);
198  constrainsUnboundConnection = QMetaObject::Connection();
199  Q_EMIT q->pointerConstraintsChanged();
200  };
201 
202  if (confinement->lifeTime() == ConfinedPointerV1Interface::LifeTime::OneShot) {
203  constrainsOneShotConnection = QObject::connect(confinement, &ConfinedPointerV1Interface::confinedChanged, q, [this, cleanUp] {
204  if (confinedPointer->isConfined()) {
205  return;
206  }
207  cleanUp();
208  });
209  }
210  constrainsUnboundConnection = QObject::connect(confinement, &ConfinedPointerV1Interface::destroyed, q, cleanUp);
211  Q_EMIT q->pointerConstraintsChanged();
212 }
213 
214 void SurfaceInterfacePrivate::installIdleInhibitor(IdleInhibitorV1Interface *inhibitor)
215 {
216  idleInhibitors << inhibitor;
217  QObject::connect(inhibitor, &IdleInhibitorV1Interface::destroyed, q, [this, inhibitor] {
218  idleInhibitors.removeOne(inhibitor);
219  if (idleInhibitors.isEmpty()) {
220  Q_EMIT q->inhibitsIdleChanged();
221  }
222  });
223  if (idleInhibitors.count() == 1) {
224  Q_EMIT q->inhibitsIdleChanged();
225  }
226 }
227 
228 void SurfaceInterfacePrivate::surface_destroy_resource(Resource *)
229 {
230  Q_EMIT q->aboutToBeDestroyed();
231  delete q;
232 }
233 
234 void SurfaceInterfacePrivate::surface_destroy(Resource *resource)
235 {
236  wl_resource_destroy(resource->handle);
237 }
238 
239 void SurfaceInterfacePrivate::surface_attach(Resource *resource, struct ::wl_resource *buffer, int32_t x, int32_t y)
240 {
241  Q_UNUSED(resource)
242  pending.bufferIsSet = true;
243  pending.offset = QPoint(x, y);
244  if (!buffer) {
245  // got a null buffer, deletes content in next frame
246  pending.buffer = nullptr;
247  pending.damage = QRegion();
248  pending.bufferDamage = QRegion();
249  return;
250  }
251  pending.buffer = compositor->display()->clientBufferForResource(buffer);
252 }
253 
254 void SurfaceInterfacePrivate::surface_damage(Resource *, int32_t x, int32_t y, int32_t width, int32_t height)
255 {
256  pending.damage |= QRect(x, y, width, height);
257 }
258 
259 void SurfaceInterfacePrivate::surface_frame(Resource *resource, uint32_t callback)
260 {
261  wl_resource *callbackResource = wl_resource_create(resource->client(),
262  &wl_callback_interface,
263  /* version */ 1,
264  callback);
265  if (!callbackResource) {
266  wl_resource_post_no_memory(resource->handle);
267  return;
268  }
269 
270  wl_resource_set_implementation(callbackResource, nullptr, nullptr, [](wl_resource *resource) {
271  wl_list_remove(wl_resource_get_link(resource));
272  });
273 
274  wl_list_insert(pending.frameCallbacks.prev, wl_resource_get_link(callbackResource));
275 }
276 
277 void SurfaceInterfacePrivate::surface_set_opaque_region(Resource *resource, struct ::wl_resource *region)
278 {
279  Q_UNUSED(resource)
280  RegionInterface *r = RegionInterface::get(region);
281  pending.opaque = r ? r->region() : QRegion();
282  pending.opaqueIsSet = true;
283 }
284 
285 void SurfaceInterfacePrivate::surface_set_input_region(Resource *resource, struct ::wl_resource *region)
286 {
287  Q_UNUSED(resource)
288  RegionInterface *r = RegionInterface::get(region);
289  pending.input = r ? r->region() : infiniteRegion();
290  pending.inputIsSet = true;
291 }
292 
293 void SurfaceInterfacePrivate::surface_commit(Resource *resource)
294 {
295  Q_UNUSED(resource)
296  if (subSurface) {
297  commitSubSurface();
298  } else {
299  applyState(&pending);
300  }
301 }
302 
303 void SurfaceInterfacePrivate::surface_set_buffer_transform(Resource *resource, int32_t transform)
304 {
305  if (transform < 0 || transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
306  wl_resource_post_error(resource->handle, error_invalid_transform, "buffer transform must be a valid transform (%d specified)", transform);
307  return;
308  }
309  pending.bufferTransform = OutputInterface::Transform(transform);
310  pending.bufferTransformIsSet = true;
311 }
312 
313 void SurfaceInterfacePrivate::surface_set_buffer_scale(Resource *resource, int32_t scale)
314 {
315  if (scale < 1) {
316  wl_resource_post_error(resource->handle, error_invalid_scale, "buffer scale must be at least one (%d specified)", scale);
317  return;
318  }
319  pending.bufferScale = scale;
320  pending.bufferScaleIsSet = true;
321 }
322 
323 void SurfaceInterfacePrivate::surface_damage_buffer(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
324 {
325  Q_UNUSED(resource)
326  pending.bufferDamage |= QRect(x, y, width, height);
327 }
328 
329 SurfaceInterface::SurfaceInterface(CompositorInterface *compositor, wl_resource *resource)
330  : QObject(compositor)
331  , d(new SurfaceInterfacePrivate(this))
332 {
333  d->compositor = compositor;
334  d->init(resource);
335  d->client = compositor->display()->getConnection(d->resource()->client());
336 }
337 
338 SurfaceInterface::~SurfaceInterface()
339 {
340 }
341 
342 uint32_t SurfaceInterface::id() const
343 {
344  return wl_resource_get_id(resource());
345 }
346 
348 {
349  return d->client;
350 }
351 
352 wl_resource *SurfaceInterface::resource() const
353 {
354  return d->resource()->handle;
355 }
356 
358 {
359  return d->compositor;
360 }
361 
362 void SurfaceInterface::frameRendered(quint32 msec)
363 {
364  // notify all callbacks
365  wl_resource *resource;
366  wl_resource *tmp;
367 
368  wl_resource_for_each_safe(resource, tmp, &d->current.frameCallbacks)
369  {
370  wl_callback_send_done(resource, msec);
371  wl_resource_destroy(resource);
372  }
373 
374  for (SubSurfaceInterface *subsurface : qAsConst(d->current.below)) {
375  subsurface->surface()->frameRendered(msec);
376  }
377  for (SubSurfaceInterface *subsurface : qAsConst(d->current.above)) {
378  subsurface->surface()->frameRendered(msec);
379  }
380 }
381 
382 bool SurfaceInterface::hasFrameCallbacks() const
383 {
384  return !wl_list_empty(&d->current.frameCallbacks);
385 }
386 
387 QMatrix4x4 SurfaceInterfacePrivate::buildSurfaceToBufferMatrix()
388 {
389  // The order of transforms is reversed, i.e. the viewport transform is the first one.
390 
391  QMatrix4x4 surfaceToBufferMatrix;
392 
393  if (!current.buffer) {
394  return surfaceToBufferMatrix;
395  }
396 
397  surfaceToBufferMatrix.scale(current.bufferScale, current.bufferScale);
398 
399  switch (current.bufferTransform) {
400  case OutputInterface::Transform::Normal:
401  case OutputInterface::Transform::Flipped:
402  break;
403  case OutputInterface::Transform::Rotated90:
404  case OutputInterface::Transform::Flipped90:
405  surfaceToBufferMatrix.translate(0, bufferSize.height() / current.bufferScale);
406  surfaceToBufferMatrix.rotate(-90, 0, 0, 1);
407  break;
408  case OutputInterface::Transform::Rotated180:
409  case OutputInterface::Transform::Flipped180:
410  surfaceToBufferMatrix.translate(bufferSize.width() / current.bufferScale, bufferSize.height() / current.bufferScale);
411  surfaceToBufferMatrix.rotate(-180, 0, 0, 1);
412  break;
413  case OutputInterface::Transform::Rotated270:
414  case OutputInterface::Transform::Flipped270:
415  surfaceToBufferMatrix.translate(bufferSize.width() / current.bufferScale, 0);
416  surfaceToBufferMatrix.rotate(-270, 0, 0, 1);
417  break;
418  }
419 
420  switch (current.bufferTransform) {
421  case OutputInterface::Transform::Flipped:
422  case OutputInterface::Transform::Flipped180:
423  surfaceToBufferMatrix.translate(bufferSize.width() / current.bufferScale, 0);
424  surfaceToBufferMatrix.scale(-1, 1);
425  break;
426  case OutputInterface::Transform::Flipped90:
427  case OutputInterface::Transform::Flipped270:
428  surfaceToBufferMatrix.translate(bufferSize.height() / current.bufferScale, 0);
429  surfaceToBufferMatrix.scale(-1, 1);
430  break;
431  default:
432  break;
433  }
434 
435  if (current.viewport.sourceGeometry.isValid()) {
436  surfaceToBufferMatrix.translate(current.viewport.sourceGeometry.x(), current.viewport.sourceGeometry.y());
437  surfaceToBufferMatrix.scale(current.viewport.sourceGeometry.width() / surfaceSize.width(),
438  current.viewport.sourceGeometry.height() / surfaceSize.height());
439  }
440 
441  return surfaceToBufferMatrix;
442 }
443 
444 void SurfaceState::mergeInto(SurfaceState *target)
445 {
446  if (bufferIsSet) {
447  target->buffer = buffer;
448  target->offset = offset;
449  target->damage = damage;
450  target->bufferDamage = bufferDamage;
451  target->bufferIsSet = bufferIsSet;
452  }
453  if (viewport.sourceGeometryIsSet) {
454  target->viewport.sourceGeometry = viewport.sourceGeometry;
455  target->viewport.sourceGeometryIsSet = true;
456  }
457  if (viewport.destinationSizeIsSet) {
458  target->viewport.destinationSize = viewport.destinationSize;
459  target->viewport.destinationSizeIsSet = true;
460  }
461  if (childrenChanged) {
462  target->below = below;
463  target->above = above;
464  target->childrenChanged = true;
465  }
466  wl_list_insert_list(&target->frameCallbacks, &frameCallbacks);
467 
468  if (shadowIsSet) {
469  target->shadow = shadow;
470  target->shadowIsSet = true;
471  }
472  if (blurIsSet) {
473  target->blur = blur;
474  target->blurIsSet = true;
475  }
476  if (contrastIsSet) {
477  target->contrast = contrast;
478  target->contrastIsSet = true;
479  }
480  if (slideIsSet) {
481  target->slide = slide;
482  target->slideIsSet = true;
483  }
484  if (inputIsSet) {
485  target->input = input;
486  target->inputIsSet = true;
487  }
488  if (opaqueIsSet) {
489  target->opaque = opaque;
490  target->opaqueIsSet = true;
491  }
492  if (bufferScaleIsSet) {
493  target->bufferScale = bufferScale;
494  target->bufferScaleIsSet = true;
495  }
496  if (bufferTransformIsSet) {
497  target->bufferTransform = bufferTransform;
498  target->bufferTransformIsSet = true;
499  }
500 
501  *this = SurfaceState{};
502  below = target->below;
503  above = target->above;
504  wl_list_init(&frameCallbacks);
505 }
506 
507 void SurfaceInterfacePrivate::applyState(SurfaceState *next)
508 {
509  const bool bufferChanged = next->bufferIsSet;
510  const bool opaqueRegionChanged = next->opaqueIsSet;
511  const bool scaleFactorChanged = next->bufferScaleIsSet && (current.bufferScale != next->bufferScale);
512  const bool transformChanged = next->bufferTransformIsSet && (current.bufferTransform != next->bufferTransform);
513  const bool shadowChanged = next->shadowIsSet;
514  const bool blurChanged = next->blurIsSet;
515  const bool contrastChanged = next->contrastIsSet;
516  const bool slideChanged = next->slideIsSet;
517  const bool childrenChanged = next->childrenChanged;
518  const bool visibilityChanged = bufferChanged && bool(current.buffer) != bool(next->buffer);
519 
520  const QSize oldSurfaceSize = surfaceSize;
521  const QSize oldBufferSize = bufferSize;
522  const QMatrix4x4 oldSurfaceToBufferMatrix = surfaceToBufferMatrix;
523  const QRegion oldInputRegion = inputRegion;
524 
525  next->mergeInto(&current);
526 
527  if (lockedPointer) {
528  auto lockedPointerPrivate = LockedPointerV1InterfacePrivate::get(lockedPointer);
529  lockedPointerPrivate->commit();
530  }
531  if (confinedPointer) {
532  auto confinedPointerPrivate = ConfinedPointerV1InterfacePrivate::get(confinedPointer);
533  confinedPointerPrivate->commit();
534  }
535 
536  if (bufferRef != current.buffer) {
537  if (bufferRef) {
538  bufferRef->unref();
539  }
540  bufferRef = current.buffer;
541  if (bufferRef) {
542  bufferRef->ref();
543  }
544  }
545 
546  // TODO: Refactor the state management code because it gets more clumsy.
547  if (current.buffer) {
548  bufferSize = current.buffer->size();
549  if (current.viewport.destinationSize.isValid()) {
550  surfaceSize = current.viewport.destinationSize;
551  } else if (current.viewport.sourceGeometry.isValid()) {
552  surfaceSize = current.viewport.sourceGeometry.size().toSize();
553  } else {
554  surfaceSize = current.buffer->size() / current.bufferScale;
555  switch (current.bufferTransform) {
556  case OutputInterface::Transform::Rotated90:
557  case OutputInterface::Transform::Rotated270:
558  case OutputInterface::Transform::Flipped90:
559  case OutputInterface::Transform::Flipped270:
560  surfaceSize.transpose();
561  break;
562  case OutputInterface::Transform::Normal:
563  case OutputInterface::Transform::Rotated180:
564  case OutputInterface::Transform::Flipped:
565  case OutputInterface::Transform::Flipped180:
566  break;
567  }
568  }
569  } else {
570  surfaceSize = QSize();
571  bufferSize = QSize();
572  }
573 
574  surfaceToBufferMatrix = buildSurfaceToBufferMatrix();
575  bufferToSurfaceMatrix = surfaceToBufferMatrix.inverted();
576  inputRegion = current.input & QRect(QPoint(0, 0), surfaceSize);
577  if (opaqueRegionChanged) {
578  Q_EMIT q->opaqueChanged(current.opaque);
579  }
580  if (oldInputRegion != inputRegion) {
581  Q_EMIT q->inputChanged(inputRegion);
582  }
583  if (scaleFactorChanged) {
584  Q_EMIT q->bufferScaleChanged(current.bufferScale);
585  }
586  if (transformChanged) {
587  Q_EMIT q->bufferTransformChanged(current.bufferTransform);
588  }
589  if (visibilityChanged) {
590  updateEffectiveMapped();
591  }
592  if (bufferChanged) {
593  if (current.buffer && (!current.damage.isEmpty() || !current.bufferDamage.isEmpty())) {
594  const QRegion windowRegion = QRegion(0, 0, q->size().width(), q->size().height());
595  const QRegion bufferDamage = q->mapFromBuffer(current.bufferDamage);
596  current.damage = windowRegion.intersected(current.damage.united(bufferDamage));
597  Q_EMIT q->damaged(current.damage);
598  }
599  }
600  if (surfaceToBufferMatrix != oldSurfaceToBufferMatrix) {
601  Q_EMIT q->surfaceToBufferMatrixChanged();
602  }
603  if (bufferSize != oldBufferSize) {
604  Q_EMIT q->bufferSizeChanged();
605  }
606  if (surfaceSize != oldSurfaceSize) {
607  Q_EMIT q->sizeChanged();
608  }
609  if (shadowChanged) {
610  Q_EMIT q->shadowChanged();
611  }
612  if (blurChanged) {
613  Q_EMIT q->blurChanged();
614  }
615  if (contrastChanged) {
616  Q_EMIT q->contrastChanged();
617  }
618  if (slideChanged) {
619  Q_EMIT q->slideOnShowHideChanged();
620  }
621  if (childrenChanged) {
622  Q_EMIT q->childSubSurfacesChanged();
623  }
624  // The position of a sub-surface is applied when its parent is committed.
625  for (SubSurfaceInterface *subsurface : qAsConst(current.below)) {
626  auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
627  subsurfacePrivate->parentCommit();
628  }
629  for (SubSurfaceInterface *subsurface : qAsConst(current.above)) {
630  auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
631  subsurfacePrivate->parentCommit();
632  }
633  if (role) {
634  role->commit();
635  }
636  Q_EMIT q->committed();
637 }
638 
639 void SurfaceInterfacePrivate::commitSubSurface()
640 {
641  if (subSurface->isSynchronized()) {
642  commitToCache();
643  } else {
644  if (hasCacheState) {
645  commitToCache();
646  commitFromCache();
647  } else {
648  applyState(&pending);
649  }
650  }
651 }
652 
653 void SurfaceInterfacePrivate::commitToCache()
654 {
655  pending.mergeInto(&cached);
656  hasCacheState = true;
657 }
658 
659 void SurfaceInterfacePrivate::commitFromCache()
660 {
661  applyState(&cached);
662  hasCacheState = false;
663 }
664 
665 bool SurfaceInterfacePrivate::computeEffectiveMapped() const
666 {
667  return bufferRef && (!subSurface || subSurface->parentSurface()->isMapped());
668 }
669 
670 void SurfaceInterfacePrivate::updateEffectiveMapped()
671 {
672  const bool effectiveMapped = computeEffectiveMapped();
673  if (mapped == effectiveMapped) {
674  return;
675  }
676 
677  mapped = effectiveMapped;
678 
679  if (mapped) {
680  Q_EMIT q->mapped();
681  } else {
682  Q_EMIT q->unmapped();
683  }
684 
685  for (SubSurfaceInterface *subsurface : qAsConst(current.below)) {
686  auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface());
687  surfacePrivate->updateEffectiveMapped();
688  }
689  for (SubSurfaceInterface *subsurface : qAsConst(current.above)) {
690  auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface());
691  surfacePrivate->updateEffectiveMapped();
692  }
693 }
694 
695 QRegion SurfaceInterface::damage() const
696 {
697  return d->current.damage;
698 }
699 
700 QRegion SurfaceInterface::opaque() const
701 {
702  return d->current.opaque;
703 }
704 
705 QRegion SurfaceInterface::input() const
706 {
707  return d->inputRegion;
708 }
709 
710 qint32 SurfaceInterface::bufferScale() const
711 {
712  return d->current.bufferScale;
713 }
714 
715 OutputInterface::Transform SurfaceInterface::bufferTransform() const
716 {
717  return d->current.bufferTransform;
718 }
719 
721 {
722  return d->bufferRef;
723 }
724 
725 QPoint SurfaceInterface::offset() const
726 {
727  return d->current.offset;
728 }
729 
731 {
732  if (auto surfacePrivate = resource_cast<SurfaceInterfacePrivate *>(native)) {
733  return surfacePrivate->q;
734  }
735  return nullptr;
736 }
737 
739 {
740  if (client) {
741  return get(client->getResource(id));
742  }
743  return nullptr;
744 }
745 
747 {
748  return d->current.below;
749 }
750 
752 {
753  return d->current.above;
754 }
755 
757 {
758  return d->subSurface;
759 }
760 
762 {
763  return d->surfaceSize;
764 }
765 
767 {
768  QRect rect(QPoint(0, 0), size());
769 
770  for (const SubSurfaceInterface *subSurface : qAsConst(d->current.below)) {
771  const SurfaceInterface *childSurface = subSurface->surface();
772  rect |= childSurface->boundingRect().translated(subSurface->position());
773  }
774  for (const SubSurfaceInterface *subSurface : qAsConst(d->current.above)) {
775  const SurfaceInterface *childSurface = subSurface->surface();
776  rect |= childSurface->boundingRect().translated(subSurface->position());
777  }
778 
779  return rect;
780 }
781 
783 {
784  return d->current.shadow;
785 }
786 
788 {
789  return d->current.blur;
790 }
791 
793 {
794  return d->current.contrast;
795 }
796 
798 {
799  return d->current.slide;
800 }
801 
803 {
804  return d->mapped;
805 }
806 
808 {
809  return d->outputs;
810 }
811 
813 {
814  QVector<OutputInterface *> removedOutputs = d->outputs;
815  for (auto it = outputs.constBegin(), end = outputs.constEnd(); it != end; ++it) {
816  const auto o = *it;
817  removedOutputs.removeOne(o);
818  }
819  for (auto it = removedOutputs.constBegin(), end = removedOutputs.constEnd(); it != end; ++it) {
820  const auto resources = (*it)->clientResources(client());
821  for (wl_resource *outputResource : resources) {
822  d->send_leave(outputResource);
823  }
824  disconnect(d->outputDestroyedConnections.take(*it));
825  disconnect(d->outputBoundConnections.take(*it));
826  }
827  QVector<OutputInterface *> addedOutputsOutputs = outputs;
828  for (auto it = d->outputs.constBegin(), end = d->outputs.constEnd(); it != end; ++it) {
829  const auto o = *it;
830  addedOutputsOutputs.removeOne(o);
831  }
832  for (auto it = addedOutputsOutputs.constBegin(), end = addedOutputsOutputs.constEnd(); it != end; ++it) {
833  const auto o = *it;
834  const auto resources = o->clientResources(client());
835  for (wl_resource *outputResource : resources) {
836  d->send_enter(outputResource);
837  }
838  d->outputDestroyedConnections[o] = connect(o, &OutputInterface::removed, this, [this, o] {
839  auto outputs = d->outputs;
840  if (outputs.removeOne(o)) {
841  setOutputs(outputs);
842  }
843  });
844 
845  Q_ASSERT(!d->outputBoundConnections.contains(o));
846  d->outputBoundConnections[o] = connect(o, &OutputInterface::bound, this, [this](ClientConnection *c, wl_resource *outputResource) {
847  if (c != client()) {
848  return;
849  }
850  d->send_enter(outputResource);
851  });
852  }
853 
854  d->outputs = outputs;
855  for (auto child : qAsConst(d->current.below)) {
856  child->surface()->setOutputs(outputs);
857  }
858  for (auto child : qAsConst(d->current.above)) {
859  child->surface()->setOutputs(outputs);
860  }
861 }
862 
864 {
865  if (!isMapped()) {
866  return nullptr;
867  }
868 
869  for (auto it = d->current.above.crbegin(); it != d->current.above.crend(); ++it) {
870  const SubSurfaceInterface *current = *it;
871  SurfaceInterface *surface = current->surface();
872  if (auto s = surface->surfaceAt(position - current->position())) {
873  return s;
874  }
875  }
876 
877  // check whether the geometry contains the pos
878  if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position)) {
879  return this;
880  }
881 
882  for (auto it = d->current.below.crbegin(); it != d->current.below.crend(); ++it) {
883  const SubSurfaceInterface *current = *it;
884  SurfaceInterface *surface = current->surface();
885  if (auto s = surface->surfaceAt(position - current->position())) {
886  return s;
887  }
888  }
889  return nullptr;
890 }
891 
893 {
894  // TODO: Most of this is very similar to SurfaceInterface::surfaceAt
895  // Is there a way to reduce the code duplication?
896  if (!isMapped()) {
897  return nullptr;
898  }
899 
900  for (auto it = d->current.above.crbegin(); it != d->current.above.crend(); ++it) {
901  const SubSurfaceInterface *current = *it;
902  auto surface = current->surface();
903  if (auto s = surface->inputSurfaceAt(position - current->position())) {
904  return s;
905  }
906  }
907 
908  // check whether the geometry and input region contain the pos
909  if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position) && input().contains(position.toPoint())) {
910  return this;
911  }
912 
913  for (auto it = d->current.below.crbegin(); it != d->current.below.crend(); ++it) {
914  const SubSurfaceInterface *current = *it;
915  auto surface = current->surface();
916  if (auto s = surface->inputSurfaceAt(position - current->position())) {
917  return s;
918  }
919  }
920 
921  return nullptr;
922 }
923 
925 {
926  return d->lockedPointer;
927 }
928 
930 {
931  return d->confinedPointer;
932 }
933 
935 {
936  return !d->idleInhibitors.isEmpty();
937 }
938 
940 {
941  return d->surfaceToBufferMatrix.map(point);
942 }
943 
945 {
946  return d->bufferToSurfaceMatrix.map(point);
947 }
948 
949 static QRegion map_helper(const QMatrix4x4 &matrix, const QRegion &region)
950 {
951  QRegion result;
952  for (const QRect &rect : region) {
953  result += matrix.mapRect(rect);
954  }
955  return result;
956 }
957 
958 QRegion SurfaceInterface::mapToBuffer(const QRegion &region) const
959 {
960  return map_helper(d->surfaceToBufferMatrix, region);
961 }
962 
963 QRegion SurfaceInterface::mapFromBuffer(const QRegion &region) const
964 {
965  return map_helper(d->bufferToSurfaceMatrix, region);
966 }
967 
969 {
970  return d->surfaceToBufferMatrix;
971 }
972 
974 {
975  QPointF local = point;
976  SurfaceInterface *surface = child;
977 
978  while (true) {
979  if (surface == this) {
980  return local;
981  }
982 
983  SubSurfaceInterface *subsurface = surface->subSurface();
984  if (Q_UNLIKELY(!subsurface)) {
985  return QPointF();
986  }
987 
988  local -= subsurface->position();
989  surface = subsurface->parentSurface();
990  }
991 
992  return QPointF();
993 }
994 
996 {
997  return d->bufferSize;
998 }
999 
1000 } // namespace KWaylandServer
QSize bufferSize() const
Returns the size of the attached buffer, in device pixels.
void translate(const QVector3D &vector)
void setOutputs(const QVector< OutputInterface * > &outputs)
Sets the outputs this SurfaceInterface overlaps with, may be empty.
The ConfinedPointerV1Interface gets installed on a SurfaceInterface.
void scale(const QVector3D &vector)
QRect boundingRect() const
Returns the rectangle that bounds this surface and all of its sub-surfaces.
SurfaceInterface * surface() const
Returns the SurfaceInterface for this SubSurfaceInterface.
void confinedChanged()
Emitted whenever the isConfined state changes.
SubSurfaceInterface * subSurface() const
QMatrix4x4 surfaceToBufferMatrix() const
Returns the projection matrix from the surface-local coordinates to buffer coordinates.
CompositorInterface * compositor() const
Returns the compositor for this SurfaceInterface.
QVector::const_iterator constEnd() const const
void viewport(const QRectF &rect)
ClientConnection * client() const
Returns the Wayland client that owns this SurfaceInterface.
bool contains(const QRectF &rectangle) const const
wl_resource * getResource(quint32 id) const
Get the wl_resource associated with the given id.
QVector< OutputInterface * > outputs() const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QRect mapRect(const QRect &rect) const const
QList< SubSurfaceInterface * > below() const
Returns the sub-surfaces that are below this surface.
SurfaceInterface * inputSurfaceAt(const QPointF &position)
Finds the input receiving SurfaceInterface at the given position in surface-local coordinates...
The SubSurfaceInterface corresponds to the Wayland interface wl_subsurface.
static SurfaceInterface * get(wl_resource *native)
void rotate(float angle, const QVector3D &vector)
QPointF mapFromBuffer(const QPointF &point) const
Maps the specified point from the buffer pixel coordinates to surface-local coordinates.
QRegion intersected(const QRegion &r) const const
QPointer< SlideInterface > slideOnShowHide() const
QRect translated(int dx, int dy) const const
ConfinedPointerV1Interface * confinedPointer() const
Pointer confinement installed on this SurfaceInterface.
void lockedChanged()
Emitted whenever the isLocked state changes.
bool removeOne(const T &t)
QPointer< ShadowInterface > shadow() const
void bound(ClientConnection *client, wl_resource *boundResource)
Emitted when a client binds to a given output.
QPointF mapToBuffer(const QPointF &point) const
Maps the specified point from the surface-local coordinates to buffer pixel coordinates.
Convenient Class which represents a wl_client.
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 isMapped() const
Whether the SurfaceInterface is currently considered to be mapped.
QList< SubSurfaceInterface * > above() const
Returns the sub-surfaces that are above this surface.
QVector::const_iterator constBegin() const const
QPoint toPoint() const const
uint32_t id() const
Returns the object id for this Wayland surface.
QPointer< BlurInterface > blur() const
SurfaceInterface * surfaceAt(const QPointF &position)
Finds the SurfaceInterface at the given position in surface-local coordinates.
SurfaceInterface * parentSurface() const
Returns the parent surface for this SubSurfaceInterface.
Resource representing a wl_surface.
OutputInterface::Transform bufferTransform() const
Returns the buffer transform that had been applied to the buffer to compensate for output rotation...
The ClientBuffer class represents a client buffer.
Definition: clientbuffer.h:29
The LockedPointerV1Interface lets the client request to disable movements of the virtual pointer (i...
wl_resource * resource() const
Returns the Wayland resource corresponding to this SurfaceInterface.
The CompositorInterface global allows clients to create surfaces and region objects.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QSize size() const
Returns the current size of the surface, in surface coordinates.
bool removeOne(const T &value)
void destroyed(QObject *obj)
QPointer< ContrastInterface > contrast() const
Q_EMITQ_EMIT
LockedPointerV1Interface * lockedPointer() const
Pointer lock installed on this SurfaceInterface.
QPoint position() const
Returns the position of the sub-surface relative to the upper-left corner of its parent.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Oct 25 2021 23:08:44 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.