File indexing completed on 2024-05-12 05:32:20

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 "clientconnection.h"
0009 #include "display_p.h"
0010 #include "linuxdmabufv1clientbuffer_p.h"
0011 #include "output.h"
0012 #include "shmclientbuffer_p.h"
0013 #include "utils/common.h"
0014 
0015 #include <poll.h>
0016 #include <string.h>
0017 #include <sys/socket.h>
0018 
0019 #include <QAbstractEventDispatcher>
0020 #include <QCoreApplication>
0021 #include <QDebug>
0022 #include <QRect>
0023 
0024 namespace KWin
0025 {
0026 DisplayPrivate *DisplayPrivate::get(Display *display)
0027 {
0028     return display->d.get();
0029 }
0030 
0031 DisplayPrivate::DisplayPrivate(Display *q)
0032     : q(q)
0033 {
0034 }
0035 
0036 void DisplayPrivate::registerSocketName(const QString &socketName)
0037 {
0038     socketNames.append(socketName);
0039     Q_EMIT q->socketNamesChanged();
0040 }
0041 
0042 Display::Display(QObject *parent)
0043     : QObject(parent)
0044     , d(new DisplayPrivate(this))
0045 {
0046     d->display = wl_display_create();
0047     d->loop = wl_display_get_event_loop(d->display);
0048 }
0049 
0050 Display::~Display()
0051 {
0052     wl_display_destroy_clients(d->display);
0053     wl_display_destroy(d->display);
0054 }
0055 
0056 bool Display::addSocketFileDescriptor(int fileDescriptor, const QString &name)
0057 {
0058     if (wl_display_add_socket_fd(d->display, fileDescriptor)) {
0059         qCWarning(KWIN_CORE, "Failed to add %d fd to display", fileDescriptor);
0060         return false;
0061     }
0062     if (!name.isEmpty()) {
0063         d->registerSocketName(name);
0064     }
0065     return true;
0066 }
0067 
0068 bool Display::addSocketName(const QString &name)
0069 {
0070     if (name.isEmpty()) {
0071         const char *socket = wl_display_add_socket_auto(d->display);
0072         if (!socket) {
0073             qCWarning(KWIN_CORE, "Failed to find a free display socket");
0074             return false;
0075         }
0076         d->registerSocketName(QString::fromUtf8(socket));
0077     } else {
0078         if (wl_display_add_socket(d->display, qPrintable(name))) {
0079             qCWarning(KWIN_CORE, "Failed to add %s socket to display", qPrintable(name));
0080             return false;
0081         }
0082         d->registerSocketName(name);
0083     }
0084     return true;
0085 }
0086 
0087 QStringList Display::socketNames() const
0088 {
0089     return d->socketNames;
0090 }
0091 
0092 bool Display::start()
0093 {
0094     if (d->running) {
0095         return true;
0096     }
0097 
0098     const int fileDescriptor = wl_event_loop_get_fd(d->loop);
0099     if (fileDescriptor == -1) {
0100         qCWarning(KWIN_CORE) << "Did not get the file descriptor for the event loop";
0101         return false;
0102     }
0103 
0104     d->socketNotifier = new QSocketNotifier(fileDescriptor, QSocketNotifier::Read, this);
0105     connect(d->socketNotifier, &QSocketNotifier::activated, this, &Display::dispatchEvents);
0106 
0107     QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
0108     connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &Display::flush);
0109 
0110     d->running = true;
0111     Q_EMIT runningChanged(true);
0112 
0113     return true;
0114 }
0115 
0116 void Display::dispatchEvents()
0117 {
0118     if (wl_event_loop_dispatch(d->loop, 0) != 0) {
0119         qCWarning(KWIN_CORE) << "Error on dispatching Wayland event loop";
0120     }
0121 }
0122 
0123 void Display::flush()
0124 {
0125     wl_display_flush_clients(d->display);
0126 }
0127 
0128 void Display::createShm()
0129 {
0130     Q_ASSERT(d->display);
0131     new ShmClientBufferIntegration(this);
0132 }
0133 
0134 quint32 Display::nextSerial()
0135 {
0136     return wl_display_next_serial(d->display);
0137 }
0138 
0139 quint32 Display::serial()
0140 {
0141     return wl_display_get_serial(d->display);
0142 }
0143 
0144 bool Display::isRunning() const
0145 {
0146     return d->running;
0147 }
0148 
0149 Display::operator wl_display *()
0150 {
0151     return d->display;
0152 }
0153 
0154 Display::operator wl_display *() const
0155 {
0156     return d->display;
0157 }
0158 
0159 QList<OutputInterface *> Display::outputs() const
0160 {
0161     return d->outputs;
0162 }
0163 
0164 QList<OutputDeviceV2Interface *> Display::outputDevices() const
0165 {
0166     return d->outputdevicesV2;
0167 }
0168 
0169 QList<OutputInterface *> Display::outputsIntersecting(const QRect &rect) const
0170 {
0171     QList<OutputInterface *> outputs;
0172     for (auto *output : std::as_const(d->outputs)) {
0173         if (output->handle()->geometry().intersects(rect)) {
0174             outputs << output;
0175         }
0176     }
0177     return outputs;
0178 }
0179 
0180 OutputInterface *Display::largestIntersectingOutput(const QRect &rect) const
0181 {
0182     OutputInterface *returnOutput = nullptr;
0183     uint64_t biggestArea = 0;
0184     for (auto *output : std::as_const(d->outputs)) {
0185         const QRect intersect = output->handle()->geometry().intersected(rect);
0186         const uint64_t area = intersect.width() * intersect.height();
0187         if (area > biggestArea) {
0188             biggestArea = area;
0189             returnOutput = output;
0190         }
0191     }
0192     return returnOutput;
0193 }
0194 
0195 QList<SeatInterface *> Display::seats() const
0196 {
0197     return d->seats;
0198 }
0199 
0200 ClientConnection *Display::getConnection(wl_client *client)
0201 {
0202     Q_ASSERT(client);
0203     auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(), [client](ClientConnection *c) {
0204         return c->client() == client;
0205     });
0206     if (it != d->clients.constEnd()) {
0207         return *it;
0208     }
0209     // no ConnectionData yet, create it
0210     auto c = new ClientConnection(client, this);
0211     d->clients << c;
0212     connect(c, &ClientConnection::disconnected, this, [this](ClientConnection *c) {
0213         const int index = d->clients.indexOf(c);
0214         Q_ASSERT(index != -1);
0215         d->clients.remove(index);
0216         Q_ASSERT(d->clients.indexOf(c) == -1);
0217         Q_EMIT clientDisconnected(c);
0218     });
0219     Q_EMIT clientConnected(c);
0220     return c;
0221 }
0222 
0223 QList<ClientConnection *> Display::connections() const
0224 {
0225     return d->clients;
0226 }
0227 
0228 ClientConnection *Display::createClient(int fd)
0229 {
0230     Q_ASSERT(fd != -1);
0231     Q_ASSERT(d->display);
0232     wl_client *c = wl_client_create(d->display, fd);
0233     if (!c) {
0234         return nullptr;
0235     }
0236     return getConnection(c);
0237 }
0238 
0239 GraphicsBuffer *Display::bufferForResource(wl_resource *resource)
0240 {
0241     if (auto buffer = LinuxDmaBufV1ClientBuffer::get(resource)) {
0242         return buffer;
0243     } else if (auto buffer = ShmClientBuffer::get(resource)) {
0244         return buffer;
0245     } else {
0246         return nullptr;
0247     }
0248 }
0249 
0250 SecurityContext::SecurityContext(Display *display, FileDescriptor &&listenFd, FileDescriptor &&closeFd, const QString &appId)
0251     : QObject(display)
0252     , m_display(display)
0253     , m_listenFd(std::move(listenFd))
0254     , m_closeFd(std::move(closeFd))
0255     , m_appId(appId)
0256 {
0257     qCDebug(KWIN_CORE) << "Adding listen fd for" << appId;
0258 
0259     auto closeSocketWatcher = new QSocketNotifier(m_closeFd.get(), QSocketNotifier::Read, this);
0260     connect(closeSocketWatcher, &QSocketNotifier::activated, this, &SecurityContext::onCloseFdActivated);
0261 
0262     if (m_closeFd.isClosed()) {
0263         deleteLater();
0264         return;
0265     }
0266 
0267     auto listenFdListener = new QSocketNotifier(m_listenFd.get(), QSocketNotifier::Read, this);
0268     connect(listenFdListener, &QSocketNotifier::activated, this, &SecurityContext::onListenFdActivated);
0269 }
0270 
0271 SecurityContext::~SecurityContext()
0272 {
0273     qCDebug(KWIN_CORE) << "Removing listen fd for " << m_appId;
0274 }
0275 
0276 void SecurityContext::onListenFdActivated(QSocketDescriptor socketDescriptor)
0277 {
0278     int clientFd = accept4(socketDescriptor, nullptr, nullptr, SOCK_CLOEXEC);
0279     if (clientFd < 0) {
0280         qCWarning(KWIN_CORE) << "Failed to accept client from security listen FD";
0281         return;
0282     }
0283     auto client = m_display->createClient(clientFd);
0284     client->setSecurityContextAppId(m_appId);
0285 }
0286 
0287 void SecurityContext::onCloseFdActivated()
0288 {
0289     if (m_closeFd.isClosed()) {
0290         deleteLater();
0291     }
0292 }
0293 
0294 } // namespace KWin
0295 
0296 #include "moc_display.cpp"