srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/foreign_toplevel.rs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-06-22 22:34:00 +0200
committersrdusr <[email protected]>2024-06-22 22:34:00 +0200
commit0818b56dd9c70b1097c5ef24be0f62baaf9ec999 (patch)
tree4b0a739b9aaaa428e9d66eff9ae332c2f1f2d51b /crates/wayland/src/foreign_toplevel.rs
parentab0916391532031376817ed4ab6ab234428559a2 (diff)
downloadsrdwm-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/wayland/src/foreign_toplevel.rs')
0 files changed, 0 insertions, 0 deletions