Add desktop widgets and streamline documentation

This commit is contained in:
Samuel Onoja committed 2026-09-26 22:53:51 +01:00
1 parent c63af64d87
commit 8dc895448d
25 files changed
+2724 -3686

No files matched your search

+213 -379
View File
@@ -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.