wayland: Phase 34 — Wayland socket, output layout, real monitors_query
Create the compositor UNIX socket via wl_display_add_socket_auto so Wayland clients can connect; store socket name and set WAYLAND_DISPLAY. Add wlr_output_layout for multi-head tracking and implement monitors_query to return real 1920x1080 head geometry from the headless output. wl-smoke-test now verifies the socket file exists in XDG_RUNTIME_DIR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f7dfc50f26
commit
97a9209b4f
|
|
@ -6,6 +6,8 @@
|
|||
* wlroots implementations one functional area at a time.
|
||||
* Phase 32: display_open/close/screen_count implemented with wlroots headless
|
||||
* backend.
|
||||
* Phase 34: Wayland compositor socket created (clients can connect);
|
||||
* wlr_output_layout added; monitors_query returns real head geometry.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
@ -15,12 +17,15 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "../../WindowMaker.h"
|
||||
|
|
@ -34,22 +39,26 @@
|
|||
/* ------------------------------------------------------------------ */
|
||||
|
||||
struct wl_compositor_state {
|
||||
struct wl_display *display;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_output *output; /* headless output (screen 0) */
|
||||
int started; /* non-zero after successful display_open */
|
||||
struct wl_display *display;
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_output *output; /* headless output (screen 0) */
|
||||
struct wlr_output_layout *output_layout; /* Phase 34 */
|
||||
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;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Display lifecycle (Phase 32) */
|
||||
/* Display lifecycle (Phase 32 / Phase 34) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void *
|
||||
wl_display_open(const char *name)
|
||||
{
|
||||
const char *sock;
|
||||
|
||||
(void)name; /* Wayland compositor picks its own socket name */
|
||||
|
||||
wlr_log_init(WLR_ERROR, NULL);
|
||||
|
|
@ -89,8 +98,29 @@ wl_display_open(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Phase 34: create the UNIX socket so Wayland clients can connect. */
|
||||
sock = wl_display_add_socket_auto(wl_state.display);
|
||||
if (!sock) {
|
||||
wwarning("wl_backend: failed to create Wayland compositor socket");
|
||||
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;
|
||||
}
|
||||
snprintf(wl_state.socket_name, sizeof(wl_state.socket_name), "%s", sock);
|
||||
setenv("WAYLAND_DISPLAY", wl_state.socket_name, 1);
|
||||
wwarning("wl_backend: compositor socket WAYLAND_DISPLAY=%s", wl_state.socket_name);
|
||||
|
||||
/* Phase 34: output layout for multi-head geometry tracking. */
|
||||
wl_state.output_layout = wlr_output_layout_create();
|
||||
|
||||
/* Add a single 1920×1080 headless output (screen 0). */
|
||||
wl_state.output = wlr_headless_add_output(wl_state.backend, 1920, 1080);
|
||||
if (wl_state.output && wl_state.output_layout)
|
||||
wlr_output_layout_add_auto(wl_state.output_layout, wl_state.output);
|
||||
|
||||
wl_state.started = 1;
|
||||
return NULL; /* no X11 Display* in the Wayland path */
|
||||
|
|
@ -101,15 +131,21 @@ wl_display_close(void)
|
|||
{
|
||||
if (!wl_state.started)
|
||||
return;
|
||||
if (wl_state.output_layout) {
|
||||
wlr_output_layout_destroy(wl_state.output_layout);
|
||||
wl_state.output_layout = NULL;
|
||||
}
|
||||
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);
|
||||
unsetenv("WAYLAND_DISPLAY");
|
||||
wl_state.renderer = NULL;
|
||||
wl_state.backend = NULL;
|
||||
wl_state.display = NULL;
|
||||
wl_state.output = NULL;
|
||||
wl_state.started = 0;
|
||||
}
|
||||
|
||||
|
|
@ -527,7 +563,40 @@ static void wl_refresh_desktop(WScreen *scr) { (void)scr; }
|
|||
|
||||
static void
|
||||
wl_monitors_query(WScreen *scr, WHeadGeometry **heads_out, int *count_out)
|
||||
{ (void)scr; *heads_out = NULL; *count_out = 0; }
|
||||
{
|
||||
(void)scr;
|
||||
|
||||
if (!wl_state.output) {
|
||||
*heads_out = NULL;
|
||||
*count_out = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Phase 34: return the single headless output as head 0. */
|
||||
WHeadGeometry *heads = wmalloc(sizeof(WHeadGeometry));
|
||||
|
||||
if (wl_state.output_layout) {
|
||||
const struct wlr_box *box =
|
||||
wlr_output_layout_get_box(wl_state.output_layout, wl_state.output);
|
||||
if (box) {
|
||||
heads[0].x = box->x;
|
||||
heads[0].y = box->y;
|
||||
heads[0].width = box->width;
|
||||
heads[0].height = box->height;
|
||||
} else {
|
||||
heads[0].x = heads[0].y = 0;
|
||||
heads[0].width = (int)wl_state.output->width;
|
||||
heads[0].height = (int)wl_state.output->height;
|
||||
}
|
||||
} else {
|
||||
heads[0].x = heads[0].y = 0;
|
||||
heads[0].width = (int)wl_state.output->width;
|
||||
heads[0].height = (int)wl_state.output->height;
|
||||
}
|
||||
|
||||
*heads_out = heads;
|
||||
*count_out = 1;
|
||||
}
|
||||
|
||||
static void wl_monitors_select_events(WScreen *scr) { (void)scr; }
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
# 2. wmaker links against wlroots
|
||||
# 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
|
||||
#
|
||||
# This test grows as wl_backend vtable slots are implemented.
|
||||
#
|
||||
|
|
@ -49,12 +50,13 @@ ldd "$WMAKER" 2>/dev/null | grep -qi 'wlroots\|libwlr' \
|
|||
# WMAKER_USE_WAYLAND=1 selects wl_backend.
|
||||
#
|
||||
# The test waits for the process to be alive (in the event loop) then
|
||||
# sends SIGTERM and checks for clean exit.
|
||||
# verifies the Wayland socket was created, sends SIGTERM, and checks
|
||||
# for clean exit.
|
||||
|
||||
WMAKER_USE_WAYLAND=1 src/wmaker \
|
||||
--no-dock --no-clip --no-autolaunch \
|
||||
--dont-restore --static \
|
||||
--for-real &
|
||||
--for-real 2>/tmp/wl-smoke-stderr &
|
||||
WM_PID=$!
|
||||
|
||||
# Wait up to 5s for wmaker to reach the event loop (stay alive)
|
||||
|
|
@ -68,7 +70,33 @@ done
|
|||
kill -0 "$WM_PID" 2>/dev/null \
|
||||
|| die "wmaker exited prematurely before SIGTERM (crashed during startup)"
|
||||
|
||||
# Send SIGTERM and wait for clean exit
|
||||
# -- 4. Wayland compositor socket must exist in XDG_RUNTIME_DIR -----------
|
||||
#
|
||||
# Phase 34: wl_display_open() calls wl_display_add_socket_auto() and logs:
|
||||
# "wl_backend: compositor socket WAYLAND_DISPLAY=<name>"
|
||||
# Parse the socket name from stderr and verify the socket file exists.
|
||||
|
||||
RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
|
||||
WL_SOCK=""
|
||||
i=0
|
||||
while [ $i -lt 20 ]; do
|
||||
WL_SOCK=$(grep -o 'WAYLAND_DISPLAY=[^ ]*' /tmp/wl-smoke-stderr 2>/dev/null \
|
||||
| head -1 | sed 's/WAYLAND_DISPLAY=//')
|
||||
[ -n "$WL_SOCK" ] && break
|
||||
sleep 0.1
|
||||
i=$(( i + 1 ))
|
||||
done
|
||||
|
||||
[ -n "$WL_SOCK" ] \
|
||||
|| die "wmaker did not log WAYLAND_DISPLAY socket name in stderr"
|
||||
|
||||
[ -S "$RUNTIME_DIR/$WL_SOCK" ] \
|
||||
|| die "Wayland compositor socket $RUNTIME_DIR/$WL_SOCK not found"
|
||||
|
||||
echo " socket check: $RUNTIME_DIR/$WL_SOCK exists"
|
||||
|
||||
# -- Send SIGTERM and wait for clean exit ---------------------------------
|
||||
kill -TERM "$WM_PID" 2>/dev/null
|
||||
WM_EXIT=0
|
||||
wait "$WM_PID" 2>/dev/null || WM_EXIT=$?
|
||||
|
|
@ -81,5 +109,5 @@ WM_PID=""
|
|||
|| die "wmaker exited with status $WM_EXIT after SIGTERM (expected 0)"
|
||||
|
||||
# -- Done -----------------------------------------------------------------
|
||||
echo "PASS (wl_backend compositor starts and exits cleanly)"
|
||||
echo "PASS (wl_backend compositor starts, socket created, exits cleanly)"
|
||||
exit 0
|
||||
|
|
|
|||
Loading…
Reference in New Issue