File indexing completed on 2026-06-14 15:32:07

0001 /*
0002     SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "wayland_display.h"
0008 #include "wayland_logging.h"
0009 
0010 #include <KWayland/Client/compositor.h>
0011 #include <KWayland/Client/pointerconstraints.h>
0012 #include <KWayland/Client/pointergestures.h>
0013 #include <KWayland/Client/registry.h>
0014 #include <KWayland/Client/relativepointer.h>
0015 #include <KWayland/Client/seat.h>
0016 #include <KWayland/Client/shm_pool.h>
0017 #include <KWayland/Client/subcompositor.h>
0018 #include <KWayland/Client/xdgdecoration.h>
0019 #include <KWayland/Client/xdgshell.h>
0020 
0021 #include <QMutex>
0022 #include <QThread>
0023 #include <QWaitCondition>
0024 
0025 #include <drm_fourcc.h>
0026 #include <fcntl.h>
0027 #include <poll.h>
0028 #include <unistd.h>
0029 #include <wayland-client.h>
0030 
0031 // Generated in src/wayland.
0032 #include "wayland-linux-dmabuf-unstable-v1-client-protocol.h"
0033 #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
0034 #include "wayland-pointer-gestures-unstable-v1-server-protocol.h"
0035 #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
0036 #include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
0037 #include "wayland-xdg-shell-client-protocol.h"
0038 
0039 namespace KWin
0040 {
0041 namespace Wayland
0042 {
0043 
0044 class WaylandEventThread : public QThread
0045 {
0046     Q_OBJECT
0047 
0048 public:
0049     WaylandEventThread(wl_display *display)
0050         : m_display(display)
0051         , m_fd(wl_display_get_fd(display))
0052         , m_quitPipe{-1, -1}
0053         , m_reading(true)
0054         , m_quitting(false)
0055     {
0056         if (pipe2(m_quitPipe, O_CLOEXEC) == -1) {
0057             qCWarning(KWIN_WAYLAND_BACKEND) << "Failed to create quite pipe in WaylandEventThread";
0058         }
0059     }
0060 
0061     ~WaylandEventThread() override
0062     {
0063         if (m_quitPipe[0] != -1) {
0064             close(m_quitPipe[0]);
0065             close(m_quitPipe[1]);
0066         }
0067     }
0068 
0069     void dispatch()
0070     {
0071         while (true) {
0072             if (wl_display_dispatch_pending(m_display) < 0) {
0073                 qFatal("Wayland connection broke");
0074             }
0075 
0076             wl_display_flush(m_display);
0077 
0078             if (m_reading.loadAcquire()) {
0079                 break;
0080             }
0081 
0082             if (wl_display_prepare_read(m_display) == 0) {
0083                 QMutexLocker lock(&m_mutex);
0084                 m_reading.storeRelease(true);
0085                 m_cond.wakeOne();
0086                 break;
0087             }
0088         }
0089     }
0090 
0091     void stop()
0092     {
0093         if (m_quitPipe[1] != -1) {
0094             write(m_quitPipe[1], "\0", 1);
0095         }
0096 
0097         m_mutex.lock();
0098         m_quitting = true;
0099         m_cond.wakeOne();
0100         m_mutex.unlock();
0101 
0102         wait();
0103     }
0104 
0105 Q_SIGNALS:
0106     void available();
0107 
0108 protected:
0109     void run() override
0110     {
0111         while (true) {
0112             m_reading.storeRelease(false);
0113 
0114             Q_EMIT available();
0115 
0116             m_mutex.lock();
0117             while (!m_reading.loadRelaxed() && !m_quitting) {
0118                 m_cond.wait(&m_mutex);
0119             }
0120             m_mutex.unlock();
0121 
0122             if (m_quitting) {
0123                 break;
0124             }
0125 
0126             pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_quitPipe[0], POLLIN, 0 } };
0127             poll(fds, 2, -1);
0128 
0129             if (fds[1].revents & POLLIN) {
0130                 wl_display_cancel_read(m_display);
0131                 break;
0132             }
0133 
0134             if (fds[0].revents & POLLIN) {
0135                 wl_display_read_events(m_display);
0136             } else {
0137                 wl_display_cancel_read(m_display);
0138             }
0139         }
0140     }
0141 
0142 private:
0143     wl_display *const m_display;
0144     int m_fd;
0145     int m_quitPipe[2];
0146     QAtomicInteger<bool> m_reading;
0147     QMutex m_mutex;
0148     QWaitCondition m_cond;
0149     bool m_quitting;
0150 };
0151 
0152 WaylandLinuxDmabufV1::WaylandLinuxDmabufV1(wl_registry *registry, uint32_t name, uint32_t version)
0153 {
0154     m_dmabuf = static_cast<zwp_linux_dmabuf_v1 *>(wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, version));
0155 
0156     static const struct zwp_linux_dmabuf_v1_listener dmabufListener = {
0157         .format = format,
0158         .modifier = modifier,
0159     };
0160     zwp_linux_dmabuf_v1_add_listener(m_dmabuf, &dmabufListener, this);
0161 }
0162 
0163 WaylandLinuxDmabufV1::~WaylandLinuxDmabufV1()
0164 {
0165     zwp_linux_dmabuf_v1_destroy(m_dmabuf);
0166 }
0167 
0168 zwp_linux_dmabuf_v1 *WaylandLinuxDmabufV1::handle() const
0169 {
0170     return m_dmabuf;
0171 }
0172 
0173 QHash<uint32_t, QVector<uint64_t>> WaylandLinuxDmabufV1::formats() const
0174 {
0175     return m_formats;
0176 }
0177 
0178 void WaylandLinuxDmabufV1::format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format)
0179 {
0180     WaylandLinuxDmabufV1 *dmabuf = static_cast<WaylandLinuxDmabufV1 *>(data);
0181     dmabuf->m_formats[format].append(DRM_FORMAT_MOD_INVALID);
0182 }
0183 
0184 void WaylandLinuxDmabufV1::modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
0185 {
0186     WaylandLinuxDmabufV1 *dmabuf = static_cast<WaylandLinuxDmabufV1 *>(data);
0187     dmabuf->m_formats[format].append((static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo);
0188 }
0189 
0190 WaylandDisplay::WaylandDisplay()
0191 {
0192 }
0193 
0194 WaylandDisplay::~WaylandDisplay()
0195 {
0196     m_eventThread->stop();
0197     m_eventThread.reset();
0198 
0199     m_compositor.reset();
0200     m_pointerConstraints.reset();
0201     m_pointerGestures.reset();
0202     m_relativePointerManager.reset();
0203     m_seat.reset();
0204     m_xdgDecorationManager.reset();
0205     m_shmPool.reset();
0206     m_xdgShell.reset();
0207     m_linuxDmabuf.reset();
0208 
0209     if (m_registry) {
0210         wl_registry_destroy(m_registry);
0211     }
0212     if (m_display) {
0213         wl_display_disconnect(m_display);
0214     }
0215 }
0216 
0217 void WaylandDisplay::flush()
0218 {
0219     m_eventThread->dispatch();
0220 }
0221 
0222 bool WaylandDisplay::initialize(const QString &socketName)
0223 {
0224     m_display = wl_display_connect(socketName.toUtf8());
0225     if (!m_display) {
0226         return false;
0227     }
0228 
0229     m_eventThread = std::make_unique<WaylandEventThread>(m_display);
0230     connect(m_eventThread.get(), &WaylandEventThread::available, this, &WaylandDisplay::flush, Qt::QueuedConnection);
0231     m_eventThread->start();
0232 
0233     static wl_registry_listener registryListener {
0234         .global = registry_global,
0235         .global_remove = registry_global_remove,
0236     };
0237     m_registry = wl_display_get_registry(m_display);
0238     wl_registry_add_listener(m_registry, &registryListener, this);
0239     wl_display_roundtrip(m_display);
0240     wl_display_roundtrip(m_display); // get dmabuf formats
0241 
0242     return true;
0243 }
0244 
0245 wl_display *WaylandDisplay::nativeDisplay() const
0246 {
0247     return m_display;
0248 }
0249 
0250 KWayland::Client::Compositor *WaylandDisplay::compositor() const
0251 {
0252     return m_compositor.get();
0253 }
0254 
0255 KWayland::Client::PointerConstraints *WaylandDisplay::pointerConstraints() const
0256 {
0257     return m_pointerConstraints.get();
0258 }
0259 
0260 KWayland::Client::PointerGestures *WaylandDisplay::pointerGestures() const
0261 {
0262     return m_pointerGestures.get();
0263 }
0264 
0265 KWayland::Client::RelativePointerManager *WaylandDisplay::relativePointerManager() const
0266 {
0267     return m_relativePointerManager.get();
0268 }
0269 
0270 KWayland::Client::ShmPool *WaylandDisplay::shmPool() const
0271 {
0272     return m_shmPool.get();
0273 }
0274 
0275 KWayland::Client::Seat *WaylandDisplay::seat() const
0276 {
0277     return m_seat.get();
0278 }
0279 
0280 KWayland::Client::XdgShell *WaylandDisplay::xdgShell() const
0281 {
0282     return m_xdgShell.get();
0283 }
0284 
0285 KWayland::Client::XdgDecorationManager *WaylandDisplay::xdgDecorationManager() const
0286 {
0287     return m_xdgDecorationManager.get();
0288 }
0289 
0290 WaylandLinuxDmabufV1 *WaylandDisplay::linuxDmabuf() const
0291 {
0292     return m_linuxDmabuf.get();
0293 }
0294 
0295 void WaylandDisplay::registry_global(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
0296 {
0297     WaylandDisplay *display = static_cast<WaylandDisplay *>(data);
0298 
0299     if (strcmp(interface, wl_compositor_interface.name) == 0) {
0300         if (version < 4) {
0301             qFatal("wl_compositor version 4 or later is required");
0302         }
0303         display->m_compositor = std::make_unique<KWayland::Client::Compositor>();
0304         display->m_compositor->setup(static_cast<wl_compositor *>(wl_registry_bind(registry, name, &wl_compositor_interface, std::min(version, 4u))));
0305     } else if (strcmp(interface, wl_shm_interface.name) == 0) {
0306         display->m_shmPool = std::make_unique<KWayland::Client::ShmPool>();
0307         display->m_shmPool->setup(static_cast<wl_shm *>(wl_registry_bind(registry, name, &wl_shm_interface, std::min(version, 1u))));
0308     } else if (strcmp(interface, wl_seat_interface.name) == 0) {
0309         display->m_seat = std::make_unique<KWayland::Client::Seat>();
0310         display->m_seat->setup(static_cast<wl_seat *>(wl_registry_bind(registry, name, &wl_seat_interface, std::min(version, 2u))));
0311     } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
0312         display->m_xdgShell = std::make_unique<KWayland::Client::XdgShellStable>();
0313         display->m_xdgShell->setup(static_cast<xdg_wm_base *>(wl_registry_bind(registry, name, &xdg_wm_base_interface, std::min(version, 1u))));
0314     } else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) {
0315         display->m_pointerConstraints = std::make_unique<KWayland::Client::PointerConstraints>();
0316         display->m_pointerConstraints->setup(static_cast<zwp_pointer_constraints_v1 *>(wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, std::min(version, 1u))));
0317     } else if (strcmp(interface, zwp_pointer_gestures_v1_interface.name) == 0) {
0318         display->m_pointerGestures = std::make_unique<KWayland::Client::PointerGestures>();
0319         display->m_pointerGestures->setup(static_cast<zwp_pointer_gestures_v1 *>(wl_registry_bind(registry, name, &zwp_pointer_gestures_v1_interface, std::min(version, 1u))));
0320     } else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
0321         display->m_relativePointerManager = std::make_unique<KWayland::Client::RelativePointerManager>();
0322         display->m_relativePointerManager->setup(static_cast<zwp_relative_pointer_manager_v1 *>(wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, std::min(version, 1u))));
0323     } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
0324         display->m_xdgDecorationManager = std::make_unique<KWayland::Client::XdgDecorationManager>();
0325         display->m_xdgDecorationManager->setup(static_cast<zxdg_decoration_manager_v1 *>(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, std::min(version, 1u))));
0326     } else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
0327         display->m_linuxDmabuf = std::make_unique<WaylandLinuxDmabufV1>(registry, name, std::min(version, 3u));
0328     }
0329 }
0330 
0331 void WaylandDisplay::registry_global_remove(void *data, wl_registry *registry, uint32_t name)
0332 {
0333 }
0334 
0335 }
0336 }
0337 
0338 #include "wayland_display.moc"