File indexing completed on 2024-05-19 16:35:18

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 #include "display.h"
0008 #include "clientbufferintegration.h"
0009 #include "display_p.h"
0010 #include "drmclientbuffer.h"
0011 #include "output_interface.h"
0012 #include "shmclientbuffer.h"
0013 #include "utils/common.h"
0014 
0015 #include <QAbstractEventDispatcher>
0016 #include <QCoreApplication>
0017 #include <QDebug>
0018 #include <QRect>
0019 
0020 namespace KWaylandServer
0021 {
0022 DisplayPrivate *DisplayPrivate::get(Display *display)
0023 {
0024     return display->d.get();
0025 }
0026 
0027 DisplayPrivate::DisplayPrivate(Display *q)
0028     : q(q)
0029 {
0030 }
0031 
0032 void DisplayPrivate::registerSocketName(const QString &socketName)
0033 {
0034     socketNames.append(socketName);
0035     Q_EMIT q->socketNamesChanged();
0036 }
0037 
0038 Display::Display(QObject *parent)
0039     : QObject(parent)
0040     , d(new DisplayPrivate(this))
0041 {
0042     d->display = wl_display_create();
0043     d->loop = wl_display_get_event_loop(d->display);
0044 }
0045 
0046 Display::~Display()
0047 {
0048     wl_display_destroy_clients(d->display);
0049     wl_display_destroy(d->display);
0050 }
0051 
0052 bool Display::addSocketFileDescriptor(int fileDescriptor, const QString &name)
0053 {
0054     if (wl_display_add_socket_fd(d->display, fileDescriptor)) {
0055         qCWarning(KWIN_CORE, "Failed to add %d fd to display", fileDescriptor);
0056         return false;
0057     }
0058     if (!name.isEmpty()) {
0059         d->registerSocketName(name);
0060     }
0061     return true;
0062 }
0063 
0064 bool Display::addSocketName(const QString &name)
0065 {
0066     if (name.isEmpty()) {
0067         const char *socket = wl_display_add_socket_auto(d->display);
0068         if (!socket) {
0069             qCWarning(KWIN_CORE, "Failed to find a free display socket");
0070             return false;
0071         }
0072         d->registerSocketName(QString::fromUtf8(socket));
0073     } else {
0074         if (wl_display_add_socket(d->display, qPrintable(name))) {
0075             qCWarning(KWIN_CORE, "Failed to add %s socket to display", qPrintable(name));
0076             return false;
0077         }
0078         d->registerSocketName(name);
0079     }
0080     return true;
0081 }
0082 
0083 QStringList Display::socketNames() const
0084 {
0085     return d->socketNames;
0086 }
0087 
0088 bool Display::start()
0089 {
0090     if (d->running) {
0091         return true;
0092     }
0093 
0094     const int fileDescriptor = wl_event_loop_get_fd(d->loop);
0095     if (fileDescriptor == -1) {
0096         qCWarning(KWIN_CORE) << "Did not get the file descriptor for the event loop";
0097         return false;
0098     }
0099 
0100     d->socketNotifier = new QSocketNotifier(fileDescriptor, QSocketNotifier::Read, this);
0101     connect(d->socketNotifier, &QSocketNotifier::activated, this, &Display::dispatchEvents);
0102 
0103     QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
0104     connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &Display::flush);
0105 
0106     d->running = true;
0107     Q_EMIT runningChanged(true);
0108 
0109     return true;
0110 }
0111 
0112 void Display::dispatchEvents()
0113 {
0114     if (wl_event_loop_dispatch(d->loop, 0) != 0) {
0115         qCWarning(KWIN_CORE) << "Error on dispatching Wayland event loop";
0116     }
0117 }
0118 
0119 void Display::flush()
0120 {
0121     wl_display_flush_clients(d->display);
0122 }
0123 
0124 void Display::createShm()
0125 {
0126     Q_ASSERT(d->display);
0127     new ShmClientBufferIntegration(this);
0128 }
0129 
0130 quint32 Display::nextSerial()
0131 {
0132     return wl_display_next_serial(d->display);
0133 }
0134 
0135 quint32 Display::serial()
0136 {
0137     return wl_display_get_serial(d->display);
0138 }
0139 
0140 bool Display::isRunning() const
0141 {
0142     return d->running;
0143 }
0144 
0145 Display::operator wl_display *()
0146 {
0147     return d->display;
0148 }
0149 
0150 Display::operator wl_display *() const
0151 {
0152     return d->display;
0153 }
0154 
0155 QList<OutputInterface *> Display::outputs() const
0156 {
0157     return d->outputs;
0158 }
0159 
0160 QList<OutputDeviceV2Interface *> Display::outputDevices() const
0161 {
0162     return d->outputdevicesV2;
0163 }
0164 
0165 QVector<OutputInterface *> Display::outputsIntersecting(const QRect &rect) const
0166 {
0167     QVector<OutputInterface *> outputs;
0168     for (auto *output : std::as_const(d->outputs)) {
0169         if (output->handle()->geometry().intersects(rect)) {
0170             outputs << output;
0171         }
0172     }
0173     return outputs;
0174 }
0175 
0176 QVector<SeatInterface *> Display::seats() const
0177 {
0178     return d->seats;
0179 }
0180 
0181 ClientConnection *Display::getConnection(wl_client *client)
0182 {
0183     Q_ASSERT(client);
0184     auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(), [client](ClientConnection *c) {
0185         return c->client() == client;
0186     });
0187     if (it != d->clients.constEnd()) {
0188         return *it;
0189     }
0190     // no ConnectionData yet, create it
0191     auto c = new ClientConnection(client, this);
0192     d->clients << c;
0193     connect(c, &ClientConnection::disconnected, this, [this](ClientConnection *c) {
0194         const int index = d->clients.indexOf(c);
0195         Q_ASSERT(index != -1);
0196         d->clients.remove(index);
0197         Q_ASSERT(d->clients.indexOf(c) == -1);
0198         Q_EMIT clientDisconnected(c);
0199     });
0200     Q_EMIT clientConnected(c);
0201     return c;
0202 }
0203 
0204 QVector<ClientConnection *> Display::connections() const
0205 {
0206     return d->clients;
0207 }
0208 
0209 ClientConnection *Display::createClient(int fd)
0210 {
0211     Q_ASSERT(fd != -1);
0212     Q_ASSERT(d->display);
0213     wl_client *c = wl_client_create(d->display, fd);
0214     if (!c) {
0215         return nullptr;
0216     }
0217     return getConnection(c);
0218 }
0219 
0220 void Display::setEglDisplay(void *display)
0221 {
0222     if (d->eglDisplay != EGL_NO_DISPLAY) {
0223         qCWarning(KWIN_CORE) << "EGLDisplay cannot be changed";
0224         return;
0225     }
0226     d->eglDisplay = (EGLDisplay)display;
0227     new DrmClientBufferIntegration(this);
0228 }
0229 
0230 void *Display::eglDisplay() const
0231 {
0232     return d->eglDisplay;
0233 }
0234 
0235 struct ClientBufferDestroyListener : wl_listener
0236 {
0237     ClientBufferDestroyListener(Display *display, ClientBuffer *buffer);
0238     ~ClientBufferDestroyListener();
0239 
0240     Display *display;
0241 };
0242 
0243 void bufferDestroyCallback(wl_listener *listener, void *data)
0244 {
0245     ClientBufferDestroyListener *destroyListener = static_cast<ClientBufferDestroyListener *>(listener);
0246     DisplayPrivate *displayPrivate = DisplayPrivate::get(destroyListener->display);
0247 
0248     ClientBuffer *buffer = displayPrivate->q->clientBufferForResource(static_cast<wl_resource *>(data));
0249     displayPrivate->unregisterClientBuffer(buffer);
0250 
0251     buffer->markAsDestroyed();
0252 }
0253 
0254 ClientBufferDestroyListener::ClientBufferDestroyListener(Display *display, ClientBuffer *buffer)
0255     : display(display)
0256 {
0257     notify = bufferDestroyCallback;
0258 
0259     link.prev = nullptr;
0260     link.next = nullptr;
0261 
0262     wl_resource_add_destroy_listener(buffer->resource(), this);
0263 }
0264 
0265 ClientBufferDestroyListener::~ClientBufferDestroyListener()
0266 {
0267     wl_list_remove(&link);
0268 }
0269 
0270 ClientBuffer *Display::clientBufferForResource(wl_resource *resource) const
0271 {
0272     ClientBuffer *buffer = d->resourceToBuffer.value(resource);
0273     if (buffer) {
0274         return buffer;
0275     }
0276 
0277     for (ClientBufferIntegration *integration : std::as_const(d->bufferIntegrations)) {
0278         ClientBuffer *buffer = integration->createBuffer(resource);
0279         if (buffer) {
0280             d->registerClientBuffer(buffer);
0281             return buffer;
0282         }
0283     }
0284     return nullptr;
0285 }
0286 
0287 void DisplayPrivate::registerClientBuffer(ClientBuffer *buffer)
0288 {
0289     resourceToBuffer.insert(buffer->resource(), buffer);
0290     bufferToListener.insert(buffer, new ClientBufferDestroyListener(q, buffer));
0291 }
0292 
0293 void DisplayPrivate::unregisterClientBuffer(ClientBuffer *buffer)
0294 {
0295     Q_ASSERT_X(buffer->resource(), "unregisterClientBuffer", "buffer must have valid resource");
0296     resourceToBuffer.remove(buffer->resource());
0297     delete bufferToListener.take(buffer);
0298 }
0299 
0300 }