wayland: Phase 36 — wl_shm, wl_output, XDG toplevel listener

Advertise wl_shm (via wlr_renderer_init_wl_shm) and expose the headless
output as a wl_output global so SHM buffer clients can render.  Wire up
the xdg_shell new_surface listener to track incoming XDG toplevels
(management hook placeholder).  wl-smoke-test now verifies wl_shm and
wl_output in the registry and that weston-simple-shm can connect without
crashing the compositor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-27 23:12:21 +01:00
parent 075b648021
commit 2182ec0fc1
2 changed files with 64 additions and 2 deletions

View File

@ -10,6 +10,7 @@
* wlr_output_layout added; monitors_query returns real head geometry.
* Phase 35: Core Wayland protocol globals advertised (wl_compositor,
* wl_subcompositor, wl_seat, wl_data_device_manager, xdg_wm_base).
* Phase 36: wl_shm and wl_output advertised; XDG toplevel listener wired.
*/
#ifdef HAVE_CONFIG_H
@ -57,12 +58,38 @@ struct wl_compositor_state {
struct wlr_seat *seat;
struct wlr_data_device_manager *data_device_mgr;
struct wlr_xdg_shell *xdg_shell;
/* Phase 36: XDG toplevel tracking */
struct wl_listener xdg_new_surface_listener;
int managed_surface_count; /* surfaces seen */
char socket_name[64]; /* Phase 34: e.g. "wayland-0" */
int started; /* non-zero after successful display_open */
};
static struct wl_compositor_state wl_state;
/* ------------------------------------------------------------------ */
/* Phase 36: XDG surface / toplevel management */
/* ------------------------------------------------------------------ */
static void
handle_xdg_new_surface(struct wl_listener *listener, void *data)
{
struct wlr_xdg_surface *xdg_surface = data;
(void)listener;
if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
return; /* ignore popups for now */
wl_state.managed_surface_count++;
wwarning("wl_backend: new XDG toplevel #%d (app_id=%s title=%s)",
wl_state.managed_surface_count,
xdg_surface->toplevel->app_id ? xdg_surface->toplevel->app_id : "(none)",
xdg_surface->toplevel->title ? xdg_surface->toplevel->title : "(none)");
/* TODO: create WWindow and call policy layer (wManageWindow equivalent)
* once the surface is committed (use map event on toplevel). */
}
/* ------------------------------------------------------------------ */
/* Display lifecycle (Phase 32 / Phase 34) */
/* ------------------------------------------------------------------ */
@ -143,6 +170,17 @@ wl_display_open(const char *name)
wlr_data_device_manager_create(wl_state.display);
wl_state.xdg_shell = wlr_xdg_shell_create(wl_state.display);
/* Phase 36: advertise wl_shm (needed by SHM buffer clients) and
* expose the headless output as a wl_output global. */
wlr_renderer_init_wl_shm(wl_state.renderer, wl_state.display);
if (wl_state.output)
wlr_output_create_global(wl_state.output);
/* Phase 36: listen for new XDG toplevel surfaces. */
wl_state.xdg_new_surface_listener.notify = handle_xdg_new_surface;
wl_signal_add(&wl_state.xdg_shell->events.new_surface,
&wl_state.xdg_new_surface_listener);
wl_state.started = 1;
return NULL; /* no X11 Display* in the Wayland path */
}

View File

@ -10,8 +10,10 @@
# 3. wmaker starts with WMAKER_USE_WAYLAND=1 and reaches the event loop
# without crashing (verified by sending SIGTERM and checking exit status)
# 4. (Phase 34) A Wayland compositor socket is created in XDG_RUNTIME_DIR
# 5. (Phase 35) Core Wayland globals are advertised (wl_compositor, wl_seat,
# 5. (Phase 35) Core Wayland globals advertised (wl_compositor, wl_seat,
# xdg_wm_base) — verified via weston-info if available
# 6. (Phase 36) wl_shm and wl_output advertised; a real SHM client
# (weston-simple-shm) can connect without crashing the compositor
#
# This test grows as wl_backend vtable slots are implemented.
#
@ -111,11 +113,33 @@ if command -v weston-info >/dev/null 2>&1; then
|| die "wl_seat not in Wayland global registry"
echo "$WI" | grep -q 'xdg_wm_base' \
|| die "xdg_wm_base not in Wayland global registry"
echo " globals check: wl_compositor, wl_seat, xdg_wm_base present"
# Phase 36 additions
echo "$WI" | grep -q 'wl_shm' \
|| die "wl_shm not in Wayland global registry"
echo "$WI" | grep -q 'wl_output' \
|| die "wl_output not in Wayland global registry"
echo " globals check: wl_compositor, wl_seat, xdg_wm_base, wl_shm, wl_output present"
else
echo " globals check: skipped (weston-info not installed)"
fi
# -- 6. A real SHM client must connect without crashing the compositor ----
#
# Phase 36: launch weston-simple-shm briefly; if it finds "No wl_shm global"
# in its output the compositor is missing wl_shm. We just check the
# compositor is still alive after the client runs (or times out).
if command -v weston-simple-shm >/dev/null 2>&1; then
CLIENT_OUT=$(WAYLAND_DISPLAY="$WL_SOCK" timeout 2s weston-simple-shm 2>&1) || true
echo "$CLIENT_OUT" | grep -q 'No wl_shm global' \
&& die "weston-simple-shm: compositor missing wl_shm"
kill -0 "$WM_PID" 2>/dev/null \
|| die "compositor crashed after weston-simple-shm connected"
echo " client check: weston-simple-shm connected; compositor survived"
else
echo " client check: skipped (weston-simple-shm not installed)"
fi
# -- Send SIGTERM and wait for clean exit ---------------------------------
kill -TERM "$WM_PID" 2>/dev/null
WM_EXIT=0