Skip to content
This repository was archived by the owner on Sep 25, 2026. It is now read-only.

fix(portal): bound D-Bus wait, capture cursor, repair zero-size env - #17

Merged
vindeckyy merged 1 commit into
masterfrom
fix/portal-stability-issues-14-16
Jul 16, 2026
Merged

vindeckyy merged 1 commit into
masterfrom
fix/portal-stability-issues-14-16

Conversation

@vindeckyy

Copy link
Copy Markdown
Owner

Closes #14 and #16.

Bug 1 — portal cursor invisible on KDE (closes #14 bug 1)

select_screencast_sources() did not pass cursor_mode in the
SelectSources options. Per the XDG Desktop Portal ScreenCast spec the
default is HIDDEN, so the PipeWire stream carried no cursor at all.

Fix: query the cached AvailableCursorModes property on the screencast
proxy. When EMBEDDED (2) is advertised (KDE returns u 7 = HIDDEN |
EMBEDDED | METADATA), request cursor_mode = EMBEDDED so the cursor
is composited into the stream. Compositors that reject EMBEDDED with
"Unavailable cursor mode 2" (RemoteDesktop, headless) keep the omit
behavior.

Bug 2 — absolute mouse silently dropped on KWin (closes #14 bug 2)

verify_and_update_display_parameters() accumulated desktop size from
the physical dimensions only. KWin reports the physical resolution
as 0x0 via wl_output while the logical resolution is valid, so
env_width/env_height were left at 0. The touch port
(touch_port_t::operator bool) then required nonzero dimensions, the
absolute move handler dropped every packet, and the only diagnostic was
verbose-level.

Fix: fall back per monitor to the logical resolution when the physical
is 0x0, and as a last resort use the stream dimensions instead of
leaving the env size at zero. A warning is logged so the fallback is
visible instead of silent.

Bug 3 — HTTPS control plane wedged by untimed portal wait (closes #16 fix 1)

dbus_response_wait() entered g_main_loop_run() with no timeout,
called from video::probe_encoders() on the nvhttp io thread. A stalled
portal wedged the entire HTTPS server; Moonlight saw the host as
offline and /resume timed out after 120 s.

Fix: arm a 15 s GLib timeout in dbus_response_init(). The wait now
returns after at most 15 s, the encoder probe fails fast, and other
HTTPS handlers stay responsive.

While here:

  • Pre-subscribe to the response signal BEFORE the proxy call is issued
    (was subscribed after, racing a fast response).
  • Verify the request_path returned by the call matches the one we
    generated, so a stale signal cannot terminate the wait for a
    different request.
  • dbus_response_t gained a destructor that unsubscribes the signal
    subscription, removes the timeout source, and unrefs the captured
    response variant. Same bug class as the recent g_autofree double-
    free fix (75c83f9), applied to the portal code path.

Out of scope for this PR (follow-up)

Issue #16 failure 3 (HTTPS session UAF during shutdown, PID 208986
core) still requires an ASan build to pinpoint reliably — GCC parallel
LTO partitioning isn't deterministic across builds, so the byte-
identical binary couldn't be reproduced. The fix in this PR removes a
concrete class of subscription/variant leaks that fit the same pattern;
the remaining UAF is tracked separately.

Verification

cmake --build build (release) and cmake --build build-asan
both compile cleanly with the changes. E2E verification on Fedora 44 /
KDE Plasma Wayland still belongs with the original reporter's setup.

Closes #14 and #16 by patching three classes of portal/Linux bugs that
combined to make capture unreliable or wedge the HTTPS control plane.

Issue #14 (cursor invisible, absolute mouse silently dropped):

- select_screencast_sources() now requests cursor_mode=EMBEDDED when the
  portal advertises AvailableCursorModes, so KDE's u 7 (HIDDEN|EMBEDDED|
  METADATA) actually puts the cursor in the PipeWire stream. Compositors
  that reject EMBEDDED (RemoteDesktop, headless) keep the omit behavior
  via the AvailableCursorModes check.

- verify_and_update_display_parameters() falls back per monitor to the
  logical resolution when wl_output reports a 0x0 physical size (KWin
  does this). As a last resort it uses the stream dimensions rather
  than leaving env_width/env_height at zero, which would otherwise
  invalidate the touch port and discard every absolute mouse packet.

Issue #16 (HTTPS control plane instability):

- g_main_loop_run() inside dbus_response_wait() is now bounded by a 15s
  GLib timeout. A stalled portal previously wedged the entire nvhttp
  io thread, which made the host look offline from Moonlight for the
  full 120 s /resume timeout. The portal still fails the encoder probe,
  but other HTTPS handlers stay responsive.

- The response signal is now subscribed BEFORE the proxy call is issued
  (not after it returns), so a fast portal response can't race the
  subscription setup. The request_path returned by the call is verified
  against the expected one, which prevents stale signals from an older
  request terminating the wait.

- dbus_response_t gained a destructor that unsubscribes the signal
  subscription, removes the timeout source, and unrefs the captured
  response variant. This removes a concrete class of subscription/
  variant leaks that fit the same pattern as the recent g_autofree
  double-free fix.

The HTTPS-session use-after-free from #16 failure 3 still requires an
ASan build to pinpoint reliably and is tracked separately.

Verified: cmake --build (release + ASan) both compile cleanly.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

2 participants