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, ®istryListener, 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"