feat(theme): add outline support for bar, widgets and surfaces#118
Merged
feat(theme): add outline support for bar, widgets and surfaces#118
Conversation
Introduces a general decorative outline feature: config schema, palette computation, and CSS variable emission. No surface consumes the variables yet — that lands in a follow-up commit. Default is outline = false, so visual output is unchanged. Config: - theme.outline / outline_width / outline_color / outline_opacity - bar.outline / widgets.outline as Option<bool> overrides that inherit from theme.outline when omitted - widgets.<name>.outline_color for per-widget color overrides (width and opacity stay theme-level) Validation: - outline_width bounded to 0..=4 (wider decorative borders should use custom CSS via style.css) - outline_opacity bounded to 0.0..=1.0 - outline_color accepts the symbolic names "subtle" / "accent" / "foreground" or hex (#rgb / #rrggbb); per-widget overrides use the same rules, with the widget path included in error messages Theme palette: - ThemePalette gains effective per-scope enable flags (bar/widget/surface_outline_enabled) and resolved width/color/opacity. - css_vars_block emits base --outline-* variables and per-scope --bar-outline-* / --widget-outline-* / --surface-outline-* aliases. Width per scope resolves to var(--outline-width) when enabled or 0px when disabled; color/opacity are simple aliases in v1 to give future scope overrides a clean extension point without renaming. - In islands mode (bar.background_opacity == 0.0) an inherited bar outline is suppressed so it doesn't draw a phantom 1px frame around an invisible bar; an explicit bar.outline = true still wins. - resolve_outline_color is exported so per-widget CSS generation can reuse it. Hot reload: - config_theme_changed picks up bar.outline / widgets.outline so toggling them takes effect without a restart. - ConfigManager exposes bar/widget/surface_outline_visible() accessors for downstream consumers (used by the blur-region commit).
Wires the outline CSS variables introduced in the previous commit into actual border declarations. Per-scope --*-outline-width resolves to 0px when disabled, so this remains visually inert until users set theme.outline = true (or a per-section override). Bar / widgets: - sectioned-bar.bar gains a border driven by --bar-outline-* - .widget gains a border driven by --widget-outline-*; widget groups inherit the rule via .widget.widget-group, putting the outline around the group pill rather than each child Popovers and surfaces: - .vp-surface-popover (used by all layer-shell widget popovers — clock, calendar, battery, system, notifications, network, bluetooth, power) gains a border driven by --surface-outline-* - The shared popover surface CSS in services/surfaces.rs (used by OSD, toasts, tray, media, Quick Settings) replaces its previous `border: none` with the same --surface-outline-* declaration
The Wayland blur region for a rounded surface is rasterized as a stack of axis-aligned scanline rectangles (one per row of the rounded corner). Without compensation, the outermost rectangle of each corner extends to the same pixel as the CSS border-radius edge — but the corner is anti-aliased, so the few sub-pixel-coverage edge pixels of a semi-transparent outline see the blurred background through them. Visually that reads as a brighter halo on the corner's anti-aliased edge wherever an outline is enabled. compute_rounded_rect_rects_with_corner_inset adds an optional 1-px inward trim on each rounded-corner scanline, applied only when a visible outline is present on the surface. add_rounded_rect_to_region_ with_outline gates the trim on outline_visible so the existing non-outline path is unchanged. Wired into the three surface-blur entry points (apply_blur_surface_with_outline, apply_bar_blur_region with the bar outline flag, apply_bar_island_blur_regions with the widget outline flag) using the new visibility accessors on ConfigManager from the plumbing commit.
- Add outline_opacity_pct > 0 guard to *_outline_visible() helpers so a fully transparent outline doesn't trigger blur corner inset - Apply first widget's name CSS class to .widget.widget-group surface so per-widget outline_color overrides work for merge groups - Narrow outline_color doc comment to accurately describe scope - Add inline comment explaining why corner inset is 1px regardless of outline_width
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional CSS border (outline) around the bar, widgets, and surfaces.

This serves two purposes: the first is purely aesthetic, some people prefer the look and I want to expose it from toml rather than just CSS.
The second is to hide jagged compositor blur edges at rounded corners, since wl_region only supports axis-aligned rectangles, the blur isn't as nicely rounded and creates a staircase effect. When an outline is active, the blur region is trimmed by 1px at corners so the jagged edges hide behind the border.


Config:
CSS variables:
--outline-width,--outline-color,--outline-opacityat:root, plus per-scope--bar-outline-width,--widget-outline-width,--surface-outline-widththat resolve tovar(--outline-width)or 0pxPer surface override other than bar/widget is excluded in v1