wayland: Hide XdgOutputV1Interface class

With the pull approach, the XdgOutputV1Interface class doesn't have to
be exposed in the public api and can be made private to simplify the
implementation of the xdg-output-v1 protocol.
This commit is contained in:
Vlad Zahorodnii 2022-10-27 13:37:46 +03:00
parent b40d76d35c
commit 0c34957625
4 changed files with 61 additions and 115 deletions

View file

@ -33,7 +33,6 @@ private:
std::unique_ptr<FakeOutput> m_outputHandle;
KWaylandServer::OutputInterface *m_serverOutput;
KWaylandServer::XdgOutputManagerV1Interface *m_serverXdgOutputManager;
KWaylandServer::XdgOutputV1Interface *m_serverXdgOutput;
KWayland::Client::ConnectionThread *m_connection;
KWayland::Client::EventQueue *m_queue;
QThread *m_thread;
@ -70,7 +69,7 @@ void TestXdgOutput::init()
m_serverOutput = new OutputInterface(m_display, m_outputHandle.get(), this);
m_serverXdgOutputManager = new XdgOutputManagerV1Interface(m_display, this);
m_serverXdgOutput = m_serverXdgOutputManager->createXdgOutput(m_serverOutput, this);
m_serverXdgOutputManager->offer(m_serverOutput);
// setup connection
m_connection = new KWayland::Client::ConnectionThread;

View file

@ -22,6 +22,29 @@ namespace KWaylandServer
{
static const quint32 s_version = 3;
class XdgOutputV1Interface : public QObject, public QtWaylandServer::zxdg_output_v1
{
public:
explicit XdgOutputV1Interface(OutputInterface *wlOutput);
void resend();
void update();
QPointF pos;
QSizeF size;
QString name;
QString description;
QPointer<OutputInterface> output;
void sendLogicalPosition(Resource *resource);
void sendLogicalSize(Resource *resource);
void sendDone(Resource *resource);
protected:
void zxdg_output_v1_bind_resource(Resource *resource) override;
void zxdg_output_v1_destroy(Resource *resource) override;
};
class XdgOutputManagerV1InterfacePrivate : public QtWaylandServer::zxdg_output_manager_v1
{
public:
@ -35,31 +58,6 @@ protected:
void zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id, wl_resource *output) override;
};
class XdgOutputV1InterfacePrivate : public QtWaylandServer::zxdg_output_v1
{
public:
XdgOutputV1InterfacePrivate(XdgOutputV1Interface *q, OutputInterface *wlOutput)
: output(wlOutput)
, q(q)
{
}
QPointF pos;
QSizeF size;
QString name;
QString description;
QPointer<OutputInterface> output;
XdgOutputV1Interface *const q;
void sendLogicalPosition(Resource *resource);
void sendLogicalSize(Resource *resource);
void sendDone(Resource *resource);
protected:
void zxdg_output_v1_bind_resource(Resource *resource) override;
void zxdg_output_v1_destroy(Resource *resource) override;
};
XdgOutputManagerV1Interface::XdgOutputManagerV1Interface(Display *display, QObject *parent)
: QObject(parent)
, d(new XdgOutputManagerV1InterfacePrivate(this, display))
@ -70,23 +68,15 @@ XdgOutputManagerV1Interface::~XdgOutputManagerV1Interface()
{
}
XdgOutputV1Interface *XdgOutputManagerV1Interface::createXdgOutput(OutputInterface *output, QObject *parent)
void XdgOutputManagerV1Interface::offer(OutputInterface *output)
{
Q_ASSERT_X(!d->outputs.contains(output), "createXdgOutput", "An XdgOuputInterface already exists for this output");
Q_ASSERT_X(!d->outputs.contains(output), "offer", "An XdgOuputInterface already exists for this output");
auto xdgOutput = new XdgOutputV1Interface(output, parent);
auto xdgOutput = new XdgOutputV1Interface(output);
d->outputs[output] = xdgOutput;
// as XdgOutput lifespan is managed by user, delete our mapping when either
// it or the relevant Output gets deleted
connect(output, &QObject::destroyed, this, [this, output]() {
d->outputs.remove(output);
delete d->outputs.take(output);
});
connect(xdgOutput, &QObject::destroyed, this, [this, output]() {
d->outputs.remove(output);
});
return xdgOutput;
}
XdgOutputManagerV1InterfacePrivate::XdgOutputManagerV1InterfacePrivate(XdgOutputManagerV1Interface *qptr, Display *d)
@ -105,7 +95,7 @@ void XdgOutputManagerV1InterfacePrivate::zxdg_output_manager_v1_get_xdg_output(R
if (!xdgOutput) {
return; // client is requesting XdgOutput for an Output that doesn't exist
}
xdgOutput->d->add(resource->client(), id, resource->version());
xdgOutput->add(resource->client(), id, resource->version());
}
void XdgOutputManagerV1InterfacePrivate::zxdg_output_manager_v1_destroy(Resource *resource)
@ -113,62 +103,57 @@ void XdgOutputManagerV1InterfacePrivate::zxdg_output_manager_v1_destroy(Resource
wl_resource_destroy(resource->handle);
}
XdgOutputV1Interface::XdgOutputV1Interface(OutputInterface *output, QObject *parent)
: QObject(parent)
, d(new XdgOutputV1InterfacePrivate(this, output))
XdgOutputV1Interface::XdgOutputV1Interface(OutputInterface *output)
: output(output)
{
const Output *handle = output->handle();
d->name = handle->name();
d->description = handle->description();
d->pos = handle->geometry().topLeft();
d->size = handle->geometry().size();
name = handle->name();
description = handle->description();
pos = handle->geometry().topLeft();
size = handle->geometry().size();
connect(handle, &Output::geometryChanged, this, &XdgOutputV1Interface::update);
}
XdgOutputV1Interface::~XdgOutputV1Interface()
{
}
void XdgOutputV1Interface::update()
{
if (!d->output || d->output->isRemoved()) {
if (!output || output->isRemoved()) {
return;
}
const QRectF geometry = d->output->handle()->fractionalGeometry();
const auto resources = d->resourceMap();
const QRectF geometry = output->handle()->fractionalGeometry();
const auto resources = resourceMap();
if (d->pos != geometry.topLeft()) {
d->pos = geometry.topLeft();
if (pos != geometry.topLeft()) {
pos = geometry.topLeft();
for (auto resource : resources) {
d->sendLogicalPosition(resource);
sendLogicalPosition(resource);
}
}
if (d->size != geometry.size()) {
d->size = geometry.size();
if (size != geometry.size()) {
size = geometry.size();
for (auto resource : resources) {
d->sendLogicalSize(resource);
sendLogicalSize(resource);
}
}
for (auto resource : resources) {
if (wl_resource_get_version(resource->handle) < 3) {
d->send_done(resource->handle);
send_done(resource->handle);
}
}
d->output->scheduleDone();
output->scheduleDone();
}
void XdgOutputV1InterfacePrivate::zxdg_output_v1_destroy(Resource *resource)
void XdgOutputV1Interface::zxdg_output_v1_destroy(Resource *resource)
{
wl_resource_destroy(resource->handle);
}
void XdgOutputV1InterfacePrivate::zxdg_output_v1_bind_resource(Resource *resource)
void XdgOutputV1Interface::zxdg_output_v1_bind_resource(Resource *resource)
{
if (!output || output->isRemoved()) {
return;
@ -186,10 +171,10 @@ void XdgOutputV1InterfacePrivate::zxdg_output_v1_bind_resource(Resource *resourc
sendDone(resource);
ClientConnection *connection = output->display()->getConnection(resource->client());
QObject::connect(connection, &ClientConnection::scaleOverrideChanged, q, &XdgOutputV1Interface::resend, Qt::UniqueConnection);
connect(connection, &ClientConnection::scaleOverrideChanged, this, &XdgOutputV1Interface::resend, Qt::UniqueConnection);
}
void XdgOutputV1InterfacePrivate::sendLogicalSize(Resource *resource)
void XdgOutputV1Interface::sendLogicalSize(Resource *resource)
{
ClientConnection *connection = output->display()->getConnection(resource->client());
qreal scaleOverride = connection->scaleOverride();
@ -197,7 +182,7 @@ void XdgOutputV1InterfacePrivate::sendLogicalSize(Resource *resource)
send_logical_size(resource->handle, std::round(size.width() * scaleOverride), std::round(size.height() * scaleOverride));
}
void XdgOutputV1InterfacePrivate::sendLogicalPosition(Resource *resource)
void XdgOutputV1Interface::sendLogicalPosition(Resource *resource)
{
ClientConnection *connection = output->display()->getConnection(resource->client());
qreal scaleOverride = connection->scaleOverride();
@ -205,7 +190,7 @@ void XdgOutputV1InterfacePrivate::sendLogicalPosition(Resource *resource)
send_logical_position(resource->handle, pos.x() * scaleOverride, pos.y() * scaleOverride);
}
void XdgOutputV1InterfacePrivate::sendDone(Resource *resource)
void XdgOutputV1Interface::sendDone(Resource *resource)
{
if (wl_resource_get_version(resource->handle) >= 3) {
output->done(resource->client());
@ -216,18 +201,18 @@ void XdgOutputV1InterfacePrivate::sendDone(Resource *resource)
void XdgOutputV1Interface::resend()
{
if (!d->output || d->output->isRemoved()) {
if (!output || output->isRemoved()) {
return;
}
auto changedConnection = qobject_cast<ClientConnection *>(sender());
const auto outputResources = d->resourceMap();
const auto outputResources = resourceMap();
for (auto resource : outputResources) {
ClientConnection *connection = d->output->display()->getConnection(resource->client());
ClientConnection *connection = output->display()->getConnection(resource->client());
if (connection == changedConnection) {
d->sendLogicalPosition(resource);
d->sendLogicalSize(resource);
d->sendDone(resource);
sendLogicalPosition(resource);
sendLogicalSize(resource);
sendDone(resource);
}
}
}

View file

@ -12,20 +12,11 @@
#include <QObject>
#include <memory>
/*
* In terms of protocol XdgOutputInterface are a resource
* but for the sake of sanity, we should treat XdgOutputs as globals like Output is
* Hence this doesn't match most of kwayland API paradigms.
*/
namespace KWaylandServer
{
class Display;
class OutputInterface;
class XdgOutputV1Interface;
class XdgOutputManagerV1InterfacePrivate;
class XdgOutputV1InterfacePrivate;
/**
* Global manager for XdgOutputs
@ -37,42 +28,13 @@ class KWIN_EXPORT XdgOutputManagerV1Interface : public QObject
public:
explicit XdgOutputManagerV1Interface(Display *display, QObject *parent = nullptr);
~XdgOutputManagerV1Interface() override;
/**
* Creates an XdgOutputInterface object for an existing Output
* which exposes XDG specific properties of outputs
*
* @arg output the wl_output interface this XDG output is for
* @parent the parent of the newly created object
*/
XdgOutputV1Interface *createXdgOutput(OutputInterface *output, QObject *parent);
void offer(OutputInterface *output);
private:
std::unique_ptr<XdgOutputManagerV1InterfacePrivate> d;
};
/**
* Extension to Output
* Users should set all relevant values on creation and on future changes.
* done() should be explicitly called after change batches including initial setting.
*/
class KWIN_EXPORT XdgOutputV1Interface : public QObject
{
Q_OBJECT
public:
~XdgOutputV1Interface() override;
private:
void resend();
void update();
explicit XdgOutputV1Interface(OutputInterface *output, QObject *parent);
friend class XdgOutputV1InterfacePrivate;
friend class XdgOutputManagerV1Interface;
friend class XdgOutputManagerV1InterfacePrivate;
std::unique_ptr<XdgOutputV1InterfacePrivate> d;
};
}
#endif

View file

@ -299,7 +299,7 @@ void WaylandServer::handleOutputEnabled(Output *output)
{
if (!output->isPlaceholder() && !output->isNonDesktop()) {
auto waylandOutput = new KWaylandServer::OutputInterface(waylandServer()->display(), output);
m_xdgOutputManagerV1->createXdgOutput(waylandOutput, waylandOutput);
m_xdgOutputManagerV1->offer(waylandOutput);
m_waylandOutputs.insert(output, waylandOutput);
}