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(¤t.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, ¤t.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(¤t);
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 ®ion)
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 ®ion) const
959 {
960 return map_helper(d->surfaceToBufferMatrix, region);
961 }
962
mapFromBuffer(const QRegion & region) const963 QRegion SurfaceInterface::mapFromBuffer(const QRegion ®ion) 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