diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 73ef75a..c91726f 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -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 */ } diff --git a/tests/wl-smoke-test.sh b/tests/wl-smoke-test.sh index d28e7f1..1647a10 100755 --- a/tests/wl-smoke-test.sh +++ b/tests/wl-smoke-test.sh @@ -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