wayland: Phases 26-28 — subcompositor, primary selection, xdg-output, idle-inhibit

Phase 26 — wl_subcompositor + primary selection (middle-click paste):
  wl_subcompositor is already advertised by wlr_compositor_create (the
  wlr_subcompositor is embedded in wlr_compositor); confirmed via weston-info.
  zwp_primary_selection_device_manager_v1 created via
  wlr_primary_selection_v1_device_manager_create().  seat.request_set_primary_
  selection wired to handle_seat_request_primary_selection which calls
  wlr_seat_set_primary_selection, so text selected in one client is available
  for middle-click paste in any other client.

Phase 27 — zxdg_output_manager_v1:
  wlr_xdg_output_manager_v1_create(display, output_layout) advertises the
  xdg-output protocol.  Panel clients (waybar, etc.) and HiDPI-aware apps
  use this to query the logical position and size of each output, which may
  differ from the physical pixel dimensions under scaling.

Phase 28 — zwp_idle_inhibit_manager_v1:
  wlr_idle_inhibit_v1_create() advertises the idle-inhibit protocol.  The
  new_inhibitor signal is wired to handle_idle_new_inhibitor which logs the
  event; the inhibitor list on wl_state.idle_inhibit_mgr can be queried by
  a future idle/DPMS implementation to suppress screen blanking while any
  inhibitor is live.

Smoke test: "protocols check" verifies all three startup log lines; the
weston-info globals check now also asserts wl_subcompositor,
zwp_primary_selection_device_manager_v1, zxdg_output_manager_v1, and
zwp_idle_inhibit_manager_v1 are present (25/25 checks pass).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-30 17:13:03 +02:00
parent 52c6ef9326
commit aac488641d
2 changed files with 116 additions and 2 deletions

View File

@ -113,7 +113,11 @@
#include <wlr/render/allocator.h> /* Phase 18: buffer allocator */
#include <wlr/types/wlr_cursor.h> /* Phase 23: hardware cursor tracking */
#include <wlr/types/wlr_xcursor_manager.h> /* Phase 23: xcursor theme */
#include <wlr/types/wlr_data_device.h> /* Phase 25: clipboard / selection */
#include <wlr/types/wlr_data_device.h> /* Phase 25: clipboard / selection */
#include <wlr/types/wlr_primary_selection.h> /* Phase 26: primary selection (middle-click) */
#include <wlr/types/wlr_primary_selection_v1.h> /* Phase 26: zwp_primary_selection_device_manager_v1 */
#include <wlr/types/wlr_xdg_output_v1.h> /* Phase 27: xdg-output for panel geometry */
#include <wlr/types/wlr_idle_inhibit_v1.h> /* Phase 28: idle inhibit for video/fullscreen */
#include <wlr/util/box.h>
/* 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)
{

View File

@ -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