wayland: Make XdgOutputV1Interface pull information from Output

This commit is contained in:
Vlad Zahorodnii 2022-10-20 12:15:47 +03:00
parent e9e97e49bf
commit c3f970b3c3
7 changed files with 88 additions and 167 deletions

View file

@ -61,17 +61,16 @@ void TestXdgOutput::init()
m_outputHandle = std::make_unique<FakeOutput>();
m_outputHandle->setMode(QSize(1920, 1080), 60000);
m_outputHandle->moveTo(QPoint(11, 12)); // not a sensible value for one monitor, but works for this test
m_outputHandle->setScale(1.5);
m_outputHandle->setName("testName");
m_outputHandle->setManufacturer("foo");
m_outputHandle->setModel("bar");
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_serverXdgOutput->setLogicalSize(QSize(1280, 720)); // a 1.5 scale factor
m_serverXdgOutput->setLogicalPosition(QPoint(11, 12)); // not a sensible value for one monitor, but works for this test
m_serverXdgOutput->setName("testName");
m_serverXdgOutput->setDescription("testDescription");
m_serverXdgOutput->done();
// setup connection
m_connection = new KWayland::Client::ConnectionThread;
@ -150,20 +149,23 @@ void TestXdgOutput::testChanges()
QCOMPARE(xdgOutput->logicalPosition(), QPoint(11, 12));
QCOMPARE(xdgOutput->logicalSize(), QSize(1280, 720));
QCOMPARE(xdgOutput->name(), "testName");
QCOMPARE(xdgOutput->description(), "testDescription");
// dynamic updates
m_serverXdgOutput->setLogicalPosition(QPoint(1000, 2000));
m_serverXdgOutput->setLogicalSize(QSize(100, 200));
// names cannot dynamically change according to the spec
m_serverXdgOutput->done();
m_serverOutput->scheduleDone();
QCOMPARE(xdgOutput->description(), "foo bar");
// change the logical position
m_outputHandle->moveTo(QPoint(1000, 2000));
QVERIFY(xdgOutputChanged.wait());
QCOMPARE(xdgOutputChanged.count(), 1);
QCOMPARE(xdgOutput->logicalPosition(), QPoint(1000, 2000));
QCOMPARE(xdgOutput->logicalSize(), QSize(100, 200));
QEXPECT_FAIL("", "KWayland::Client::XdgOutput incorrectly handles partial updates", Continue);
QCOMPARE(xdgOutput->logicalSize(), QSize(1280, 720));
// change the logical size
m_outputHandle->setScale(2);
QVERIFY(xdgOutputChanged.wait());
QCOMPARE(xdgOutputChanged.count(), 2);
QEXPECT_FAIL("", "KWayland::Client::XdgOutput incorrectly handles partial updates", Continue);
QCOMPARE(xdgOutput->logicalPosition(), QPoint(1000, 2000));
QCOMPARE(xdgOutput->logicalSize(), QSize(960, 540));
}
QTEST_GUILESS_MAIN(TestXdgOutput)

View file

@ -69,3 +69,24 @@ void FakeOutput::setPhysicalSize(QSize size)
.physicalSize = size,
});
}
void FakeOutput::setName(const QString &name)
{
Information info = m_information;
info.name = name;
setInformation(info);
}
void FakeOutput::setManufacturer(const QString &manufacturer)
{
Information info = m_information;
info.manufacturer = manufacturer;
setInformation(info);
}
void FakeOutput::setModel(const QString &model)
{
Information info = m_information;
info.model = model;
setInformation(info);
}

View file

@ -18,6 +18,9 @@ public:
FakeOutput();
KWin::RenderLoop *renderLoop() const override;
void setName(const QString &name);
void setManufacturer(const QString &manufacturer);
void setModel(const QString &model);
void setMode(QSize size, uint32_t refreshRate);
void setSubPixel(SubPixel subPixel);
void setDpmsSupported(bool supported);

View file

@ -10,10 +10,14 @@
#include "qwayland-server-xdg-output-unstable-v1.h"
#include "core/output.h"
#include <QDebug>
#include <QHash>
#include <QPointer>
using namespace KWin;
namespace KWaylandServer
{
static const quint32 s_version = 3;
@ -44,14 +48,11 @@ public:
QSize size;
QString name;
QString description;
bool dirty = false;
bool doneOnce = false;
QPointer<OutputInterface> output;
XdgOutputV1Interface *const q;
void sendLogicalPosition(Resource *resource, const QPoint &position);
void sendLogicalSize(Resource *resource, const QSize &size);
void sendLogicalPosition(Resource *resource);
void sendLogicalSize(Resource *resource);
void sendDone(Resource *resource);
protected:
@ -116,76 +117,50 @@ XdgOutputV1Interface::XdgOutputV1Interface(OutputInterface *output, QObject *par
: QObject(parent)
, d(new XdgOutputV1InterfacePrivate(this, output))
{
const Output *handle = output->handle();
d->name = handle->name();
d->description = handle->description();
d->pos = handle->geometry().topLeft();
d->size = handle->geometry().size();
connect(handle, &Output::geometryChanged, this, &XdgOutputV1Interface::update);
}
XdgOutputV1Interface::~XdgOutputV1Interface()
{
}
void XdgOutputV1Interface::setLogicalSize(const QSize &size)
void XdgOutputV1Interface::update()
{
if (size == d->size) {
if (!d->output || d->output->isRemoved()) {
return;
}
d->size = size;
d->dirty = true;
const auto outputResources = d->resourceMap();
for (auto resource : outputResources) {
d->sendLogicalSize(resource, size);
const QRect geometry = d->output->handle()->geometry();
const auto resources = d->resourceMap();
if (d->pos != geometry.topLeft()) {
d->pos = geometry.topLeft();
for (auto resource : resources) {
d->sendLogicalPosition(resource);
}
}
}
QSize XdgOutputV1Interface::logicalSize() const
{
return d->size;
}
void XdgOutputV1Interface::setLogicalPosition(const QPoint &pos)
{
if (pos == d->pos) {
return;
if (d->size != geometry.size()) {
d->size = geometry.size();
for (auto resource : resources) {
d->sendLogicalSize(resource);
}
}
d->pos = pos;
d->dirty = true;
const auto outputResources = d->resourceMap();
for (auto resource : outputResources) {
d->sendLogicalPosition(resource, pos);
}
}
QPoint XdgOutputV1Interface::logicalPosition() const
{
return d->pos;
}
void XdgOutputV1Interface::setName(const QString &name)
{
d->name = name;
// this can only be set once before the client connects
}
void XdgOutputV1Interface::setDescription(const QString &description)
{
d->description = description;
// this can only be set once before the client connects
}
void XdgOutputV1Interface::done()
{
d->doneOnce = true;
if (!d->dirty) {
return;
}
d->dirty = false;
const auto outputResources = d->resourceMap();
for (auto resource : outputResources) {
for (auto resource : resources) {
if (wl_resource_get_version(resource->handle) < 3) {
d->send_done(resource->handle);
}
}
d->output->scheduleDone();
}
void XdgOutputV1InterfacePrivate::zxdg_output_v1_destroy(Resource *resource)
@ -199,8 +174,8 @@ void XdgOutputV1InterfacePrivate::zxdg_output_v1_bind_resource(Resource *resourc
return;
}
sendLogicalPosition(resource, pos);
sendLogicalSize(resource, size);
sendLogicalPosition(resource);
sendLogicalSize(resource);
if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
send_name(resource->handle, name);
}
@ -211,25 +186,19 @@ 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::sendRefresh, Qt::UniqueConnection);
QObject::connect(connection, &ClientConnection::scaleOverrideChanged, q, &XdgOutputV1Interface::resend, Qt::UniqueConnection);
}
void XdgOutputV1InterfacePrivate::sendLogicalSize(Resource *resource, const QSize &size)
void XdgOutputV1InterfacePrivate::sendLogicalSize(Resource *resource)
{
if (!output || output->isRemoved()) {
return;
}
ClientConnection *connection = output->display()->getConnection(resource->client());
qreal scaleOverride = connection->scaleOverride();
send_logical_size(resource->handle, size.width() * scaleOverride, size.height() * scaleOverride);
}
void XdgOutputV1InterfacePrivate::sendLogicalPosition(Resource *resource, const QPoint &pos)
void XdgOutputV1InterfacePrivate::sendLogicalPosition(Resource *resource)
{
if (!output || output->isRemoved()) {
return;
}
ClientConnection *connection = output->display()->getConnection(resource->client());
qreal scaleOverride = connection->scaleOverride();
@ -238,10 +207,6 @@ void XdgOutputV1InterfacePrivate::sendLogicalPosition(Resource *resource, const
void XdgOutputV1InterfacePrivate::sendDone(Resource *resource)
{
if (!doneOnce || !output || output->isRemoved()) {
return;
}
if (wl_resource_get_version(resource->handle) >= 3) {
output->done(resource->client());
} else {
@ -249,16 +214,19 @@ void XdgOutputV1InterfacePrivate::sendDone(Resource *resource)
}
}
void XdgOutputV1Interface::sendRefresh()
void XdgOutputV1Interface::resend()
{
auto changedConnection = qobject_cast<ClientConnection *>(sender());
if (!d->output || d->output->isRemoved()) {
return;
}
auto changedConnection = qobject_cast<ClientConnection *>(sender());
const auto outputResources = d->resourceMap();
for (auto resource : outputResources) {
ClientConnection *connection = d->output->display()->getConnection(resource->client());
if (connection == changedConnection) {
d->sendLogicalPosition(resource, d->pos);
d->sendLogicalSize(resource, d->size);
d->sendLogicalPosition(resource);
d->sendLogicalSize(resource);
d->sendDone(resource);
}
}

View file

@ -61,58 +61,9 @@ class KWIN_EXPORT XdgOutputV1Interface : public QObject
public:
~XdgOutputV1Interface() override;
/**
* Sets the size of this output in logical co-ordinates.
* Users should call done() after setting all values
*/
void setLogicalSize(const QSize &size);
/**
* Returns the last set logical size on this output
*/
QSize logicalSize() const;
/**
* Sets the topleft position of this output in logical co-ordinates.
* Users should call done() after setting all values
* @see OutputInterface::setPosition
*/
void setLogicalPosition(const QPoint &pos);
/**
* Returns the last set logical position on this output
*/
QPoint logicalPosition() const;
/**
* @brief Sets a short name of the output
* This should be consistent across reboots for the same monitor
* It should be set once before the first done call
*/
void setName(const QString &name);
/**
* The last set name
*/
void name() const;
/**
* @brief Sets a longer description of the output
* This should be consistent across reboots for the same monitor
* It should be set once before the first done call
*/
void setDescription(const QString &description);
/**
* The last set description
*/
void description() const;
/**
* Submit changes to all clients
*/
void done();
private:
void sendRefresh();
void resend();
void update();
explicit XdgOutputV1Interface(OutputInterface *output, QObject *parent);
friend class XdgOutputV1InterfacePrivate;

View file

@ -18,27 +18,6 @@ WaylandOutput::WaylandOutput(Output *output, QObject *parent)
, m_waylandOutput(new KWaylandServer::OutputInterface(waylandServer()->display(), output))
, m_xdgOutputV1(waylandServer()->xdgOutputManagerV1()->createXdgOutput(m_waylandOutput.get(), m_waylandOutput.get()))
{
const QRect geometry = m_platformOutput->geometry();
m_xdgOutputV1->setName(output->name());
m_xdgOutputV1->setDescription(output->description());
m_xdgOutputV1->setLogicalPosition(geometry.topLeft());
m_xdgOutputV1->setLogicalSize(geometry.size());
m_xdgOutputV1->done();
m_waylandOutput->scheduleDone();
connect(output, &Output::geometryChanged, this, &WaylandOutput::update);
}
void WaylandOutput::update()
{
const QRect geometry = m_platformOutput->geometry();
m_xdgOutputV1->setLogicalPosition(geometry.topLeft());
m_xdgOutputV1->setLogicalSize(geometry.size());
m_xdgOutputV1->done();
m_waylandOutput->scheduleDone();
}
} // namespace KWin

View file

@ -21,9 +21,6 @@ class WaylandOutput : public QObject
public:
explicit WaylandOutput(Output *output, QObject *parent = nullptr);
private Q_SLOTS:
void update();
private:
Output *m_platformOutput;
KWaylandServer::ScopedGlobalPointer<KWaylandServer::OutputInterface> m_waylandOutput;