From: Volker Schlecht Subject: Testing: wayland monitor hotplug To: ports@openbsd.org Date: Tue, 5 Aug 2025 19:31:55 +0200 During l2k25 I tried to get output hotplug to work with wlroots based wayland compositors. The attached diff seems to work rather well for matthieu@ and myself but could probably use some wider testing from whoever is interested :-) For those who haven't used wayland on OpenBSD before: $ doas pkg_add sway * apply the attached diff to wayland/wlroots, rebuild and install * kill all running X sessions, make sure to stop xenodm if it's running $ startsway.sh * Plug, unplug and replug any external monitors you have around, and see if sway detects and uses them. Index: Makefile =================================================================== RCS file: /cvs/ports/wayland/wlroots/Makefile,v diff -u -p -r1.11 Makefile --- Makefile 16 Dec 2024 18:25:23 -0000 1.11 +++ Makefile 5 Aug 2025 17:21:53 -0000 @@ -2,6 +2,7 @@ COMMENT = modular Wayland compositor lib V = 0.18.2 EPOCH = 0 +REVISION = 0 DISTNAME = wlroots-${V} CATEGORIES = wayland Index: patches/patch-backend_drm_backend_c =================================================================== RCS file: patches/patch-backend_drm_backend_c diff -N patches/patch-backend_drm_backend_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-backend_drm_backend_c 5 Aug 2025 17:21:53 -0000 @@ -0,0 +1,45 @@ +Index: backend/drm/backend.c +--- backend/drm/backend.c.orig ++++ backend/drm/backend.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include "backend/drm/drm.h" + #include "backend/drm/fb.h" +@@ -167,6 +168,8 @@ static void handle_parent_destroy(struct wl_listener * + + struct wlr_backend *wlr_drm_backend_create(struct wlr_session *session, + struct wlr_device *dev, struct wlr_backend *parent) { ++ int kq; ++ struct kevent kev; + assert(session && dev); + assert(!parent || wlr_backend_is_drm(parent)); + +@@ -267,6 +270,24 @@ struct wlr_backend *wlr_drm_backend_create(struct wlr_ + drm->session_destroy.notify = handle_session_destroy; + wl_signal_add(&session->events.destroy, &drm->session_destroy); + ++ if ((kq = kqueue()) <= 0) ++ goto error_kqueue; ++ ++ EV_SET(&kev, dev->fd, EVFILT_DEVICE, EV_ADD | EV_ENABLE | EV_CLEAR, ++ NOTE_CHANGE, 0, NULL); ++ ++ if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0) ++ goto error_kqueue; ++ ++ drm->drm_kevent = wl_event_loop_add_fd(session->event_loop, kq, ++ WL_EVENT_READABLE, handle_drm_kevent, drm); ++ if (!drm->drm_kevent) { ++ wlr_log(WLR_ERROR, "Failed to create DRM kevent source"); ++ goto error_kqueue; ++ } ++ wlr_log(WLR_INFO, "DRM kevent source added"); ++ ++error_kqueue: + return &drm->backend; + + error_mgpu_renderer: Index: patches/patch-backend_drm_drm_c =================================================================== RCS file: patches/patch-backend_drm_drm_c diff -N patches/patch-backend_drm_drm_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-backend_drm_drm_c 5 Aug 2025 17:21:53 -0000 @@ -0,0 +1,30 @@ +Index: backend/drm/drm.c +--- backend/drm/drm.c.orig ++++ backend/drm/drm.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2113,6 +2114,18 @@ int handle_drm_event(int fd, uint32_t mask, void *data + wlr_log(WLR_ERROR, "drmHandleEvent failed"); + wlr_backend_destroy(&drm->backend); + } ++ return 1; ++} ++ ++int handle_drm_kevent(int fd, uint32_t mask, void *data) { ++ struct kevent kev; ++ struct wlr_drm_backend *drm = data; ++ ++ if ((kevent(fd, NULL, 0, &kev, 1, NULL)) && kev.fflags & NOTE_CHANGE) { ++ wlr_log(WLR_INFO, "drm hotplug detected"); ++ scan_drm_connectors(drm, NULL); ++ } ++ + return 1; + } + Index: patches/patch-include_backend_drm_drm_h =================================================================== RCS file: patches/patch-include_backend_drm_drm_h diff -N patches/patch-include_backend_drm_drm_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-include_backend_drm_drm_h 5 Aug 2025 17:21:53 -0000 @@ -0,0 +1,19 @@ +Index: include/backend/drm/drm.h +--- include/backend/drm/drm.h.orig ++++ include/backend/drm/drm.h +@@ -96,6 +96,7 @@ struct wlr_drm_backend { + struct wlr_drm_plane *planes; + + struct wl_event_source *drm_event; ++ struct wl_event_source *drm_kevent; + + struct wl_listener session_destroy; + struct wl_listener session_active; +@@ -215,6 +216,7 @@ bool commit_drm_device(struct wlr_drm_backend *drm, + const struct wlr_backend_output_state *states, size_t states_len, bool test_only); + void restore_drm_device(struct wlr_drm_backend *drm); + int handle_drm_event(int fd, uint32_t mask, void *data); ++int handle_drm_kevent(int fd, uint32_t mask, void *data); + void destroy_drm_connector(struct wlr_drm_connector *conn); + bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn); + size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,