diff --git a/src/wayland/contenttype_v1_interface.cpp b/src/wayland/contenttype_v1_interface.cpp index b0a3028460..6ef7fbff7f 100644 --- a/src/wayland/contenttype_v1_interface.cpp +++ b/src/wayland/contenttype_v1_interface.cpp @@ -62,16 +62,16 @@ void ContentTypeV1Interface::wp_content_type_v1_set_content_type(Resource *, uin return; } SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); - surfacePrivate->pending.contentType = waylandToKwinContentType(content_type); - surfacePrivate->pending.contentTypeIsSet = true; + surfacePrivate->pending->contentType = waylandToKwinContentType(content_type); + surfacePrivate->pending->contentTypeIsSet = true; } void ContentTypeV1Interface::wp_content_type_v1_destroy(Resource *resource) { if (m_surface) { SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); - surfacePrivate->pending.contentType = KWin::ContentType::None; - surfacePrivate->pending.contentTypeIsSet = true; + surfacePrivate->pending->contentType = KWin::ContentType::None; + surfacePrivate->pending->contentTypeIsSet = true; } wl_resource_destroy(resource->handle); } diff --git a/src/wayland/datadevice_interface.cpp b/src/wayland/datadevice_interface.cpp index 5ac9f2a6b1..e38f23b88a 100644 --- a/src/wayland/datadevice_interface.cpp +++ b/src/wayland/datadevice_interface.cpp @@ -22,36 +22,33 @@ namespace KWaylandServer class DragAndDropIconPrivate : public SurfaceRole { public: - explicit DragAndDropIconPrivate(DragAndDropIcon *q, SurfaceInterface *surface); + explicit DragAndDropIconPrivate(SurfaceInterface *surface); - void commit() override; - - DragAndDropIcon *q; QPoint position; }; -DragAndDropIconPrivate::DragAndDropIconPrivate(DragAndDropIcon *q, SurfaceInterface *surface) +DragAndDropIconPrivate::DragAndDropIconPrivate(SurfaceInterface *surface) : SurfaceRole(surface, QByteArrayLiteral("dnd_icon")) - , q(q) { } -void DragAndDropIconPrivate::commit() -{ - position += surface()->offset(); - Q_EMIT q->changed(); -} - DragAndDropIcon::DragAndDropIcon(SurfaceInterface *surface) : QObject(surface) - , d(new DragAndDropIconPrivate(this, surface)) + , d(new DragAndDropIconPrivate(surface)) { + connect(surface, &SurfaceInterface::committed, this, &DragAndDropIcon::commit); } DragAndDropIcon::~DragAndDropIcon() { } +void DragAndDropIcon::commit() +{ + d->position += d->surface()->offset(); + Q_EMIT changed(); +} + QPoint DragAndDropIcon::position() const { return d->position; diff --git a/src/wayland/datadevice_interface.h b/src/wayland/datadevice_interface.h index 4d9c973025..5c254e3d2c 100644 --- a/src/wayland/datadevice_interface.h +++ b/src/wayland/datadevice_interface.h @@ -55,6 +55,8 @@ Q_SIGNALS: void changed(); private: + void commit(); + explicit DragAndDropIcon(SurfaceInterface *surface); friend class DataDeviceInterfacePrivate; std::unique_ptr d; diff --git a/src/wayland/inputmethod_v1_interface.cpp b/src/wayland/inputmethod_v1_interface.cpp index 7782771eb8..19b1f57e83 100644 --- a/src/wayland/inputmethod_v1_interface.cpp +++ b/src/wayland/inputmethod_v1_interface.cpp @@ -327,10 +327,6 @@ public: Q_EMIT q->topLevel(OutputInterface::get(output), InputPanelSurfaceV1Interface::Position(position)); } - void commit() override - { - } - void zwp_input_panel_surface_v1_destroy_resource(Resource *) override { delete q; diff --git a/src/wayland/layershell_v1_interface.cpp b/src/wayland/layershell_v1_interface.cpp index 96ae1085e7..4e362e4be9 100644 --- a/src/wayland/layershell_v1_interface.cpp +++ b/src/wayland/layershell_v1_interface.cpp @@ -39,38 +39,45 @@ protected: void zwlr_layer_shell_v1_destroy(Resource *resource) override; }; -class LayerSurfaceV1State +struct LayerSurfaceV1Commit { -public: + std::optional layer; + std::optional anchor; + std::optional margins; + std::optional desiredSize; + std::optional exclusiveZone; + std::optional acknowledgedConfigure; + std::optional acceptsFocus; +}; + +struct LayerSurfaceV1State +{ + QQueue serials; LayerSurfaceV1Interface::Layer layer = LayerSurfaceV1Interface::BottomLayer; Qt::Edges anchor; QMargins margins; QSize desiredSize = QSize(0, 0); int exclusiveZone = 0; - quint32 acknowledgedConfigure; - bool acknowledgedConfigureIsSet = false; bool acceptsFocus = false; + bool configured = false; + bool closed = false; + bool committed = false; + bool firstBufferAttached = false; }; -class LayerSurfaceV1InterfacePrivate : public SurfaceRole, public QtWaylandServer::zwlr_layer_surface_v1 +class LayerSurfaceV1InterfacePrivate : public SurfaceRole, public SurfaceExtension, public QtWaylandServer::zwlr_layer_surface_v1 { public: LayerSurfaceV1InterfacePrivate(LayerSurfaceV1Interface *q, SurfaceInterface *surface); - void commit() override; + void apply(LayerSurfaceV1Commit *commit) override; LayerSurfaceV1Interface *q; LayerShellV1Interface *shell; QPointer surface; QPointer output; - LayerSurfaceV1State current; - LayerSurfaceV1State pending; - QQueue serials; QString scope; - bool isClosed = false; - bool isConfigured = false; - bool isCommitted = false; - bool firstBufferAttached = false; + LayerSurfaceV1State state; protected: void zwlr_layer_surface_v1_destroy_resource(Resource *resource) override; @@ -150,6 +157,7 @@ Display *LayerShellV1Interface::display() const LayerSurfaceV1InterfacePrivate::LayerSurfaceV1InterfacePrivate(LayerSurfaceV1Interface *q, SurfaceInterface *surface) : SurfaceRole(surface, QByteArrayLiteral("layer_surface_v1")) + , SurfaceExtension(surface) , q(q) , surface(surface) { @@ -177,19 +185,19 @@ void LayerSurfaceV1InterfacePrivate::zwlr_layer_surface_v1_set_anchor(Resource * pending.anchor = Qt::Edges(); if (anchor & anchor_top) { - pending.anchor |= Qt::TopEdge; + *pending.anchor |= Qt::TopEdge; } if (anchor & anchor_right) { - pending.anchor |= Qt::RightEdge; + *pending.anchor |= Qt::RightEdge; } if (anchor & anchor_bottom) { - pending.anchor |= Qt::BottomEdge; + *pending.anchor |= Qt::BottomEdge; } if (anchor & anchor_left) { - pending.anchor |= Qt::LeftEdge; + *pending.anchor |= Qt::LeftEdge; } } @@ -223,19 +231,18 @@ void LayerSurfaceV1InterfacePrivate::zwlr_layer_surface_v1_get_popup(Resource *r void LayerSurfaceV1InterfacePrivate::zwlr_layer_surface_v1_ack_configure(Resource *resource, uint32_t serial) { - if (!serials.contains(serial)) { + if (!state.serials.contains(serial)) { wl_resource_post_error(resource->handle, error_invalid_surface_state, "invalid configure serial %d", serial); return; } - while (!serials.isEmpty()) { - const quint32 head = serials.takeFirst(); + while (!state.serials.isEmpty()) { + const quint32 head = state.serials.takeFirst(); if (head == serial) { break; } } - if (!isClosed) { + if (!state.closed) { pending.acknowledgedConfigure = serial; - pending.acknowledgedConfigureIsSet = true; } } @@ -253,19 +260,17 @@ void LayerSurfaceV1InterfacePrivate::zwlr_layer_surface_v1_set_layer(Resource *r pending.layer = LayerSurfaceV1Interface::Layer(layer); } -void LayerSurfaceV1InterfacePrivate::commit() +void LayerSurfaceV1InterfacePrivate::apply(LayerSurfaceV1Commit *commit) { - if (isClosed) { + if (state.closed) { return; } - if (pending.acknowledgedConfigureIsSet) { - current.acknowledgedConfigure = pending.acknowledgedConfigure; - pending.acknowledgedConfigureIsSet = false; - Q_EMIT q->configureAcknowledged(pending.acknowledgedConfigure); + if (commit->acknowledgedConfigure.has_value()) { + Q_EMIT q->configureAcknowledged(commit->acknowledgedConfigure.value()); } - if (Q_UNLIKELY(surface->isMapped() && !isConfigured)) { + if (Q_UNLIKELY(surface->isMapped() && !state.configured)) { wl_resource_post_error(resource()->handle, error_invalid_surface_state, "a buffer has been attached to a layer surface prior " @@ -273,57 +278,79 @@ void LayerSurfaceV1InterfacePrivate::commit() return; } - if (Q_UNLIKELY(pending.desiredSize.width() == 0 && (!(pending.anchor & Qt::LeftEdge) || !(pending.anchor & Qt::RightEdge)))) { - wl_resource_post_error(resource()->handle, - error_invalid_size, - "the layer surface has a width of 0 but its anchor " - "doesn't include the left and the right screen edge"); - return; + if (commit->desiredSize && commit->desiredSize->width() == 0) { + const Qt::Edges anchor = commit->anchor.value_or(state.anchor); + if (!(anchor & Qt::LeftEdge) || !(anchor & Qt::RightEdge)) { + wl_resource_post_error(resource()->handle, + error_invalid_size, + "the layer surface has a width of 0 but its anchor " + "doesn't include the left and the right screen edge"); + return; + } } - if (Q_UNLIKELY(pending.desiredSize.height() == 0 && (!(pending.anchor & Qt::TopEdge) || !(pending.anchor & Qt::BottomEdge)))) { - wl_resource_post_error(resource()->handle, - error_invalid_size, - "the layer surface has a height of 0 but its anchor " - "doesn't include the top and the bottom screen edge"); - return; + if (commit->desiredSize && commit->desiredSize->height() == 0) { + const Qt::Edges anchor = commit->anchor.value_or(state.anchor); + if (!(anchor & Qt::TopEdge) || !(anchor & Qt::BottomEdge)) { + wl_resource_post_error(resource()->handle, + error_invalid_size, + "the layer surface has a height of 0 but its anchor " + "doesn't include the top and the bottom screen edge"); + return; + } } // detect reset - if (!surface->isMapped() && firstBufferAttached) { - isCommitted = false; - firstBufferAttached = false; - isConfigured = false; - - current = LayerSurfaceV1State(); - pending = LayerSurfaceV1State(); + if (!surface->isMapped() && state.firstBufferAttached) { + state = LayerSurfaceV1State(); + pending = LayerSurfaceV1Commit(); + stashed.clear(); return; } - const LayerSurfaceV1State previous = std::exchange(current, pending); + const LayerSurfaceV1State previous = state; - isCommitted = true; // Must set the committed state before emitting any signals. + state.committed = true; // Must set the committed state before emitting any signals. if (surface->isMapped()) { - firstBufferAttached = true; + state.firstBufferAttached = true; } - if (previous.acceptsFocus != current.acceptsFocus) { + if (commit->layer.has_value()) { + state.layer = commit->layer.value(); + } + if (commit->anchor.has_value()) { + state.anchor = commit->anchor.value(); + } + if (commit->margins.has_value()) { + state.margins = commit->margins.value(); + } + if (commit->desiredSize.has_value()) { + state.desiredSize = commit->desiredSize.value(); + } + if (commit->exclusiveZone.has_value()) { + state.exclusiveZone = commit->exclusiveZone.value(); + } + if (commit->acceptsFocus.has_value()) { + state.acceptsFocus = commit->acceptsFocus.value(); + } + + if (previous.acceptsFocus != state.acceptsFocus) { Q_EMIT q->acceptsFocusChanged(); } - if (previous.layer != current.layer) { + if (previous.layer != state.layer) { Q_EMIT q->layerChanged(); } - if (previous.anchor != current.anchor) { + if (previous.anchor != state.anchor) { Q_EMIT q->anchorChanged(); } - if (previous.desiredSize != current.desiredSize) { + if (previous.desiredSize != state.desiredSize) { Q_EMIT q->desiredSizeChanged(); } - if (previous.exclusiveZone != current.exclusiveZone) { + if (previous.exclusiveZone != state.exclusiveZone) { Q_EMIT q->exclusiveZoneChanged(); } - if (previous.margins != current.margins) { + if (previous.margins != state.margins) { Q_EMIT q->marginsChanged(); } } @@ -336,8 +363,7 @@ LayerSurfaceV1Interface::LayerSurfaceV1Interface(LayerShellV1Interface *shell, wl_resource *resource) : d(new LayerSurfaceV1InterfacePrivate(this, surface)) { - d->current.layer = layer; - d->pending.layer = layer; + d->state.layer = layer; d->shell = shell; d->output = output; @@ -352,7 +378,7 @@ LayerSurfaceV1Interface::~LayerSurfaceV1Interface() bool LayerSurfaceV1Interface::isCommitted() const { - return d->isCommitted; + return d->state.committed; } SurfaceInterface *LayerSurfaceV1Interface::surface() const @@ -362,52 +388,52 @@ SurfaceInterface *LayerSurfaceV1Interface::surface() const Qt::Edges LayerSurfaceV1Interface::anchor() const { - return d->current.anchor; + return d->state.anchor; } QSize LayerSurfaceV1Interface::desiredSize() const { - return d->current.desiredSize; + return d->state.desiredSize; } bool LayerSurfaceV1Interface::acceptsFocus() const { - return d->current.acceptsFocus; + return d->state.acceptsFocus; } LayerSurfaceV1Interface::Layer LayerSurfaceV1Interface::layer() const { - return d->current.layer; + return d->state.layer; } QMargins LayerSurfaceV1Interface::margins() const { - return d->current.margins; + return d->state.margins; } int LayerSurfaceV1Interface::leftMargin() const { - return d->current.margins.left(); + return d->state.margins.left(); } int LayerSurfaceV1Interface::topMargin() const { - return d->current.margins.top(); + return d->state.margins.top(); } int LayerSurfaceV1Interface::rightMargin() const { - return d->current.margins.right(); + return d->state.margins.right(); } int LayerSurfaceV1Interface::bottomMargin() const { - return d->current.margins.bottom(); + return d->state.margins.bottom(); } int LayerSurfaceV1Interface::exclusiveZone() const { - return d->current.exclusiveZone; + return d->state.exclusiveZone; } Qt::Edge LayerSurfaceV1Interface::exclusiveEdge() const @@ -442,25 +468,25 @@ QString LayerSurfaceV1Interface::scope() const quint32 LayerSurfaceV1Interface::sendConfigure(const QSize &size) { - if (d->isClosed) { + if (d->state.closed) { qCWarning(KWIN_CORE) << "Cannot configure a closed layer shell surface"; return 0; } const uint32_t serial = d->shell->display()->nextSerial(); - d->serials << serial; + d->state.serials << serial; d->send_configure(serial, size.width(), size.height()); - d->isConfigured = true; + d->state.configured = true; return serial; } void LayerSurfaceV1Interface::sendClosed() { - if (!d->isClosed) { + if (!d->state.closed) { d->send_closed(); - d->isClosed = true; + d->state.closed = true; } } diff --git a/src/wayland/pointerconstraints_v1_interface.cpp b/src/wayland/pointerconstraints_v1_interface.cpp index 54378dfe9d..3909dfbb90 100644 --- a/src/wayland/pointerconstraints_v1_interface.cpp +++ b/src/wayland/pointerconstraints_v1_interface.cpp @@ -138,27 +138,28 @@ LockedPointerV1InterfacePrivate::LockedPointerV1InterfacePrivate(LockedPointerV1 const QRegion ®ion, ::wl_resource *resource) : QtWaylandServer::zwp_locked_pointer_v1(resource) + , SurfaceExtension(surface) , q(q) , surface(surface) , lifeTime(lifeTime) - , pendingRegion(region) - , hasPendingRegion(true) { - commit(); + pending.region = region; + + apply(&pending); + + pending = LockedPointerV1Commit{}; } -void LockedPointerV1InterfacePrivate::commit() +void LockedPointerV1InterfacePrivate::apply(LockedPointerV1Commit *commit) { const QRegion oldRegion = effectiveRegion; const QPointF oldHint = hint; - if (hasPendingRegion) { - region = mapScaleOverride(pendingRegion, surface->scaleOverride()); - hasPendingRegion = false; + if (commit->region.has_value()) { + region = mapScaleOverride(commit->region.value(), surface->scaleOverride()); } - if (hasPendingHint) { - hint = pendingHint / surface->scaleOverride(); - hasPendingHint = false; + if (commit->hint.has_value()) { + hint = commit->hint.value() / surface->scaleOverride(); } effectiveRegion = surface->input(); @@ -187,17 +188,18 @@ void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_destroy(Resource *re void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_set_cursor_position_hint(Resource *resource, wl_fixed_t surface_x, wl_fixed_t surface_y) { - pendingHint = QPointF(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); - hasPendingHint = true; + pending.hint = QPointF(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); } void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_set_region(Resource *resource, ::wl_resource *region_resource) { - pendingRegion = regionFromResource(region_resource); - hasPendingRegion = true; + pending.region = regionFromResource(region_resource); } -LockedPointerV1Interface::LockedPointerV1Interface(SurfaceInterface *surface, LifeTime lifeTime, const QRegion ®ion, ::wl_resource *resource) +LockedPointerV1Interface::LockedPointerV1Interface(SurfaceInterface *surface, + LifeTime lifeTime, + const QRegion ®ion, + ::wl_resource *resource) : d(new LockedPointerV1InterfacePrivate(this, surface, lifeTime, region, resource)) { SurfaceInterfacePrivate::get(surface)->installPointerConstraint(this); @@ -255,22 +257,24 @@ ConfinedPointerV1InterfacePrivate::ConfinedPointerV1InterfacePrivate(ConfinedPoi const QRegion ®ion, ::wl_resource *resource) : QtWaylandServer::zwp_confined_pointer_v1(resource) + , SurfaceExtension(surface) , q(q) , surface(surface) , lifeTime(lifeTime) - , pendingRegion(region) - , hasPendingRegion(true) { - commit(); + pending.region = region; + + apply(&pending); + + pending = ConfinedPointerV1Commit{}; } -void ConfinedPointerV1InterfacePrivate::commit() +void ConfinedPointerV1InterfacePrivate::apply(ConfinedPointerV1Commit *commit) { const QRegion oldRegion = effectiveRegion; - if (hasPendingRegion) { - region = mapScaleOverride(pendingRegion, surface->scaleOverride()); - hasPendingRegion = false; + if (commit->region.has_value()) { + region = mapScaleOverride(commit->region.value(), surface->scaleOverride()); } effectiveRegion = surface->input(); @@ -295,11 +299,13 @@ void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_destroy(Resource void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_set_region(Resource *resource, ::wl_resource *region_resource) { - pendingRegion = regionFromResource(region_resource); - hasPendingRegion = true; + pending.region = regionFromResource(region_resource); } -ConfinedPointerV1Interface::ConfinedPointerV1Interface(SurfaceInterface *surface, LifeTime lifeTime, const QRegion ®ion, ::wl_resource *resource) +ConfinedPointerV1Interface::ConfinedPointerV1Interface(SurfaceInterface *surface, + LifeTime lifeTime, + const QRegion ®ion, + ::wl_resource *resource) : d(new ConfinedPointerV1InterfacePrivate(this, surface, lifeTime, region, resource)) { SurfaceInterfacePrivate::get(surface)->installPointerConstraint(this); diff --git a/src/wayland/pointerconstraints_v1_interface_p.h b/src/wayland/pointerconstraints_v1_interface_p.h index 67e9394fc2..ad05837d53 100644 --- a/src/wayland/pointerconstraints_v1_interface_p.h +++ b/src/wayland/pointerconstraints_v1_interface_p.h @@ -8,6 +8,8 @@ #pragma once #include "pointerconstraints_v1_interface.h" +#include "surface_interface.h" + #include #include "qwayland-server-pointer-constraints-unstable-v1.h" @@ -35,25 +37,27 @@ protected: void zwp_pointer_constraints_v1_destroy(Resource *resource) override; }; -class LockedPointerV1InterfacePrivate : public QtWaylandServer::zwp_locked_pointer_v1 +struct LockedPointerV1Commit +{ + std::optional region; + std::optional hint; +}; + +class LockedPointerV1InterfacePrivate final : public QtWaylandServer::zwp_locked_pointer_v1, public SurfaceExtension { public: static LockedPointerV1InterfacePrivate *get(LockedPointerV1Interface *pointer); LockedPointerV1InterfacePrivate(LockedPointerV1Interface *q, SurfaceInterface *surface, LockedPointerV1Interface::LifeTime lifeTime, const QRegion ®ion, ::wl_resource *resource); - void commit(); + void apply(LockedPointerV1Commit *commit) override; LockedPointerV1Interface *q; QPointer surface; LockedPointerV1Interface::LifeTime lifeTime; QRegion effectiveRegion; QRegion region; - QRegion pendingRegion; QPointF hint = QPointF(-1, -1); - QPointF pendingHint; - bool hasPendingRegion = false; - bool hasPendingHint = false; bool isLocked = false; protected: @@ -63,25 +67,29 @@ protected: void zwp_locked_pointer_v1_set_region(Resource *resource, struct ::wl_resource *region_resource) override; }; -class ConfinedPointerV1InterfacePrivate : public QtWaylandServer::zwp_confined_pointer_v1 +struct ConfinedPointerV1Commit +{ + std::optional region; +}; + +class ConfinedPointerV1InterfacePrivate final : public QtWaylandServer::zwp_confined_pointer_v1, public SurfaceExtension { public: static ConfinedPointerV1InterfacePrivate *get(ConfinedPointerV1Interface *pointer); - ConfinedPointerV1InterfacePrivate(ConfinedPointerV1Interface *q, SurfaceInterface *surface, + ConfinedPointerV1InterfacePrivate(ConfinedPointerV1Interface *q, + SurfaceInterface *surface, ConfinedPointerV1Interface::LifeTime lifeTime, const QRegion ®ion, ::wl_resource *resource); - void commit(); + void apply(ConfinedPointerV1Commit *commit) override; ConfinedPointerV1Interface *q; QPointer surface; ConfinedPointerV1Interface::LifeTime lifeTime; QRegion effectiveRegion; QRegion region; - QRegion pendingRegion; - bool hasPendingRegion = false; bool isConfined = false; protected: diff --git a/src/wayland/subcompositor_interface.cpp b/src/wayland/subcompositor_interface.cpp index b65016d0de..442ac1bc88 100644 --- a/src/wayland/subcompositor_interface.cpp +++ b/src/wayland/subcompositor_interface.cpp @@ -109,8 +109,8 @@ void SubSurfaceInterfacePrivate::subsurface_set_position(Resource *resource, int SurfaceInterfacePrivate *parentPrivate = SurfaceInterfacePrivate::get(parent); - parentPrivate->pending.subsurface.position[q] = QPoint(x, y); - parentPrivate->pending.subsurfacePositionChanged = true; + parentPrivate->pending->subsurface.position[q] = QPoint(x, y); + parentPrivate->pending->subsurfacePositionChanged = true; } void SubSurfaceInterfacePrivate::subsurface_place_above(Resource *resource, struct ::wl_resource *sibling_resource) @@ -166,20 +166,19 @@ void SubSurfaceInterfacePrivate::subsurface_set_desync(Resource *) mode = SubSurfaceInterface::Mode::Desynchronized; if (!q->isSynchronized()) { auto surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->commitFromCache(); + while (!locks.isEmpty()) { + SubSurfaceStateLock lock = locks.takeFirst(); + surfacePrivate->unlockState(lock.serial); + } } Q_EMIT q->modeChanged(SubSurfaceInterface::Mode::Desynchronized); } -void SubSurfaceInterfacePrivate::commit() -{ -} - -void SubSurfaceInterfacePrivate::parentCommit() +void SubSurfaceInterfacePrivate::parentApplyState(quint32 serial) { auto parentPrivate = SurfaceInterfacePrivate::get(parent); - if (parentPrivate->current.subsurfacePositionChanged) { - const QPoint &pos = parentPrivate->current.subsurface.position[q]; + if (parentPrivate->current->subsurfacePositionChanged) { + const QPoint &pos = parentPrivate->current->subsurface.position[q]; if (position != pos) { position = pos; Q_EMIT q->positionChanged(pos); @@ -188,7 +187,10 @@ void SubSurfaceInterfacePrivate::parentCommit() if (mode == SubSurfaceInterface::Mode::Synchronized) { auto surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->commitFromCache(); + while (!locks.isEmpty() && locks[0].parentSerial == serial) { + SubSurfaceStateLock lock = locks.takeFirst(); + surfacePrivate->unlockState(lock.serial); + } } } @@ -266,6 +268,24 @@ SurfaceInterface *SubSurfaceInterface::mainSurface() const return d->parent; } +void SubSurfaceInterface::commit() +{ + SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(d->surface); + if (isSynchronized()) { + const quint32 serial = surfacePrivate->lockState(surfacePrivate->pending.get()); + const quint32 parentSerial = SurfaceInterfacePrivate::get(d->parent)->pending->serial; + d->locks.append(SubSurfaceStateLock{ + .serial = serial, + .parentSerial = parentSerial, + }); + } else { + while (!d->locks.isEmpty()) { + SubSurfaceStateLock lock = d->locks.takeFirst(); + surfacePrivate->unlockState(lock.serial); + } + } +} + } // namespace KWaylandServer #include "moc_subcompositor_interface.cpp" diff --git a/src/wayland/subcompositor_interface.h b/src/wayland/subcompositor_interface.h index 21c7f9812e..049a45b777 100644 --- a/src/wayland/subcompositor_interface.h +++ b/src/wayland/subcompositor_interface.h @@ -116,7 +116,11 @@ Q_SIGNALS: private: SubSurfaceInterface(SurfaceInterface *surface, SurfaceInterface *parent, wl_resource *resource); + + void commit(); + std::unique_ptr d; + friend class SurfaceInterfacePrivate; friend class SubSurfaceInterfacePrivate; friend class SubCompositorInterfacePrivate; }; diff --git a/src/wayland/subsurface_interface_p.h b/src/wayland/subsurface_interface_p.h index cf04f40a36..8979f8a7dd 100644 --- a/src/wayland/subsurface_interface_p.h +++ b/src/wayland/subsurface_interface_p.h @@ -29,6 +29,12 @@ protected: void subcompositor_get_subsurface(Resource *resource, uint32_t id, struct ::wl_resource *surface_resource, struct ::wl_resource *parent_resource) override; }; +struct SubSurfaceStateLock +{ + const quint32 serial; + const quint32 parentSerial; +}; + class SubSurfaceInterfacePrivate : public SurfaceRole, public QtWaylandServer::wl_subsurface { public: @@ -36,14 +42,14 @@ public: SubSurfaceInterfacePrivate(SubSurfaceInterface *q, SurfaceInterface *surface, SurfaceInterface *parent, ::wl_resource *resource); - void commit() override; - void parentCommit(); + void parentApplyState(quint32 serial); SubSurfaceInterface *q; QPoint position = QPoint(0, 0); SubSurfaceInterface::Mode mode = SubSurfaceInterface::Mode::Synchronized; QPointer surface; QPointer parent; + QList locks; protected: void subsurface_destroy_resource(Resource *resource) override; diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp index 25ccb38770..9c9f03092f 100644 --- a/src/wayland/surface_interface.cpp +++ b/src/wayland/surface_interface.cpp @@ -40,10 +40,9 @@ static QRegion map_helper(const QMatrix4x4 &matrix, const QRegion ®ion) SurfaceInterfacePrivate::SurfaceInterfacePrivate(SurfaceInterface *q) : q(q) + , current(std::make_unique()) + , pending(std::make_unique()) { - wl_list_init(¤t.frameCallbacks); - wl_list_init(&pending.frameCallbacks); - wl_list_init(&cached.frameCallbacks); } SurfaceInterfacePrivate::~SurfaceInterfacePrivate() @@ -51,23 +50,29 @@ SurfaceInterfacePrivate::~SurfaceInterfacePrivate() wl_resource *resource; wl_resource *tmp; - wl_resource_for_each_safe (resource, tmp, ¤t.frameCallbacks) { + wl_resource_for_each_safe (resource, tmp, ¤t->frameCallbacks) { wl_resource_destroy(resource); } - wl_resource_for_each_safe (resource, tmp, &pending.frameCallbacks) { + wl_resource_for_each_safe (resource, tmp, &pending->frameCallbacks) { wl_resource_destroy(resource); } - wl_resource_for_each_safe (resource, tmp, &cached.frameCallbacks) { - wl_resource_destroy(resource); + for (const auto &stash : std::as_const(stashed)) { + wl_resource_for_each_safe (resource, tmp, &stash->frameCallbacks) { + wl_resource_destroy(resource); + } } } void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child) { // protocol is not precise on how to handle the addition of new sub surfaces - pending.subsurface.above.append(child); - cached.subsurface.above.append(child); - current.subsurface.above.append(child); + current->subsurface.above.append(child); + pending->subsurface.above.append(child); + + for (int i = 0; i < stashed.size(); ++i) { + stashed[i]->subsurface.above.append(child); + } + child->surface()->setOutputs(outputs); if (preferredBufferScale.has_value()) { child->surface()->setPreferredBufferScale(preferredBufferScale.value()); @@ -83,15 +88,17 @@ void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child) void SurfaceInterfacePrivate::removeChild(SubSurfaceInterface *child) { // protocol is not precise on how to handle the addition of new sub surfaces - pending.subsurface.below.removeAll(child); - pending.subsurface.above.removeAll(child); - pending.subsurface.position.remove(child); - cached.subsurface.below.removeAll(child); - cached.subsurface.above.removeAll(child); - cached.subsurface.position.remove(child); - current.subsurface.below.removeAll(child); - current.subsurface.above.removeAll(child); - current.subsurface.position.remove(child); + current->subsurface.below.removeAll(child); + current->subsurface.above.removeAll(child); + + pending->subsurface.below.removeAll(child); + pending->subsurface.above.removeAll(child); + + for (int i = 0; i < stashed.size(); ++i) { + stashed[i]->subsurface.below.removeAll(child); + stashed[i]->subsurface.above.removeAll(child); + } + Q_EMIT q->childSubSurfaceRemoved(child); Q_EMIT q->childSubSurfacesChanged(); } @@ -103,23 +110,23 @@ bool SurfaceInterfacePrivate::raiseChild(SubSurfaceInterface *subsurface, Surfac QList *anchorList; int anchorIndex; - pending.subsurface.below.removeOne(subsurface); - pending.subsurface.above.removeOne(subsurface); + pending->subsurface.below.removeOne(subsurface); + pending->subsurface.above.removeOne(subsurface); if (anchor == q) { // Pretend as if the parent surface were before the first child in the above list. - anchorList = &pending.subsurface.above; + anchorList = &pending->subsurface.above; anchorIndex = -1; - } else if (anchorIndex = pending.subsurface.above.indexOf(anchor->subSurface()); anchorIndex != -1) { - anchorList = &pending.subsurface.above; - } else if (anchorIndex = pending.subsurface.below.indexOf(anchor->subSurface()); anchorIndex != -1) { - anchorList = &pending.subsurface.below; + } else if (anchorIndex = pending->subsurface.above.indexOf(anchor->subSurface()); anchorIndex != -1) { + anchorList = &pending->subsurface.above; + } else if (anchorIndex = pending->subsurface.below.indexOf(anchor->subSurface()); anchorIndex != -1) { + anchorList = &pending->subsurface.below; } else { return false; // The anchor belongs to other sub-surface tree. } anchorList->insert(anchorIndex + 1, subsurface); - pending.subsurfaceOrderChanged = true; + pending->subsurfaceOrderChanged = true; return true; } @@ -130,48 +137,48 @@ bool SurfaceInterfacePrivate::lowerChild(SubSurfaceInterface *subsurface, Surfac QList *anchorList; int anchorIndex; - pending.subsurface.below.removeOne(subsurface); - pending.subsurface.above.removeOne(subsurface); + pending->subsurface.below.removeOne(subsurface); + pending->subsurface.above.removeOne(subsurface); if (anchor == q) { // Pretend as if the parent surface were after the last child in the below list. - anchorList = &pending.subsurface.below; - anchorIndex = pending.subsurface.below.count(); - } else if (anchorIndex = pending.subsurface.above.indexOf(anchor->subSurface()); anchorIndex != -1) { - anchorList = &pending.subsurface.above; - } else if (anchorIndex = pending.subsurface.below.indexOf(anchor->subSurface()); anchorIndex != -1) { - anchorList = &pending.subsurface.below; + anchorList = &pending->subsurface.below; + anchorIndex = pending->subsurface.below.count(); + } else if (anchorIndex = pending->subsurface.above.indexOf(anchor->subSurface()); anchorIndex != -1) { + anchorList = &pending->subsurface.above; + } else if (anchorIndex = pending->subsurface.below.indexOf(anchor->subSurface()); anchorIndex != -1) { + anchorList = &pending->subsurface.below; } else { return false; // The anchor belongs to other sub-surface tree. } anchorList->insert(anchorIndex, subsurface); - pending.subsurfaceOrderChanged = true; + pending->subsurfaceOrderChanged = true; return true; } void SurfaceInterfacePrivate::setShadow(const QPointer &shadow) { - pending.shadow = shadow; - pending.shadowIsSet = true; + pending->shadow = shadow; + pending->shadowIsSet = true; } void SurfaceInterfacePrivate::setBlur(const QPointer &blur) { - pending.blur = blur; - pending.blurIsSet = true; + pending->blur = blur; + pending->blurIsSet = true; } void SurfaceInterfacePrivate::setSlide(const QPointer &slide) { - pending.slide = slide; - pending.slideIsSet = true; + pending->slide = slide; + pending->slideIsSet = true; } void SurfaceInterfacePrivate::setContrast(const QPointer &contrast) { - pending.contrast = contrast; - pending.contrastIsSet = true; + pending->contrast = contrast; + pending->contrastIsSet = true; } void SurfaceInterfacePrivate::installPointerConstraint(LockedPointerV1Interface *lock) @@ -263,23 +270,23 @@ void SurfaceInterfacePrivate::surface_attach(Resource *resource, struct ::wl_res return; } } else { - pending.offset = QPoint(x, y); + pending->offset = QPoint(x, y); } - pending.bufferIsSet = true; + pending->bufferIsSet = true; if (!buffer) { // got a null buffer, deletes content in next frame - pending.buffer = nullptr; - pending.damage = QRegion(); - pending.bufferDamage = QRegion(); + pending->buffer = nullptr; + pending->damage = QRegion(); + pending->bufferDamage = QRegion(); return; } - pending.buffer = Display::bufferForResource(buffer); + pending->buffer = Display::bufferForResource(buffer); } void SurfaceInterfacePrivate::surface_damage(Resource *, int32_t x, int32_t y, int32_t width, int32_t height) { - pending.damage |= QRect(x, y, width, height); + pending->damage |= QRect(x, y, width, height); } void SurfaceInterfacePrivate::surface_frame(Resource *resource, uint32_t callback) @@ -297,30 +304,43 @@ void SurfaceInterfacePrivate::surface_frame(Resource *resource, uint32_t callbac wl_list_remove(wl_resource_get_link(resource)); }); - wl_list_insert(pending.frameCallbacks.prev, wl_resource_get_link(callbackResource)); + wl_list_insert(pending->frameCallbacks.prev, wl_resource_get_link(callbackResource)); } void SurfaceInterfacePrivate::surface_set_opaque_region(Resource *resource, struct ::wl_resource *region) { RegionInterface *r = RegionInterface::get(region); - pending.opaque = r ? r->region() : QRegion(); - pending.opaqueIsSet = true; + pending->opaque = r ? r->region() : QRegion(); + pending->opaqueIsSet = true; } void SurfaceInterfacePrivate::surface_set_input_region(Resource *resource, struct ::wl_resource *region) { RegionInterface *r = RegionInterface::get(region); - pending.input = r ? r->region() : infiniteRegion(); - pending.inputIsSet = true; + pending->input = r ? r->region() : infiniteRegion(); + pending->inputIsSet = true; } void SurfaceInterfacePrivate::surface_commit(Resource *resource) { if (subSurface) { - commitSubSurface(); - } else { - applyState(&pending); + subSurface->commit(); } + + // If there are already stashed states, this one will be applied when all the previous + // states are applied. + if (pending->locks || !stashed.empty()) { + auto stash = std::make_unique(); + pending->mergeInto(stash.get()); + const quint32 serial = stash->serial; + + stashed.push_back(std::move(stash)); + Q_EMIT q->stateStashed(serial); + } else { + applyState(pending.get()); + } + + pending->serial++; } void SurfaceInterfacePrivate::surface_set_buffer_transform(Resource *resource, int32_t transform) @@ -329,8 +349,8 @@ void SurfaceInterfacePrivate::surface_set_buffer_transform(Resource *resource, i wl_resource_post_error(resource->handle, error_invalid_transform, "buffer transform must be a valid transform (%d specified)", transform); return; } - pending.bufferTransform = KWin::OutputTransform::Kind(transform); - pending.bufferTransformIsSet = true; + pending->bufferTransform = KWin::OutputTransform::Kind(transform); + pending->bufferTransformIsSet = true; } void SurfaceInterfacePrivate::surface_set_buffer_scale(Resource *resource, int32_t scale) @@ -339,18 +359,18 @@ void SurfaceInterfacePrivate::surface_set_buffer_scale(Resource *resource, int32 wl_resource_post_error(resource->handle, error_invalid_scale, "buffer scale must be at least one (%d specified)", scale); return; } - pending.bufferScale = scale; - pending.bufferScaleIsSet = true; + pending->bufferScale = scale; + pending->bufferScaleIsSet = true; } void SurfaceInterfacePrivate::surface_damage_buffer(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - pending.bufferDamage |= QRect(x, y, width, height); + pending->bufferDamage |= QRect(x, y, width, height); } void SurfaceInterfacePrivate::surface_offset(Resource *resource, int32_t x, int32_t y) { - pending.offset = QPoint(x, y); + pending->offset = QPoint(x, y); } SurfaceInterface::SurfaceInterface(CompositorInterface *compositor, wl_resource *resource) @@ -398,22 +418,22 @@ void SurfaceInterface::frameRendered(quint32 msec) wl_resource *resource; wl_resource *tmp; - wl_resource_for_each_safe (resource, tmp, &d->current.frameCallbacks) { + wl_resource_for_each_safe (resource, tmp, &d->current->frameCallbacks) { wl_callback_send_done(resource, msec); wl_resource_destroy(resource); } - for (SubSurfaceInterface *subsurface : std::as_const(d->current.subsurface.below)) { + for (SubSurfaceInterface *subsurface : std::as_const(d->current->subsurface.below)) { subsurface->surface()->frameRendered(msec); } - for (SubSurfaceInterface *subsurface : std::as_const(d->current.subsurface.above)) { + for (SubSurfaceInterface *subsurface : std::as_const(d->current->subsurface.above)) { subsurface->surface()->frameRendered(msec); } } bool SurfaceInterface::hasFrameCallbacks() const { - return !wl_list_empty(&d->current.frameCallbacks); + return !wl_list_empty(&d->current->frameCallbacks); } QMatrix4x4 SurfaceInterfacePrivate::buildSurfaceToBufferMatrix() @@ -422,56 +442,56 @@ QMatrix4x4 SurfaceInterfacePrivate::buildSurfaceToBufferMatrix() QMatrix4x4 surfaceToBufferMatrix; - if (!current.buffer) { + if (!current->buffer) { return surfaceToBufferMatrix; } - surfaceToBufferMatrix.scale(current.bufferScale, current.bufferScale); + surfaceToBufferMatrix.scale(current->bufferScale, current->bufferScale); surfaceToBufferMatrix.scale(scaleOverride, scaleOverride); - switch (current.bufferTransform.kind()) { + switch (current->bufferTransform.kind()) { case KWin::OutputTransform::Normal: case KWin::OutputTransform::Flipped: break; case KWin::OutputTransform::Rotated90: case KWin::OutputTransform::Flipped90: - surfaceToBufferMatrix.translate(0, bufferSize.height() / current.bufferScale); + surfaceToBufferMatrix.translate(0, bufferSize.height() / current->bufferScale); surfaceToBufferMatrix.rotate(-90, 0, 0, 1); break; case KWin::OutputTransform::Rotated180: case KWin::OutputTransform::Flipped180: - surfaceToBufferMatrix.translate(bufferSize.width() / current.bufferScale, bufferSize.height() / current.bufferScale); + surfaceToBufferMatrix.translate(bufferSize.width() / current->bufferScale, bufferSize.height() / current->bufferScale); surfaceToBufferMatrix.rotate(-180, 0, 0, 1); break; case KWin::OutputTransform::Rotated270: case KWin::OutputTransform::Flipped270: - surfaceToBufferMatrix.translate(bufferSize.width() / current.bufferScale, 0); + surfaceToBufferMatrix.translate(bufferSize.width() / current->bufferScale, 0); surfaceToBufferMatrix.rotate(-270, 0, 0, 1); break; } - switch (current.bufferTransform.kind()) { + switch (current->bufferTransform.kind()) { case KWin::OutputTransform::Flipped: case KWin::OutputTransform::Flipped180: - surfaceToBufferMatrix.translate(bufferSize.width() / current.bufferScale, 0); + surfaceToBufferMatrix.translate(bufferSize.width() / current->bufferScale, 0); surfaceToBufferMatrix.scale(-1, 1); break; case KWin::OutputTransform::Flipped90: case KWin::OutputTransform::Flipped270: - surfaceToBufferMatrix.translate(bufferSize.height() / current.bufferScale, 0); + surfaceToBufferMatrix.translate(bufferSize.height() / current->bufferScale, 0); surfaceToBufferMatrix.scale(-1, 1); break; default: break; } - if (current.viewport.sourceGeometry.isValid()) { - surfaceToBufferMatrix.translate(current.viewport.sourceGeometry.x(), current.viewport.sourceGeometry.y()); + if (current->viewport.sourceGeometry.isValid()) { + surfaceToBufferMatrix.translate(current->viewport.sourceGeometry.x(), current->viewport.sourceGeometry.y()); } QSizeF sourceSize; - if (current.viewport.sourceGeometry.isValid()) { - sourceSize = current.viewport.sourceGeometry.size(); + if (current->viewport.sourceGeometry.isValid()) { + sourceSize = current->viewport.sourceGeometry.size(); } else { sourceSize = implicitSurfaceSize; } @@ -485,21 +505,29 @@ QMatrix4x4 SurfaceInterfacePrivate::buildSurfaceToBufferMatrix() QRectF SurfaceInterfacePrivate::computeBufferSourceBox() const { - if (!current.viewport.sourceGeometry.isValid()) { + if (!current->viewport.sourceGeometry.isValid()) { return QRectF(0, 0, bufferSize.width(), bufferSize.height()); } - const QSizeF bounds = current.bufferTransform.map(bufferSize); - const QRectF box(current.viewport.sourceGeometry.x() * current.bufferScale, - current.viewport.sourceGeometry.y() * current.bufferScale, - current.viewport.sourceGeometry.width() * current.bufferScale, - current.viewport.sourceGeometry.height() * current.bufferScale); + const QSizeF bounds = current->bufferTransform.map(bufferSize); + const QRectF box(current->viewport.sourceGeometry.x() * current->bufferScale, + current->viewport.sourceGeometry.y() * current->bufferScale, + current->viewport.sourceGeometry.width() * current->bufferScale, + current->viewport.sourceGeometry.height() * current->bufferScale); - return current.bufferTransform.inverted().map(box, bounds); + return current->bufferTransform.inverted().map(box, bounds); +} + +SurfaceState::SurfaceState() +{ + wl_list_init(&frameCallbacks); } void SurfaceState::mergeInto(SurfaceState *target) { + target->serial = serial; + target->locks = locks; + target->bufferIsSet = bufferIsSet; if (target->bufferIsSet) { target->buffer = buffer; @@ -580,6 +608,7 @@ void SurfaceState::mergeInto(SurfaceState *target) } *this = SurfaceState{}; + serial = target->serial; subsurface = target->subsurface; wl_list_init(&frameCallbacks); } @@ -588,13 +617,13 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) { const bool bufferChanged = next->bufferIsSet; const bool opaqueRegionChanged = next->opaqueIsSet; - const bool transformChanged = next->bufferTransformIsSet && (current.bufferTransform != next->bufferTransform); + const bool transformChanged = next->bufferTransformIsSet && (current->bufferTransform != next->bufferTransform); const bool shadowChanged = next->shadowIsSet; const bool blurChanged = next->blurIsSet; const bool contrastChanged = next->contrastIsSet; const bool slideChanged = next->slideIsSet; const bool subsurfaceOrderChanged = next->subsurfaceOrderChanged; - const bool visibilityChanged = bufferChanged && bool(current.buffer) != bool(next->buffer); + const bool visibilityChanged = bufferChanged && bool(current->buffer) != bool(next->buffer); const QSizeF oldSurfaceSize = surfaceSize; const QSize oldBufferSize = bufferSize; @@ -602,17 +631,17 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) const QMatrix4x4 oldSurfaceToBufferMatrix = surfaceToBufferMatrix; const QRegion oldInputRegion = inputRegion; - next->mergeInto(¤t); - bufferRef = current.buffer; + next->mergeInto(current.get()); + bufferRef = current->buffer; scaleOverride = pendingScaleOverride; // TODO: Refactor the state management code because it gets more clumsy. - if (current.buffer) { - bufferSize = current.buffer->size(); + if (current->buffer) { + bufferSize = current->buffer->size(); bufferSourceBox = computeBufferSourceBox(); - implicitSurfaceSize = current.buffer->size() / current.bufferScale; - switch (current.bufferTransform.kind()) { + implicitSurfaceSize = current->buffer->size() / current->bufferScale; + switch (current->bufferTransform.kind()) { case KWin::OutputTransform::Rotated90: case KWin::OutputTransform::Rotated270: case KWin::OutputTransform::Flipped90: @@ -626,21 +655,21 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) break; } - if (current.viewport.destinationSize.isValid()) { - surfaceSize = current.viewport.destinationSize; - } else if (current.viewport.sourceGeometry.isValid()) { - surfaceSize = current.viewport.sourceGeometry.size(); + if (current->viewport.destinationSize.isValid()) { + surfaceSize = current->viewport.destinationSize; + } else if (current->viewport.sourceGeometry.isValid()) { + surfaceSize = current->viewport.sourceGeometry.size(); } else { surfaceSize = implicitSurfaceSize; } const QRectF surfaceRect(QPoint(0, 0), surfaceSize); - inputRegion = current.input & surfaceRect.toAlignedRect(); + inputRegion = current->input & surfaceRect.toAlignedRect(); - if (!current.buffer->hasAlphaChannel()) { + if (!current->buffer->hasAlphaChannel()) { opaqueRegion = surfaceRect.toAlignedRect(); } else { - opaqueRegion = current.opaque & surfaceRect.toAlignedRect(); + opaqueRegion = current->opaque & surfaceRect.toAlignedRect(); } QMatrix4x4 scaleOverrideMatrix; @@ -663,15 +692,6 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) surfaceToBufferMatrix = buildSurfaceToBufferMatrix(); - if (lockedPointer) { - auto lockedPointerPrivate = LockedPointerV1InterfacePrivate::get(lockedPointer); - lockedPointerPrivate->commit(); - } - if (confinedPointer) { - auto confinedPointerPrivate = ConfinedPointerV1InterfacePrivate::get(confinedPointer); - confinedPointerPrivate->commit(); - } - if (opaqueRegionChanged) { Q_EMIT q->opaqueChanged(opaqueRegion); } @@ -679,7 +699,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) Q_EMIT q->inputChanged(inputRegion); } if (transformChanged) { - Q_EMIT q->bufferTransformChanged(current.bufferTransform); + Q_EMIT q->bufferTransformChanged(current->bufferTransform); } if (visibilityChanged) { updateEffectiveMapped(); @@ -713,56 +733,56 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) } if (bufferChanged) { - if (current.buffer && (!current.damage.isEmpty() || !current.bufferDamage.isEmpty())) { - const QRect bufferRect = QRect(QPoint(0, 0), current.buffer->size()); - bufferDamage = current.bufferDamage - .united(q->mapToBuffer(current.damage)) + if (current->buffer && (!current->damage.isEmpty() || !current->bufferDamage.isEmpty())) { + const QRect bufferRect = QRect(QPoint(0, 0), current->buffer->size()); + bufferDamage = current->bufferDamage + .united(q->mapToBuffer(current->damage)) .intersected(bufferRect); Q_EMIT q->damaged(bufferDamage); } } // The position of a sub-surface is applied when its parent is committed. - for (SubSurfaceInterface *subsurface : std::as_const(current.subsurface.below)) { + for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.below)) { auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface); - subsurfacePrivate->parentCommit(); + subsurfacePrivate->parentApplyState(next->serial); } - for (SubSurfaceInterface *subsurface : std::as_const(current.subsurface.above)) { + for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.above)) { auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface); - subsurfacePrivate->parentCommit(); - } - if (role) { - role->commit(); + subsurfacePrivate->parentApplyState(next->serial); } + + Q_EMIT q->stateApplied(next->serial); Q_EMIT q->committed(); } -void SurfaceInterfacePrivate::commitSubSurface() +quint32 SurfaceInterfacePrivate::lockState(SurfaceState *state) { - if (subSurface->isSynchronized()) { - commitToCache(); + state->locks++; + return state->serial; +} + +void SurfaceInterfacePrivate::unlockState(quint32 serial) +{ + if (pending->serial == serial) { + Q_ASSERT(pending->locks > 0); + pending->locks--; } else { - if (hasCacheState) { - commitToCache(); - commitFromCache(); - } else { - applyState(&pending); + for (const auto &state : stashed) { + if (state->serial == serial) { + Q_ASSERT(state->locks > 0); + state->locks--; + break; + } + } + while (!stashed.empty() && !stashed[0]->locks) { + auto stash = std::move(stashed.front()); + stashed.pop_front(); + applyState(stash.get()); } } } -void SurfaceInterfacePrivate::commitToCache() -{ - pending.mergeInto(&cached); - hasCacheState = true; -} - -void SurfaceInterfacePrivate::commitFromCache() -{ - applyState(&cached); - hasCacheState = false; -} - bool SurfaceInterfacePrivate::computeEffectiveMapped() const { if (!bufferRef) { @@ -789,11 +809,11 @@ void SurfaceInterfacePrivate::updateEffectiveMapped() Q_EMIT q->unmapped(); } - for (SubSurfaceInterface *subsurface : std::as_const(current.subsurface.below)) { + for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.below)) { auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface()); surfacePrivate->updateEffectiveMapped(); } - for (SubSurfaceInterface *subsurface : std::as_const(current.subsurface.above)) { + for (SubSurfaceInterface *subsurface : std::as_const(current->subsurface.above)) { auto surfacePrivate = SurfaceInterfacePrivate::get(subsurface->surface()); surfacePrivate->updateEffectiveMapped(); } @@ -835,7 +855,7 @@ QRectF SurfaceInterface::bufferSourceBox() const KWin::OutputTransform SurfaceInterface::bufferTransform() const { - return d->current.bufferTransform; + return d->current->bufferTransform; } KWin::GraphicsBuffer *SurfaceInterface::buffer() const @@ -845,7 +865,7 @@ KWin::GraphicsBuffer *SurfaceInterface::buffer() const QPoint SurfaceInterface::offset() const { - return d->current.offset / d->scaleOverride; + return d->current->offset / d->scaleOverride; } SurfaceInterface *SurfaceInterface::get(wl_resource *native) @@ -866,12 +886,12 @@ SurfaceInterface *SurfaceInterface::get(quint32 id, const ClientConnection *clie QList SurfaceInterface::below() const { - return d->current.subsurface.below; + return d->current->subsurface.below; } QList SurfaceInterface::above() const { - return d->current.subsurface.above; + return d->current->subsurface.above; } SubSurfaceInterface *SurfaceInterface::subSurface() const @@ -888,11 +908,11 @@ QRectF SurfaceInterface::boundingRect() const { QRectF rect(QPoint(0, 0), size()); - for (const SubSurfaceInterface *subSurface : std::as_const(d->current.subsurface.below)) { + for (const SubSurfaceInterface *subSurface : std::as_const(d->current->subsurface.below)) { const SurfaceInterface *childSurface = subSurface->surface(); rect |= childSurface->boundingRect().translated(subSurface->position()); } - for (const SubSurfaceInterface *subSurface : std::as_const(d->current.subsurface.above)) { + for (const SubSurfaceInterface *subSurface : std::as_const(d->current->subsurface.above)) { const SurfaceInterface *childSurface = subSurface->surface(); rect |= childSurface->boundingRect().translated(subSurface->position()); } @@ -902,22 +922,22 @@ QRectF SurfaceInterface::boundingRect() const QPointer SurfaceInterface::shadow() const { - return d->current.shadow; + return d->current->shadow; } QPointer SurfaceInterface::blur() const { - return d->current.blur; + return d->current->blur; } QPointer SurfaceInterface::contrast() const { - return d->current.contrast; + return d->current->contrast; } QPointer SurfaceInterface::slideOnShowHide() const { - return d->current.slide; + return d->current->slide; } bool SurfaceInterface::isMapped() const @@ -973,10 +993,10 @@ void SurfaceInterface::setOutputs(const QVector &outputs) } d->outputs = outputs; - for (auto child : std::as_const(d->current.subsurface.below)) { + for (auto child : std::as_const(d->current->subsurface.below)) { child->surface()->setOutputs(outputs); } - for (auto child : std::as_const(d->current.subsurface.above)) { + for (auto child : std::as_const(d->current->subsurface.above)) { child->surface()->setOutputs(outputs); } } @@ -987,7 +1007,7 @@ SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position) return nullptr; } - for (auto it = d->current.subsurface.above.crbegin(); it != d->current.subsurface.above.crend(); ++it) { + for (auto it = d->current->subsurface.above.crbegin(); it != d->current->subsurface.above.crend(); ++it) { const SubSurfaceInterface *current = *it; SurfaceInterface *surface = current->surface(); if (auto s = surface->surfaceAt(position - current->position())) { @@ -1000,7 +1020,7 @@ SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position) return this; } - for (auto it = d->current.subsurface.below.crbegin(); it != d->current.subsurface.below.crend(); ++it) { + for (auto it = d->current->subsurface.below.crbegin(); it != d->current->subsurface.below.crend(); ++it) { const SubSurfaceInterface *current = *it; SurfaceInterface *surface = current->surface(); if (auto s = surface->surfaceAt(position - current->position())) { @@ -1018,7 +1038,7 @@ SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position) return nullptr; } - for (auto it = d->current.subsurface.above.crbegin(); it != d->current.subsurface.above.crend(); ++it) { + for (auto it = d->current->subsurface.above.crbegin(); it != d->current->subsurface.above.crend(); ++it) { const SubSurfaceInterface *current = *it; auto surface = current->surface(); if (auto s = surface->inputSurfaceAt(position - current->position())) { @@ -1031,7 +1051,7 @@ SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position) return this; } - for (auto it = d->current.subsurface.below.crbegin(); it != d->current.subsurface.below.crend(); ++it) { + for (auto it = d->current->subsurface.below.crbegin(); it != d->current->subsurface.below.crend(); ++it) { const SubSurfaceInterface *current = *it; auto surface = current->surface(); if (auto s = surface->inputSurfaceAt(position - current->position())) { @@ -1064,7 +1084,7 @@ LinuxDmaBufV1Feedback *SurfaceInterface::dmabufFeedbackV1() const KWin::ContentType SurfaceInterface::contentType() const { - return d->current.contentType; + return d->current->contentType; } QPointF SurfaceInterface::mapToBuffer(const QPointF &point) const @@ -1126,7 +1146,7 @@ QPointF SurfaceInterface::toSurfaceLocal(const QPointF &point) const PresentationHint SurfaceInterface::presentationHint() const { - return d->current.presentationHint; + return d->current->presentationHint; } void SurfaceInterface::setPreferredBufferScale(qreal scale) @@ -1143,10 +1163,10 @@ void SurfaceInterface::setPreferredBufferScale(qreal scale) d->send_preferred_buffer_scale(std::ceil(scale)); } - for (auto child : qAsConst(d->current.subsurface.below)) { + for (auto child : qAsConst(d->current->subsurface.below)) { child->surface()->setPreferredBufferScale(scale); } - for (auto child : qAsConst(d->current.subsurface.above)) { + for (auto child : qAsConst(d->current->subsurface.above)) { child->surface()->setPreferredBufferScale(scale); } } @@ -1162,10 +1182,10 @@ void SurfaceInterface::setPreferredBufferTransform(KWin::OutputTransform transfo d->send_preferred_buffer_transform(uint32_t(transform.kind())); } - for (auto child : qAsConst(d->current.subsurface.below)) { + for (auto child : qAsConst(d->current->subsurface.below)) { child->surface()->setPreferredBufferTransform(transform); } - for (auto child : qAsConst(d->current.subsurface.above)) { + for (auto child : qAsConst(d->current->subsurface.above)) { child->surface()->setPreferredBufferTransform(transform); } } diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h index e36f80e240..6a56a4be3f 100644 --- a/src/wayland/surface_interface.h +++ b/src/wayland/surface_interface.h @@ -430,11 +430,64 @@ Q_SIGNALS: */ void committed(); + /** + * This signal is emitted when a surface commit with the specified \a serial has been cached + * to be applied later. + */ + void stateStashed(quint32 serial); + + /** + * This signal is emitted when the state in a surface commit with the specified \a serial + * has been applied. + */ + void stateApplied(quint32 serial); + private: std::unique_ptr d; friend class SurfaceInterfacePrivate; }; -} +/** + * The SurfaceExtension class is the base class for wl_surface extensions. The SurfaceExtension + * helps with managing extension state and keeping it in sync with the surface state. + */ +template +class SurfaceExtension : public QObject +{ +public: + explicit SurfaceExtension(SurfaceInterface *surface) + { + connect(surface, &SurfaceInterface::stateStashed, this, &SurfaceExtension::stashState); + connect(surface, &SurfaceInterface::stateApplied, this, &SurfaceExtension::applyState); + } + + virtual void apply(Commit *commit) = 0; + + Commit pending; + QMap stashed; + +private: + void stashState(quint32 serial) + { + Commit stash = std::exchange(pending, Commit{}); + stashed.insert(serial, stash); + } + + void applyState(quint32 serial) + { + if (!stashed.isEmpty()) { + if (stashed.firstKey() == serial) { + Commit stash = stashed.take(serial); + apply(&stash); + } + return; + } + + apply(&pending); + pending = Commit{}; + } +}; + +} // namespace KWaylandServer Q_DECLARE_METATYPE(KWaylandServer::SurfaceInterface *) diff --git a/src/wayland/surface_interface_p.h b/src/wayland/surface_interface_p.h index 5b58066e6b..f7a547b93d 100644 --- a/src/wayland/surface_interface_p.h +++ b/src/wayland/surface_interface_p.h @@ -15,6 +15,7 @@ // Wayland #include "qwayland-server-wayland.h" // C++ +#include #include namespace KWaylandServer @@ -28,8 +29,13 @@ class FractionalScaleV1Interface; struct SurfaceState { + SurfaceState(); + void mergeInto(SurfaceState *target); + quint32 serial = 0; + quint32 locks = 0; + QRegion damage = QRegion(); QRegion bufferDamage = QRegion(); QRegion opaque = QRegion(); @@ -103,14 +109,13 @@ public: void installPointerConstraint(ConfinedPointerV1Interface *confinement); void installIdleInhibitor(IdleInhibitorV1Interface *inhibitor); - void commitToCache(); - void commitFromCache(); - - void commitSubSurface(); QMatrix4x4 buildSurfaceToBufferMatrix(); QRectF computeBufferSourceBox() const; void applyState(SurfaceState *next); + quint32 lockState(SurfaceState *state); + void unlockState(quint32 serial); + bool computeEffectiveMapped() const; void updateEffectiveMapped(); @@ -124,9 +129,9 @@ public: CompositorInterface *compositor; SurfaceInterface *q; SurfaceRole *role = nullptr; - SurfaceState current; - SurfaceState pending; - SurfaceState cached; + std::unique_ptr current; + std::unique_ptr pending; + std::deque> stashed; SubSurfaceInterface *subSurface = nullptr; QMatrix4x4 surfaceToBufferMatrix; QSize bufferSize = QSize(0, 0); @@ -139,7 +144,6 @@ public: KWin::GraphicsBufferRef bufferRef; QRegion bufferDamage; bool mapped = false; - bool hasCacheState = false; qreal scaleOverride = 1.; qreal pendingScaleOverride = 1.; diff --git a/src/wayland/surfacerole_p.h b/src/wayland/surfacerole_p.h index 8dbbbfe6ba..0b0d9ec21c 100644 --- a/src/wayland/surfacerole_p.h +++ b/src/wayland/surfacerole_p.h @@ -24,8 +24,6 @@ public: return m_surface; } - virtual void commit() = 0; - static SurfaceRole *get(SurfaceInterface *surface); private: diff --git a/src/wayland/tearingcontrol_v1_interface.cpp b/src/wayland/tearingcontrol_v1_interface.cpp index 9ddaefa100..09eb3c5e3e 100644 --- a/src/wayland/tearingcontrol_v1_interface.cpp +++ b/src/wayland/tearingcontrol_v1_interface.cpp @@ -74,8 +74,8 @@ TearingControlV1Interface::~TearingControlV1Interface() { if (m_surface) { SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); - surfacePrivate->pending.presentationHint = PresentationHint::VSync; - surfacePrivate->pending.tearingIsSet = true; + surfacePrivate->pending->presentationHint = PresentationHint::VSync; + surfacePrivate->pending->tearingIsSet = true; surfacePrivate->tearing = nullptr; } } @@ -85,11 +85,11 @@ void TearingControlV1Interface::wp_tearing_control_v1_set_presentation_hint(Reso if (m_surface) { SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); if (hint == presentation_hint::presentation_hint_async) { - surfacePrivate->pending.presentationHint = PresentationHint::Async; + surfacePrivate->pending->presentationHint = PresentationHint::Async; } else { - surfacePrivate->pending.presentationHint = PresentationHint::VSync; + surfacePrivate->pending->presentationHint = PresentationHint::VSync; } - surfacePrivate->pending.tearingIsSet = true; + surfacePrivate->pending->tearingIsSet = true; } } diff --git a/src/wayland/viewporter_interface.cpp b/src/wayland/viewporter_interface.cpp index 573897af69..dde62a32b8 100644 --- a/src/wayland/viewporter_interface.cpp +++ b/src/wayland/viewporter_interface.cpp @@ -70,10 +70,10 @@ void ViewportInterface::wp_viewport_destroy(Resource *resource) { if (surface) { SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->pending.viewport.sourceGeometry = QRectF(); - surfacePrivate->pending.viewport.sourceGeometryIsSet = true; - surfacePrivate->pending.viewport.destinationSize = QSize(); - surfacePrivate->pending.viewport.destinationSizeIsSet = true; + surfacePrivate->pending->viewport.sourceGeometry = QRectF(); + surfacePrivate->pending->viewport.sourceGeometryIsSet = true; + surfacePrivate->pending->viewport.destinationSize = QSize(); + surfacePrivate->pending->viewport.destinationSizeIsSet = true; } wl_resource_destroy(resource->handle); @@ -93,8 +93,8 @@ void ViewportInterface::wp_viewport_set_source(Resource *resource, wl_fixed_t x_ if (x == -1 && y == -1 && width == -1 && height == -1) { SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->pending.viewport.sourceGeometry = QRectF(); - surfacePrivate->pending.viewport.sourceGeometryIsSet = true; + surfacePrivate->pending->viewport.sourceGeometry = QRectF(); + surfacePrivate->pending->viewport.sourceGeometryIsSet = true; return; } @@ -104,8 +104,8 @@ void ViewportInterface::wp_viewport_set_source(Resource *resource, wl_fixed_t x_ } SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->pending.viewport.sourceGeometry = QRectF(x, y, width, height); - surfacePrivate->pending.viewport.sourceGeometryIsSet = true; + surfacePrivate->pending->viewport.sourceGeometry = QRectF(x, y, width, height); + surfacePrivate->pending->viewport.sourceGeometryIsSet = true; } void ViewportInterface::wp_viewport_set_destination(Resource *resource, int32_t width, int32_t height) @@ -117,8 +117,8 @@ void ViewportInterface::wp_viewport_set_destination(Resource *resource, int32_t if (width == -1 && height == -1) { SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->pending.viewport.destinationSize = QSize(); - surfacePrivate->pending.viewport.destinationSizeIsSet = true; + surfacePrivate->pending->viewport.destinationSize = QSize(); + surfacePrivate->pending->viewport.destinationSizeIsSet = true; return; } @@ -128,8 +128,8 @@ void ViewportInterface::wp_viewport_set_destination(Resource *resource, int32_t } SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface); - surfacePrivate->pending.viewport.destinationSize = QSize(width, height); - surfacePrivate->pending.viewport.destinationSizeIsSet = true; + surfacePrivate->pending->viewport.destinationSize = QSize(width, height); + surfacePrivate->pending->viewport.destinationSizeIsSet = true; } ViewporterInterface::ViewporterInterface(Display *display, QObject *parent) diff --git a/src/wayland/xdgshell_interface.cpp b/src/wayland/xdgshell_interface.cpp index d19c730bfd..83296f5d93 100644 --- a/src/wayland/xdgshell_interface.cpp +++ b/src/wayland/xdgshell_interface.cpp @@ -142,7 +142,6 @@ void XdgSurfaceInterfacePrivate::unassignRole() { toplevel = nullptr; popup = nullptr; - current = nullptr; pending = nullptr; } @@ -150,46 +149,40 @@ void XdgSurfaceInterfacePrivate::assignRole(XdgToplevelInterface *toplevel) { this->toplevel = toplevel; - XdgSurfaceRole *role = XdgToplevelInterfacePrivate::get(toplevel); - current = &role->current.base; - pending = &role->pending.base; + XdgSurfaceRole *role = XdgToplevelInterfacePrivate::get(toplevel); + pending = &role->pending; } void XdgSurfaceInterfacePrivate::assignRole(XdgPopupInterface *popup) { this->popup = popup; - XdgSurfaceRole *role = XdgPopupInterfacePrivate::get(popup); - current = &role->current.base; - pending = &role->pending.base; + XdgSurfaceRole *role = XdgPopupInterfacePrivate::get(popup); + pending = &role->pending; } -void XdgSurfaceInterfacePrivate::applyState(XdgSurfaceState *next) +void XdgSurfaceInterfacePrivate::apply(XdgSurfaceCommit *commit) { if (surface->buffer()) { firstBufferAttached = true; } - if (next->acknowledgedConfigureIsSet) { - current->acknowledgedConfigure = next->acknowledgedConfigure; - next->acknowledgedConfigureIsSet = false; - Q_EMIT q->configureAcknowledged(current->acknowledgedConfigure); + if (commit->acknowledgedConfigure.has_value()) { + Q_EMIT q->configureAcknowledged(commit->acknowledgedConfigure.value()); } - if (next->windowGeometryIsSet) { - current->windowGeometry = next->windowGeometry; - next->windowGeometryIsSet = false; - Q_EMIT q->windowGeometryChanged(current->windowGeometry); + if (commit->windowGeometry.has_value()) { + windowGeometry = commit->windowGeometry.value(); + Q_EMIT q->windowGeometryChanged(windowGeometry); } } -void XdgSurfaceInterfacePrivate::resetState() +void XdgSurfaceInterfacePrivate::reset() { firstBufferAttached = false; isConfigured = false; isInitialized = false; - *current = XdgSurfaceState{}; - *pending = XdgSurfaceState{}; + windowGeometry = QRect(); Q_EMIT q->resetOccurred(); } @@ -275,7 +268,6 @@ void XdgSurfaceInterfacePrivate::xdg_surface_set_window_geometry(Resource *resou } pending->windowGeometry = QRect(x, y, width, height); - pending->windowGeometryIsSet = true; } void XdgSurfaceInterfacePrivate::xdg_surface_ack_configure(Resource *resource, uint32_t serial) @@ -286,7 +278,6 @@ void XdgSurfaceInterfacePrivate::xdg_surface_ack_configure(Resource *resource, u } pending->acknowledgedConfigure = serial; - pending->acknowledgedConfigureIsSet = true; } XdgSurfaceInterface::XdgSurfaceInterface(XdgShellInterface *shell, SurfaceInterface *surface, ::wl_resource *resource) @@ -333,7 +324,7 @@ bool XdgSurfaceInterface::isConfigured() const QRect XdgSurfaceInterface::windowGeometry() const { - return d->current->windowGeometry; + return d->windowGeometry; } XdgSurfaceInterface *XdgSurfaceInterface::get(::wl_resource *resource) @@ -351,7 +342,7 @@ XdgToplevelInterfacePrivate::XdgToplevelInterfacePrivate(XdgToplevelInterface *t { } -void XdgToplevelInterfacePrivate::commit() +void XdgToplevelInterfacePrivate::apply(XdgToplevelCommit *commit) { auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); if (xdgSurfacePrivate->firstBufferAttached && !xdgSurfacePrivate->surface->buffer()) { @@ -359,15 +350,15 @@ void XdgToplevelInterfacePrivate::commit() return; } - xdgSurfacePrivate->applyState(&pending.base); + xdgSurfacePrivate->apply(commit); - if (current.minimumSize != pending.minimumSize) { - current.minimumSize = pending.minimumSize; - Q_EMIT q->minimumSizeChanged(current.minimumSize); + if (commit->minimumSize && commit->minimumSize != minimumSize) { + minimumSize = commit->minimumSize.value(); + Q_EMIT q->minimumSizeChanged(minimumSize); } - if (current.maximumSize != pending.maximumSize) { - current.maximumSize = pending.maximumSize; - Q_EMIT q->maximumSizeChanged(current.maximumSize); + if (commit->maximumSize && commit->maximumSize != maximumSize) { + maximumSize = commit->maximumSize.value(); + Q_EMIT q->maximumSizeChanged(maximumSize); } if (!xdgSurfacePrivate->isInitialized) { @@ -379,12 +370,14 @@ void XdgToplevelInterfacePrivate::commit() void XdgToplevelInterfacePrivate::reset() { auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); - xdgSurfacePrivate->resetState(); + xdgSurfacePrivate->reset(); windowTitle = QString(); windowClass = QString(); - current = XdgToplevelState{}; - pending = XdgToplevelState{}; + minimumSize = QSize(); + maximumSize = QSize(); + pending = XdgToplevelCommit{}; + stashed.clear(); Q_EMIT q->resetOccurred(); } @@ -574,12 +567,12 @@ QString XdgToplevelInterface::windowClass() const QSize XdgToplevelInterface::minimumSize() const { - return d->current.minimumSize.isEmpty() ? QSize(0, 0) : d->current.minimumSize; + return d->minimumSize.isEmpty() ? QSize(0, 0) : d->minimumSize; } QSize XdgToplevelInterface::maximumSize() const { - return d->current.maximumSize.isEmpty() ? QSize(INT_MAX, INT_MAX) : d->current.maximumSize; + return d->maximumSize.isEmpty() ? QSize(INT_MAX, INT_MAX) : d->maximumSize; } quint32 XdgToplevelInterface::sendConfigure(const QSize &size, const States &states) @@ -693,7 +686,7 @@ XdgPopupInterfacePrivate::XdgPopupInterfacePrivate(XdgPopupInterface *popup, Xdg { } -void XdgPopupInterfacePrivate::commit() +void XdgPopupInterfacePrivate::apply(XdgPopupCommit *commit) { if (!parentSurface) { auto shellPrivate = XdgShellInterfacePrivate::get(xdgSurface->shell()); @@ -709,7 +702,7 @@ void XdgPopupInterfacePrivate::commit() return; } - xdgSurfacePrivate->applyState(&pending.base); + xdgSurfacePrivate->apply(commit); if (!xdgSurfacePrivate->isInitialized) { Q_EMIT q->initializeRequested(); @@ -720,7 +713,9 @@ void XdgPopupInterfacePrivate::commit() void XdgPopupInterfacePrivate::reset() { auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); - xdgSurfacePrivate->resetState(); + pending = XdgPopupCommit{}; + stashed.clear(); + xdgSurfacePrivate->reset(); } void XdgPopupInterfacePrivate::xdg_popup_destroy_resource(Resource *resource) diff --git a/src/wayland/xdgshell_interface_p.h b/src/wayland/xdgshell_interface_p.h index 25527698e0..4831a5611d 100644 --- a/src/wayland/xdgshell_interface_p.h +++ b/src/wayland/xdgshell_interface_p.h @@ -9,7 +9,7 @@ #include "qwayland-server-xdg-shell.h" #include "xdgshell_interface.h" -#include "surface_interface.h" +#include "surface_interface_p.h" #include "surfacerole_p.h" namespace KWaylandServer @@ -83,37 +83,31 @@ protected: void xdg_positioner_set_parent_configure(Resource *resource, uint32_t serial) override; }; -struct XdgSurfaceState +struct XdgSurfaceCommit { - QRect windowGeometry; - quint32 acknowledgedConfigure; - bool acknowledgedConfigureIsSet = false; - bool windowGeometryIsSet = false; + std::optional windowGeometry; + std::optional acknowledgedConfigure; }; -struct XdgToplevelState +struct XdgToplevelCommit : XdgSurfaceCommit { - XdgSurfaceState base; - QSize minimumSize; - QSize maximumSize; + std::optional minimumSize; + std::optional maximumSize; }; -struct XdgPopupState +struct XdgPopupCommit : XdgSurfaceCommit { - XdgSurfaceState base; }; -template -class XdgSurfaceRole : public SurfaceRole +template +class XdgSurfaceRole : public SurfaceRole, public SurfaceExtension { public: XdgSurfaceRole(SurfaceInterface *surface, const QByteArray &name) : SurfaceRole(surface, name) + , SurfaceExtension(surface) { } - - State pending; - State current; }; class XdgSurfaceInterfacePrivate : public QtWaylandServer::xdg_surface @@ -121,22 +115,22 @@ class XdgSurfaceInterfacePrivate : public QtWaylandServer::xdg_surface public: XdgSurfaceInterfacePrivate(XdgSurfaceInterface *xdgSurface); - void applyState(XdgSurfaceState *next); - void resetState(); + void apply(XdgSurfaceCommit *commit); + void reset(); void unassignRole(); void assignRole(XdgToplevelInterface *toplevel); void assignRole(XdgPopupInterface *popup); // These two point into XdgSurfaceRole's state and are valid as long as a role is assigned. - XdgSurfaceState *current = nullptr; - XdgSurfaceState *pending = nullptr; + XdgSurfaceCommit *pending = nullptr; XdgSurfaceInterface *q; XdgShellInterface *shell = nullptr; QPointer toplevel; QPointer popup; QPointer surface; + QRect windowGeometry; bool firstBufferAttached = false; bool isConfigured = false; bool isInitialized = false; @@ -152,12 +146,12 @@ protected: void xdg_surface_ack_configure(Resource *resource, uint32_t serial) override; }; -class XdgToplevelInterfacePrivate : public XdgSurfaceRole, public QtWaylandServer::xdg_toplevel +class XdgToplevelInterfacePrivate : public XdgSurfaceRole, public QtWaylandServer::xdg_toplevel { public: XdgToplevelInterfacePrivate(XdgToplevelInterface *toplevel, XdgSurfaceInterface *surface); - void commit() override; + void apply(XdgToplevelCommit *commit) override; void reset(); static XdgToplevelInterfacePrivate *get(XdgToplevelInterface *toplevel); @@ -169,6 +163,8 @@ public: XdgSurfaceInterface *xdgSurface; QString windowTitle; QString windowClass; + QSize minimumSize; + QSize maximumSize; protected: void xdg_toplevel_destroy_resource(Resource *resource) override; @@ -188,14 +184,14 @@ protected: void xdg_toplevel_set_minimized(Resource *resource) override; }; -class XdgPopupInterfacePrivate : public XdgSurfaceRole, public QtWaylandServer::xdg_popup +class XdgPopupInterfacePrivate : public XdgSurfaceRole, public QtWaylandServer::xdg_popup { public: static XdgPopupInterfacePrivate *get(XdgPopupInterface *popup); XdgPopupInterfacePrivate(XdgPopupInterface *popup, XdgSurfaceInterface *surface); - void commit() override; + void apply(XdgPopupCommit *commit) override; void reset(); XdgPopupInterface *q; diff --git a/src/wayland/xwaylandshell_v1_interface.cpp b/src/wayland/xwaylandshell_v1_interface.cpp index 6a023a1348..454b5091cb 100644 --- a/src/wayland/xwaylandshell_v1_interface.cpp +++ b/src/wayland/xwaylandshell_v1_interface.cpp @@ -7,8 +7,8 @@ #include "xwaylandshell_v1_interface.h" #include "display.h" +#include "surface_interface_p.h" #include "surfacerole_p.h" -#include "surface_interface.h" #include "qwayland-server-xwayland-shell-v1.h" @@ -30,23 +30,21 @@ protected: void xwayland_shell_v1_get_xwayland_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) override; }; -struct XwaylandSurfaceV1State +struct XwaylandSurfaceV1Commit { std::optional serial; }; -class XwaylandSurfaceV1InterfacePrivate : public SurfaceRole, public QtWaylandServer::xwayland_surface_v1 +class XwaylandSurfaceV1InterfacePrivate : public SurfaceRole, public SurfaceExtension, public QtWaylandServer::xwayland_surface_v1 { public: XwaylandSurfaceV1InterfacePrivate(XwaylandShellV1Interface *shell, SurfaceInterface *surface, wl_client *client, uint32_t id, int version, XwaylandSurfaceV1Interface *q); - void commit() override; + void apply(XwaylandSurfaceV1Commit *commit) override; XwaylandSurfaceV1Interface *q; XwaylandShellV1Interface *shell; - - XwaylandSurfaceV1State current; - XwaylandSurfaceV1State pending; + std::optional serial; protected: void xwayland_surface_v1_destroy_resource(Resource *resource) override; @@ -82,16 +80,17 @@ void XwaylandShellV1InterfacePrivate::xwayland_shell_v1_get_xwayland_surface(Res XwaylandSurfaceV1InterfacePrivate::XwaylandSurfaceV1InterfacePrivate(XwaylandShellV1Interface *shell, SurfaceInterface *surface, wl_client *client, uint32_t id, int version, XwaylandSurfaceV1Interface *q) : SurfaceRole(surface, QByteArrayLiteral("xwayland_surface_v1")) + , SurfaceExtension(surface) , QtWaylandServer::xwayland_surface_v1(client, id, version) , q(q) , shell(shell) { } -void XwaylandSurfaceV1InterfacePrivate::commit() +void XwaylandSurfaceV1InterfacePrivate::apply(XwaylandSurfaceV1Commit *commit) { - if (pending.serial.has_value()) { - current.serial = std::exchange(pending.serial, std::nullopt); + if (commit->serial.has_value()) { + serial = commit->serial; Q_EMIT shell->surfaceAssociated(q); } } @@ -109,9 +108,9 @@ void XwaylandSurfaceV1InterfacePrivate::xwayland_surface_v1_set_serial(Resource return; } - if (current.serial.has_value()) { + if (this->serial.has_value()) { wl_resource_post_error(resource->handle, error_already_associated, - "xwayland_surface_v1 already has a serial assigned to it: %" PRIu64, current.serial.value()); + "xwayland_surface_v1 already has a serial assigned to it: %" PRIu64, this->serial.value()); return; } @@ -159,7 +158,7 @@ SurfaceInterface *XwaylandSurfaceV1Interface::surface() const std::optional XwaylandSurfaceV1Interface::serial() const { - return d->current.serial; + return d->serial; } } // namespace KWaylandServer