diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index be3373f..ee541c4 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -113,7 +113,11 @@ #include /* Phase 18: buffer allocator */ #include /* Phase 23: hardware cursor tracking */ #include /* Phase 23: xcursor theme */ -#include /* Phase 25: clipboard / selection */ +#include /* Phase 25: clipboard / selection */ +#include /* Phase 26: primary selection (middle-click) */ +#include /* Phase 26: zwp_primary_selection_device_manager_v1 */ +#include /* Phase 27: xdg-output for panel geometry */ +#include /* Phase 28: idle inhibit for video/fullscreen */ #include /* Generated xdg-shell protocol implementation (Wayland glue code) */ #include "protocols/xdg-shell-protocol.c" @@ -263,6 +267,14 @@ struct wl_compositor_state { struct wl_listener seat_request_cursor_listener; /* Phase 25: clipboard — seat selection request listener. */ struct wl_listener seat_request_set_selection_listener; + /* Phase 26: primary selection (middle-click paste). */ + struct wlr_primary_selection_v1_device_manager *primary_selection_mgr; + struct wl_listener seat_request_primary_selection_listener; + /* Phase 27: xdg-output manager for logical output geometry. */ + struct wlr_xdg_output_manager_v1 *xdg_output_mgr; + /* Phase 28: idle-inhibit manager for video players / fullscreen apps. */ + struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; + struct wl_listener idle_new_inhibitor_listener; }; static struct wl_compositor_state wl_state; @@ -325,6 +337,10 @@ static struct wlr_surface *view_surface_at(int px, int py, double *sx_out, static void handle_seat_request_cursor(struct wl_listener *listener, void *data); /* Phase 25: client clipboard selection request handler. */ static void handle_seat_request_set_selection(struct wl_listener *listener, void *data); +/* Phase 26: primary selection request handler. */ +static void handle_seat_request_primary_selection(struct wl_listener *listener, void *data); +/* Phase 28: idle inhibitor created/destroyed handler. */ +static void handle_idle_new_inhibitor(struct wl_listener *listener, void *data); /* Phase 17: XWayland new surface forward declaration. */ static void handle_xwayland_new_surface(struct wl_listener *listener, void *data); /* Phase 20: nested backend real input device forward declaration. */ @@ -1464,6 +1480,39 @@ wl_display_open(const char *name) &wl_state.seat_request_set_selection_listener); wwarning("wl_backend: clipboard selection wired"); } + + /* Phase 26: primary selection (middle-click paste) via + * zwp_primary_selection_device_manager_v1. */ + wl_state.primary_selection_mgr = + wlr_primary_selection_v1_device_manager_create(wl_state.display); + if (wl_state.primary_selection_mgr && wl_state.seat) { + wl_state.seat_request_primary_selection_listener.notify = + handle_seat_request_primary_selection; + wl_signal_add(&wl_state.seat->events.request_set_primary_selection, + &wl_state.seat_request_primary_selection_listener); + wwarning("wl_backend: primary selection (middle-click) wired"); + } + + /* Phase 27: xdg-output — panels and HiDPI apps query logical output + * geometry via zxdg_output_manager_v1. Requires output_layout. */ + if (wl_state.output_layout) { + wl_state.xdg_output_mgr = + wlr_xdg_output_manager_v1_create(wl_state.display, + wl_state.output_layout); + if (wl_state.xdg_output_mgr) + wwarning("wl_backend: xdg-output-manager created"); + } + + /* Phase 28: idle-inhibit — video players and games create inhibitor + * objects to suppress screen blanking while active. */ + wl_state.idle_inhibit_mgr = + wlr_idle_inhibit_v1_create(wl_state.display); + if (wl_state.idle_inhibit_mgr) { + wl_state.idle_new_inhibitor_listener.notify = handle_idle_new_inhibitor; + wl_signal_add(&wl_state.idle_inhibit_mgr->events.new_inhibitor, + &wl_state.idle_new_inhibitor_listener); + wwarning("wl_backend: idle-inhibit manager created"); + } wl_state.xdg_shell = wlr_xdg_shell_create(wl_state.display); /* Phase 64: advertise zxdg_decoration_manager_v1 so clients that @@ -1756,6 +1805,9 @@ wl_display_close(void) /* Phase 24/25: seat cursor + selection listeners */ WL_LISTENER_REMOVE(wl_state.seat_request_cursor_listener); WL_LISTENER_REMOVE(wl_state.seat_request_set_selection_listener); + /* Phase 26/28: primary selection + idle inhibitor listeners */ + WL_LISTENER_REMOVE(wl_state.seat_request_primary_selection_listener); + WL_LISTENER_REMOVE(wl_state.idle_new_inhibitor_listener); #undef WL_LISTENER_REMOVE /* Phase 23: destroy cursor and xcursor manager before display teardown. */ @@ -2092,6 +2144,37 @@ handle_seat_request_set_selection(struct wl_listener *listener, void *data) wlr_seat_set_selection(wl_state.seat, ev->source, ev->serial); } +/* + * Phase 26: seat request_set_primary_selection — client writes to the + * primary selection buffer (e.g. by selecting text). Forward to + * wlr_seat so middle-click paste works in other clients. + */ +static void +handle_seat_request_primary_selection(struct wl_listener *listener, void *data) +{ + (void)listener; + struct wlr_seat_request_set_primary_selection_event *ev = data; + if (!wl_state.seat) + return; + wlr_seat_set_primary_selection(wl_state.seat, ev->source, ev->serial); +} + +/* + * Phase 28: idle_inhibit new_inhibitor — a client (e.g. mpv, a game) created + * an idle-inhibit object. wlroots tracks the inhibitor list internally; + * the compositor can query wl_state.idle_inhibit_mgr->inhibitors to decide + * whether to suppress screen blanking. For now we just log the event so + * the capability is advertised and the inhibitor object doesn't error out. + */ +static void +handle_idle_new_inhibitor(struct wl_listener *listener, void *data) +{ + (void)listener; + struct wlr_idle_inhibitor_v1 *inhibitor = data; + (void)inhibitor; + wwarning("wl_backend: idle inhibitor created (client suppressing screen blank)"); +} + static void handle_pointer_button(struct wl_listener *listener, void *data) { diff --git a/tests/wl-smoke-test.sh b/tests/wl-smoke-test.sh index b1bf7c3..6e69b50 100755 --- a/tests/wl-smoke-test.sh +++ b/tests/wl-smoke-test.sh @@ -147,6 +147,15 @@ # handlers now start a compositor-side grab that tracks pointer motion # and repositions/resizes the window in the scene graph. Button release # ends the grab. Build-only check (no client sends request_move here). +# 45. (Phase 26) wl_subcompositor already advertised by wlr_compositor_create +# (embedded in wlr_compositor struct); verified via weston-info. +# zwp_primary_selection_device_manager_v1 created; seat +# request_set_primary_selection wired → wlr_seat_set_primary_selection +# so middle-click paste propagates between clients. +# 46. (Phase 27) zxdg_output_manager_v1 created from output_layout so panels +# and HiDPI apps can query logical output geometry. +# 47. (Phase 28) zwp_idle_inhibit_manager_v1 created; new_inhibitor wired so +# video players and games can suppress screen blanking. # 38. (Phase 11) noclip/nodock set in wl_screen_create_internals: wDockCreate # requires X11 rendering resources unavailable in Wayland mode; disabling # the dock/clip prevents crashes when wWorkspaceNew is called to create @@ -297,6 +306,15 @@ grep -q 'clipboard selection wired' /tmp/wl-smoke-stderr \ || die "compositor did not log clipboard wired (seat request_set_selection listener missing)" echo " clipboard check: clipboard selection wired" +# -- 4f2c. Phases 26-28: primary selection + xdg-output + idle-inhibit ---- +grep -q 'primary selection.*wired' /tmp/wl-smoke-stderr \ + || die "compositor did not log primary selection wired" +grep -q 'xdg-output-manager created' /tmp/wl-smoke-stderr \ + || die "compositor did not log xdg-output-manager created" +grep -q 'idle-inhibit manager created' /tmp/wl-smoke-stderr \ + || die "compositor did not log idle-inhibit manager created" +echo " protocols check: primary-selection, xdg-output, idle-inhibit created" + # -- 4f3. Phase 23: cursor created and xcursor theme loaded --------------- grep -q 'cursor created, xcursor theme loaded' /tmp/wl-smoke-stderr \ || die "compositor did not log cursor creation (wlr_cursor_create or xcursor_manager_create failed)" @@ -359,7 +377,20 @@ if command -v weston-info >/dev/null 2>&1; then # Phase 64: zxdg_decoration_manager_v1 must be in the global registry echo "$WI" | grep -q 'zxdg_decoration_manager_v1' \ || die "zxdg_decoration_manager_v1 not in Wayland global registry" - echo " globals check: wl_compositor, wl_seat, xdg_wm_base, wl_shm, wl_output, zxdg_decoration_manager_v1 present; seat has pointer capability" + # Phase 26: wl_subcompositor (subsurfaces for Chromium, Firefox, etc.) + echo "$WI" | grep -q 'wl_subcompositor' \ + || die "wl_subcompositor not in Wayland global registry" + # Phase 26: primary selection (middle-click paste) + echo "$WI" | grep -q 'zwp_primary_selection_device_manager_v1' \ + || die "zwp_primary_selection_device_manager_v1 not in Wayland global registry" + # Phase 27: xdg-output (panel/HiDPI logical geometry) + echo "$WI" | grep -q 'zxdg_output_manager_v1' \ + || die "zxdg_output_manager_v1 not in Wayland global registry" + # Phase 28: idle-inhibit (video players, games) + echo "$WI" | grep -q 'zwp_idle_inhibit_manager_v1' \ + || die "zwp_idle_inhibit_manager_v1 not in Wayland global registry" + echo " globals check: wl_compositor, wl_subcompositor, wl_seat, xdg_wm_base, wl_shm, wl_output," \ + "zxdg_decoration_manager_v1, zwp_primary_selection, zxdg_output, zwp_idle_inhibit present" else echo " globals check: skipped (weston-info not installed)" fi