Files
punktfunk/crates/lumen-host/protocols/zkde-screencast-unstable-v1.xml
T
enricobuehler 7d08e43c16 feat: M2 — KWin virtual-output backend behind a VirtualDisplay trait (native client resolution)
Honor the client's requested resolution by rendering a compositor virtual output at
exactly that size — native, headless, no scaling. There is no cross-compositor Wayland
protocol for this, so it's a per-compositor backend behind the (previously stubbed)
VirtualDisplay trait.

- vdisplay.rs: VirtualDisplay::create(mode) now returns a live VirtualOutput
  { node_id, remote_fd: Option<OwnedFd>, keepalive } with RAII teardown (drop releases
  the output) instead of an inert OutputHandle + explicit destroy. Add compositor
  detect() (LUMEN_COMPOSITOR / XDG_CURRENT_DESKTOP).
- vdisplay/kwin.rs: the KWin backend — the zkde_screencast_unstable_v1 stream_virtual_output
  client (vendored protocol XML + wayland-scanner codegen). Creates a WxH output, returns
  its PipeWire node (default daemon, remote_fd=None); a keepalive thread holds the Wayland
  connection until dropped. (Moved here from capture/kwin.rs — it's a vdisplay backend, not
  capture.)
- capture: generalize the PipeWire consumer to Option<OwnedFd> (portal remote vs. default
  daemon) and add capture_virtual_output(vout), compositor-agnostic, owning the keepalive.
- gamestream/stream.rs: LUMEN_VIDEO_SOURCE=virtual creates a virtual display sized to the
  client's cfg and captures it (self-contained, not pooled — a reconnect at a new
  resolution gets a fresh output).
- m0: --source kwin-virtual goes through the trait.

Verified end-to-end against the running headless KWin: the request reaches the compositor
and is handled cleanly. Native creation needs a backend implementing createVirtualOutput —
the DRM backend, or the VirtualBackend since KWin 6.5.6; on this box's --virtual 6.4.5 it
returns "Could not find output" (expected; validates after the KWin upgrade). wlroots/Mutter
backends are the next ones to land on the same seam.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 17:30:02 +00:00

106 lines
6.0 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<protocol name="zkde_screencast_unstable_v1">
<copyright><![CDATA[
SPDX-FileCopyrightText: 2020-2021 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: LGPL-2.1-or-later
]]></copyright>
<interface name="zkde_screencast_unstable_v1" version="6">
<description summary="Protocol for managing PipeWire feeds of the different displays and windows">
Warning! The protocol described in this file is a desktop environment
implementation detail. Regular clients must not use this protocol.
Backward incompatible changes may be added without bumping the major
version of the extension.
</description>
<enum name="pointer">
<description summary="Stream consumer attachment attributes" />
<entry name="hidden" value="1" summary="No cursor"/>
<entry name="embedded" value="2" summary="Render the cursor on the stream"/>
<entry name="metadata" value="4" summary="Send metadata about where the cursor is through PipeWire"/>
</enum>
<request name="stream_output">
<description summary="requests a feed from a given source"/>
<arg name="stream" type="new_id" interface="zkde_screencast_stream_unstable_v1"/>
<arg name="output" type="object" interface="wl_output"/>
<arg name="pointer" type="uint" summary="Requested pointer mode"/>
</request>
<request name="stream_window">
<description summary="requests a feed from a given source"/>
<arg name="stream" type="new_id" interface="zkde_screencast_stream_unstable_v1"/>
<arg name="window_uuid" type="string" summary="window Identifier"/>
<arg name="pointer" type="uint" summary="Requested pointer mode"/>
</request>
<request name="destroy" type="destructor">
<description summary="Destroy the zkde_screencast_unstable_v1">
Destroy the zkde_screencast_unstable_v1 object.
</description>
</request>
<request name="stream_virtual_output" since="2">
<description summary="requests a feed from a new virtual output"/>
<arg name="stream" type="new_id" interface="zkde_screencast_stream_unstable_v1"/>
<arg name="name" type="string" summary="name of the created output"/>
<arg name="width" type="int" summary="Logical width resolution"/>
<arg name="height" type="int" summary="Logical height resolution"/>
<arg name="scale" type="fixed" summary="Scaling factor of the display where it's to be displayed"/>
<arg name="pointer" type="uint" summary="Requested pointer mode"/>
</request>
<request name="stream_region" since="3">
<description summary="requests a feed from region in the workspace">
Since version 5, the compositor will choose the highest scale
factor for the region if the given scale is 0.0.
</description>
<arg name="stream" type="new_id" interface="zkde_screencast_stream_unstable_v1"/>
<arg name="x" type="int" summary="Logical left position"/>
<arg name="y" type="int" summary="Logical top position"/>
<arg name="width" type="uint" summary="Logical width resolution"/>
<arg name="height" type="uint" summary="Logical height resolution"/>
<arg name="scale" type="fixed" summary="Scaling factor of the output recording"/>
<arg name="pointer" type="uint" summary="Requested pointer mode"/>
</request>
<request name="stream_virtual_output_with_description" since="4">
<description summary="requests a feed from a new virtual output"/>
<arg name="stream" type="new_id" interface="zkde_screencast_stream_unstable_v1"/>
<arg name="name" type="string" summary="name of the created output"/>
<arg name="description" type="string" summary="user visible description of the created output"/>
<arg name="width" type="int" summary="Logical width resolution"/>
<arg name="height" type="int" summary="Logical height resolution"/>
<arg name="scale" type="fixed" summary="Scaling factor of the display where it's to be displayed"/>
<arg name="pointer" type="uint" summary="Requested pointer mode"/>
</request>
</interface>
<interface name="zkde_screencast_stream_unstable_v1" version="6">
<request name="close" type="destructor">
<description summary="Indicates we are done with the stream and the communication is over."/>
</request>
<event name="closed">
<description summary="Notifies that the server has stopped the stream. Clients should now call close."/>
</event>
<event name="created" deprecated-since="6">
<description summary="Notifies about a pipewire feed being created">
Deprecated since version 6, use the object serial from the serial event instead
</description>
<arg name="node" type="uint" summary="node of the pipewire buffer"/>
</event>
<event name="failed">
<description summary="Offers an error message so the client knows the created event will not arrive, and the client should close the resource."/>
<arg name="error" type="string" summary="A human readable translated error message."/>
</event>
<event name="serial" since="6">
<description summary="the pipewire object serial">
The pipewire object serial of the stream. Should be preferred over the node id which is prone to id reuse.
Will be sent before the created event.
</description>
<arg name="object_serial_hi" type="uint" summary="high bits of the pipewire object serial"/>
<arg name="object_serial_low" type="uint" summary="low bits of the pipewire object serial"/>
</event>
</interface>
</protocol>