diff options
| author | srdusr <[email protected]> | 2024-06-22 22:34:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2024-06-22 22:34:00 +0200 |
| commit | 0818b56dd9c70b1097c5ef24be0f62baaf9ec999 (patch) | |
| tree | 4b0a739b9aaaa428e9d66eff9ae332c2f1f2d51b /crates/windows | |
| parent | ab0916391532031376817ed4ab6ab234428559a2 (diff) | |
| download | srdwm-0818b56dd9c70b1097c5ef24be0f62baaf9ec999.tar.gz srdwm-0818b56dd9c70b1097c5ef24be0f62baaf9ec999.zip | |
Bypass smithay's Space rendering for window/layer content: real per-window opacity
The user asked for per-window opacity (MISSING.md's `windowrule = opacity`
gap) and pushed back on treating smithay's convenience wrappers as a hard
ceiling: "don't rely on smithay, it won't have everything we need." Looked
again at why opacity was ruled out earlier - `render_output`/
`space_render_elements` take one `alpha` for the whole frame's `self.space`
content, no per-element control - and found a path that doesn't need
nesting smithay's internal `SpaceRenderElements` type (the approach that
hit an unresolvable generic-bounds wall investigating fullscreen-hiding
earlier): call `render_elements_from_surface_tree` directly,
once per window and once per layer-shell surface, each with its own alpha,
wrapping the result in the *existing* `OverlayElement::Surface` variant.
That primitive was already proven safe in this codebase (cursor.rs's
client-image path, this file's own popup rendering) - reusing it here for
a window's main content is the same call, not a new one.
Both `udev.rs` and `winit.rs`'s render loops now build window content and
layer-shell surfaces themselves (`elements.rs`: `surface_content_elements`,
`output_layer_elements`, `window_wl_surface` for the Wayland/XWayland
split), in the correct front-to-back order, then call
`OutputDamageTracker::render_output` directly instead of the
`space::render_output`/`space_render_elements` convenience wrappers. Content
itself needs no occlusion clipping against `occluders` (unlike border/
titlebar bitmaps) - pushed in the same front-to-back order as everything
else, ordinary painter's-algorithm draw order already occludes it correctly,
the same property it had via `self.space`'s own order before. `self.space`
stays mapped and `resync_stacking_order`-maintained exactly as before; only
the render step stopped reading from it.
A comment in winit.rs's render loop warned that a near-identical earlier
attempt was reverted for a real ordering bug (whichever window was created
first always painted in front, regardless of focus). That bug's actual root
cause, identified and fixed since, was `Space::map_element` silently
re-stacking on every geometry sync, independent of which render path was
used - see `resync_stacking_order`. This rewrite never reads `Space`'s
internal order for rendering at all (`ids` comes from `WindowManager.order`
directly, the same source `hit_test` already trusts), so that specific bug
class can't recur here regardless of whether `resync_stacking_order` ever
drifts again.
Bonus from the same infrastructure: the bar/dock now genuinely don't render
at all (not just get covered) for a fullscreen window - `output_layer_elements`
skips `Layer::Top`/`Overlay` entirely when any visible window is fullscreen,
the hardening this work backed away from earlier for being too risky to
build via the nested-SpaceRenderElements approach. `capture_offscreen`
(winit.rs's screencopy path) picked up opacity-aware content and layer-shell
inclusion too, though not full parity with the on-screen loop (still no
border/shadow strips there - a pre-existing, separately-flagged gap).
Opacity itself: `Window.opacity` (core), `WindowRuleActions.opacity` /
`srd.rule(..., { opacity = 0.9 })`, `srd.window.set_opacity()`. Caught live,
before commit: opacity was wired into `add_window`'s own rule match but not
`reapply_rules_if_pending` - the *only* path a class-based rule actually
takes effect through for a native Wayland client, since `add_window`'s own
attempt always runs against a still-empty `app_id` (see the regression test
next to the existing one covering the identical historical bug for
`decorated`). Found by setting an isolated `SRDWM_CONFIG_PATH` test config
with `srd.rule({ class = "Alacritty" }, { opacity = 0.4 })` against a nested
instance and pixel-sampling a real screenshot: predicted blend (242,230,53)
at 0.4 over (10,10,15) is (103,98,30); measured (105,100,33).
Verified live in a nested session, screenshotting the *host* compositor
(shows the real on-screen render, unlike grim against the nested socket,
which - separately discovered this work - routes through
`capture_offscreen`): stacking order correct with two overlapping windows
(topmost fully occludes the one behind it, the exact scenario the reverted
attempt got wrong), opacity blend matches prediction. Also confirmed, by
testing the previous commit against the same scene, that upside-down
content on this backend is a pre-existing bug unrelated to this change --
noted, not fixed here.
cargo build --workspace (all 9 crates), cargo clippy --workspace (0 new
warnings), cargo test --workspace (197 tests, 0 failed, includes 2 new
regression tests).
Diffstat (limited to 'crates/windows')
0 files changed, 0 insertions, 0 deletions