Fix modal keyboard navigation and title switches; refresh documentation
This commit is contained in:
1 parent
1b665f4157
commit
67d2d95a01
9 files changed
+312
-192
No files matched your search
@@ -15,22 +15,21 @@ Ferese is a window manager and desktop shell built together and configured in on
|
||||
|
||||

|
||||
|
||||
[View more screenshots](docs/screenshots.md).
|
||||
[View more screenshots](docs/screenshots.md)
|
||||
|
||||
## Features
|
||||
|
||||
- Scrolling and tree layouts, floating windows, and a workspace overview.
|
||||
- Configurable keyboard shortcuts and touchpad gestures.
|
||||
- Multiple monitors with fractional scaling.
|
||||
- Six theme families, Light/Dark/Auto modes, custom KDL themes, wallpapers, blur, and adjustable corners.
|
||||
- Clock and sticky-note widgets.
|
||||
- Screenshots with Satty editing, screen sharing, and top-bar recording.
|
||||
|
||||
- Arrange your windows in scrolling columns or tree layouts, keep some floating, and bring your workspaces together in overview
|
||||
- Move around with keyboard shortcuts and touchpad gestures you can change to suit you
|
||||
- Set up multiple monitors with fractional scaling
|
||||
- Make the whole desktop your own with six theme families, Light/Dark/Auto modes, custom KDL themes, wallpapers, blur and adjustable corners
|
||||
- Keep a clock and sticky notes on your desktop
|
||||
- Capture and edit screenshots with Satty, share a window or display, and record from the top bar
|
||||
|
||||
## Install
|
||||
|
||||
Install the [dependencies](docs/installation.md#requirements), then build as your
|
||||
normal user:
|
||||
Start with the [dependencies](docs/installation.md#requirements), then clone Ferese and
|
||||
build it as your normal user:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/ferese-wm/ferese.git
|
||||
@@ -38,22 +37,24 @@ cd ferese
|
||||
./scripts/install.sh
|
||||
```
|
||||
|
||||
Log out, select **Ferese** at your login screen, and sign in. For a TTY or a
|
||||
greeter that accepts a command, run `ferese-session`.
|
||||
See [Installation](docs/installation.md) for previews, updates, and recovery.
|
||||
Once it’s installed, log out and choose **Ferese** at your login screen, or run
|
||||
`ferese-session` from a TTY or a greeter that accepts a command. The [installation
|
||||
guide](docs/installation.md) also walks you through previews, updates and recovery.
|
||||
|
||||
## Configure
|
||||
|
||||
Open **Control Center → Settings**, or edit `~/.config/ferese/config.kdl`.
|
||||
Changes reload automatically; invalid edits keep the last working configuration.
|
||||
Make it yours through **Control Center → Settings** or `~/.config/ferese/config.kdl`,
|
||||
with changes applying as you make them and the last working configuration staying in
|
||||
place if an edit is invalid.
|
||||
|
||||
See the [configuration reference](docs/configuration.md) and
|
||||
[example config](packaging/config.kdl).
|
||||
The [configuration reference](docs/configuration.md) and [example
|
||||
config](packaging/config.kdl) cover everything from appearance and window layouts to
|
||||
displays and startup apps.
|
||||
|
||||
## Default shortcuts
|
||||
|
||||
`Super` is usually the Windows key. Change shortcuts and gestures in
|
||||
**Settings → Shortcuts**.
|
||||
Use `Super`, usually the Windows key, to move around your desktop, and open **Settings →
|
||||
Shortcuts** whenever you want to change a shortcut or gesture.
|
||||
|
||||
| Control | Action |
|
||||
| --- | --- |
|
||||
@@ -72,13 +73,16 @@ See the [configuration reference](docs/configuration.md) and
|
||||
| Three-finger swipe up / down | Next / previous workspace |
|
||||
| Three-finger swipe left / right | Focus the window to the right / left |
|
||||
|
||||
See [all shortcuts and mouse actions](docs/shortcuts.md), including Super-drag
|
||||
to move and Super-right-drag to resize floating windows.
|
||||
Explore [all shortcuts and mouse actions](docs/shortcuts.md) for more ways to arrange
|
||||
your windows and move between workspaces.
|
||||
|
||||
## Documentation
|
||||
|
||||
Start with the [documentation index](docs/README.md) for user guides and
|
||||
[development instructions](docs/development.md) for builds and testing.
|
||||
The [documentation index](docs/README.md) brings the desktop guides together, while
|
||||
[development instructions](docs/development.md) cover building, testing and
|
||||
contributing.
|
||||
|
||||
Ferese is written in Rust using Smithay. Report bugs on
|
||||
[GitHub](https://github.com/ferese-wm/ferese/issues) with reproduction steps and logs.
|
||||
Ferese is written in Rust using Smithay, with development happening [on
|
||||
GitHub](https://github.com/ferese-wm/ferese). If something goes wrong, [open an
|
||||
issue](https://github.com/ferese-wm/ferese/issues) with the steps to reproduce it and
|
||||
any relevant logs.
|
||||
@@ -92,7 +92,7 @@ pub fn settings_input(p: Palette) -> theme::TextInput {
|
||||
}
|
||||
|
||||
fn styled_button(p: Palette, selected: bool, navigation: bool) -> theme::Button {
|
||||
let style = move |hover: bool| {
|
||||
let style = move |hover: bool, focused: bool| {
|
||||
let background = if selected {
|
||||
mix(p.sidebar, p.accent, if hover { 0.24 } else { 0.17 })
|
||||
} else if hover {
|
||||
@@ -115,18 +115,18 @@ fn styled_button(p: Palette, selected: bool, navigation: bool) -> theme::Button
|
||||
border_radius: p.radius.min(9.).into(),
|
||||
border_width: if selected { 1. } else { 0. },
|
||||
border_color: if selected { p.accent } else { Color::TRANSPARENT },
|
||||
outline_width: 0.,
|
||||
outline_color: Color::TRANSPARENT,
|
||||
outline_width: if focused { 2. } else { 0. },
|
||||
outline_color: p.accent,
|
||||
overlay: None,
|
||||
shadow_offset: Vector::ZERO,
|
||||
}
|
||||
};
|
||||
|
||||
theme::Button::Custom {
|
||||
active: Box::new(move |_, _| style(false)),
|
||||
hovered: Box::new(move |_, _| style(true)),
|
||||
pressed: Box::new(move |_, _| style(true)),
|
||||
disabled: Box::new(move |_| style(false)),
|
||||
active: Box::new(move |focused, _| style(false, focused)),
|
||||
hovered: Box::new(move |focused, _| style(true, focused)),
|
||||
pressed: Box::new(move |focused, _| style(true, focused)),
|
||||
disabled: Box::new(move |_| style(false, false)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+95
-98
@@ -1,17 +1,17 @@
|
||||
# Installation
|
||||
|
||||
Ferese runs on Linux and installs as a standalone Wayland session. Use any login
|
||||
manager that can launch Wayland sessions, a command-based greeter, or a local
|
||||
TTY. You do not need to replace your existing login manager or desktop.
|
||||
Ferese runs on Linux as its own Wayland session, alongside your existing desktop, and
|
||||
you can launch it from a login manager, a command-based greeter or a local TTY.
|
||||
|
||||
## Requirements
|
||||
|
||||
Use a Wayland-capable graphics driver and a local user session with seat access
|
||||
through logind or seatd. A nested preview runs inside an existing Wayland desktop.
|
||||
For a full session, you’ll need a Wayland-capable graphics driver and a local user
|
||||
session with seat access through logind or seatd, while a nested preview runs inside the
|
||||
Wayland desktop you already use.
|
||||
|
||||
Building requires **Rust 1.95 or newer**, a C/C++ toolchain, CMake, pkg-config,
|
||||
and the libraries below. The installer builds all Ferese components; install
|
||||
system packages separately.
|
||||
To build Ferese, install **Rust 1.95 or newer**, a C/C++ toolchain, CMake, pkg-config
|
||||
and the libraries below. The installer builds the Ferese components once those system
|
||||
packages are in place.
|
||||
|
||||
### Fedora
|
||||
|
||||
@@ -49,9 +49,10 @@ sudo apt install build-essential git curl cmake pkg-config libwayland-dev \
|
||||
gstreamer1.0-plugins-good
|
||||
```
|
||||
|
||||
Fedora is the tested installation path. Package names and versions may differ
|
||||
on other distributions. See [Smithay dependencies](https://github.com/Smithay/smithay#system-dependencies)
|
||||
for equivalent libraries.
|
||||
Fedora is the tested installation path, and package names or versions may differ on
|
||||
other distributions, where the [Smithay
|
||||
dependencies](https://github.com/Smithay/smithay#system-dependencies) can help you find
|
||||
equivalent libraries.
|
||||
|
||||
### Rust toolchain
|
||||
|
||||
@@ -62,9 +63,9 @@ rustc --version
|
||||
cargo --version
|
||||
```
|
||||
|
||||
If Rust is missing, install it using the instructions at
|
||||
[rustup.rs](https://rustup.rs/), then reopen your terminal. With rustup installed,
|
||||
you can select the required version for this checkout after cloning:
|
||||
If you don’t have Rust yet, follow the instructions at [rustup.rs](https://rustup.rs/)
|
||||
and reopen your terminal, then select the required toolchain for this checkout after
|
||||
cloning:
|
||||
|
||||
```sh
|
||||
rustup toolchain install 1.95.0
|
||||
@@ -81,21 +82,22 @@ cd ferese
|
||||
./scripts/install.sh
|
||||
```
|
||||
|
||||
The script builds locked release binaries, then requests administrator access
|
||||
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 script builds locked release binaries as your normal user and then asks for
|
||||
administrator access through `sudo` or `pkexec` to install them, so leave the build
|
||||
itself unprivileged. The first build needs network access to fetch Rust dependencies.
|
||||
|
||||
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.
|
||||
Installation brings together the session launcher, desktop tools, portal backend, login
|
||||
entry, icons, default wallpaper and example config. Releases live under
|
||||
`/usr/local/lib/ferese/releases/` and commands under `/usr/local/bin/`, with `current`
|
||||
and `previous` links for switching between releases during updates and rollback.
|
||||
|
||||
Your configuration, other desktop sessions, and existing PAM policy are preserved.
|
||||
Ferese starts its authentication agent and portal services with the session.
|
||||
Your configuration, other desktop sessions and existing PAM policy stay in place, while
|
||||
Ferese starts its authentication agent and portal services together with the session.
|
||||
|
||||
### Initial configuration
|
||||
|
||||
Ferese has built-in defaults. To start from the example without replacing your config:
|
||||
You can start with Ferese’s built-in defaults, or copy the example config if you’d like
|
||||
a file to customize:
|
||||
|
||||
```sh
|
||||
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/ferese"
|
||||
@@ -105,18 +107,18 @@ if [ ! -e "${XDG_CONFIG_HOME:-$HOME/.config}/ferese/config.kdl" ]; then
|
||||
fi
|
||||
```
|
||||
|
||||
Open **Control Center → Settings** after login, or run `ferese-settings`.
|
||||
See [Configuration](configuration.md) for themes, displays, shortcuts, and startup
|
||||
applications. The default terminal shortcut uses `foot`; change the terminal
|
||||
command in Settings if you prefer another terminal.
|
||||
After login, open **Control Center → Settings** or run `ferese-settings` to shape your
|
||||
desktop, using [Configuration](configuration.md) for themes, displays, shortcuts and
|
||||
startup apps. The default terminal is `foot`, which you can replace with your preferred
|
||||
terminal command in Settings.
|
||||
|
||||
## Start a session
|
||||
|
||||
### Graphical login managers
|
||||
|
||||
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
|
||||
`/usr/share/wayland-sessions/` can discover the installed entry.
|
||||
Save your work and log out, then open your login screen’s session selector, choose
|
||||
**Ferese** and sign in. Login managers that support Wayland sessions can discover the
|
||||
installed entry in `/usr/share/wayland-sessions/`.
|
||||
|
||||
If Ferese is missing, confirm that the session entry exists and its launcher is
|
||||
executable:
|
||||
@@ -127,9 +129,9 @@ test -x /usr/local/bin/ferese-session && echo "Session launcher is ready"
|
||||
desktop-file-validate /usr/share/wayland-sessions/ferese.desktop
|
||||
```
|
||||
|
||||
Check your manager's documentation for enabling Wayland session discovery. A
|
||||
manager that only launches X11 sessions cannot start Ferese through that path;
|
||||
use a Wayland-capable greeter or the TTY method below.
|
||||
If the entry still doesn’t appear, check your login manager’s documentation for Wayland
|
||||
session discovery, or use a Wayland-capable greeter or the TTY method below if your
|
||||
manager only launches X11 sessions.
|
||||
|
||||
### Command-based greeters
|
||||
|
||||
@@ -139,26 +141,24 @@ If your greeter asks for a session command instead of reading desktop files, use
|
||||
/usr/local/bin/ferese-session
|
||||
```
|
||||
|
||||
For greetd, use this as the session command after authentication; see the
|
||||
[greetd documentation](https://sr.ht/~kennylevinsen/greetd/).
|
||||
The launcher starts the compositor, shell, and session services together.
|
||||
For greetd, set this as the session command after authentication using the [greetd
|
||||
documentation](https://sr.ht/~kennylevinsen/greetd/), and the launcher will start the
|
||||
compositor, shell and session services together.
|
||||
|
||||
### From a TTY
|
||||
|
||||
Log out of the graphical session, switch to a local console with
|
||||
**Ctrl+Alt+F2** (or another available function key), and sign in as your normal
|
||||
user. Then run:
|
||||
Log out of your graphical session and switch to a local console with **Ctrl+Alt+F2**, or
|
||||
another available function key, then sign in as your normal user and run:
|
||||
|
||||
```sh
|
||||
/usr/local/bin/ferese-session
|
||||
```
|
||||
|
||||
Your login must provide `XDG_RUNTIME_DIR` and access to the active seat through
|
||||
logind or seatd. If either is missing, fix the distribution's login/session setup;
|
||||
do not work around it by running Ferese as root or making device nodes writable.
|
||||
For non-systemd systems, follow your distribution's seatd and user-session setup.
|
||||
Do not start the DRM backend inside an existing graphical session; use a nested
|
||||
preview there.
|
||||
Your login needs to provide `XDG_RUNTIME_DIR` and access to the active seat through
|
||||
logind or seatd; if either is missing, fix your distribution’s login and session setup
|
||||
rather than running Ferese as root or making device nodes writable. On non-systemd
|
||||
systems, follow the distribution’s seatd and user-session instructions, and use a nested
|
||||
preview whenever you’re already inside a graphical session.
|
||||
|
||||
## Optional desktop tools
|
||||
|
||||
@@ -173,18 +173,18 @@ Install these through your distribution when you want the corresponding features
|
||||
| Audio controls | PipeWire, WirePlumber, and `wpctl` |
|
||||
| Bluetooth controls | BlueZ, `bluetoothctl`, and its running service |
|
||||
|
||||
Package names and availability vary by distribution. In particular, install
|
||||
Satty using its [upstream instructions](https://github.com/Satty-org/Satty#install)
|
||||
if your repositories do not provide it. Ferese does not enable these services
|
||||
or replace your existing service configuration during installation.
|
||||
Package names and availability vary by distribution, so use Satty’s [upstream
|
||||
instructions](https://github.com/Satty-org/Satty#install) if it isn’t in your
|
||||
repositories. Ferese leaves service setup to you and preserves your existing service
|
||||
configuration during installation.
|
||||
|
||||
Print Screen captures the active monitor; **Super+Shift+S** selects an area.
|
||||
Use `ferese-screenshot --all` to capture all monitors in one image.
|
||||
Use **Print Screen** to capture the active monitor, **Super+Shift+S** to select an area,
|
||||
or `ferese-screenshot --all` to capture all monitors in one image.
|
||||
|
||||
The native locker follows your shell theme. Open **Settings → Lock Screen** to
|
||||
customize it, or run `ferese-lock --preview` to see an ordinary preview window.
|
||||
Test real unlocking before enabling automatic locking; see
|
||||
[Native locker](locking.md) for authentication, idle locking, and limitations.
|
||||
The native locker follows your shell theme and can be personalized in **Settings → Lock
|
||||
Screen**, with `ferese-lock --preview` opening an ordinary preview window. Before
|
||||
enabling automatic locking, test real unlocking and read [Native locker](locking.md) for
|
||||
authentication, idle locking and limits.
|
||||
|
||||
## Preview and logs
|
||||
|
||||
@@ -204,21 +204,19 @@ After installation, the equivalent launcher is:
|
||||
ferese-session --nested
|
||||
```
|
||||
|
||||
The session launcher stores logs in `${XDG_STATE_HOME:-$HOME/.local/state}/ferese/`.
|
||||
A directly launched source build writes to its terminal. Keep another desktop
|
||||
available while testing scaling, monitor hotplug, suspend, and locking.
|
||||
The session launcher saves logs in `${XDG_STATE_HOME:-$HOME/.local/state}/ferese/`,
|
||||
while a source build launched directly writes to its terminal. Keep another desktop
|
||||
available when testing scaling, monitor hotplug, suspend or locking so you have a way
|
||||
back if something goes wrong.
|
||||
|
||||
The launcher enables the screencopy protocol for screenshot tools. Set
|
||||
`FERESE_ENABLE_SCREENCOPY=0` in the session environment to disable it. This
|
||||
turns off every path that can read the screen, including the built-in
|
||||
screenshot command, not only the Wayland protocol. When enabled, Wayland clients
|
||||
can capture the unlocked desktop, and `feresectl screenshot` is available.
|
||||
Capture remains blocked while the session is locked. Launcher changes take
|
||||
effect at next login.
|
||||
The launcher enables screencopy for screenshot tools, allowing Wayland clients to
|
||||
capture the unlocked desktop and making `feresectl screenshot` available. Set
|
||||
`FERESE_ENABLE_SCREENCOPY=0` in the session environment to disable every screen-reading
|
||||
path, including the built-in screenshot command, at your next login; capture is always
|
||||
blocked while the session is locked.
|
||||
|
||||
Starting the compositor directly instead of through `ferese-session` leaves
|
||||
`FERESE_ENABLE_SCREENCOPY` unset, which disables screenshots. Export
|
||||
`FERESE_ENABLE_SCREENCOPY=1` to use them.
|
||||
When you launch the compositor directly, set `FERESE_ENABLE_SCREENCOPY=1` to enable
|
||||
screenshots, since that variable is otherwise unset and screen capture stays disabled.
|
||||
|
||||
## Updating
|
||||
|
||||
@@ -229,14 +227,14 @@ git pull --ff-only
|
||||
./scripts/install.sh
|
||||
```
|
||||
|
||||
Log out and back in to use the new release. Running sessions keep their existing
|
||||
processes and release paths until restarted.
|
||||
Log out and back in to start using the new release, as a running session keeps its
|
||||
existing processes and release paths until it restarts.
|
||||
|
||||
The installer records shipped portal configuration with each release for future
|
||||
upgrades. Modified or untracked administrator files stop installation. To replace
|
||||
Ferese portal configuration from an earlier development install, use
|
||||
`./scripts/install.sh --skip-build --replace-portal-config` after building. Existing
|
||||
files are backed up under the new release's `portal-config.previous/` directory.
|
||||
Each release records the portal configuration it ships so later upgrades can identify
|
||||
it, and installation stops if it encounters modified or untracked administrator files.
|
||||
To replace Ferese portal configuration from an earlier development install, build first
|
||||
and run `./scripts/install.sh --skip-build --replace-portal-config`, which backs up the
|
||||
existing files in the new release’s `portal-config.previous/` directory.
|
||||
|
||||
Installer options:
|
||||
|
||||
@@ -246,25 +244,25 @@ Installer options:
|
||||
./scripts/install.sh --skip-build
|
||||
```
|
||||
|
||||
`--dry-run` prints the planned commands. `--offline` requires dependencies to be
|
||||
cached already. `--skip-build` installs the binaries already in `target/release/`;
|
||||
use it only after building all components from the intended revision.
|
||||
Run `./scripts/install.sh --help` for all options.
|
||||
Use `--dry-run` to see the planned commands, `--offline` when dependencies are already
|
||||
cached, or `--skip-build` after building every component from the revision you want to
|
||||
install. The latter uses binaries already in `target/release/`, and
|
||||
`./scripts/install.sh --help` lists all available options.
|
||||
|
||||
## Logout and recovery
|
||||
|
||||
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
|
||||
identify the affected compositor process:
|
||||
Save your work before leaving: **Super+Shift+E** and `feresectl request-logout` ask for
|
||||
confirmation, while `feresectl exit` ends the session immediately. If Ferese freezes,
|
||||
switch to another TTY with **Ctrl+Alt+F1–F12**, sign in and find the affected compositor
|
||||
process:
|
||||
|
||||
```sh
|
||||
pgrep -a -u "$USER" -x ferese
|
||||
```
|
||||
|
||||
Terminate only that session's process with `kill PID`, replacing `PID` with the
|
||||
correct process ID. This ends its applications and can lose unsaved work. You
|
||||
can then select your other desktop at the next login.
|
||||
Replace `PID` with the affected session’s process ID and use `kill PID` to end it,
|
||||
bearing in mind that its applications will close and unsaved work may be lost. You can
|
||||
then choose another desktop at the next login.
|
||||
|
||||
### Roll back a release
|
||||
|
||||
@@ -288,9 +286,9 @@ sudo sh -eu -c '
|
||||
'
|
||||
```
|
||||
|
||||
Then log in again. This changes the selected binaries; it does not restore your
|
||||
config or replace the PAM policy. Settings keeps a backup when saving config
|
||||
changes; see [Saving and validation](configuration.md#saving-and-validation).
|
||||
Log in again to use the selected binaries, with your config and PAM policy still in
|
||||
place. If you also need to recover a configuration edit, Settings keeps a backup when
|
||||
saving, as described in [Saving and validation](configuration.md#saving-and-validation).
|
||||
|
||||
### Remove the login option
|
||||
|
||||
@@ -301,14 +299,13 @@ sudo mv /usr/share/wayland-sessions/ferese.desktop \
|
||||
/usr/local/lib/ferese/ferese.desktop.disabled
|
||||
```
|
||||
|
||||
For a command-based greeter, remove Ferese from its session choices using that
|
||||
greeter's configuration. Reinstalling restores the desktop session entry.
|
||||
For a command-based greeter, remove Ferese from its session choices in the greeter’s
|
||||
configuration; reinstalling Ferese restores the desktop session entry.
|
||||
|
||||
## Screen sharing and recording
|
||||
|
||||
The installer includes Ferese’s native ScreenCast portal. It backs up the old
|
||||
user service override that points to `~/.local/libexec/ferese`, so new sessions
|
||||
use the installed release. Custom overrides are preserved and reported before
|
||||
building. See
|
||||
[Screen sharing](screen-sharing.md) for consent, PipeWire setup, supported sources,
|
||||
and current recording limitations.
|
||||
Ferese’s native ScreenCast portal is included in the installation, which backs up the
|
||||
old user service override pointing to `~/.local/libexec/ferese` so new sessions use the
|
||||
installed release. Custom overrides are preserved and reported before building, and
|
||||
[Screen sharing](screen-sharing.md) covers consent, PipeWire setup, supported sources
|
||||
and recording limits.
|
||||
+11
-9
@@ -4,21 +4,22 @@ Most Wayland desktops are assembled from separate programs such as a compositor,
|
||||
|
||||
## Choose how windows fit
|
||||
|
||||
Scrolling columns let you keep windows at useful widths and move through them
|
||||
horizontally. Tree tiling divides the screen into nested splits. Floating windows
|
||||
work alongside either layout, and overview shows windows across workspaces.
|
||||
Keep windows at useful widths and move through them horizontally with scrolling columns,
|
||||
divide the screen into nested splits with tree tiling, or let individual windows float
|
||||
alongside either layout. When you want to see how everything fits together, overview
|
||||
brings your windows and workspaces into view.
|
||||
|
||||

|
||||
|
||||
## Change the desktop together
|
||||
|
||||
Choose a theme in Settings, then adjust the wallpaper, colors, font, corners,
|
||||
and motion. Changes apply live. Window corners and shell corners can be set
|
||||
independently.
|
||||
Choose a theme in Settings and build on it with your own wallpaper, colors, font,
|
||||
corners and motion, with changes applying across the desktop as you make them. Window
|
||||
and shell corners have separate controls, so you can shape each to your liking.
|
||||
|
||||

|
||||
|
||||
For example, this changes shell corners:
|
||||
To give your shell corners a different radius, add:
|
||||
|
||||
```kdl
|
||||
theme {
|
||||
@@ -28,5 +29,6 @@ theme {
|
||||
}
|
||||
```
|
||||
|
||||
See [Configuration](configuration.md) for all options, or
|
||||
[Installation](installation.md) to try Ferese in a nested preview.
|
||||
Explore [Configuration](configuration.md) for everything you can change, or follow
|
||||
[Installation](installation.md) to try Ferese inside your current desktop with a nested
|
||||
preview.
|
||||
@@ -1794,6 +1794,16 @@ impl FereseShell {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Event::Keyboard(cosmic::iced::keyboard::Event::KeyPressed {
|
||||
key: cosmic::iced::keyboard::Key::Named(cosmic::iced::keyboard::key::Named::Tab),
|
||||
modifiers,
|
||||
..
|
||||
}) = &event
|
||||
&& !modifiers.control()
|
||||
&& self.system_modal.as_ref().is_some_and(|modal| modal.contains(id))
|
||||
{
|
||||
return self.navigate_system_modal(modifiers.shift());
|
||||
}
|
||||
if matches!(
|
||||
&event,
|
||||
Event::Keyboard(cosmic::iced::keyboard::Event::KeyPressed {
|
||||
@@ -1841,8 +1851,11 @@ impl FereseShell {
|
||||
}
|
||||
}
|
||||
|
||||
window::run(id, native_wayland_surface)
|
||||
.map(move |surface| cosmic::Action::App(Message::NativeSurface(id, surface)))
|
||||
Task::batch([
|
||||
self.focus_system_modal(id),
|
||||
window::run(id, native_wayland_surface)
|
||||
.map(move |surface| cosmic::Action::App(Message::NativeSurface(id, surface))),
|
||||
])
|
||||
}
|
||||
Event::Keyboard(cosmic::iced::keyboard::Event::KeyPressed {
|
||||
key: cosmic::iced::keyboard::Key::Named(cosmic::iced::keyboard::key::Named::Escape),
|
||||
|
||||
@@ -435,6 +435,22 @@ impl FereseShell {
|
||||
p,
|
||||
));
|
||||
}
|
||||
if kind == Menu::Network
|
||||
&& let Some(network) = &self.status.network
|
||||
{
|
||||
heading = heading.push(shell_switch(
|
||||
"Wi-Fi",
|
||||
network.enabled,
|
||||
Action::Wifi(!network.enabled),
|
||||
theme,
|
||||
p,
|
||||
));
|
||||
}
|
||||
if kind == Menu::Audio
|
||||
&& let Some(audio) = &self.status.audio
|
||||
{
|
||||
heading = heading.push(shell_switch("Mute", audio.muted, Action::Mute(!audio.muted), theme, p));
|
||||
}
|
||||
let mut rows = column::with_capacity(12).spacing(12).width(Length::Fill);
|
||||
if kind != Menu::Calendar {
|
||||
rows = rows.push(heading);
|
||||
@@ -546,7 +562,8 @@ impl FereseShell {
|
||||
muted,
|
||||
color_with_opacity(theme.accent, p),
|
||||
p,
|
||||
Some((n.enabled, Action::Wifi(!n.enabled))),
|
||||
n.enabled,
|
||||
None,
|
||||
));
|
||||
if connected {
|
||||
let strength = match n.signal {
|
||||
@@ -589,6 +606,7 @@ impl FereseShell {
|
||||
muted,
|
||||
color_with_opacity(theme.accent, p),
|
||||
p,
|
||||
b.enabled,
|
||||
Some((b.enabled, Action::Bluetooth(!b.enabled))),
|
||||
));
|
||||
|
||||
@@ -620,17 +638,13 @@ impl FereseShell {
|
||||
if (combined || menu.kind == Menu::Audio)
|
||||
&& let Some(a) = &self.status.audio
|
||||
{
|
||||
let mut volume_heading = row![text("Volume").size(13).width(Length::Fill)].align_y(Alignment::Center);
|
||||
if combined {
|
||||
volume_heading =
|
||||
volume_heading.push(shell_switch("Mute", a.muted, Action::Mute(!a.muted), theme, p));
|
||||
}
|
||||
let audio = column![
|
||||
row![
|
||||
text("Volume").size(13).width(Length::Fill),
|
||||
menu_button(
|
||||
if a.muted { "Unmute" } else { "Mute" },
|
||||
Message::Control(Action::Mute(!a.muted)),
|
||||
primary,
|
||||
p
|
||||
)
|
||||
]
|
||||
.align_y(Alignment::Center),
|
||||
volume_heading,
|
||||
text(&a.output).size(12).class(theme::Text::Color(muted)),
|
||||
slider_row(
|
||||
audio_icon(a.volume, a.muted),
|
||||
@@ -856,9 +870,9 @@ fn status_summary<'a>(
|
||||
muted: Color,
|
||||
accent: Color,
|
||||
opacity: f32,
|
||||
enabled: bool,
|
||||
toggle: Option<(bool, Action)>,
|
||||
) -> Element<'a, cosmic::Action<Message>> {
|
||||
let enabled = toggle.as_ref().is_some_and(|(enabled, _)| *enabled);
|
||||
let badge_color = if enabled { accent } else { primary };
|
||||
let badge = container(accented_icon(source, 22, primary, accent))
|
||||
.width(32)
|
||||
|
||||
@@ -67,6 +67,7 @@ pub(super) struct SystemModal {
|
||||
pub(super) motion: motion::PopupMotion,
|
||||
error: Option<String>,
|
||||
inhibitors: Option<compositor_ipc::Approval>,
|
||||
keyboard_nav: bool,
|
||||
}
|
||||
|
||||
impl SystemModal {
|
||||
@@ -190,12 +191,15 @@ impl FereseShell {
|
||||
move |result| cosmic::Action::App(Message::SystemInhibitors(id, result)),
|
||||
));
|
||||
}
|
||||
let keyboard_nav = self.core.keyboard_nav();
|
||||
self.core.set_keyboard_nav(false);
|
||||
self.system_modal = Some(SystemModal {
|
||||
content,
|
||||
surfaces,
|
||||
motion: motion::PopupMotion::new(self.config.animations),
|
||||
error: None,
|
||||
inhibitors: mode.is_none().then(compositor_ipc::Approval::default),
|
||||
keyboard_nav,
|
||||
});
|
||||
Task::batch(tasks)
|
||||
}
|
||||
@@ -293,6 +297,7 @@ impl FereseShell {
|
||||
let Some(modal) = self.system_modal.take() else {
|
||||
return Task::none();
|
||||
};
|
||||
self.core.set_keyboard_nav(modal.keyboard_nav);
|
||||
if cancel
|
||||
&& let Content::Power(PowerAction::Logout(serial)) = modal.content
|
||||
&& let Some(control) = &self.control
|
||||
@@ -322,6 +327,23 @@ impl FereseShell {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn focus_system_modal(&self, id: window::Id) -> Task<Message> {
|
||||
if self.system_modal.as_ref().is_some_and(|modal| {
|
||||
!modal.motion.closing() && modal.surfaces.iter().any(|surface| surface.id == id && surface.primary)
|
||||
}) {
|
||||
button::focus("ferese-modal-cancel".into())
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn navigate_system_modal(&self, backwards: bool) -> Task<Message> {
|
||||
if self.system_modal.as_ref().is_none_or(|modal| modal.motion.closing()) {
|
||||
return Task::none();
|
||||
}
|
||||
cosmic::iced::advanced::widget::operate(modal_focus_operation(backwards))
|
||||
}
|
||||
|
||||
pub(super) fn execute_system_modal(&mut self) -> Task<Message> {
|
||||
let Some(modal) = &mut self.system_modal else {
|
||||
return Task::none();
|
||||
@@ -440,18 +462,22 @@ impl FereseShell {
|
||||
rows = rows.push(text(error).size(13));
|
||||
}
|
||||
rows.push(
|
||||
row![
|
||||
Space::new().width(Length::Fill),
|
||||
ferese_theme::controls::text_button("Cancel", shell_font(), palette, false)
|
||||
.on_press(cosmic::Action::App(Message::CancelPower)),
|
||||
ferese_theme::controls::text_button(label, shell_font(), palette, true).on_press_maybe(
|
||||
modal
|
||||
.inhibitors
|
||||
.is_some()
|
||||
.then_some(cosmic::Action::App(Message::ExecutePower))
|
||||
),
|
||||
]
|
||||
.spacing(10),
|
||||
container(
|
||||
row![
|
||||
Space::new().width(Length::Fill),
|
||||
ferese_theme::controls::text_button("Cancel", shell_font(), palette, false)
|
||||
.id("ferese-modal-cancel".into())
|
||||
.on_press(cosmic::Action::App(Message::CancelPower)),
|
||||
ferese_theme::controls::text_button(label, shell_font(), palette, true).on_press_maybe(
|
||||
modal
|
||||
.inhibitors
|
||||
.is_some()
|
||||
.then_some(cosmic::Action::App(Message::ExecutePower))
|
||||
),
|
||||
]
|
||||
.spacing(10),
|
||||
)
|
||||
.id("ferese-system-modal-controls"),
|
||||
)
|
||||
}
|
||||
Content::Guide(entries) => {
|
||||
@@ -482,11 +508,13 @@ impl FereseShell {
|
||||
text("Disable this guide in Settings → Shortcuts. It appears at each login until disabled.")
|
||||
.size(12)
|
||||
.class(theme::Text::Color(palette.muted)),
|
||||
row![
|
||||
container(row![
|
||||
Space::new().width(Length::Fill),
|
||||
ferese_theme::controls::text_button("Got it", shell_font(), palette, true,)
|
||||
.id("ferese-modal-cancel".into())
|
||||
.on_press(cosmic::Action::App(Message::CancelPower)),
|
||||
],
|
||||
])
|
||||
.id("ferese-system-modal-controls"),
|
||||
]
|
||||
.spacing(14)
|
||||
}
|
||||
@@ -537,10 +565,65 @@ impl FereseShell {
|
||||
}
|
||||
}
|
||||
|
||||
// Restrict Tab traversal to the modal actions, excluding the bar and desktop widgets.
|
||||
fn modal_focus_operation<T: Send + 'static>(backwards: bool) -> Box<dyn cosmic::iced::advanced::widget::Operation<T>> {
|
||||
use cosmic::iced::advanced::widget::{Id, operation};
|
||||
let target = Id::new("ferese-system-modal-controls");
|
||||
if backwards {
|
||||
Box::new(operation::scoped(target, operation::focusable::focus_previous()))
|
||||
} else {
|
||||
Box::new(operation::scoped(target, operation::focusable::focus_next()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tab_stays_within_modal_actions_in_both_directions() {
|
||||
use cosmic::iced::Rectangle;
|
||||
use cosmic::iced::advanced::widget::{Id, Operation, operation};
|
||||
|
||||
#[derive(Default)]
|
||||
struct Focus(bool);
|
||||
impl operation::Focusable for Focus {
|
||||
fn is_focused(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
fn focus(&mut self) {
|
||||
self.0 = true;
|
||||
}
|
||||
fn unfocus(&mut self) {
|
||||
self.0 = false;
|
||||
}
|
||||
}
|
||||
|
||||
let mut outside = Focus(true);
|
||||
let mut cancel = Focus(true);
|
||||
let mut confirm = Focus(false);
|
||||
for (backwards, expected_cancel) in [(false, false), (false, true), (true, false), (true, true)] {
|
||||
let mut current: Box<dyn Operation<()>> = modal_focus_operation(backwards);
|
||||
loop {
|
||||
current.focusable(Some(&Id::new("bar")), Rectangle::default(), &mut outside);
|
||||
current.container(Some(&Id::new("ferese-system-modal-controls")), Rectangle::default());
|
||||
current.traverse(&mut |operation| {
|
||||
operation.focusable(Some(&Id::new("cancel")), Rectangle::default(), &mut cancel);
|
||||
operation.focusable(Some(&Id::new("confirm")), Rectangle::default(), &mut confirm);
|
||||
});
|
||||
match current.finish() {
|
||||
operation::Outcome::Chain(next) => current = next,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
assert!(outside.0, "modal navigation changed focus outside the modal");
|
||||
assert_ne!(cancel.0, confirm.0);
|
||||
assert_eq!(cancel.0, expected_cancel);
|
||||
}
|
||||
assert!(cancel.0);
|
||||
assert!(!confirm.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_power_actions_require_confirmation() {
|
||||
assert_eq!(
|
||||
|
||||
+14
-12
@@ -1,7 +1,8 @@
|
||||
# Ferese website and handbook
|
||||
|
||||
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.
|
||||
The website introduces Ferese as one desktop you can make your own, with a handbook
|
||||
built from the project’s Markdown guides so the website and repository share the same
|
||||
documentation.
|
||||
|
||||
## Local preview
|
||||
|
||||
@@ -12,8 +13,9 @@ python3 -m venv .site-venv
|
||||
python3 -m http.server 8080 --bind 127.0.0.1 --directory build/site
|
||||
```
|
||||
|
||||
Open http://localhost:8080 or http://localhost:8080/docs/. Rebuild after editing
|
||||
site sources or Markdown guides, then refresh the browser.
|
||||
Open http://localhost:8080 for the homepage or http://localhost:8080/docs/ for the
|
||||
handbook, then rebuild and refresh the browser whenever you change the site sources or
|
||||
guides.
|
||||
|
||||
- `site/index.html` and `site/styles.css`: homepage and shared visual design.
|
||||
- `site/content/index.md`: handbook introduction.
|
||||
@@ -25,13 +27,13 @@ site sources or Markdown guides, then refresh the browser.
|
||||
|
||||
## GitHub Pages
|
||||
|
||||
Select **Settings → Pages → Source → GitHub Actions**. The Pages workflow
|
||||
publishes site and documentation changes pushed to `main`, or can run manually.
|
||||
Expected URL: https://ferese-wm.github.io/ferese/.
|
||||
Choose **Settings → Pages → Source → GitHub Actions** to publish through the Pages
|
||||
workflow, which runs when site or documentation changes reach `main` and can also be
|
||||
started manually. The expected address is https://ferese-wm.github.io/ferese/.
|
||||
|
||||
Local links are relative, including documentation search, so publishing under
|
||||
the `/ferese/` project path works. Screenshots are copied from `docs/images`
|
||||
during the build; the generated `build/site` directory is ignored by Git.
|
||||
The site uses relative links, including for handbook search, so it also works under the
|
||||
`/ferese/` project path. Each build copies screenshots from `docs/images` into
|
||||
`build/site`, which is ignored by Git.
|
||||
|
||||
See [GitHub's custom workflow documentation](https://docs.github.com/en/pages/getting-started-with-github-pages/using-custom-workflows-with-github-pages)
|
||||
for deployment setup.
|
||||
For deployment setup, follow [GitHub’s custom workflow
|
||||
documentation](https://docs.github.com/en/pages/getting-started-with-github-pages/using-custom-workflows-with-github-pages).
|
||||
+18
-13
@@ -1,9 +1,11 @@
|
||||
# Ferese handbook
|
||||
|
||||
Ferese is a Linux Wayland desktop with scrolling columns, tree tiling, floating
|
||||
windows, and a shared theme for its desktop tools.
|
||||
Ferese is a window manager and desktop shell built together and configured in one place,
|
||||
for people who want their desktop to be their own. This handbook helps you get settled,
|
||||
shape the desktop around the way you work and understand what you can change.
|
||||
|
||||
[Browse screenshots](screenshots.md) of the desktop, themes and shell controls.
|
||||
[Browse screenshots](screenshots.md) to see the themes, layouts and desktop controls in
|
||||
use
|
||||
|
||||
## Get started
|
||||
|
||||
@@ -13,7 +15,8 @@ windows, and a shared theme for its desktop tools.
|
||||
|
||||
## Default shortcuts
|
||||
|
||||
`Super` is usually the Windows key. All these shortcuts can be changed in Settings.
|
||||
Use `Super`, usually the Windows key, for the shortcuts below, and make them your own in
|
||||
**Settings → Shortcuts**.
|
||||
|
||||
| Control | Action |
|
||||
| --- | --- |
|
||||
@@ -32,8 +35,8 @@ windows, and a shared theme for its desktop tools.
|
||||
| Three-finger swipe left / right | Focus the window to the right / left |
|
||||
| Login shortcut guide | Appears at login; disable in Settings → Shortcuts |
|
||||
|
||||
See [all shortcuts and mouse actions](shortcuts.md), including Super-drag to move
|
||||
and Super-right-drag to resize floating windows.
|
||||
The [shortcuts and mouse actions guide](shortcuts.md) covers the rest, including how to
|
||||
group windows, resize them and move between workspaces.
|
||||
|
||||
## Desktop guides
|
||||
|
||||
@@ -43,14 +46,16 @@ and Super-right-drag to resize floating windows.
|
||||
- [Screen sharing and recording](screen-sharing.md): share an app or display, or save a video.
|
||||
- [Desktop portals](portals.md): integration with applications.
|
||||
|
||||
Use Settings or edit `~/.config/ferese/config.kdl`. Changes reload automatically;
|
||||
invalid edits keep the last working configuration.
|
||||
Personalize the desktop in Settings or edit `~/.config/ferese/config.kdl` directly, with
|
||||
changes applying live and the last working configuration staying in place if an edit is
|
||||
invalid.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
See [logs and recovery](installation.md#logout-and-recovery). `feresectl exit`
|
||||
ends the session immediately; `feresectl request-logout` asks for confirmation.
|
||||
If you need to end a session, `feresectl request-logout` asks for confirmation and
|
||||
`feresectl exit` exits immediately, so save your work first. The [logs and recovery
|
||||
guide](installation.md#logout-and-recovery) helps when something stops responding.
|
||||
|
||||
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
|
||||
session, and relevant logs. Contributors can start with [Development](development.md).
|
||||
You can [report a problem](https://github.com/ferese-wm/ferese/issues) with the steps to
|
||||
reproduce it, relevant logs and whether you were using a nested preview or a direct
|
||||
session, or start with [Development](development.md) if you’d like to contribute.
|
||||
Reference in new issue
Block a user