1 /*
2     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
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 {
SurfaceInterfacePrivate(SurfaceInterface * q)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 
~SurfaceInterfacePrivate()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 
addChild(SubSurfaceInterface * child)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 
removeChild(SubSurfaceInterface * child)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 
raiseChild(SubSurfaceInterface * subsurface,SurfaceInterface * anchor)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 
lowerChild(SubSurfaceInterface * subsurface,SurfaceInterface * anchor)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 
setShadow(const QPointer<ShadowInterface> & shadow)134 void SurfaceInterfacePrivate::setShadow(const QPointer<ShadowInterface> &shadow)
135 {
136     pending.shadow = shadow;
137     pending.shadowIsSet = true;
138 }
139 
setBlur(const QPointer<BlurInterface> & blur)140 void SurfaceInterfacePrivate::setBlur(const QPointer<BlurInterface> &blur)
141 {
142     pending.blur = blur;
143     pending.blurIsSet = true;
144 }
145 
setSlide(const QPointer<SlideInterface> & slide)146 void SurfaceInterfacePrivate::setSlide(const QPointer<SlideInterface> &slide)
147 {
148     pending.slide = slide;
149     pending.slideIsSet = true;
150 }
151 
setContrast(const QPointer<ContrastInterface> & contrast)152 void SurfaceInterfacePrivate::setContrast(const QPointer<ContrastInterface> &contrast)
153 {
154     pending.contrast = contrast;
155     pending.contrastIsSet = true;
156 }
157 
installPointerConstraint(LockedPointerV1Interface * lock)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 
installPointerConstraint(ConfinedPointerV1Interface * confinement)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 
installIdleInhibitor(IdleInhibitorV1Interface * inhibitor)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 
surface_destroy_resource(Resource *)228 void SurfaceInterfacePrivate::surface_destroy_resource(Resource *)
229 {
230     Q_EMIT q->aboutToBeDestroyed();
231     delete q;
232 }
233 
surface_destroy(Resource * resource)234 void SurfaceInterfacePrivate::surface_destroy(Resource *resource)
235 {
236     wl_resource_destroy(resource->handle);
237 }
238 
surface_attach(Resource * resource,struct::wl_resource * buffer,int32_t x,int32_t y)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 
surface_damage(Resource *,int32_t x,int32_t y,int32_t width,int32_t height)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 
surface_frame(Resource * resource,uint32_t callback)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 
surface_set_opaque_region(Resource * resource,struct::wl_resource * region)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 
surface_set_input_region(Resource * resource,struct::wl_resource * region)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 
surface_commit(Resource * resource)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 
surface_set_buffer_transform(Resource * resource,int32_t transform)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 
surface_set_buffer_scale(Resource * resource,int32_t scale)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 
surface_damage_buffer(Resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)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 
SurfaceInterface(CompositorInterface * compositor,wl_resource * resource)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 
~SurfaceInterface()338 SurfaceInterface::~SurfaceInterface()
339 {
340 }
341 
id() const342 uint32_t SurfaceInterface::id() const
343 {
344     return wl_resource_get_id(resource());
345 }
346 
client() const347 ClientConnection *SurfaceInterface::client() const
348 {
349     return d->client;
350 }
351 
resource() const352 wl_resource *SurfaceInterface::resource() const
353 {
354     return d->resource()->handle;
355 }
356 
compositor() const357 CompositorInterface *SurfaceInterface::compositor() const
358 {
359     return d->compositor;
360 }
361 
frameRendered(quint32 msec)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 
hasFrameCallbacks() const382 bool SurfaceInterface::hasFrameCallbacks() const
383 {
384     return !wl_list_empty(&d->current.frameCallbacks);
385 }
386 
buildSurfaceToBufferMatrix()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 
mergeInto(SurfaceState * target)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 
applyState(SurfaceState * next)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 
commitSubSurface()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 
commitToCache()653 void SurfaceInterfacePrivate::commitToCache()
654 {
655     pending.mergeInto(&cached);
656     hasCacheState = true;
657 }
658 
commitFromCache()659 void SurfaceInterfacePrivate::commitFromCache()
660 {
661     applyState(&cached);
662     hasCacheState = false;
663 }
664 
computeEffectiveMapped() const665 bool SurfaceInterfacePrivate::computeEffectiveMapped() const
666 {
667     return bufferRef && (!subSurface || subSurface->parentSurface()->isMapped());
668 }
669 
updateEffectiveMapped()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 
damage() const695 QRegion SurfaceInterface::damage() const
696 {
697     return d->current.damage;
698 }
699 
opaque() const700 QRegion SurfaceInterface::opaque() const
701 {
702     return d->current.opaque;
703 }
704 
input() const705 QRegion SurfaceInterface::input() const
706 {
707     return d->inputRegion;
708 }
709 
bufferScale() const710 qint32 SurfaceInterface::bufferScale() const
711 {
712     return d->current.bufferScale;
713 }
714 
bufferTransform() const715 OutputInterface::Transform SurfaceInterface::bufferTransform() const
716 {
717     return d->current.bufferTransform;
718 }
719 
buffer() const720 ClientBuffer *SurfaceInterface::buffer() const
721 {
722     return d->bufferRef;
723 }
724 
offset() const725 QPoint SurfaceInterface::offset() const
726 {
727     return d->current.offset;
728 }
729 
get(wl_resource * native)730 SurfaceInterface *SurfaceInterface::get(wl_resource *native)
731 {
732     if (auto surfacePrivate = resource_cast<SurfaceInterfacePrivate *>(native)) {
733         return surfacePrivate->q;
734     }
735     return nullptr;
736 }
737 
get(quint32 id,const ClientConnection * client)738 SurfaceInterface *SurfaceInterface::get(quint32 id, const ClientConnection *client)
739 {
740     if (client) {
741         return get(client->getResource(id));
742     }
743     return nullptr;
744 }
745 
below() const746 QList<SubSurfaceInterface *> SurfaceInterface::below() const
747 {
748     return d->current.below;
749 }
750 
above() const751 QList<SubSurfaceInterface *> SurfaceInterface::above() const
752 {
753     return d->current.above;
754 }
755 
subSurface() const756 SubSurfaceInterface *SurfaceInterface::subSurface() const
757 {
758     return d->subSurface;
759 }
760 
size() const761 QSize SurfaceInterface::size() const
762 {
763     return d->surfaceSize;
764 }
765 
boundingRect() const766 QRect SurfaceInterface::boundingRect() const
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 
shadow() const782 QPointer<ShadowInterface> SurfaceInterface::shadow() const
783 {
784     return d->current.shadow;
785 }
786 
blur() const787 QPointer<BlurInterface> SurfaceInterface::blur() const
788 {
789     return d->current.blur;
790 }
791 
contrast() const792 QPointer<ContrastInterface> SurfaceInterface::contrast() const
793 {
794     return d->current.contrast;
795 }
796 
slideOnShowHide() const797 QPointer<SlideInterface> SurfaceInterface::slideOnShowHide() const
798 {
799     return d->current.slide;
800 }
801 
isMapped() const802 bool SurfaceInterface::isMapped() const
803 {
804     return d->mapped;
805 }
806 
outputs() const807 QVector<OutputInterface *> SurfaceInterface::outputs() const
808 {
809     return d->outputs;
810 }
811 
setOutputs(const QVector<OutputInterface * > & outputs)812 void SurfaceInterface::setOutputs(const QVector<OutputInterface *> &outputs)
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 
surfaceAt(const QPointF & position)863 SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position)
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 
inputSurfaceAt(const QPointF & position)892 SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position)
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 
lockedPointer() const924 LockedPointerV1Interface *SurfaceInterface::lockedPointer() const
925 {
926     return d->lockedPointer;
927 }
928 
confinedPointer() const929 ConfinedPointerV1Interface *SurfaceInterface::confinedPointer() const
930 {
931     return d->confinedPointer;
932 }
933 
inhibitsIdle() const934 bool SurfaceInterface::inhibitsIdle() const
935 {
936     return !d->idleInhibitors.isEmpty();
937 }
938 
mapToBuffer(const QPointF & point) const939 QPointF SurfaceInterface::mapToBuffer(const QPointF &point) const
940 {
941     return d->surfaceToBufferMatrix.map(point);
942 }
943 
mapFromBuffer(const QPointF & point) const944 QPointF SurfaceInterface::mapFromBuffer(const QPointF &point) const
945 {
946     return d->bufferToSurfaceMatrix.map(point);
947 }
948 
map_helper(const QMatrix4x4 & matrix,const QRegion & region)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 
mapToBuffer(const QRegion & region) const958 QRegion SurfaceInterface::mapToBuffer(const QRegion &region) const
959 {
960     return map_helper(d->surfaceToBufferMatrix, region);
961 }
962 
mapFromBuffer(const QRegion & region) const963 QRegion SurfaceInterface::mapFromBuffer(const QRegion &region) const
964 {
965     return map_helper(d->bufferToSurfaceMatrix, region);
966 }
967 
surfaceToBufferMatrix() const968 QMatrix4x4 SurfaceInterface::surfaceToBufferMatrix() const
969 {
970     return d->surfaceToBufferMatrix;
971 }
972 
mapToChild(SurfaceInterface * child,const QPointF & point) const973 QPointF SurfaceInterface::mapToChild(SurfaceInterface *child, const QPointF &point) const
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 
bufferSize() const995 QSize SurfaceInterface::bufferSize() const
996 {
997     return d->bufferSize;
998 }
999 
1000 } // namespace KWaylandServer
1001