11#include <KWayland/Client/compositor.h>
12#include <KWayland/Client/pointerconstraints.h>
13#include <KWayland/Client/pointergestures.h>
14#include <KWayland/Client/registry.h>
15#include <KWayland/Client/relativepointer.h>
16#include <KWayland/Client/seat.h>
17#include <KWayland/Client/subcompositor.h>
18#include <KWayland/Client/xdgdecoration.h>
19#include <KWayland/Client/xdgshell.h>
23#include <QWaitCondition>
25#include <drm_fourcc.h>
30#include <wayland-client.h>
34#include "wayland-linux-dmabuf-unstable-v1-client-protocol.h"
35#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
36#include "wayland-pointer-gestures-unstable-v1-server-protocol.h"
37#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
38#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
39#include "wayland-xdg-shell-client-protocol.h"
53 , m_fd(wl_display_get_fd(display))
58 if (pipe2(m_quitPipe, O_CLOEXEC) == -1) {
59 qCWarning(KWIN_WAYLAND_BACKEND) <<
"Failed to create quite pipe in WaylandEventThread";
65 if (m_quitPipe[0] != -1) {
74 if (wl_display_dispatch_pending(m_display) < 0) {
75 qFatal(
"Wayland connection broke");
78 wl_display_flush(m_display);
80 if (m_reading.loadAcquire()) {
84 if (wl_display_prepare_read(m_display) == 0) {
85 QMutexLocker lock(&m_mutex);
86 m_reading.storeRelease(
true);
95 if (m_quitPipe[1] != -1) {
96 write(m_quitPipe[1],
"\0", 1);
114 m_reading.storeRelease(
false);
119 while (!m_reading.loadRelaxed() && !m_quitting) {
120 m_cond.wait(&m_mutex);
128 pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_quitPipe[0], POLLIN, 0 } };
131 if (fds[1].revents & POLLIN) {
132 wl_display_cancel_read(m_display);
136 if (fds[0].revents & POLLIN) {
137 wl_display_read_events(m_display);
139 wl_display_cancel_read(m_display);
145 wl_display *
const m_display;
148 QAtomicInteger<bool> m_reading;
150 QWaitCondition m_cond;
154static dev_t deserializeDeviceId(wl_array *data)
156 Q_ASSERT(
sizeof(dev_t) == data->size);
158 std::memcpy(&ret, data->data, data->size);
168 static const struct zwp_linux_dmabuf_feedback_v1_listener feedbackListener = {
170 .format_table = format_table,
171 .main_device = main_device,
172 .tranche_done = tranche_done,
173 .tranche_target_device = tranche_target_device,
174 .tranche_formats = tranche_formats,
175 .tranche_flags = tranche_flags,
177 zwp_linux_dmabuf_feedback_v1_add_listener(
feedback, &feedbackListener,
this);
182 zwp_linux_dmabuf_feedback_v1_destroy(
feedback);
193 static void done(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1)
198 static void format_table(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, int32_t fd, uint32_t size)
206 static void main_device(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, wl_array *deviceId)
210 feedback->mainDeviceId = deserializeDeviceId(deviceId);
212 drmDevice *device =
nullptr;
213 if (drmGetDeviceFromDevId(
feedback->mainDeviceId, 0, &device) != 0) {
214 qCWarning(KWIN_WAYLAND_BACKEND) <<
"drmGetDeviceFromDevId() failed";
218 if (device->available_nodes & (1 << DRM_NODE_RENDER)) {
219 feedback->mainDevice = QByteArray(device->nodes[DRM_NODE_RENDER]);
220 }
else if (device->available_nodes & (1 << DRM_NODE_PRIMARY)) {
223 feedback->mainDevice = QByteArray(device->nodes[DRM_NODE_PRIMARY]);
226 drmFreeDevice(&device);
229 static void tranche_done(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1)
234 feedback->formatTable = MemoryMap{};
237 static void tranche_target_device(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, wl_array *deviceId)
241 feedback->trancheDeviceId = deserializeDeviceId(deviceId);
244 static void tranche_formats(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, wl_array *indices)
247 if (!
feedback->formatTable.isValid()) {
254 struct linux_dmabuf_feedback_v1_table_entry
261 const auto entries =
static_cast<linux_dmabuf_feedback_v1_table_entry *
>(
feedback->formatTable.data());
262 for (
const uint16_t &index : std::span(static_cast<uint16_t *>(indices->data), indices->size / sizeof(uint16_t))) {
263 const linux_dmabuf_feedback_v1_table_entry &entry = entries[index];
264 feedback->formats[entry.format].append(entry.modifier);
268 static void tranche_flags(
void *data, zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, uint32_t flags)
276 m_dmabuf =
static_cast<zwp_linux_dmabuf_v1 *
>(wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
version));
278 static const struct zwp_linux_dmabuf_v1_listener dmabufListener = {
280 .modifier = modifier,
282 zwp_linux_dmabuf_v1_add_listener(m_dmabuf, &dmabufListener,
this);
284 m_defaultFeedback = std::make_unique<WaylandLinuxDmabufFeedbackV1>(zwp_linux_dmabuf_v1_get_default_feedback(m_dmabuf));
289 zwp_linux_dmabuf_v1_destroy(m_dmabuf);
299 return m_defaultFeedback->mainDevice;
304 return m_defaultFeedback->formats;
307void WaylandLinuxDmabufV1::format(
void *data,
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t
format)
312void WaylandLinuxDmabufV1::modifier(
void *data,
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t
format, uint32_t modifier_hi, uint32_t modifier_lo)
323 m_eventThread->stop();
324 m_eventThread.reset();
326 m_compositor.reset();
327 m_pointerConstraints.reset();
328 m_pointerGestures.reset();
329 m_relativePointerManager.reset();
331 m_xdgDecorationManager.reset();
333 m_linuxDmabuf.reset();
336 wl_shm_destroy(m_shm);
339 wl_registry_destroy(m_registry);
342 wl_display_disconnect(m_display);
348 m_eventThread->dispatch();
353 m_display = wl_display_connect(socketName.toUtf8());
358 m_eventThread = std::make_unique<WaylandEventThread>(m_display);
360 m_eventThread->start();
362 static wl_registry_listener registryListener {
363 .global = registry_global,
364 .global_remove = registry_global_remove,
366 m_registry = wl_display_get_registry(m_display);
367 wl_registry_add_listener(m_registry, ®istryListener,
this);
368 wl_display_roundtrip(m_display);
369 wl_display_roundtrip(m_display);
381 return m_compositor.get();
386 return m_pointerConstraints.get();
391 return m_pointerGestures.get();
396 return m_relativePointerManager.get();
411 return m_xdgShell.get();
416 return m_xdgDecorationManager.get();
421 return m_linuxDmabuf.get();
424void WaylandDisplay::registry_global(
void *data, wl_registry *registry, uint32_t name,
const char *interface, uint32_t
version)
428 if (strcmp(interface, wl_compositor_interface.name) == 0) {
430 qFatal(
"wl_compositor version 4 or later is required");
432 display->m_compositor = std::make_unique<KWayland::Client::Compositor>();
433 display->m_compositor->setup(
static_cast<wl_compositor *
>(wl_registry_bind(registry, name, &wl_compositor_interface, std::min(
version, 4u))));
434 }
else if (strcmp(interface, wl_shm_interface.name) == 0) {
435 display->m_shm =
static_cast<wl_shm *
>(wl_registry_bind(registry, name, &wl_shm_interface, std::min(
version, 1u)));
436 }
else if (strcmp(interface, wl_seat_interface.name) == 0) {
437 display->m_seat = std::make_unique<KWayland::Client::Seat>();
438 display->m_seat->setup(
static_cast<wl_seat *
>(wl_registry_bind(registry, name, &wl_seat_interface, std::min(
version, 5u))));
439 }
else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
440 display->m_xdgShell = std::make_unique<KWayland::Client::XdgShellStable>();
441 display->m_xdgShell->setup(
static_cast<xdg_wm_base *
>(wl_registry_bind(registry, name, &xdg_wm_base_interface, std::min(
version, 1u))));
442 }
else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) {
443 display->m_pointerConstraints = std::make_unique<KWayland::Client::PointerConstraints>();
444 display->m_pointerConstraints->setup(
static_cast<zwp_pointer_constraints_v1 *
>(wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, std::min(
version, 1u))));
445 }
else if (strcmp(interface, zwp_pointer_gestures_v1_interface.name) == 0) {
446 display->m_pointerGestures = std::make_unique<KWayland::Client::PointerGestures>();
447 display->m_pointerGestures->setup(
static_cast<zwp_pointer_gestures_v1 *
>(wl_registry_bind(registry, name, &zwp_pointer_gestures_v1_interface, std::min(
version, 1u))));
448 }
else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
449 display->m_relativePointerManager = std::make_unique<KWayland::Client::RelativePointerManager>();
450 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))));
451 }
else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
452 display->m_xdgDecorationManager = std::make_unique<KWayland::Client::XdgDecorationManager>();
453 display->m_xdgDecorationManager->setup(
static_cast<zxdg_decoration_manager_v1 *
>(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, std::min(
version, 1u))));
454 }
else if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
456 qWarning(
"zwp_linux_dmabuf_v1 v4 or newer is needed");
459 display->m_linuxDmabuf = std::make_unique<WaylandLinuxDmabufV1>(registry, name, std::min(
version, 4u));
463void WaylandDisplay::registry_global_remove(
void *data, wl_registry *registry, uint32_t name)
470#include "wayland_display.moc"
472#include "moc_wayland_display.cpp"
wl_display * nativeDisplay() const
KWayland::Client::PointerConstraints * pointerConstraints() const
KWayland::Client::RelativePointerManager * relativePointerManager() const
bool initialize(const QString &socketName)
WaylandLinuxDmabufV1 * linuxDmabuf() const
KWayland::Client::XdgDecorationManager * xdgDecorationManager() const
~WaylandDisplay() override
KWayland::Client::Compositor * compositor() const
KWayland::Client::PointerGestures * pointerGestures() const
KWayland::Client::Seat * seat() const
KWayland::Client::XdgShell * xdgShell() const
~WaylandEventThread() override
WaylandEventThread(wl_display *display)
QHash< uint32_t, QList< uint64_t > > formats
~WaylandLinuxDmabufFeedbackV1()
zwp_linux_dmabuf_feedback_v1 * feedback
WaylandLinuxDmabufFeedbackV1(zwp_linux_dmabuf_feedback_v1 *feedback)
WaylandLinuxDmabufV1(wl_registry *registry, uint32_t name, uint32_t version)
QHash< uint32_t, QList< uint64_t > > formats() const
QByteArray mainDevice() const
zwp_linux_dmabuf_v1 * handle() const