wayland: Phase 32 — display_open/close/screen_count through vtable

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 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-27 22:35:54 +01:00
parent e8e230b2db
commit d07362b90e
6 changed files with 204 additions and 43 deletions

View File

@ -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])])

View File

@ -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) */
/* ------------------------------------------------------------------ */

View File

@ -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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/headless.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/util/log.h>
#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,

View File

@ -14,6 +14,8 @@
#include <string.h>
#include <time.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
@ -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,

View File

@ -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 <WINGs/WUtil.h>
@ -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)

View File

@ -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();