Commit 56ba6610 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii

Rewrite subsurface wrappers following the new design principles

This change rewrites implementation of subsurfaces with qtwaylandscanner
and fixes various smaller issues, such as proper handling of position
updates for subsurfaces in the desync mode and getting rid of QPointer in
the public API.
parent 023228cd
......@@ -131,8 +131,6 @@ void TestWaylandSeat::init()
m_compositorInterface = m_display->createCompositor(m_display);
m_subCompositorInterface = m_display->createSubCompositor(m_display);
QVERIFY(m_subCompositorInterface);
m_subCompositorInterface->create();
QVERIFY(m_subCompositorInterface->isValid());
m_relativePointerManagerInterface = m_display->createRelativePointerManager(RelativePointerInterfaceVersion::UnstableV1, m_display);
QVERIFY(m_relativePointerManagerInterface);
......
......@@ -85,8 +85,6 @@ void TestSubCompositor::init()
m_subcompositorInterface = m_display->createSubCompositor(m_display);
QVERIFY(m_subcompositorInterface);
m_subcompositorInterface->create();
QVERIFY(m_subcompositorInterface->isValid());
QVERIFY(subCompositorSpy.wait());
m_subCompositor = registry.createSubCompositor(subCompositorSpy.first().first().value<quint32>(), subCompositorSpy.first().last().value<quint32>(), this);
......
......@@ -98,7 +98,7 @@ void PointerInterface::Private::registerPinchGesture(PointerPinchGestureInterfac
namespace {
static QPointF surfacePosition(SurfaceInterface *surface) {
if (surface && surface->subSurface()) {
return surface->subSurface()->position() + surfacePosition(surface->subSurface()->parentSurface().data());
return surface->subSurface()->position() + surfacePosition(surface->subSurface()->parentSurface());
}
return QPointF();
}
......
This diff is collapsed.
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef WAYLAND_SERVER_SUBCOMPOSITOR_INTERFACE_H
#define WAYLAND_SERVER_SUBCOMPOSITOR_INTERFACE_H
#pragma once
#include <QObject>
#include <QPointer>
#include <KWaylandServer/kwaylandserver_export.h>
#include "global.h"
#include "resource.h"
struct wl_resource;
namespace KWaylandServer
{
class Display;
class SubCompositorInterfacePrivate;
class SurfaceInterface;
class SubSurfaceInterface;
class SubSurfaceInterfacePrivate;
/**
* @todo Add documentation
* The SubCompositorInterface compositor extension provides applications a way to offload
* compositing work within a window from clients to the compositor. This may reduce the power
* usage for applications such as video players, etc.
*
* The SubCompositorInterface corresponds to the Wayland interface @c wl_subcompositor.
*/
class KWAYLANDSERVER_EXPORT SubCompositorInterface : public Global
class KWAYLANDSERVER_EXPORT SubCompositorInterface : public QObject
{
Q_OBJECT
public:
virtual ~SubCompositorInterface();
explicit SubCompositorInterface(Display *display, QObject *parent = nullptr);
~SubCompositorInterface() override;
Q_SIGNALS:
void subSurfaceCreated(KWaylandServer::SubSurfaceInterface*);
/**
* This signal is emitted when a new sub-surface @subsurface has been created.
*/
void subSurfaceCreated(KWaylandServer::SubSurfaceInterface *subsurface);
private:
explicit SubCompositorInterface(Display *display, QObject *parent = nullptr);
friend class Display;
class Private;
QScopedPointer<SubCompositorInterfacePrivate> d;
};
/**
* @todo Add documentation
* The SubSurfaceInterface corresponds to the Wayland interface @c wl_subsurface.
*/
class KWAYLANDSERVER_EXPORT SubSurfaceInterface : public Resource
class KWAYLANDSERVER_EXPORT SubSurfaceInterface : public QObject
{
Q_OBJECT
Q_PROPERTY(QPoint position READ position NOTIFY positionChanged)
Q_PROPERTY(KWaylandServer::SubSurfaceInterface::Mode mode READ mode NOTIFY modeChanged)
public:
virtual ~SubSurfaceInterface();
~SubSurfaceInterface() override;
/**
* Returns the position of the sub-surface relative to the upper-left corner of its parent.
*/
QPoint position() const;
/**
* This enum type is used to specify the commit behavior for a subsurface.
*/
enum class Mode {
Synchronized,
Desynchronized
};
/**
* Returns the current commit mode.
*
* @see isSynchronized
*/
Mode mode() const;
/**
* Whether this SubSurfaceInterface is in synchronized mode.
* A SubSurface is in synchronized mode if either {@link mode} is
* @c Mode::Synchronized or if the parent surface is in synchronized
* mode. If a SubSurfaceInterface is in synchronized mode all child
* SubSurfaceInterfaces are also in synchronized mode ignoring the actual mode.
* @returns Whether this SubSurfaceInterface is in synchronized mode.
* Returns @c true if the sub-surface is in synchronized mode; otherwise returns @c false.
*
* This method checks whether this sub-surface or any of its ancestors is in the synchronized
* mode. Note that this function is not equivalent to calling mode() and checking whether
* the return value is Mode::Synchronized.
*
* @see mode
* @since 5.22
**/
*/
bool isSynchronized() const;
// TODO: remove with ABI break (KF6)
QPointer<SurfaceInterface> surface();
/**
* @returns The surface this SubSurfaceInterface was created on.
* @since 5.22
**/
QPointer<SurfaceInterface> surface() const;
// TODO: remove with ABI break (KF6)
QPointer<SurfaceInterface> parentSurface();
* Returns the SurfaceInterface for this SubSurfaceInterface. This function never returns a
* @c null.
*/
SurfaceInterface *surface() const;
/**
* @returns The parent surface for which this SubSurfaceInterface is a child
* @since 5.22
**/
QPointer<SurfaceInterface> parentSurface() const;
* Returns the parent surface for this SubSurfaceInterface. This function may return @c null.
*/
SurfaceInterface *parentSurface() const;
/**
* @returns the main surface for the sub-surface tree, that is the first surface without a parent
* @since 5.22
**/
QPointer<SurfaceInterface> mainSurface() const;
* Returns the main surface for the sub-surface tree, that is the first surface without a parent
*/
SurfaceInterface *mainSurface() const;
Q_SIGNALS:
void positionChanged(const QPoint&);
void modeChanged(KWaylandServer::SubSurfaceInterface::Mode);
/**
* This signal is emitted when the position of the sub-surface has changed.
*/
void positionChanged(const QPoint &position);
/**
* This signal is emitted when the commit mode of the sub-surface has changed.
*/
void modeChanged(KWaylandServer::SubSurfaceInterface::Mode mode);
private:
friend class SubCompositorInterface;
friend class SurfaceInterface;
friend class SurfaceInterfacePrivate;
explicit SubSurfaceInterface(SubCompositorInterface *parent, wl_resource *parentResource);
class Private;
Private *d_func() const;
SubSurfaceInterface(SurfaceInterface *surface, SurfaceInterface *parent, wl_resource *resource);
QScopedPointer<SubSurfaceInterfacePrivate> d;
friend class SubSurfaceInterfacePrivate;
friend class SubCompositorInterfacePrivate;
};
}
} // namespace KWaylandServer
Q_DECLARE_METATYPE(KWaylandServer::SubSurfaceInterface::Mode)
#endif
/*
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#ifndef WAYLAND_SERVER_SUBSURFACE_INTERFACE_P_H
#define WAYLAND_SERVER_SUBSURFACE_INTERFACE_P_H
#pragma once
#include "subcompositor_interface.h"
#include "resource_p.h"
// Qt
#include "surfacerole_p.h"
#include <QPoint>
// Wayland
#include <wayland-server.h>
#include <QPointer>
#include "qwayland-server-wayland.h"
namespace KWaylandServer
{
class SubSurfaceInterface::Private : public Resource::Private
class SubCompositorInterfacePrivate : public QtWaylandServer::wl_subcompositor
{
public:
Private(SubSurfaceInterface *q, SubCompositorInterface *compositor, wl_resource *parentResource);
~Private();
SubCompositorInterfacePrivate(Display *display, SubCompositorInterface *q);
using Resource::Private::create;
void create(ClientConnection *client, quint32 version, quint32 id, SurfaceInterface *surface, SurfaceInterface *parent);
void commit();
SubCompositorInterface *q;
QPoint pos = QPoint(0, 0);
QPoint scheduledPos = QPoint();
bool scheduledPosChange = false;
Mode mode = Mode::Synchronized;
protected:
void subcompositor_destroy(Resource *resource) override;
void subcompositor_get_subsurface(Resource *resource, uint32_t id,
struct ::wl_resource *surface_resource,
struct ::wl_resource *parent_resource) override;
};
class SubSurfaceInterfacePrivate : public SurfaceRole, public QtWaylandServer::wl_subsurface
{
public:
static SubSurfaceInterfacePrivate *get(SubSurfaceInterface *subsurface);
SubSurfaceInterfacePrivate(SubSurfaceInterface *q, SurfaceInterface *surface,
SurfaceInterface *parent, ::wl_resource *resource);
void commit() override;
void parentCommit(bool synchronized = false);
void synchronizedCommit();
void commitToCache();
void commitFromCache();
SubSurfaceInterface *q;
QPoint position = QPoint(0, 0);
QPoint pendingPosition = QPoint(0, 0);
SubSurfaceInterface::Mode mode = SubSurfaceInterface::Mode::Synchronized;
QPointer<SurfaceInterface> surface;
QPointer<SurfaceInterface> parent;
bool hasCacheState = false;
bool hasPendingPosition = false;
private:
SubSurfaceInterface *q_func() {
return reinterpret_cast<SubSurfaceInterface *>(q);
}
void setMode(Mode mode);
void setPosition(const QPoint &pos);
void placeAbove(SurfaceInterface *sibling);
void placeBelow(SurfaceInterface *sibling);
static void setPositionCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y);
static void placeAboveCallback(wl_client *client, wl_resource *resource, wl_resource *sibling);
static void placeBelowCallback(wl_client *client, wl_resource *resource, wl_resource *sibling);
static void setSyncCallback(wl_client *client, wl_resource *resource);
static void setDeSyncCallback(wl_client *client, wl_resource *resource);
static const struct wl_subsurface_interface s_interface;
protected:
void subsurface_destroy_resource(Resource *resource) override;
void subsurface_destroy(Resource *resource) override;
void subsurface_set_position(Resource *resource, int32_t x, int32_t y) override;
void subsurface_place_above(Resource *resource, struct ::wl_resource *sibling_resource) override;
void subsurface_place_below(Resource *resource, struct ::wl_resource *sibling_resource) override;
void subsurface_set_sync(Resource *resource) override;
void subsurface_set_desync(Resource *resource) override;
};
}
#endif
} // namespace KWaylandServer
......@@ -76,7 +76,7 @@ SurfaceInterfacePrivate::~SurfaceInterfacePrivate()
surfaces.removeOne(q);
}
void SurfaceInterfacePrivate::addChild(QPointer<SubSurfaceInterface> child)
void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child)
{
// protocol is not precise on how to handle the addition of new sub surfaces
pending.children.append(child);
......@@ -84,13 +84,13 @@ void SurfaceInterfacePrivate::addChild(QPointer<SubSurfaceInterface> child)
current.children.append(child);
emit q->childSubSurfaceAdded(child);
emit q->subSurfaceTreeChanged();
QObject::connect(child.data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child->surface().data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child->surface().data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child->surface().data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child, &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child->surface(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child->surface(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::connect(child->surface(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
}
void SurfaceInterfacePrivate::removeChild(QPointer<SubSurfaceInterface> child)
void SurfaceInterfacePrivate::removeChild(SubSurfaceInterface *child)
{
// protocol is not precise on how to handle the addition of new sub surfaces
pending.children.removeAll(child);
......@@ -98,15 +98,15 @@ void SurfaceInterfacePrivate::removeChild(QPointer<SubSurfaceInterface> child)
current.children.removeAll(child);
emit q->childSubSurfaceRemoved(child);
emit q->subSurfaceTreeChanged();
QObject::disconnect(child.data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
if (!child->surface().isNull()) {
QObject::disconnect(child->surface().data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::disconnect(child->surface().data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::disconnect(child->surface().data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::disconnect(child, &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
if (child->surface()) {
QObject::disconnect(child->surface(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::disconnect(child->surface(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged);
QObject::disconnect(child->surface(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged);
}
}
bool SurfaceInterfacePrivate::raiseChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling)
bool SurfaceInterfacePrivate::raiseChild(SubSurfaceInterface *subsurface, SurfaceInterface *sibling)
{
auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
if (it == pending.children.end()) {
......@@ -141,7 +141,7 @@ bool SurfaceInterfacePrivate::raiseChild(QPointer<SubSurfaceInterface> subsurfac
return true;
}
bool SurfaceInterfacePrivate::lowerChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling)
bool SurfaceInterfacePrivate::lowerChild(SubSurfaceInterface *subsurface, SurfaceInterface *sibling)
{
auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
if (it == pending.children.end()) {
......@@ -423,11 +423,7 @@ void SurfaceInterface::frameRendered(quint32 msec)
frameCallback->destroy();
}
for (auto it = d->current.children.constBegin(); it != d->current.children.constEnd(); ++it) {
const auto &subSurface = *it;
if (subSurface.isNull() || subSurface->d_func()->surface.isNull()) {
continue;
}
subSurface->d_func()->surface->frameRendered(msec);
(*it)->surface()->frameRendered(msec);
}
if (needsFlush) {
client()->flush();
......@@ -684,43 +680,22 @@ void SurfaceInterfacePrivate::swapStates(State *source, State *target, bool emit
void SurfaceInterfacePrivate::commit()
{
if (!subSurface.isNull() && subSurface->isSynchronized()) {
swapStates(&pending, &cached, false);
} else {
if (!subSurface) {
swapStates(&pending, &current, true);
if (!subSurface.isNull()) {
subSurface->d_func()->commit();
}
// commit all subSurfaces to apply position changes
// "The cached state is applied to the sub-surface immediately after the parent surface's state is applied"
for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
const auto &subSurface = *it;
if (subSurface.isNull()) {
continue;
}
subSurface->d_func()->commit();
// The position of a sub-surface is applied when its parent is committed.
const QList<SubSurfaceInterface *> children = current.children;
for (SubSurfaceInterface *subsurface : children) {
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit();
}
}
if (role) {
role->commit();
}
emit q->committed();
}
void SurfaceInterfacePrivate::commitSubSurface()
{
if (subSurface.isNull() || !subSurface->isSynchronized()) {
return;
}
swapStates(&cached, &current, true);
// "The cached state is applied to the sub-surface immediately after the parent surface's state is applied"
for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
const auto &subSurface = *it;
if (subSurface.isNull() || !subSurface->isSynchronized()) {
continue;
}
subSurface->d_func()->commit();
}
emit q->committed();
}
QRegion SurfaceInterface::damage() const
......@@ -777,12 +752,12 @@ SurfaceInterface *SurfaceInterface::get(quint32 id, const ClientConnection *clie
return nullptr;
}
QList< QPointer< SubSurfaceInterface > > SurfaceInterface::childSubSurfaces() const
QList<SubSurfaceInterface *> SurfaceInterface::childSubSurfaces() const
{
return d->current.children;
}
QPointer< SubSurfaceInterface > SurfaceInterface::subSurface() const
SubSurfaceInterface *SurfaceInterface::subSurface() const
{
return d->subSurface;
}
......@@ -796,7 +771,7 @@ QRect SurfaceInterface::boundingRect() const
{
QRect rect(QPoint(0, 0), size());
const QList<QPointer<SubSurfaceInterface>> subSurfaces = childSubSurfaces();
const QList<SubSurfaceInterface *> subSurfaces = childSubSurfaces();
for (const SubSurfaceInterface *subSurface : subSurfaces) {
const SurfaceInterface *childSurface = subSurface->surface();
rect |= childSurface->boundingRect().translated(subSurface->position());
......@@ -830,7 +805,7 @@ bool SurfaceInterface::isMapped() const
if (d->subSurface) {
// from spec:
// "A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and the parent surface is mapped."
return d->subSurfaceIsMapped && !d->subSurface->parentSurface().isNull() && d->subSurface->parentSurface()->isMapped();
return d->subSurfaceIsMapped && d->subSurface->parentSurface() && d->subSurface->parentSurface()->isMapped();
}
return d->current.buffer != nullptr;
}
......@@ -892,14 +867,11 @@ SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position)
return nullptr;
}
// go from top to bottom. Top most child is last in list
QListIterator<QPointer<SubSurfaceInterface>> it(d->current.children);
QListIterator<SubSurfaceInterface *> it(d->current.children);
it.toBack();
while (it.hasPrevious()) {
const auto &current = it.previous();
auto surface = current->surface();
if (surface.isNull()) {
continue;
}
if (auto s = surface->surfaceAt(position - current->position())) {
return s;
}
......@@ -919,14 +891,11 @@ SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position)
return nullptr;
}
// go from top to bottom. Top most child is last in list
QListIterator<QPointer<SubSurfaceInterface>> it(d->current.children);
QListIterator<SubSurfaceInterface *> it(d->current.children);
it.toBack();
while (it.hasPrevious()) {
const auto &current = it.previous();
auto surface = current->surface();
if (surface.isNull()) {
continue;
}
if (auto s = surface->inputSurfaceAt(position - current->position())) {
return s;
}
......
......@@ -202,11 +202,11 @@ public:
/**
* @returns The SubSurface for this Surface in case there is one.
**/
QPointer<SubSurfaceInterface> subSurface() const;
SubSurfaceInterface *subSurface() const;
/**
* @returns Children in stacking order from bottom (first) to top (last).
**/
QList<QPointer<SubSurfaceInterface>> childSubSurfaces() const;
QList<SubSurfaceInterface *> childSubSurfaces() const;
/**
* @returns The Shadow for this Surface.
......
......@@ -64,7 +64,7 @@ public:
QPoint offset = QPoint();
BufferInterface *buffer = nullptr;
// stacking order: bottom (first) -> top (last)
QList<QPointer<SubSurfaceInterface>> children;
QList<SubSurfaceInterface *> children;
QPointer<ShadowInterface> shadow;
QPointer<BlurInterface> blur;
QPointer<ContrastInterface> contrast;
......@@ -76,10 +76,10 @@ public:
explicit SurfaceInterfacePrivate(SurfaceInterface *q);
~SurfaceInterfacePrivate() override;
void addChild(QPointer<SubSurfaceInterface> subsurface);
void removeChild(QPointer<SubSurfaceInterface> subsurface);
bool raiseChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling);
bool lowerChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling);
void addChild(SubSurfaceInterface *subsurface);
void removeChild(SubSurfaceInterface *subsurface);
bool raiseChild(SubSurfaceInterface *subsurface, SurfaceInterface *sibling);
bool lowerChild(SubSurfaceInterface *subsurface, SurfaceInterface *sibling);
void setShadow(const QPointer<ShadowInterface> &shadow);
void setBlur(const QPointer<BlurInterface> &blur);
void setContrast(const QPointer<ContrastInterface> &contrast);
......@@ -88,9 +88,9 @@ public:
void installPointerConstraint(ConfinedPointerInterface *confinement);
void installIdleInhibitor(IdleInhibitorV1Interface *inhibitor);
void commitSubSurface();
void commit();
QMatrix4x4 buildSurfaceToBufferMatrix(const State *state);
void swapStates(State *source, State *target, bool emitChanged);
CompositorInterface *compositor;
SurfaceInterface *q;
......@@ -99,7 +99,7 @@ public:
State current;
State pending;
State cached;
QPointer<SubSurfaceInterface> subSurface;
SubSurfaceInterface *subSurface = nullptr;
QRegion trackedDamage;
QMatrix4x4 surfaceToBufferMatrix;
QMatrix4x4 bufferToSurfaceMatrix;
......@@ -139,8 +139,6 @@ protected:
void surface_damage_buffer(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override;
private:
void swapStates(State *source, State *target, bool emitChanged);
QMetaObject::Connection constrainsOneShotConnection;
QMetaObject::Connection constrainsUnboundConnection;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment