Add XDG Output Protocol
Summary: Done primarily for XWayland which for legacy reasons doesn't assume the logical size of a display is pixelSize / outputScale. Meaning xwayland windows that position themselves are wrong in a scaled environment. It also allows the possibility for us to support fractional scaling whilst keeping wl_output::scale as an integer. The protocol is a bit odd as it operates via the FooManager + Foo pattern rather than using globals like Output so I've wrapped it so it behaves more like globals. Test Plan: #plasma Reviewers: romangg Subscribers: #frameworks Tags: #frameworks Maniphest Tasks: T8501 Differential Revision: https://phabricator.kde.org/D12235
This commit is contained in:
parent
8da9a184ed
commit
b2f7c6ea02
8 changed files with 641 additions and 0 deletions
|
@ -54,6 +54,7 @@ set(SERVER_LIB_SRCS
|
||||||
xdgforeign_v2_interface.cpp
|
xdgforeign_v2_interface.cpp
|
||||||
xdgforeign_interface.cpp
|
xdgforeign_interface.cpp
|
||||||
xdgshell_v6_interface.cpp
|
xdgshell_v6_interface.cpp
|
||||||
|
xdgoutput_interface.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
|
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
|
||||||
|
@ -180,6 +181,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
|
||||||
BASENAME remote-access
|
BASENAME remote-access
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
|
||||||
|
PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-output-unstable-v1.xml
|
||||||
|
BASENAME xdg-output
|
||||||
|
)
|
||||||
|
|
||||||
set(SERVER_GENERATED_SRCS
|
set(SERVER_GENERATED_SRCS
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-client-protocol.h
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-client-protocol.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-server-protocol.h
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-server-protocol.h
|
||||||
|
@ -227,6 +233,8 @@ set(SERVER_GENERATED_SRCS
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-foreign-unstable-v2-server-protocol.h
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-foreign-unstable-v2-server-protocol.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-client-protocol.h
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-client-protocol.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-server-protocol.h
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-server-protocol.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-unstable-v1-client-protocol.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-unstable-v1-server-protocol.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(${SERVER_GENERATED_SRCS} PROPERTIES SKIP_AUTOMOC ON)
|
set_source_files_properties(${SERVER_GENERATED_SRCS} PROPERTIES SKIP_AUTOMOC ON)
|
||||||
|
@ -306,6 +314,7 @@ set(SERVER_LIB_HEADERS
|
||||||
touch_interface.h
|
touch_interface.h
|
||||||
xdgshell_interface.h
|
xdgshell_interface.h
|
||||||
xdgforeign_interface.h
|
xdgforeign_interface.h
|
||||||
|
xdgoutput_interface.h
|
||||||
)
|
)
|
||||||
|
|
||||||
install(FILES
|
install(FILES
|
||||||
|
|
|
@ -429,3 +429,14 @@ add_executable(testRemoteAccess ${testRemoteAccess_SRCS})
|
||||||
target_link_libraries( testRemoteAccess Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer)
|
target_link_libraries( testRemoteAccess Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer)
|
||||||
add_test(NAME kwayland-testRemoteAccess COMMAND testRemoteAccess)
|
add_test(NAME kwayland-testRemoteAccess COMMAND testRemoteAccess)
|
||||||
ecm_mark_as_test(testRemoteAccess)
|
ecm_mark_as_test(testRemoteAccess)
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Test XDG Output
|
||||||
|
########################################################
|
||||||
|
set( testXdgOutput_SRCS
|
||||||
|
test_xdg_output.cpp
|
||||||
|
)
|
||||||
|
add_executable(testXdgOutput ${testXdgOutput_SRCS})
|
||||||
|
target_link_libraries( testXdgOutput Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer Wayland::Client Wayland::Server)
|
||||||
|
add_test(NAME kwayland-testXdgOutput COMMAND testXdgOutput)
|
||||||
|
ecm_mark_as_test(testXdgOutput)
|
||||||
|
|
174
src/wayland/autotests/client/test_xdg_output.cpp
Normal file
174
src/wayland/autotests/client/test_xdg_output.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/********************************************************************
|
||||||
|
Copyright 2018 David Edmundson <davidedmundson@kde.org>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
// Qt
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
// KWin
|
||||||
|
#include "../../src/client/connection_thread.h"
|
||||||
|
#include "../../src/client/event_queue.h"
|
||||||
|
#include "../../src/client/dpms.h"
|
||||||
|
#include "../../src/client/output.h"
|
||||||
|
#include "../../src/client/xdgoutput.h"
|
||||||
|
#include "../../src/client/registry.h"
|
||||||
|
#include "../../src/server/display.h"
|
||||||
|
#include "../../src/server/dpms_interface.h"
|
||||||
|
#include "../../src/server/output_interface.h"
|
||||||
|
#include "../../src/server/xdgoutput_interface.h"
|
||||||
|
|
||||||
|
// Wayland
|
||||||
|
|
||||||
|
class TestXdgOutput : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TestXdgOutput(QObject *parent = nullptr);
|
||||||
|
private Q_SLOTS:
|
||||||
|
void init();
|
||||||
|
void cleanup();
|
||||||
|
void testChanges();
|
||||||
|
private:
|
||||||
|
KWayland::Server::Display *m_display;
|
||||||
|
KWayland::Server::OutputInterface *m_serverOutput;
|
||||||
|
KWayland::Server::XdgOutputManagerInterface *m_serverXdgOutputManager;
|
||||||
|
KWayland::Server::XdgOutputInterface *m_serverXdgOutput;
|
||||||
|
KWayland::Client::ConnectionThread *m_connection;
|
||||||
|
KWayland::Client::EventQueue *m_queue;
|
||||||
|
QThread *m_thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const QString s_socketName = QStringLiteral("kwin-test-xdg-output-0");
|
||||||
|
|
||||||
|
TestXdgOutput::TestXdgOutput(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_display(nullptr)
|
||||||
|
, m_serverOutput(nullptr)
|
||||||
|
, m_connection(nullptr)
|
||||||
|
, m_thread(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestXdgOutput::init()
|
||||||
|
{
|
||||||
|
using namespace KWayland::Server;
|
||||||
|
delete m_display;
|
||||||
|
m_display = new Display(this);
|
||||||
|
m_display->setSocketName(s_socketName);
|
||||||
|
m_display->start();
|
||||||
|
QVERIFY(m_display->isRunning());
|
||||||
|
|
||||||
|
m_serverOutput = m_display->createOutput(this);
|
||||||
|
m_serverOutput->addMode(QSize(1920, 1080), OutputInterface::ModeFlags(OutputInterface::ModeFlag::Preferred));
|
||||||
|
m_serverOutput->setCurrentMode(QSize(1920, 1080));
|
||||||
|
m_serverOutput->create();
|
||||||
|
|
||||||
|
m_serverXdgOutputManager = m_display->createXdgOutputManager(this);
|
||||||
|
m_serverXdgOutputManager->create();
|
||||||
|
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->done();
|
||||||
|
|
||||||
|
// setup connection
|
||||||
|
m_connection = new KWayland::Client::ConnectionThread;
|
||||||
|
QSignalSpy connectedSpy(m_connection, SIGNAL(connected()));
|
||||||
|
m_connection->setSocketName(s_socketName);
|
||||||
|
|
||||||
|
m_thread = new QThread(this);
|
||||||
|
m_connection->moveToThread(m_thread);
|
||||||
|
m_thread->start();
|
||||||
|
|
||||||
|
m_connection->initConnection();
|
||||||
|
QVERIFY(connectedSpy.wait());
|
||||||
|
|
||||||
|
m_queue = new KWayland::Client::EventQueue(this);
|
||||||
|
QVERIFY(!m_queue->isValid());
|
||||||
|
m_queue->setup(m_connection);
|
||||||
|
QVERIFY(m_queue->isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestXdgOutput::cleanup()
|
||||||
|
{
|
||||||
|
if (m_queue) {
|
||||||
|
delete m_queue;
|
||||||
|
m_queue = nullptr;
|
||||||
|
}
|
||||||
|
if (m_thread) {
|
||||||
|
m_thread->quit();
|
||||||
|
m_thread->wait();
|
||||||
|
delete m_thread;
|
||||||
|
m_thread = nullptr;
|
||||||
|
}
|
||||||
|
delete m_connection;
|
||||||
|
m_connection = nullptr;
|
||||||
|
|
||||||
|
delete m_serverOutput;
|
||||||
|
m_serverOutput = nullptr;
|
||||||
|
|
||||||
|
delete m_display;
|
||||||
|
m_display = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestXdgOutput::testChanges()
|
||||||
|
{
|
||||||
|
// verify the server modes
|
||||||
|
using namespace KWayland::Server;
|
||||||
|
using namespace KWayland::Client;
|
||||||
|
KWayland::Client::Registry registry;
|
||||||
|
QSignalSpy announced(®istry, SIGNAL(outputAnnounced(quint32,quint32)));
|
||||||
|
QSignalSpy xdgOutputAnnounced(®istry, SIGNAL(xdgOutputAnnounced(quint32,quint32)));
|
||||||
|
|
||||||
|
registry.setEventQueue(m_queue);
|
||||||
|
registry.create(m_connection->display());
|
||||||
|
QVERIFY(registry.isValid());
|
||||||
|
registry.setup();
|
||||||
|
QVERIFY(announced.wait());
|
||||||
|
if (xdgOutputAnnounced.count() != 1) {
|
||||||
|
QVERIFY(xdgOutputAnnounced.wait());
|
||||||
|
}
|
||||||
|
|
||||||
|
KWayland::Client::Output output;
|
||||||
|
QSignalSpy outputChanged(&output, SIGNAL(changed()));
|
||||||
|
|
||||||
|
output.setup(registry.bindOutput(announced.first().first().value<quint32>(), announced.first().last().value<quint32>()));
|
||||||
|
QVERIFY(outputChanged.wait());
|
||||||
|
|
||||||
|
QScopedPointer<KWayland::Client::XdgOutputManager> xdgOutputManager(registry.createXdgOutputManager(xdgOutputAnnounced.first().first().value<quint32>(), xdgOutputAnnounced.first().last().value<quint32>(), this));
|
||||||
|
|
||||||
|
QScopedPointer<KWayland::Client::XdgOutput> xdgOutput(xdgOutputManager->getXdgOutput(&output, this));
|
||||||
|
QSignalSpy xdgOutputChanged(xdgOutput.data(), SIGNAL(changed()));
|
||||||
|
|
||||||
|
//check details are sent on client bind
|
||||||
|
QVERIFY(xdgOutputChanged.wait());
|
||||||
|
xdgOutputChanged.clear();
|
||||||
|
QCOMPARE(xdgOutput->logicalPosition(), QPoint(11,12));
|
||||||
|
QCOMPARE(xdgOutput->logicalSize(), QSize(1280,720));
|
||||||
|
|
||||||
|
//dynamic updates
|
||||||
|
m_serverXdgOutput->setLogicalPosition(QPoint(1000, 2000));
|
||||||
|
m_serverXdgOutput->setLogicalSize(QSize(100,200));
|
||||||
|
m_serverXdgOutput->done();
|
||||||
|
|
||||||
|
QVERIFY(xdgOutputChanged.wait());
|
||||||
|
QCOMPARE(xdgOutputChanged.count(), 1);
|
||||||
|
QCOMPARE(xdgOutput->logicalPosition(), QPoint(1000, 2000));
|
||||||
|
QCOMPARE(xdgOutput->logicalSize(), QSize(100,200));
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(TestXdgOutput)
|
||||||
|
#include "test_xdg_output.moc"
|
|
@ -50,6 +50,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "xdgshell_v6_interface_p.h"
|
#include "xdgshell_v6_interface_p.h"
|
||||||
#include "appmenu_interface.h"
|
#include "appmenu_interface.h"
|
||||||
#include "server_decoration_palette_interface.h"
|
#include "server_decoration_palette_interface.h"
|
||||||
|
#include "xdgoutput_interface.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
@ -457,6 +458,13 @@ ServerSideDecorationPaletteManagerInterface *Display::createServerSideDecoration
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XdgOutputManagerInterface *Display::createXdgOutputManager(QObject *parent)
|
||||||
|
{
|
||||||
|
auto b = new XdgOutputManagerInterface(this, parent);
|
||||||
|
connect(this, &Display::aboutToTerminate, b, [this, b] { delete b; });
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
void Display::createShm()
|
void Display::createShm()
|
||||||
{
|
{
|
||||||
Q_ASSERT(d->display);
|
Q_ASSERT(d->display);
|
||||||
|
|
|
@ -86,6 +86,7 @@ class PointerConstraintsInterface;
|
||||||
class XdgForeignInterface;
|
class XdgForeignInterface;
|
||||||
class AppMenuManagerInterface;
|
class AppMenuManagerInterface;
|
||||||
class ServerSideDecorationPaletteManagerInterface;
|
class ServerSideDecorationPaletteManagerInterface;
|
||||||
|
class XdgOutputManagerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class holding the Wayland server display loop.
|
* @brief Class holding the Wayland server display loop.
|
||||||
|
@ -258,6 +259,14 @@ public:
|
||||||
**/
|
**/
|
||||||
ServerSideDecorationPaletteManagerInterface *createServerSideDecorationPaletteManager(QObject *parent = nullptr);
|
ServerSideDecorationPaletteManagerInterface *createServerSideDecorationPaletteManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the XdgOutputManagerInterface
|
||||||
|
*
|
||||||
|
* @return the created manager
|
||||||
|
* @since 5.XDGOUTPUTVERSION
|
||||||
|
*/
|
||||||
|
XdgOutputManagerInterface *createXdgOutputManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ClientConnection for the given @p client.
|
* Gets the ClientConnection for the given @p client.
|
||||||
|
|
307
src/wayland/server/xdgoutput_interface.cpp
Normal file
307
src/wayland/server/xdgoutput_interface.cpp
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright 2018 David Edmundson <kde@davidedmundson.co.uk>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "xdgoutput_interface.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "global_p.h"
|
||||||
|
#include "resource_p.h"
|
||||||
|
#include "output_interface.h"
|
||||||
|
|
||||||
|
#include <wayland-xdg-output-server-protocol.h>
|
||||||
|
|
||||||
|
namespace KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
|
||||||
|
class XdgOutputManagerInterface::Private : public Global::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Private(XdgOutputManagerInterface *q, Display *d);
|
||||||
|
QHash<OutputInterface*, XdgOutputInterface*> outputs;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void bind(wl_client *client, uint32_t version, uint32_t id) override;
|
||||||
|
|
||||||
|
static void unbind(wl_resource *resource);
|
||||||
|
static Private *cast(wl_resource *r) {
|
||||||
|
return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroyCallback(wl_client *client, wl_resource *resource);
|
||||||
|
static void getXdgOutputCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * output);
|
||||||
|
|
||||||
|
XdgOutputManagerInterface *q;
|
||||||
|
static const struct zxdg_output_manager_v1_interface s_interface;
|
||||||
|
static const quint32 s_version;
|
||||||
|
};
|
||||||
|
|
||||||
|
const quint32 XdgOutputManagerInterface::Private::s_version = 1;
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
const struct zxdg_output_manager_v1_interface XdgOutputManagerInterface::Private::s_interface = {
|
||||||
|
destroyCallback,
|
||||||
|
getXdgOutputCallback
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class XdgOutputV1Interface: public Resource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XdgOutputV1Interface(XdgOutputManagerInterface *parent, wl_resource *parentResource);
|
||||||
|
~XdgOutputV1Interface();
|
||||||
|
void setLogicalSize(const QSize &size);
|
||||||
|
void setLogicalPosition(const QPoint &pos);
|
||||||
|
void done();
|
||||||
|
private:
|
||||||
|
class Private;
|
||||||
|
};
|
||||||
|
|
||||||
|
class XdgOutputInterface::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void resourceConnected(XdgOutputV1Interface *resource);
|
||||||
|
void resourceDisconnected(XdgOutputV1Interface *resource);
|
||||||
|
QPoint pos;
|
||||||
|
QSize size;
|
||||||
|
bool doneOnce = false;
|
||||||
|
QList<XdgOutputV1Interface*> resources;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
XdgOutputManagerInterface::XdgOutputManagerInterface(Display *display, QObject *parent)
|
||||||
|
: Global(new XdgOutputManagerInterface::Private(this, display))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgOutputManagerInterface::~XdgOutputManagerInterface()
|
||||||
|
{}
|
||||||
|
|
||||||
|
XdgOutputInterface* XdgOutputManagerInterface::createXdgOutput(OutputInterface *output, QObject *parent)
|
||||||
|
{
|
||||||
|
Q_D();
|
||||||
|
if (!d->outputs.contains(output)) {
|
||||||
|
auto xdgOutput = new XdgOutputInterface(parent);
|
||||||
|
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]() {
|
||||||
|
Q_D();
|
||||||
|
d->outputs.remove(output);
|
||||||
|
});
|
||||||
|
connect(xdgOutput, &QObject::destroyed, this, [this, output]() {
|
||||||
|
Q_D();
|
||||||
|
d->outputs.remove(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
return d->outputs[output];
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgOutputManagerInterface::Private* XdgOutputManagerInterface::d_func() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Private*>(d.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputManagerInterface::Private::destroyCallback(wl_client *client, wl_resource *resource)
|
||||||
|
{
|
||||||
|
Q_UNUSED(client)
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputManagerInterface::Private::getXdgOutputCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * outputResource)
|
||||||
|
{
|
||||||
|
auto d = cast(resource);
|
||||||
|
auto output = OutputInterface::get(outputResource);
|
||||||
|
if (!output) { // output client is requesting XdgOutput for an Output that doesn't exist
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!d->outputs.contains(output)) {
|
||||||
|
return; //server hasn't created an XdgOutput for this output yet, give the client nothing
|
||||||
|
}
|
||||||
|
auto iface = new XdgOutputV1Interface(d->q, resource);
|
||||||
|
iface->create(d->display->getConnection(client), wl_resource_get_version(resource), id);
|
||||||
|
if (!iface->resource()) {
|
||||||
|
wl_resource_post_no_memory(resource);
|
||||||
|
delete iface;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto xdgOutput = d->outputs[output];
|
||||||
|
xdgOutput->d->resourceConnected(iface);
|
||||||
|
connect(iface, &XdgOutputV1Interface::unbound, xdgOutput, [xdgOutput, iface]() {
|
||||||
|
xdgOutput->d->resourceDisconnected(iface);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgOutputManagerInterface::Private::Private(XdgOutputManagerInterface *q, Display *d)
|
||||||
|
: Global::Private(d, &zxdg_output_manager_v1_interface, s_version)
|
||||||
|
, q(q)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
|
||||||
|
{
|
||||||
|
auto c = display->getConnection(client);
|
||||||
|
wl_resource *resource = c->createResource(&zxdg_output_manager_v1_interface, qMin(version, s_version), id);
|
||||||
|
if (!resource) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_resource_set_implementation(resource, &s_interface, this, unbind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputManagerInterface::Private::unbind(wl_resource *resource)
|
||||||
|
{
|
||||||
|
Q_UNUSED(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgOutputInterface::XdgOutputInterface(QObject *parent):
|
||||||
|
QObject(parent),
|
||||||
|
d(new XdgOutputInterface::Private)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgOutputInterface::~XdgOutputInterface()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void XdgOutputInterface::setLogicalSize(const QSize &size)
|
||||||
|
{
|
||||||
|
if (size == d->size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->size = size;
|
||||||
|
for(auto resource: d->resources) {
|
||||||
|
resource->setLogicalSize(size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize XdgOutputInterface::logicalSize() const
|
||||||
|
{
|
||||||
|
return d->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputInterface::setLogicalPosition(const QPoint &pos)
|
||||||
|
{
|
||||||
|
if (pos == d->pos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->pos = pos;
|
||||||
|
for(auto resource: d->resources) {
|
||||||
|
resource->setLogicalPosition(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint XdgOutputInterface::logicalPosition() const
|
||||||
|
{
|
||||||
|
return d->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputInterface::done()
|
||||||
|
{
|
||||||
|
d->doneOnce = true;
|
||||||
|
for(auto resource: d->resources) {
|
||||||
|
resource->done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputInterface::Private::resourceConnected(XdgOutputV1Interface *resource)
|
||||||
|
{
|
||||||
|
resource->setLogicalPosition(pos);
|
||||||
|
resource->setLogicalSize(size);
|
||||||
|
if (doneOnce) {
|
||||||
|
resource->done();
|
||||||
|
}
|
||||||
|
resources << resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputInterface::Private::resourceDisconnected(XdgOutputV1Interface *resource)
|
||||||
|
{
|
||||||
|
resources.removeOne(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class XdgOutputV1Interface::Private : public Resource::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Private(XdgOutputV1Interface *q, XdgOutputManagerInterface *c, wl_resource *parentResource);
|
||||||
|
~Private();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
XdgOutputV1Interface *q_func() {
|
||||||
|
return reinterpret_cast<XdgOutputV1Interface *>(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct zxdg_output_v1_interface s_interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
XdgOutputV1Interface::XdgOutputV1Interface(XdgOutputManagerInterface *parent, wl_resource *parentResource)
|
||||||
|
:Resource(new XdgOutputV1Interface::Private(this, parent, parentResource))
|
||||||
|
{}
|
||||||
|
|
||||||
|
XdgOutputV1Interface::~XdgOutputV1Interface()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void XdgOutputV1Interface::setLogicalSize(const QSize &size)
|
||||||
|
{
|
||||||
|
if (!d->resource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zxdg_output_v1_send_logical_size(d->resource, size.width(), size.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputV1Interface::setLogicalPosition(const QPoint &pos)
|
||||||
|
{
|
||||||
|
if (!d->resource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zxdg_output_v1_send_logical_position(d->resource, pos.x(), pos.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void XdgOutputV1Interface::done()
|
||||||
|
{
|
||||||
|
if (!d->resource) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zxdg_output_v1_send_done(d->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||||
|
const struct zxdg_output_v1_interface XdgOutputV1Interface::Private::s_interface = {
|
||||||
|
resourceDestroyedCallback
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
XdgOutputV1Interface::Private::Private(XdgOutputV1Interface *q, XdgOutputManagerInterface *c, wl_resource *parentResource)
|
||||||
|
: Resource::Private(q, c, parentResource, &zxdg_output_v1_interface, &s_interface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgOutputV1Interface::Private::~Private()
|
||||||
|
{
|
||||||
|
if (resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
resource = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
121
src/wayland/server/xdgoutput_interface.h
Normal file
121
src/wayland/server/xdgoutput_interface.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/****************************************************************************
|
||||||
|
Copyright 2018 David Edmundson <kde@davidedmundson.co.uk>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) version 3, or any
|
||||||
|
later version accepted by the membership of KDE e.V. (or its
|
||||||
|
successor approved by the membership of KDE e.V.), which shall
|
||||||
|
act as a proxy defined in Section 6 of version 3 of the license.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef KWAYLAND_SERVER_XDGOUTPUT_H
|
||||||
|
#define KWAYLAND_SERVER_XDGOUTPUT_H
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <KWayland/Server/kwaylandserver_export.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 KWayland
|
||||||
|
{
|
||||||
|
namespace Server
|
||||||
|
{
|
||||||
|
|
||||||
|
class Display;
|
||||||
|
class OutputInterface;
|
||||||
|
class XdgOutputInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global manager for XdgOutputs
|
||||||
|
* @since 5.XDGOUTPUT
|
||||||
|
*/
|
||||||
|
class KWAYLANDSERVER_EXPORT XdgOutputManagerInterface : public Global
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
virtual ~XdgOutputManagerInterface();
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
XdgOutputInterface* createXdgOutput(OutputInterface *output, QObject *parent);
|
||||||
|
private:
|
||||||
|
explicit XdgOutputManagerInterface(Display *display, QObject *parent = nullptr);
|
||||||
|
friend class Display;
|
||||||
|
class Private;
|
||||||
|
Private *d_func() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @since 5.XDGOUTPUT
|
||||||
|
*/
|
||||||
|
class KWAYLANDSERVER_EXPORT XdgOutputInterface : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
virtual ~XdgOutputInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit changes to all clients
|
||||||
|
*/
|
||||||
|
void done();
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit XdgOutputInterface(QObject *parent);
|
||||||
|
friend class XdgOutputManagerInterface;
|
||||||
|
|
||||||
|
class Private;
|
||||||
|
QScopedPointer<Private> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -62,3 +62,5 @@ zwp_idle_inhibit_manager_v1;IdleInhibitManager
|
||||||
zwp_idle_inhibitor_v1;IdleInhibitor
|
zwp_idle_inhibitor_v1;IdleInhibitor
|
||||||
org_kde_kwin_remote_access_manager;RemoteAccessManager
|
org_kde_kwin_remote_access_manager;RemoteAccessManager
|
||||||
org_kde_kwin_remote_buffer;RemoteBuffer
|
org_kde_kwin_remote_buffer;RemoteBuffer
|
||||||
|
zxdg_output_v1;XdgOutput
|
||||||
|
zxdg_output_manager_v1;XdgOutputManager
|
||||||
|
|
Loading…
Reference in a new issue