2020-03-15 15:19:28 +00:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
|
2014-08-26 14:07:39 +00:00
|
|
|
|
2020-03-15 15:19:28 +00:00
|
|
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
|
|
*/
|
2014-08-26 14:07:39 +00:00
|
|
|
#include "display.h"
|
2021-07-20 17:02:13 +00:00
|
|
|
#include "clientbufferintegration.h"
|
2020-12-09 20:13:19 +00:00
|
|
|
#include "display_p.h"
|
2021-07-20 17:02:13 +00:00
|
|
|
#include "drmclientbuffer.h"
|
2021-06-24 08:20:09 +00:00
|
|
|
#include "output_interface.h"
|
2021-07-20 17:02:13 +00:00
|
|
|
#include "shmclientbuffer.h"
|
2022-04-22 09:27:33 +00:00
|
|
|
#include "utils/common.h"
|
2014-08-26 14:07:39 +00:00
|
|
|
|
2021-06-24 08:20:09 +00:00
|
|
|
#include <QAbstractEventDispatcher>
|
2014-08-26 14:07:39 +00:00
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QDebug>
|
2021-06-24 08:20:09 +00:00
|
|
|
#include <QRect>
|
2015-03-03 08:43:30 +00:00
|
|
|
|
2020-04-29 14:56:38 +00:00
|
|
|
namespace KWaylandServer
|
2014-08-26 14:07:39 +00:00
|
|
|
{
|
2020-12-09 20:13:19 +00:00
|
|
|
DisplayPrivate *DisplayPrivate::get(Display *display)
|
2014-09-18 13:40:22 +00:00
|
|
|
{
|
2022-08-01 21:29:02 +00:00
|
|
|
return display->d.get();
|
2020-12-09 20:13:19 +00:00
|
|
|
}
|
2014-09-18 13:40:22 +00:00
|
|
|
|
2020-12-09 20:13:19 +00:00
|
|
|
DisplayPrivate::DisplayPrivate(Display *q)
|
2014-09-18 13:40:22 +00:00
|
|
|
: q(q)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-12-09 20:13:19 +00:00
|
|
|
void DisplayPrivate::registerSocketName(const QString &socketName)
|
2014-11-07 10:41:37 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
socketNames.append(socketName);
|
2021-05-13 09:33:08 +00:00
|
|
|
Q_EMIT q->socketNamesChanged();
|
2014-11-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
|
2014-08-26 14:07:39 +00:00
|
|
|
Display::Display(QObject *parent)
|
|
|
|
: QObject(parent)
|
2020-12-09 20:13:19 +00:00
|
|
|
, d(new DisplayPrivate(this))
|
2014-08-26 14:07:39 +00:00
|
|
|
{
|
2020-07-06 09:36:25 +00:00
|
|
|
d->display = wl_display_create();
|
2020-10-19 15:52:56 +00:00
|
|
|
d->loop = wl_display_get_event_loop(d->display);
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Display::~Display()
|
|
|
|
{
|
2020-10-30 13:36:24 +00:00
|
|
|
wl_display_destroy_clients(d->display);
|
2020-07-06 09:36:25 +00:00
|
|
|
wl_display_destroy(d->display);
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
|
|
|
|
2021-08-16 16:36:15 +00:00
|
|
|
bool Display::addSocketFileDescriptor(int fileDescriptor, const QString &name)
|
2015-04-21 06:56:19 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
if (wl_display_add_socket_fd(d->display, fileDescriptor)) {
|
2022-04-22 09:27:33 +00:00
|
|
|
qCWarning(KWIN_CORE, "Failed to add %d fd to display", fileDescriptor);
|
2020-10-19 15:52:56 +00:00
|
|
|
return false;
|
2015-04-21 06:56:19 +00:00
|
|
|
}
|
2021-08-16 16:36:15 +00:00
|
|
|
if (!name.isEmpty()) {
|
|
|
|
d->registerSocketName(name);
|
|
|
|
}
|
2020-10-19 15:52:56 +00:00
|
|
|
return true;
|
2015-04-21 06:56:19 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
bool Display::addSocketName(const QString &name)
|
2014-08-26 14:07:39 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
if (name.isEmpty()) {
|
|
|
|
const char *socket = wl_display_add_socket_auto(d->display);
|
|
|
|
if (!socket) {
|
2022-04-22 09:27:33 +00:00
|
|
|
qCWarning(KWIN_CORE, "Failed to find a free display socket");
|
2020-10-19 15:52:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
d->registerSocketName(QString::fromUtf8(socket));
|
|
|
|
} else {
|
|
|
|
if (wl_display_add_socket(d->display, qPrintable(name))) {
|
2022-04-22 09:27:33 +00:00
|
|
|
qCWarning(KWIN_CORE, "Failed to add %s socket to display", qPrintable(name));
|
2020-10-19 15:52:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
d->registerSocketName(name);
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
2020-10-19 15:52:56 +00:00
|
|
|
return true;
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
QStringList Display::socketNames() const
|
2014-08-26 14:07:39 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
return d->socketNames;
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
bool Display::start()
|
2014-08-26 14:07:39 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
if (d->running) {
|
|
|
|
return true;
|
|
|
|
}
|
2014-08-26 14:07:39 +00:00
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
const int fileDescriptor = wl_event_loop_get_fd(d->loop);
|
|
|
|
if (fileDescriptor == -1) {
|
2022-04-22 09:27:33 +00:00
|
|
|
qCWarning(KWIN_CORE) << "Did not get the file descriptor for the event loop";
|
2020-10-19 15:52:56 +00:00
|
|
|
return false;
|
2018-11-23 13:42:18 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
d->socketNotifier = new QSocketNotifier(fileDescriptor, QSocketNotifier::Read, this);
|
|
|
|
connect(d->socketNotifier, &QSocketNotifier::activated, this, &Display::dispatchEvents);
|
2018-11-23 13:42:18 +00:00
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
|
|
|
|
connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &Display::flush);
|
2014-08-26 14:07:39 +00:00
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
d->running = true;
|
2021-05-13 09:33:08 +00:00
|
|
|
Q_EMIT runningChanged(true);
|
2020-07-06 09:36:25 +00:00
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
return true;
|
2014-11-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
void Display::dispatchEvents()
|
2014-11-07 10:41:37 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
if (wl_event_loop_dispatch(d->loop, 0) != 0) {
|
2022-04-22 09:27:33 +00:00
|
|
|
qCWarning(KWIN_CORE) << "Error on dispatching Wayland event loop";
|
2015-05-18 08:27:44 +00:00
|
|
|
}
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:52:56 +00:00
|
|
|
void Display::flush()
|
2014-08-26 14:07:39 +00:00
|
|
|
{
|
2020-10-19 15:52:56 +00:00
|
|
|
wl_display_flush_clients(d->display);
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|
|
|
|
|
2014-08-28 12:22:53 +00:00
|
|
|
void Display::createShm()
|
|
|
|
{
|
2015-02-09 16:13:20 +00:00
|
|
|
Q_ASSERT(d->display);
|
2021-07-20 17:02:13 +00:00
|
|
|
new ShmClientBufferIntegration(this);
|
2014-08-28 12:22:53 +00:00
|
|
|
}
|
|
|
|
|
2014-08-29 09:42:57 +00:00
|
|
|
quint32 Display::nextSerial()
|
|
|
|
{
|
2014-09-18 13:40:22 +00:00
|
|
|
return wl_display_next_serial(d->display);
|
2014-08-29 09:42:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
quint32 Display::serial()
|
|
|
|
{
|
2014-09-18 13:40:22 +00:00
|
|
|
return wl_display_get_serial(d->display);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Display::isRunning() const
|
|
|
|
{
|
|
|
|
return d->running;
|
2014-08-29 09:42:57 +00:00
|
|
|
}
|
|
|
|
|
2021-08-29 05:11:06 +00:00
|
|
|
Display::operator wl_display *()
|
2014-09-18 13:40:22 +00:00
|
|
|
{
|
|
|
|
return d->display;
|
|
|
|
}
|
|
|
|
|
2021-08-29 05:11:06 +00:00
|
|
|
Display::operator wl_display *() const
|
2014-09-18 13:40:22 +00:00
|
|
|
{
|
|
|
|
return d->display;
|
|
|
|
}
|
|
|
|
|
2021-08-29 05:11:06 +00:00
|
|
|
QList<OutputInterface *> Display::outputs() const
|
2014-09-18 13:40:22 +00:00
|
|
|
{
|
|
|
|
return d->outputs;
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:14:26 +00:00
|
|
|
QList<OutputDeviceV2Interface *> Display::outputDevices() const
|
server side of new outputmanagement protocol
This implements the server part of the screen management protocol. The
protocol is implemented as a wayland protocol.
It provides the following mechanisms:
- a list of outputs, close to wl_output, with additional properties for
enabled, uuid, edid, etc.. These OutputDevices correspond to a
connected output that can be enabled by the compositor, but is not
necessarily currently used for rendering.
- a global OutputManagement, which allows creating config objects, one
per client. The client can make changes to the outputs through
setScale(outputdevice*, scale) for example.
- an OutputConfiguration resource, that can be handed to a client and
used for configuration. Changes are double buffered here. Only after
OutputConfiguration.apply() has been called, the changes are relayed
over the global OutputManagement.
The compositor is responsible to handle changes.
For a more detailed description, see the API docs in especially
outputconfiguration.h.
REVIEW:125942
2015-11-04 14:36:52 +00:00
|
|
|
{
|
2021-07-23 14:12:28 +00:00
|
|
|
return d->outputdevicesV2;
|
server side of new outputmanagement protocol
This implements the server part of the screen management protocol. The
protocol is implemented as a wayland protocol.
It provides the following mechanisms:
- a list of outputs, close to wl_output, with additional properties for
enabled, uuid, edid, etc.. These OutputDevices correspond to a
connected output that can be enabled by the compositor, but is not
necessarily currently used for rendering.
- a global OutputManagement, which allows creating config objects, one
per client. The client can make changes to the outputs through
setScale(outputdevice*, scale) for example.
- an OutputConfiguration resource, that can be handed to a client and
used for configuration. Changes are double buffered here. Only after
OutputConfiguration.apply() has been called, the changes are relayed
over the global OutputManagement.
The compositor is responsible to handle changes.
For a more detailed description, see the API docs in especially
outputconfiguration.h.
REVIEW:125942
2015-11-04 14:36:52 +00:00
|
|
|
}
|
|
|
|
|
2021-06-24 08:20:09 +00:00
|
|
|
QVector<OutputInterface *> Display::outputsIntersecting(const QRect &rect) const
|
|
|
|
{
|
|
|
|
QVector<OutputInterface *> outputs;
|
2022-10-31 19:02:23 +00:00
|
|
|
for (auto *output : std::as_const(d->outputs)) {
|
2022-09-27 10:57:10 +00:00
|
|
|
if (output->handle()->geometry().intersects(rect)) {
|
2021-06-24 08:20:09 +00:00
|
|
|
outputs << output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return outputs;
|
|
|
|
}
|
|
|
|
|
2021-08-29 05:11:06 +00:00
|
|
|
QVector<SeatInterface *> Display::seats() const
|
2015-12-15 14:47:19 +00:00
|
|
|
{
|
|
|
|
return d->seats;
|
|
|
|
}
|
|
|
|
|
2014-11-17 15:01:18 +00:00
|
|
|
ClientConnection *Display::getConnection(wl_client *client)
|
|
|
|
{
|
|
|
|
Q_ASSERT(client);
|
2021-08-29 05:11:06 +00:00
|
|
|
auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(), [client](ClientConnection *c) {
|
|
|
|
return c->client() == client;
|
|
|
|
});
|
2014-11-17 15:01:18 +00:00
|
|
|
if (it != d->clients.constEnd()) {
|
|
|
|
return *it;
|
|
|
|
}
|
|
|
|
// no ConnectionData yet, create it
|
|
|
|
auto c = new ClientConnection(client, this);
|
|
|
|
d->clients << c;
|
2021-08-29 05:11:06 +00:00
|
|
|
connect(c, &ClientConnection::disconnected, this, [this](ClientConnection *c) {
|
|
|
|
const int index = d->clients.indexOf(c);
|
|
|
|
Q_ASSERT(index != -1);
|
|
|
|
d->clients.remove(index);
|
|
|
|
Q_ASSERT(d->clients.indexOf(c) == -1);
|
|
|
|
Q_EMIT clientDisconnected(c);
|
|
|
|
});
|
2021-05-13 09:33:08 +00:00
|
|
|
Q_EMIT clientConnected(c);
|
2014-11-17 15:01:18 +00:00
|
|
|
return c;
|
|
|
|
}
|
2014-09-18 13:40:22 +00:00
|
|
|
|
2021-08-29 05:11:06 +00:00
|
|
|
QVector<ClientConnection *> Display::connections() const
|
2014-11-17 17:13:28 +00:00
|
|
|
{
|
|
|
|
return d->clients;
|
|
|
|
}
|
|
|
|
|
2014-11-27 15:16:54 +00:00
|
|
|
ClientConnection *Display::createClient(int fd)
|
|
|
|
{
|
|
|
|
Q_ASSERT(fd != -1);
|
|
|
|
Q_ASSERT(d->display);
|
|
|
|
wl_client *c = wl_client_create(d->display, fd);
|
|
|
|
if (!c) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return getConnection(c);
|
|
|
|
}
|
|
|
|
|
2015-03-03 08:43:30 +00:00
|
|
|
void Display::setEglDisplay(void *display)
|
|
|
|
{
|
|
|
|
if (d->eglDisplay != EGL_NO_DISPLAY) {
|
2022-04-22 09:27:33 +00:00
|
|
|
qCWarning(KWIN_CORE) << "EGLDisplay cannot be changed";
|
2015-03-03 08:43:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
d->eglDisplay = (EGLDisplay)display;
|
2021-07-20 17:02:13 +00:00
|
|
|
new DrmClientBufferIntegration(this);
|
2015-03-03 08:43:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void *Display::eglDisplay() const
|
|
|
|
{
|
|
|
|
return d->eglDisplay;
|
|
|
|
}
|
|
|
|
|
2022-04-19 10:14:26 +00:00
|
|
|
struct ClientBufferDestroyListener : wl_listener
|
|
|
|
{
|
2021-07-20 17:02:13 +00:00
|
|
|
ClientBufferDestroyListener(Display *display, ClientBuffer *buffer);
|
|
|
|
~ClientBufferDestroyListener();
|
|
|
|
|
|
|
|
Display *display;
|
|
|
|
};
|
|
|
|
|
|
|
|
void bufferDestroyCallback(wl_listener *listener, void *data)
|
|
|
|
{
|
|
|
|
ClientBufferDestroyListener *destroyListener = static_cast<ClientBufferDestroyListener *>(listener);
|
|
|
|
DisplayPrivate *displayPrivate = DisplayPrivate::get(destroyListener->display);
|
|
|
|
|
|
|
|
ClientBuffer *buffer = displayPrivate->q->clientBufferForResource(static_cast<wl_resource *>(data));
|
|
|
|
displayPrivate->unregisterClientBuffer(buffer);
|
|
|
|
|
|
|
|
buffer->markAsDestroyed();
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientBufferDestroyListener::ClientBufferDestroyListener(Display *display, ClientBuffer *buffer)
|
|
|
|
: display(display)
|
|
|
|
{
|
|
|
|
notify = bufferDestroyCallback;
|
|
|
|
|
|
|
|
link.prev = nullptr;
|
|
|
|
link.next = nullptr;
|
|
|
|
|
|
|
|
wl_resource_add_destroy_listener(buffer->resource(), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientBufferDestroyListener::~ClientBufferDestroyListener()
|
|
|
|
{
|
|
|
|
wl_list_remove(&link);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClientBuffer *Display::clientBufferForResource(wl_resource *resource) const
|
|
|
|
{
|
|
|
|
ClientBuffer *buffer = d->resourceToBuffer.value(resource);
|
|
|
|
if (buffer) {
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2022-10-31 19:02:23 +00:00
|
|
|
for (ClientBufferIntegration *integration : std::as_const(d->bufferIntegrations)) {
|
2021-07-20 17:02:13 +00:00
|
|
|
ClientBuffer *buffer = integration->createBuffer(resource);
|
|
|
|
if (buffer) {
|
|
|
|
d->registerClientBuffer(buffer);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayPrivate::registerClientBuffer(ClientBuffer *buffer)
|
|
|
|
{
|
|
|
|
resourceToBuffer.insert(buffer->resource(), buffer);
|
|
|
|
bufferToListener.insert(buffer, new ClientBufferDestroyListener(q, buffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayPrivate::unregisterClientBuffer(ClientBuffer *buffer)
|
|
|
|
{
|
|
|
|
Q_ASSERT_X(buffer->resource(), "unregisterClientBuffer", "buffer must have valid resource");
|
|
|
|
resourceToBuffer.remove(buffer->resource());
|
|
|
|
delete bufferToListener.take(buffer);
|
|
|
|
}
|
|
|
|
|
2014-08-26 14:07:39 +00:00
|
|
|
}
|