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 }