From e26af6c0cc369b441e730af25ae79348ba649290 Mon Sep 17 00:00:00 2001 From: Mitchell R Date: Thu, 21 May 2026 10:21:17 +0200 Subject: [PATCH] fix(kiosk): hide cursor inside WebViews + at compositor level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WebView showed a grey/black half-square in the top-left — that's GDK's "none" cursor rendered by WebKit's own surface, which ignores the GTK-window CSS we set elsewhere. Inject a WebKit UserStyleSheet that applies cursor:none !important to every page + frame at User priority, overriding page-author CSS. For the boot gap (cage start → first kiosk frame), set XCURSOR_SIZE=1 and WLR_NO_HARDWARE_CURSORS=1 in the systemd unit. SW fallback honors the 1-pixel size; HW cursors don't, which is why a default arrow leaks through on some Pi GPUs. --- deploy/systemd/betterframe-kiosk.service | 6 ++++++ kiosk/src/ui.rs | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/deploy/systemd/betterframe-kiosk.service b/deploy/systemd/betterframe-kiosk.service index c138e04..598da6a 100644 --- a/deploy/systemd/betterframe-kiosk.service +++ b/deploy/systemd/betterframe-kiosk.service @@ -29,6 +29,12 @@ EnvironmentFile=-/etc/default/betterframe-kiosk Environment=XDG_SESSION_TYPE=wayland Environment=XDG_SESSION_CLASS=user Environment=GST_DEBUG=1 +# Cursor: cage/wlroots draws a sprite in the gap between compositor start +# and first kiosk frame. Collapse to 1px transparent + force software +# fallback so XCURSOR_SIZE actually applies (HW cursors ignore size on +# some GPUs, leaving a default white-arrow visible in the corner). +Environment=XCURSOR_SIZE=1 +Environment=WLR_NO_HARDWARE_CURSORS=1 # Let the unprivileged kiosk process control the Pi fan PWM sysfs files. ExecStartPre=+/bin/sh -c 'for d in /sys/class/hwmon/hwmon*; do [ -e "$d/pwm1" ] || continue; chgrp bfkiosk "$d/pwm1" "$d/pwm1_enable" 2>/dev/null || true; chmod g+w "$d/pwm1" "$d/pwm1_enable" 2>/dev/null || true; done' ExecStartPre=+/usr/local/sbin/betterframe-firmware-rollback.sh diff --git a/kiosk/src/ui.rs b/kiosk/src/ui.rs index 537963b..ffa4dfc 100644 --- a/kiosk/src/ui.rs +++ b/kiosk/src/ui.rs @@ -1561,6 +1561,26 @@ fn ensure_web( let wv = webkit6::WebView::new(); wv.set_vexpand(true); wv.set_hexpand(true); + + // Hide the pointer inside every WebKit page. The default GTK CSS cursor: + // none we set on top-level windows doesn't propagate into the WebView's + // own surface — it draws its own cursor over hovered HTML elements. + // Inject a UserStyleSheet at the WebKit level so every page (and every + // frame) hides the cursor unconditionally. UserStyleLevel::User wins + // over page-author CSS. + { + use webkit6::prelude::*; + let ucm = wv.user_content_manager(); + let style = webkit6::UserStyleSheet::new( + "*, *::before, *::after { cursor: none !important; }", + webkit6::UserContentInjectedFrames::AllFrames, + webkit6::UserStyleLevel::User, + &[], + &[], + ); + ucm.add_style_sheet(&style); + } + match source { WebSource::Html(html) => { webkit6::prelude::WebViewExt::load_html(&wv, html, None);