KWin
Loading...
Searching...
No Matches
surface.cpp
Go to the documentation of this file.
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.h"
8#include "blur.h"
9#include "clientconnection.h"
10#include "compositor.h"
11#include "contrast.h"
12#include "display.h"
15#include "idleinhibit_v1_p.h"
17#include "output.h"
19#include "presentationtime.h"
20#include "region_p.h"
21#include "shadow.h"
22#include "slide.h"
23#include "subcompositor.h"
24#include "surface_p.h"
25#include "transaction.h"
26#include "utils/resource.h"
28
29#include <wayland-server.h>
30// std
31#include <algorithm>
32#include <cmath>
33
34namespace KWin
35{
36
37static QRegion map_helper(const QMatrix4x4 &matrix, const QRegion &region)
38{
39 QRegion result;
40 for (const QRect &rect : region) {
41 result += matrix.mapRect(QRectF(rect)).toAlignedRect();
42 }
43 return result;
44}
45
46SurfaceRole::SurfaceRole(const QByteArray &name)
47 : m_name(name)
48{
49}
50
51QByteArray SurfaceRole::name() const
52{
53 return m_name;
54}
55
57 : q(q)
58 , current(std::make_unique<SurfaceState>())
59 , pending(std::make_unique<SurfaceState>())
60{
61}
62
64{
65 // protocol is not precise on how to handle the addition of new sub surfaces
66 current->subsurface.above.append(child);
67 pending->subsurface.above.append(child);
68
69 if (subsurface.transaction) {
70 subsurface.transaction->amend(q, [child](SurfaceState *state) {
71 state->subsurface.above.append(child);
72 });
73 }
74
76 transaction->amend(q, [child](SurfaceState *state) {
77 state->subsurface.above.append(child);
78 });
79 }
80
82 if (preferredBufferScale.has_value()) {
84 }
85 if (preferredBufferTransform.has_value()) {
87 }
90 }
91
92 Q_EMIT q->childSubSurfaceAdded(child);
93 Q_EMIT q->childSubSurfacesChanged();
94}
95
97{
98 // protocol is not precise on how to handle the addition of new sub surfaces
99 current->subsurface.below.removeAll(child);
100 current->subsurface.above.removeAll(child);
101
102 pending->subsurface.below.removeAll(child);
103 pending->subsurface.above.removeAll(child);
104
105 if (subsurface.transaction) {
106 subsurface.transaction->amend(q, [child](SurfaceState *state) {
107 state->subsurface.below.removeOne(child);
108 state->subsurface.above.removeOne(child);
109 });
110 }
111
113 transaction->amend(q, [child](SurfaceState *state) {
114 state->subsurface.below.removeOne(child);
115 state->subsurface.above.removeOne(child);
116 });
117 }
118
119 Q_EMIT q->childSubSurfaceRemoved(child);
120 Q_EMIT q->childSubSurfacesChanged();
121}
122
124{
125 Q_ASSERT(subsurface->parentSurface() == q);
126
127 QList<SubSurfaceInterface *> *anchorList;
128 int anchorIndex;
129
130 pending->subsurface.below.removeOne(subsurface);
131 pending->subsurface.above.removeOne(subsurface);
132
133 if (anchor == q) {
134 // Pretend as if the parent surface were before the first child in the above list.
135 anchorList = &pending->subsurface.above;
136 anchorIndex = -1;
137 } else if (anchorIndex = pending->subsurface.above.indexOf(anchor->subSurface()); anchorIndex != -1) {
138 anchorList = &pending->subsurface.above;
139 } else if (anchorIndex = pending->subsurface.below.indexOf(anchor->subSurface()); anchorIndex != -1) {
140 anchorList = &pending->subsurface.below;
141 } else {
142 return false; // The anchor belongs to other sub-surface tree.
143 }
144
145 anchorList->insert(anchorIndex + 1, subsurface);
146 pending->subsurfaceOrderChanged = true;
147 return true;
148}
149
151{
152 Q_ASSERT(subsurface->parentSurface() == q);
153
154 QList<SubSurfaceInterface *> *anchorList;
155 int anchorIndex;
156
157 pending->subsurface.below.removeOne(subsurface);
158 pending->subsurface.above.removeOne(subsurface);
159
160 if (anchor == q) {
161 // Pretend as if the parent surface were after the last child in the below list.
162 anchorList = &pending->subsurface.below;
163 anchorIndex = pending->subsurface.below.count();
164 } else if (anchorIndex = pending->subsurface.above.indexOf(anchor->subSurface()); anchorIndex != -1) {
165 anchorList = &pending->subsurface.above;
166 } else if (anchorIndex = pending->subsurface.below.indexOf(anchor->subSurface()); anchorIndex != -1) {
167 anchorList = &pending->subsurface.below;
168 } else {
169 return false; // The anchor belongs to other sub-surface tree.
170 }
171
172 anchorList->insert(anchorIndex, subsurface);
173 pending->subsurfaceOrderChanged = true;
174 return true;
175}
176
177void SurfaceInterfacePrivate::setShadow(const QPointer<ShadowInterface> &shadow)
178{
179 pending->shadow = shadow;
180 pending->shadowIsSet = true;
181}
182
183void SurfaceInterfacePrivate::setBlur(const QPointer<BlurInterface> &blur)
184{
185 pending->blur = blur;
186 pending->blurIsSet = true;
187}
188
189void SurfaceInterfacePrivate::setSlide(const QPointer<SlideInterface> &slide)
190{
191 pending->slide = slide;
192 pending->slideIsSet = true;
193}
194
195void SurfaceInterfacePrivate::setContrast(const QPointer<ContrastInterface> &contrast)
196{
197 pending->contrast = contrast;
198 pending->contrastIsSet = true;
199}
200
202{
203 Q_ASSERT(!lockedPointer);
204 Q_ASSERT(!confinedPointer);
205
206 lockedPointer = lock;
207
208 auto cleanUp = [this]() {
209 lockedPointer = nullptr;
210 QObject::disconnect(constrainsOneShotConnection);
211 constrainsOneShotConnection = QMetaObject::Connection();
212 QObject::disconnect(constrainsUnboundConnection);
213 constrainsUnboundConnection = QMetaObject::Connection();
215 };
216
218 constrainsOneShotConnection = QObject::connect(lock, &LockedPointerV1Interface::lockedChanged, q, [this, cleanUp] {
219 if (lockedPointer->isLocked()) {
220 return;
221 }
222 cleanUp();
223 });
224 }
225 constrainsUnboundConnection = QObject::connect(lock, &LockedPointerV1Interface::destroyed, q, cleanUp);
227}
228
230{
231 Q_ASSERT(!lockedPointer);
232 Q_ASSERT(!confinedPointer);
233
234 confinedPointer = confinement;
235
236 auto cleanUp = [this]() {
237 confinedPointer = nullptr;
238 QObject::disconnect(constrainsOneShotConnection);
239 constrainsOneShotConnection = QMetaObject::Connection();
240 QObject::disconnect(constrainsUnboundConnection);
241 constrainsUnboundConnection = QMetaObject::Connection();
243 };
244
246 constrainsOneShotConnection = QObject::connect(confinement, &ConfinedPointerV1Interface::confinedChanged, q, [this, cleanUp] {
248 return;
249 }
250 cleanUp();
251 });
252 }
253 constrainsUnboundConnection = QObject::connect(confinement, &ConfinedPointerV1Interface::destroyed, q, cleanUp);
255}
256
258{
259 idleInhibitors << inhibitor;
260 if (idleInhibitors.count() == 1) {
261 Q_EMIT q->inhibitsIdleChanged();
262 }
263}
264
266{
267 idleInhibitors.removeOne(inhibitor);
268 if (idleInhibitors.isEmpty()) {
269 Q_EMIT q->inhibitsIdleChanged();
270 }
271}
272
274{
275 Q_EMIT q->aboutToBeDestroyed();
276 delete q;
277}
278
280{
281 wl_resource_destroy(resource->handle);
282}
283
284void SurfaceInterfacePrivate::surface_attach(Resource *resource, struct ::wl_resource *buffer, int32_t x, int32_t y)
285{
286 if (wl_resource_get_version(resource->handle) >= WL_SURFACE_OFFSET_SINCE_VERSION) {
287 if (x != 0 || y != 0) {
288 wl_resource_post_error(resource->handle, error_invalid_offset, "wl_surface.attach offset must be 0");
289 return;
290 }
291 } else {
292 pending->offset = QPoint(x, y);
293 }
294
295 pending->bufferIsSet = true;
296 if (!buffer) {
297 // got a null buffer, deletes content in next frame
298 pending->buffer = nullptr;
299 pending->damage = QRegion();
300 pending->bufferDamage = QRegion();
301 return;
302 }
303 pending->buffer = Display::bufferForResource(buffer);
304}
305
306void SurfaceInterfacePrivate::surface_damage(Resource *, int32_t x, int32_t y, int32_t width, int32_t height)
307{
308 pending->damage += QRect(x, y, width, height);
309}
310
311void SurfaceInterfacePrivate::surface_frame(Resource *resource, uint32_t callback)
312{
313 wl_resource *callbackResource = wl_resource_create(resource->client(),
314 &wl_callback_interface,
315 /* version */ 1,
316 callback);
317 if (!callbackResource) {
318 wl_resource_post_no_memory(resource->handle);
319 return;
320 }
321
322 wl_resource_set_implementation(callbackResource, nullptr, nullptr, [](wl_resource *resource) {
323 wl_list_remove(wl_resource_get_link(resource));
324 });
325
326 wl_list_insert(pending->frameCallbacks.prev, wl_resource_get_link(callbackResource));
327}
328
329void SurfaceInterfacePrivate::surface_set_opaque_region(Resource *resource, struct ::wl_resource *region)
330{
332 pending->opaque = r ? r->region() : QRegion();
333 pending->opaqueIsSet = true;
334}
335
336void SurfaceInterfacePrivate::surface_set_input_region(Resource *resource, struct ::wl_resource *region)
337{
339 pending->input = r ? r->region() : infiniteRegion();
340 pending->inputIsSet = true;
341}
342
344{
345 const bool sync = subsurface.handle && subsurface.handle->isSynchronized();
346
348 if (sync) {
349 if (!subsurface.transaction) {
350 subsurface.transaction = std::make_unique<Transaction>();
351 }
352 transaction = subsurface.transaction.get();
353 } else {
354 transaction = new Transaction();
355 }
356
357 for (SubSurfaceInterface *subsurface : std::as_const(pending->subsurface.below)) {
358 auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface());
359 if (surfacePrivate->subsurface.transaction) {
360 transaction->merge(surfacePrivate->subsurface.transaction.get());
361 surfacePrivate->subsurface.transaction.reset();
362 }
363 }
364 for (SubSurfaceInterface *subsurface : std::as_const(pending->subsurface.above)) {
365 auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface());
366 if (surfacePrivate->subsurface.transaction) {
367 transaction->merge(surfacePrivate->subsurface.transaction.get());
368 surfacePrivate->subsurface.transaction.reset();
369 }
370 }
371
372 transaction->add(q);
373 if (!sync) {
374 transaction->commit();
375 }
376
377 pending->serial++;
378}
379
380void SurfaceInterfacePrivate::surface_set_buffer_transform(Resource *resource, int32_t transform)
381{
382 if (transform < 0 || transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
383 wl_resource_post_error(resource->handle, error_invalid_transform, "buffer transform must be a valid transform (%d specified)", transform);
384 return;
385 }
386 pending->bufferTransform = OutputTransform::Kind(transform);
387 pending->bufferTransformIsSet = true;
388}
389
390void SurfaceInterfacePrivate::surface_set_buffer_scale(Resource *resource, int32_t scale)
391{
392 if (scale < 1) {
393 wl_resource_post_error(resource->handle, error_invalid_scale, "buffer scale must be at least one (%d specified)", scale);
394 return;
395 }
396 pending->bufferScale = scale;
397 pending->bufferScaleIsSet = true;
398}
399
400void SurfaceInterfacePrivate::surface_damage_buffer(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
401{
402 pending->bufferDamage += QRect(x, y, width, height);
403}
404
405void SurfaceInterfacePrivate::surface_offset(Resource *resource, int32_t x, int32_t y)
406{
407 pending->offset = QPoint(x, y);
408}
409
411 : QObject(compositor)
412 , d(new SurfaceInterfacePrivate(this))
413{
414 d->compositor = compositor;
415 d->init(resource);
416 d->client = compositor->display()->getConnection(d->resource()->client());
417
418 d->pendingScaleOverride = d->client->scaleOverride();
419 d->scaleOverride = d->pendingScaleOverride;
420 connect(d->client, &ClientConnection::scaleOverrideChanged, this, [this]() {
421 d->pendingScaleOverride = d->client->scaleOverride();
422 });
423}
424
428
430{
431 return d->role;
432}
433
435{
436 d->role = role;
437}
438
439uint32_t SurfaceInterface::id() const
440{
441 return wl_resource_get_id(resource());
442}
443
445{
446 return d->client;
447}
448
449wl_resource *SurfaceInterface::resource() const
450{
451 return d->resource()->handle;
452}
453
455{
456 return d->compositor;
457}
458
460{
461 // notify all callbacks
462 wl_resource *resource;
463 wl_resource *tmp;
464
465 wl_resource_for_each_safe (resource, tmp, &d->current->frameCallbacks) {
466 wl_callback_send_done(resource, msec);
467 wl_resource_destroy(resource);
468 }
469}
470
471std::unique_ptr<PresentationFeedback> SurfaceInterface::takePresentationFeedback(Output *output)
472{
473 if (output && (!d->primaryOutput || d->primaryOutput->handle() != output)) {
474 return nullptr;
475 }
476 return std::move(d->current->presentationFeedback);
477}
478
480{
481 return !wl_list_empty(&d->current->frameCallbacks);
482}
483
485{
486 if (!current->viewport.sourceGeometry.isValid()) {
487 return QRectF(0, 0, bufferSize.width(), bufferSize.height());
488 }
489
490 const QSizeF bounds = current->bufferTransform.map(bufferSize);
491 const QRectF box(current->viewport.sourceGeometry.x() * current->bufferScale,
492 current->viewport.sourceGeometry.y() * current->bufferScale,
493 current->viewport.sourceGeometry.width() * current->bufferScale,
494 current->viewport.sourceGeometry.height() * current->bufferScale);
495
496 return current->bufferTransform.map(box, bounds);
497}
498
500{
501 wl_list_init(&frameCallbacks);
502}
503
505{
506 wl_resource *resource;
507 wl_resource *tmp;
508
509 wl_resource_for_each_safe (resource, tmp, &frameCallbacks) {
510 wl_resource_destroy(resource);
511 }
512}
513
515{
516 target->serial = serial;
517
518 if (bufferIsSet) {
519 target->buffer = buffer;
520 target->offset = offset;
521 target->damage = damage;
522 target->bufferDamage = bufferDamage;
523 target->bufferIsSet = true;
524 }
525 if (viewport.sourceGeometryIsSet) {
526 target->viewport.sourceGeometry = viewport.sourceGeometry;
527 target->viewport.sourceGeometryIsSet = true;
528 }
529 if (viewport.destinationSizeIsSet) {
530 target->viewport.destinationSize = viewport.destinationSize;
531 target->viewport.destinationSizeIsSet = true;
532 }
533
534 target->subsurface = subsurface;
537
538 wl_list_insert_list(&target->frameCallbacks, &frameCallbacks);
539
540 if (shadowIsSet) {
541 target->shadow = shadow;
542 target->shadowIsSet = true;
543 }
544 if (blurIsSet) {
545 target->blur = blur;
546 target->blurIsSet = true;
547 }
548 if (contrastIsSet) {
549 target->contrast = contrast;
550 target->contrastIsSet = true;
551 }
552 if (slideIsSet) {
553 target->slide = slide;
554 target->slideIsSet = true;
555 }
556 if (inputIsSet) {
557 target->input = input;
558 target->inputIsSet = true;
559 }
560 if (opaqueIsSet) {
561 target->opaque = opaque;
562 target->opaqueIsSet = true;
563 }
564 if (bufferScaleIsSet) {
565 target->bufferScale = bufferScale;
566 target->bufferScaleIsSet = true;
567 }
570 target->bufferTransformIsSet = true;
571 }
572 if (contentTypeIsSet) {
573 target->contentType = contentType;
574 target->contentTypeIsSet = true;
575 }
578 target->presentationModeHintIsSet = true;
579 }
582 target->colorDescriptionIsSet = true;
583 }
584 target->presentationFeedback = std::move(presentationFeedback);
585
586 *this = SurfaceState{};
587 serial = target->serial;
588 subsurface = target->subsurface;
589 wl_list_init(&frameCallbacks);
590}
591
593{
594 const bool bufferChanged = next->bufferIsSet;
595 const bool opaqueRegionChanged = next->opaqueIsSet;
596 const bool transformChanged = next->bufferTransformIsSet && (current->bufferTransform != next->bufferTransform);
597 const bool shadowChanged = next->shadowIsSet;
598 const bool blurChanged = next->blurIsSet;
599 const bool contrastChanged = next->contrastIsSet;
600 const bool slideChanged = next->slideIsSet;
601 const bool subsurfaceOrderChanged = next->subsurfaceOrderChanged;
602 const bool visibilityChanged = bufferChanged && bool(current->buffer) != bool(next->buffer);
603 const bool colorDescriptionChanged = next->colorDescriptionIsSet;
604 const bool presentationModeHintChanged = next->presentationModeHintIsSet;
605
606 const QSizeF oldSurfaceSize = surfaceSize;
607 const QSize oldBufferSize = bufferSize;
608 const QRectF oldBufferSourceBox = bufferSourceBox;
609 const QRegion oldInputRegion = inputRegion;
610
611 next->mergeInto(current.get());
612 bufferRef = current->buffer;
614
615 if (current->buffer) {
616 bufferSize = current->buffer->size();
618
619 if (current->viewport.destinationSize.isValid()) {
620 surfaceSize = current->viewport.destinationSize;
621 } else if (current->viewport.sourceGeometry.isValid()) {
622 surfaceSize = current->viewport.sourceGeometry.size();
623 } else {
624 surfaceSize = current->bufferTransform.map(current->buffer->size() / current->bufferScale);
625 }
626
627 const QRectF surfaceRect(QPoint(0, 0), surfaceSize);
628 inputRegion = current->input & surfaceRect.toAlignedRect();
629
630 if (!current->buffer->hasAlphaChannel()) {
631 opaqueRegion = surfaceRect.toAlignedRect();
632 } else {
633 opaqueRegion = current->opaque & surfaceRect.toAlignedRect();
634 }
635
636 QMatrix4x4 scaleOverrideMatrix;
637 if (scaleOverride != 1.) {
638 scaleOverrideMatrix.scale(1. / scaleOverride, 1. / scaleOverride);
639 }
640
641 opaqueRegion = map_helper(scaleOverrideMatrix, opaqueRegion);
642 inputRegion = map_helper(scaleOverrideMatrix, inputRegion);
644 } else {
645 surfaceSize = QSizeF(0, 0);
646 bufferSize = QSize(0, 0);
647 bufferSourceBox = QRectF();
648 inputRegion = QRegion();
649 opaqueRegion = QRegion();
650 }
651
652 if (opaqueRegionChanged) {
654 }
655 if (oldInputRegion != inputRegion) {
656 Q_EMIT q->inputChanged(inputRegion);
657 }
658 if (transformChanged) {
659 Q_EMIT q->bufferTransformChanged(current->bufferTransform);
660 }
661 if (visibilityChanged) {
663 }
664 if (bufferSourceBox != oldBufferSourceBox) {
665 Q_EMIT q->bufferSourceBoxChanged();
666 }
667 if (bufferSize != oldBufferSize) {
668 Q_EMIT q->bufferSizeChanged();
669 }
670 if (surfaceSize != oldSurfaceSize) {
671 Q_EMIT q->sizeChanged();
672 }
673 if (shadowChanged) {
674 Q_EMIT q->shadowChanged();
675 }
676 if (blurChanged) {
677 Q_EMIT q->blurChanged();
678 }
679 if (contrastChanged) {
680 Q_EMIT q->contrastChanged();
681 }
682 if (slideChanged) {
683 Q_EMIT q->slideOnShowHideChanged();
684 }
685 if (subsurfaceOrderChanged) {
686 Q_EMIT q->childSubSurfacesChanged();
687 }
688 if (colorDescriptionChanged) {
689 Q_EMIT q->colorDescriptionChanged();
690 }
691 if (presentationModeHintChanged) {
693 }
694
695 if (bufferChanged) {
696 if (current->buffer && (!current->damage.isEmpty() || !current->bufferDamage.isEmpty())) {
697 const QRect bufferRect = QRect(QPoint(0, 0), current->buffer->size());
698 bufferDamage = current->bufferDamage
699 .united(mapToBuffer(current->damage))
700 .intersected(bufferRect);
701 Q_EMIT q->damaged(bufferDamage);
702 }
703 }
704
705 // The position of a sub-surface is applied when its parent is committed.
706 for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.below)) {
707 subsurface->parentApplyState(next->serial);
708 }
709 for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.above)) {
710 subsurface->parentApplyState(next->serial);
711 }
712
713 Q_EMIT q->stateApplied(next->serial);
714 Q_EMIT q->committed();
715}
716
718{
719 if (!bufferRef) {
720 return false;
721 }
722 if (subsurface.handle) {
723 return subsurface.handle->parentSurface() && subsurface.handle->parentSurface()->isMapped();
724 }
725 return true;
726}
727
729{
730 const bool effectiveMapped = computeEffectiveMapped();
731 if (mapped == effectiveMapped) {
732 return;
733 }
734
735 mapped = effectiveMapped;
736
737 if (mapped) {
738 Q_EMIT q->mapped();
739 } else {
740 Q_EMIT q->unmapped();
741 }
742
743 for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.below)) {
744 auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface());
745 surfacePrivate->updateEffectiveMapped();
746 }
747 for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.above)) {
748 auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface());
749 surfacePrivate->updateEffectiveMapped();
750 }
751}
752
753bool SurfaceInterfacePrivate::contains(const QPointF &position) const
754{
755 // avoid QRectF::contains as that includes all edges
756 const qreal x = position.x();
757 const qreal y = position.y();
758
759 return mapped && x >= 0 && y >= 0 && x < surfaceSize.width() && y < surfaceSize.height();
760}
761
762bool SurfaceInterfacePrivate::inputContains(const QPointF &position) const
763{
764 return contains(position) && inputRegion.contains(QPoint(std::floor(position.x()), std::floor(position.y())));
765}
766
767QRegion SurfaceInterfacePrivate::mapToBuffer(const QRegion &region) const
768{
769 if (region.isEmpty()) {
770 return QRegion();
771 }
772
773 const QRectF sourceBox = current->bufferTransform.inverted().map(bufferSourceBox, bufferSize);
774 const qreal xScale = sourceBox.width() / surfaceSize.width();
775 const qreal yScale = sourceBox.height() / surfaceSize.height();
776
777 QRegion result;
778 for (QRectF rect : region) {
779 result += current->bufferTransform.map(QRectF(rect.x() * xScale, rect.y() * yScale, rect.width() * xScale, rect.height() * yScale), sourceBox.size()).translated(bufferSourceBox.topLeft()).toAlignedRect();
780 }
781 return result;
782}
783
785{
786 return d->bufferDamage;
787}
788
790{
791 return d->opaqueRegion;
792}
793
795{
796 return d->inputRegion;
797}
798
800{
801 return d->bufferSourceBox;
802}
803
805{
806 return d->current->bufferTransform;
807}
808
810{
811 return d->bufferRef.buffer();
812}
813
815{
816 return d->current->offset / d->scaleOverride;
817}
818
820{
821 if (auto surfacePrivate = resource_cast<SurfaceInterfacePrivate *>(native)) {
822 return surfacePrivate->q;
823 }
824 return nullptr;
825}
826
828{
829 if (client) {
830 return get(client->getResource(id));
831 }
832 return nullptr;
833}
834
835QList<SubSurfaceInterface *> SurfaceInterface::below() const
836{
837 return d->current->subsurface.below;
838}
839
840QList<SubSurfaceInterface *> SurfaceInterface::above() const
841{
842 return d->current->subsurface.above;
843}
844
846{
847 return d->subsurface.handle;
848}
849
851{
852 return d->surfaceSize;
853}
854
856{
857 QRectF rect(QPoint(0, 0), size());
858
859 for (const SubSurfaceInterface *subSurface : std::as_const(d->current->subsurface.below)) {
860 const SurfaceInterface *childSurface = subSurface->surface();
861 rect |= childSurface->boundingRect().translated(subSurface->position());
862 }
863 for (const SubSurfaceInterface *subSurface : std::as_const(d->current->subsurface.above)) {
864 const SurfaceInterface *childSurface = subSurface->surface();
865 rect |= childSurface->boundingRect().translated(subSurface->position());
866 }
867
868 return rect;
869}
870
872{
873 return d->current->shadow;
874}
875
877{
878 return d->current->blur;
879}
880
882{
883 return d->current->contrast;
884}
885
887{
888 return d->current->slide;
889}
890
892{
893 return d->mapped;
894}
895
896QList<OutputInterface *> SurfaceInterface::outputs() const
897{
898 return d->outputs;
899}
900
901void SurfaceInterface::setOutputs(const QList<OutputInterface *> &outputs, OutputInterface *primaryOutput)
902{
903 QList<OutputInterface *> removedOutputs = d->outputs;
904 for (auto it = outputs.constBegin(), end = outputs.constEnd(); it != end; ++it) {
905 const auto o = *it;
906 removedOutputs.removeOne(o);
907 }
908 for (auto it = removedOutputs.constBegin(), end = removedOutputs.constEnd(); it != end; ++it) {
909 const auto resources = (*it)->clientResources(client()->client());
910 for (wl_resource *outputResource : resources) {
911 d->send_leave(outputResource);
912 }
913 disconnect(d->outputDestroyedConnections.take(*it));
914 disconnect(d->outputBoundConnections.take(*it));
915 }
916 QList<OutputInterface *> addedOutputsOutputs = outputs;
917 for (auto it = d->outputs.constBegin(), end = d->outputs.constEnd(); it != end; ++it) {
918 const auto o = *it;
919 addedOutputsOutputs.removeOne(o);
920 }
921 for (auto it = addedOutputsOutputs.constBegin(), end = addedOutputsOutputs.constEnd(); it != end; ++it) {
922 const auto o = *it;
923 const auto resources = o->clientResources(client()->client());
924 for (wl_resource *outputResource : resources) {
925 d->send_enter(outputResource);
926 }
927 d->outputDestroyedConnections[o] = connect(o, &OutputInterface::removed, this, [this, o] {
928 auto outputs = d->outputs;
929 if (outputs.removeOne(o)) {
930 setOutputs(outputs, d->primaryOutput);
931 }
932 });
933
934 Q_ASSERT(!d->outputBoundConnections.contains(o));
935 d->outputBoundConnections[o] = connect(o, &OutputInterface::bound, this, [this](ClientConnection *c, wl_resource *outputResource) {
936 if (c != client()) {
937 return;
938 }
939 d->send_enter(outputResource);
940 });
941 }
942
943 d->outputs = outputs;
944 d->primaryOutput = primaryOutput;
945 for (auto child : std::as_const(d->current->subsurface.below)) {
946 child->surface()->setOutputs(outputs, primaryOutput);
947 }
948 for (auto child : std::as_const(d->current->subsurface.above)) {
949 child->surface()->setOutputs(outputs, primaryOutput);
950 }
951}
952
954{
955 if (!isMapped()) {
956 return nullptr;
957 }
958
959 for (auto it = d->current->subsurface.above.crbegin(); it != d->current->subsurface.above.crend(); ++it) {
960 const SubSurfaceInterface *current = *it;
961 SurfaceInterface *surface = current->surface();
962 if (auto s = surface->surfaceAt(position - current->position())) {
963 return s;
964 }
965 }
966
967 // check whether the geometry contains the pos
968 if (d->contains(position)) {
969 return this;
970 }
971
972 for (auto it = d->current->subsurface.below.crbegin(); it != d->current->subsurface.below.crend(); ++it) {
973 const SubSurfaceInterface *current = *it;
974 SurfaceInterface *surface = current->surface();
975 if (auto s = surface->surfaceAt(position - current->position())) {
976 return s;
977 }
978 }
979 return nullptr;
980}
981
983{
984 // TODO: Most of this is very similar to SurfaceInterface::surfaceAt
985 // Is there a way to reduce the code duplication?
986 if (!isMapped()) {
987 return nullptr;
988 }
989
990 for (auto it = d->current->subsurface.above.crbegin(); it != d->current->subsurface.above.crend(); ++it) {
991 const SubSurfaceInterface *current = *it;
992 auto surface = current->surface();
993 if (auto s = surface->inputSurfaceAt(position - current->position())) {
994 return s;
995 }
996 }
997
998 // check whether the geometry and input region contain the pos
999 if (d->inputContains(position)) {
1000 return this;
1001 }
1002
1003 for (auto it = d->current->subsurface.below.crbegin(); it != d->current->subsurface.below.crend(); ++it) {
1004 const SubSurfaceInterface *current = *it;
1005 auto surface = current->surface();
1006 if (auto s = surface->inputSurfaceAt(position - current->position())) {
1007 return s;
1008 }
1009 }
1010
1011 return nullptr;
1012}
1013
1015{
1016 return d->lockedPointer;
1017}
1018
1020{
1021 return d->confinedPointer;
1022}
1023
1025{
1026 return !d->idleInhibitors.isEmpty();
1027}
1028
1030{
1031 return d->dmabufFeedbackV1.get();
1032}
1033
1035{
1036 return d->current->contentType;
1037}
1038
1039QPointF SurfaceInterface::mapToChild(SurfaceInterface *child, const QPointF &point) const
1040{
1041 QPointF local = point;
1042 SurfaceInterface *surface = child;
1043
1044 while (true) {
1045 if (surface == this) {
1046 return local;
1047 }
1048
1049 SubSurfaceInterface *subsurface = surface->subSurface();
1050 if (Q_UNLIKELY(!subsurface)) {
1051 return QPointF();
1052 }
1053
1054 local -= subsurface->position();
1055 surface = subsurface->parentSurface();
1056 }
1057
1058 return QPointF();
1059}
1060
1062{
1063 return d->bufferSize;
1064}
1065
1067{
1068 return d->scaleOverride;
1069}
1070
1071QPoint SurfaceInterface::toSurfaceLocal(const QPoint &point) const
1072{
1073 return QPoint(point.x() * d->scaleOverride, point.y() * d->scaleOverride);
1074}
1075
1076QPointF SurfaceInterface::toSurfaceLocal(const QPointF &point) const
1077{
1078 return QPointF(point.x() * d->scaleOverride, point.y() * d->scaleOverride);
1079}
1080
1082{
1083 return d->current->presentationHint;
1084}
1085
1087{
1088 return d->current->colorDescription;
1089}
1090
1092{
1093 d->preferredColorDescription = descr;
1094 if (d->frogColorManagement) {
1095 d->frogColorManagement->setPreferredColorDescription(descr);
1096 }
1097 if (d->xxColorSurface) {
1098 d->xxColorSurface->setPreferredColorDescription(descr);
1099 }
1100 for (auto child : std::as_const(d->current->subsurface.below)) {
1101 child->surface()->setPreferredColorDescription(descr);
1102 }
1103 for (auto child : std::as_const(d->current->subsurface.above)) {
1104 child->surface()->setPreferredColorDescription(descr);
1105 }
1106}
1107
1109{
1110 if (scale == d->preferredBufferScale) {
1111 return;
1112 }
1113 d->preferredBufferScale = scale;
1114
1115 if (d->fractionalScaleExtension) {
1116 d->fractionalScaleExtension->setPreferredScale(scale);
1117 }
1118 if (d->resource()->version() >= WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION) {
1119 d->send_preferred_buffer_scale(std::ceil(scale));
1120 }
1121
1122 for (auto child : std::as_const(d->current->subsurface.below)) {
1123 child->surface()->setPreferredBufferScale(scale);
1124 }
1125 for (auto child : std::as_const(d->current->subsurface.above)) {
1126 child->surface()->setPreferredBufferScale(scale);
1127 }
1128}
1129
1131{
1132 if (transform == d->preferredBufferTransform) {
1133 return;
1134 }
1135 d->preferredBufferTransform = transform;
1136
1137 if (d->resource()->version() >= WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION) {
1138 d->send_preferred_buffer_transform(uint32_t(transform.kind()));
1139 }
1140
1141 for (auto child : std::as_const(d->current->subsurface.below)) {
1142 child->surface()->setPreferredBufferTransform(transform);
1143 }
1144 for (auto child : std::as_const(d->current->subsurface.above)) {
1145 child->surface()->setPreferredBufferTransform(transform);
1146 }
1147}
1148
1150{
1151 return d->firstTransaction;
1152}
1153
1155{
1156 d->firstTransaction = transaction;
1157}
1158
1160{
1161 return d->lastTransaction;
1162}
1163
1165{
1166 d->lastTransaction = transaction;
1167}
1168
1169void SurfaceInterface::traverseTree(std::function<void(SurfaceInterface *surface)> callback)
1170{
1171 callback(this);
1172
1173 for (SubSurfaceInterface *subsurface : std::as_const(d->current->subsurface.below)) {
1174 subsurface->surface()->traverseTree(callback);
1175 }
1176 for (SubSurfaceInterface *subsurface : std::as_const(d->current->subsurface.above)) {
1177 subsurface->surface()->traverseTree(callback);
1178 }
1179}
1180
1181} // namespace KWin
1182
1183#include "moc_surface.cpp"
Represents the Resource for the org_kde_kwin_blur interface.
Definition blur.h:59
Convenient Class which represents a wl_client.
wl_resource * getResource(quint32 id) const
wl_client * client() const
Display * display() const
Represents the Resource for the org_kde_kwin_contrast interface.
Definition contrast.h:60
ClientConnection * getConnection(wl_client *client)
Definition display.cpp:200
virtual QSize size() const =0
void bound(ClientConnection *client, wl_resource *boundResource)
Kind kind() const
Definition output.cpp:64
static RegionInterface * get(wl_resource *native)
Definition region.cpp:42
QRegion region() const
Definition region.cpp:37
SurfaceInterface * parentSurface() const
SurfaceInterface * surface() const
Resource representing a wl_surface.
Definition surface.h:80
SlideInterface * slideOnShowHide() const
Definition surface.cpp:886
std::unique_ptr< PresentationFeedback > takePresentationFeedback(Output *output)
Definition surface.cpp:471
const ColorDescription & colorDescription() const
Definition surface.cpp:1086
SurfaceInterface * surfaceAt(const QPointF &position)
Definition surface.cpp:953
ClientConnection * client() const
Definition surface.cpp:444
void damaged(const QRegion &)
PresentationModeHint presentationModeHint() const
Definition surface.cpp:1081
static SurfaceInterface * get(wl_resource *native)
Definition surface.cpp:819
ContentType contentType() const
Definition surface.cpp:1034
void setPreferredBufferScale(qreal scale)
Definition surface.cpp:1108
void stateApplied(quint32 serial)
QRectF bufferSourceBox() const
Definition surface.cpp:799
QRegion bufferDamage() const
Definition surface.cpp:784
BlurInterface * blur() const
Definition surface.cpp:876
void setPreferredBufferTransform(OutputTransform transform)
Definition surface.cpp:1130
void inputChanged(const QRegion &)
void childSubSurfaceRemoved(SubSurfaceInterface *subSurface)
void traverseTree(std::function< void(SurfaceInterface *surface)> callback)
Definition surface.cpp:1169
bool isMapped() const
Definition surface.cpp:891
QPoint offset() const
Definition surface.cpp:814
QPointF mapToChild(SurfaceInterface *child, const QPointF &point) const
Definition surface.cpp:1039
void setLastTransaction(Transaction *transaction)
Definition surface.cpp:1164
OutputTransform bufferTransform() const
Definition surface.cpp:804
GraphicsBuffer * buffer() const
Definition surface.cpp:809
QPoint toSurfaceLocal(const QPoint &point) const
Definition surface.cpp:1071
QSize bufferSize() const
Definition surface.cpp:1061
SurfaceRole * role() const
Definition surface.cpp:429
ShadowInterface * shadow() const
Definition surface.cpp:871
QList< OutputInterface * > outputs() const
Definition surface.cpp:896
void bufferTransformChanged(KWin::OutputTransform)
void setFirstTransaction(Transaction *transaction)
Definition surface.cpp:1154
SurfaceInterface(CompositorInterface *compositor, wl_resource *resource)
Definition surface.cpp:410
ContrastInterface * contrast() const
Definition surface.cpp:881
SubSurfaceInterface * subSurface() const
Definition surface.cpp:845
uint32_t id() const
Definition surface.cpp:439
void presentationModeHintChanged()
wl_resource * resource() const
Definition surface.cpp:449
void opaqueChanged(const QRegion &)
void childSubSurfaceAdded(SubSurfaceInterface *subSurface)
QList< SubSurfaceInterface * > above() const
Definition surface.cpp:840
LinuxDmaBufV1Feedback * dmabufFeedbackV1() const
Definition surface.cpp:1029
~SurfaceInterface() override
Definition surface.cpp:425
Transaction * firstTransaction() const
Definition surface.cpp:1149
void frameRendered(quint32 msec)
Definition surface.cpp:459
ConfinedPointerV1Interface * confinedPointer() const
Definition surface.cpp:1019
CompositorInterface * compositor() const
Definition surface.cpp:454
void setOutputs(const QList< OutputInterface * > &outputs, OutputInterface *primaryOutput)
Definition surface.cpp:901
QList< SubSurfaceInterface * > below() const
Definition surface.cpp:835
QRectF boundingRect() const
Definition surface.cpp:855
void setPreferredColorDescription(const ColorDescription &descr)
Definition surface.cpp:1091
bool inhibitsIdle() const
Definition surface.cpp:1024
LockedPointerV1Interface * lockedPointer() const
Definition surface.cpp:1014
qreal scaleOverride() const
Definition surface.cpp:1066
SurfaceInterface * inputSurfaceAt(const QPointF &position)
Definition surface.cpp:982
void setRole(SurfaceRole *role)
Definition surface.cpp:434
bool hasFrameCallbacks() const
Definition surface.cpp:479
Transaction * lastTransaction() const
Definition surface.cpp:1159
QRectF computeBufferSourceBox() const
Definition surface.cpp:484
void surface_commit(Resource *resource) override
Definition surface.cpp:343
void setContrast(const QPointer< ContrastInterface > &contrast)
Definition surface.cpp:195
void installIdleInhibitor(IdleInhibitorV1Interface *inhibitor)
Definition surface.cpp:257
void removeIdleInhibitor(IdleInhibitorV1Interface *inhibitor)
Definition surface.cpp:265
void surface_set_input_region(Resource *resource, struct ::wl_resource *region) override
Definition surface.cpp:336
void setBlur(const QPointer< BlurInterface > &blur)
Definition surface.cpp:183
void surface_set_buffer_scale(Resource *resource, int32_t scale) override
Definition surface.cpp:390
bool raiseChild(SubSurfaceInterface *subsurface, SurfaceInterface *anchor)
Definition surface.cpp:123
ConfinedPointerV1Interface * confinedPointer
Definition surface_p.h:160
QList< OutputInterface * > outputs
Definition surface_p.h:153
std::unique_ptr< Transaction > transaction
Definition surface_p.h:177
bool contains(const QPointF &position) const
Definition surface.cpp:753
void surface_destroy(Resource *resource) override
Definition surface.cpp:279
std::unique_ptr< SurfaceState > current
Definition surface_p.h:136
void surface_frame(Resource *resource, uint32_t callback) override
Definition surface.cpp:311
std::optional< qreal > preferredBufferScale
Definition surface_p.h:155
void setShadow(const QPointer< ShadowInterface > &shadow)
Definition surface.cpp:177
void removeChild(SubSurfaceInterface *subsurface)
Definition surface.cpp:96
bool computeEffectiveMapped() const
Definition surface.cpp:717
std::unique_ptr< SurfaceState > pending
Definition surface_p.h:137
void surface_damage(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override
Definition surface.cpp:306
void surface_destroy_resource(Resource *resource) override
Definition surface.cpp:273
static SurfaceInterfacePrivate * get(SurfaceInterface *surface)
Definition surface_p.h:99
QRegion mapToBuffer(const QRegion &region) const
Definition surface.cpp:767
void installPointerConstraint(LockedPointerV1Interface *lock)
Definition surface.cpp:201
bool inputContains(const QPointF &position) const
Definition surface.cpp:762
GraphicsBufferRef bufferRef
Definition surface_p.h:144
void surface_damage_buffer(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override
Definition surface.cpp:400
void surface_attach(Resource *resource, struct ::wl_resource *buffer, int32_t x, int32_t y) override
Definition surface.cpp:284
LockedPointerV1Interface * lockedPointer
Definition surface_p.h:159
QList< IdleInhibitorV1Interface * > idleInhibitors
Definition surface_p.h:164
SurfaceInterfacePrivate(SurfaceInterface *q)
Definition surface.cpp:56
QPointer< OutputInterface > primaryOutput
Definition surface_p.h:154
void addChild(SubSurfaceInterface *subsurface)
Definition surface.cpp:63
void surface_set_buffer_transform(Resource *resource, int32_t transform) override
Definition surface.cpp:380
void surface_set_opaque_region(Resource *resource, struct ::wl_resource *region) override
Definition surface.cpp:329
struct KWin::SurfaceInterfacePrivate::@30 subsurface
void surface_offset(Resource *resource, int32_t x, int32_t y) override
Definition surface.cpp:405
void applyState(SurfaceState *next)
Definition surface.cpp:592
bool lowerChild(SubSurfaceInterface *subsurface, SurfaceInterface *anchor)
Definition surface.cpp:150
std::optional< OutputTransform > preferredBufferTransform
Definition surface_p.h:156
void setSlide(const QPointer< SlideInterface > &slide)
Definition surface.cpp:189
std::optional< ColorDescription > preferredColorDescription
Definition surface_p.h:157
QByteArray name() const
Definition surface.cpp:51
SurfaceRole(const QByteArray &name)
Definition surface.cpp:46
Transaction * next(SurfaceInterface *surface) const
KWIN_EXPORT QRect infiniteRegion()
Definition globals.h:234
PresentationModeHint
Definition globals.h:299
ContentType
Definition globals.h:284
bool destinationSizeIsSet
Definition surface_p.h:92
QPointer< ContrastInterface > contrast
Definition surface_p.h:68
struct KWin::SurfaceState::@29 viewport
void mergeInto(SurfaceState *target)
Definition surface.cpp:514
bool colorDescriptionIsSet
Definition surface_p.h:60
QPointer< SlideInterface > slide
Definition surface_p.h:69
OutputTransform bufferTransform
Definition surface_p.h:62
ContentType contentType
Definition surface_p.h:70
bool presentationModeHintIsSet
Definition surface_p.h:59
PresentationModeHint presentationHint
Definition surface_p.h:71
QRectF sourceGeometry
Definition surface_p.h:89
struct KWin::SurfaceState::@28 subsurface
QPointer< ShadowInterface > shadow
Definition surface_p.h:66
QPointer< BlurInterface > blur
Definition surface_p.h:67
QList< SubSurfaceInterface * > below
Definition surface_p.h:80
ColorDescription colorDescription
Definition surface_p.h:72
bool bufferTransformIsSet
Definition surface_p.h:57
bool subsurfacePositionChanged
Definition surface_p.h:55
wl_list frameCallbacks
Definition surface_p.h:63
QPointer< GraphicsBuffer > buffer
Definition surface_p.h:65
QRegion bufferDamage
Definition surface_p.h:44
std::unique_ptr< PresentationTimeFeedback > presentationFeedback
Definition surface_p.h:73
bool subsurfaceOrderChanged
Definition surface_p.h:54
QList< SubSurfaceInterface * > above
Definition surface_p.h:81