From d07362b90ebd869fde1c3deff4c082255a39f57f Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Fri, 27 Mar 2026 22:35:54 +0100 Subject: [PATCH] =?UTF-8?q?wayland:=20Phase=2032=20=E2=80=94=20display=5Fo?= =?UTF-8?q?pen/close/screen=5Fcount=20through=20vtable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add three display-lifecycle slots to WMBackend: display_open(name) — open/init display connection, return Display* (NULL for Wayland; compositor init side-effect) display_close() — tear down display connection display_screen_count() — number of logical screens x11_backend: implement with XOpenDisplay (including close-on-exec fcntl), XCloseDisplay, ScreenCount(dpy); remove fcntl/FD_CLOEXEC from main.c. wl_backend: implement display_open() with full wlroots headless compositor init — wl_display_create, wlr_headless_backend_create, wlr_renderer_autocreate, wlr_backend_start. display_close() tears down in reverse order. Compositor state held in a file-static struct. Adds -DWLR_USE_UNSTABLE to WLROOTS_CFLAGS in configure.ac. main.c: move backend selection before display_open() (was in StartUp()), call wm_backend->display_open() instead of XOpenDisplay(); guard all X11-specific post-open code (visual-id, DisplayName, wXModifierInitialize) in if(dpy != NULL). startup.c: replace ScreenCount(dpy) with wm_backend->display_screen_count(); remove now-redundant backend-selection block (owned by main.c). Co-Authored-By: Claude Sonnet 4.6 --- configure.ac | 1 + src/backend/backend.h | 26 +++++++++ src/backend/wayland/wl_backend.c | 99 ++++++++++++++++++++++++++++++++ src/backend/x11/x11_backend.c | 35 +++++++++++ src/main.c | 73 ++++++++++++----------- src/startup.c | 13 +---- 6 files changed, 204 insertions(+), 43 deletions(-) diff --git a/configure.ac b/configure.ac index 0e2a875..4cfe877 100644 --- a/configure.ac +++ b/configure.ac @@ -671,6 +671,7 @@ AS_IF([test "x$enable_wayland_backend" != "xno"], AS_IF([test "x$have_wlroots" = "xyes"], [AC_DEFINE([USE_WAYLAND_BACKEND], [1], [Define to 1 to build the wlroots Wayland compositor backend]) + WLROOTS_CFLAGS="$WLROOTS_CFLAGS -DWLR_USE_UNSTABLE" supported_core="$supported_core WaylandBackend"], [AS_IF([test "x$enable_wayland_backend" = "xyes"], [AC_MSG_ERROR([wlroots >= 0.15, wayland-server, or xkbcommon not found])]) diff --git a/src/backend/backend.h b/src/backend/backend.h index a3a350c..b61b29b 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -46,6 +46,32 @@ struct WObjDescriptor; */ typedef struct WMBackend { + /* ------------------------------------------------------------------ */ + /* Display lifecycle (Phase 32) */ + /* ------------------------------------------------------------------ */ + + /* + * Open the display connection and return the native handle. + * X11: XOpenDisplay(name) -- returns Display*. + * Wayland: initialises the wl_display + wlroots compositor; returns NULL + * (no X11 Display* exists in the Wayland path). + * Called from main.c before StartUp(). Sets up any connection-level + * state (e.g. X11 close-on-exec flag). + */ + void *(*display_open)(const char *name); + + /* + * Close/destroy the display connection. + * Called during final shutdown after all screens have been closed. + */ + void (*display_close)(void); + + /* + * Return the number of logical screens (X11: ScreenCount; Wayland: 1). + * Called from main.c / StartUp() after display_open(). + */ + int (*display_screen_count)(void); + /* ------------------------------------------------------------------ */ /* Screen lifecycle (Phase 2) */ /* ------------------------------------------------------------------ */ diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 0d2353c..90b118a 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -4,6 +4,8 @@ * Phase 31: complete stub vtable. Every slot compiles and returns a safe * zero/null/false value. Subsequent phases will replace stubs with real * wlroots implementations one functional area at a time. + * Phase 32: display_open/close/screen_count implemented with wlroots headless + * backend. */ #ifdef HAVE_CONFIG_H @@ -12,6 +14,13 @@ #include #include +#include + +#include +#include +#include +#include +#include #include "../../WindowMaker.h" #include "../../screen.h" @@ -19,6 +28,92 @@ #include "../backend.h" #include "wl_backend.h" +/* ------------------------------------------------------------------ */ +/* Global compositor state */ +/* ------------------------------------------------------------------ */ + +struct wl_compositor_state { + struct wl_display *display; + struct wlr_backend *backend; + struct wlr_renderer *renderer; + int started; /* non-zero after successful display_open */ +}; + +static struct wl_compositor_state wl_state; + +/* ------------------------------------------------------------------ */ +/* Display lifecycle (Phase 32) */ +/* ------------------------------------------------------------------ */ + +static void * +wl_display_open(const char *name) +{ + (void)name; /* Wayland compositor picks its own socket name */ + + wlr_log_init(WLR_ERROR, NULL); + + wl_state.display = wl_display_create(); + if (!wl_state.display) { + wwarning("wl_backend: failed to create wl_display"); + return NULL; + } + + wl_state.backend = wlr_headless_backend_create(wl_state.display); + if (!wl_state.backend) { + wwarning("wl_backend: failed to create wlroots headless backend"); + wl_display_destroy(wl_state.display); + wl_state.display = NULL; + return NULL; + } + + wl_state.renderer = wlr_renderer_autocreate(wl_state.backend); + if (!wl_state.renderer) { + wwarning("wl_backend: failed to create wlroots renderer"); + wlr_backend_destroy(wl_state.backend); + wl_display_destroy(wl_state.display); + wl_state.backend = NULL; + wl_state.display = NULL; + return NULL; + } + + if (!wlr_backend_start(wl_state.backend)) { + wwarning("wl_backend: failed to start wlroots headless backend"); + wlr_renderer_destroy(wl_state.renderer); + wlr_backend_destroy(wl_state.backend); + wl_display_destroy(wl_state.display); + wl_state.renderer = NULL; + wl_state.backend = NULL; + wl_state.display = NULL; + return NULL; + } + + wl_state.started = 1; + return NULL; /* no X11 Display* in the Wayland path */ +} + +static void +wl_display_close(void) +{ + if (!wl_state.started) + return; + if (wl_state.renderer) + wlr_renderer_destroy(wl_state.renderer); + if (wl_state.backend) + wlr_backend_destroy(wl_state.backend); + if (wl_state.display) + wl_display_destroy(wl_state.display); + wl_state.renderer = NULL; + wl_state.backend = NULL; + wl_state.display = NULL; + wl_state.started = 0; +} + +static int +wl_display_screen_count(void) +{ + return wl_state.started ? 1 : 0; +} + /* ------------------------------------------------------------------ */ /* Screen open/close */ /* ------------------------------------------------------------------ */ @@ -435,6 +530,10 @@ static void wl_register_error_handlers(void) {} /* ------------------------------------------------------------------ */ const WMBackend wl_backend = { + .display_open = wl_display_open, + .display_close = wl_display_close, + .display_screen_count = wl_display_screen_count, + .screen_open = wl_screen_open, .screen_close = wl_screen_close, diff --git a/src/backend/x11/x11_backend.c b/src/backend/x11/x11_backend.c index 21681f5..870cf68 100644 --- a/src/backend/x11/x11_backend.c +++ b/src/backend/x11/x11_backend.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -70,6 +72,36 @@ struct WBackendScreen { int screen_number; /* X11 screen index */ }; +/* -------------------------------------------------------------------- */ +/* Display lifecycle (Phase 32) */ +/* -------------------------------------------------------------------- */ + +static void * +x11_display_open(const char *name) +{ + Display *d = XOpenDisplay(name); + if (!d) + return NULL; + if (fcntl(ConnectionNumber(d), F_SETFD, FD_CLOEXEC) < 0) + werror("error setting close-on-exec flag for X connection"); + return d; +} + +static void +x11_display_close(void) +{ + if (dpy) { + XCloseDisplay(dpy); + dpy = NULL; + } +} + +static int +x11_display_screen_count(void) +{ + return dpy ? ScreenCount(dpy) : 0; +} + /* -------------------------------------------------------------------- */ /* Screen lifecycle */ /* -------------------------------------------------------------------- */ @@ -2326,6 +2358,9 @@ x11_register_error_handlers(void) /* -------------------------------------------------------------------- */ const WMBackend x11_backend = { + .display_open = x11_display_open, + .display_close = x11_display_close, + .display_screen_count = x11_display_screen_count, .screen_open = x11_screen_open, .screen_close = x11_screen_close, .frame_create_toplevel = x11_frame_create_toplevel, diff --git a/src/main.c b/src/main.c index 3ba6c10..d6fae38 100644 --- a/src/main.c +++ b/src/main.c @@ -55,6 +55,11 @@ #include "main.h" #include "monitor.h" #include "misc.h" +#include "backend/backend.h" +#include "backend/x11/x11_backend.h" +#ifdef USE_WAYLAND_BACKEND +#include "backend/wayland/wl_backend.h" +#endif #include @@ -765,44 +770,48 @@ static int real_main(int argc, char **argv) *ptr = 0; } + /* Select backend before opening the display. */ +#ifdef USE_WAYLAND_BACKEND + if (getenv("WMAKER_USE_WAYLAND")) + wm_backend = &wl_backend; + else +#endif + wm_backend = &x11_backend; + /* open display */ - dpy = XOpenDisplay(DisplayName); - if (dpy == NULL) { + dpy = (Display *)wm_backend->display_open(DisplayName); + if (dpy == NULL && wm_backend == &x11_backend) { wfatal(_("could not open display \"%s\""), XDisplayName(DisplayName)); exit(1); } - if (fcntl(ConnectionNumber(dpy), F_SETFD, FD_CLOEXEC) < 0) { - werror("error setting close-on-exec flag for X connection"); - exit(1); + if (dpy != NULL) { + if (getWVisualID(0) < 0) { + /* + * If unspecified, use default visual instead of waiting + * for wrlib/context.c:bestContext() that may end up choosing + * the "fake" 24 bits added by the Composite extension. + * This is required to avoid all sort of corruptions when + * composite is enabled, and at a depth other than 24. + */ + setWVisualID(0, (int)DefaultVisual(dpy, DefaultScreen(dpy))->visualid); + } + + /* check if the user specified a complete display name (with screen). + * If so, only manage the specified screen */ + if (DisplayName) + pos = strchr(DisplayName, ':'); + else + pos = NULL; + + if (pos && sscanf(pos, ":%i.%i", &d, &s) == 2) + multiHead = False; + + DisplayName = XDisplayName(DisplayName); + setenv("DISPLAY", DisplayName, 1); + + wXModifierInitialize(); } - - - if (getWVisualID(0) < 0) { - /* - * If unspecified, use default visual instead of waiting - * for wrlib/context.c:bestContext() that may end up choosing - * the "fake" 24 bits added by the Composite extension. - * This is required to avoid all sort of corruptions when - * composite is enabled, and at a depth other than 24. - */ - setWVisualID(0, (int)DefaultVisual(dpy, DefaultScreen(dpy))->visualid); - } - - /* check if the user specified a complete display name (with screen). - * If so, only manage the specified screen */ - if (DisplayName) - pos = strchr(DisplayName, ':'); - else - pos = NULL; - - if (pos && sscanf(pos, ":%i.%i", &d, &s) == 2) - multiHead = False; - - DisplayName = XDisplayName(DisplayName); - setenv("DISPLAY", DisplayName, 1); - - wXModifierInitialize(); StartUp(!multiHead); if (w_global.screen_count == 1) diff --git a/src/startup.c b/src/startup.c index d32495a..753d327 100644 --- a/src/startup.c +++ b/src/startup.c @@ -49,9 +49,6 @@ #include "session.h" #include "defaults.h" #include "backend/x11/x11_backend.h" -#ifdef USE_WAYLAND_BACKEND -#include "backend/wayland/wl_backend.h" -#endif #include "properties.h" #include "dialog.h" #include "wmspec.h" @@ -516,19 +513,13 @@ void StartUp(Bool defaultScreenOnly) if (defaultScreenOnly) max = 1; else - max = ScreenCount(dpy); + max = wm_backend->display_screen_count(); wScreen = wmalloc(sizeof(WScreen *) * max); w_global.screen_count = 0; - /* Select the display backend before any screen is initialized. */ -#ifdef USE_WAYLAND_BACKEND - if (getenv("WMAKER_USE_WAYLAND")) - wm_backend = &wl_backend; - else -#endif - wm_backend = &x11_backend; + /* wm_backend is selected in real_main() before display_open(). */ /* Check if TIFF images are supported */ formats = RSupportedFileFormats();