Add desktop widgets and streamline documentation
This commit is contained in:
1 parent
c63af64d87
commit
8dc895448d
25 files changed
+2724
-3686
No files matched your search
@@ -1,68 +0,0 @@
|
||||
# ADR 0001: libcosmic for the Ferese shell
|
||||
|
||||
Status: provisional, pending the M8 lifecycle spike
|
||||
Date: 2026-09-25
|
||||
|
||||
## Decision
|
||||
|
||||
Use libcosmic for the Ferese shell UI if the M8 lifecycle spike passes. Pin the
|
||||
dependency to commit `03d7dcb832bc6d15bc1bb07327a1aa426b2d5bc0` until a suitable
|
||||
stable release exists.
|
||||
|
||||
Keep the spike in `tools/ferese-shell-spike`; it is not the production shell.
|
||||
The production shell will continue to use public layer-shell for surface roles
|
||||
and Ferese-private protocols only for control and semantic effects.
|
||||
|
||||
## Why
|
||||
|
||||
libcosmic is a Rust-native toolkit designed for Wayland desktop components. Its
|
||||
current API can create layer-shell surfaces without an ordinary xdg-toplevel,
|
||||
select an active or explicit output, request keyboard interactivity, observe
|
||||
configure/focus/output events, and destroy surfaces through the runtime.
|
||||
|
||||
The previous GPUI direction depended on an older release and did not provide a
|
||||
convincing first-class path for Ferese shell surfaces.
|
||||
|
||||
## Constraints found during source review
|
||||
|
||||
- The selected revision declares Rust 1.93, so the isolated spike overrides the
|
||||
workspace's Rust 1.87 minimum. Ferese core crates keep their existing MSRV.
|
||||
- libcosmic exposes the created `WlSurface` in public Wayland layer events. This
|
||||
is necessary but may not be sufficient to bind `ferese-effects-v1` on the
|
||||
toolkit's event queue.
|
||||
- The spike must therefore prove private semantic-effects attachment before the
|
||||
production shell adopts libcosmic. If that cannot be done through supported
|
||||
APIs, Ferese will place a thin native Wayland surface adapter beneath the UI
|
||||
or revisit this decision; it will not replace public layer-shell with a
|
||||
private surface role.
|
||||
|
||||
## Validation gate
|
||||
|
||||
The provisional decision becomes accepted only after the spike demonstrates:
|
||||
|
||||
1. public layer-surface creation on the intended output;
|
||||
2. output discovery and updates;
|
||||
3. configure and resize delivery;
|
||||
4. on-demand keyboard focus and focus release;
|
||||
5. clean compositor-driven and application-driven shutdown; and
|
||||
6. `ferese-effects-v1` attachment to the toolkit-owned surface without an
|
||||
unsupported libcosmic or Iced fork.
|
||||
|
||||
## Spike result
|
||||
|
||||
Items 1 through 5 pass against nested Ferese. Item 6 passes after libcosmic
|
||||
publishes the surface in a focus event: the spike reconstructs a supported
|
||||
`wayland-client` connection handle, binds the capability-filtered effects
|
||||
global, and assigns `panel` to the same `wl_surface`.
|
||||
|
||||
The decision remains provisional because libcosmic does not currently publish
|
||||
its layer-surface creation event to the application. A normal non-focusable top
|
||||
bar therefore has no deterministic pre-map surface handle. Production work may
|
||||
proceed with libcosmic widgets and application state, but the top-bar surface
|
||||
path must first gain either:
|
||||
|
||||
1. a supported upstream surface-created callback; or
|
||||
2. the thin native Wayland surface adapter already allowed by the M8 plan.
|
||||
|
||||
Ferese will not make the persistent top bar steal keyboard focus merely to
|
||||
obtain its surface handle.
|
||||
@@ -1,26 +0,0 @@
|
||||
# Animation regression checks
|
||||
|
||||
Run `cargo test -p ferese-animation -p ferese --offline` for transition,
|
||||
resize requests, reduced motion, stacking, and refresh-rate regression tests.
|
||||
|
||||
For visual validation, use a disposable Ferese session with three tiled windows
|
||||
containing text and at least one floating window. Test both the nested and DRM
|
||||
backends. Record the session at its native refresh rate when comparing builds;
|
||||
single screenshots cannot establish smoothness.
|
||||
|
||||
| Scenario | Expected result |
|
||||
| --- | --- |
|
||||
| Super+F on the middle column, then exit | Neighbours remain behind the expanding window. The shrinking window stays above them until the transition finishes. |
|
||||
| Toggle Super+F repeatedly at 40–80 ms intervals | Every reversal starts at the presented frame. Corners, border and shadow follow the same zoom progress. The final state matches the last input. |
|
||||
| Cycle width, then immediately Super+F | The old column-width spring cannot override fullscreen width. |
|
||||
| Exit fullscreen and immediately resize or scroll | The current frame is retained when the target changes; scrolling resumes without a position jump. |
|
||||
| Drag a floating window; resize from its top-left corner | The window follows the pointer directly. The opposite edge stays anchored. Delayed client commits do not move or raise it. |
|
||||
| Zoom responsive and slow-redrawing clients | Each zoom requests the destination size once. Client redraws do not generate intermediate resize requests or restart the motion. |
|
||||
| Zoom the leftmost and rightmost columns in and out | Each outer edge moves monotonically toward its destination; neither side trembles or reverses near the screen edge. |
|
||||
| Disable borders and shadows, then zoom | Rounded corner pixels repaint through the final frame; no corner remnants remain. |
|
||||
| Repeat on 60 Hz and 144 Hz outputs; move focus between them | Similar elapsed-time motion with no double advancement. Check frame timing on actual DRM hardware. |
|
||||
| Enable reduced motion | Geometry and decorations reach their final values together. |
|
||||
|
||||
Zoom requests the destination client size once and scales the available buffer
|
||||
along the transition. This avoids repeated content reflow during motion. It is
|
||||
not a buffer snapshot or a guarantee of perfectly sharp intermediate text.
|
||||
+213
-379
@@ -1,327 +1,171 @@
|
||||
# Configuration and session reference
|
||||
# Configuration
|
||||
|
||||
## Live configuration
|
||||
Edit `~/.config/ferese/config.toml` (or `$XDG_CONFIG_HOME/ferese/config.toml`),
|
||||
or open **Control Center → Settings**. Start with the [example](../packaging/config.toml).
|
||||
All supported configuration sections are listed below; [desktop widgets](desktop-widgets.md)
|
||||
covers the complete clock and sticky-note fields separately.
|
||||
|
||||
`ferese-settings` opens the native settings application, also available from
|
||||
Control Center → Settings after installation. It includes appearance presets,
|
||||
wallpaper selection, menu bar geometry, window behavior, motion, keyboard/mouse,
|
||||
custom shortcut editing, login items, and existing display profiles. Changes save
|
||||
automatically; text fields save on Enter or when leaving the field. Sliders save
|
||||
when released. Settings also refreshes after external config edits, preserving
|
||||
active drafts. Display profiles, touchpad options, and login items update live.
|
||||
Wallpaper browsing uses Zenity's native GTK file chooser (`zenity` must be
|
||||
installed); entering an image path directly remains available.
|
||||
## Saving and validation
|
||||
|
||||
The app validates changes with `ferese --check-config PATH` before atomically
|
||||
replacing your file, preserves comments and unrelated keys, and keeps a
|
||||
`config.toml.settings-backup`. Undo restores the previous save; external edits
|
||||
require Reload before saving. Search filters settings categories. To preview
|
||||
against a disposable config without changing your desktop config:
|
||||
Settings saves automatically: text on Enter/focus loss, sliders when released.
|
||||
Undo restores the previous save; Reload picks up external edits without merging
|
||||
unfinished drafts. Wallpaper browsing needs `zenity`; a path can also be entered.
|
||||
Settings keeps `config.toml.settings-backup` before saving.
|
||||
|
||||
File edits reload automatically, including atomic editor saves. Invalid changes
|
||||
keep the last working configuration. Appearance, wallpaper, motion, input,
|
||||
bindings, rules, layouts, displays, widgets and login items update live.
|
||||
|
||||
```sh
|
||||
cargo build -p ferese -p ferese-settings --locked
|
||||
target/debug/ferese-settings --config /tmp/ferese-settings-preview.toml
|
||||
feresectl reload-config # reload with error feedback
|
||||
ferese --check-config PATH # validate without applying
|
||||
ferese-settings --config PATH # edit a separate preview config
|
||||
```
|
||||
|
||||
The GUI is not a replacement for every advanced config option: adding display
|
||||
profiles, arranging outputs, new shortcut definitions, and window rules remain
|
||||
in `config.toml`. Theme presets update palette and focus-gradient colors without
|
||||
replacing custom rules, bindings, wallpaper, or layout settings.
|
||||
Defaults below are built-in defaults, not your personal or packaged overrides.
|
||||
Dimensions are logical pixels unless noted; numbers must be finite. Optional
|
||||
values are omitted, not `null`. Colors use `#RRGGBB` or `#RRGGBBAA`.
|
||||
Live config is limited to 60 KiB.
|
||||
|
||||
New installations float Settings by default. To do the same in an existing
|
||||
config, add a `[[window_rules]]` entry with `app_id = "dev.ferese.Settings"`
|
||||
and `floating = true`.
|
||||
## Layout
|
||||
|
||||
Saving `~/.config/ferese/config.toml` (or `$XDG_CONFIG_HOME/ferese/config.toml`)
|
||||
reloads it automatically. Atomic editor saves are supported and bursts are
|
||||
debounced. Invalid edits keep the last working compositor and shell config;
|
||||
the rejection is logged. Idle watching does not reread the file.
|
||||
| `[layout]` key | Type / values | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `mode` | `"scrolling"`, `"tree"` | `"scrolling"` | Workspace layout |
|
||||
| `inner_gap` | number ≥ 0 | `10` | Between windows |
|
||||
| `outer_gap` | number ≥ 0 | `4` | Around workspace edges |
|
||||
| `smart_gaps` | boolean | `false` | Remove outer gaps for one tiled window |
|
||||
|
||||
Use `feresectl reload-config` to reload manually and report validation errors.
|
||||
Live sources are limited to 60 KiB for safe delivery over the private protocol.
|
||||
| `[scrolling]` key | Type / values | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `default_column_width` | proportion > 0; or `"full"` | `0.5` | Width of new columns |
|
||||
| `focus_strategy` | `"minimal"`, `"center_on_focus"`, `"paged"` | `"minimal"` | Viewport movement on focus |
|
||||
| `width_presets` | array of widths | `[0.3333333333333333, 0.5, 0.6666666666666666, "full"]` | Super+R cycle; empty uses defaults |
|
||||
|
||||
Appearance, fonts, wallpaper, animations, keybindings, keyboard layout/repeat,
|
||||
gaps, scrolling focus policy/default widths, and bar geometry reload live.
|
||||
Wallpaper decoding stays off the render thread and keeps the old image until
|
||||
the replacement is ready. Layout-mode changes convert existing workspaces;
|
||||
default-width changes update columns using the previous default, preserving
|
||||
custom widths. Changed window rules are reapplied to existing matching windows.
|
||||
Output profiles and touchpad changes apply immediately. Display changes retain
|
||||
output/workspace identity; configurations with no usable output are rejected.
|
||||
The compositor and shell need one initial update/restart to enable this feature.
|
||||
`minimal` scrolls only to reveal the focused window. `center_on_focus` centers
|
||||
it. `paged` packs columns into viewport-sized pages: halves form pairs, thirds
|
||||
form triples; mixed widths and client minimum sizes determine actual boundaries.
|
||||
Changing default width preserves manually resized columns.
|
||||
|
||||
## Session services and locking
|
||||
## Motion
|
||||
|
||||
`[[autostart]]` entries run after the compositor's public socket is ready:
|
||||
| Section / key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `animations.enabled` | boolean | `true` | Enable motion |
|
||||
| `animations.reduced_motion` | boolean | `false` | Disable animated motion |
|
||||
| `animations.speed` | number > 0 | `1` | Higher is faster; `0.75` is slower |
|
||||
| `animations.spring.mass` | number > 0 | `1` | Window-motion spring mass |
|
||||
| `animations.spring.stiffness` | number > 0 | `700` | Spring stiffness |
|
||||
| `animations.spring.damping` | number ≥ 0 | `53` | Spring damping |
|
||||
| `animations.viewport_spring.mass` | number > 0 | `1` | Scrolling spring mass |
|
||||
| `animations.viewport_spring.stiffness` | number > 0 | `320` | Scrolling stiffness |
|
||||
| `animations.viewport_spring.damping_ratio` | number > 0 | `1` | `1` is critically damped |
|
||||
|
||||
```toml
|
||||
[[autostart]]
|
||||
command = ["awari"]
|
||||
enabled = true
|
||||
restart = true
|
||||
## Appearance
|
||||
|
||||
[[autostart]]
|
||||
command = ["swayidle", "-w", "timeout", "600", "ferese-lock", "before-sleep", "ferese-lock", "lock", "ferese-lock"]
|
||||
restart = true
|
||||
```
|
||||
| Section / key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `appearance.corner_radius` | number ≥ 0 | `14` | Shell material/card radius |
|
||||
| `appearance.inactive_dim.enabled` | boolean | `false` | Dim unfocused windows |
|
||||
| `appearance.inactive_dim.amount` | number 0–1 | `0.15` | Darkening strength |
|
||||
| `appearance.inactive_dim.duration_ms` | number ≥ 0 | `150` | Dimming and focus-ring transition; 0 snaps |
|
||||
| `theme.typography.font_family` | string | system sans-serif | Shell, Settings and overview font |
|
||||
| `theme.background.path` | string | omitted | Wallpaper image path |
|
||||
| `theme.background.mode` | `"fill"`, `"fit"` | `"fill"` | Crop or letterbox |
|
||||
| `theme.material.style` | `"solid"`, `"translucent"` | `"solid"` | Shell background material |
|
||||
| `theme.material.blur_radius` | number ≥ 0 | `12` | Translucent backdrop blur, capped at 32; 0 disables |
|
||||
|
||||
Services are session-owned, reaped, and restarted with a five-second retry delay.
|
||||
They receive the correct public Wayland display without private shell privileges.
|
||||
Nested previews skip them unless `nested = true` is explicitly configured.
|
||||
Autostart changes reconcile live: unchanged commands keep their processes,
|
||||
new/enabled items start, and disabled/removed commands stop without blocking rendering.
|
||||
Run foreground daemons here, not commands that fork themselves into the background.
|
||||
| `[theme.colors]` key | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `surface_base` | `"#111821"` | Material/card base color |
|
||||
| `text_primary` | `"#F4F7FB"` | Main text |
|
||||
| `text_muted` | `"#7F8A98"` | Secondary text |
|
||||
| `accent` | `"#5B8CFF"` | Active controls and solid focus ring |
|
||||
| `border` | `"#FFFFFF18"` | Unfocused window border |
|
||||
| `shadow` | `"#00000055"` | Window shadow color |
|
||||
|
||||
Ferese implements `ext-session-lock-v1`. While locked, only lock surfaces over an
|
||||
opaque fallback are rendered, normal input/shortcuts and IPC are blocked, and
|
||||
screencopy is unavailable. DRM confirmation waits for safe page flips on active
|
||||
outputs. A missing/crashed locker leaves the session locked; it is not an unlock.
|
||||
`ferese-lock` runs swaylock/swaylock-effects with optional
|
||||
`~/.config/ferese/swaylock.conf`, waiting for lock confirmation before daemonizing.
|
||||
The compositor authenticates no passwords itself; authentication belongs to the locker.
|
||||
Validate password unlock in a disposable nested session before enabling automatic
|
||||
locking on a primary session. Crash recovery currently requires ending that session
|
||||
from another VT; there is deliberately no unauthenticated IPC unlock.
|
||||
| `[theme.geometry]` key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `border_width` | number ≥ 0 | `1` | Window border thickness |
|
||||
| `focus_ring_width` | number ≥ 0 | `2` | Focused border thickness |
|
||||
| `window_radius` | number ≥ 0 | `14` | Managed-window corners |
|
||||
| `top_bar_height` | number > 0 | `28` | Menu-bar height |
|
||||
| `top_bar_margin_top` | integer ≥ 0 | `0` | Space above bar |
|
||||
| `top_bar_window_gap` | integer ≥ 0 | `0` | Clearance below bar |
|
||||
| `top_bar_margin_horizontal` | integer ≥ 0 | `0` | Bar side margins |
|
||||
| `top_bar_radius` | number ≥ 0 | `0` | Bar corners |
|
||||
| `panel_padding` | number ≥ 0 | `12` | Bar inner padding |
|
||||
| `control_gap` | number ≥ 0 | `12` | Right-side control spacing |
|
||||
|
||||
| Section / key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `theme.surface.bar.background` | color | `"#1C202EF2"` | Shell fallback background; compositor materials use `surface_base` |
|
||||
| `theme.surface.bar.opacity` | number 0–1 | omitted | Material opacity defaults to `0.78`; fallback retains background alpha |
|
||||
| `theme.surface.bar.text_primary` | color | `"#F0F3FA"` | Bar text/icons |
|
||||
| `theme.surface.bar.text_muted` | color | `"#AAB4C7"` | Inactive bar foreground |
|
||||
| `theme.surface.popover.opacity` | number 0–1 | `0.96` | Shell popover fill alpha |
|
||||
| `theme.shadow.soft.offset_y` | number | `4` | Window shadow vertical offset |
|
||||
| `theme.shadow.soft.blur` | number ≥ 0 | `18` | Window shadow softness |
|
||||
| `theme.shadow.soft.opacity` | number 0–1 | `0.20` | Window shadow strength |
|
||||
|
||||
## Configuration reference
|
||||
Solid materials omit blur; translucent materials blur behind the surface color.
|
||||
True fullscreen removes decorations. Focus transitions never scale the content.
|
||||
|
||||
Ferese reads `$XDG_CONFIG_HOME/ferese/config.toml`, or
|
||||
`~/.config/ferese/config.toml` when `XDG_CONFIG_HOME` is unset. New scrolling
|
||||
columns use half the viewport by default. To make every newly opened column use
|
||||
the full viewport width:
|
||||
|
||||
```toml
|
||||
[scrolling]
|
||||
default_column_width = "full"
|
||||
```
|
||||
|
||||
`default_column_width = 1.0` is equivalent. `Super+M` switches the active
|
||||
workspace between scrolling and tree modes.
|
||||
|
||||
Outer gaps remain visible with one window by default. To intentionally remove
|
||||
them for a lone tiled window:
|
||||
|
||||
```toml
|
||||
[layout]
|
||||
outer_gap = 4.0
|
||||
smart_gaps = true
|
||||
```
|
||||
|
||||
Managed-window borders use theme tokens and overlay the window edge without
|
||||
adding inner padding or changing client geometry:
|
||||
|
||||
```toml
|
||||
[theme.colors]
|
||||
border = "#FFFFFF18"
|
||||
accent = "#5B8CFF"
|
||||
shadow = "#00000055"
|
||||
|
||||
[theme.geometry]
|
||||
border_width = 1.0
|
||||
focus_ring_width = 2.0
|
||||
window_radius = 14.0
|
||||
|
||||
[theme.shadow.soft]
|
||||
offset_y = 4.0
|
||||
blur = 18.0
|
||||
opacity = 0.20
|
||||
|
||||
[theme.material]
|
||||
style = "solid" # solid or translucent
|
||||
blur_radius = 12.0 # logical pixels; translucent only, 0 disables blur
|
||||
|
||||
[appearance.inactive_dim]
|
||||
enabled = true # opt-in; disabled by default
|
||||
amount = 0.15 # dark tint over unfocused windows, 0–1; 0 disables
|
||||
duration_ms = 150 # 0 snaps immediately; reduced motion also snaps
|
||||
```
|
||||
|
||||
Inactive dimming follows window focus with a smooth, interruption-safe fade.
|
||||
Focus-ring paint (including gradients) and width use the same `duration_ms`,
|
||||
even when dimming is disabled. Focus changes never scale or move the window.
|
||||
Shell buttons fade their hover tint over 120 ms. Both transitions respect
|
||||
`animations.speed`, `animations.enabled`, and `animations.reduced_motion`;
|
||||
click actions remain immediate and settled hover states do not animate.
|
||||
It keeps window opacity intact, respects animated geometry and rounded corners,
|
||||
and leaves shell bars/popovers untouched. Overview temporarily removes dimming.
|
||||
|
||||
Material roles use the configured surface color and role-specific shadows.
|
||||
Solid is the default. Translucent adds backdrop blur behind the same surface
|
||||
color, without grain, glossy lighting, saturation boosts, or inset highlights.
|
||||
The radius is clamped to 32 logical pixels. A shader/allocation failure falls
|
||||
back to a plain translucent fill. Shell popovers report rounded card regions;
|
||||
their outer padding and gaps stay transparent. Each surface shares one capture
|
||||
across its cards, so cards do not sample already blurred neighboring cards.
|
||||
|
||||
```toml
|
||||
[appearance]
|
||||
corner_radius = 14.0
|
||||
```
|
||||
|
||||
Shell shadows use restrained logical-pixel presets: panel `1/5/4%`, popover
|
||||
and menu `2/8/7%`, HUD `1/4/4%`, and notification/modal `3/10/9%`
|
||||
(vertical offset / blur / opacity). Private effects capabilities
|
||||
remain required; public background-effect requests cannot select these materials.
|
||||
|
||||
Fullscreen windows are borderless and shadowless. Other managed windows use GPU
|
||||
rounded clipping, matching rounded focus rings, and an analytic soft shadow.
|
||||
These effects overlay or surround the allocation without adding client padding.
|
||||
|
||||
Scrolling keeps windows in stable workspace coordinates and animates the
|
||||
viewport only when focus must be revealed. Set
|
||||
`focus_strategy = "center_on_focus"` under `[scrolling]` to center focused
|
||||
columns instead.
|
||||
|
||||
Use `focus_strategy = "paged"` to pack consecutive columns into viewport-sized
|
||||
pages. Half-width columns form pairs, thirds form triples, and full-width
|
||||
columns occupy their own page. Mixed widths and client minimum sizes use their
|
||||
actual allocated widths, including gaps. Focusing within a page keeps it still;
|
||||
crossing a page boundary scrolls to that page. Explicit centering remains in
|
||||
effect until focus changes or the output resizes.
|
||||
|
||||
Scrolling controls use `Super+R` to cycle configured width presets, `Super+C`
|
||||
to center the focused column, `Super+[` to consume the focused window into an
|
||||
adjacent column, and `Super+]` to expel it. `Super+Ctrl+H/J/K/L` resizes in the
|
||||
corresponding direction.
|
||||
|
||||
`Super+Tab` toggles the compositor overview. Its live window previews retain
|
||||
their client surfaces, `Super+H/J/K/L` moves the selection using the presented
|
||||
preview geometry, and clicking a preview activates it without forwarding the
|
||||
selection click to the application.
|
||||
|
||||
The shell provides a configurable libcosmic menu bar backed
|
||||
by the private shell-control connection. Build and preview it nested with:
|
||||
|
||||
```bash
|
||||
cargo build --release -p ferese -p ferese-shell
|
||||
target/release/ferese --backend nested --grant-effects --grant-shell-control -- \
|
||||
target/release/ferese-shell
|
||||
```
|
||||
|
||||
The Ferese mark enters overview. A workspace selector sits on the left;
|
||||
status controls and day/time sit on the right. Bar geometry, spacing, colors
|
||||
and material style are configurable and reload live.
|
||||
|
||||
The compositor decodes wallpaper in parallel with startup. Small shell surfaces prefer the lightweight
|
||||
software renderer, with GPU rendering available as a fallback. Set `ICED_BACKEND=wgpu` to explicitly use GPU
|
||||
rendering for shell content. Use release builds when evaluating startup and
|
||||
animation performance; debug image processing is considerably slower.
|
||||
|
||||
Resize presentation configures the destination once and coordinates the
|
||||
matching client commits with the workspace motion (300 ms maximum wait).
|
||||
Application content stays at native pixel size; animated bounds crop/reveal
|
||||
it rather than stretching text. A resize-only previous-frame snapshot fades
|
||||
out over 80 ms, with a 64 MiB total snapshot budget and automatic release.
|
||||
All monitors share one elapsed-time animation clock, and window content,
|
||||
clips, borders and shadows use the same physical-pixel edges.
|
||||
|
||||
Window borders and focus rings use solid colors by default. Optional linear
|
||||
gradients can be configured independently:
|
||||
Optional `[theme.focus_ring.gradient]` and `[theme.border.gradient]` use the same
|
||||
keys: required `from` and `to` colors, and `angle` (number, default `0`). Angles
|
||||
are clockwise: 0 is left-to-right, 90 top-to-bottom. Omit the gradient section
|
||||
for solid `accent` or `border` colors.
|
||||
|
||||
```toml
|
||||
[theme.focus_ring.gradient]
|
||||
from = "#e5c890"
|
||||
to = "#b98d58"
|
||||
angle = 135.0
|
||||
|
||||
# Optional unfocused-window gradient:
|
||||
[theme.border.gradient]
|
||||
from = "#3e3e43"
|
||||
to = "#242429"
|
||||
angle = 90.0
|
||||
```
|
||||
|
||||
Angles are clockwise in window coordinates: 0 is left-to-right and 90 is
|
||||
top-to-bottom. Both endpoints accept `#RRGGBB` or `#RRGGBBAA`. Remove either
|
||||
gradient section to restore its solid `theme.colors.accent` or `border` color.
|
||||
Gradients share the existing rounded-border shader and add no animation or
|
||||
extra render pass. Configuration changes reload live.
|
||||
## Input
|
||||
|
||||
Overview has a horizontally scrollable workspace strip with live window
|
||||
thumbnails and an accent outline on the workspace shown by each output.
|
||||
Click a workspace to change the window grid without leaving overview; click
|
||||
a window to focus it and exit, or press Escape to dismiss. Only the workspace
|
||||
strip has a tinted surface; the window grid sits directly over the wallpaper.
|
||||
Strip labels use `[theme.typography].font_family` and rasterize at output scale.
|
||||
The strip fades independently and preserves its opacity on rapid reversals,
|
||||
including when the selected workspace is empty.
|
||||
| `[input]` key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `focus_follows_mouse` | boolean | `false` | Focus windows under the pointer |
|
||||
| `xkb_layout` | nonempty string | `"us"` | XKB layout |
|
||||
| `xkb_variant` | string | `""` | XKB variant |
|
||||
| `xkb_options` | string array | `[]` | XKB options |
|
||||
| `repeat_rate` | integer > 0 | `25` | Repeats per second |
|
||||
| `repeat_delay_ms` | integer ≥ 0 | `600` | Delay before repeat |
|
||||
|
||||
Ferese renders `[theme.background]` wallpapers directly: `path` selects the
|
||||
image and `mode = "fill"` or `"fit"` controls crop/letterboxing. One decoded
|
||||
image and one texture per GPU context serve every output; resizing requires
|
||||
no image reload or full-screen shell buffers. The launched shell receives
|
||||
`FERESE_COMPOSITOR_WALLPAPER=1` to disable its redundant wallpaper surfaces.
|
||||
When no valid image path is configured, the shell's existing fallback remains.
|
||||
`[input.touchpad]` has three boolean keys, all defaulting to `true`: `tap`,
|
||||
`natural_scroll` and `disable_while_typing`. These apply to DRM devices; nested
|
||||
previews use the host's physical input settings.
|
||||
|
||||
Keyboard and direct-session touchpad settings reload live:
|
||||
## Commands and bindings
|
||||
|
||||
```toml
|
||||
[input]
|
||||
focus_follows_mouse = false
|
||||
xkb_layout = "us"
|
||||
xkb_variant = ""
|
||||
xkb_options = []
|
||||
repeat_rate = 25
|
||||
repeat_delay_ms = 600
|
||||
`[commands]` maps arbitrary names to nonempty argument arrays. The built-in
|
||||
`terminal = ["foot"]` can be overridden. Commands run directly, without a shell.
|
||||
|
||||
[input.touchpad]
|
||||
tap = true
|
||||
natural_scroll = true
|
||||
disable_while_typing = true
|
||||
```
|
||||
| `[[bindings]]` key | Type / values | Default |
|
||||
| --- | --- | --- |
|
||||
| `keys` | chord string, e.g. `"Super+Enter"` | required |
|
||||
| `match` | `"keysym"`, `"physical"` | `"keysym"` |
|
||||
| `action` | action name below | required unless disabled |
|
||||
| `argument` | string | required only for actions listed below |
|
||||
| `disabled` | boolean | `false` |
|
||||
|
||||
Touchpad settings apply to libinput devices in the direct DRM session. In the
|
||||
nested backend, the host compositor remains responsible for physical touchpad
|
||||
configuration.
|
||||
Modifiers: `Super`/`Logo`/`Mod4`, `Ctrl`/`Control`, `Alt`, `Shift`.
|
||||
Keys use XKB keysyms (`Enter`, letters, `[`/`]`) or physical XKB names (`AD06`).
|
||||
A binding replaces the same normalized chord/match mode. Duplicate bindings are
|
||||
invalid. A disabled binding must omit `action` and `argument`.
|
||||
|
||||
The direct DRM backend selects the first output profile whose listed monitors
|
||||
are all connected. Match either the connector name reported by `get-outputs`
|
||||
or its persistent EDID-derived identity:
|
||||
|
||||
```toml
|
||||
[[output_profiles]]
|
||||
name = "docked"
|
||||
|
||||
[[output_profiles.outputs]]
|
||||
match = "HDMI-A-1"
|
||||
mode = "[email protected]"
|
||||
scale = 1.6
|
||||
position = [0, 0]
|
||||
|
||||
[[output_profiles.outputs]]
|
||||
match = "eDP-1"
|
||||
enabled = false
|
||||
|
||||
[[output_profiles]]
|
||||
name = "laptop"
|
||||
|
||||
[[output_profiles.outputs]]
|
||||
match = "eDP-1"
|
||||
mode = "2880x1800@120"
|
||||
scale = 1.6
|
||||
position = [0, 0]
|
||||
```
|
||||
|
||||
Unspecified connected outputs remain enabled with their preferred mode, scale
|
||||
`1.0`, normal transform, and automatic horizontal placement. Supported
|
||||
transforms are `normal`, `rotate_90`, `rotate_180`, `rotate_270`, `flipped`,
|
||||
and their rotated flipped variants. Output configuration is applied at startup,
|
||||
on hotplug, and live reload, including modes, scale, transform, and position.
|
||||
|
||||
On DRM, closing the laptop lid disables internal panels when a usable external
|
||||
output is available. With no usable external output, the panel stays enabled;
|
||||
Ferese does not change the system's suspend policy. Workspaces are evacuated
|
||||
to a remaining output without merging their windows, and return to their
|
||||
original output when the lid reopens or a disconnected monitor returns.
|
||||
Normal use of an evacuated workspace does not cancel its automatic return.
|
||||
|
||||
Commands are argv arrays and are started directly, without a shell. The
|
||||
default `Super+Enter` binding runs the built-in `terminal = ["foot"]` command:
|
||||
| Actions | Argument |
|
||||
| --- | --- |
|
||||
| `spawn` | Name in `[commands]` |
|
||||
| `focus`, `move`, `resize` | `"left"`, `"right"`, `"up"`, `"down"` |
|
||||
| `workspace`, `move-to-workspace` | Workspace number string, 1–255 |
|
||||
| `close`, `exit`, `toggle-maximized`, `toggle-fullscreen`, `toggle-layout`, `cycle-column-width`, `center-column`, `consume`, `expel`, `toggle-floating`, `toggle-overview` | None |
|
||||
|
||||
```toml
|
||||
[commands]
|
||||
terminal = ["foot", "--app-id", "terminal"]
|
||||
terminal = ["foot"]
|
||||
|
||||
[[bindings]]
|
||||
keys = "Super+Enter"
|
||||
@@ -329,115 +173,105 @@ action = "spawn"
|
||||
argument = "terminal"
|
||||
```
|
||||
|
||||
A configured binding replaces the built-in binding with the same normalized
|
||||
chord and match mode. Disable a default explicitly with no action:
|
||||
Defaults: Super+Enter terminal; Super+Q close; Super+H/J/K/L focus;
|
||||
Super+Shift+H/J/K/L move; Super+Ctrl+H/J/K/L resize; Super+1–9 workspace;
|
||||
Super+Shift+1–9 move to workspace; Super+R width cycle; Super+C center;
|
||||
Super+[/] consume/expel; Super+F maximize; Super+Shift+F fullscreen;
|
||||
Super+M layout; Super+Shift+Space floating; Super+Tab overview;
|
||||
Super+Shift+E immediate logout.
|
||||
|
||||
```toml
|
||||
[[bindings]]
|
||||
keys = "Super+Q"
|
||||
disabled = true
|
||||
```
|
||||
## Window rules
|
||||
|
||||
Bindings follow the active layout by default. To bind a keyboard position
|
||||
instead, set `match = "physical"` and use an XKB physical key name such as
|
||||
`AD06`. Invalid chords, actions, arguments, duplicate bindings, and missing
|
||||
command references stop startup with an error.
|
||||
| `[[window_rules]]` key | Type | Default / meaning |
|
||||
| --- | --- | --- |
|
||||
| `app_id` | nonempty string | Optional exact match; case-insensitive, `.desktop` suffix ignored |
|
||||
| `title` | nonempty string | Optional exact, case-sensitive match |
|
||||
| `transient` | boolean | Optional parent-dialog match |
|
||||
| `workspace` | integer > 0 | Leave placement unchanged |
|
||||
| `floating` | boolean | Leave placement unchanged |
|
||||
| `width`, `height` | numbers > 0 | Application-chosen floating size |
|
||||
| `fullscreen` | boolean | Leave fullscreen state unchanged |
|
||||
|
||||
Initial window rules match `app_id`, exact title, and/or transient status. All
|
||||
matching rules are applied in declaration order; later rules override only the
|
||||
fields they specify. Width or height implies floating placement when `floating`
|
||||
is omitted:
|
||||
|
||||
With `floating = true` and no explicit dimensions, the application chooses its
|
||||
initial size and Ferese centers that size on its workspace's output. Small
|
||||
dialogs are not forced into a workspace-sized container.
|
||||
At least one matcher is required; supplied matchers must all match. Rules apply
|
||||
in order, with later fields overriding earlier ones. Dimensions imply floating
|
||||
when `floating` is omitted. Floating apps without dimensions choose their own
|
||||
size and open centered on the output. Title changes do not trigger new rules;
|
||||
config rule changes apply to existing windows.
|
||||
|
||||
```toml
|
||||
[[window_rules]]
|
||||
app_id = "org.example.Editor"
|
||||
workspace = 3
|
||||
app_id = "dev.ferese.Settings"
|
||||
floating = true
|
||||
width = 900.0
|
||||
height = 600.0
|
||||
fullscreen = false
|
||||
```
|
||||
|
||||
Rules are finalized on the first toplevel commit, before its buffer is
|
||||
presented, and are not re-applied when an application later changes its title.
|
||||
## Displays
|
||||
|
||||
`feresectl` controls the running compositor through the same-user socket at
|
||||
`$XDG_RUNTIME_DIR/ferese/control.sock`. For example:
|
||||
`[[output_profiles]]` has a required unique nonempty `name` and one or more
|
||||
`[[output_profiles.outputs]]` entries. The first profile whose listed monitors
|
||||
are connected wins. Find connector names and persistent identities using
|
||||
`feresectl get-outputs`.
|
||||
|
||||
```bash
|
||||
cargo run -p feresectl -- focus left
|
||||
cargo run -p feresectl -- workspace 2
|
||||
cargo run -p feresectl -- get-workspaces
|
||||
cargo run -p feresectl -- get-outputs
|
||||
| `[[output_profiles.outputs]]` key | Type | Default |
|
||||
| --- | --- | --- |
|
||||
| `match` | nonempty connector or persistent identity string | required; unique within profile |
|
||||
| `enabled` | boolean | `true` |
|
||||
| `mode` | `"WIDTHxHEIGHT"` or `"WIDTHxHEIGHT@HZ"` | Preferred mode |
|
||||
| `scale` | number > 0 | `1` |
|
||||
| `transform` | enum below | `"normal"` |
|
||||
| `position` | `[integer, integer]` | Automatic horizontal placement |
|
||||
|
||||
Transforms: `normal`, `rotate_90`, `rotate_180`, `rotate_270`, `flipped`,
|
||||
`flipped_90`, `flipped_180`, `flipped_270`. Unspecified connected displays stay
|
||||
enabled with defaults. Disabling every usable output is rejected.
|
||||
|
||||
```toml
|
||||
[[output_profiles]]
|
||||
name = "docked"
|
||||
|
||||
[[output_profiles.outputs]]
|
||||
match = "HDMI-A-1"
|
||||
scale = 1.5
|
||||
position = [0, 0]
|
||||
```
|
||||
|
||||
The v0 IPC slice also supports `move`, `resize`, `move-to-workspace`,
|
||||
`toggle-floating`, `toggle-maximized`, `toggle-fullscreen`, `toggle-layout`, `cycle-column-width`,
|
||||
`center-column`, `consume`, `expel`, `close`, `get-focused-window`, and
|
||||
`get-outputs`. Requests use versioned, 1 MiB-limited length-prefixed JSON. The
|
||||
runtime directory and socket are restricted to modes `0700` and `0600`, and the
|
||||
server rejects peers whose effective UID differs from the compositor's. IPC has
|
||||
a bounded request queue and accepts at most 64 concurrent client connections.
|
||||
`get-outputs` includes disabled-but-connected monitors, connector and persistent
|
||||
identity matchers, current and available modes with refresh rates, fractional
|
||||
scale, transform, logical position and size, and physical dimensions.
|
||||
With a usable external display, closing the lid disables internal panels.
|
||||
Workspaces move to a remaining display and return when their original output
|
||||
returns. Ferese does not change the system's suspend policy.
|
||||
|
||||
Text-input-v3 is available to applications by default. Input-method-v2 is
|
||||
hidden unless the session explicitly opts in, because an input method can
|
||||
request privileged keyboard access. Enable it only when launching a trusted
|
||||
IME for the session:
|
||||
## Status controls
|
||||
|
||||
```bash
|
||||
FERESE_ENABLE_INPUT_METHOD=1 cargo run -p ferese
|
||||
| `[status]` key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `battery_percentage` | boolean | `true` | Show percentage beside icon |
|
||||
| `low_battery_threshold` | integer 0–100 | `20` | Warning-color threshold |
|
||||
| `settings_command` | argument array | `["ferese-settings"]` | Settings launcher; `[]` hides the action |
|
||||
|
||||
## Login items and locking
|
||||
|
||||
| `[[autostart]]` key | Type | Default | Meaning |
|
||||
| --- | --- | --- | --- |
|
||||
| `command` | nonempty argument array | required | Foreground process, not a self-daemonizing command |
|
||||
| `enabled` | boolean | `true` | Start service |
|
||||
| `restart` | boolean | `true` | Restart after exit, with a five-second retry delay |
|
||||
| `nested` | boolean | `false` | Also run in nested previews |
|
||||
|
||||
Unchanged services keep running on reload; removed/disabled items stop. To lock
|
||||
after five minutes and before sleep:
|
||||
|
||||
```toml
|
||||
[[autostart]]
|
||||
command = ["swayidle", "-w", "timeout", "300", "ferese-lock", "before-sleep", "ferese-lock", "lock", "ferese-lock"]
|
||||
```
|
||||
|
||||
`Ctrl+Alt+Escape` always releases an active client shortcut inhibitor.
|
||||
`ferese-lock` uses swaylock/swaylock-effects and optional
|
||||
`~/.config/ferese/swaylock.conf`. Test unlock in a nested preview before enabling
|
||||
automatic locking. A crashed locker leaves the session locked; recovery requires
|
||||
ending the session from another TTY.
|
||||
|
||||
Keyboard-shortcut inhibition is hidden unless a trusted VM or remote-desktop
|
||||
session explicitly enables it:
|
||||
## Optional session protocols
|
||||
|
||||
```bash
|
||||
FERESE_ENABLE_SHORTCUT_INHIBIT=1 cargo run -p ferese
|
||||
```
|
||||
|
||||
The emergency `Ctrl+Alt+Escape` binding remains available while inhibition is
|
||||
active.
|
||||
|
||||
Screen capture is hidden by default. A session that has already made an
|
||||
explicit capture-policy decision can expose screencopy-v1 to its clients with:
|
||||
|
||||
```bash
|
||||
FERESE_ENABLE_SCREENCOPY=1 cargo run -p ferese
|
||||
```
|
||||
|
||||
The current M5 implementation supports one-shot output and region capture into
|
||||
ARGB8888 shared-memory buffers. Cursor overlays are included only when the
|
||||
capture client requests them.
|
||||
|
||||
### Direct DRM session
|
||||
|
||||
Run the hardware backend from a spare TTY, outside another graphical session:
|
||||
|
||||
```bash
|
||||
RUST_LOG=ferese=debug cargo run -p ferese -- --backend=drm -- foot
|
||||
```
|
||||
|
||||
Do not run that command from a terminal inside the active desktop: the direct
|
||||
backend requests control of the seat and primary DRM device. Use
|
||||
Ctrl+Alt+F1–F12 to switch virtual terminals.
|
||||
|
||||
M4 validation requires the direct session to:
|
||||
|
||||
- start `foot` and render the same animated tiling workload as the nested path;
|
||||
- retain keyboard and pointer input;
|
||||
- pause when switching away and redraw after switching back; and
|
||||
- log page-flip timing and any missed presentation deadlines on the reference
|
||||
integrated GPU.
|
||||
|
||||
The direct path creates an independent render pipeline per connected output and
|
||||
rescans connectors on hotplug. Physical unplug/replug acceptance testing on the
|
||||
reference hardware is still pending.
|
||||
These are launch-time environment switches, not TOML keys. Enable only for
|
||||
trusted clients: `FERESE_ENABLE_INPUT_METHOD=1`,
|
||||
`FERESE_ENABLE_SHORTCUT_INHIBIT=1`, `FERESE_ENABLE_SCREENCOPY=1`.
|
||||
Text input is available by default; Ctrl+Alt+Escape releases an active shortcut
|
||||
inhibitor. Use `feresectl --help` for runtime control commands.
|
||||
@@ -0,0 +1,129 @@
|
||||
# Desktop widgets
|
||||
|
||||
The shell's desktop clock sits above the wallpaper and behind normal windows.
|
||||
Drag the clock to reposition it; it reserves no workspace space.
|
||||
All desktop widgets share dragging: grab the clock or a note's title. Release
|
||||
to save the position, or press Escape to cancel.
|
||||
Dragging stops at other visible widgets on the same output; edges can slide
|
||||
along each other. Disabled widgets and widgets on other outputs do not block it.
|
||||
Each matching output gets a small, transparent surface—not a full-screen canvas.
|
||||
Lock-screen rendering remains separate and does not expose the desktop clock.
|
||||
|
||||
Enable it in Settings → Desktop widgets or in your Ferese config:
|
||||
|
||||
```toml
|
||||
[desktop_widgets.clock]
|
||||
enabled = true
|
||||
outputs = [] # every output; or ["DP-2"] using your own connector
|
||||
anchor = "top_left"
|
||||
margin_x = 64 # distance from anchored left/right edge
|
||||
margin_y = 80 # distance from anchored top/bottom edge
|
||||
width = 440
|
||||
height = 160
|
||||
font_family = "" # empty/omitted follows your desktop font
|
||||
bold = false
|
||||
time_size = 72.0
|
||||
date_size = 18.0
|
||||
time_format = "%-I:%M %p" # 12-hour; "%H:%M" for 24-hour, "%H:%M:%S" for seconds
|
||||
date_format = "%A, %-d %B"
|
||||
time_zone = "" # system zone; or e.g. "Africa/Lagos", "UTC"
|
||||
show_date = true
|
||||
lowercase = true
|
||||
color = "" # theme primary text; or "#ffffff", "#ffffffcc"
|
||||
date_color = "" # theme muted text
|
||||
opacity = 0.9 # multiplies text and optional background alpha
|
||||
alignment = "center" # left, center, right
|
||||
gap = 4.0
|
||||
padding = 12.0
|
||||
background = "" # transparent; or e.g. "#10101080" for a solid tint
|
||||
radius = 16.0 # optional background corner radius
|
||||
```
|
||||
|
||||
Positions: `top_left`, `top_center`, `top_right`, `center_left`, `center`,
|
||||
`center_right`, `bottom_left`, `bottom_center`, `bottom_right`.
|
||||
Margins affect anchored axes only: a centered horizontal position ignores
|
||||
`margin_x`; a centered vertical position ignores `margin_y`.
|
||||
All geometry and text sizes use logical pixels and follow the output's scale.
|
||||
Increase the widget width/height for longer formats or larger text.
|
||||
|
||||
Saving reloads appearance and labels live. Placement, size, output filters and
|
||||
enable/disable changes recreate only clock surfaces; normal windows and the bar
|
||||
remain intact. Disconnecting an output destroys its clock; reconnecting creates
|
||||
one if its name matches the filter. Invalid configuration keeps the last working
|
||||
configuration. Theme changes apply to colors/fonts that have no explicit override.
|
||||
|
||||
Formatting uses [Jiff's strftime-compatible formats](https://docs.rs/jiff/latest/jiff/fmt/strtime/index.html).
|
||||
Seconds update on the shell's existing timer. Without seconds, unchanged labels
|
||||
produce no additional clock buffer damage; there is no widget animation loop.
|
||||
Widget placement can be changed by dragging or through Settings and TOML.
|
||||
Sticky notes also support editing directly on the desktop.
|
||||
|
||||
## Clock limits
|
||||
|
||||
All clock keys are optional. The example enables the clock (disabled by default);
|
||||
the other values illustrate defaults or their empty-string equivalents.
|
||||
`outputs` is an array of strings; `enabled`, `bold`, `show_date`, `lowercase` are
|
||||
booleans; `width`, `height`, and margins are integers. Other sizes/opacity are numbers.
|
||||
|
||||
| Fields | Accepted range |
|
||||
| --- | --- |
|
||||
| `width`, `height` | 64–1600, 32–800 |
|
||||
| `margin_x`, `margin_y` | 0–8192 |
|
||||
| `time_size`, `date_size` | 8–240, 8–96 |
|
||||
| `opacity` | 0–1 |
|
||||
| `gap`, `padding`, `radius` | 0–64, 0–64, 0–128 |
|
||||
| `font_family`, `time_format`, `date_format` | At most 128 bytes each |
|
||||
| `outputs` | At most 32 exact output names, each 1–128 bytes |
|
||||
|
||||
Formats must be valid; `time_zone` must be empty or a recognized IANA name.
|
||||
Colors are empty (inherit), `#RRGGBB` or `#RRGGBBAA`; all numeric values must be finite.
|
||||
|
||||
## Sticky notes
|
||||
|
||||
Settings → Desktop widgets → Add note creates a card. Drag its title to move it;
|
||||
click Edit for its multiline editor, then Done to finish. Text autosaves after
|
||||
500 ms without typing. Escape cancels a drag or finishes editing. Position saves
|
||||
on release; dragging changes the anchor to `top_left` and saves pixel margins.
|
||||
Title, size and style are also editable in Settings. Notes persist in the config.
|
||||
These are plain-text notes, not Markdown or HTML.
|
||||
|
||||
```toml
|
||||
[[desktop_widgets.notes]]
|
||||
id = "today"
|
||||
title = "Today"
|
||||
text = """
|
||||
Review the pull request
|
||||
Take a break
|
||||
"""
|
||||
anchor = "top_right"
|
||||
margin_x = 48
|
||||
margin_y = 80
|
||||
```
|
||||
|
||||
Repeat the table for additional notes; IDs must be unique. Cards stay behind windows
|
||||
and take keyboard focus only when clicked. Set `interactive = false` for a fully
|
||||
click-through card. Long text wraps; increase height if needed. Notes have no idle
|
||||
animation loop. Clock and notes share a compact drag preview moved by the
|
||||
compositor, not an output-sized canvas. It is released when dragging ends.
|
||||
|
||||
| Key | Type | Default / accepted values |
|
||||
| --- | --- | --- |
|
||||
| `id` | string | `"note"`; unique, 1–64 ASCII letters/digits/`-`/`_` |
|
||||
| `enabled` | boolean | `true` |
|
||||
| `interactive` | boolean | `true`; drag/edit controls; `false` is click-through |
|
||||
| `title` | string | `"Note"`; empty hides it; maximum 256 bytes |
|
||||
| `text` | string | `""`; multiline plain text, maximum 16 KiB |
|
||||
| `outputs` | string array | `[]` means all; at most 32 exact names, each 1–128 bytes |
|
||||
| `anchor` | string | `"top_right"`; same nine positions as clock |
|
||||
| `margin_x`, `margin_y` | integer | `48`, `80`; 0–8192; anchored edges only |
|
||||
| `width`, `height` | integer | `320`, `240`; 120–1200, 80–1200 |
|
||||
| `font_family` | string | omitted/empty follows desktop font; maximum 128 bytes |
|
||||
| `text_size`, `title_size` | number | `16`, `18`; 8–96 |
|
||||
| `color` | string | omitted/empty/`"theme"` follows primary text; or hex color |
|
||||
| `background` | string | omitted/`"theme"` follows surface base; empty is transparent; or hex color |
|
||||
| `opacity` | number | `0.9`; 0–1, multiplies text/background alpha |
|
||||
| `padding`, `gap` | number | `20`, `8`; 0–64 |
|
||||
| `radius` | number | `16`; 0–128 |
|
||||
| `alignment` | string | `"left"`; `left`, `center`, `right` |
|
||||
|
||||
At most 32 notes; the entire live config is limited to 60 KiB.
|
||||
@@ -1,454 +0,0 @@
|
||||
# Ferese Shell Design Specification
|
||||
|
||||
Status: Draft for implementation
|
||||
Target: Ferese desktop tier
|
||||
Normative owner: shell behavior and interaction
|
||||
|
||||
Companion documents:
|
||||
- `ferese-window-manager-spec.md` — compositor mechanism and policy
|
||||
- `ferese-theme-ui-spec.md` — visual tokens and exact component geometry
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
`ferese-shell` provides the integrated desktop interface around Ferese-managed
|
||||
windows.
|
||||
|
||||
The initial shell consists of:
|
||||
|
||||
- one floating top bar per output;
|
||||
- an apps-only launcher;
|
||||
- overview controls;
|
||||
- top-bar popovers and a compact control center;
|
||||
- notifications and notification history; and
|
||||
- volume/brightness OSD.
|
||||
|
||||
Ferese deliberately provides no persistent dock or bottom application bar.
|
||||
|
||||
The shell MUST remain optional. If it crashes, managed windows, layout trees,
|
||||
workspaces, focus topology, and client sessions remain valid.
|
||||
|
||||
## 2. Document boundaries
|
||||
|
||||
This document owns:
|
||||
|
||||
```text
|
||||
shell visibility
|
||||
layer-shell roles
|
||||
exclusive-zone behavior
|
||||
focus acquisition/restoration
|
||||
launcher behavior
|
||||
top-bar actions
|
||||
notification/DND behavior
|
||||
modal interaction
|
||||
fullscreen shell behavior
|
||||
shell restart behavior
|
||||
```
|
||||
|
||||
It MUST NOT define raw colors, pixel heights, radii, blur amounts, icon sizes,
|
||||
font sizes, or shadows. Those belong to `ferese-theme-ui-spec.md`.
|
||||
|
||||
## 3. Surface architecture
|
||||
|
||||
The shell uses public layer-shell for normal shell surfaces.
|
||||
|
||||
```text
|
||||
background(output) background layer, optional
|
||||
top_bar(output) top layer, exclusive zone
|
||||
launcher(output) overlay layer, exclusive_zone = 0
|
||||
notification_stack(output) overlay layer, exclusive_zone = 0
|
||||
osd(output) overlay layer, exclusive_zone = 0
|
||||
popover(output) overlay/top, exclusive_zone = 0
|
||||
modal(output) overlay layer, exclusive_zone = 0
|
||||
```
|
||||
|
||||
`ferese-shell-v1` is a private control protocol only. It MUST NOT duplicate
|
||||
layer-shell geometry or roles.
|
||||
|
||||
Its initial responsibilities are:
|
||||
|
||||
```text
|
||||
window list and lifecycle
|
||||
application identity metadata
|
||||
focused / urgent state
|
||||
activate managed window
|
||||
request close
|
||||
enter / exit overview
|
||||
select overview window / workspace
|
||||
```
|
||||
|
||||
## 4. Top bar
|
||||
|
||||
A top bar exists on every active output unless disabled.
|
||||
|
||||
Its conceptual regions are:
|
||||
|
||||
```text
|
||||
LEFT
|
||||
Ferese mark
|
||||
workspace switcher
|
||||
focused application
|
||||
|
||||
CENTER
|
||||
clock / date
|
||||
|
||||
RIGHT
|
||||
notifications
|
||||
sound
|
||||
power
|
||||
control-center entry
|
||||
```
|
||||
|
||||
The top bar is the only persistent shell surface that reserves workspace space.
|
||||
|
||||
Workspace controls MUST use compositor workspace truth and ordinary Ferese
|
||||
workspace policy.
|
||||
|
||||
The top bar SHOULD remain non-keyboard-interactive during ordinary use.
|
||||
|
||||
## 5. Fullscreen behavior
|
||||
|
||||
Entering fullscreen hides the top bar visually.
|
||||
|
||||
The underlying tiled workspace layout region MUST remain unchanged while
|
||||
fullscreen is active.
|
||||
|
||||
A temporary top-bar reveal over fullscreen:
|
||||
|
||||
```text
|
||||
uses overlay presentation
|
||||
uses exclusive_zone = 0
|
||||
does not resize the fullscreen client
|
||||
does not mutate the underlying workspace layout
|
||||
```
|
||||
|
||||
Leaving fullscreen restores the ordinary top-bar presentation without
|
||||
reconfiguring hidden tiled windows merely because the bar reappears.
|
||||
|
||||
## 6. Shell reservation lease
|
||||
|
||||
If `ferese-shell` disconnects unexpectedly, Ferese SHOULD retain the most recent
|
||||
valid Ferese-owned top-bar reservation for a short bounded grace period.
|
||||
|
||||
If the shell reconnects before expiry with a compatible reservation, tiled
|
||||
windows MUST NOT reflow.
|
||||
|
||||
If the grace period expires, Ferese removes the reservation and performs at most
|
||||
one ordinary layout reflow.
|
||||
|
||||
Default:
|
||||
|
||||
```text
|
||||
reservation_grace_ms = 2000
|
||||
```
|
||||
|
||||
## 7. Launcher
|
||||
|
||||
The initial launcher is apps-only.
|
||||
|
||||
Default invocation:
|
||||
|
||||
```text
|
||||
Super + Space
|
||||
```
|
||||
|
||||
The launcher MAY also be opened by a Ferese control in the top bar.
|
||||
|
||||
The launcher:
|
||||
|
||||
- receives keyboard focus immediately;
|
||||
- discovers XDG desktop applications;
|
||||
- searches by application name and normalized desktop identity;
|
||||
- supports pointer and keyboard navigation;
|
||||
- launches selected applications with XDG activation;
|
||||
- dismisses on Escape; and
|
||||
- restores the previous valid managed-window focus on dismissal.
|
||||
|
||||
Initial placeholder:
|
||||
|
||||
```text
|
||||
Search apps…
|
||||
```
|
||||
|
||||
The launcher MUST NOT expose dead tabs for files, settings, commands, or recents.
|
||||
|
||||
Future search providers MAY extend it without changing the base interaction
|
||||
model.
|
||||
|
||||
## 8. Application identity and launch state
|
||||
|
||||
The launcher consumes the compositor's normalized application identity and launch
|
||||
association model.
|
||||
|
||||
It MUST NOT assume strings such as:
|
||||
|
||||
```text
|
||||
firefox
|
||||
org.mozilla.firefox
|
||||
Mozilla Firefox
|
||||
```
|
||||
|
||||
are the same application unless desktop-entry or activation metadata establishes
|
||||
that relationship.
|
||||
|
||||
Ferese does not maintain a persistent running-application strip.
|
||||
|
||||
## 9. Top-bar popovers
|
||||
|
||||
A top-bar control may own one anchored popover.
|
||||
|
||||
Only one primary top-bar popover SHOULD be open per output at a time.
|
||||
|
||||
Initial popovers MAY include:
|
||||
|
||||
```text
|
||||
calendar / time
|
||||
sound
|
||||
battery / power status
|
||||
notifications
|
||||
control center
|
||||
```
|
||||
|
||||
Network and Bluetooth configuration are not part of the initial desktop tier and
|
||||
MUST NOT appear as required or placeholder rows.
|
||||
|
||||
Opening another primary popover closes the previous one on that output.
|
||||
|
||||
## 10. Control center
|
||||
|
||||
The initial control center MAY expose only services backed by real providers:
|
||||
|
||||
```text
|
||||
sound
|
||||
battery / power status
|
||||
Do Not Disturb
|
||||
notification state
|
||||
Ferese Settings
|
||||
```
|
||||
|
||||
Unavailable capabilities are omitted.
|
||||
|
||||
## 11. Do Not Disturb
|
||||
|
||||
When DND is off:
|
||||
|
||||
```text
|
||||
eligible notifications may create transient toasts
|
||||
notifications enter history according to normal policy
|
||||
```
|
||||
|
||||
When DND is on:
|
||||
|
||||
```text
|
||||
normal transient toasts are suppressed
|
||||
notifications still enter history
|
||||
unread state still updates
|
||||
```
|
||||
|
||||
A future explicitly defined critical-urgency policy MAY bypass DND.
|
||||
|
||||
No application-name heuristic may bypass DND.
|
||||
|
||||
DND state persists across shell restart.
|
||||
|
||||
## 12. Notifications
|
||||
|
||||
`ferese-shell` implements `org.freedesktop.Notifications`.
|
||||
|
||||
Initial support:
|
||||
|
||||
```text
|
||||
summary
|
||||
body
|
||||
icon metadata
|
||||
expiry
|
||||
replacement
|
||||
close
|
||||
actions
|
||||
urgency metadata
|
||||
```
|
||||
|
||||
Notification content is untrusted.
|
||||
|
||||
Transient toasts:
|
||||
|
||||
- do not reserve workspace space;
|
||||
- appear beneath the top bar;
|
||||
- obey DND;
|
||||
- do not take keyboard focus by default.
|
||||
|
||||
## 13. Notification center
|
||||
|
||||
Notification history opens from the top bar.
|
||||
|
||||
The initial implementation SHOULD use a large anchored popover rather than a
|
||||
permanent side drawer.
|
||||
|
||||
The center may take shell keyboard focus while interactive and MUST restore the
|
||||
previous managed-window focus when dismissed.
|
||||
|
||||
## 14. OSD
|
||||
|
||||
OSD handles transient state such as:
|
||||
|
||||
```text
|
||||
volume
|
||||
brightness
|
||||
microphone mute
|
||||
keyboard backlight
|
||||
```
|
||||
|
||||
OSD surfaces:
|
||||
|
||||
```text
|
||||
use overlay layer
|
||||
use exclusive_zone = 0
|
||||
never take keyboard focus
|
||||
dismiss automatically
|
||||
```
|
||||
|
||||
## 15. Overview
|
||||
|
||||
`Super+Tab` enters overview.
|
||||
|
||||
Managed-window previews remain compositor-owned live scene nodes.
|
||||
|
||||
The shell provides:
|
||||
|
||||
```text
|
||||
selection affordances
|
||||
application/window labels
|
||||
workspace controls
|
||||
optional later search UI
|
||||
```
|
||||
|
||||
The shell MUST NOT implement overview by continuously copying each managed
|
||||
window into the shell process.
|
||||
|
||||
Window activation and close actions use `ferese-shell-v1`.
|
||||
|
||||
## 16. Modal interaction
|
||||
|
||||
Shell modals are reserved for:
|
||||
|
||||
```text
|
||||
destructive confirmation
|
||||
security-sensitive confirmation
|
||||
irreversible shell action
|
||||
```
|
||||
|
||||
Ordinary settings MUST NOT use shell modals.
|
||||
|
||||
When a shell modal opens:
|
||||
|
||||
```text
|
||||
SeatState.keyboard_focus -> FocusTarget::Shell(modal)
|
||||
```
|
||||
|
||||
The compositor presents the modal above a scrim.
|
||||
|
||||
Input outside the modal is consumed by the scrim and MUST NOT reach managed
|
||||
applications.
|
||||
|
||||
On dismissal, the previous valid managed-window focus is restored.
|
||||
|
||||
Ferese does not ship a polkit authentication agent in the initial desktop tier.
|
||||
|
||||
## 17. Shell restart
|
||||
|
||||
On restart:
|
||||
|
||||
```text
|
||||
managed windows remain unchanged
|
||||
workspace assignments remain unchanged
|
||||
layout trees remain unchanged
|
||||
managed-window focus remains valid where possible
|
||||
```
|
||||
|
||||
The restarted shell reconstructs:
|
||||
|
||||
```text
|
||||
top bars
|
||||
workspace indicators
|
||||
focused-app metadata
|
||||
notification service/state
|
||||
DND state
|
||||
```
|
||||
|
||||
from compositor truth and persistent shell state.
|
||||
|
||||
## 18. Shell configuration
|
||||
|
||||
Representative behavior-only configuration:
|
||||
|
||||
```toml
|
||||
[shell]
|
||||
enabled = true
|
||||
reservation_grace_ms = 2000
|
||||
|
||||
[shell.top_bar]
|
||||
enabled = true
|
||||
hide_in_fullscreen = true
|
||||
show_workspaces = true
|
||||
show_focused_app = true
|
||||
show_clock = true
|
||||
|
||||
[shell.launcher]
|
||||
enabled = true
|
||||
binding = "Super+Space"
|
||||
|
||||
[shell.overview]
|
||||
enabled = true
|
||||
binding = "Super+Tab"
|
||||
|
||||
[shell.notifications]
|
||||
enabled = true
|
||||
do_not_disturb = false
|
||||
```
|
||||
|
||||
Visual measurements do not belong here.
|
||||
|
||||
## 19. First shell implementation slice
|
||||
|
||||
```text
|
||||
top bar
|
||||
launcher
|
||||
one top-bar popover
|
||||
OSD
|
||||
```
|
||||
|
||||
Demo:
|
||||
|
||||
```text
|
||||
1. Start Ferese.
|
||||
2. Top bar appears.
|
||||
3. Workspace and focused-app state are correct.
|
||||
4. Press Super+Space.
|
||||
5. Launcher opens and receives focus.
|
||||
6. Search for Foot and launch it.
|
||||
7. Foot enters the current workspace through normal tiling policy.
|
||||
8. Open Sound from the top bar.
|
||||
9. Sound popover anchors to its invoking control.
|
||||
10. Enter fullscreen.
|
||||
11. Top bar hides without changing the underlying tiled layout region.
|
||||
12. Reveal top bar temporarily as an overlay.
|
||||
13. Exit fullscreen.
|
||||
14. Top bar returns to normal reserved presentation.
|
||||
15. Restart ferese-shell.
|
||||
16. Tiled windows do not reflow during the reservation grace period.
|
||||
```
|
||||
|
||||
## 20. Completion criteria
|
||||
|
||||
The initial shell is complete when:
|
||||
|
||||
1. every active output has a functional top bar;
|
||||
2. launcher search and application launching work;
|
||||
3. workspace indicators reflect compositor truth;
|
||||
4. focused application state is accurate;
|
||||
5. top-bar popovers anchor correctly;
|
||||
6. notifications and DND work;
|
||||
7. OSD works without taking focus;
|
||||
8. overview uses compositor-owned live windows;
|
||||
9. fullscreen hide/reveal does not alter underlying layout geometry;
|
||||
10. shell restart does not disturb managed windows; and
|
||||
11. all visual presentation is supplied through the theme/UI token system.
|
||||
@@ -1,822 +0,0 @@
|
||||
# Ferese Theme and UI Specification
|
||||
|
||||
Status: Draft for implementation
|
||||
Target: Ferese desktop tier
|
||||
Normative owner: visual tokens and component geometry
|
||||
|
||||
Companion documents:
|
||||
- `ferese-window-manager-spec.md` — compositor mechanism and policy
|
||||
- `ferese-shell-design.md` — shell behavior and interaction
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This document defines the Ferese visual language.
|
||||
|
||||
It owns:
|
||||
|
||||
- desktop background treatment;
|
||||
- color tokens;
|
||||
- semantic surface tokens;
|
||||
- typography;
|
||||
- iconography;
|
||||
- spacing;
|
||||
- exact top-bar geometry;
|
||||
- launcher geometry;
|
||||
- popover/menu/modal geometry;
|
||||
- notification geometry;
|
||||
- OSD geometry;
|
||||
- settings UI primitives;
|
||||
- motion tokens; and
|
||||
- glass, translucent, and solid visual profiles.
|
||||
|
||||
It does not define shell focus, fullscreen behavior, workspace policy, launcher
|
||||
behavior, notification policy, or compositor security.
|
||||
|
||||
Ferese intentionally has no persistent dock or bottom application bar.
|
||||
|
||||
## 2. Design language
|
||||
|
||||
Ferese UI should feel:
|
||||
|
||||
```text
|
||||
quiet
|
||||
precise
|
||||
soft
|
||||
material
|
||||
low-latency
|
||||
high-contrast
|
||||
spatially consistent
|
||||
```
|
||||
|
||||
The shell MUST avoid:
|
||||
|
||||
- excessive glow;
|
||||
- RGB/gamer styling;
|
||||
- ornamental gradients;
|
||||
- gratuitous transparency;
|
||||
- oversized shadows;
|
||||
- arbitrary component styling;
|
||||
- large chrome that steals workspace area; and
|
||||
- pixel-for-pixel imitation of another operating system.
|
||||
|
||||
Ferese must still look complete with blur disabled.
|
||||
|
||||
## 3. Theme model
|
||||
|
||||
Components request semantic surface roles:
|
||||
|
||||
```text
|
||||
surface.panel
|
||||
surface.panel_elevated
|
||||
surface.popover
|
||||
surface.menu
|
||||
surface.notification
|
||||
surface.hud
|
||||
surface.modal
|
||||
```
|
||||
|
||||
The active profile maps each role to material parameters.
|
||||
|
||||
Themes change appearance, not component structure or behavior.
|
||||
|
||||
## 4. Material styles
|
||||
|
||||
```rust
|
||||
pub enum MaterialStyle {
|
||||
Glass,
|
||||
Translucent,
|
||||
Solid,
|
||||
}
|
||||
```
|
||||
|
||||
### Glass
|
||||
|
||||
Backdrop blur plus restrained tint, saturation, brightness, and optional noise.
|
||||
|
||||
### Translucent
|
||||
|
||||
Alpha-composited semantic tint with no backdrop blur.
|
||||
|
||||
### Solid
|
||||
|
||||
Opaque semantic surface with identical geometry.
|
||||
|
||||
Changing material style MUST NOT move, resize, or restructure shell components.
|
||||
|
||||
## 5. Built-in profiles
|
||||
|
||||
```text
|
||||
ferese-glass
|
||||
ferese-translucent
|
||||
ferese-solid
|
||||
```
|
||||
|
||||
All share:
|
||||
|
||||
```text
|
||||
component geometry
|
||||
spacing
|
||||
typography
|
||||
icon metrics
|
||||
interaction states
|
||||
motion semantics
|
||||
```
|
||||
|
||||
## 6. Background
|
||||
|
||||
Supported:
|
||||
|
||||
```text
|
||||
solid color
|
||||
image fill
|
||||
image fit
|
||||
```
|
||||
|
||||
```toml
|
||||
[theme.background]
|
||||
path = "/path/to/wallpaper.png"
|
||||
mode = "fill" # fill or fit
|
||||
```
|
||||
|
||||
Ferese SHOULD NOT globally blur the wallpaper.
|
||||
|
||||
Optional restrained adjustments MAY include:
|
||||
|
||||
```text
|
||||
brightness
|
||||
dimming
|
||||
saturation
|
||||
```
|
||||
|
||||
Default fallback:
|
||||
|
||||
```text
|
||||
#0B0F14
|
||||
```
|
||||
|
||||
## 7. Color tokens
|
||||
|
||||
Representative dark profile:
|
||||
|
||||
```toml
|
||||
[theme.colors]
|
||||
desktop_background = "#0B0F14"
|
||||
|
||||
surface_base = "#111821"
|
||||
surface_raised = "#18212C"
|
||||
surface_elevated = "#202B37"
|
||||
|
||||
text_primary = "#F4F7FB"
|
||||
text_secondary = "#B7C0CB"
|
||||
text_muted = "#7F8A98"
|
||||
text_disabled = "#58616D"
|
||||
|
||||
accent = "#5B8CFF"
|
||||
accent_soft = "#8EAFFF"
|
||||
accent_text = "#FFFFFF"
|
||||
|
||||
success = "#4CC38A"
|
||||
warning = "#F0B45B"
|
||||
danger = "#F06A6A"
|
||||
|
||||
border = "#FFFFFF18"
|
||||
border_strong = "#FFFFFF2A"
|
||||
|
||||
shadow = "#00000055"
|
||||
scrim = "#05070AB8"
|
||||
```
|
||||
|
||||
## 8. Surface tokens
|
||||
|
||||
Representative glass profile:
|
||||
|
||||
```toml
|
||||
[theme.surface.panel]
|
||||
style = "glass"
|
||||
opacity = 0.78
|
||||
blur = 24.0
|
||||
saturation = 1.08
|
||||
brightness = 1.02
|
||||
noise = 0.012
|
||||
border_opacity = 0.10
|
||||
shadow = "soft"
|
||||
|
||||
[theme.surface.panel_elevated]
|
||||
style = "glass"
|
||||
opacity = 0.84
|
||||
blur = 28.0
|
||||
saturation = 1.10
|
||||
brightness = 1.03
|
||||
noise = 0.014
|
||||
border_opacity = 0.12
|
||||
shadow = "elevated"
|
||||
|
||||
[theme.surface.popover]
|
||||
style = "glass"
|
||||
opacity = 0.84
|
||||
blur = 28.0
|
||||
saturation = 1.10
|
||||
brightness = 1.03
|
||||
noise = 0.014
|
||||
border_opacity = 0.12
|
||||
shadow = "elevated"
|
||||
|
||||
[theme.surface.hud]
|
||||
style = "glass"
|
||||
opacity = 0.88
|
||||
blur = 30.0
|
||||
saturation = 1.06
|
||||
brightness = 1.04
|
||||
noise = 0.010
|
||||
border_opacity = 0.12
|
||||
shadow = "elevated"
|
||||
```
|
||||
|
||||
## 9. Geometry tokens
|
||||
|
||||
```toml
|
||||
[theme.geometry]
|
||||
base_unit = 8.0
|
||||
|
||||
window_radius = 14.0
|
||||
|
||||
top_bar_height = 38.0
|
||||
top_bar_margin_top = 4.0
|
||||
top_bar_margin_horizontal = 10.0
|
||||
top_bar_radius = 19.0
|
||||
|
||||
launcher_width = 560.0
|
||||
launcher_radius = 20.0
|
||||
|
||||
popover_radius = 16.0
|
||||
menu_radius = 14.0
|
||||
modal_radius = 18.0
|
||||
hud_radius = 18.0
|
||||
|
||||
panel_padding = 12.0
|
||||
control_gap = 8.0
|
||||
section_gap = 16.0
|
||||
```
|
||||
|
||||
Only the top bar consumes persistent shell space.
|
||||
|
||||
## 10. Typography
|
||||
|
||||
```toml
|
||||
[theme.typography]
|
||||
font_family = "sans-serif"
|
||||
```
|
||||
|
||||
Initial roles:
|
||||
|
||||
```text
|
||||
caption 11-12 px
|
||||
body 13-14 px
|
||||
body-strong 13-14 px medium
|
||||
label 12-13 px medium
|
||||
title 16-18 px semibold
|
||||
display 22-28 px semibold
|
||||
```
|
||||
|
||||
Use the system UI sans-serif by default.
|
||||
|
||||
The configured family applies consistently to shell text. Icon assets use the
|
||||
theme icon set and are sized from the same scale tokens rather than text glyph
|
||||
metrics.
|
||||
|
||||
Clocks and changing numeric values SHOULD use tabular numerals where available.
|
||||
|
||||
## 11. Iconography
|
||||
|
||||
System icons are monochrome vectors.
|
||||
|
||||
```text
|
||||
visual box 16-20 px
|
||||
stroke approximately 1.5-2 px
|
||||
style simple and optically balanced
|
||||
```
|
||||
|
||||
Application icons retain original artwork.
|
||||
|
||||
System icons MUST NOT use arbitrary gradients.
|
||||
|
||||
## 12. Top bar
|
||||
|
||||
Default composition:
|
||||
|
||||
```text
|
||||
╭──────────────────────────────────────────────────────────────╮
|
||||
│ F 1 2 3 4 Zed 09:41 🔊 ◉ │
|
||||
╰──────────────────────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
Surface role:
|
||||
|
||||
```text
|
||||
surface.panel
|
||||
```
|
||||
|
||||
### Workspace state
|
||||
|
||||
Inactive workspaces use muted text.
|
||||
|
||||
Active workspace uses a compact filled or accent-backed indicator.
|
||||
|
||||
### Focused application
|
||||
|
||||
May display:
|
||||
|
||||
```text
|
||||
application icon
|
||||
application name
|
||||
```
|
||||
|
||||
Full changing window titles are not part of the default bar.
|
||||
|
||||
### Clock
|
||||
|
||||
Compact:
|
||||
|
||||
```text
|
||||
09:41
|
||||
```
|
||||
|
||||
Optional wide:
|
||||
|
||||
```text
|
||||
Mon, Sep 23 09:41
|
||||
```
|
||||
|
||||
## 13. Launcher
|
||||
|
||||
The launcher is the primary application-selection surface.
|
||||
|
||||
Default placement:
|
||||
|
||||
```text
|
||||
centered horizontally
|
||||
upper-middle or center of usable workspace
|
||||
```
|
||||
|
||||
Surface role:
|
||||
|
||||
```text
|
||||
surface.panel_elevated
|
||||
```
|
||||
|
||||
Default geometry:
|
||||
|
||||
```text
|
||||
width theme.geometry.launcher_width
|
||||
max height 70% of usable output
|
||||
radius theme.geometry.launcher_radius
|
||||
```
|
||||
|
||||
Initial content:
|
||||
|
||||
```text
|
||||
╭──────────────────────────────────────╮
|
||||
│ Search apps… │
|
||||
├──────────────────────────────────────┤
|
||||
│ │
|
||||
│ Zed Firefox Foot │
|
||||
│ Files Settings Music │
|
||||
│ │
|
||||
╰──────────────────────────────────────╯
|
||||
```
|
||||
|
||||
Initial implementation is apps-only.
|
||||
|
||||
## 14. Launcher search field
|
||||
|
||||
```text
|
||||
height 44-48 px
|
||||
radius 12 px
|
||||
```
|
||||
|
||||
Placeholder:
|
||||
|
||||
```text
|
||||
Search apps…
|
||||
```
|
||||
|
||||
The search field is the visual focus.
|
||||
|
||||
## 15. Launcher application grid
|
||||
|
||||
Recommended:
|
||||
|
||||
```text
|
||||
4-6 columns depending on launcher width
|
||||
```
|
||||
|
||||
Entries show:
|
||||
|
||||
```text
|
||||
application icon
|
||||
one-line application name
|
||||
```
|
||||
|
||||
Long names truncate with ellipsis.
|
||||
|
||||
## 16. Top-bar popovers
|
||||
|
||||
Surface:
|
||||
|
||||
```text
|
||||
surface.popover
|
||||
```
|
||||
|
||||
Recommended:
|
||||
|
||||
```text
|
||||
width 280-360 px
|
||||
padding 12 px
|
||||
radius theme.geometry.popover_radius
|
||||
anchor gap 8 px
|
||||
```
|
||||
|
||||
They visually align with the invoking top-bar control.
|
||||
|
||||
## 17. Control center
|
||||
|
||||
Representative:
|
||||
|
||||
```text
|
||||
╭──────────────────────────────╮
|
||||
│ Sound │
|
||||
│ ━━━━━━━━━━━●━━━━━━ │
|
||||
│ │
|
||||
│ Battery 92% │
|
||||
│ Do Not Disturb Off │
|
||||
│ Notifications 3 │
|
||||
│ │
|
||||
│ Ferese Settings │
|
||||
╰──────────────────────────────╯
|
||||
```
|
||||
|
||||
Network/Bluetooth rows are not part of the initial visual contract.
|
||||
|
||||
## 18. Menus
|
||||
|
||||
Menus use:
|
||||
|
||||
```text
|
||||
surface.menu
|
||||
```
|
||||
|
||||
Row:
|
||||
|
||||
```text
|
||||
icon label shortcut
|
||||
```
|
||||
|
||||
Disabled items use `text_disabled`.
|
||||
|
||||
## 19. Modals
|
||||
|
||||
Modals use:
|
||||
|
||||
```text
|
||||
surface.modal
|
||||
```
|
||||
|
||||
Default width:
|
||||
|
||||
```text
|
||||
360-480 px
|
||||
```
|
||||
|
||||
Background scrim uses `theme.colors.scrim`.
|
||||
|
||||
Modal visuals do not imply a Ferese authentication agent.
|
||||
|
||||
## 20. Notifications
|
||||
|
||||
Toast surface:
|
||||
|
||||
```text
|
||||
surface.notification
|
||||
```
|
||||
|
||||
Recommended width:
|
||||
|
||||
```text
|
||||
320-360 px
|
||||
```
|
||||
|
||||
Structure:
|
||||
|
||||
```text
|
||||
icon
|
||||
summary
|
||||
body
|
||||
time
|
||||
optional actions
|
||||
```
|
||||
|
||||
Newest appears nearest the top bar.
|
||||
|
||||
## 21. OSD
|
||||
|
||||
Surface:
|
||||
|
||||
```text
|
||||
surface.hud
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
╭──────────────────────╮
|
||||
│ 🔊 ━━━━━━━●━━━━━ │
|
||||
╰──────────────────────╯
|
||||
```
|
||||
|
||||
Default placement is centered or lower-middle.
|
||||
|
||||
## 22. Overview chrome
|
||||
|
||||
Managed windows remain live compositor surfaces.
|
||||
|
||||
Theme/UI owns only:
|
||||
|
||||
```text
|
||||
selection ring
|
||||
labels
|
||||
workspace strip
|
||||
scrim
|
||||
overview control surfaces
|
||||
```
|
||||
|
||||
Selected preview uses an accent ring, not a large glow.
|
||||
|
||||
## 23. Interaction states
|
||||
|
||||
Controls support:
|
||||
|
||||
```text
|
||||
rest
|
||||
hover
|
||||
pressed
|
||||
focused
|
||||
selected
|
||||
disabled
|
||||
urgent where applicable
|
||||
```
|
||||
|
||||
Hover changes color/contrast only.
|
||||
|
||||
Pressed controls MAY use a tiny local scale response around `0.98`.
|
||||
|
||||
There is no dock-style magnification behavior.
|
||||
|
||||
## 24. Focus rings
|
||||
|
||||
Keyboard focus:
|
||||
|
||||
```text
|
||||
2 px accent ring
|
||||
2 px visual separation where needed
|
||||
```
|
||||
|
||||
Focus rings MUST NOT alter component geometry.
|
||||
|
||||
## 25. Shadows
|
||||
|
||||
Levels:
|
||||
|
||||
```text
|
||||
none
|
||||
soft
|
||||
elevated
|
||||
```
|
||||
|
||||
Representative:
|
||||
|
||||
```toml
|
||||
[theme.shadow.soft]
|
||||
offset_y = 4.0
|
||||
blur = 18.0
|
||||
opacity = 0.20
|
||||
|
||||
[theme.shadow.elevated]
|
||||
offset_y = 10.0
|
||||
blur = 36.0
|
||||
opacity = 0.28
|
||||
```
|
||||
|
||||
Top bar uses `soft`.
|
||||
|
||||
Launcher, popovers, notifications, modals, and HUDs typically use `elevated`.
|
||||
|
||||
## 26. Borders
|
||||
|
||||
Default:
|
||||
|
||||
```text
|
||||
1 logical px
|
||||
```
|
||||
|
||||
Glass uses subtle highlight borders.
|
||||
|
||||
Solid may use slightly stronger borders.
|
||||
|
||||
Borders MUST NOT resemble neon outlines.
|
||||
|
||||
## 27. Motion tokens
|
||||
|
||||
```text
|
||||
spatial spring
|
||||
bounded easing
|
||||
```
|
||||
|
||||
Approximate ranges:
|
||||
|
||||
```text
|
||||
micro feedback 80-120 ms
|
||||
popover/menu 140-200 ms
|
||||
launcher 180-240 ms
|
||||
notification 160-220 ms
|
||||
```
|
||||
|
||||
Managed-window and overview motion remains compositor spring-driven.
|
||||
|
||||
## 28. Reduced motion
|
||||
|
||||
Reduced motion:
|
||||
|
||||
```text
|
||||
removes decorative scale
|
||||
shortens/removes large shell translation
|
||||
uses opacity where spatial context is unnecessary
|
||||
does not animate blur intensity
|
||||
```
|
||||
|
||||
## 29. Fullscreen visual presentation
|
||||
|
||||
When fullscreen is active, the top bar is visually absent.
|
||||
|
||||
Temporary reveal uses the same visual tokens without implying any layout change.
|
||||
|
||||
## 30. Settings application
|
||||
|
||||
Ferese Settings consumes the same tokens.
|
||||
|
||||
Representative layout:
|
||||
|
||||
```text
|
||||
╭──────────────────────────────────────────────╮
|
||||
│ sidebar │ content │
|
||||
│ │ │
|
||||
│ General │ Appearance │
|
||||
│ Appearance │ │
|
||||
│ Tiling │ live preview │
|
||||
│ Workspaces │ controls │
|
||||
│ Shortcuts │ │
|
||||
│ Input │ │
|
||||
╰──────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
## 31. Appearance settings
|
||||
|
||||
Expose:
|
||||
|
||||
```text
|
||||
material style
|
||||
accent
|
||||
corner radius
|
||||
shadow intensity
|
||||
glass blur
|
||||
glass opacity
|
||||
animation speed
|
||||
reduced motion
|
||||
```
|
||||
|
||||
Material style:
|
||||
|
||||
```text
|
||||
Glass
|
||||
Translucent
|
||||
Solid
|
||||
```
|
||||
|
||||
Changing style MUST preserve geometry.
|
||||
|
||||
## 32. Theme configuration
|
||||
|
||||
```toml
|
||||
[theme]
|
||||
profile = "ferese-glass"
|
||||
mode = "dark"
|
||||
|
||||
[theme.colors]
|
||||
accent = "#5B8CFF"
|
||||
|
||||
[theme.material]
|
||||
style = "glass"
|
||||
|
||||
[theme.material.glass]
|
||||
blur = 24.0
|
||||
opacity = 0.80
|
||||
saturation = 1.08
|
||||
noise = 0.012
|
||||
|
||||
[theme.geometry]
|
||||
window_radius = 14.0
|
||||
top_bar_height = 38.0
|
||||
top_bar_radius = 19.0
|
||||
launcher_width = 560.0
|
||||
launcher_radius = 20.0
|
||||
|
||||
[theme.motion]
|
||||
speed = 1.0
|
||||
reduced_motion = false
|
||||
```
|
||||
|
||||
## 33. Validation
|
||||
|
||||
Reject:
|
||||
|
||||
```text
|
||||
non-finite dimensions
|
||||
negative radii
|
||||
negative blur
|
||||
opacity outside 0..1
|
||||
invalid colors
|
||||
unknown material style
|
||||
invalid font sizes
|
||||
invalid motion factors
|
||||
```
|
||||
|
||||
Theme changes use the same transactional Ferese configuration path.
|
||||
|
||||
## 34. Custom theme scope
|
||||
|
||||
Themes MAY change:
|
||||
|
||||
```text
|
||||
colors
|
||||
material parameters
|
||||
radii
|
||||
shadows
|
||||
typography
|
||||
accent
|
||||
icon tint
|
||||
motion scale
|
||||
validated component geometry tokens
|
||||
```
|
||||
|
||||
Themes MUST NOT change:
|
||||
|
||||
```text
|
||||
top-bar behavior
|
||||
launcher behavior
|
||||
focus behavior
|
||||
workspace behavior
|
||||
notification policy
|
||||
Wayland roles
|
||||
security behavior
|
||||
```
|
||||
|
||||
Ferese intentionally does not expose arbitrary CSS.
|
||||
|
||||
## 35. Performance degradation
|
||||
|
||||
Priority:
|
||||
|
||||
```text
|
||||
1. geometry correctness
|
||||
2. input latency
|
||||
3. text/icon clarity
|
||||
4. animation continuity
|
||||
5. shadow quality
|
||||
6. blur quality
|
||||
7. decorative effects
|
||||
```
|
||||
|
||||
Allowed degradation:
|
||||
|
||||
```text
|
||||
glass
|
||||
-> lower-resolution glass
|
||||
-> translucent
|
||||
-> solid
|
||||
```
|
||||
|
||||
Component geometry remains unchanged.
|
||||
|
||||
## 36. Visual acceptance criteria
|
||||
|
||||
Implementation succeeds when:
|
||||
|
||||
1. top bar, launcher, popovers, notifications, OSD, overview chrome, and Settings
|
||||
share one spacing/material/typography system;
|
||||
2. glass, translucent, and solid profiles preserve geometry;
|
||||
3. typography remains readable on bright and dark backgrounds;
|
||||
4. icons have consistent optical weight;
|
||||
5. launcher and popovers look anchored and intentional;
|
||||
6. focus/selection/urgent states remain distinct without relying on glow;
|
||||
7. disabling blur does not make the desktop look unfinished;
|
||||
8. reduced-motion mode remains coherent; and
|
||||
9. the desktop feels complete without a persistent dock or bottom application bar.
|
||||
File diff suppressed because it is too large.
Load diff
+29
-54
@@ -1,73 +1,48 @@
|
||||
# Fedora / SDDM installation
|
||||
# Installation
|
||||
|
||||
From the checkout, run the installer as your normal user:
|
||||
## Build and install
|
||||
|
||||
On Fedora with SDDM, install a Rust toolchain (1.93 or newer), native build
|
||||
dependencies, `desktop-file-utils`, D-Bus and `foot`. Wallpaper browsing also
|
||||
needs `zenity`; locking needs swaylock or swaylock-effects.
|
||||
|
||||
From the checkout, run as your normal user:
|
||||
|
||||
```sh
|
||||
./scripts/install.sh
|
||||
```
|
||||
|
||||
It builds all four release binaries with the locked dependencies, then uses
|
||||
`sudo` (or `pkexec`) for installation. Install the Rust toolchain, native build
|
||||
dependencies, `desktop-file-utils`, and D-Bus first. Cargo reports missing native
|
||||
libraries during the build. The shell requires Rust 1.93 or newer.
|
||||
|
||||
Useful options:
|
||||
The script builds locked release binaries, then requests elevation to install.
|
||||
It preserves your configuration and other desktop sessions. Log out and select
|
||||
**Ferese** at the login screen. Upgrades require logging out and back in too.
|
||||
|
||||
```sh
|
||||
./scripts/install.sh --dry-run
|
||||
./scripts/install.sh --offline --release-id my-demo
|
||||
./scripts/install.sh --skip-build --release-id existing-build
|
||||
./scripts/install.sh --offline --release-id my-build
|
||||
./scripts/install.sh --skip-build
|
||||
```
|
||||
|
||||
The script works from any directory and preserves your user configuration.
|
||||
Use `--help` for all options. To test and install manually:
|
||||
Use `--help` for all options. New configs can be copied from
|
||||
`/usr/local/lib/ferese/current/config.example.toml` to
|
||||
`~/.config/ferese/config.toml`. See [Configuration](configuration.md).
|
||||
|
||||
```sh
|
||||
cargo test -p ferese -p feresectl -p ferese-animation -p ferese-core -p ferese-layout -p ferese-shell -p ferese-settings --locked
|
||||
cargo build --release --locked -p ferese -p ferese-shell -p ferese-settings -p feresectl
|
||||
sudo bash scripts/install-session.sh YOUR_RELEASE_ID
|
||||
```
|
||||
## Preview and logs
|
||||
|
||||
The installer adds **Ferese** to SDDM without changing Plasma or
|
||||
the default session. It installs immutable, versioned directories in
|
||||
`/usr/local/lib/ferese/releases/` and launchers in `/usr/local/bin/`.
|
||||
`current` selects the installed build; `previous` records the prior selection
|
||||
on upgrades. Installation refuses to replace unmanaged launchers/session files.
|
||||
Run `ferese-session --nested` inside an existing Wayland desktop. For a hardware
|
||||
session, use the login screen or a spare TTY; never run Ferese as root or start
|
||||
its DRM backend inside an active graphical session.
|
||||
|
||||
Keep your existing `~/.config/ferese/config.toml`. For a new configuration, copy
|
||||
`/usr/local/lib/ferese/current/config.example.toml` there. The existing compositor
|
||||
defaults handle connected monitors automatically; add output profiles only after
|
||||
checking `feresectl get-outputs` on the actual DRM session.
|
||||
|
||||
Use `ferese-session --nested` for an installed-build preview. Log out of Plasma
|
||||
and select Ferese in SDDM for real hardware use. `ferese-session` can also run
|
||||
from a spare logged-in TTY. It must run as your normal user, never as root.
|
||||
Foot and `dbus-run-session` must be installed.
|
||||
|
||||
Session logs are written under `${XDG_STATE_HOME:-~/.local/state}/ferese/`.
|
||||
The launcher sets Wayland desktop variables, starts D-Bus if none is available,
|
||||
and grants shell capabilities only to the compositor-launched shell process.
|
||||
It does not enable public screencopy, privileged input methods, or shortcut
|
||||
inhibition by default.
|
||||
Logs are stored in `${XDG_STATE_HOME:-~/.local/state}/ferese/`. Keep an existing
|
||||
desktop available while testing scaling, monitor hotplug, suspend and locking.
|
||||
|
||||
## Logout and recovery
|
||||
|
||||
Save your work, then press **Super+Shift+E** or run `feresectl exit` to log out.
|
||||
Ferese stops its event loop and terminates its shell child during shutdown.
|
||||
This is immediate logout, without a save-confirmation dialog.
|
||||
Save your work before **Super+Shift+E** or `feresectl exit`: logout is immediate.
|
||||
If frozen, switch to another TTY with Ctrl+Alt+F1–F12, terminate the specific
|
||||
Ferese process, and select your other desktop on the next login. Restarting SDDM
|
||||
also ends other sessions, so avoid it with unsaved work.
|
||||
|
||||
If the compositor becomes unresponsive, switch to another TTY using
|
||||
Ctrl+Alt+F1–F12 and terminate that specific Ferese process. Select Plasma on the
|
||||
next login. Do not restart SDDM while a desktop contains unsaved work.
|
||||
|
||||
For a binary rollback, inspect `/usr/local/lib/ferese/previous` and select that
|
||||
release with the `current` symlink while Ferese is stopped. Existing releases
|
||||
are retained. To hide the login option, move
|
||||
Installed binaries live in `/usr/local/lib/ferese/releases/`. While Ferese is
|
||||
stopped, select a retained release with the `current` symlink; `previous` points
|
||||
to the prior installation. To hide the session option, move
|
||||
`/usr/share/wayland-sessions/ferese.desktop` out of that directory.
|
||||
|
||||
## First hardware session
|
||||
|
||||
Verify terminal/editor/browser, clipboard, fullscreen, fractional scaling,
|
||||
monitor disconnect/reconnect, VT switching away/back, and logout. Suspend/resume
|
||||
and session locking are not certified by the nested smoke test. Keep Plasma
|
||||
available until real development sessions and these checks pass.
|
||||
@@ -1,71 +0,0 @@
|
||||
# Native-client soak testing
|
||||
|
||||
The M6 soak runner repeatedly creates and destroys native Wayland clients while
|
||||
exercising focus, resize, column width, fullscreen, floating, and workspace
|
||||
paths. Every tenth iteration also terminates a client abruptly. If a local
|
||||
malformed-client probe is available, it opens three isolated connections that
|
||||
send malformed Wayland messages. The runner requires
|
||||
Ferese to disconnect each malformed client and then checks that the compositor
|
||||
and authenticated IPC socket remain responsive. It also records compositor RSS
|
||||
growth.
|
||||
|
||||
Build Ferese and `feresectl`, start the compositor, and run:
|
||||
|
||||
```bash
|
||||
FERESE_TRACE_PERFORMANCE=1 cargo run -p ferese -- foot
|
||||
```
|
||||
|
||||
From a terminal connected to Ferese, or from the host with the Ferese socket
|
||||
selected, run:
|
||||
|
||||
```bash
|
||||
WAYLAND_DISPLAY=wayland-1 \
|
||||
FERESE_PID="$(pgrep -n -x ferese)" \
|
||||
./scripts/soak-native.sh
|
||||
```
|
||||
|
||||
The default duration is 24 hours. A shorter validation run is:
|
||||
|
||||
```bash
|
||||
WAYLAND_DISPLAY=wayland-1 \
|
||||
FERESE_PID="$(pgrep -n -x ferese)" \
|
||||
FERESE_SOAK_SECONDS=300 \
|
||||
./scripts/soak-native.sh
|
||||
```
|
||||
|
||||
Development probes are local-only, not distributed in the Cargo workspace.
|
||||
Supply an existing executable with `FERESE_MALFORMED_CLIENT` to enable protocol
|
||||
checks. An explicitly configured missing probe is an error; without a probe,
|
||||
the runner reports that protocol checks are skipped.
|
||||
|
||||
The local probe can also be run independently against a disposable Ferese session:
|
||||
|
||||
```bash
|
||||
WAYLAND_DISPLAY=wayland-1 /path/to/ferese-malformed-client
|
||||
target/debug/feresectl get-outputs
|
||||
```
|
||||
|
||||
Do not point the malformed-client probe at the host compositor socket.
|
||||
|
||||
Environment controls:
|
||||
|
||||
- `FERESE_SOAK_SECONDS`: run duration, default `86400`;
|
||||
- `FERESE_SOAK_DELAY`: delay between operations, default `0.15` seconds;
|
||||
- `FERESE_SOAK_CLIENT`: native client executable, default `foot`;
|
||||
- `FERESECTL`: path to `feresectl`, default `target/debug/feresectl`;
|
||||
- `FERESE_MALFORMED_CLIENT`: path to the malformed protocol probe, default
|
||||
`target/debug/ferese-malformed-client`;
|
||||
- `FERESE_PID`: compositor PID; automatic lookup is only a fallback;
|
||||
- `FERESE_SOAK_LOG`: result log, default `/tmp/ferese-soak-<pid>.log`.
|
||||
- `FERESE_SOAK_MAX_RSS_GROWTH_KIB`: maximum RSS growth, default `131072`
|
||||
(128 MiB);
|
||||
- `FERESE_SOAK_MAX_FD_GROWTH`: maximum open-file-descriptor growth, default
|
||||
`32`;
|
||||
- `FERESE_SOAK_MAX_THREAD_GROWTH`: maximum thread growth, default `8`.
|
||||
|
||||
Run the same workload once with the nested backend and once from a direct DRM
|
||||
session. Samples are taken after spawned clients are reaped. A passing run
|
||||
requires the compositor to remain alive, IPC queries to succeed, and RSS, file
|
||||
descriptor, and thread growth to stay within the declared budgets. Tighten the
|
||||
defaults for release hardware when its normal cache behavior is known. Preserve
|
||||
the soak log and the `ferese::render` summaries with the release artifacts.
|
||||
@@ -1,61 +0,0 @@
|
||||
# Nested live-resize regression check
|
||||
|
||||
The shell enables libcosmic's `wgpu` feature. Without it, iced uses tiny-skia
|
||||
to resample and rasterize the wallpaper on the CPU. In an unoptimized build,
|
||||
this blocks the UI/render thread shared with the top bar for seconds. Prompt
|
||||
layer configures, buffer stretching, and compositor vsync cannot fix that
|
||||
client-side bottleneck. Software rendering remains available as a fallback.
|
||||
|
||||
## Reproduce and compare
|
||||
|
||||
```sh
|
||||
cargo build --locked -p ferese -p ferese-shell
|
||||
WAYLAND_DEBUG=1 FERESE_TRACE_PERFORMANCE=1 \
|
||||
target/debug/ferese --backend nested --grant-effects --grant-shell-control -- \
|
||||
target/debug/ferese-shell 2>/tmp/ferese-resize.log
|
||||
```
|
||||
|
||||
Use a configured wallpaper. Drag the host window's edges in both directions,
|
||||
then maximize/restore it repeatedly. Check that the wallpaper and bar follow
|
||||
the window, including at fractional host scaling. Repeat with
|
||||
`ICED_BACKEND=wgpu` to require GPU rendering (rather than silently accepting
|
||||
fallback), and with `ICED_BACKEND=tiny-skia` to compare software rendering.
|
||||
Use a release build if software fallback is needed for regular use.
|
||||
|
||||
Trace the chain, not just the compositor's frame rate:
|
||||
|
||||
1. Host `xdg_toplevel.configure` becomes Winit `Resized`.
|
||||
2. Ferese updates the output, arranges layers, and sends
|
||||
`zwlr_layer_surface_v1.configure` for the new logical dimensions.
|
||||
3. The shell acknowledges configure and eventually attaches/commits a new
|
||||
buffer. A fast acknowledgement does **not** imply a finished render.
|
||||
4. Committed buffers change surface damage; Ferese renders the damaged output
|
||||
and submits through EGL to the host compositor.
|
||||
|
||||
`FERESE_TRACE_PERFORMANCE` measures Ferese's rendering/submission, not shell
|
||||
rasterization. Wayland traces distinguish software SHM buffers from GPU
|
||||
buffers (Mesa Vulkan on the tested system).
|
||||
|
||||
## Measured validation (KDE Wayland, 175% scale)
|
||||
|
||||
With temporary instrumentation, 24 host maximize/restore requests spaced
|
||||
250 ms apart generated 26 Winit resize events including initialization. The
|
||||
same debug binaries were tested with each renderer forced:
|
||||
|
||||
| Measurement | tiny-skia | wgpu |
|
||||
| --- | ---: | ---: |
|
||||
| Median configure acknowledgement | 1.35 ms | 2.27 ms |
|
||||
| Median Ferese render + submit | 0.82 ms | 1.10 ms |
|
||||
| Wallpaper buffer interval | 5919 ms (only two buffers) | 9.85 ms median |
|
||||
| Bar buffers observed | 1 | 996 |
|
||||
|
||||
The CPU capture ran for 14 seconds and the GPU capture for 18 seconds;
|
||||
counts are diagnostic, not equal-duration throughput benchmarks. GPU maximum
|
||||
buffer intervals were about 200 ms for wallpaper and 158 ms for the bar, so
|
||||
the median does not imply every frame met a refresh deadline. These figures
|
||||
include protocol tracing overhead. The temporary resize/timing hooks were
|
||||
removed after testing; no synthetic resizing runs in production.
|
||||
|
||||
The fix does not alter output coordinates, layer exclusion, damage tracking,
|
||||
frame scheduling, or EGL swap settings. It also applies to the same shell
|
||||
running under DRM, though this validation used the nested backend.
|
||||
Reference in new issue
Block a user