wayland: Phase 63 — DELETE_WINDOW=1 for Wayland; wClientSendProtocol dispatches client_close

All XDG toplevels support polite close via wlr_xdg_toplevel_send_close.
PropGetProtocols now sets DELETE_WINDOW=1 in the Wayland path so
wManageWindow sets kill_close=0 (prefer polite close over force-kill)
and the MC_CLOSE menu item is enabled for Wayland windows.

wClientSendProtocol dispatches wm_backend->client_close in the Wayland
path instead of returning early; since all atoms are 0 in Wayland, atom
comparison is unreliable, but all callers that reach wClientSendProtocol
are requesting a polite close — the only Wayland-meaningful WM_PROTOCOL.

wManageWindow succeeded log gains a kill_close= field; smoke test check
21 verifies kill_close=0 for each managed Wayland toplevel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-28 09:24:22 +01:00
parent 6764c14863
commit 36b024d849
4 changed files with 35 additions and 6 deletions

View File

@ -47,6 +47,10 @@
* and calls wlr_seat_keyboard_clear_focus; wl_focus_set recognises
* WNATIVE_NONE as "clear focus" and calls wlr_seat_keyboard_clear_focus
* instead of delivering focus to a nonexistent surface.
* Phase 63: PropGetProtocols sets DELETE_WINDOW=1 for all Wayland windows
* (all XDG toplevels support close); wClientSendProtocol dispatches
* client_close in the Wayland path so MC_CLOSE is enabled and kill_close=0.
* wManageWindow succeeded log now includes kill_close= field.
*/
#ifdef HAVE_CONFIG_H
@ -241,11 +245,12 @@ handle_toplevel_map(struct wl_listener *listener, void *data)
if (wwin) {
int pid = wl_client_get_pid(view->id);
wwarning("wl_backend: wManageWindow succeeded id=0x%lx "
"class=%s name=%s geo=%dx%d pid=%d",
"class=%s name=%s geo=%dx%d pid=%d kill_close=%d",
view->id,
wwin->wm_class ? wwin->wm_class : "(none)",
wwin->wm_instance ? wwin->wm_instance : "(none)",
wwin->client.width, wwin->client.height, pid);
wwin->client.width, wwin->client.height, pid,
wwin->client_flags.kill_close);
/* Phase 62: focus delivered by wManageWindow via wSetFocusTo
* (auto_focus=1 set in wl_screen_create_internals); the
* direct wl_focus_set() call is no longer needed here. */

View File

@ -250,8 +250,14 @@ void wClientSendProtocol(WWindow * wwin, Atom protocol, Time time)
{
XEvent event;
if (!dpy)
return; /* Wayland: no X11 ClientMessage */
if (!dpy) {
/* Phase 63: Wayland — there are no X11 ClientMessages. All atoms
* are 0 in the Wayland path so atom comparison is unreliable; all
* callers that reach here are requesting a polite close (the only
* Wayland-meaningful WM_PROTOCOL), so dispatch client_close. */
wm_backend->client_close(wwin->client_win);
return;
}
event.xclient.type = ClientMessage;
event.xclient.message_type = w_global.atom.wm.protocols;

View File

@ -41,8 +41,13 @@ void PropGetProtocols(Window window, WProtocols * prots)
int count, i;
memset(prots, 0, sizeof(WProtocols));
if (!dpy)
return; /* Wayland: no ICCCM WM_PROTOCOLS */
if (!dpy) {
/* Phase 63: all XDG toplevels support close (wlr_xdg_toplevel_send_close).
* Advertise DELETE_WINDOW so wManageWindow sets kill_close=0 and the
* close menu item is enabled. */
prots->DELETE_WINDOW = 1;
return;
}
if (!XGetWMProtocols(dpy, window, &protocols, &count)) {
return;
}

View File

@ -44,6 +44,9 @@
# 20. (Phase 62) wl_screen_create_internals sets no_focus_win=WNATIVE_NONE;
# wl_focus_set(WNATIVE_NONE) calls wlr_seat_keyboard_clear_focus and logs
# "focus_clear" when the last managed window unmaps.
# 21. (Phase 63) PropGetProtocols sets DELETE_WINDOW=1 for Wayland windows;
# wClientSendProtocol dispatches client_close so MC_CLOSE is enabled and
# polite close works; verified by wManageWindow logging kill_close=0.
#
# This test grows as wl_backend vtable slots are implemented.
#
@ -233,6 +236,16 @@ if command -v weston-simple-shm >/dev/null 2>&1; then
|| die "compositor did not log 'focus_clear' (wl_focus_set WNATIVE_NONE path not reached)"
echo " focus_clear check: keyboard focus cleared after last window unmap"
# -- 21. Phase 63: DELETE_WINDOW=1 → kill_close=0 for Wayland toplevels --
#
# PropGetProtocols now sets DELETE_WINDOW=1 for all Wayland windows so
# wManageWindow sets kill_close=0 (polite close preferred over force-kill).
# Verified by the kill_close= field in the wManageWindow succeeded log.
KC=$(grep -o 'kill_close=[0-9]*' /tmp/wl-smoke-stderr | head -1 | sed 's/kill_close=//')
[ "$KC" = "0" ] \
|| die "expected kill_close=0 for Wayland toplevel (DELETE_WINDOW not set?), got kill_close=${KC:-missing}"
echo " kill_close check: kill_close=0 (DELETE_WINDOW=1, polite close enabled)"
# -- 15. Phase 51: two simultaneous clients both managed --------------
#
# Launch two weston-simple-shm processes in parallel (2s and 3s).