6 #include "surface_interface.h" 7 #include "surface_interface_p.h" 8 #include "buffer_interface.h" 9 #include "clientconnection.h" 10 #include "compositor_interface.h" 11 #include "idleinhibit_interface_p.h" 12 #include "pointerconstraints_interface_p.h" 13 #include "region_interface.h" 14 #include "subcompositor_interface.h" 15 #include "subsurface_interface_p.h" 16 #include "surfacerole_p.h" 18 #include <QListIterator> 20 #include <wayland-server.h> 29 SurfaceInterface::Private::Private(SurfaceInterface *q, CompositorInterface *c, wl_resource *parentResource)
30 : Resource::Private(q, c, parentResource, &wl_surface_interface, &s_interface)
34 SurfaceInterface::Private::~Private()
42 pending.children.append(child);
43 subSurfacePending.children.append(child);
44 current.children.append(child);
45 Q_Q(SurfaceInterface);
46 Q_EMIT q->childSubSurfaceAdded(child);
47 Q_EMIT q->subSurfaceTreeChanged();
48 QObject::connect(child.
data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
49 QObject::connect(child->surface().
data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
50 QObject::connect(child->surface().
data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
51 QObject::connect(child->surface().
data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
57 pending.children.removeAll(child);
58 subSurfacePending.children.removeAll(child);
59 current.children.removeAll(child);
60 Q_Q(SurfaceInterface);
61 Q_EMIT q->childSubSurfaceRemoved(child);
62 Q_EMIT q->subSurfaceTreeChanged();
63 QObject::disconnect(child.
data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
64 if (!child->surface().
isNull()) {
65 QObject::disconnect(child->surface().
data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
66 QObject::disconnect(child->surface().
data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
67 QObject::disconnect(child->surface().
data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
73 Q_Q(SurfaceInterface);
74 auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
75 if (it == pending.children.end()) {
78 if (pending.children.count() == 1) {
84 pending.children.append(*it);
85 pending.children.erase(it);
86 pending.childrenChanged =
true;
89 if (!sibling->subSurface()) {
93 auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
94 if (siblingIt == pending.children.end() || siblingIt == it) {
99 pending.children.erase(it);
101 siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
102 pending.children.insert(++siblingIt, value);
103 pending.childrenChanged =
true;
109 Q_Q(SurfaceInterface);
110 auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
111 if (it == pending.children.end()) {
114 if (pending.children.count() == 1) {
121 pending.children.erase(it);
122 pending.children.prepend(value);
123 pending.childrenChanged =
true;
126 if (!sibling->subSurface()) {
130 auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
131 if (siblingIt == pending.children.end() || siblingIt == it) {
136 pending.children.erase(it);
138 siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
139 pending.children.insert(siblingIt, value);
140 pending.childrenChanged =
true;
146 pending.shadow = shadow;
147 pending.shadowIsSet =
true;
153 pending.blurIsSet =
true;
158 pending.slide = slide;
159 pending.slideIsSet =
true;
164 pending.contrast = contrast;
165 pending.contrastIsSet =
true;
168 void SurfaceInterface::Private::installPointerConstraint(LockedPointerInterface *lock)
170 Q_ASSERT(lockedPointer.isNull());
171 Q_ASSERT(confinedPointer.isNull());
174 auto cleanUp = [
this]() {
175 lockedPointer.
clear();
180 Q_EMIT q_func()->pointerConstraintsChanged();
183 if (lock->lifeTime() == LockedPointerInterface::LifeTime::OneShot) {
184 constrainsOneShotConnection =
QObject::connect(lock, &LockedPointerInterface::lockedChanged, q_func(),
186 if (lockedPointer.isNull() || lockedPointer->isLocked()) {
193 constrainsUnboundConnection =
QObject::connect(lock, &LockedPointerInterface::unbound, q_func(),
195 if (lockedPointer.isNull()) {
201 Q_EMIT q_func()->pointerConstraintsChanged();
204 void SurfaceInterface::Private::installPointerConstraint(ConfinedPointerInterface *confinement)
206 Q_ASSERT(lockedPointer.isNull());
207 Q_ASSERT(confinedPointer.isNull());
210 auto cleanUp = [
this]() {
211 confinedPointer.
clear();
216 Q_EMIT q_func()->pointerConstraintsChanged();
219 if (confinement->lifeTime() == ConfinedPointerInterface::LifeTime::OneShot) {
220 constrainsOneShotConnection =
QObject::connect(confinement, &ConfinedPointerInterface::confinedChanged, q_func(),
222 if (confinedPointer.isNull() || confinedPointer->isConfined()) {
229 constrainsUnboundConnection =
QObject::connect(confinement, &ConfinedPointerInterface::unbound, q_func(),
231 if (confinedPointer.isNull()) {
237 Q_EMIT q_func()->pointerConstraintsChanged();
240 void SurfaceInterface::Private::installIdleInhibitor(IdleInhibitorInterface *inhibitor)
242 idleInhibitors << inhibitor;
245 idleInhibitors.removeOne(inhibitor);
246 if (idleInhibitors.isEmpty()) {
247 Q_EMIT q_func()->inhibitsIdleChanged();
251 if (idleInhibitors.count() == 1) {
252 Q_EMIT q_func()->inhibitsIdleChanged();
257 const struct wl_surface_interface SurfaceInterface::Private::s_interface = {
258 resourceDestroyedCallback,
262 opaqueRegionCallback,
265 bufferTransformCallback,
271 SurfaceInterface::SurfaceInterface(CompositorInterface *
parent, wl_resource *parentResource)
272 : Resource(new Private(this, parent, parentResource))
276 SurfaceInterface::~SurfaceInterface() =
default;
278 void SurfaceInterface::frameRendered(quint32 msec)
282 const bool needsFlush = !d->current.callbacks.isEmpty();
283 while (!d->current.callbacks.isEmpty()) {
284 wl_resource *r = d->current.callbacks.takeFirst();
285 wl_callback_send_done(r, msec);
286 wl_resource_destroy(r);
288 for (
auto it = d->current.children.constBegin(); it != d->current.children.constEnd(); ++it) {
289 const auto &subSurface = *it;
290 if (subSurface.isNull() || subSurface->d_func()->surface.isNull()) {
293 subSurface->d_func()->surface->frameRendered(msec);
300 void SurfaceInterface::Private::destroy()
306 callbacksToDestroy << current.callbacks;
307 current.callbacks.
clear();
308 callbacksToDestroy << pending.callbacks;
309 pending.callbacks.
clear();
310 callbacksToDestroy << subSurfacePending.callbacks;
311 subSurfacePending.callbacks.
clear();
313 wl_resource_destroy(*it);
315 if (current.buffer) {
316 current.buffer->unref();
320 void SurfaceInterface::Private::swapStates(State *source, State *target,
bool emitChanged)
322 Q_Q(SurfaceInterface);
323 bool bufferChanged = source->bufferIsSet;
324 const bool opaqueRegionChanged = source->opaqueIsSet;
325 const bool inputRegionChanged = source->inputIsSet;
326 const bool scaleFactorChanged = source->scaleIsSet && (target->scale != source->scale);
327 const bool transformChanged = source->transformIsSet && (target->transform != source->transform);
328 const bool shadowChanged = source->shadowIsSet;
329 const bool blurChanged = source->blurIsSet;
330 const bool contrastChanged = source->contrastIsSet;
331 const bool slideChanged = source->slideIsSet;
332 const bool childrenChanged = source->childrenChanged;
333 bool sizeChanged =
false;
334 auto buffer = target->buffer;
338 if (target->buffer) {
339 oldSize = target->buffer->size();
341 target->buffer->unref();
342 QObject::disconnect(target->buffer, &BufferInterface::sizeChanged, q, &SurfaceInterface::sizeChanged);
344 delete target->buffer;
345 target->buffer =
nullptr;
348 if (source->buffer) {
350 source->buffer->ref();
351 QObject::connect(source->buffer, &BufferInterface::sizeChanged, q, &SurfaceInterface::sizeChanged);
353 const QSize newSize = source->buffer->size();
354 sizeChanged = newSize.
isValid() && newSize != oldSize;
356 if (!target->buffer && !source->buffer && emitChanged) {
358 bufferChanged =
false;
360 buffer = source->buffer;
364 target->buffer = buffer;
365 target->offset = source->offset;
366 target->damage = source->damage;
367 target->bufferDamage = source->bufferDamage;
368 target->bufferIsSet = source->bufferIsSet;
370 if (childrenChanged) {
371 target->childrenChanged = source->childrenChanged;
372 target->children = source->children;
374 target->callbacks.append(source->callbacks);
377 target->shadow = source->shadow;
378 target->shadowIsSet =
true;
381 target->blur = source->blur;
382 target->blurIsSet =
true;
384 if (contrastChanged) {
385 target->contrast = source->contrast;
386 target->contrastIsSet =
true;
389 target->slide = source->slide;
390 target->slideIsSet =
true;
392 if (inputRegionChanged) {
393 target->input = source->input;
394 target->inputIsInfinite = source->inputIsInfinite;
395 target->inputIsSet =
true;
397 if (opaqueRegionChanged) {
398 target->opaque = source->opaque;
399 target->opaqueIsSet =
true;
401 if (scaleFactorChanged) {
402 target->
scale = source->scale;
403 target->scaleIsSet =
true;
405 if (transformChanged) {
406 target->transform = source->transform;
407 target->transformIsSet =
true;
409 if (!lockedPointer.isNull()) {
410 lockedPointer->d_func()->commit();
412 if (!confinedPointer.isNull()) {
413 confinedPointer->d_func()->commit();
417 source->children = target->children;
418 if (opaqueRegionChanged) {
419 Q_EMIT q->opaqueChanged(target->opaque);
421 if (inputRegionChanged) {
422 Q_EMIT q->inputChanged(target->input);
424 if (scaleFactorChanged) {
425 Q_EMIT q->scaleChanged(target->scale);
426 if (buffer && !sizeChanged) {
430 if (transformChanged) {
431 Q_EMIT q->transformChanged(target->transform);
433 if (bufferChanged && emitChanged) {
434 if (target->buffer && (!target->damage.isEmpty() || !target->bufferDamage.isEmpty())) {
435 const QRegion windowRegion =
QRegion(0, 0, q->size().width(), q->size().height());
438 if (!target->bufferDamage.isEmpty()) {
439 typedef OutputInterface::Transform Tr;
440 const Tr
tr = target->transform;
441 const qint32 sc = target->scale;
442 if (tr == Tr::Rotated90 || tr == Tr::Rotated270 ||
443 tr == Tr::Flipped90 || tr == Tr::Flipped270) {
445 for (
const auto &rect : target->bufferDamage) {
446 const auto add =
QRegion(rect.x() / sc, rect.y() / sc, rect.height() / sc, rect.width() / sc);
447 bufferDamage = bufferDamage.
united(add);
449 }
else if (sc != 1) {
451 for (
const auto &rect : target->bufferDamage) {
452 const auto add =
QRegion(rect.x() / sc, rect.y() / sc, rect.width() / sc, rect.height() / sc);
453 bufferDamage = bufferDamage.
united(add);
456 bufferDamage = target->bufferDamage;
459 target->damage = windowRegion.
intersected(target->damage.united(bufferDamage));
461 subSurfaceIsMapped =
true;
462 trackedDamage = trackedDamage.
united(target->damage);
463 Q_EMIT q->damaged(target->damage);
467 const auto mainSurface = subSurface->mainSurface();
468 if (!mainSurface || !mainSurface->buffer()) {
474 }
else if (!target->buffer && emitChanged) {
475 subSurfaceIsMapped =
false;
486 Q_EMIT q->shadowChanged();
491 if (contrastChanged) {
492 Q_EMIT q->contrastChanged();
495 Q_EMIT q->slideOnShowHideChanged();
497 if (childrenChanged) {
498 Q_EMIT q->subSurfaceTreeChanged();
502 void SurfaceInterface::Private::commit()
504 Q_Q(SurfaceInterface);
505 if (!subSurface.isNull() && subSurface->isSynchronized()) {
506 swapStates(&pending, &subSurfacePending,
false);
508 swapStates(&pending, ¤t,
true);
509 if (!subSurface.isNull()) {
510 subSurface->d_func()->commit();
514 for (
auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
515 const auto &subSurface = *it;
516 if (subSurface.isNull()) {
519 subSurface->d_func()->commit();
528 void SurfaceInterface::Private::commitSubSurface()
530 if (subSurface.isNull() || !subSurface->isSynchronized()) {
533 swapStates(&subSurfacePending, ¤t,
true);
535 for (
auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
536 const auto &subSurface = *it;
537 if (subSurface.isNull() || !subSurface->isSynchronized()) {
540 subSurface->d_func()->commit();
544 void SurfaceInterface::Private::damage(
const QRect &rect)
546 pending.damage = pending.damage.united(rect);
549 void SurfaceInterface::Private::damageBuffer(
const QRect &rect)
551 pending.bufferDamage = pending.bufferDamage.united(rect);
554 void SurfaceInterface::Private::setScale(qint32
scale)
556 pending.scale =
scale;
557 pending.scaleIsSet =
true;
560 void SurfaceInterface::Private::setTransform(OutputInterface::Transform transform)
562 pending.transform = transform;
565 void SurfaceInterface::Private::addFrameCallback(uint32_t callback)
567 wl_resource *r = client->createResource(&wl_callback_interface, 1, callback);
569 wl_resource_post_no_memory(resource);
572 wl_resource_set_implementation(r,
nullptr,
this, destroyFrameCallback);
573 pending.callbacks << r;
576 void SurfaceInterface::Private::attachBuffer(wl_resource *buffer,
const QPoint &offset)
578 pending.bufferIsSet =
true;
579 pending.offset = offset;
580 if (pending.buffer) {
581 delete pending.buffer;
585 pending.buffer =
nullptr;
587 pending.bufferDamage =
QRegion();
590 Q_Q(SurfaceInterface);
591 pending.buffer =
new BufferInterface(buffer, q);
593 [
this](BufferInterface *buffer) {
594 if (pending.buffer == buffer) {
595 pending.buffer = nullptr;
597 if (subSurfacePending.buffer == buffer) {
598 subSurfacePending.buffer = nullptr;
600 if (current.buffer == buffer) {
601 current.buffer->unref();
602 current.buffer = nullptr;
608 void SurfaceInterface::Private::destroyFrameCallback(wl_resource *r)
610 auto s = cast<Private>(r);
611 s->current.callbacks.removeAll(r);
612 s->pending.callbacks.removeAll(r);
613 s->subSurfacePending.callbacks.removeAll(r);
616 void SurfaceInterface::Private::attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy)
622 void SurfaceInterface::Private::damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
625 cast<Private>(resource)->
damage(
QRect(x, y, width, height));
628 void SurfaceInterface::Private::damageBufferCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
634 void SurfaceInterface::Private::frameCallback(wl_client *client, wl_resource *resource, uint32_t callback)
636 auto s = cast<Private>(resource);
637 Q_ASSERT(client == *s->client);
638 s->addFrameCallback(callback);
641 void SurfaceInterface::Private::opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
643 auto s = cast<Private>(resource);
644 Q_ASSERT(client == *s->client);
645 auto r = RegionInterface::get(region);
646 s->setOpaque(r ? r->region() :
QRegion());
649 void SurfaceInterface::Private::setOpaque(
const QRegion ®ion)
651 pending.opaqueIsSet =
true;
652 pending.opaque = region;
655 void SurfaceInterface::Private::inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
657 auto s = cast<Private>(resource);
658 Q_ASSERT(client == *s->client);
659 auto r = RegionInterface::get(region);
660 s->setInput(r ? r->region() :
QRegion(), !r);
663 void SurfaceInterface::Private::setInput(
const QRegion ®ion,
bool isInfinite)
665 pending.inputIsSet =
true;
666 pending.inputIsInfinite = isInfinite;
667 pending.input = region;
670 void SurfaceInterface::Private::commitCallback(wl_client *client, wl_resource *resource)
673 cast<Private>(resource)->commit();
676 void SurfaceInterface::Private::bufferTransformCallback(wl_client *client, wl_resource *resource, int32_t transform)
679 cast<Private>(resource)->setTransform(OutputInterface::Transform(transform));
682 void SurfaceInterface::Private::bufferScaleCallback(wl_client *client, wl_resource *resource, int32_t
scale)
685 cast<Private>(resource)->
setScale(scale);
691 return d->current.damage;
694 QRegion SurfaceInterface::opaque()
const 697 return d->current.opaque;
700 QRegion SurfaceInterface::input()
const 703 return d->current.input;
706 bool SurfaceInterface::inputIsInfitine()
const 708 return inputIsInfinite();
711 bool SurfaceInterface::inputIsInfinite()
const 714 return d->current.inputIsInfinite;
717 qint32 SurfaceInterface::scale()
const 720 return d->current.scale;
723 OutputInterface::Transform SurfaceInterface::transform()
const 726 return d->current.transform;
732 return d->current.buffer;
735 QPoint SurfaceInterface::offset()
const 738 return d->current.offset;
743 return Private::get<SurfaceInterface>(native);
748 return Private::get<SurfaceInterface>(
id, client);
754 return d->current.children;
760 return d->subSurface;
763 QSize SurfaceInterface::size()
const 767 if (d->current.buffer) {
768 return d->current.buffer->size() /
scale();
773 QRect SurfaceInterface::boundingRect()
const 789 return d->current.shadow;
795 return d->current.blur;
801 return d->current.contrast;
807 return d->current.slide;
810 bool SurfaceInterface::isMapped()
const 816 return d->subSurfaceIsMapped && !d->subSurface->parentSurface().
isNull() && d->subSurface->parentSurface()->isMapped();
818 return d->current.buffer !=
nullptr;
821 QRegion SurfaceInterface::trackedDamage()
const 824 return d->trackedDamage;
827 void SurfaceInterface::resetTrackedDamage()
847 for (
auto it = removedOutputs.
constBegin(), end = removedOutputs.
constEnd(); it != end; ++it) {
848 const auto resources = (*it)->clientResources(client());
849 for (wl_resource *r : resources) {
850 wl_surface_send_leave(d->resource, r);
855 for (
auto it = d->outputs.constBegin(), end = d->outputs.constEnd(); it != end; ++it) {
857 addedOutputsOutputs.removeOne(o);
859 for (
auto it = addedOutputsOutputs.constBegin(), end = addedOutputsOutputs.constEnd(); it != end; ++it) {
861 const auto resources = o->clientResources(client());
862 for (wl_resource *r : resources) {
863 wl_surface_send_enter(d->resource, r);
865 d->outputDestroyedConnections[o] =
connect(o, &Global::aboutToDestroyGlobal,
this, [
this, o] {
867 auto outputs = d->outputs;
887 const auto ¤t = it.
previous();
888 auto surface = current->surface();
889 if (surface.isNull()) {
892 if (
auto s = surface->surfaceAt(position - current->position())) {
915 const auto ¤t = it.
previous();
916 auto surface = current->surface();
917 if (surface.isNull()) {
920 if (
auto s = surface->inputSurfaceAt(position - current->position())) {
926 (inputIsInfinite() || input().contains(position.
toPoint()))) {
935 return d->lockedPointer;
941 return d->confinedPointer;
944 bool SurfaceInterface::inhibitsIdle()
const 947 return !d->idleInhibitors.isEmpty();
953 d->dataProxy = surface;
962 SurfaceInterface::Private *SurfaceInterface::d_func()
const 964 return reinterpret_cast<Private*
>(d.
data());
void damageBuffer(const QRect &rect)
Mark rect in buffer coordinates as damaged for the next frame.
bool isValid() const const
bool isEmpty() const const
void destroy()
Destroys the data held by this Surface.
QVector::const_iterator constEnd() const const
bool contains(const QRectF &rectangle) const const
KIOFILEWIDGETS_EXPORT void add(const QString &fileClass, const QString &directory)
void scale(int width, int height, Qt::AspectRatioMode mode)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString tr(const char *sourceText, const char *disambiguation, int n)
void setScale(qint32 scale)
The purpose of this method is to allow to supply higher resolution buffer data for use on high resolu...
bool isNull() const const
Resource representing a wl_surface.
QRegion intersected(const QRegion &r) const const
QRect translated(int dx, int dy) const const
Reference counted representation of a Wayland buffer on Server side.
bool removeOne(const T &t)
QVector< Output * > outputs() const
bool isNull() const const
const QList< QKeySequence > & end()
QVector::const_iterator constBegin() const const
bool hasPrevious() const const
QPoint toPoint() const const
QRect boundingRect() const
Returns the rectangle that bounds this surface and all of its sub-surfaces.
void damage(const QRect &rect)
Mark rect as damaged for the next frame.
Convenient Class which represents a wl_client.
void attachBuffer(wl_buffer *buffer, const QPoint &offset=QPoint())
Attaches the buffer to this Surface for the next frame.
bool isEmpty() const const
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QRegion united(const QRegion &r) const const