File indexing completed on 2024-11-10 04:57:26
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"