Simplify documentation and website; expand shortcut guides
This commit is contained in:
1 parent
46509f880a
commit
4d60c296a7
26 files changed
+1060
-1032
No files matched your search
+1
-7
@@ -3,14 +3,8 @@
|
|||||||
*.log
|
*.log
|
||||||
ChatGPT Image*.png
|
ChatGPT Image*.png
|
||||||
|
|
||||||
# Local implementation notes and validation plans
|
# Local architecture decision notes
|
||||||
/docs/adr/
|
/docs/adr/
|
||||||
/docs/animation-validation.md
|
|
||||||
/docs/nested-resize-testing.md
|
|
||||||
/docs/native-soak-testing.md
|
|
||||||
/docs/ferese-window-manager-spec.md
|
|
||||||
/docs/ferese-theme-ui-spec.md
|
|
||||||
/docs/ferese-shell-design.md
|
|
||||||
|
|
||||||
# Generated GitHub Pages site
|
# Generated GitHub Pages site
|
||||||
/build/site/
|
/build/site/
|
||||||
|
|||||||
@@ -2,60 +2,35 @@
|
|||||||
<img src="docs/images/ferese-lockup.svg" width="300" alt="Ferese">
|
<img src="docs/images/ferese-lockup.svg" width="300" alt="Ferese">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center"><strong>A beautiful, fluid Wayland desktop made to feel like yours.</strong></p>
|
<p align="center"><strong>A Wayland desktop with scrolling layouts and a shared theme.</strong></p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="docs/installation.md">Install</a> ·
|
<a href="docs/installation.md">Install</a> ·
|
||||||
<a href="docs/configuration.md">Configure</a> ·
|
<a href="docs/configuration.md">Configure</a> ·
|
||||||
<a href="docs/desktop-widgets.md">Widgets</a> ·
|
<a href="docs/README.md">Documentation</a>
|
||||||
<a href="docs/notifications.md">Notifications</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Ferese is a complete Wayland desktop built around personalization. Its custom
|
Ferese is a Linux desktop with scrolling columns, tree tiling, and floating
|
||||||
shell, native settings, live-reloading themes and wallpapers, desktop widgets,
|
windows. It includes a top bar, Settings, notifications, desktop widgets, a
|
||||||
fluid animations, and scrolling and tiling layouts work together as one
|
lock screen, and screen sharing. Change themes and settings without restarting.
|
||||||
cohesive experience—beautiful by default and unmistakably yours.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Why Ferese
|
## Features
|
||||||
|
|
||||||
- **Flexible layouts:** scrolling columns, tree tiling, floating windows and a
|
- Scrolling and tree layouts, floating windows, and a workspace overview.
|
||||||
workspace overview.
|
- Configurable keyboard shortcuts and touchpad gestures.
|
||||||
- **A native shell:** menu bar, control center, settings, notifications and
|
- Multiple monitors with fractional scaling.
|
||||||
desktop widgets designed to belong together, including themed authentication prompts.
|
- Six theme presets, wallpapers, blur, and adjustable corners.
|
||||||
Native apps share the [Ferese theme components](crates/ferese-theme/README.md).
|
- Clock and sticky-note widgets.
|
||||||
- **Personal by design:** themes, wallpapers, accent colors, blur, borders and
|
- Screenshots with Satty editing, screen sharing, and top-bar recording.
|
||||||
motion that update without restarting your session.
|
|
||||||
- **Ready for real setups:** gestures, multi-monitor support, fractional
|
|
||||||
scaling, screenshots, background services and session locking.
|
|
||||||
- **Screen sharing:** a native display picker and PipeWire video streams for
|
|
||||||
portal-compatible recording and conferencing apps.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The overview brings windows and workspaces into one view. Read more about
|
|
||||||
[why Ferese builds the compositor and shell together](docs/why-ferese.md).
|
|
||||||
|
|
||||||
## Make it yours
|
|
||||||
|
|
||||||
Use the native Settings app for everyday customization, or edit
|
|
||||||
`~/.config/ferese/config.kdl` when you want complete control. Ferese reloads
|
|
||||||
changes as you make them and keeps the last working configuration if an edit is
|
|
||||||
invalid.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Choose a preset or build your own look. Window behavior, gestures, shortcuts,
|
|
||||||
rules, displays, widgets and login items are configurable too. Start with the
|
|
||||||
[configuration guide](docs/configuration.md) or the
|
|
||||||
[example config](packaging/config.kdl).
|
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
Install Ferese on Linux with any Wayland-capable login manager, a command-based
|
Install the [dependencies](docs/installation.md#requirements), then build as your
|
||||||
greeter, or a local TTY. Start with the [installation guide](docs/installation.md)
|
normal user:
|
||||||
for system dependencies and Rust 1.95 or newer, then build as your normal user:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/ferese-wm/ferese.git
|
git clone https://github.com/ferese-wm/ferese.git
|
||||||
@@ -63,59 +38,48 @@ cd ferese
|
|||||||
./scripts/install.sh
|
./scripts/install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Log out and select **Ferese** at your login screen. For greeters that take a
|
Log out, select **Ferese** at your login screen, and sign in. For a TTY or a
|
||||||
session command, use `/usr/local/bin/ferese-session`. The installer preserves
|
greeter that accepts a command, run `ferese-session`.
|
||||||
your configuration and other sessions, and retains the previous release for
|
See [Installation](docs/installation.md) for previews, updates, and recovery.
|
||||||
rollback. The guide covers [all startup methods](docs/installation.md#start-a-session),
|
|
||||||
optional tools, updates, and recovery.
|
|
||||||
|
|
||||||
To preview Ferese inside your current Wayland desktop instead:
|
## Configure
|
||||||
|
|
||||||
```sh
|
Open **Control Center → Settings**, or edit `~/.config/ferese/config.kdl`.
|
||||||
cargo build --release --locked -p ferese -p ferese-shell -p ferese-settings -p feresectl -p ferese-lock
|
Changes reload automatically; invalid edits keep the last working configuration.
|
||||||
target/release/ferese --backend nested --grant-effects --grant-shell-control -- \
|
|
||||||
target/release/ferese-shell
|
|
||||||
```
|
|
||||||
|
|
||||||
## Get around
|

|
||||||
|
|
||||||
These are the built-in defaults; every shortcut and gesture can be changed.
|
See the [configuration reference](docs/configuration.md) and
|
||||||
The login guide shows your active shortcuts. Disable it in **Settings → Shortcuts**
|
[example config](packaging/config.kdl).
|
||||||
when you no longer need it.
|
|
||||||
|
## Default shortcuts
|
||||||
|
|
||||||
|
`Super` is usually the Windows key. Change shortcuts and gestures in
|
||||||
|
**Settings → Shortcuts**.
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Super + Enter | Open a terminal |
|
| Super + Enter | Open a terminal |
|
||||||
| Super + H / J / K / L | Focus a window |
|
| Super + H / J / K / L | Focus left / down / up / right |
|
||||||
|
| Super + F | Maximize the window |
|
||||||
|
| Super + Shift + F | Toggle fullscreen |
|
||||||
| Super + R | Cycle column width |
|
| Super + R | Cycle column width |
|
||||||
| Super + Tab | Open workspace and window overview |
|
| Super + Tab | Open overview |
|
||||||
| Super + M | Switch scrolling / tree layout |
|
| Super + M | Switch scrolling / tree layout |
|
||||||
|
| Print Screen | Capture the active monitor and open Satty |
|
||||||
| Super + Shift + S | Select a screenshot area |
|
| Super + Shift + S | Select a screenshot area |
|
||||||
|
| Super + Shift + E | Ask to log out |
|
||||||
|
|
||||||
Click the bar date for a calendar. Click the battery for power modes and
|
See [all shortcuts and mouse actions](docs/shortcuts.md), including Super-drag
|
||||||
confirmed Restart, Power off and Suspend actions.
|
to move and Super-right-drag to resize floating windows.
|
||||||
|
|
||||||
Three-finger swipes move between workspaces and windows. Open **Control Center →
|
Three-finger swipes up/down switch workspaces; left/right focus windows.
|
||||||
Settings → Shortcuts** to change them or assign gestures to other actions.
|
The shortcut guide appears at login until disabled in Settings.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- [Why Ferese](docs/why-ferese.md)
|
Start with the [documentation index](docs/README.md) for user guides and
|
||||||
- [Installation and recovery](docs/installation.md)
|
[development instructions](docs/development.md) for builds and testing.
|
||||||
- [Configuration reference](docs/configuration.md)
|
|
||||||
- [Desktop widgets](docs/desktop-widgets.md)
|
|
||||||
- [Notifications](docs/notifications.md)
|
|
||||||
- [Native locker](docs/locking.md)
|
|
||||||
- [Desktop portals and compatibility](docs/portals.md)
|
|
||||||
- [Screen sharing and recording](docs/screen-sharing.md)
|
|
||||||
|
|
||||||
## Development
|
Ferese is written in Rust using Smithay. Report bugs on
|
||||||
|
[GitHub](https://github.com/ferese-wm/ferese/issues) with reproduction steps and logs.
|
||||||
```sh
|
|
||||||
cargo test --workspace --locked
|
|
||||||
cargo fmt --all --check
|
|
||||||
```
|
|
||||||
|
|
||||||
Ferese is built in Rust on Smithay. Use release builds when evaluating motion
|
|
||||||
and startup performance, and keep another desktop session available while
|
|
||||||
testing hardware behavior.
|
|
||||||
+17
-13
@@ -65,7 +65,7 @@ use smithay::wayland::xdg_toplevel_icon::XdgToplevelIconManager;
|
|||||||
|
|
||||||
use crate::backends::direct::DirectBackendState;
|
use crate::backends::direct::DirectBackendState;
|
||||||
use crate::config::{Binding, DaemonConfig, InputSettings, OutputProfile, ThemeSettings};
|
use crate::config::{Binding, DaemonConfig, InputSettings, OutputProfile, ThemeSettings};
|
||||||
use crate::cursor::NamedCursor;
|
use crate::cursor::{NamedCursor, cursor_theme, load_named_cursor};
|
||||||
use crate::dimming::DimAnimation;
|
use crate::dimming::DimAnimation;
|
||||||
use crate::gestures::{Swipe, SwipeDirection};
|
use crate::gestures::{Swipe, SwipeDirection};
|
||||||
use crate::handlers::screencopy::PendingScreencopy;
|
use crate::handlers::screencopy::PendingScreencopy;
|
||||||
@@ -74,13 +74,14 @@ use crate::handlers::screenshot_worker::Worker;
|
|||||||
use crate::input::LockedPointerHint;
|
use crate::input::LockedPointerHint;
|
||||||
use crate::input_capture::InputCapture;
|
use crate::input_capture::InputCapture;
|
||||||
use crate::ipc::IpcSocketGuard;
|
use crate::ipc::IpcSocketGuard;
|
||||||
|
use crate::overview::OverviewState;
|
||||||
use crate::portal_session::PortalSession;
|
use crate::portal_session::PortalSession;
|
||||||
use crate::portal_shortcuts::PortalShortcuts;
|
use crate::portal_shortcuts::PortalShortcuts;
|
||||||
use crate::resize_transaction::ResizeTransaction;
|
use crate::resize_transaction::ResizeTransaction;
|
||||||
use crate::session_lock::{IdleSettings, Lock};
|
use crate::session_lock::{IdleSettings, Lock};
|
||||||
use crate::shell_control::ShellSnapshot;
|
use crate::shell_control::ShellSnapshot;
|
||||||
use crate::stacking::WindowStack;
|
use crate::stacking::WindowStack;
|
||||||
use crate::wallpaper::WallpaperState;
|
use crate::wallpaper::{WallpaperConfig, WallpaperState};
|
||||||
use crate::window_rules::{WindowRule, resolve as resolve_window_rules};
|
use crate::window_rules::{WindowRule, resolve as resolve_window_rules};
|
||||||
use crate::winit::{
|
use crate::winit::{
|
||||||
BlurProgram, MaterialBuffers, MaterialProgram, NestedBackend, OverviewScrim, ResizeSnapshot, RoundedClipPrograms,
|
BlurProgram, MaterialBuffers, MaterialProgram, NestedBackend, OverviewScrim, ResizeSnapshot, RoundedClipPrograms,
|
||||||
@@ -344,10 +345,10 @@ pub struct Ferese {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct RuntimeConfig {
|
pub struct RuntimeConfig {
|
||||||
pub(crate) lock_idle: crate::session_lock::IdleSettings,
|
pub(crate) lock_idle: IdleSettings,
|
||||||
pub(crate) autostart: Vec<crate::config::DaemonConfig>,
|
pub(crate) autostart: Vec<DaemonConfig>,
|
||||||
pub(crate) overview_font_family: String,
|
pub(crate) overview_font_family: String,
|
||||||
pub(crate) wallpaper: crate::wallpaper::WallpaperConfig,
|
pub(crate) wallpaper: WallpaperConfig,
|
||||||
pub layout_mode: LayoutMode,
|
pub layout_mode: LayoutMode,
|
||||||
pub gap_config: GapConfig,
|
pub gap_config: GapConfig,
|
||||||
pub input_settings: InputSettings,
|
pub input_settings: InputSettings,
|
||||||
@@ -371,9 +372,11 @@ impl Ferese {
|
|||||||
config: RuntimeConfig,
|
config: RuntimeConfig,
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
) -> Result<Self, Box<dyn Error>> {
|
||||||
let display_handle = display.handle();
|
let display_handle = display.handle();
|
||||||
|
|
||||||
crate::handlers::screencopy::init_global(&display_handle);
|
crate::handlers::screencopy::init_global(&display_handle);
|
||||||
crate::effects::init_global(&display_handle);
|
crate::effects::init_global(&display_handle);
|
||||||
crate::shell_control::init_global(&display_handle);
|
crate::shell_control::init_global(&display_handle);
|
||||||
|
|
||||||
let alpha_modifier_state = AlphaModifierState::new::<Self>(&display_handle);
|
let alpha_modifier_state = AlphaModifierState::new::<Self>(&display_handle);
|
||||||
let compositor_state = CompositorState::new::<Self>(&display_handle);
|
let compositor_state = CompositorState::new::<Self>(&display_handle);
|
||||||
let cursor_shape_state = CursorShapeManagerState::new::<Self>(&display_handle);
|
let cursor_shape_state = CursorShapeManagerState::new::<Self>(&display_handle);
|
||||||
@@ -427,8 +430,8 @@ impl Ferese {
|
|||||||
let socket_name = Self::init_wayland_listener(display, event_loop)?;
|
let socket_name = Self::init_wayland_listener(display, event_loop)?;
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let cursor_theme = crate::cursor::cursor_theme();
|
let cursor_theme = cursor_theme();
|
||||||
let default_cursor = crate::cursor::load_named_cursor(&cursor_theme, CursorIcon::Default);
|
let default_cursor = load_named_cursor(&cursor_theme, CursorIcon::Default);
|
||||||
let named_cursors = HashMap::from([(CursorIcon::Default, default_cursor)]);
|
let named_cursors = HashMap::from([(CursorIcon::Default, default_cursor)]);
|
||||||
|
|
||||||
let mut state = Self {
|
let mut state = Self {
|
||||||
@@ -457,10 +460,10 @@ impl Ferese {
|
|||||||
resize_transactions: HashMap::new(),
|
resize_transactions: HashMap::new(),
|
||||||
resize_snapshots: HashMap::new(),
|
resize_snapshots: HashMap::new(),
|
||||||
nested_backend: None,
|
nested_backend: None,
|
||||||
wallpaper: crate::wallpaper::WallpaperState::with_wakeup(config.wallpaper, Some(event_loop.get_signal())),
|
wallpaper: WallpaperState::with_wakeup(config.wallpaper, Some(event_loop.get_signal())),
|
||||||
maximized_windows: HashSet::new(),
|
maximized_windows: HashSet::new(),
|
||||||
maximized_column_widths: HashMap::new(),
|
maximized_column_widths: HashMap::new(),
|
||||||
window_stack: crate::stacking::WindowStack::default(),
|
window_stack: WindowStack::default(),
|
||||||
floating_above_fullscreen: HashMap::new(),
|
floating_above_fullscreen: HashMap::new(),
|
||||||
natural_floating_pending: HashSet::new(),
|
natural_floating_pending: HashSet::new(),
|
||||||
window_borders: HashMap::new(),
|
window_borders: HashMap::new(),
|
||||||
@@ -473,7 +476,7 @@ impl Ferese {
|
|||||||
overview_scrims: HashMap::new(),
|
overview_scrims: HashMap::new(),
|
||||||
material_programs: HashMap::new(),
|
material_programs: HashMap::new(),
|
||||||
material_buffers: HashMap::new(),
|
material_buffers: HashMap::new(),
|
||||||
portal_shortcuts: crate::portal_shortcuts::PortalShortcuts::default(),
|
portal_shortcuts: PortalShortcuts::default(),
|
||||||
pending_logout: None,
|
pending_logout: None,
|
||||||
logout_query: None,
|
logout_query: None,
|
||||||
logout_owner: None,
|
logout_owner: None,
|
||||||
@@ -506,20 +509,20 @@ impl Ferese {
|
|||||||
cursor_theme,
|
cursor_theme,
|
||||||
named_cursors,
|
named_cursors,
|
||||||
intercepted_keys: HashSet::new(),
|
intercepted_keys: HashSet::new(),
|
||||||
swipe: crate::gestures::Swipe::default(),
|
swipe: Swipe::default(),
|
||||||
idle_inhibitors: HashMap::new(),
|
idle_inhibitors: HashMap::new(),
|
||||||
active_shortcuts_inhibitor: None,
|
active_shortcuts_inhibitor: None,
|
||||||
direct_backend: None,
|
direct_backend: None,
|
||||||
_ipc_socket: None,
|
_ipc_socket: None,
|
||||||
pending_dmabuf_imports: Vec::new(),
|
pending_dmabuf_imports: Vec::new(),
|
||||||
pending_screencopies: Vec::new(),
|
pending_screencopies: Vec::new(),
|
||||||
screenshot: crate::handlers::screenshot::Coordinator::new(),
|
screenshot: Coordinator::new(),
|
||||||
screenshot_parts: None,
|
screenshot_parts: None,
|
||||||
screenshot_worker: None,
|
screenshot_worker: None,
|
||||||
shell_resources: Vec::new(),
|
shell_resources: Vec::new(),
|
||||||
shell_snapshot_serial: 0,
|
shell_snapshot_serial: 0,
|
||||||
last_shell_snapshot: None,
|
last_shell_snapshot: None,
|
||||||
overview: crate::overview::OverviewState::with_font_family(config.overview_font_family),
|
overview: OverviewState::with_font_family(config.overview_font_family),
|
||||||
next_window_id: 1,
|
next_window_id: 1,
|
||||||
next_output_id: 1,
|
next_output_id: 1,
|
||||||
last_animation_tick: start_time,
|
last_animation_tick: start_time,
|
||||||
@@ -557,6 +560,7 @@ impl Ferese {
|
|||||||
state.screenshot_parts = Some(screenshot.parts);
|
state.screenshot_parts = Some(screenshot.parts);
|
||||||
state.screenshot_worker = Some(screenshot.worker);
|
state.screenshot_worker = Some(screenshot.worker);
|
||||||
state._ipc_socket = Some(screenshot._guard);
|
state._ipc_socket = Some(screenshot._guard);
|
||||||
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ prompt and screen-sharing/recording chooser.
|
|||||||
|
|
||||||
- `Palette` resolves KDL colors and corners and builds the native toolkit theme.
|
- `Palette` resolves KDL colors and corners and builds the native toolkit theme.
|
||||||
- `PRESETS` defines the six built-in color schemes.
|
- `PRESETS` defines the six built-in color schemes.
|
||||||
- `font` and `text` share bounded font-name storage and explicit font selection.
|
- `font` and `text` provide shared font selection and text.
|
||||||
- `controls` supplies surfaces, navigation, font-aware text buttons and input styles.
|
- `controls` supplies surfaces, navigation, font-aware text buttons and input styles.
|
||||||
- `menus` supplies headings, rows, sections, separators, switches and slider styles.
|
- `menus` supplies headings, rows, sections, separators, switches and slider styles.
|
||||||
- `calendar` supplies date/time labels, stacked clock digits and calendar grids.
|
- `calendar` supplies date/time labels, stacked clock digits and calendar grids.
|
||||||
@@ -16,9 +16,8 @@ prompt and screen-sharing/recording chooser.
|
|||||||
Keep the attachment alive with its window and make the client background
|
Keep the attachment alive with its window and make the client background
|
||||||
transparent after attachment succeeds. Other compositors retain the client fill.
|
transparent after attachment succeeds. Other compositors retain the client fill.
|
||||||
|
|
||||||
Applications own layout, data, actions and animation timing. Pass their current
|
Applications supply layout, data, actions, and animation progress. Extend shared
|
||||||
palette and animation progress into the shared components; do not build another
|
components when a style is needed across apps.
|
||||||
native theme or copy a common control style into an application.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let palette = ferese_theme::Palette::from_document(Some(&document));
|
let palette = ferese_theme::Palette::from_document(Some(&document));
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Documentation
|
||||||
|
|
||||||
|
## Get started
|
||||||
|
|
||||||
|
- [Installation](installation.md): dependencies, login, previews, updates, and recovery.
|
||||||
|
- [Configuration](configuration.md): KDL syntax, layouts, input, shortcuts, and displays.
|
||||||
|
- [Why Ferese](why-ferese.md): layouts and the shared desktop theme.
|
||||||
|
|
||||||
|
## Use the desktop
|
||||||
|
|
||||||
|
- [Shortcuts and gestures](shortcuts.md): keyboard navigation, Super-drag, resize, and window grouping.
|
||||||
|
|
||||||
|
- [Desktop widgets](desktop-widgets.md): clocks and sticky notes.
|
||||||
|
- [Notifications](notifications.md): popups, history, and Do Not Disturb.
|
||||||
|
- [Lock screen](locking.md): appearance, automatic locking, and display sleep.
|
||||||
|
- [Screen sharing and recording](screen-sharing.md): choosing sources and stopping a session.
|
||||||
|
- [Desktop portals](portals.md): application integration and supported services.
|
||||||
|
|
||||||
|
## Develop Ferese
|
||||||
|
|
||||||
|
- [Development](development.md): builds, tests, and portal checks.
|
||||||
|
- [Compositor architecture](ferese-window-manager-spec.md).
|
||||||
|
- [Shell behavior](ferese-shell-design.md).
|
||||||
|
- [Theme components](ferese-theme-ui-spec.md).
|
||||||
|
- [Animation checks](animation-validation.md).
|
||||||
|
- [Nested resize checks](nested-resize-testing.md).
|
||||||
|
- [Client soak testing](native-soak-testing.md).
|
||||||
|
- [Performance measurements](performance-baseline.md).
|
||||||
|
- [Website development](../site/README.md).
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# 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 maximized width. |
|
||||||
|
| Exit maximize or 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.
|
||||||
+81
-106
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
Edit `~/.config/ferese/config.kdl` (or `$XDG_CONFIG_HOME/ferese/config.kdl`),
|
Edit `~/.config/ferese/config.kdl` (or `$XDG_CONFIG_HOME/ferese/config.kdl`),
|
||||||
or open **Control Center → Settings**. Start with the [example](../packaging/config.kdl).
|
or open **Control Center → Settings**. Start with the [example](../packaging/config.kdl).
|
||||||
All supported configuration sections are listed below; [desktop widgets](desktop-widgets.md)
|
This reference covers layouts, appearance, input, and desktop behavior.
|
||||||
covers the complete clock and sticky-note fields separately.
|
See [Desktop widgets](desktop-widgets.md), [Notifications](notifications.md),
|
||||||
|
and [Desktop portals](portals.md) for their additional options.
|
||||||
|
|
||||||
## KDL syntax
|
## KDL syntax
|
||||||
|
|
||||||
@@ -44,8 +45,7 @@ its command as positional arguments. Duplicate fields are rejected.
|
|||||||
The dotted paths in the reference tables below describe nested sections.
|
The dotted paths in the reference tables below describe nested sections.
|
||||||
|
|
||||||
Settings preserves comments and custom fields when editing, while normalizing
|
Settings preserves comments and custom fields when editing, while normalizing
|
||||||
indentation. Runtime configuration uses KDL only. KDL parsing requires Rust 1.95
|
indentation. Configuration uses KDL.
|
||||||
or newer to build.
|
|
||||||
|
|
||||||
## Saving and validation
|
## Saving and validation
|
||||||
|
|
||||||
@@ -74,15 +74,15 @@ Live config is limited to 60 KiB.
|
|||||||
| `layout` key | Type / values | Default | Meaning |
|
| `layout` key | Type / values | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `mode` | `"scrolling"`, `"tree"` | `"scrolling"` | Workspace layout |
|
| `mode` | `"scrolling"`, `"tree"` | `"scrolling"` | Workspace layout |
|
||||||
| `inner_gap` | number ≥ 0 | `10` | Between windows |
|
| `inner-gap` | number ≥ 0 | `10` | Between windows |
|
||||||
| `outer_gap` | number ≥ 0 | `4` | Around workspace edges |
|
| `outer-gap` | number ≥ 0 | `4` | Around workspace edges |
|
||||||
| `smart_gaps` | boolean | `false` | Remove outer gaps for one tiled window |
|
| `smart-gaps` | boolean | `false` | Remove outer gaps for one tiled window |
|
||||||
|
|
||||||
| `scrolling` key | Type / values | Default | Meaning |
|
| `scrolling` key | Type / values | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `default_column_width` | proportion > 0; or `"full"` | `0.5` | Width of new columns |
|
| `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 |
|
| `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 |
|
| `width-presets` | array of widths | `[0.3333333333333333, 0.5, 0.6666666666666666, "full"]` | Super+R cycle; empty uses defaults |
|
||||||
|
|
||||||
`minimal` scrolls only to reveal the focused window. `center_on_focus` centers
|
`minimal` scrolls only to reveal the focused window. `center_on_focus` centers
|
||||||
it. `paged` packs columns into viewport-sized pages: halves form pairs, thirds
|
it. `paged` packs columns into viewport-sized pages: halves form pairs, thirds
|
||||||
@@ -94,95 +94,73 @@ Changing default width preserves manually resized columns.
|
|||||||
| Section / key | Type | Default | Meaning |
|
| Section / key | Type | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `animations.enabled` | boolean | `true` | Enable motion |
|
| `animations.enabled` | boolean | `true` | Enable motion |
|
||||||
| `animations.reduced_motion` | boolean | `false` | Disable animated motion |
|
| `animations.reduced-motion` | boolean | `false` | Disable animated motion |
|
||||||
| `animations.speed` | number > 0 | `1` | Higher is faster; `0.75` is slower |
|
| `animations.speed` | number > 0 | `1` | Higher is faster; `0.75` is slower |
|
||||||
| `animations.spring.mass` | number > 0 | `1` | Window-motion spring mass |
|
| `animations.spring.mass` | number > 0 | `1` | Window-motion spring mass |
|
||||||
| `animations.spring.stiffness` | number > 0 | `700` | Spring stiffness |
|
| `animations.spring.stiffness` | number > 0 | `700` | Spring stiffness |
|
||||||
| `animations.spring.damping` | number ≥ 0 | `53` | Spring damping |
|
| `animations.spring.damping` | number ≥ 0 | `53` | Spring damping |
|
||||||
| `animations.viewport_spring.mass` | number > 0 | `1` | Scrolling spring mass |
|
| `animations.viewport-spring.mass` | number > 0 | `1` | Scrolling spring mass |
|
||||||
| `animations.viewport_spring.stiffness` | number > 0 | `320` | Scrolling stiffness |
|
| `animations.viewport-spring.stiffness` | number > 0 | `320` | Scrolling stiffness |
|
||||||
| `animations.viewport_spring.damping_ratio` | number > 0 | `1` | `1` is critically damped |
|
| `animations.viewport-spring.damping-ratio` | number > 0 | `1` | `1` is critically damped |
|
||||||
|
|
||||||
## Appearance
|
## Appearance
|
||||||
|
|
||||||
Settings → Appearance offers six presets: **Ferese Blue** (default),
|
Settings → Appearance offers six presets: **Ferese Blue** (default),
|
||||||
**Monochrome**, **Gruvbox**, **Dracula**, **Ayu Light**, and **Monokai**.
|
**Monochrome**, **Gruvbox**, **Dracula**, **Ayu Light**, and **Monokai**.
|
||||||
The two-row gallery previews each palette on a miniature desktop; a checkmark
|
Ferese Blue uses the logo accent, `#3D7BE6`. Presets update colors and preserve
|
||||||
identifies the active preset.
|
wallpaper, fonts, corners, and opacity. Colors remain individually editable.
|
||||||
Ferese Blue uses the README logo's `#3D7BE6`. Each preset coordinates surfaces,
|
|
||||||
text, menu-bar colors, borders and the focus ring. Ayu Light also switches native
|
|
||||||
Settings controls to light styling. Presets preserve wallpaper, typography,
|
|
||||||
geometry and opacity settings; colors remain individually editable.
|
|
||||||
|
|
||||||
The community palettes are desktop adaptations with text shades adjusted for
|
|
||||||
readability. Sources: [Gruvbox](https://github.com/morhetz/gruvbox),
|
|
||||||
[Dracula](https://github.com/dracula/visual-studio-code),
|
|
||||||
[Ayu](https://github.com/ayu-theme/ayu-colors), and
|
|
||||||
[classic Monokai](https://github.com/microsoft/vscode/blob/main/extensions/theme-monokai/themes/monokai-color-theme.json).
|
|
||||||
Marketplace install counts informed the shortlist; they are not a measurement
|
|
||||||
of desktop users. Monochrome and Gruvbox replace similar blue palettes to keep
|
|
||||||
these six visually distinct.
|
|
||||||
|
|
||||||
|
|
||||||
| Section / key | Type | Default | Meaning |
|
| Section / key | Type | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `appearance.corner_radius` | number ≥ 0 | unset | Legacy fallback for shell radius |
|
| `appearance.corner-radius` | number ≥ 0 | unset | Legacy fallback for shell radius |
|
||||||
| `appearance.inactive_dim.enabled` | boolean | `false` | Dim unfocused windows |
|
| `appearance.inactive-dim.enabled` | boolean | `false` | Dim unfocused windows |
|
||||||
| `appearance.inactive_dim.amount` | number 0–1 | `0.15` | Darkening strength |
|
| `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 |
|
| `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.typography.font-family` | string | system sans-serif | Shell, Settings and overview font |
|
||||||
| `theme.background.path` | string | bundled Ferese wallpaper | Wallpaper image path; an existing selection overrides the default |
|
| `theme.background.path` | string | bundled Ferese wallpaper | Wallpaper image path; an existing selection overrides the default |
|
||||||
| `theme.background.mode` | `"fill"`, `"fit"` | `"fill"` | Crop or letterbox |
|
| `theme.background.mode` | `"fill"`, `"fit"` | `"fill"` | Crop or letterbox |
|
||||||
| `theme.material.style` | `"solid"`, `"translucent"` | `"solid"` | Shell background material |
|
| `theme.material.style` | `"solid"`, `"translucent"` | `"solid"` | Shell background material |
|
||||||
| `theme.material.opacity` | number 0–1 | `0.78` | Shared shell background opacity for bars, menus, popovers, notifications and themed dialogs. Text/icons stay opaque; 0 hides the material. Solid mode is always opaque |
|
| `theme.material.opacity` | number 0–1 | `0.78` | Shared shell background opacity for bars, menus, popovers, notifications and themed dialogs. Text/icons stay opaque; 0 hides the material. Solid mode is always opaque |
|
||||||
| `theme.material.blur_radius` | number ≥ 0 | `12` | Translucent backdrop blur, capped at 32; 0 disables |
|
| `theme.material.blur-radius` | number ≥ 0 | `12` | Translucent backdrop blur, capped at 32; 0 disables |
|
||||||
|
|
||||||
| `theme.colors` key | Default | Meaning |
|
| `theme.colors` key | Default | Meaning |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `surface_base` | `"#111821"` | Material/card base color |
|
| `surface-base` | `"#111821"` | Material/card base color |
|
||||||
| `text_primary` | `"#F4F7FB"` | Main text |
|
| `text-primary` | `"#F4F7FB"` | Main text |
|
||||||
| `text_muted` | `"#8793A2"` | Secondary text |
|
| `text-muted` | `"#8793A2"` | Secondary text |
|
||||||
| `accent` | `"#3D7BE6"` | Active controls and solid focus ring |
|
| `accent` | `"#3D7BE6"` | Active controls and solid focus ring |
|
||||||
| `border` | `"#FFFFFF18"` | Unfocused window border |
|
| `border` | `"#FFFFFF18"` | Unfocused window border |
|
||||||
| `shadow` | `"#00000055"` | Window shadow color |
|
| `shadow` | `"#00000055"` | Window shadow color |
|
||||||
|
|
||||||
Ferese derives the text and icon color for filled accent controls from the
|
Filled controls choose a contrasting text color automatically.
|
||||||
configured theme. It keeps the configured text color and, when necessary, shades
|
|
||||||
the accent fill slightly to reach a 4.5:1 contrast ratio. If that would require a
|
|
||||||
large color change, it chooses black or white instead. The same rule is shared by
|
|
||||||
native dialogs, settings selections, and notification badges. Hover, pressed,
|
|
||||||
and disabled accent-button states use the same policy. Small filled controls
|
|
||||||
resolve accent transparency against their theme surface so wallpaper cannot
|
|
||||||
make their labels unreadable. No separate per-application color setting is needed.
|
|
||||||
The target follows [normal-text contrast guidance](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html).
|
|
||||||
|
|
||||||
| `theme.geometry` key | Type | Default | Meaning |
|
| `theme.geometry` key | Type | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `border_width` | number ≥ 0 | `1` | Window border thickness |
|
| `border-width` | number ≥ 0 | `1` | Window border thickness |
|
||||||
| `focus_ring_width` | number ≥ 0 | `2` | Focused border thickness |
|
| `focus-ring-width` | number ≥ 0 | `2` | Focused border thickness |
|
||||||
| `window_radius` | number ≥ 0 | `14` | Managed-window corners, independent of the shell |
|
| `window-radius` | number ≥ 0 | `14` | Managed-window corners, independent of the shell |
|
||||||
| `shell_radius` | number ≥ 0 | `14` | All shell surfaces, cards, widgets and interaction backgrounds; 0 makes them square |
|
| `shell-radius` | number ≥ 0 | `14` | All shell surfaces, cards, widgets and interaction backgrounds; 0 makes them square |
|
||||||
| `top_bar_height` | number > 0 | `28` | Menu-bar height |
|
| `top-bar-height` | number > 0 | `28` | Menu-bar height |
|
||||||
| `top_bar_margin_top` | integer ≥ 0 | `0` | Space above bar |
|
| `top-bar-margin-top` | integer ≥ 0 | `0` | Space above bar |
|
||||||
| `top_bar_window_gap` | integer ≥ 0 | `0` | Clearance below bar |
|
| `top-bar-window-gap` | integer ≥ 0 | `0` | Clearance below bar |
|
||||||
| `top_bar_margin_horizontal` | integer ≥ 0 | `0` | Bar side margins |
|
| `top-bar-margin-horizontal` | integer ≥ 0 | `0` | Bar side margins |
|
||||||
| `top_bar_radius` | number ≥ 0 | unset | Legacy fallback for shell radius |
|
| `top-bar-radius` | number ≥ 0 | unset | Legacy fallback for shell radius |
|
||||||
| `panel_padding` | number ≥ 0 | `12` | Bar inner padding |
|
| `panel-padding` | number ≥ 0 | `12` | Bar inner padding |
|
||||||
| `control_gap` | number ≥ 0 | `12` | Right-side control spacing |
|
| `control-gap` | number ≥ 0 | `12` | Right-side control spacing |
|
||||||
|
|
||||||
| Section / key | Type | Default | Meaning |
|
| Section / key | Type | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `theme.surface.bar.background` | color | `"#1C202EF2"` | Shell fallback background; compositor materials use `surface_base` |
|
| `theme.surface.bar.background` | color | `"#1C202EF2"` | Shell fallback background; compositor materials use `surface-base` |
|
||||||
| `theme.surface.bar.text_primary` | color | `"#F0F3FA"` | Bar text/icons |
|
| `theme.surface.bar.text-primary` | color | `"#F0F3FA"` | Bar text/icons |
|
||||||
| `theme.surface.bar.text_muted` | color | `"#AAB4C7"` | Inactive bar foreground |
|
| `theme.surface.bar.text-muted` | color | `"#AAB4C7"` | Inactive bar foreground |
|
||||||
| `theme.shadow.soft.offset_y` | number | `4` | Window shadow vertical offset |
|
| `theme.shadow.soft.offset-y` | number | `4` | Window shadow vertical offset |
|
||||||
| `theme.shadow.soft.blur` | number ≥ 0 | `18` | Window shadow softness |
|
| `theme.shadow.soft.blur` | number ≥ 0 | `18` | Window shadow softness |
|
||||||
| `theme.shadow.soft.opacity` | number 0–1 | `0.20` | Window shadow strength |
|
| `theme.shadow.soft.opacity` | number 0–1 | `0.20` | Window shadow strength |
|
||||||
|
|
||||||
Solid materials omit blur; translucent materials blur behind the surface color.
|
Solid materials omit blur; translucent materials blur behind the surface color.
|
||||||
True fullscreen removes decorations. Focus transitions never scale the content.
|
True fullscreen removes decorations. Focus transitions never scale the content.
|
||||||
|
|
||||||
Optional `theme.focus_ring.gradient` and `theme.border.gradient` use the same
|
Optional `theme.focus-ring.gradient` and `theme.border.gradient` use the same
|
||||||
keys: required `from` and `to` colors, and `angle` (number, default `0`). Angles
|
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
|
are clockwise: 0 is left-to-right, 90 top-to-bottom. Omit the gradient section
|
||||||
for solid `accent` or `border` colors.
|
for solid `accent` or `border` colors.
|
||||||
@@ -199,16 +177,25 @@ theme {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Workspaces
|
||||||
|
|
||||||
|
A single-output session starts with workspace 1. Numbered workspace shortcuts create
|
||||||
|
workspaces on demand; switching forward past the last workspace also creates the
|
||||||
|
next one when the current workspace contains windows. Empty workspaces are
|
||||||
|
cleaned up automatically, keeping at most one empty workspace in addition to
|
||||||
|
any empty workspace currently shown on another display. Additional displays
|
||||||
|
receive their own workspace.
|
||||||
|
|
||||||
## Input
|
## Input
|
||||||
|
|
||||||
| `input` key | Type | Default | Meaning |
|
| `input` key | Type | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `focus_follows_mouse` | boolean | `false` | Focus visible windows under the pointer without raising them or scrolling; click or use keyboard focus to reveal a window |
|
| `focus-follows-mouse` | boolean | `false` | Focus visible windows under the pointer without raising them or scrolling; click or use keyboard focus to reveal a window |
|
||||||
| `xkb_layout` | nonempty string | `"us"` | XKB layout |
|
| `xkb-layout` | nonempty string | `"us"` | XKB layout |
|
||||||
| `xkb_variant` | string | `""` | XKB variant |
|
| `xkb-variant` | string | `""` | XKB variant |
|
||||||
| `xkb_options` | string array | `[]` | XKB options |
|
| `xkb-options` | string array | `[]` | XKB options |
|
||||||
| `repeat_rate` | integer > 0 | `25` | Repeats per second |
|
| `repeat-rate` | integer > 0 | `25` | Repeats per second |
|
||||||
| `repeat_delay_ms` | integer ≥ 0 | `600` | Delay before repeat |
|
| `repeat-delay-ms` | integer ≥ 0 | `600` | Delay before repeat |
|
||||||
|
|
||||||
With focus-follows-mouse enabled, hovering a visible part of a window changes
|
With focus-follows-mouse enabled, hovering a visible part of a window changes
|
||||||
keyboard focus without raising it or moving the scrolling viewport. Clicking or
|
keyboard focus without raising it or moving the scrolling viewport. Clicking or
|
||||||
@@ -221,7 +208,7 @@ Clicking a workspace card's background switches workspaces while keeping Overvie
|
|||||||
open. Previews follow layout order and use the configured shell font and colors.
|
open. Previews follow layout order and use the configured shell font and colors.
|
||||||
|
|
||||||
The touchpad device keys are booleans, all defaulting to `true`: `tap`,
|
The touchpad device keys are booleans, all defaulting to `true`: `tap`,
|
||||||
`natural_scroll` and `disable_while_typing`. These apply to DRM devices; nested
|
`natural-scroll` and `disable-while-typing`. These apply to DRM devices; nested
|
||||||
previews use the host's physical input settings.
|
previews use the host's physical input settings.
|
||||||
|
|
||||||
Three-finger swipes navigate on release: up goes to the next workspace on the
|
Three-finger swipes navigate on release: up goes to the next workspace on the
|
||||||
@@ -254,6 +241,8 @@ Adjust recognition distance in **Settings → Keyboard & mouse**, or with
|
|||||||
|
|
||||||
## Commands and bindings
|
## Commands and bindings
|
||||||
|
|
||||||
|
See [Shortcuts and gestures](shortcuts.md) for the full default keymap and mouse actions.
|
||||||
|
|
||||||
`commands` maps arbitrary names to nonempty argument arrays. The built-in
|
`commands` maps arbitrary names to nonempty argument arrays. The built-in
|
||||||
`terminal "foot"` can be overridden. Commands run directly, without a shell.
|
`terminal "foot"` can be overridden. Commands run directly, without a shell.
|
||||||
|
|
||||||
@@ -292,7 +281,7 @@ 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+[/] consume/expel; Super+F maximize; Super+Shift+F fullscreen;
|
||||||
Super+M layout; Super+Shift+Space floating; Super+Tab overview;
|
Super+M layout; Super+Shift+Space floating; Super+Tab overview;
|
||||||
Super+Shift+S area screenshot; Print Screen whole-screen screenshot;
|
Super+Shift+S area screenshot; Print Screen whole-screen screenshot;
|
||||||
Super+Shift+E immediate logout.
|
Super+Shift+E logout confirmation.
|
||||||
|
|
||||||
Hold Super and drag a floating window with the left mouse button to move it.
|
Hold Super and drag a floating window with the left mouse button to move it.
|
||||||
Hold Super and drag with the right mouse button to resize it from the nearest
|
Hold Super and drag with the right mouse button to resize it from the nearest
|
||||||
@@ -314,19 +303,8 @@ the same save and copy workflow.
|
|||||||
|
|
||||||
`ferese-screenshot --all` captures every enabled output as one image.
|
`ferese-screenshot --all` captures every enabled output as one image.
|
||||||
|
|
||||||
The editor window is sized from the captured image rather than the output, so a
|
Satty opens as a floating window sized for the captured image and constrained
|
||||||
small area selection does not open a large window. Sizing is advisory: the
|
to the workspace.
|
||||||
compositor floats the editor at whatever size Satty requests, clamped to the
|
|
||||||
workspace.
|
|
||||||
|
|
||||||
A capture is assembled from the readback each output produces when it is next
|
|
||||||
redrawn, so a request is abandoned if an output has not been redrawn within 30
|
|
||||||
seconds. That is reported as an error rather than a partial or empty image, and
|
|
||||||
the request holds no resources once it is abandoned. Nothing is left in the
|
|
||||||
runtime directory: `feresctl screenshot` writes a private file that the caller
|
|
||||||
opens and unlinks, and any file a dead client leaves behind is reclaimed after
|
|
||||||
an hour.
|
|
||||||
|
|
||||||
|
|
||||||
## Window rules
|
## Window rules
|
||||||
|
|
||||||
@@ -335,7 +313,7 @@ window rules can override that behavior.
|
|||||||
|
|
||||||
| `window-rule` key | Type | Default / meaning |
|
| `window-rule` key | Type | Default / meaning |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `app_id` | nonempty string | Optional exact match; case-insensitive, `.desktop` suffix ignored |
|
| `app-id` | nonempty string | Optional exact match; case-insensitive, `.desktop` suffix ignored |
|
||||||
| `title` | nonempty string | Optional exact, case-sensitive match |
|
| `title` | nonempty string | Optional exact, case-sensitive match |
|
||||||
| `transient` | boolean | Optional parent-dialog match |
|
| `transient` | boolean | Optional parent-dialog match |
|
||||||
| `workspace` | integer > 0 | Leave placement unchanged |
|
| `workspace` | integer > 0 | Leave placement unchanged |
|
||||||
@@ -369,8 +347,8 @@ are connected wins. Find connector names and persistent identities using
|
|||||||
| `transform` | enum below | `"normal"` |
|
| `transform` | enum below | `"normal"` |
|
||||||
| `position` | `[integer, integer]` | Automatic horizontal placement |
|
| `position` | `[integer, integer]` | Automatic horizontal placement |
|
||||||
|
|
||||||
Transforms: `normal`, `rotate_90`, `rotate_180`, `rotate_270`, `flipped`,
|
Transforms: `normal`, `rotate-90`, `rotate-180`, `rotate-270`, `flipped`,
|
||||||
`flipped_90`, `flipped_180`, `flipped_270`. Unspecified connected displays stay
|
`flipped-90`, `flipped-180`, `flipped-270`. Unspecified connected displays stay
|
||||||
enabled with defaults. Disabling every usable output is rejected.
|
enabled with defaults. Disabling every usable output is rejected.
|
||||||
|
|
||||||
```kdl
|
```kdl
|
||||||
@@ -390,10 +368,10 @@ returns. Ferese does not change the system's suspend policy.
|
|||||||
| `status` key | Type | Default | Meaning |
|
| `status` key | Type | Default | Meaning |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `keybinding-guide` | boolean | `true` | Show the active shortcut guide at login until disabled in Settings → Shortcuts. |
|
| `keybinding-guide` | boolean | `true` | Show the active shortcut guide at login until disabled in Settings → Shortcuts. |
|
||||||
| `window_title` | boolean | `true` | Focused window title in the bar center when space allows |
|
| `window-title` | boolean | `true` | Focused window title in the bar center when space allows |
|
||||||
| `battery_percentage` | boolean | `true` | Show percentage beside icon |
|
| `battery-percentage` | boolean | `true` | Show percentage beside icon |
|
||||||
| `low_battery_threshold` | integer 0–100 | `20` | Warning-color threshold |
|
| `low-battery-threshold` | integer 0–100 | `20` | Warning-color threshold |
|
||||||
| `settings_command` | argument array | `["ferese-settings"]` | Settings launcher; `[]` hides the action |
|
| `settings-command` | argument array | `["ferese-settings"]` | Settings launcher; `[]` hides the action |
|
||||||
|
|
||||||
## Login items and locking
|
## Login items and locking
|
||||||
|
|
||||||
@@ -443,22 +421,19 @@ environment for screenshots to work.
|
|||||||
Text input is available by default; Ctrl+Alt+Escape releases an active shortcut
|
Text input is available by default; Ctrl+Alt+Escape releases an active shortcut
|
||||||
inhibitor. Use `feresectl --help` for runtime control commands.
|
inhibitor. Use `feresectl --help` for runtime control commands.
|
||||||
|
|
||||||
## Notifications
|
|
||||||
|
|
||||||
Settings → Notifications controls popups, Do Not Disturb, and the default timeout. See [Notifications](notifications.md) for KDL options and app behavior.
|
|
||||||
|
|
||||||
A single-output session starts with workspace 1. Numbered workspace shortcuts create
|
|
||||||
workspaces on demand; switching forward past the last workspace also creates the
|
|
||||||
next one when the current workspace contains windows. Empty workspaces are
|
|
||||||
cleaned up automatically, keeping at most one empty workspace in addition to
|
|
||||||
any empty workspace currently shown on another display. Additional displays
|
|
||||||
receive their own workspace.
|
|
||||||
|
|
||||||
Shell rounding is controlled in Settings → Appearance → Shell corner radius.
|
Shell rounding is controlled in Settings → Appearance → Shell corner radius.
|
||||||
Small controls cap the radius to fit their size. Window rounding remains under
|
Small controls cap the radius to fit their size. Window rounding remains under
|
||||||
Settings → Windows. `theme.geometry.shell_radius` takes precedence over the old
|
Settings → Windows. `theme.geometry.shell-radius` takes precedence over the old
|
||||||
`appearance.corner_radius` and then `theme.geometry.top_bar_radius` keys; when
|
`appearance.corner-radius` and then `theme.geometry.top-bar-radius` keys; when
|
||||||
none are set, the shell uses 14 px. Legacy clock/note radius fields no longer
|
none are set, the shell uses 14 px. Legacy clock/note radius fields no longer
|
||||||
override shell rounding.
|
override shell rounding.
|
||||||
|
|
||||||
Power actions use a centered system confirmation. The `exit` key binding (Super+Shift+E by default) requests logout confirmation; `feresectl request-logout` does the same. `feresectl exit` remains an immediate administrative exit.
|
## Power and logout
|
||||||
|
|
||||||
|
Power actions use a centered confirmation. **Super+Shift+E** and
|
||||||
|
`feresectl request-logout` ask to log out. `feresectl exit` ends the session
|
||||||
|
immediately.
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
See [Notifications](notifications.md) for popups, Do Not Disturb, and timeout options.
|
||||||
+25
-33
@@ -1,13 +1,8 @@
|
|||||||
# Desktop widgets
|
# Desktop widgets
|
||||||
|
|
||||||
The shell's desktop clock sits above the wallpaper and behind normal windows.
|
Clock and sticky-note widgets sit above the wallpaper and behind windows.
|
||||||
Drag the clock to reposition it; it reserves no workspace space.
|
Drag the clock or a note's title to move it. Release to save, or press Escape to
|
||||||
All desktop widgets share dragging: grab the clock or a note's title. Release
|
cancel. Widgets stop at each other's edges on the same display.
|
||||||
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:
|
Enable it in Settings → Desktop widgets or in your Ferese config:
|
||||||
|
|
||||||
@@ -42,42 +37,40 @@ desktop-widgets {
|
|||||||
Positions: `top_left`, `top_center`, `top_right`, `center_left`, `center`,
|
Positions: `top_left`, `top_center`, `top_right`, `center_left`, `center`,
|
||||||
`center_right`, `bottom_left`, `bottom_center`, `bottom_right`.
|
`center_right`, `bottom_left`, `bottom_center`, `bottom_right`.
|
||||||
Margins affect anchored axes only: a centered horizontal position ignores
|
Margins affect anchored axes only: a centered horizontal position ignores
|
||||||
`margin_x`; a centered vertical position ignores `margin_y`.
|
`margin-x`; a centered vertical position ignores `margin-y`.
|
||||||
All geometry and text sizes use logical pixels and follow the output's scale.
|
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.
|
Increase the widget width/height for longer formats or larger text.
|
||||||
|
|
||||||
Pixel is the default clock style: heavy hours above minutes, alternating theme colors, and a small plain date above. Its bundled Cantarell display font can be replaced with the font selector. Minimal retains the plain time/date layout. Pixel zero-pads hours and hides am/pm for the stacked display. Formats with seconds or additional text retain their full formatted label on one line. Both styles shrink time text to fit smaller widget dimensions; an explicit text color overrides the alternating colors.
|
Choose **Pixel** for stacked hours and minutes with alternating theme colors,
|
||||||
|
or **Minimal** for a plain time/date layout. Pixel zero-pads hours and hides am/pm.
|
||||||
|
Formats containing seconds or extra text use a single line. Both styles shrink
|
||||||
|
time text to fit. Select a different font in Settings, or set `font-family`.
|
||||||
|
|
||||||
Saving reloads appearance and labels live. Placement, size, output filters and
|
Changes apply live. Colors and fonts follow the theme unless overridden.
|
||||||
enable/disable changes recreate only clock surfaces; normal windows and the bar
|
Formatting uses [strftime-compatible formats](https://docs.rs/jiff/latest/jiff/fmt/strtime/index.html).
|
||||||
remain intact. Disconnecting an output destroys its clock; reconnecting creates
|
Use `%H:%M` for 24-hour time or `%-I:%M %p` for 12-hour time.
|
||||||
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 KDL.
|
|
||||||
Sticky notes also support editing directly on the desktop.
|
|
||||||
|
|
||||||
## Clock limits
|
## Clock limits
|
||||||
|
|
||||||
|
Clock and note corners follow the shared shell radius. Their `radius` fields
|
||||||
|
are accepted for compatibility but do not override it.
|
||||||
|
|
||||||
All clock keys are optional. The example enables the clock (disabled by default);
|
All clock keys are optional. The example enables the clock (disabled by default);
|
||||||
the other values illustrate defaults or their empty-string equivalents.
|
the other values illustrate defaults or their empty-string equivalents.
|
||||||
`outputs` is an array of strings; `enabled`, `bold`, `show_date`, `lowercase` are
|
`outputs` is an array of strings; `enabled`, `bold`, `show-date`, `lowercase` are
|
||||||
booleans; `width`, `height`, and margins are integers. Other sizes/opacity are numbers.
|
booleans; `width`, `height`, and margins are integers. Other sizes/opacity are numbers.
|
||||||
|
|
||||||
| Fields | Accepted range |
|
| Fields | Accepted range |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `width`, `height` | 64–1600, 32–800 |
|
| `width`, `height` | 64–1600, 32–800 |
|
||||||
| `margin_x`, `margin_y` | 0–8192 |
|
| `margin-x`, `margin-y` | 0–8192 |
|
||||||
| `time_size`, `date_size` | 8–240, 8–96 |
|
| `time-size`, `date-size` | 8–240, 8–96 |
|
||||||
| `opacity` | 0–1 |
|
| `opacity` | 0–1 |
|
||||||
| `gap`, `padding`, `radius` | 0–64, 0–64, 0–128 |
|
| `gap`, `padding`, `radius` | 0–64, 0–64, 0–128 |
|
||||||
| `font_family`, `time_format`, `date_format` | At most 128 bytes each |
|
| `font-family`, `time-format`, `date-format` | At most 128 bytes each |
|
||||||
| `outputs` | At most 32 exact output names, each 1–128 bytes |
|
| `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.
|
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.
|
Colors are empty (inherit), `#RRGGBB` or `#RRGGBBAA`; all numeric values must be finite.
|
||||||
|
|
||||||
## Sticky notes
|
## Sticky notes
|
||||||
@@ -87,7 +80,8 @@ 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
|
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.
|
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.
|
Title, size and style are also editable in Settings. Notes persist in the config.
|
||||||
Choose each note’s font in Settings using the installed-font dropdown or enter a family name manually. Default font inherits the interface font. In KDL, use `font-family "Comfortaa"` inside the `note` node.
|
Choose a note’s font in Settings or set `font-family "Comfortaa"` in its `note`
|
||||||
|
node. Without an override, notes use the interface font.
|
||||||
|
|
||||||
These are plain-text notes, not Markdown or HTML.
|
These are plain-text notes, not Markdown or HTML.
|
||||||
|
|
||||||
@@ -99,9 +93,7 @@ desktop-widgets {
|
|||||||
|
|
||||||
Repeat the `note` node for additional notes; IDs must be unique. Cards stay behind windows
|
Repeat the `note` node for additional notes; IDs must be unique. Cards stay behind windows
|
||||||
and take keyboard focus only when clicked. Set `interactive #false` for a fully
|
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
|
click-through card. Long text wraps; increase height if needed.
|
||||||
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 |
|
| Key | Type | Default / accepted values |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
@@ -112,10 +104,10 @@ compositor, not an output-sized canvas. It is released when dragging ends.
|
|||||||
| `text` | string | `""`; multiline plain text, maximum 16 KiB |
|
| `text` | string | `""`; multiline plain text, maximum 16 KiB |
|
||||||
| `outputs` | string array | `[]` means all; at most 32 exact names, each 1–128 bytes |
|
| `outputs` | string array | `[]` means all; at most 32 exact names, each 1–128 bytes |
|
||||||
| `anchor` | string | `"top_right"`; same nine positions as clock |
|
| `anchor` | string | `"top_right"`; same nine positions as clock |
|
||||||
| `margin_x`, `margin_y` | integer | `48`, `80`; 0–8192; anchored edges only |
|
| `margin-x`, `margin-y` | integer | `48`, `80`; 0–8192; anchored edges only |
|
||||||
| `width`, `height` | integer | `320`, `240`; 120–1200, 80–1200 |
|
| `width`, `height` | integer | `320`, `240`; 120–1200, 80–1200 |
|
||||||
| `font_family` | string | omitted/empty follows desktop font; maximum 128 bytes |
|
| `font-family` | string | omitted/empty follows desktop font; maximum 128 bytes |
|
||||||
| `text_size`, `title_size` | number | `16`, `18`; 8–96 |
|
| `text-size`, `title-size` | number | `16`, `18`; 8–96 |
|
||||||
| `color` | string | omitted/empty/`"theme"` follows primary text; or hex color |
|
| `color` | string | omitted/empty/`"theme"` follows primary text; or hex color |
|
||||||
| `background` | string | omitted/`"theme"` follows surface base; empty is transparent; 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 |
|
| `opacity` | number | `0.9`; 0–1, multiplies text/background alpha |
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# Development
|
||||||
|
|
||||||
|
Install the [build dependencies](installation.md#requirements), then run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo build --release --locked --workspace
|
||||||
|
cargo test --workspace --locked
|
||||||
|
cargo fmt --all --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Use release builds for performance and animation checks. Preview changes in a
|
||||||
|
[nested session](installation.md#preview-and-logs) before testing hardware behavior.
|
||||||
|
Keep another desktop available for direct-session recovery.
|
||||||
|
|
||||||
|
## Test guides
|
||||||
|
|
||||||
|
- [Animation checks](animation-validation.md): transitions, interruption, and hit testing.
|
||||||
|
- [Nested resize checks](nested-resize-testing.md): wallpaper and bar responsiveness.
|
||||||
|
- [Client soak testing](native-soak-testing.md): repeated client lifecycle and resource growth.
|
||||||
|
- [Performance measurements](performance-baseline.md): sampling and historical results.
|
||||||
|
|
||||||
|
The [compositor](ferese-window-manager-spec.md), [shell](ferese-shell-design.md),
|
||||||
|
and [theme](ferese-theme-ui-spec.md) references describe the main code boundaries.
|
||||||
|
|
||||||
|
## Portal checks
|
||||||
|
|
||||||
|
Run backend unit tests and compare D-Bus contracts against installed portal XML:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo test --locked -p xdg-desktop-portal-ferese
|
||||||
|
python3 scripts/tests/test_portal_contracts.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The contract test uses a private bus. It checks signatures, appearance changes,
|
||||||
|
invalid-config retention, and caller authorization. It does not prove complete
|
||||||
|
compatibility with every app or open consent dialogs.
|
||||||
|
|
||||||
|
With release binaries built, run isolated integration checks:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
FERESE_TEST_SHORTCUTS=1 python3 scripts/tests/test_shortcuts_isolated.py
|
||||||
|
FERESE_TEST_WINDOW_CAPTURE=1 python3 scripts/tests/test_window_capture_isolated.py
|
||||||
|
FERESE_TEST_INHIBIT=1 python3 scripts/tests/test_inhibit_isolated.py
|
||||||
|
FERESE_TEST_RESTORE=1 python3 scripts/tests/test_restore_isolated.py
|
||||||
|
FERESE_TEST_WINDOW_STREAM=1 python3 scripts/tests/test_window_stream_isolated.py
|
||||||
|
```
|
||||||
|
|
||||||
|
These cover shortcut cleanup, window capture, inhibitors, restored permissions,
|
||||||
|
and live window streams. Check each script's dependencies before running it.
|
||||||
|
They use disposable nested sessions or private buses.
|
||||||
|
|
||||||
|
For monitor streaming and lock revocation, install Python GI/GStreamer with
|
||||||
|
`pipewiresrc`, `dbus-daemon`, `xdg-desktop-portal`, and `bwrap`, then run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
FERESE_TEST_PORTAL=1 \
|
||||||
|
FERESE_TEST_PORTAL_BINARY=target/release/xdg-desktop-portal-ferese \
|
||||||
|
python3 scripts/tests/test_portal_isolated.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `FERESE_TEST_PORTAL_CONSENT=1` to exercise the picker. Choose the temporary
|
||||||
|
display and click **Share**. Tests must target the nested preview, not the host desktop.
|
||||||
|
|
||||||
|
Check real encoding and the private InputCapture transport:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo test --locked -p xdg-desktop-portal-ferese --bin ferese-record encoder_finishes_a_real_webm -- --ignored
|
||||||
|
cargo test --locked -p ferese input_capture::tests
|
||||||
|
cargo test --locked -p xdg-desktop-portal-ferese eis::tests -- --ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
Encoding needs the recorder's GStreamer plugins. The transport test needs libei
|
||||||
|
and uses synthetic input over a private socket pair. Hardware pointer barriers,
|
||||||
|
multiple monitors, display sleep, and live authentication still need session tests.
|
||||||
|
|
||||||
|
## Report a bug
|
||||||
|
|
||||||
|
Include the commit or installed release, reproduction steps, backend (nested or
|
||||||
|
direct), monitor scales/transforms, and relevant logs. Avoid publishing passwords,
|
||||||
|
access tokens, or private window content.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Shell behavior
|
||||||
|
|
||||||
|
This is a maintainer reference. User options are documented in
|
||||||
|
[Configuration](configuration.md). Common UI belongs in
|
||||||
|
[ferese-theme](../crates/ferese-theme/README.md).
|
||||||
|
|
||||||
|
## Bar and popovers
|
||||||
|
|
||||||
|
The shell creates a bar for each output. Workspace buttons use compositor state
|
||||||
|
and appear in numeric order. The active window title occupies the center when
|
||||||
|
space allows. Date and time form one calendar button. Right-side controls open
|
||||||
|
sound, battery, notifications, recording, and Control Center popovers.
|
||||||
|
|
||||||
|
A popover is anchored to its control and constrained to the same output.
|
||||||
|
Opening another primary popover replaces the current one. Popovers reserve no
|
||||||
|
workspace space; the bar reserves its configured height and margins.
|
||||||
|
True fullscreen hides the bar without changing the preserved tiled layout.
|
||||||
|
|
||||||
|
Use real service availability for controls. Handle missing services and failed
|
||||||
|
actions without blocking the UI. Settings opens as a separate application.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The compositor presents window previews; the shell supplies labels and workspace
|
||||||
|
controls. Do not continuously copy windows into the shell process.
|
||||||
|
|
||||||
|
Clicking a workspace background selects that workspace and keeps overview open
|
||||||
|
so its windows can be selected. Clicking a window activates that exact window.
|
||||||
|
Directional keys change selection, Enter activates it, and Escape dismisses.
|
||||||
|
Activation must use the selected window ID, not the window focused before overview.
|
||||||
|
|
||||||
|
## Focus and dialogs
|
||||||
|
|
||||||
|
The bar and notification popups do not normally take keyboard focus. Interactive
|
||||||
|
shell surfaces restore the previous valid app focus when dismissed.
|
||||||
|
|
||||||
|
Power actions and logout use a centered system confirmation, including blockers
|
||||||
|
when present. Input outside the confirmation must not reach applications.
|
||||||
|
Authentication, screen-sharing, and recording dialogs are separate themed windows.
|
||||||
|
Use one visible frame, content-sized height, and an output-sized height limit.
|
||||||
|
Scrollable lists must leave headings and action buttons accessible.
|
||||||
|
|
||||||
|
Attach dialog material to the content card using the shared theme helper.
|
||||||
|
Match blur regions to the displayed card throughout opening and resize; do not
|
||||||
|
paint an opaque window behind a translucent card.
|
||||||
|
|
||||||
|
## Notifications and widgets
|
||||||
|
|
||||||
|
The shell provides the standard notification service. Normal popups respect
|
||||||
|
Do Not Disturb; critical messages bypass it. History is held in memory and clears
|
||||||
|
when the shell exits. See [Notifications](notifications.md).
|
||||||
|
|
||||||
|
Clock and note widgets sit behind application windows, reserve no workspace space,
|
||||||
|
and save positions after dragging. Only interactive notes take keyboard focus.
|
||||||
|
See [Desktop widgets](desktop-widgets.md).
|
||||||
|
|
||||||
|
## Lifecycle
|
||||||
|
|
||||||
|
Shell failure must not destroy managed windows or workspace state. Reconstruct
|
||||||
|
bars and controls from compositor state after reconnecting, and clear dead shell
|
||||||
|
focus. Notification history is not reconstructed from disk.
|
||||||
|
|
||||||
|
Keep slow service queries, image loading, and filesystem work away from UI event
|
||||||
|
handling. Stop animation work once the UI settles. Validate popover placement,
|
||||||
|
fullscreen transitions, dialog dismissal, and shell restart in a nested session.
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# Theme components
|
||||||
|
|
||||||
|
Ferese's native apps use [ferese-theme](../crates/ferese-theme/README.md) for
|
||||||
|
colors, fonts, controls, menus, icons, calendar elements, and dialog materials.
|
||||||
|
Use [Configuration → Appearance](configuration.md#appearance) for supported keys
|
||||||
|
and defaults.
|
||||||
|
|
||||||
|
## Shared appearance
|
||||||
|
|
||||||
|
The six presets are Ferese Blue, Monochrome, Gruvbox, Dracula, Ayu Light, and
|
||||||
|
Monokai. Ferese Blue uses the logo accent, `#3D7BE6`. Presets change colors while
|
||||||
|
preserving wallpaper, typography, corners, and opacity.
|
||||||
|
|
||||||
|
The interface font applies to shell text and native dialogs. Clock and note
|
||||||
|
widgets can override it. Managed-window corners and shell corners are separate
|
||||||
|
settings; small controls cap their corners to fit their size.
|
||||||
|
|
||||||
|
## Materials
|
||||||
|
|
||||||
|
Two material styles are supported:
|
||||||
|
|
||||||
|
| Style | Background |
|
||||||
|
| --- | --- |
|
||||||
|
| `solid` | Opaque theme surface |
|
||||||
|
| `translucent` | Theme tint over blurred background content |
|
||||||
|
|
||||||
|
Bars, popovers, notifications, and themed dialogs share `theme.material.opacity`
|
||||||
|
and `blur-radius`. Text and icons stay opaque. An opacity of zero hides the
|
||||||
|
material; blur radius zero disables blur. Solid mode stays opaque.
|
||||||
|
|
||||||
|
```kdl
|
||||||
|
theme {
|
||||||
|
colors {
|
||||||
|
accent "#3D7BE6"
|
||||||
|
}
|
||||||
|
material {
|
||||||
|
style "translucent"
|
||||||
|
opacity 0.78
|
||||||
|
blur-radius 12
|
||||||
|
}
|
||||||
|
geometry {
|
||||||
|
shell-radius 14
|
||||||
|
window-radius 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The compositor owns blur and tint. `material::ModalMaterial` attaches native
|
||||||
|
dialogs to that rendering path. Keep the attachment alive with the window and
|
||||||
|
make the attached client background transparent. Outside Ferese, retain a client
|
||||||
|
background so the dialog remains usable.
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
| Module | Use |
|
||||||
|
| --- | --- |
|
||||||
|
| `palette` | Resolve configuration colors and build the native toolkit theme |
|
||||||
|
| `controls` | Surfaces, navigation, text buttons, and input styles |
|
||||||
|
| `menus` | Rows, headings, sections, separators, switches, and sliders |
|
||||||
|
| `calendar` | Date/time labels, clock digits, and calendar grids |
|
||||||
|
| `icons` | Shared SVG assets, sizing, and tint |
|
||||||
|
| `typography` | Shared font selection and text |
|
||||||
|
| `contrast` | Readable labels on filled controls |
|
||||||
|
| `material` | Attach modal cards to compositor materials |
|
||||||
|
|
||||||
|
Applications provide data, layout, actions, and animation progress. Extend shared
|
||||||
|
components when a style is needed in multiple apps. Avoid hardcoded app-specific
|
||||||
|
fonts, foreground colors, or opacity values.
|
||||||
|
|
||||||
|
## UI checks
|
||||||
|
|
||||||
|
- Check text and icons in all six presets, including Ayu Light.
|
||||||
|
- Check rest, hover, pressed, focused, selected, and disabled controls.
|
||||||
|
- Keep accent-button labels readable after typing or changing focus.
|
||||||
|
- Keep controls usable with solid materials and blur disabled.
|
||||||
|
- Align material regions with the visible card at every output scale.
|
||||||
|
- Give dialogs one frame; cap their height and scroll their content, preserving actions.
|
||||||
|
- Respect reduced motion and stop requesting animation frames after settling.
|
||||||
|
|
||||||
|
Theme changes affect appearance; they do not change focus, workspace ownership,
|
||||||
|
input permissions, or authentication policy.
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# Compositor architecture
|
||||||
|
|
||||||
|
This is a maintainer reference. For supported configuration and shortcuts, use
|
||||||
|
[Configuration](configuration.md); for builds and checks, use [Development](development.md).
|
||||||
|
|
||||||
|
## Processes and crates
|
||||||
|
|
||||||
|
| Component | Responsibility |
|
||||||
|
| --- | --- |
|
||||||
|
| `ferese` | Wayland clients, windows, workspaces, input, outputs, and rendering |
|
||||||
|
| `ferese-shell` | Bar, popovers, notifications, widgets, and system confirmations |
|
||||||
|
| `ferese-settings` | Configuration editor |
|
||||||
|
| `feresectl` | Command-line control |
|
||||||
|
| `ferese-lock` | Lock-screen UI and PAM authentication |
|
||||||
|
| `ferese-polkit-agent` | System authentication prompts |
|
||||||
|
| `xdg-desktop-portal-ferese` | Desktop portal requests and PipeWire streams |
|
||||||
|
| `ferese-record` | Video encoding and saving |
|
||||||
|
|
||||||
|
The compositor uses Smithay and calloop. The direct backend renders through
|
||||||
|
DRM/KMS; the nested backend renders into a window on another Wayland desktop.
|
||||||
|
Native UIs use libcosmic. Layout, animation, configuration, IPC, protocols, and
|
||||||
|
[theme components](../crates/ferese-theme/README.md) live in separate crates.
|
||||||
|
|
||||||
|
## State and ownership
|
||||||
|
|
||||||
|
The event loop owns compositor state and Wayland objects. Background workers
|
||||||
|
return results through bounded channels; results must be checked against current
|
||||||
|
window, output, and request identities before application.
|
||||||
|
|
||||||
|
Keep these relationships valid after a state change:
|
||||||
|
|
||||||
|
- Each window belongs to one workspace and appears once in its layout or floating list.
|
||||||
|
- Each attached workspace belongs to one output; each output has one active workspace.
|
||||||
|
- A window's output follows workspace ownership.
|
||||||
|
- Fullscreen preserves the underlying layout or floating placement.
|
||||||
|
- Focus points to a live window or authorized shell surface.
|
||||||
|
- Workspace focus history is distinct from current keyboard focus.
|
||||||
|
|
||||||
|
Monitor removal migrates workspaces to a remaining output. Returning monitors
|
||||||
|
restore eligible workspaces; explicit user moves take priority. Selecting a
|
||||||
|
workspace visible on another monitor focuses that monitor.
|
||||||
|
|
||||||
|
## Layout and presentation
|
||||||
|
|
||||||
|
Scrolling layouts arrange columns horizontally. Windows within a column divide
|
||||||
|
its height. A workspace owns its viewport; presentation subtracts that viewport
|
||||||
|
from window positions. Tree layouts use nested splits and stacks. Layout changes
|
||||||
|
preserve window membership and floating placement.
|
||||||
|
|
||||||
|
Keep layout targets, animated rectangles, and committed client sizes separate.
|
||||||
|
A layout transition requests the destination client size rather than sending
|
||||||
|
one configure per animation frame. Available content is scaled and clipped until
|
||||||
|
the matching client buffer arrives. Hit testing uses the same presented geometry.
|
||||||
|
Interrupted animations continue from their current position.
|
||||||
|
|
||||||
|
Input and layout use logical pixels. Rendering converts them using the output's
|
||||||
|
scale and transform. Application popups use their parent's output and presented
|
||||||
|
position when calculating bounds.
|
||||||
|
|
||||||
|
## Rendering and frame delivery
|
||||||
|
|
||||||
|
Render damage from client commits, animations, effects, cursor motion, and output
|
||||||
|
changes. Movement damages both old and new bounds, including shadows and blur.
|
||||||
|
Output-specific callbacks follow window ownership. Presentation feedback is
|
||||||
|
collected only for surfaces the renderer actually displayed on that output.
|
||||||
|
An unchanged frame still permits paced client callbacks without submitting a
|
||||||
|
new display buffer.
|
||||||
|
|
||||||
|
Animations use elapsed time across outputs, with a timer while transitions remain
|
||||||
|
active. An idle focused monitor must not stall another monitor's animation.
|
||||||
|
|
||||||
|
The compositor renders blur from content behind the requesting surface. Material
|
||||||
|
regions and client content must share coordinates during placement, scaling,
|
||||||
|
and animation. See [Theme components](ferese-theme-ui-spec.md).
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
Use milliseconds for keyboard, pointer, touch, and gesture protocol events;
|
||||||
|
relative-motion timestamps retain microseconds. Keep keyboard focus, pointer
|
||||||
|
focus, and window stacking separate. Hover focus does not scroll or raise windows.
|
||||||
|
|
||||||
|
Pointer grabs and constraints must end cleanly when their surface disappears.
|
||||||
|
A locked pointer's position hint is stored while locked, then resolved against
|
||||||
|
current surface geometry and clamped to an output when the lock is released.
|
||||||
|
|
||||||
|
## IPC and private protocols
|
||||||
|
|
||||||
|
User control uses `$XDG_RUNTIME_DIR/ferese/control.sock`, restricted to the
|
||||||
|
session user. The parent directory is private and peers are checked by UID.
|
||||||
|
IPC frames are length-prefixed JSON with bounded message sizes, workers, and queues.
|
||||||
|
See `feresectl --help` for commands.
|
||||||
|
|
||||||
|
Private Wayland capabilities grant shell control or material effects to trusted
|
||||||
|
components. Public layer-shell access alone grants neither. Trusted connections
|
||||||
|
and descriptors must not leak to launched applications. Capture paths check
|
||||||
|
session policy and reject capture while locked.
|
||||||
|
|
||||||
|
Session locking must protect every output, including hotplug, and remain secure
|
||||||
|
if the lock UI crashes. [Portal integration](portals.md) documents application
|
||||||
|
consent and the currently supported services.
|
||||||
|
|
||||||
|
## Review and testing
|
||||||
|
|
||||||
|
Check output ownership, presented geometry, focus restoration, request lifetimes,
|
||||||
|
and bounded work whenever changing a protocol or rendering path. Test both
|
||||||
|
backends; a nested result does not establish hardware behavior.
|
||||||
|
|
||||||
|
Use the [animation](animation-validation.md), [resize](nested-resize-testing.md),
|
||||||
|
and [soak](native-soak-testing.md) checks alongside the workspace tests.
|
||||||
+24
-58
@@ -6,23 +6,12 @@ TTY. You do not need to replace your existing login manager or desktop.
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
You need a working graphics driver with DRM/KMS and EGL support, an authenticated
|
Use a Wayland-capable graphics driver and a local user session with seat access
|
||||||
local login session with seat access through logind or seatd, D-Bus, and
|
through logind or seatd. A nested preview runs inside an existing Wayland desktop.
|
||||||
Linux-PAM for the native locker. A nested preview needs an existing Wayland
|
|
||||||
desktop instead of direct access to the graphics device.
|
|
||||||
|
|
||||||
Build with **Rust 1.95 or newer**, a C/C++ toolchain, CMake, pkg-config, and the
|
Building requires **Rust 1.95 or newer**, a C/C++ toolchain, CMake, pkg-config,
|
||||||
native development libraries below. The installer builds Ferese, its shell,
|
and the libraries below. The installer builds all Ferese components; install
|
||||||
Settings, command-line tools, locker, polkit agent, and desktop portal backend together. It does not install system
|
system packages separately.
|
||||||
packages or enable background services at boot. On systemd systems, the installed
|
|
||||||
session helper activates `ferese-session.target` after exporting the compositor's
|
|
||||||
Wayland display, and stops it when the shell exits. This keeps
|
|
||||||
`graphical-session.target` active so desktop portals can start. The native portal
|
|
||||||
is D-Bus activated and supervised by systemd; it stops with the session so a
|
|
||||||
previous release cannot remain running after logout. Session startup also refreshes
|
|
||||||
an already-running native portal after importing the current display environment.
|
|
||||||
Nested previews
|
|
||||||
do not alter the host's activation environment or session targets.
|
|
||||||
|
|
||||||
### Fedora
|
### Fedora
|
||||||
|
|
||||||
@@ -60,11 +49,9 @@ sudo apt install build-essential git curl cmake pkg-config libwayland-dev \
|
|||||||
gstreamer1.0-plugins-good
|
gstreamer1.0-plugins-good
|
||||||
```
|
```
|
||||||
|
|
||||||
These are package recipes, not a claim that every distribution release has been
|
Fedora is the tested installation path. Package names and versions may differ
|
||||||
tested. Fedora is the currently exercised installation path. Older releases
|
on other distributions. See [Smithay dependencies](https://github.com/Smithay/smithay#system-dependencies)
|
||||||
may need newer packages or additional repositories. For other distributions,
|
for equivalent libraries.
|
||||||
install the equivalent libraries; see the upstream
|
|
||||||
[Smithay dependencies](https://github.com/Smithay/smithay#system-dependencies).
|
|
||||||
|
|
||||||
### Rust toolchain
|
### Rust toolchain
|
||||||
|
|
||||||
@@ -98,32 +85,17 @@ The script builds locked release binaries, then requests administrator access
|
|||||||
through `sudo` or `pkexec` for installation. Do not run the whole build as root.
|
through `sudo` or `pkexec` for installation. Do not run the whole build as root.
|
||||||
The first build needs network access to fetch Rust dependencies.
|
The first build needs network access to fetch Rust dependencies.
|
||||||
|
|
||||||
The installer adds:
|
The installer adds the session launcher, desktop tools, portal backend, login
|
||||||
|
entry, icons, default wallpaper, and example config. Releases live under
|
||||||
|
`/usr/local/lib/ferese/releases/`; commands live under `/usr/local/bin/`.
|
||||||
|
The `current` and `previous` links support updates and rollback.
|
||||||
|
|
||||||
- Versioned releases under `/usr/local/lib/ferese/releases/`, with `current` and
|
Your configuration, other desktop sessions, and existing PAM policy are preserved.
|
||||||
`previous` links for upgrades and rollback.
|
Ferese starts its authentication agent and portal services with the session.
|
||||||
- Commands under `/usr/local/bin/`, including `ferese-session`, `ferese-settings`,
|
|
||||||
`feresectl`, `ferese-lock`, `ferese-polkit-agent`, `ferese-screenshot`, and
|
|
||||||
`xdg-desktop-portal-ferese`, and `ferese-record`.
|
|
||||||
- D-Bus activation and Ferese-specific desktop portal registration.
|
|
||||||
- A Wayland session entry at `/usr/share/wayland-sessions/ferese.desktop`.
|
|
||||||
- A Settings application entry, icons, the default wallpaper, and an example config.
|
|
||||||
- `/etc/pam.d/ferese-lock`, using your distribution's authentication stack.
|
|
||||||
An existing administrator-supplied policy is preserved.
|
|
||||||
|
|
||||||
Your existing configuration and other desktop sessions are preserved. The
|
|
||||||
installer does not change your default session or login manager.
|
|
||||||
|
|
||||||
Ferese starts its own polkit authentication agent with the shell. Password
|
|
||||||
prompts follow the configured font, accent, surface color, and corner radius.
|
|
||||||
Authentication still uses polkit's system helper and policy. The agent starts
|
|
||||||
only inside a Ferese session; logging into another desktop leaves its agent
|
|
||||||
unchanged. Restart your Ferese session after upgrading to use the new prompt.
|
|
||||||
|
|
||||||
### Initial configuration
|
### Initial configuration
|
||||||
|
|
||||||
Ferese has built-in defaults. To start from the example without replacing an
|
Ferese has built-in defaults. To start from the example without replacing your config:
|
||||||
existing config:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/ferese"
|
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/ferese"
|
||||||
@@ -144,9 +116,7 @@ command in Settings if you prefer another terminal.
|
|||||||
|
|
||||||
Save your work and log out. Open your login screen's session selector, choose
|
Save your work and log out. Open your login screen's session selector, choose
|
||||||
**Ferese**, and sign in. Any manager that supports Wayland sessions and reads
|
**Ferese**, and sign in. Any manager that supports Wayland sessions and reads
|
||||||
`/usr/share/wayland-sessions/` can discover the installed entry. The selector's
|
`/usr/share/wayland-sessions/` can discover the installed entry.
|
||||||
location and whether it appears before or after choosing your account depend
|
|
||||||
on the login manager.
|
|
||||||
|
|
||||||
If Ferese is missing, confirm that the session entry exists and its launcher is
|
If Ferese is missing, confirm that the session entry exists and its launcher is
|
||||||
executable:
|
executable:
|
||||||
@@ -169,15 +139,9 @@ If your greeter asks for a session command instead of reading desktop files, use
|
|||||||
/usr/local/bin/ferese-session
|
/usr/local/bin/ferese-session
|
||||||
```
|
```
|
||||||
|
|
||||||
For a setup such as greetd, configure that as the command launched **after user
|
For greetd, use this as the session command after authentication; see the
|
||||||
authentication**, using your greeter's session-command option. Preserve the
|
[greetd documentation](https://sr.ht/~kennylevinsen/greetd/).
|
||||||
existing authentication and greeter configuration. Do not set Ferese itself as
|
The launcher starts the compositor, shell, and session services together.
|
||||||
the privileged greeter process. See the
|
|
||||||
[greetd documentation](https://sr.ht/~kennylevinsen/greetd/) for your chosen frontend.
|
|
||||||
|
|
||||||
The launcher starts the compositor and shell together, sets the desktop
|
|
||||||
environment variables, and starts a D-Bus session when one is not already
|
|
||||||
available. Launch it instead of the bare compositor for a complete desktop.
|
|
||||||
|
|
||||||
### From a TTY
|
### From a TTY
|
||||||
|
|
||||||
@@ -229,7 +193,8 @@ inside an existing Wayland desktop:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo build --release --locked -p ferese -p ferese-shell -p ferese-settings -p feresectl -p ferese-lock -p xdg-desktop-portal-ferese
|
cargo build --release --locked -p ferese -p ferese-shell -p ferese-settings -p feresectl -p ferese-lock -p xdg-desktop-portal-ferese
|
||||||
target/release/ferese --backend nested --grant-effects --grant-shell-control -- \
|
FERESE_ENABLE_SCREENCOPY=1 target/release/ferese --backend nested \
|
||||||
|
--grant-effects --grant-shell-control -- \
|
||||||
target/release/ferese-shell
|
target/release/ferese-shell
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -283,12 +248,13 @@ Installer options:
|
|||||||
|
|
||||||
`--dry-run` prints the planned commands. `--offline` requires dependencies to be
|
`--dry-run` prints the planned commands. `--offline` requires dependencies to be
|
||||||
cached already. `--skip-build` installs the binaries already in `target/release/`;
|
cached already. `--skip-build` installs the binaries already in `target/release/`;
|
||||||
use it only after building all six components from the intended revision.
|
use it only after building all components from the intended revision.
|
||||||
Run `./scripts/install.sh --help` for all options.
|
Run `./scripts/install.sh --help` for all options.
|
||||||
|
|
||||||
## Logout and recovery
|
## Logout and recovery
|
||||||
|
|
||||||
Save your work before **Super+Shift+E** or `feresectl exit`: logout is immediate.
|
Use **Super+Shift+E** or `feresectl request-logout` to ask for logout confirmation.
|
||||||
|
`feresectl exit` ends the session immediately; save your work first.
|
||||||
If Ferese freezes, switch to another TTY with **Ctrl+Alt+F1–F12**, sign in, and
|
If Ferese freezes, switch to another TTY with **Ctrl+Alt+F1–F12**, sign in, and
|
||||||
identify the affected compositor process:
|
identify the affected compositor process:
|
||||||
|
|
||||||
|
|||||||
+38
-83
@@ -1,79 +1,43 @@
|
|||||||
# Native locker
|
# Lock screen
|
||||||
|
|
||||||
Ferese Lock uses `ext-session-lock-v1`, not a fullscreen application overlay.
|
Ferese Lock follows your desktop wallpaper, colors, font, and shell corners.
|
||||||
Each output receives its own surface, including outputs added while locked.
|
Open **Settings → Lock screen** to change its clock, date, wallpaper softness,
|
||||||
The compositor protects the desktop if the client exits or crashes.
|
and inactivity delays.
|
||||||
|
|
||||||
## Preview
|
## Preview and lock
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo build --release --locked -p ferese-lock
|
ferese-lock --preview # ordinary window; does not lock or check passwords
|
||||||
target/release/ferese-lock --preview
|
ferese-lock # lock; returns after compositor confirmation
|
||||||
|
ferese-lock --foreground # stay attached until unlock
|
||||||
```
|
```
|
||||||
|
|
||||||
This is an ordinary, closable window. Submitting the field does not call PAM,
|
Do not enter your real password in a preview. The account picture comes from
|
||||||
lock, or unlock anything. Do not type your actual password into a visual preview.
|
AccountsService or `~/.face`; a silhouette is used when neither is available.
|
||||||
|
|
||||||
Settings → Lock screen provides clock visibility, date visibility, time format,
|
Escape clears the password. Caps Lock is shown beside authentication status.
|
||||||
wallpaper dimming and softness, inactivity delays, and a safe preview button. Your account picture is loaded from
|
Failed attempts show an error and delay retries. Authentication uses the system's
|
||||||
AccountsService or `~/.face`, with a user silhouette as a fallback.
|
PAM policy; both password and account validation must succeed.
|
||||||
|
|
||||||
The locker reads Ferese's wallpaper, theme colors, typography, and shell radius
|
## Automatic locking
|
||||||
at startup. The wallpaper is softened once and shared across displays. Set softness
|
|
||||||
to zero to keep it sharp. Escape clears the password. Caps Lock is shown above authentication
|
|
||||||
status. Password verification runs on a worker, and repeated attempts are held
|
|
||||||
for two seconds after failure, in addition to delays enforced by PAM.
|
|
||||||
|
|
||||||
## Installation and locking
|
Install `swayidle`, then add this to `~/.config/ferese/config.kdl` to lock after
|
||||||
|
five minutes and before system sleep:
|
||||||
|
|
||||||
The normal `scripts/install.sh` includes the native binary and installs
|
```kdl
|
||||||
`/etc/pam.d/ferese-lock` if absent. Existing administrator policies are preserved.
|
autostart {
|
||||||
Fedora/Arch installations use `system-auth`; Debian-family installations use
|
command "swayidle" "-w" "timeout" "300" "ferese-lock" "before-sleep" "ferese-lock" "lock" "ferese-lock"
|
||||||
`common-auth` and `common-account`; the fallback uses the system `login` stack.
|
}
|
||||||
There is no setuid binary, password command argument, or shadow-file reader.
|
|
||||||
Both authentication and account validation must succeed. Expired credentials
|
|
||||||
must be updated outside the locker. Interactive multi-factor enrollment and
|
|
||||||
password changes are not supported by this initial password UI.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
ferese-lock # returns after confirmation, UI stays running
|
|
||||||
ferese-lock --foreground # stays attached until unlock
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `swayidle -w` example in [Configuration](configuration.md#login-items-and-locking)
|
Test password unlocking before enabling automatic locking. The installer provides
|
||||||
can invoke the default command. Auto-locking is opt-in. This change does not
|
`/etc/pam.d/ferese-lock` and preserves an existing administrator policy.
|
||||||
install or start an idle daemon, replace your login manager, or change the Control Center's
|
|
||||||
suspend action. Test real password authentication inside a nested Ferese session
|
|
||||||
before enabling this on your desktop.
|
|
||||||
|
|
||||||
## Security and recovery
|
|
||||||
|
|
||||||
Never interpret the preview as proof of a locked desktop. A missing PAM policy
|
|
||||||
or unsupported compositor produces an error before a lock request. A failure
|
|
||||||
or authentication-worker panic never authorizes unlock. A crash after the lock
|
|
||||||
request may leave the session permanently locked; end that session from another
|
|
||||||
TTY if necessary. Do not restart the compositor to test crash behavior on a live
|
|
||||||
session with unsaved work.
|
|
||||||
|
|
||||||
The pinned libcosmic backend emits `Locked` twice: once when requesting a lock
|
|
||||||
and once on the actual protocol callback. The startup handshake waits for the
|
|
||||||
second notification. Re-audit this behavior whenever upgrading libcosmic. The
|
|
||||||
parent times out with an error after 15 seconds and leaves the UI running; it
|
|
||||||
never reports success merely because the window appeared.
|
|
||||||
|
|
||||||
Validation references: [session-lock protocol](https://wayland.app/protocols/ext-session-lock-v1),
|
|
||||||
[PAM authentication](https://man7.org/linux/man-pages/man3/pam_authenticate.3.html),
|
|
||||||
and [PAM account checks](https://man7.org/linux/man-pages/man3/pam_acct_mgmt.3.html).
|
|
||||||
|
|
||||||
## Inactivity and display sleep
|
## Inactivity and display sleep
|
||||||
|
|
||||||
A locked display dims after 30 seconds without input and sleeps after 120 seconds.
|
Locked displays dim after 30 seconds without input and sleep after 120 seconds.
|
||||||
Dimming fades over half a second. Any keyboard, pointer or touch activity restores
|
Keyboard, pointer, or touch activity wakes them without unlocking. Set either
|
||||||
brightness and wakes the display while keeping the session locked. The compositor
|
delay to zero to disable it, in Settings or KDL:
|
||||||
owns this policy, so it remains effective if the locker crashes. Sleep starts only
|
|
||||||
after the compositor has confirmed that every display is protected.
|
|
||||||
|
|
||||||
Settings → Lock screen adjusts both delays. Zero disables that action:
|
|
||||||
|
|
||||||
```kdl
|
```kdl
|
||||||
lock-screen {
|
lock-screen {
|
||||||
@@ -82,28 +46,19 @@ lock-screen {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
These delays are independent of automatic locking. Existing idle inhibitors from
|
These delays start after locking, independently of the automatic-lock timer.
|
||||||
apps cannot keep an already locked display awake. In a direct session, display
|
Display sleep does not suspend the computer. A nested preview shows black
|
||||||
sleep uses DRM DPMS without removing outputs or rearranging workspaces; nested
|
instead of powering off the host display.
|
||||||
previews show black instead of powering off the host display. This puts displays
|
|
||||||
to sleep, not the computer. Suspend remains a separate system power action.
|
|
||||||
|
|
||||||
## Practical swaylock comparison
|
## Recovery and limits
|
||||||
|
|
||||||
| Behavior | Ferese Lock |
|
The lock covers all displays, including newly connected ones. If the lock UI
|
||||||
| --- | --- |
|
crashes, the compositor keeps the session protected. Recovery may require ending
|
||||||
| Secure Wayland locking and protection after a locker crash | Session-lock protocol, compositor-owned fallback |
|
that session from another TTY; see [Recovery](installation.md#logout-and-recovery).
|
||||||
| All displays, including hotplug | Separate lock surface for each display |
|
|
||||||
| Readiness before an idle manager permits suspend | Default command waits for compositor confirmation |
|
|
||||||
| Password verification | PAM authentication and account checks on a worker |
|
|
||||||
| Password clearing and Caps Lock feedback | Escape clears; Caps Lock indicator |
|
|
||||||
| Authentication failure feedback and retry delay | Error message and bounded retry delay |
|
|
||||||
| Wallpaper, font and color customization | Shared Ferese theme and Settings |
|
|
||||||
| Inactivity and display power | Compositor dimming and DPMS; input restores brightness |
|
|
||||||
|
|
||||||
[Swaylock](https://github.com/swaywm/swaylock/blob/master/swaylock.1.scd) provides
|
The password interface does not support password changes or interactive
|
||||||
additional appearance flags, layout indicators and readiness-FD CLI options.
|
multi-factor prompts. Update expired credentials outside the locker.
|
||||||
Ferese uses its shared configuration and existing startup acknowledgement instead.
|
|
||||||
Like the [swayidle example](https://github.com/swaywm/swayidle/blob/master/swayidle.1.scd),
|
Developers should validate locking and readiness against
|
||||||
locking and display sleep are separate from system suspend. Password changes and
|
[ext-session-lock-v1](https://wayland.app/protocols/ext-session-lock-v1).
|
||||||
interactive multi-factor prompts remain outside this password-only interface.
|
See [Development](development.md) for tests.
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# Native-client soak testing
|
||||||
|
|
||||||
|
The 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` and start a disposable
|
||||||
|
[nested session](installation.md#preview-and-logs). Select its Wayland socket and
|
||||||
|
compositor PID explicitly, then run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
WAYLAND_DISPLAY=wayland-N FERESE_PID=PID ./scripts/soak-native.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `wayland-N` and `PID` with the preview's values. Do not use the host socket
|
||||||
|
or rely on automatic PID selection when multiple sessions are running.
|
||||||
|
|
||||||
|
The default duration is 24 hours. A shorter validation run is:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
WAYLAND_DISPLAY=wayland-N \
|
||||||
|
FERESE_PID=PID \
|
||||||
|
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.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Nested resize checks
|
||||||
|
|
||||||
|
Build and launch a preview with protocol and render logging:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo build --release --locked -p ferese -p ferese-shell
|
||||||
|
WAYLAND_DEBUG=1 FERESE_TRACE_PERFORMANCE=1 \
|
||||||
|
target/release/ferese --backend nested --grant-effects --grant-shell-control -- \
|
||||||
|
target/release/ferese-shell 2>/tmp/ferese-resize.log
|
||||||
|
```
|
||||||
|
|
||||||
|
Use a wallpaper, drag each edge of the host window, and repeatedly maximize and
|
||||||
|
restore it. Check that the wallpaper and bar follow without long stalls, including
|
||||||
|
at fractional scaling.
|
||||||
|
|
||||||
|
## Compare renderers
|
||||||
|
|
||||||
|
Repeat with `ICED_BACKEND=wgpu` and `ICED_BACKEND=tiny-skia`. The shell enables
|
||||||
|
wgpu; software fallback can be slower when resampling wallpaper.
|
||||||
|
|
||||||
|
Trace the whole sequence: host resize, layer configure, client acknowledgement,
|
||||||
|
new buffer commit, then compositor rendering. A quick acknowledgement does not
|
||||||
|
mean the client has finished drawing. `FERESE_TRACE_PERFORMANCE` measures compositor
|
||||||
|
work, not shell rasterization.
|
||||||
|
|
||||||
|
## Historical check
|
||||||
|
|
||||||
|
A KDE Wayland check at 175% scale used debug binaries and protocol tracing.
|
||||||
|
Median configure acknowledgement was 1.35 ms with tiny-skia and 2.27 ms with
|
||||||
|
wgpu. Wallpaper buffer intervals were 5919 ms with tiny-skia (only two buffers)
|
||||||
|
and 9.85 ms median with wgpu. Capture durations differed, so these are diagnostic
|
||||||
|
observations rather than throughput benchmarks. GPU intervals also had stalls
|
||||||
|
up to about 200 ms.
|
||||||
|
|
||||||
|
Repeat on the current build. A nested result does not establish direct-session
|
||||||
|
resize or frame-pacing behavior.
|
||||||
+28
-38
@@ -1,37 +1,24 @@
|
|||||||
# Notifications
|
# Notifications
|
||||||
|
|
||||||
Ferese Shell provides themed notification cards and an in-session history panel.
|
Ferese shows compact notification popups and a history panel opened from the bar.
|
||||||
Cards appear beneath the bar on the focused output and follow the selected theme.
|
Their colors, font, corners, and background follow the shell theme.
|
||||||
Click the notification icon in the bar to open history, toggle Do Not Disturb, or
|
|
||||||
clear notifications. Escape, clicking outside, or the close button closes the history panel.
|
|
||||||
The center uses the same anchored popup and animation as the other bar menus.
|
|
||||||
Both the center and popup cards follow the shell material: translucent mode uses
|
|
||||||
the compositor’s blur and tint, while solid mode stays opaque.
|
|
||||||
|
|
||||||
## Send a notification
|
|
||||||
|
|
||||||
Notifications use the standard `org.freedesktop.Notifications` D-Bus interface.
|
|
||||||
Existing apps and `notify-send` work without Ferese-specific commands:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
notify-send --app-name=Ferese --icon=dialog-information "Hello" "Your desktop notification"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Popups and history
|
## Popups and history
|
||||||
|
|
||||||
Up to three popup cards are visible at once. History keeps the most recent 100
|
Up to three popups are visible at once. Hovering pauses a popup's timer.
|
||||||
notifications in memory and clears when the shell exits. Hovering a popup pauses
|
History keeps the latest 100 notifications and clears when the shell exits.
|
||||||
its timer. Critical notifications bypass Do Not Disturb and do not expire unless
|
App action buttons work when provided by the sender. Transient messages leave
|
||||||
the sender supplies a timeout. App action buttons emit the standard action signal;
|
history when closed.
|
||||||
a replacement updates the same notification ID. Transient messages are removed
|
|
||||||
from history when they close.
|
|
||||||
|
|
||||||
## Settings and Do Not Disturb
|
Critical notifications bypass Do Not Disturb and remain visible unless the app
|
||||||
|
provides a timeout. Other apps can also request a timeout or no timeout.
|
||||||
|
|
||||||
Settings → Notifications controls popup visibility, the initial Do Not Disturb
|
## Settings
|
||||||
state, and the default timeout. The bar's Do Not Disturb toggle is temporary;
|
|
||||||
changing the Settings option saves the preference for future sessions. Apps can
|
**Settings → Notifications** controls popup visibility, the default timeout, and
|
||||||
request their own timeout, including no timeout.
|
the Do Not Disturb preference. The bar toggle changes Do Not Disturb for the
|
||||||
|
current session; Settings saves it for future sessions. Hidden popups still enter
|
||||||
|
history.
|
||||||
|
|
||||||
```kdl
|
```kdl
|
||||||
notifications {
|
notifications {
|
||||||
@@ -41,17 +28,20 @@ notifications {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The timeout must be between 1000 and 30000 milliseconds. Hiding popups still
|
The default timeout accepts 1000–30000 milliseconds.
|
||||||
records notifications in history. Appearance follows the Ferese theme.
|
|
||||||
|
|
||||||
## Session integration
|
## Send a test notification
|
||||||
|
|
||||||
Only one notification server can own the D-Bus interface. The Ferese session
|
```sh
|
||||||
launcher stops the SwayNotificationCenter user service before starting its shell.
|
notify-send --app-name=Ferese --icon=dialog-information "Hello" "Your desktop notification"
|
||||||
For a manually started shell, stop that service with `systemctl --user stop
|
```
|
||||||
swaync.service`. If another server already owns the interface, Ferese leaves it
|
|
||||||
running and logs that native notifications are unavailable.
|
|
||||||
|
|
||||||
This implementation supports plain text, app icons, urgency, transient/resident
|
## Troubleshooting
|
||||||
hints, actions, replacements, and close signals. It does not advertise rich body
|
|
||||||
markup, embedded image data, notification sounds, or history persistence.
|
Only one notification server can run on the session bus. The session launcher
|
||||||
|
stops `swaync.service` before starting the shell. When launching the shell manually,
|
||||||
|
stop any existing notification server first. If another server owns the interface,
|
||||||
|
Ferese logs that native notifications are unavailable.
|
||||||
|
|
||||||
|
Ferese supports plain text, app icons, actions, replacement, and urgency. Rich
|
||||||
|
markup, embedded images, sounds, and saved notification history are not supported.
|
||||||
+39
-206
@@ -1,217 +1,50 @@
|
|||||||
# Release performance baseline
|
# Performance measurements
|
||||||
|
|
||||||
Measured 2026-09-27 at commit `08a5866`, using
|
Use release builds and a fixed workload when comparing performance. Record the
|
||||||
`cargo build --release --locked -p ferese -p ferese-shell -p feresectl`.
|
commit, output size, scale, refresh rate, graphics driver, and whether the session
|
||||||
|
is nested or direct. Keep the nested preview visible: host occlusion changes
|
||||||
|
rendering behavior.
|
||||||
|
|
||||||
Two disposable nested sessions used separate runtime/config directories, default
|
## Collect a sample
|
||||||
configuration, the bundled wallpaper, and the release shell. Performance logging
|
|
||||||
was enabled with `FERESE_TRACE_PERFORMANCE=1`. The nested output reported
|
|
||||||
1422 × 1696 physical pixels, 2× scale and 60 Hz. The parent DRM output was a
|
|
||||||
2880 × 1800 eDP panel at 120 Hz and 2× scale.
|
|
||||||
|
|
||||||
## Measurements
|
```sh
|
||||||
|
cargo build --release --locked -p ferese -p ferese-shell -p feresectl
|
||||||
|
FERESE_TRACE_PERFORMANCE=1 target/release/ferese --backend nested \
|
||||||
|
--grant-effects --grant-shell-control -- target/release/ferese-shell
|
||||||
|
```
|
||||||
|
|
||||||
CPU is process CPU time from `/proc/PID/stat` divided by elapsed monotonic time,
|
Compare idle, several windows, overview, Settings navigation, translucent
|
||||||
expressed as a percentage of one core. First-run samples lasted 10 seconds;
|
popovers, and screen capture separately. Allow startup to settle and repeat each
|
||||||
second-run samples lasted 5 seconds. These are short observational samples,
|
sample. Record process CPU, child-process CPU, RSS, render attempts, and damaged
|
||||||
not statistically established improvements or before/after comparisons.
|
frames. Keep build work and unrelated activity outside the sampling interval.
|
||||||
|
|
||||||
| Scenario | Compositor CPU, run 1 / run 2 | Shell CPU, run 1 / run 2 |
|
CPU percentages below use one core as 100%. Short samples are observations,
|
||||||
|
not guarantees or hardware-session benchmarks.
|
||||||
|
|
||||||
|
## Historical results
|
||||||
|
|
||||||
|
On 2026-09-27 at `08a5866`, two nested runs used a 1422 × 1696 output at 2× scale,
|
||||||
|
reporting 60 Hz on a 120 Hz host. Samples lasted 5–10 seconds.
|
||||||
|
|
||||||
|
| Scenario | Compositor CPU, two runs | Shell CPU, two runs |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Idle shell, no application window | 5.3% / 5.8% | 1.5% / 1.6% |
|
| Idle, no application window | 5.3% / 5.8% | 1.5% / 1.6% |
|
||||||
| Overview with one terminal | 18.6% / 16.2% | 1.3% / 1.4% |
|
| Overview with one terminal | 18.6% / 16.2% | 1.3% / 1.4% |
|
||||||
| After window transitions, terminal still open | 6.6% / 6.4% | 1.5% / 1.4% |
|
| After transitions | 6.6% / 6.4% | 1.5% / 1.4% |
|
||||||
|
|
||||||
Compositor RSS was approximately 81–82 MiB initially and 91–92 MiB after the
|
Compositor RSS increased from about 81–82 MiB to 91–92 MiB during the exercise.
|
||||||
short exercise. This does not establish a leak or long-term memory stability.
|
These samples do not establish a leak or long-term stability. A follow-up had
|
||||||
Main-thread voluntary context switches were approximately 162–165/s at idle
|
lower rendering rates, so the original observations did not prove duplicate scheduling.
|
||||||
and 498–505/s in overview; these are scheduling proxies, not hardware wakeups.
|
|
||||||
|
|
||||||
A five-second idle log interval contained 60 damaged frames and 531 no-damage
|
A 20-second status-worker comparison removed five commands per poll (15 to 10).
|
||||||
attempts, approximately 118 attempts/s. A later overview interval contained
|
Total measured CPU time including child processes fell from 2.41 to 1.90 seconds.
|
||||||
591 damaged frames in 5001 ms. Nested frame scheduling and overview damage
|
The timing wrapper was included, and this was one comparison.
|
||||||
therefore deserve investigation first. The parent runs at 120 Hz, so the
|
|
||||||
mismatch with the nested output's reported 60 Hz must be understood before
|
|
||||||
attributing these counts to duplicate scheduling.
|
|
||||||
|
|
||||||
## Behavioral exercise
|
For push status delivery (`4bf0757` to `b0583eb`), a synthetic transport test
|
||||||
|
measured median delivery delay of 129.398 ms before and 0.130 ms after. It excluded
|
||||||
|
queries, UI dispatch, and painting. Visible shell samples suggested lower typical
|
||||||
|
CPU, but an after-run spike raised the mean; they did not establish a robust
|
||||||
|
average CPU saving.
|
||||||
|
|
||||||
Both sessions exited with status 0. The probes created a terminal, entered and
|
These results predate later changes. Run fresh comparisons for current claims,
|
||||||
left overview, and toggled maximize, fullscreen and floating twice each.
|
and validate direct rendering and multiple monitors separately.
|
||||||
The second session exercised `theme.typography.font_family`, wallpaper fit/fill,
|
|
||||||
and replacement image paths through filesystem-driven reloads. Logs confirmed
|
|
||||||
accepted reloads and replacement wallpaper decoding. This verifies execution
|
|
||||||
and liveness, not pixel-perfect appearance or GPU allocation-failure recovery.
|
|
||||||
The first probe used an incorrect font key; only the second probe counts as
|
|
||||||
font reload coverage.
|
|
||||||
|
|
||||||
Raw local artifacts:
|
|
||||||
|
|
||||||
- `/tmp/ferese-profile-7cbrpopn/{results.json,session.log}`
|
|
||||||
- `/tmp/ferese-profile-h2ypepn6/{results.json,session.log}`
|
|
||||||
- Probe scripts: `/tmp/ferese-profile.py` and `/tmp/ferese-profile-reloads.py`
|
|
||||||
|
|
||||||
## Limits and next work
|
|
||||||
|
|
||||||
The installed DRM compositor is release `20260927-042025-168287`; its binary hash
|
|
||||||
differs from the tested release build. A read-only host sample measured 9.8%
|
|
||||||
compositor CPU and 1.7% shell CPU, but overlapped the nested workload and is not
|
|
||||||
an idle baseline or validation of the new DRM code. No session was replaced.
|
|
||||||
Only one monitor was connected, so multi-monitor behavior remains untested.
|
|
||||||
|
|
||||||
Next investigate nested refresh scheduling and repeated overview damage, using
|
|
||||||
these scenarios for before/after measurements. Preserve client frame callbacks,
|
|
||||||
animation pacing and idle responsiveness. Status command polling remains a
|
|
||||||
secondary target; blur invalidation needs a separate translucent-material
|
|
||||||
workload before ranking its cost. New-build DRM and multi-monitor validation
|
|
||||||
remain necessary before claiming hardware performance improvements.
|
|
||||||
|
|
||||||
## Follow-up investigation
|
|
||||||
|
|
||||||
A repeat baseline (`/tmp/ferese-profile-n8437l1i`) confirmed 60 Hz after startup
|
|
||||||
but ran near 60 attempts/s rather than 118. Compositor CPU was 3.0% idle, 9.2%
|
|
||||||
in overview and 4.6% after transitions. The earlier high-rate behavior is not
|
|
||||||
consistently reproduced, so it is not sufficient evidence of duplicate redraws.
|
|
||||||
The candidate refresh-period guard was discarded after testing.
|
|
||||||
|
|
||||||
The guard run (`/tmp/ferese-profile-llcrkvm5`) measured 4.0% idle, 8.6% overview,
|
|
||||||
and 3.6% after transitions. Render attempts fell slightly below the nominal
|
|
||||||
cadence. This did not establish a benefit, so no frame-pacing change was kept.
|
|
||||||
The next investigation is unconditional thumbnail damage in overview.
|
|
||||||
|
|
||||||
## Broader profiling (visible preview)
|
|
||||||
|
|
||||||
Artifacts: `/tmp/ferese-profile-all-0lhodit4/`; script:
|
|
||||||
`/tmp/ferese-profile-all.py`. This run used the unchanged release compositor,
|
|
||||||
release shell and release Settings. The user kept the preview visible after an
|
|
||||||
earlier hidden-window run proved that host occlusion invalidated render samples.
|
|
||||||
Six-second samples are exploratory, not statistically stable benchmarks.
|
|
||||||
The captured output was 2856 × 1696 pixels; the preview was resized during the
|
|
||||||
session, so these workloads must not be compared as if output size were fixed.
|
|
||||||
|
|
||||||
| Scenario | Compositor CPU | Shell CPU | Shell waited-child CPU | Settings CPU |
|
|
||||||
| --- | ---: | ---: | ---: | ---: |
|
|
||||||
| Idle shell | 4.33% | 1.33% | 7.50% | — |
|
|
||||||
| Three terminals | 6.67% | 1.50% | 11.33% | — |
|
|
||||||
| Overview, three terminals | 17.50% | 1.17% | 8.17% | — |
|
|
||||||
| Settings open, idle | 6.17% | 1.50% | 10.83% | 0.00% |
|
|
||||||
| After capture/window transitions | 8.50% | 1.33% | 11.00% | 2.50% |
|
|
||||||
|
|
||||||
Percentages use one CPU core as 100%. Child CPU is Linux's accumulated CPU time
|
|
||||||
for reaped children, separate from the shell process. This includes the timing
|
|
||||||
wrapper: a PATH-local `timeout` wrapper invokes GNU time and the real timeout
|
|
||||||
command. Read-only PipeWire queries use the host runtime socket; no status
|
|
||||||
control actions were sent. The native installed shell cross-check, without
|
|
||||||
instrumentation, measured 2.0% self CPU plus 8.8% waited-child CPU over ten
|
|
||||||
seconds. It is an older binary and a different scene, so this corroborates the
|
|
||||||
existence of subprocess overhead rather than providing an exact comparison.
|
|
||||||
|
|
||||||
The preview recorded 273 successful status command invocations across 21 polls:
|
|
||||||
13 per poll. The three login1 capability calls consumed 1.88 seconds total wall
|
|
||||||
time, about 90 ms/poll. Three nmcli queries consumed 1.35 seconds total; two wpctl
|
|
||||||
queries consumed 0.80 seconds. GNU time's hundredth-second granularity makes
|
|
||||||
per-command CPU totals unsuitable for precise attribution. Stable capability
|
|
||||||
queries, device metadata and frequently changing values currently share one
|
|
||||||
poll cycle. Separate refresh policies or service subscriptions deserve priority.
|
|
||||||
|
|
||||||
Settings mapped in 109 ms, measured from process launch until IPC reported it
|
|
||||||
focused (not first completed paint). Idle Settings RSS was 108068 KiB, with 38
|
|
||||||
threads and 65 descriptors. Zero measured CPU over six seconds means below this
|
|
||||||
sample's resolution, not a guarantee of zero work. Startup font enumeration was
|
|
||||||
not isolated separately. Settings interaction/search/page-switch profiling is
|
|
||||||
still outstanding.
|
|
||||||
|
|
||||||
Twenty `feresectl get-outputs` calls had median process-inclusive latency of
|
|
||||||
3.05 ms and maximum 3.95 ms. Five captures took 1.13 seconds total, including
|
|
||||||
client startup, transfer and PNG encoding. Capture was enabled only in the
|
|
||||||
isolated compositor with `FERESE_ENABLE_SCREENCOPY=1`. The first screenshot was
|
|
||||||
visually inspected and showed the shell and Settings rendered. It does not
|
|
||||||
measure GPU readback independently. Window maximize/fullscreen/layout toggles
|
|
||||||
completed, but there was no instrumented input-to-photon latency measurement.
|
|
||||||
|
|
||||||
The four-second visible overview perf recording (`cpu-clock:u`, 999 Hz) collected
|
|
||||||
471 samples with no lost samples. Shared-object attribution: 47.77% Ferese
|
|
||||||
executable (including statically linked dependencies), 30.36% Mesa Gallium,
|
|
||||||
14.23% libc, 2.97% Wayland client library. Approximately 96.4% of samples were in
|
|
||||||
the main compositor thread. Texture upload/memory-copy paths appear in the
|
|
||||||
sampled stacks. This is user-space CPU sampling, not GPU timing; short samples
|
|
||||||
and incomplete frame-pointer unwinding limit function-level attribution.
|
|
||||||
|
|
||||||
The earlier broad run (`/tmp/ferese-profile-all-boiq_r30`) had a 37-second render
|
|
||||||
reporting gap while hidden, no usable perf samples, and a disabled screencopy
|
|
||||||
protocol. Its render/overview and capture results are excluded. Its bare idle
|
|
||||||
sample was 1.0% CPU, but visibility differences preclude subtracting it from the
|
|
||||||
visible shell run.
|
|
||||||
|
|
||||||
Next priority: shell status subprocesses. Then investigate sustained overview
|
|
||||||
damage and texture uploads with controlled window visibility and dimensions.
|
|
||||||
Control-center interaction, widgets, translucent-material workloads, long-term
|
|
||||||
memory growth, new-build DRM and multi-monitor runs remain unprofiled. No source
|
|
||||||
changes or profiling-note commits were made during this profiling pass.
|
|
||||||
|
|
||||||
## Status-worker optimization comparison
|
|
||||||
|
|
||||||
Compared the production status module at `08a5866` with the new single-command
|
|
||||||
brightness reader and reusable native D-Bus connections. A standalone harness
|
|
||||||
started `Service::start(None)`, consumed updates every 250 ms, and ran for 20
|
|
||||||
seconds without a UI. Both variants used the same host runtime/services and
|
|
||||||
command timing wrapper. Artifacts: `/tmp/ferese-status-compare/`.
|
|
||||||
|
|
||||||
Both completed nine polls. Notifications were available in this comparison, so
|
|
||||||
the original worker launched 15 commands/poll and the new one launched 10:
|
|
||||||
135 versus 90 invocations. Four busctl launches and one brightnessctl launch per
|
|
||||||
poll were removed. When notifications are absent, the equivalent counts are
|
|
||||||
13 versus 8. Poll frequency, fresh capability queries and post-action generation
|
|
||||||
handling remain unchanged; no status-value caching was introduced.
|
|
||||||
|
|
||||||
GNU time measured total user+system CPU, including waited children: 2.41 seconds
|
|
||||||
before, 1.90 seconds after over 20.01 seconds each (about 21% lower in this single
|
|
||||||
comparison). Timing-wrapper overhead is included, so this is not a precise
|
|
||||||
uninstrumented CPU improvement estimate. Native D-Bus adds persistent sockets
|
|
||||||
and a runtime thread pool; UI samples observed roughly 26–28 shell threads and
|
|
||||||
48 descriptors versus roughly 18 threads and 42 descriptors previously.
|
|
||||||
|
|
||||||
One UI run showed a transient self-CPU spike; a subsequent perf recording
|
|
||||||
identified tiny-skia raster work rather than D-Bus queries among its hot paths.
|
|
||||||
The UI-free comparison avoids treating variable UI activity as polling cost.
|
|
||||||
|
|
||||||
Validation: workspace suite and explicit private-dbus-daemon test passed. The
|
|
||||||
private bus exercised live capability changes, yes/challenge/no/na handling,
|
|
||||||
notification-owner appearance/disappearance, error replies, missing methods,
|
|
||||||
and a reply delayed past the configured timeout. Brightness parser tests cover
|
|
||||||
rounding, zero brightness, invalid classes and malformed/nonfinite values.
|
|
||||||
|
|
||||||
### Push status delivery measurement (b0583eb)
|
|
||||||
|
|
||||||
Compared release binaries for 4bf0757 and b0583eb with the same nested compositor,
|
|
||||||
empty isolated config and a visible preview. Binary SHA-256 hashes differ and
|
|
||||||
were checked after forcing a shell rebuild to avoid shared-target artifact reuse.
|
|
||||||
No status-command timing wrappers were active. Discarded an initial baseline
|
|
||||||
that overlapped compilation. Retained after/before/after runs, each with three
|
|
||||||
10-second samples following a three-second startup settle. Artifacts and harness:
|
|
||||||
`/tmp/ferese-status-push-measure/` (`summary.json`, `ui.py`, `latency.rs`).
|
|
||||||
|
|
||||||
Shell CPU percentages of one core:
|
|
||||||
- Before: 1.5, 1.4, 1.6 (median 1.5).
|
|
||||||
- After run 1: 0.8, 1.1, 1.1.
|
|
||||||
- After run 2: 1.0, 1.1, 7.5 (combined after median 1.1).
|
|
||||||
|
|
||||||
The 7.5% sample coincided with a large damaged-pixel burst (44.3 million in a
|
|
||||||
five-second interval), higher RSS and two additional descriptors. Its cause was
|
|
||||||
not isolated; it is retained, not silently excluded. Combined after mean is
|
|
||||||
2.1%, versus 1.5% before, so these short runs do not establish a robust average
|
|
||||||
CPU saving. Typical steady-state samples suggest a 0.4 percentage-point reduction.
|
|
||||||
Status child CPU remained roughly 6–8% of one core, dominating shell self CPU.
|
|
||||||
|
|
||||||
Steady-state damaged frames were about 12/s before versus 6.6–7.6/s in the first
|
|
||||||
after run. The repeat had similar quiet intervals plus bursts at 15.6 and 22.7/s.
|
|
||||||
Total render attempts stayed around 60/s, confirming active rather than hidden
|
|
||||||
preview sampling. No claim is made about DRM-session CPU or total idle wakeups.
|
|
||||||
|
|
||||||
An isolated transport harness used the old bounded mpsc + 250ms polling path and
|
|
||||||
an extracted copy of the new Updates::stream implementation, with 40 synthetic
|
|
||||||
updates per path at 317ms intervals. Worker-to-consumer delay:
|
|
||||||
- Before: median 129.398ms, p95 239.957ms, maximum 245.881ms.
|
|
||||||
- After: median 0.130ms, p95 0.330ms, maximum 0.425ms.
|
|
||||||
This measures delivery only, excluding status queries, UI dispatch and painting.
|
|
||||||
The preview processes exited and the temporary source worktree was removed.
|
|
||||||
+45
-159
@@ -1,174 +1,60 @@
|
|||||||
# Desktop portals
|
# Desktop portals
|
||||||
|
|
||||||
Applications call the standard `org.freedesktop.portal.Desktop` frontend. Ferese's
|
Desktop portals let applications request screen sharing, screenshots, wallpaper
|
||||||
native backend implements desktop integration; GTK remains the fallback for
|
changes, and other desktop services. Ferese provides themed consent dialogs;
|
||||||
standard file, print and application dialogs. Install both backends.
|
GTK supplies file, print, and other standard dialogs.
|
||||||
|
|
||||||
## Native services
|
Install `xdg-desktop-portal`, `xdg-desktop-portal-gtk`, and Ferese's backend through
|
||||||
|
[Installation](installation.md). The session launcher starts the services with
|
||||||
|
the correct display environment.
|
||||||
|
|
||||||
- **Settings:** Ferese's color scheme, accent color, contrast preference and
|
## Supported services
|
||||||
reduced-motion setting. Changes are signalled after valid KDL appearance
|
|
||||||
changes; malformed saves leave the last valid preferences intact.
|
|
||||||
- **Screenshot:** screen, selected-area, selected-window and active-window PNG
|
|
||||||
captures, plus a screen color picker. Window captures render the selected
|
|
||||||
toplevel and its subsurfaces in isolation, preserving transparency; occluding
|
|
||||||
windows, separate popups, shell layers and compositor borders are excluded.
|
|
||||||
The native window picker lists window titles and application IDs. Every capture
|
|
||||||
asks for consent. Interactive requests offer area selection; area and color
|
|
||||||
selection use `slurp`. Captures use Ferese's bounded screenshot IPC.
|
|
||||||
The helper must disappear from the compositor before capture starts.
|
|
||||||
- **Wallpaper:** a preview and confirmation, then an atomic configuration update.
|
|
||||||
Desktop and lock-screen wallpaper can be set independently, or together.
|
|
||||||
Ferese copies accepted local images into its own private data directory so
|
|
||||||
temporary portal files can disappear safely. Image bytes and decoded dimensions
|
|
||||||
are bounded. `theme.background.lock-path` overrides the lock-screen image;
|
|
||||||
without it the lock screen follows `theme.background.path`.
|
|
||||||
- **Background:** native open-window/app state, change signals and per-instance
|
|
||||||
background consent. Legacy autostart requests create managed XDG desktop entries;
|
|
||||||
current frontends manage those files themselves. Direct sessions launch standard
|
|
||||||
XDG autostart entries after importing the display environment. User overrides,
|
|
||||||
Hidden, OnlyShowIn, NotShowIn and TryExec are respected; previews skip autostart.
|
|
||||||
- **Lockdown:** standard printing, save-to-disk, application-handler, location,
|
|
||||||
camera, microphone and sound-output restrictions. All default to unrestricted.
|
|
||||||
Configure boolean `disable-*` fields under `portals { lockdown { ... } }`;
|
|
||||||
changes are signalled to the frontend. Invalid policy types retain the current
|
|
||||||
policy. Only the portal frontend may write backend policy properties.
|
|
||||||
- **USB:** native confirmation showing device vendor/model and requested read-only
|
|
||||||
or read/write access. The portal frontend handles device enumeration and opening.
|
|
||||||
- **GlobalShortcuts:** session-scoped keyboard shortcuts with native trigger
|
|
||||||
selection, conflict checking, activation/release signals and reconfiguration.
|
|
||||||
Applications cannot replace Ferese bindings or reserved escape/VT shortcuts.
|
|
||||||
Closing a session or losing its compositor connection releases its shortcuts;
|
|
||||||
shortcuts do not activate on the lock screen. Saved choices are offered for
|
|
||||||
future sessions, with explicit approval before registering them.
|
|
||||||
- **Inhibit:** connection-scoped logout, suspend and idle inhibitors, backed by
|
|
||||||
logind descriptors and compositor idle inhibition. Native session monitors
|
|
||||||
report lock state and Running/QueryEnd/Ending transitions. Ending queries wait
|
|
||||||
for acknowledgements for up to one second. Power confirmations list blockers
|
|
||||||
and recheck them before acting; authentication failure cancels the query.
|
|
||||||
UserSwitch is recorded, but Ferese currently has no user-switch operation.
|
|
||||||
- **InputCapture:** approved keyboard and pointer capture over a private EIS
|
|
||||||
connection, with standard screen zones and pointer barriers on outside display
|
|
||||||
edges. Capture begins at a configured barrier; releasing it restores local
|
|
||||||
input. Ctrl+Alt+Escape returns control immediately. Locking, topology/keymap
|
|
||||||
changes, receiver disconnects and stalled consumers stop capture. Permission
|
|
||||||
is requested for every session; touch capture and remembered grants are not
|
|
||||||
offered. This is an input receiver, not remote input injection.
|
|
||||||
- **ScreenCast:** monitor and isolated window sharing with a native picker, PipeWire streams and explicit opt-in
|
|
||||||
saved permissions. The frontend stores and revokes saved choices. Invalid
|
|
||||||
restore data or changed display identity requires fresh consent.
|
|
||||||
See [screen sharing](screen-sharing.md) for lifetime and recording details.
|
|
||||||
|
|
||||||
Native request dialogs use Ferese's theme and are floating windows. Screenshot,
|
| Service | Behavior |
|
||||||
PickColor, Wallpaper, USB, InputCapture and ScreenCast consent dialogs use Wayland parent identifiers to establish
|
|
||||||
a transient relationship with the requesting window.
|
|
||||||
Cancelling a request or losing the portal frontend terminates its pending helper.
|
|
||||||
|
|
||||||
The packaged `ferese-portals.conf` selects these interfaces explicitly. Existing
|
|
||||||
user overrides in `~/.config/xdg-desktop-portal/` may take precedence. Install the
|
|
||||||
new compositor, backend and preference files together; screenshot synchronization
|
|
||||||
requires the updated compositor IPC.
|
|
||||||
|
|
||||||
## GNOME compatibility audit
|
|
||||||
|
|
||||||
The audit compares the [GNOME backend's registered interfaces](https://github.com/GNOME/xdg-desktop-portal-gnome/blob/main/data/meson.build)
|
|
||||||
with the [standard backend D-Bus contracts](https://flatpak.github.io/xdg-desktop-portal/docs/impl-dbus-interfaces.html).
|
|
||||||
Matching D-Bus signatures does not establish complete feature parity.
|
|
||||||
|
|
||||||
| Interface | Ferese integration |
|
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Settings | Native, including appearance change signals |
|
| Settings | Color scheme, accent, contrast, and reduced-motion preferences |
|
||||||
| Screenshot | Native screen/area/window/active-window capture and PickColor |
|
| Screenshot | Screen, area, window, active-window capture, and color picking |
|
||||||
| Wallpaper | Native desktop, lock-screen and combined targets |
|
| Wallpaper | Preview and approval for desktop, lock screen, or both |
|
||||||
| ScreenCast | Native v4 monitors and isolated windows, logical geometry, live window resizing and opt-in saved display permissions |
|
| ScreenCast | Display and window sharing through PipeWire |
|
||||||
| Access, Account, AppChooser, DynamicLauncher, FileChooser, Notification, Print | Delegated to GTK |
|
| Background | Permission to run in the background and startup integration |
|
||||||
| Background | Native application state, per-instance consent and XDG autostart |
|
| USB | Device information and approval for requested access |
|
||||||
| Usb | Native consent; standard frontend handles enumeration and device descriptors |
|
| GlobalShortcuts | App shortcut selection, conflict checks, and activation |
|
||||||
| GlobalShortcuts | Native sessions, configurable keyboard triggers, conflict checks and activation/release signals |
|
| Inhibit | App requests to delay logout, suspend, or idle actions |
|
||||||
| RemoteDesktop | Deferred: authorized input injection and EIS transport |
|
| InputCapture | Approved keyboard/pointer capture for input-sharing applications |
|
||||||
| Clipboard | Deferred with RemoteDesktop |
|
| Lockdown | Administrator restrictions on printing, saving, handlers, location, camera, microphone, and sound |
|
||||||
| InputCapture | Native v2 keyboard/pointer consent, zones, outside-edge barriers and private EIS receiver transport |
|
| FileChooser, Print, Access, Account, AppChooser, DynamicLauncher, Notification | GTK backend |
|
||||||
| Lockdown | Native seven-property policy provider with persisted configuration and change signals |
|
|
||||||
| Inhibit | Native inhibitors and session monitors; UserSwitch recorded until a switch operation exists |
|
|
||||||
|
|
||||||
The frontend supplies additional APIs such as OpenURI, network monitoring,
|
RemoteDesktop and its session Clipboard integration are not implemented.
|
||||||
document export and permission storage. Adding a similarly named backend service
|
This does not affect ordinary application clipboard use.
|
||||||
is neither required nor sufficient for those APIs.
|
|
||||||
|
|
||||||
Window streams render only the selected toplevel and its subsurfaces, including
|
## Consent and capture
|
||||||
on an inactive workspace. Overlapping apps, shell layers, separate popup windows
|
|
||||||
and compositor decorations are excluded. The private capture protocol is available
|
|
||||||
only to the native portal executable and checks session opt-in and locking.
|
|
||||||
Window resizing renegotiates PipeWire video dimensions. Closing the selected
|
|
||||||
window ends sharing; its lifetime ID cannot select a replacement app. Window
|
|
||||||
selections require fresh consent and are not saved as display permissions.
|
|
||||||
RemoteDesktop and its Clipboard integration remain deferred.
|
|
||||||
|
|
||||||
## Validation
|
Screenshot and screen-sharing requests ask for approval. Screen sharing can
|
||||||
|
remember display permissions when the application requests it and the user opts
|
||||||
|
in. Window sharing always asks again. See [Screen sharing](screen-sharing.md).
|
||||||
|
Window captures contain the selected app and its subsurfaces; separate popups,
|
||||||
|
other apps, shell layers, and compositor decorations are excluded.
|
||||||
|
|
||||||
Build the backend and run unit tests, then check its contracts on a private bus:
|
InputCapture starts at an approved display-edge barrier. **Ctrl+Alt+Escape**
|
||||||
|
returns local control. Locking, disconnecting the receiver, or changing displays
|
||||||
|
or the keyboard layout stops capture. Touch and remembered InputCapture grants
|
||||||
|
are not supported. InputCapture forwards local input; it does not inject remote input.
|
||||||
|
|
||||||
```sh
|
Wallpaper approval copies the image into Ferese's data directory and updates the
|
||||||
cargo build --locked -p xdg-desktop-portal-ferese
|
config. Set `theme.background.lock-path` for a separate lock-screen image; otherwise
|
||||||
cargo test --locked -p xdg-desktop-portal-ferese
|
it follows the desktop wallpaper.
|
||||||
python3 scripts/tests/test_portal_contracts.py
|
|
||||||
```
|
|
||||||
|
|
||||||
With a Wayland host and a built compositor, check shortcut connection cleanup
|
Global shortcuts cannot replace Ferese bindings or reserved escape/console keys.
|
||||||
and configuration conflicts in an isolated nested compositor:
|
They stop when the app session closes and never activate on the lock screen.
|
||||||
|
Power confirmations show app inhibitors before proceeding. Ferese has no
|
||||||
|
user-switch operation.
|
||||||
|
|
||||||
```sh
|
## Portal selection
|
||||||
FERESE_TEST_SHORTCUTS=1 python3 scripts/tests/test_shortcuts_isolated.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Check window capture isolation, transparency and orientation with overlapping
|
The installer writes `/usr/share/xdg-desktop-portal/ferese-portals.conf`.
|
||||||
clients in a temporary nested compositor:
|
Overrides in `~/.config/xdg-desktop-portal/` may take precedence. If a request opens
|
||||||
|
the wrong dialog or no source appears, check those overrides and confirm that
|
||||||
|
`XDG_CURRENT_DESKTOP` includes `Ferese`.
|
||||||
|
|
||||||
```sh
|
For capture issues, see [screen-sharing troubleshooting](screen-sharing.md#troubleshooting).
|
||||||
FERESE_TEST_WINDOW_CAPTURE=1 python3 scripts/tests/test_window_capture_isolated.py
|
For backend contracts and integration checks, see [Development](development.md#portal-checks).
|
||||||
```
|
|
||||||
|
|
||||||
Capture a managed window directly from the CLI with `feresectl screenshot-window
|
|
||||||
<window-id> > capture.png`; `feresectl get-windows` lists IDs.
|
|
||||||
|
|
||||||
The contract test compares introspection against the installed official backend
|
|
||||||
XML, verifies appearance changes and invalid-save retention, and checks that
|
|
||||||
sensitive methods reject callers outside the portal frontend. It does not open
|
|
||||||
consent dialogs or capture the host desktop. Interactive consent, fractional-scale
|
|
||||||
capture, polkit and hotplug still require a live session test.
|
|
||||||
|
|
||||||
Check native inhibitor lifetimes, acknowledgement generations and session-ending
|
|
||||||
transitions against a mock logind in an isolated nested compositor:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
FERESE_TEST_INHIBIT=1 python3 scripts/tests/test_inhibit_isolated.py
|
|
||||||
```
|
|
||||||
|
|
||||||
The shell now requires version 4 of Ferese's shell protocol; rebuild the shell
|
|
||||||
and compositor together when upgrading.
|
|
||||||
|
|
||||||
Check restored sharing, mode downgrade, stale-data fallback, output-generation
|
|
||||||
validation and frontend-disconnect cleanup with synthetic monitor identities on
|
|
||||||
an isolated bus and nested compositor:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
FERESE_TEST_RESTORE=1 python3 scripts/tests/test_restore_isolated.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Check live window pixels, overlap isolation, inactive workspaces, resizing and
|
|
||||||
closure using a disposable nested compositor and a real PipeWire consumer:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
FERESE_TEST_WINDOW_STREAM=1 python3 scripts/tests/test_window_stream_isolated.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Check InputCapture state and its transport against an installed libei receiver:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo test --locked -p ferese input_capture::tests
|
|
||||||
cargo test --locked -p xdg-desktop-portal-ferese eis::tests -- --ignored
|
|
||||||
```
|
|
||||||
|
|
||||||
The receiver test uses a private socket pair and synthetic input; it never
|
|
||||||
captures the host keyboard or changes host focus. Real pointer-barrier crossings
|
|
||||||
and interactive consent still need a live session check.
|
|
||||||
+50
-120
@@ -1,142 +1,73 @@
|
|||||||
# Screen sharing and recording
|
# Screen sharing and recording
|
||||||
|
|
||||||
Ferese includes a ScreenCast portal backend, `xdg-desktop-portal-ferese`.
|
Share a monitor or window from a Wayland-compatible recording or conferencing app,
|
||||||
Applications use the standard desktop portal to request a display or window, then receive
|
or save a video using the top bar. [Installation](installation.md) includes the
|
||||||
video through PipeWire. A recorder or conferencing application handles encoding,
|
portal and PipeWire dependencies.
|
||||||
saving files, or sending video; those tasks do not run inside the compositor.
|
|
||||||
|
|
||||||
## Record from the top bar
|
## Record from the top bar
|
||||||
|
|
||||||
1. Click the screen-recording icon in the top bar to open the display picker.
|
1. Click the recording icon.
|
||||||
2. Choose a monitor in the native picker and click **Share**.
|
2. Select a monitor and click **Share**.
|
||||||
3. The icon changes to a stop square and shows elapsed time. Click it to stop.
|
3. Click the stop square to finish.
|
||||||
|
|
||||||
The recorder finishes the video before sending a notification with its saved
|
Videos are saved as VP8 WebM files in your XDG Videos folder under `Ferese`.
|
||||||
path. Videos are saved as VP8 WebM files under
|
A notification shows the saved path. Audio and region recording are not supported
|
||||||
`Videos/Ferese` (using your configured XDG Videos folder). Audio is off.
|
by the built-in recorder; other recording apps can handle audio separately.
|
||||||
The icon uses the same theme accent, hover effect, and corner radius as the
|
If recording fails, a notification reports the error and any unfinished
|
||||||
other bar controls.
|
`.webm.part` file.
|
||||||
|
|
||||||
Encoding runs in a separate native `ferese-record` process using GStreamer.
|
|
||||||
The shell remains responsive while a file is recorded or finalized. If saving
|
|
||||||
fails, an error appears in the notification center; an unfinished `.webm.part` file
|
|
||||||
may remain at the path shown in the error.
|
|
||||||
|
|
||||||
## Start sharing
|
## Start sharing
|
||||||
|
|
||||||
Use a Wayland screen-sharing or recording source in your application. Ferese
|
Select a Wayland screen-sharing source in your application. In Ferese's picker,
|
||||||
opens a native source picker. Depending on what the application requests, choose
|
choose a display or window and click **Share**. Nothing is selected initially.
|
||||||
from displays, windows, or both and press **Share**. Nothing is selected by default.
|
Apps requesting multiple sources can select up to eight.
|
||||||
Applications that request multiple sources can select up to eight. Display and
|
|
||||||
window choices are grouped separately. Windows show their title and application.
|
|
||||||
Window streams capture only the selected app's toplevel and subsurfaces, even
|
|
||||||
when covered or on another workspace. Separate popups and compositor decorations
|
|
||||||
are excluded. Resizing a shared window updates the video size without ending the
|
|
||||||
session. Closing that window ends sharing.
|
|
||||||
The picker uses your Ferese theme colors, font, and shell corner radius. Its
|
|
||||||
background uses the same compositor material as popovers and authentication
|
|
||||||
prompts: opaque in solid mode, or blurred and translucent using the shared
|
|
||||||
**Appearance → Shell opacity** and blur settings. Text and icons remain opaque.
|
|
||||||
|
|
||||||
Other applications keep a **screen sharing** window with a **Stop sharing** button.
|
A shared display includes everything visible on it, including notifications.
|
||||||
Ferese’s built-in recorder uses the top-bar stop control instead, leaving your
|
A shared window includes only that app's content and subsurfaces, even when
|
||||||
windows accessible after display selection. The command-line recorder keeps the
|
covered or on another workspace. Separate popups and compositor decorations are
|
||||||
sharing window when it is not launched by the shell. Press **Stop sharing** or
|
excluded. Resizing a shared window updates its video size; closing it ends sharing.
|
||||||
close the sharing window to revoke an ordinary application’s session. Closing the requesting application,
|
|
||||||
locking Ferese, disconnecting the selected display, or changing a monitor's capture
|
|
||||||
size also ends sharing. By default, each request asks for consent. If an application requests saved
|
|
||||||
permissions, the picker offers an **Allow without asking** switch, off by default.
|
|
||||||
Permissions can last while the application runs or until revoked, as requested
|
|
||||||
by the app. The standard portal frontend owns permission storage and revocation.
|
|
||||||
A changed or missing display, different app, or changed cursor options asks again.
|
|
||||||
Displays without a reliable EDID identity, including nested previews, always need
|
|
||||||
fresh consent. Window selections also require fresh consent and cannot enable saved
|
|
||||||
display permissions. Stopping a stream ends that stream; it does not erase a previously
|
|
||||||
saved permission.
|
|
||||||
Everything visible on a shared display, including notifications, is included.
|
|
||||||
|
|
||||||
## Installation
|
The picker follows your shell colors, font, corners, opacity, and blur.
|
||||||
|
|
||||||
The [standard installer](installation.md) builds and installs the backend, its
|
## Stop sharing
|
||||||
D-Bus activation entry, and a Ferese-specific portal preference file. Install
|
|
||||||
`pipewire`, a PipeWire session manager such as `wireplumber`,
|
|
||||||
`xdg-desktop-portal`, and `xdg-desktop-portal-gtk` using your distribution's package
|
|
||||||
manager. The GTK backend supplies standard dialogs such as file selection. Ferese also
|
|
||||||
provides native Settings, Screenshot and Wallpaper services; see
|
|
||||||
[desktop portals](portals.md).
|
|
||||||
The built-in recorder also needs GStreamer’s PipeWire, base, and good plugins
|
|
||||||
(`pipewiresrc`, `videoconvert`, `vp8enc`, and `webmmux`). The installation guide
|
|
||||||
includes these packages.
|
|
||||||
|
|
||||||
Log into a new Ferese session after installation. The session launcher imports
|
Click **Stop sharing** in the sharing window, or close that window. The built-in
|
||||||
its Wayland display into the D-Bus activation environment. Nested previews leave
|
recorder uses the top-bar stop button instead. Sharing also ends when the app
|
||||||
the host activation environment alone.
|
closes or Ferese locks. Disconnecting a shared monitor or changing its capture
|
||||||
|
size ends its stream; start sharing again afterward.
|
||||||
|
|
||||||
Existing custom window rules can float the picker and sharing indicator:
|
## Remember permissions
|
||||||
|
|
||||||
```kdl
|
When an app requests saved display permissions, the picker offers **Allow without
|
||||||
window-rule app-id="dev.ferese.ScreenShare" floating=#true
|
asking**, off by default. Approval lasts for the duration requested by the app.
|
||||||
```
|
The portal manages stored permissions and revocation.
|
||||||
|
|
||||||
The packaged example configuration already includes this rule. Existing user
|
A different app, changed display, or changed cursor option needs approval again.
|
||||||
configuration is preserved during installation.
|
Nested previews and displays without a reliable identity always ask. Window
|
||||||
|
permissions are not saved. Stopping a stream does not erase a saved permission.
|
||||||
|
|
||||||
## Current capabilities
|
## Requirements and limits
|
||||||
|
|
||||||
- Monitor and isolated window capture, one PipeWire stream per source, up to 30 fps.
|
Install PipeWire, WirePlumber, `xdg-desktop-portal`, and `xdg-desktop-portal-gtk`.
|
||||||
- Window streams keep working across workspace switches and renegotiate on resize.
|
The built-in recorder also needs GStreamer's PipeWire, base, and good plugins;
|
||||||
- Hidden or embedded pointer, as requested by the application.
|
see the [package lists](installation.md#requirements).
|
||||||
- Logical stream position and size, including fractional output scales.
|
|
||||||
- Wayland parent-window relationships for the consent picker.
|
|
||||||
- Bounded frame storage and reusable shared-memory buffers.
|
|
||||||
- Cancellation during selection, an explicit stop control, and process cleanup.
|
|
||||||
- ScreenCast backend version 4 with explicit opt-in saved display permissions.
|
|
||||||
|
|
||||||
Region selection and audio capture in Ferese’s recorder are not implemented yet.
|
The installer supplies Ferese's portal backend and selects it for screen sharing.
|
||||||
The top-bar recorder currently requests monitors. Other recording applications can handle audio separately.
|
Log into a new Ferese session after installation.
|
||||||
Video currently uses CPU copies through the compositor's shared-memory screencopy path, not DMA-BUF zero-copy. High-resolution
|
|
||||||
or multiple-display recording can therefore use significant CPU and memory
|
|
||||||
bandwidth. A paused stream checks capture availability once per second so locking
|
|
||||||
also ends sessions without an active consumer.
|
|
||||||
|
|
||||||
## Development checks
|
Streams run at up to 30 fps and support hidden or embedded cursors. Capture copies
|
||||||
|
frames through CPU-accessible buffers, so large or multiple streams can use
|
||||||
Build the backend after installing the native dependencies in the
|
substantial CPU and memory bandwidth.
|
||||||
[installation guide](installation.md#requirements):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo build --release --locked -p xdg-desktop-portal-ferese
|
|
||||||
cargo test --locked -p xdg-desktop-portal-ferese
|
|
||||||
# Exercise real video encoding and playback (requires the plugins above):
|
|
||||||
cargo test --locked -p xdg-desktop-portal-ferese --bin ferese-record encoder_finishes_a_real_webm -- --ignored
|
|
||||||
```
|
|
||||||
|
|
||||||
The opt-in integration test opens a temporary nested compositor and uses a
|
|
||||||
private D-Bus session. It requires built Ferese and locker binaries, Python
|
|
||||||
GI/GStreamer with `pipewiresrc`, `dbus-daemon`, `xdg-desktop-portal`, and `bwrap`.
|
|
||||||
It checks capture delivery and timestamps, cancellation, frontend loss, and lock
|
|
||||||
revocation:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
FERESE_TEST_PORTAL=1 \
|
|
||||||
FERESE_TEST_PORTAL_BINARY=target/release/xdg-desktop-portal-ferese \
|
|
||||||
python3 scripts/tests/test_portal_isolated.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Add `FERESE_TEST_PORTAL_CONSENT=1` to exercise the native picker and restricted
|
|
||||||
PipeWire connection. Select the temporary display and click **Share** when
|
|
||||||
prompted. Tests capture only the nested preview and leave host PAM policies and
|
|
||||||
D-Bus activation unchanged.
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
Confirm that `XDG_CURRENT_DESKTOP` contains `Ferese`, PipeWire is running, and
|
- Confirm PipeWire and WirePlumber are running.
|
||||||
`FERESE_ENABLE_SCREENCOPY` was not set to `0` before launching the session.
|
- Confirm `XDG_CURRENT_DESKTOP` includes `Ferese`.
|
||||||
|
- Check that `FERESE_ENABLE_SCREENCOPY` was not set to `0` before session startup.
|
||||||
|
- Check for portal overrides in `~/.config/xdg-desktop-portal/`.
|
||||||
|
|
||||||
The installed preference is
|
The installed preference is `/usr/share/xdg-desktop-portal/ferese-portals.conf`.
|
||||||
`/usr/share/xdg-desktop-portal/ferese-portals.conf`. A user override under
|
Its ScreenCast entry should select Ferese:
|
||||||
`~/.config/xdg-desktop-portal/` can take precedence. Its ScreenCast preference
|
|
||||||
should name `ferese`:
|
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[preferred]
|
[preferred]
|
||||||
@@ -144,8 +75,7 @@ default=gtk;
|
|||||||
org.freedesktop.impl.portal.ScreenCast=ferese;
|
org.freedesktop.impl.portal.ScreenCast=ferese;
|
||||||
```
|
```
|
||||||
|
|
||||||
If capture dimensions change, stop and start sharing again. Ferese ends the old
|
`xdg-desktop-portal-ferese --sources` lists displays on the current
|
||||||
session instead of feeding incorrectly sized frames to the application.
|
`WAYLAND_DISPLAY` without starting a stream. Nested previews do not replace the
|
||||||
|
host desktop's portal environment. See [Development](development.md#portal-checks)
|
||||||
For development, `xdg-desktop-portal-ferese --sources` lists displays available
|
for isolated sharing tests.
|
||||||
on the current `WAYLAND_DISPLAY`. This command does not start a stream.
|
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# Shortcuts and gestures
|
||||||
|
|
||||||
|
`Super` is usually the Windows key. These are the built-in defaults. Open
|
||||||
|
**Settings → Shortcuts** to change bindings and gestures or disable the login
|
||||||
|
guide. Your saved bindings can override these defaults.
|
||||||
|
|
||||||
|
## Move and resize with the mouse
|
||||||
|
|
||||||
|
| Action | Result |
|
||||||
|
| --- | --- |
|
||||||
|
| Super + left-button drag on a floating window | Move the window |
|
||||||
|
| Super + right-button drag on a floating window | Resize from the nearest corner |
|
||||||
|
| Super + Shift + Space | Switch the focused window between tiled and floating |
|
||||||
|
|
||||||
|
You can drag from inside the window; a title bar or resize border is not required.
|
||||||
|
To place an app freely, toggle it to floating, then Super-drag it.
|
||||||
|
|
||||||
|
## Focus, move, and resize
|
||||||
|
|
||||||
|
`H`, `J`, `K`, and `L` mean left, down, up, and right.
|
||||||
|
|
||||||
|
| Shortcut | Action |
|
||||||
|
| --- | --- |
|
||||||
|
| Super + H / J / K / L | Focus in that direction |
|
||||||
|
| Super + Shift + H / J / K / L | Move the focused window in that direction |
|
||||||
|
| Super + Ctrl + H / J / K / L | Resize in that direction |
|
||||||
|
| Super + Q | Close the focused window |
|
||||||
|
| Super + F | Maximize or restore the window |
|
||||||
|
| Super + Shift + F | Enter or leave fullscreen |
|
||||||
|
|
||||||
|
Maximize fills the available workspace. Fullscreen also hides the bar and window
|
||||||
|
decorations.
|
||||||
|
|
||||||
|
## Columns and layouts
|
||||||
|
|
||||||
|
| Shortcut | Action |
|
||||||
|
| --- | --- |
|
||||||
|
| Super + R | Cycle column width |
|
||||||
|
| Super + C | Center the focused column |
|
||||||
|
| Super + [ | Place the window in a neighbouring column |
|
||||||
|
| Super + ] | Extract the window into its own column |
|
||||||
|
| Super + M | Switch scrolling / tree layout |
|
||||||
|
| Super + Tab | Open or close overview |
|
||||||
|
|
||||||
|
In scrolling mode, **Super + [** uses the left neighbour when available, otherwise
|
||||||
|
the right. Try it with two terminals to place them vertically in one column.
|
||||||
|
**Super + ]** separates the focused window again.
|
||||||
|
|
||||||
|
In overview, select a workspace to see its windows, then click the window you
|
||||||
|
want. Directional focus keys move selection; Enter activates it and Escape closes
|
||||||
|
overview.
|
||||||
|
|
||||||
|
## Workspaces
|
||||||
|
|
||||||
|
| Shortcut | Action |
|
||||||
|
| --- | --- |
|
||||||
|
| Super + 1–9 | Switch to that workspace |
|
||||||
|
| Super + Shift + 1–9 | Move the window to that workspace |
|
||||||
|
|
||||||
|
Workspaces are created as needed. Selecting one visible on another monitor focuses
|
||||||
|
that monitor.
|
||||||
|
|
||||||
|
## Desktop actions
|
||||||
|
|
||||||
|
| Shortcut | Action |
|
||||||
|
| --- | --- |
|
||||||
|
| Super + Enter | Open the configured terminal (`foot` by default) |
|
||||||
|
| Print Screen | Capture the active monitor and open Satty |
|
||||||
|
| Super + Shift + S | Select a screenshot area and open Satty |
|
||||||
|
| Super + Shift + E | Ask to log out |
|
||||||
|
|
||||||
|
In Satty, Enter saves the edited screenshot and copies it to the clipboard;
|
||||||
|
Escape discards it. See [Configuration](configuration.md#commands-and-bindings)
|
||||||
|
for dependencies and custom screenshot commands.
|
||||||
|
|
||||||
|
## Touchpad gestures
|
||||||
|
|
||||||
|
| Three-finger swipe | Action on release |
|
||||||
|
| --- | --- |
|
||||||
|
| Up / down | Next / previous workspace on this monitor |
|
||||||
|
| Left / right | Focus the window to the right / left |
|
||||||
|
|
||||||
|
Short, diagonal, or cancelled swipes do nothing. Gestures can use the same actions
|
||||||
|
as keyboard bindings, including overview or moving a window. Four- and five-finger
|
||||||
|
bindings are supported too.
|
||||||
|
|
||||||
|
## Add a shortcut
|
||||||
|
|
||||||
|
For example, bind a lock command and use a swipe to open overview:
|
||||||
|
|
||||||
|
```kdl
|
||||||
|
commands {
|
||||||
|
lock "ferese-lock"
|
||||||
|
}
|
||||||
|
binding "Super+Alt+L" "spawn" "lock"
|
||||||
|
binding "Swipe3Up" "toggle-overview"
|
||||||
|
```
|
||||||
|
|
||||||
|
These are examples, not defaults. To disable a built-in binding:
|
||||||
|
|
||||||
|
```kdl
|
||||||
|
binding "Super+Q" disabled=#true
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Commands and bindings](configuration.md#commands-and-bindings) for action
|
||||||
|
names, arguments, and physical-key matching.
|
||||||
+16
-60
@@ -1,34 +1,26 @@
|
|||||||
# Why Ferese
|
# Why Ferese
|
||||||
|
|
||||||
Omarchy and Ferese come from two different ideas about how a desktop should be
|
Ferese combines window management and a desktop shell with one configuration.
|
||||||
built. Omarchy brings existing Linux tools together and configures them as one
|
Settings, the bar, notifications, widgets, authentication prompts, and the lock
|
||||||
environment, which gives it access to mature components that already do their
|
screen share colors and fonts.
|
||||||
jobs well.
|
|
||||||
|
|
||||||
A setup like that might combine:
|
## Choose how windows fit
|
||||||
|
|
||||||
```text
|
Scrolling columns let you keep windows at useful widths and move through them
|
||||||
Hyprland + bar + launcher + notifications + lock screen + theme scripts
|
horizontally. Tree tiling divides the screen into nested splits. Floating windows
|
||||||
```
|
work alongside either layout, and overview shows windows across workspaces.
|
||||||
|
|
||||||
There is nothing wrong with this approach, and being able to replace each part
|

|
||||||
is useful, but those parts still have their own configuration, state, rendering,
|
|
||||||
and lifecycle. Matching their themes can make them look related, while keeping
|
|
||||||
their behavior in sync remains an ongoing part of maintaining the desktop.
|
|
||||||
|
|
||||||
With Ferese, we are building the compositor and shell together, so workspaces,
|
## Change the desktop together
|
||||||
layout, focus, outputs, input, and materials all come from the same desktop
|
|
||||||
state. The shell and Settings use first-party interfaces to work with that state
|
|
||||||
instead of reading separate versions of it from several external tools.
|
|
||||||
|
|
||||||
This does not mean every Ferese component has to run in one process. It means
|
Choose a theme in Settings, then adjust the wallpaper, colors, font, corners,
|
||||||
that the components share the same concepts, configuration, and protocols, so a
|
and motion. Changes apply live. Window corners and shell corners can be set
|
||||||
workspace or surface means the same thing everywhere it appears.
|
independently.
|
||||||
|
|
||||||
## What this means in practice
|

|
||||||
|
|
||||||
You can see the difference in something as simple as corner radius. Ferese has a
|
For example, this changes shell corners:
|
||||||
shared setting for shell surfaces:
|
|
||||||
|
|
||||||
```kdl
|
```kdl
|
||||||
theme {
|
theme {
|
||||||
@@ -38,41 +30,5 @@ theme {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Changing that value updates the bar, Control Center, popovers, notifications,
|
See [Configuration](configuration.md) for all options, or
|
||||||
widgets, and native lock screen together. Managed windows have their own radius
|
[Installation](installation.md) to try Ferese in a nested preview.
|
||||||
because they are a different kind of surface, but each value still has one clear
|
|
||||||
meaning wherever it is used.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
In an assembled desktop, making the same visual change may mean editing the
|
|
||||||
window manager, bar CSS, launcher theme, notification daemon, and lock screen
|
|
||||||
config separately, then keeping those values aligned as the setup changes.
|
|
||||||
|
|
||||||
The same difference shows up in how the desktop behaves. Ferese implements
|
|
||||||
scrolling as part of its workspace model, renders blur behind shell surfaces in
|
|
||||||
the compositor, and builds the overview from the real window scene. Focus,
|
|
||||||
fullscreen, workspace geometry, and input all work from the same state rather
|
|
||||||
than waiting for separate tools to catch up with one another.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
When a window opens, Ferese can handle the result as one transition:
|
|
||||||
|
|
||||||
```text
|
|
||||||
window opens → layout updates → viewport moves → input follows
|
|
||||||
```
|
|
||||||
|
|
||||||
An assembled environment may need to publish a window-manager event, pass it
|
|
||||||
through IPC, run a script, update the bar, and start another animation before
|
|
||||||
the rest of the desktop reflects the change. Each step can be fast, but it is
|
|
||||||
still another boundary that has to be maintained.
|
|
||||||
|
|
||||||
## The tradeoff we are making
|
|
||||||
|
|
||||||
Building more of the desktop ourselves gives Ferese tighter control over how its
|
|
||||||
parts work together, but it also leaves us responsible for more code. Omarchy
|
|
||||||
can rely on mature components from across the Linux desktop ecosystem, while
|
|
||||||
Ferese has to build that same level of maturity over time, and that is a tradeoff
|
|
||||||
we are willing to make to keep the desktop consistent in both behavior and
|
|
||||||
configuration.
|
|
||||||
@@ -16,10 +16,13 @@ PAGES = [
|
|||||||
('why-ferese', 'Why Ferese', ROOT / 'docs/why-ferese.md'),
|
('why-ferese', 'Why Ferese', ROOT / 'docs/why-ferese.md'),
|
||||||
('installation', 'Installation', ROOT / 'docs/installation.md'),
|
('installation', 'Installation', ROOT / 'docs/installation.md'),
|
||||||
('configuration', 'Configuration', ROOT / 'docs/configuration.md'),
|
('configuration', 'Configuration', ROOT / 'docs/configuration.md'),
|
||||||
|
('shortcuts', 'Shortcuts and gestures', ROOT / 'docs/shortcuts.md'),
|
||||||
('desktop-widgets', 'Desktop widgets', ROOT / 'docs/desktop-widgets.md'),
|
('desktop-widgets', 'Desktop widgets', ROOT / 'docs/desktop-widgets.md'),
|
||||||
('notifications', 'Notifications', ROOT / 'docs/notifications.md'),
|
('notifications', 'Notifications', ROOT / 'docs/notifications.md'),
|
||||||
('locking', 'Native locker', ROOT / 'docs/locking.md'),
|
('locking', 'Lock screen', ROOT / 'docs/locking.md'),
|
||||||
('screen-sharing', 'Screen sharing', ROOT / 'docs/screen-sharing.md'),
|
('screen-sharing', 'Screen sharing', ROOT / 'docs/screen-sharing.md'),
|
||||||
|
('portals', 'Desktop portals', ROOT / 'docs/portals.md'),
|
||||||
|
('development', 'Development', ROOT / 'docs/development.md'),
|
||||||
]
|
]
|
||||||
md = MarkdownIt('commonmark', {'html': False}).enable('table')
|
md = MarkdownIt('commonmark', {'html': False}).enable('table')
|
||||||
OUTPUT.mkdir(parents=True, exist_ok=True)
|
OUTPUT.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -101,7 +104,7 @@ for page_number, (slug, title, source) in enumerate(PAGES):
|
|||||||
<div class="docs-layout"><aside class="docs-sidebar"><div class="docs-search" hidden><label class="sr-only" for="docs-search">Search the handbook</label><input id="docs-search" type="search" placeholder="Search the handbook…" autocomplete="off" aria-controls="search-results"><div class="search-results" id="search-results" hidden></div><p class="sr-only" id="search-status" role="status"></p></div><details open><summary>FERESE HANDBOOK</summary><nav aria-label="Documentation">{navigation}</nav></details><div class="sidebar-links"><a href="{REPO}/issues">Report an issue <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a><a href="../">Back to Ferese ←</a></div></aside>
|
<div class="docs-layout"><aside class="docs-sidebar"><div class="docs-search" hidden><label class="sr-only" for="docs-search">Search the handbook</label><input id="docs-search" type="search" placeholder="Search the handbook…" autocomplete="off" aria-controls="search-results"><div class="search-results" id="search-results" hidden></div><p class="sr-only" id="search-status" role="status"></p></div><details open><summary>FERESE HANDBOOK</summary><nav aria-label="Documentation">{navigation}</nav></details><div class="sidebar-links"><a href="{REPO}/issues">Report an issue <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a><a href="../">Back to Ferese ←</a></div></aside>
|
||||||
<main class="docs-article" id="main"><div class="breadcrumb"><a href="./">Handbook</a><span aria-hidden="true">/</span><span>{escape(title)}</span></div><article class="prose">{body}</article><a class="edit-link" href="{REPO}/blob/main/{source.relative_to(ROOT)}">View this guide on GitHub <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a><nav class="docs-pager" aria-label="Previous and next guide">{pager}</nav></main>
|
<main class="docs-article" id="main"><div class="breadcrumb"><a href="./">Handbook</a><span aria-hidden="true">/</span><span>{escape(title)}</span></div><article class="prose">{body}</article><a class="edit-link" href="{REPO}/blob/main/{source.relative_to(ROOT)}">View this guide on GitHub <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a><nav class="docs-pager" aria-label="Previous and next guide">{pager}</nav></main>
|
||||||
<aside class="docs-toc" aria-label="On this page">{'<p>ON THIS PAGE</p><nav>' + contents + '</nav>' if contents else ''}</aside></div>
|
<aside class="docs-toc" aria-label="On this page">{'<p>ON THIS PAGE</p><nav>' + contents + '</nav>' if contents else ''}</aside></div>
|
||||||
<footer class="site-footer page-width"><a class="wordmark" href="../">ferese</a><p>A beautiful, fluid Wayland desktop.</p><a href="{REPO}">Built in the open <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a></footer></body></html>'''
|
<footer class="site-footer page-width"><a class="wordmark" href="../">ferese</a><p>A Wayland desktop with scrolling layouts.</p><a href="{REPO}">Built in the open <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a></footer></body></html>'''
|
||||||
(OUTPUT / 'docs' / f'{slug}.html').write_text(doc)
|
(OUTPUT / 'docs' / f'{slug}.html').write_text(doc)
|
||||||
(OUTPUT / 'docs/search-index.json').write_text(json.dumps(search_index, ensure_ascii=False))
|
(OUTPUT / 'docs/search-index.json').write_text(json.dumps(search_index, ensure_ascii=False))
|
||||||
print(f'Built website and {len(PAGES)} handbook pages at {OUTPUT}')
|
print(f'Built website and {len(PAGES)} handbook pages at {OUTPUT}')
|
||||||
+1
-3
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
The public site is static HTML and CSS. The handbook is generated from the
|
The public site is static HTML and CSS. The handbook is generated from the
|
||||||
project's Markdown guides, so website and repository documentation stay in sync.
|
project's Markdown guides, so website and repository documentation stay in sync.
|
||||||
There are no client frameworks, external fonts, or tracking scripts.
|
|
||||||
|
|
||||||
## Local preview
|
## Local preview
|
||||||
|
|
||||||
@@ -18,8 +17,7 @@ site sources or Markdown guides, then refresh the browser.
|
|||||||
|
|
||||||
- `site/index.html` and `site/styles.css`: homepage and shared visual design.
|
- `site/index.html` and `site/styles.css`: homepage and shared visual design.
|
||||||
- `site/content/index.md`: handbook introduction.
|
- `site/content/index.md`: handbook introduction.
|
||||||
- `docs/{why-ferese,installation,configuration,desktop-widgets,notifications,locking,screen-sharing}.md`:
|
- `docs/*.md`: guides; published pages are listed in `scripts/build-site.py`.
|
||||||
source guides.
|
|
||||||
- `scripts/build-site.py`: renders Markdown, resolves links, generates section
|
- `scripts/build-site.py`: renders Markdown, resolves links, generates section
|
||||||
navigation, previous/next links, and the search index.
|
navigation, previous/next links, and the search index.
|
||||||
- `site/app.js`: handbook search and code copying. Reading and navigation work
|
- `site/app.js`: handbook search and code copying. Reading and navigation work
|
||||||
|
|||||||
+33
-49
@@ -1,69 +1,53 @@
|
|||||||
# The Ferese handbook
|
# Ferese handbook
|
||||||
|
|
||||||
Ferese is a complete Wayland desktop built around personalization. Its custom shell, native Settings, live themes, and flexible layouts work together as one cohesive experience.
|
Ferese is a Linux Wayland desktop with scrolling columns, tree tiling, floating
|
||||||
|
windows, and a shared theme for its desktop tools.
|
||||||
|
|
||||||
This handbook covers installing Ferese, finding your way around, and making the desktop your own.
|
## Get started
|
||||||
|
|
||||||
[Why Ferese](why-ferese.md) explains why the desktop is designed as one integrated system rather than assembled from separately configured tools.
|
1. [Install Ferese](installation.md), or try a [nested preview](installation.md#preview-and-logs).
|
||||||
|
|
||||||
## Start with your first session
|
|
||||||
|
|
||||||
1. Read [Installation](installation.md) for dependencies, building, login-manager or TTY startup, and recovery.
|
|
||||||
2. Open **Control Center → Settings** to choose a theme and configure your desktop.
|
2. Open **Control Center → Settings** to choose a theme and configure your desktop.
|
||||||
3. Explore the [configuration reference](configuration.md) for layouts, shortcuts, window rules, and displays.
|
3. Use the [configuration reference](configuration.md) for shortcuts, gestures, window rules, and displays.
|
||||||
|
|
||||||
Want to try it before switching desktops? The [preview instructions](installation.md#preview-and-logs) cover running Ferese inside an existing Wayland session.
|
## Default shortcuts
|
||||||
|
|
||||||
## Find your way around
|
`Super` is usually the Windows key. All these shortcuts can be changed in Settings.
|
||||||
|
|
||||||
Ferese supports scrolling columns, tree tiling, floating windows, and a workspace overview. These are the built-in keyboard shortcuts; all can be changed in Settings.
|
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Super + Enter | Open a terminal |
|
| Super + Enter | Open a terminal |
|
||||||
| Super + H / J / K / L | Focus a window |
|
| Super + H / J / K / L | Focus left / down / up / right |
|
||||||
| Super + R | Cycle column width |
|
| Super + F | Maximize the window |
|
||||||
| Super + Tab | Open workspace and window overview |
|
| Super + Shift + F | Toggle fullscreen |
|
||||||
|
| Super + Tab | Open overview |
|
||||||
| Super + M | Switch scrolling / tree layout |
|
| Super + M | Switch scrolling / tree layout |
|
||||||
|
| Print Screen | Capture the active monitor and open Satty |
|
||||||
| Super + Shift + S | Select a screenshot area |
|
| Super + Shift + S | Select a screenshot area |
|
||||||
|
| Super + Shift + E | Ask to log out |
|
||||||
|
|
||||||
Three-finger swipes move between workspaces and windows. Open **Control Center → Settings → Shortcuts** to change the defaults or assign gestures to other actions.
|
See [all shortcuts and mouse actions](shortcuts.md), including Super-drag to move
|
||||||
|
and Super-right-drag to resize floating windows.
|
||||||
|
|
||||||
## Make it feel like yours
|
Three-finger swipes up/down switch workspaces; left/right focus windows.
|
||||||
|
Change gestures in **Settings → Shortcuts**. The login shortcut guide can be
|
||||||
|
disabled there too.
|
||||||
|
|
||||||
Use **Settings** for everyday customization. Choose an appearance preset, change the wallpaper, adjust shell and window corners, or add a clock and sticky notes through [Desktop widgets](desktop-widgets.md).
|
## Desktop guides
|
||||||
|
|
||||||
[Native locker](locking.md) covers lock-screen appearance, authentication, and idle locking.
|
- [Desktop widgets](desktop-widgets.md): clocks and sticky notes.
|
||||||
|
- [Notifications](notifications.md): history and Do Not Disturb.
|
||||||
|
- [Lock screen](locking.md): appearance, automatic locking, and display sleep.
|
||||||
|
- [Screen sharing and recording](screen-sharing.md): share an app or display, or save a video.
|
||||||
|
- [Desktop portals](portals.md): integration with applications.
|
||||||
|
|
||||||
[Notifications](notifications.md) explains popup cards, history, Do Not Disturb, and app actions.
|
Use Settings or edit `~/.config/ferese/config.kdl`. Changes reload automatically;
|
||||||
|
invalid edits keep the last working configuration.
|
||||||
|
|
||||||
If you prefer a text editor, your configuration lives at:
|
## Troubleshooting
|
||||||
|
|
||||||
```text
|
See [logs and recovery](installation.md#logout-and-recovery). `feresectl exit`
|
||||||
~/.config/ferese/config.kdl
|
ends the session immediately; `feresectl request-logout` asks for confirmation.
|
||||||
```
|
|
||||||
|
|
||||||
Ferese reloads changes as you make them. An invalid edit keeps the last working configuration. Settings also preserves a backup of your previous save. See [Saving and validation](configuration.md#saving-and-validation).
|
Report problems in the [issue tracker](https://github.com/ferese-wm/ferese/issues).
|
||||||
|
Include reproduction steps, whether Ferese ran as a nested preview or a direct
|
||||||
## Share your screen
|
session, and relevant logs. Contributors can start with [Development](development.md).
|
||||||
|
|
||||||
Use Ferese’s native display picker to share a monitor with a portal-compatible
|
|
||||||
recording or conferencing app. To save a video directly, click the recording
|
|
||||||
icon in the top bar. See [Screen sharing and recording](screen-sharing.md) for setup, stopping a session, and supported sources.
|
|
||||||
|
|
||||||
## Keep a recovery path
|
|
||||||
|
|
||||||
Keep another desktop session available while testing hardware behavior. Save your work before logging out: `feresectl exit` and **Super + Shift + E** end the current session immediately.
|
|
||||||
|
|
||||||
The [recovery guide](installation.md#logout-and-recovery) explains logs, installed releases, and rollback.
|
|
||||||
|
|
||||||
## Work on Ferese
|
|
||||||
|
|
||||||
Ferese is built in Rust on Smithay. Use release builds when evaluating motion and startup performance. From the repository checkout:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo test --workspace --locked
|
|
||||||
cargo fmt --all --check
|
|
||||||
```
|
|
||||||
|
|
||||||
The [source repository](https://github.com/ferese-wm/ferese) is the place to explore implementation details and report issues. When reporting a problem, include how to reproduce it, whether you used the nested or DRM backend, and relevant logs.
|
|
||||||
+12
-12
@@ -6,15 +6,15 @@
|
|||||||
<meta name="theme-color" content="#10151c" />
|
<meta name="theme-color" content="#10151c" />
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Ferese is a beautiful, fluid Wayland desktop made to feel like yours. Explore the desktop, then get started with the documentation."
|
content="Ferese is a Linux Wayland desktop with scrolling layouts, native Settings, and a shared theme."
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
property="og:title"
|
property="og:title"
|
||||||
content="Ferese — A desktop that feels like yours"
|
content="Ferese — Wayland desktop"
|
||||||
/>
|
/>
|
||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content="A complete Wayland desktop built around personalization."
|
content="A Wayland desktop with scrolling layouts and a shared theme."
|
||||||
/>
|
/>
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta
|
<meta
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
content="https://ferese-wm.github.io/ferese/assets/ferese-desktop.png"
|
content="https://ferese-wm.github.io/ferese/assets/ferese-desktop.png"
|
||||||
/>
|
/>
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<title>Ferese — A desktop that feels like yours</title>
|
<title>Ferese — Wayland desktop</title>
|
||||||
<link rel="icon" href="assets/ferese.svg" type="image/svg+xml" />
|
<link rel="icon" href="assets/ferese.svg" type="image/svg+xml" />
|
||||||
<link rel="stylesheet" href="styles.css?v=jetbrains" />
|
<link rel="stylesheet" href="styles.css?v=jetbrains" />
|
||||||
</head>
|
</head>
|
||||||
@@ -47,11 +47,11 @@
|
|||||||
<main id="main" class="simple-home">
|
<main id="main" class="simple-home">
|
||||||
<section class="product-intro page-width">
|
<section class="product-intro page-width">
|
||||||
<h1 class="product-tagline">
|
<h1 class="product-tagline">
|
||||||
A beautiful, fluid Wayland desktop made to feel like yours.
|
A Wayland desktop with scrolling layouts and a shared theme.
|
||||||
</h1>
|
</h1>
|
||||||
<p class="product-description">
|
<p class="product-description">
|
||||||
A complete Linux desktop with a custom shell, native settings,
|
A Linux desktop with a top bar, Settings,
|
||||||
scrolling and tiling layouts, and live-reloading themes.
|
scrolling and tiling layouts, and themes that update live.
|
||||||
</p>
|
</p>
|
||||||
<div class="product-links">
|
<div class="product-links">
|
||||||
<a class="button" href="docs/installation.html">Install Ferese</a>
|
<a class="button" href="docs/installation.html">Install Ferese</a>
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
A menu bar, Control Center, Settings, notifications, and desktop
|
A menu bar, Control Center, Settings, notifications, and desktop
|
||||||
widgets, designed to work together.
|
widgets, designed to work together.
|
||||||
</p>
|
</p>
|
||||||
<a href="docs/why-ferese.html">Why integration matters →</a>
|
<a href="docs/why-ferese.html">Explore Ferese →</a>
|
||||||
</article>
|
</article>
|
||||||
<article>
|
<article>
|
||||||
<h2>Make it yours</h2>
|
<h2>Make it yours</h2>
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
<h2>Getting started</h2>
|
<h2>Getting started</h2>
|
||||||
<p>
|
<p>
|
||||||
The <a href="docs/installation.html">installation guide</a> covers
|
The <a href="docs/installation.html">installation guide</a> covers
|
||||||
dependencies, setup with any Wayland-capable login manager, and TTY startup. You can also
|
dependencies, login, updates, and recovery. You can also
|
||||||
<a href="docs/installation.html#preview-and-logs">preview Ferese</a>
|
<a href="docs/installation.html#preview-and-logs">preview Ferese</a>
|
||||||
inside an existing Wayland session before installing.
|
inside an existing Wayland session before installing.
|
||||||
</p>
|
</p>
|
||||||
@@ -116,17 +116,17 @@
|
|||||||
Share a display with recording and conferencing apps through Ferese’s
|
Share a display with recording and conferencing apps through Ferese’s
|
||||||
native screen-sharing portal. Choose what to share and stop at any time.
|
native screen-sharing portal. Choose what to share and stop at any time.
|
||||||
See <a href="docs/screen-sharing.html">screen sharing and recording</a>
|
See <a href="docs/screen-sharing.html">screen sharing and recording</a>
|
||||||
for setup and current capabilities.
|
for setup and limits.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Built in Rust on Smithay. Development happens
|
Find <a href="docs/shortcuts.html">shortcuts and mouse actions</a> in the handbook. Development happens
|
||||||
<a href="https://github.com/ferese-wm/ferese">on GitHub</a>.
|
<a href="https://github.com/ferese-wm/ferese">on GitHub</a>.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<footer class="site-footer page-width">
|
<footer class="site-footer page-width">
|
||||||
<a class="wordmark" href="./">ferese</a>
|
<a class="wordmark" href="./">ferese</a>
|
||||||
<p>A beautiful, fluid Wayland desktop.</p>
|
<p>A Wayland desktop with scrolling layouts.</p>
|
||||||
<a href="docs/">Read the handbook <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a>
|
<a href="docs/">Read the handbook <svg class="link-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M7 17 17 7M7 7h10v10"/></svg></a>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in new issue
Block a user