Fix boot-critical, session, and UX bugs found in round-3 UX audit
Snapshots panel was non-functional (wrong snapper flag); breadgreet picked the wrong session .desktop and skipped bos-session's PATH fixup; Calamares aborted offline installs over an unnecessary packages module; snapshot rollback silently no-op'd on BOS's pinned-subvolume layout (now points at grub-btrfs instead); breadcrumbs was configurable but had no daemon to run it. Also: SUPER+I double-bind, breadpaper/packages panels blocking the GTK main thread, dead polkit rule, and a sweep of smaller drift (default sidebar view, stale wording, missing .desktop launchers, wallpaper daemon not recording its own default).
This commit is contained in:
parent
a8f1592e75
commit
d78a2343f4
32 changed files with 553 additions and 209 deletions
|
|
@ -35,7 +35,12 @@ sequence:
|
|||
- users
|
||||
- networkcfg
|
||||
- hwclock
|
||||
- packages
|
||||
# packages module removed: it set update_db:true with no
|
||||
# skip_if_no_internet/ignore_update_db_error, so an offline install (the
|
||||
# exact case bos-welcome's nmtui step exists for) aborted here with a
|
||||
# fatal pacman -Sy failure. Its only try_install packages (pipewire-pulse,
|
||||
# pipewire-alsa) are already in packages.x86_64 and installed by
|
||||
# unpackfs, so the step did nothing useful even when it succeeded.
|
||||
# archiso strips the kernel from the squashfs; stage it, drop the archiso
|
||||
# initramfs config, and write a stock mkinitcpio preset before initcpio runs.
|
||||
- shellprocess@kernel
|
||||
|
|
|
|||
26
iso/airootfs/etc/greetd/breadgreet.example.toml
Normal file
26
iso/airootfs/etc/greetd/breadgreet.example.toml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# breadgreet commonly runs as the dedicated `greeter` system user (per
|
||||
# greetd's own convention), so it checks /etc/greetd/breadgreet.toml first;
|
||||
# copy this there for a real install. For local dev/testing under a normal
|
||||
# user session it falls back to ~/.config/breadgreet/breadgreet.toml.
|
||||
#
|
||||
# Every field is optional and defaults to the value shown here.
|
||||
|
||||
[background]
|
||||
mode = "color"
|
||||
path = ""
|
||||
blur = false
|
||||
|
||||
[clock]
|
||||
format = "%H:%M"
|
||||
|
||||
[font]
|
||||
family = "Varela Round"
|
||||
|
||||
[sessions]
|
||||
# Directories scanned for .desktop session entries, in order.
|
||||
wayland_dirs = ["/usr/share/wayland-sessions"]
|
||||
xsessions_dirs = ["/usr/share/xsessions"]
|
||||
# .desktop file stem (without extension) to auto-select. Falls back to the
|
||||
# first entry found if this isn't present. v1 has no session picker UI —
|
||||
# BOS only ships one session (Hyprland) today.
|
||||
default = "hyprland"
|
||||
15
iso/airootfs/etc/greetd/breadgreet.toml
Normal file
15
iso/airootfs/etc/greetd/breadgreet.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# BOS's real breadgreet config — see breadgreet.example.toml in this same
|
||||
# directory for the full set of options with explanations.
|
||||
#
|
||||
# The one setting that actually matters here: `sessions.default` MUST be
|
||||
# "bos", not breadgreet's compiled-in default of "hyprland". The `hyprland`
|
||||
# pacman package installs its own /usr/share/wayland-sessions/hyprland.desktop
|
||||
# alongside BOS's own bos.desktop, and breadgreet's session picker matches by
|
||||
# .desktop file stem — with no override it picks "hyprland.desktop" over
|
||||
# "bos.desktop", which skips bos-session's PATH fixup (adds ~/.local/bin for
|
||||
# the bakery bread apps; greetd starts no login shell, so /etc/profile.d is
|
||||
# never sourced any other way). Confirmed via breadgreet's own test suite
|
||||
# (sessions.rs: discover_prefers_configured_default_over_first_entry).
|
||||
|
||||
[sessions]
|
||||
default = "bos"
|
||||
|
|
@ -2,11 +2,15 @@
|
|||
# squashfs and enabled by post-install.sh; the live ISO instead autologins
|
||||
# liveuser on tty1 (see getty@tty1 drop-in) so the installer comes straight up.
|
||||
#
|
||||
# tuigreet shows a minimal greeter, then launches the BOS Hyprland session via
|
||||
# bos-session (which fixes up PATH for the bakery bread apps).
|
||||
# breadgreet (bread-ecosystem's own greeter) is hosted under cage — a single-
|
||||
# client kiosk Wayland compositor, since greetd itself has no display of its
|
||||
# own — and speaks greetd's IPC directly. It resolves the session to launch
|
||||
# from /usr/share/wayland-sessions/bos.desktop, which points at bos-session
|
||||
# (fixes up PATH for the bakery bread apps; greetd starts no login shell, so
|
||||
# /etc/profile.d is never sourced otherwise).
|
||||
[terminal]
|
||||
vt = 1
|
||||
|
||||
[default_session]
|
||||
command = "tuigreet --remember --time --cmd /usr/local/bin/bos-session"
|
||||
command = "cage -s -- breadgreet"
|
||||
user = "greeter"
|
||||
|
|
|
|||
|
|
@ -9,4 +9,3 @@ DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
|||
SUPPORT_URL="https://bbs.archlinux.org/"
|
||||
BUG_REPORT_URL="https://git.breadway.dev/Breadway/bos/issues"
|
||||
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
|
||||
LOGO=archlinux-logo
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
// Allow members of the wheel group to perform snapper rollback via pkexec
|
||||
// without a password prompt. Other snapper operations (list/create/delete)
|
||||
// are controlled by ALLOW_USERS in /etc/snapper/configs/root.
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "io.opensuse.Snapper.Rollback" &&
|
||||
subject.local &&
|
||||
subject.active &&
|
||||
subject.isInGroup("wheel")) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
|
|
@ -1 +1,5 @@
|
|||
bread.activate_profile("default")
|
||||
bread.once("bread.system.startup", function()
|
||||
bread.profile.activate("default")
|
||||
end)
|
||||
|
||||
return bread
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
[[profile]]
|
||||
name = "home"
|
||||
ssids = []
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Copy to ~/.config/breadlock/breadlock.toml — every field is optional and
|
||||
# defaults to the value shown here if omitted or the file doesn't exist.
|
||||
|
||||
[background]
|
||||
# "color" (bread-theme palette background) or "image" (a PNG, cover-fit)
|
||||
mode = "color"
|
||||
path = ""
|
||||
# v2 feature — accepted but currently just logs a warning and shows the
|
||||
# background unblurred (needs a wlr-screencopy capture, not implemented yet).
|
||||
blur = false
|
||||
|
||||
[clock]
|
||||
# strftime format
|
||||
format = "%H:%M"
|
||||
|
||||
[font]
|
||||
family = "Varela Round"
|
||||
|
||||
[input]
|
||||
# How long the "wrong password" state (red pill) shows before input
|
||||
# re-enables, in milliseconds.
|
||||
fail_timeout_ms = 800
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
# playback, etc. won't dim or suspend the machine). Vendor-neutral: nothing here
|
||||
# is Intel/AMD specific.
|
||||
general {
|
||||
lock_cmd = pidof hyprlock || hyprlock
|
||||
lock_cmd = pidof breadlock || breadlock
|
||||
before_sleep_cmd = loginctl lock-session
|
||||
after_sleep_cmd = hyprctl dispatch dpms on
|
||||
ignore_dbus_inhibit = false
|
||||
|
|
|
|||
|
|
@ -124,10 +124,15 @@ hl.bind(mod .. " + comma", hl.dsp.exec_cmd("bos-settings"))
|
|||
hl.bind(mod .. " + slash", hl.dsp.exec_cmd("bos-keybinds"))
|
||||
hl.bind(mod .. " + L", hl.dsp.exec_cmd("loginctl lock-session"))
|
||||
hl.bind(mod .. " + F", hl.dsp.window.fullscreen({ action = "toggle" }))
|
||||
hl.bind(mod .. " + V", hl.dsp.window.float({ action = "toggle" }))
|
||||
hl.bind(mod .. " + I", hl.dsp.window.float({ action = "toggle" }))
|
||||
hl.bind(mod .. " + P", hl.dsp.window.pseudo({ action = "toggle" }))
|
||||
hl.bind(mod .. " + R", hl.dsp.window.resize())
|
||||
-- breadclip (its own gtk4-layer-shell popup — not a TUI, so no terminal
|
||||
-- needed). Previously piped cliphist through fzf directly from the
|
||||
-- compositor with no terminal attached, which was a silent no-op.
|
||||
-- Bound on both V (breadclip's own suggested default, freed up now that
|
||||
-- float toggle moved to I) and SHIFT+V (kept for muscle memory).
|
||||
hl.bind(mod .. " + V", hl.dsp.exec_cmd("breadclip"))
|
||||
hl.bind(mod .. " + SHIFT + V", hl.dsp.exec_cmd("breadclip"))
|
||||
hl.bind(mod .. " + T", hl.dsp.layout("togglesplit"))
|
||||
hl.bind(mod .. " + Tab", hl.dsp.focus({ urgent_or_last = true }))
|
||||
|
|
@ -185,6 +190,7 @@ hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"
|
|||
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true })
|
||||
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true })
|
||||
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
|
||||
hl.bind("XF86Calculator", hl.dsp.exec_cmd("gnome-calculator"))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Autostart. polkit agent + the bread ecosystem + idle daemon + wallpaper.
|
||||
|
|
@ -206,8 +212,12 @@ hl.on("hyprland.start", function()
|
|||
-- rather than an exec-once here.
|
||||
"/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1",
|
||||
"awww-daemon",
|
||||
-- set the default wallpaper once the daemon is up (retry until ready)
|
||||
[[bash -c 'until awww img /usr/share/backgrounds/bos/bread-background.png 2>/dev/null; do sleep 0.3; done']],
|
||||
-- Set the default wallpaper once the daemon is up (retry until
|
||||
-- ready) via `breadpaper set`, not raw `awww img` — breadpaper also
|
||||
-- generates the pywal palette and reloads bread-theme, and records
|
||||
-- the path so `breadpaper get` (and its bos-settings panel) show
|
||||
-- the real default instead of "No wallpaper set" on a fresh install.
|
||||
[[bash -c 'until breadpaper set /usr/share/backgrounds/bos/bread-background.png 2>/dev/null; do sleep 0.3; done']],
|
||||
-- breadd runs as a systemd user service (~/.config/systemd/user/breadd.service,
|
||||
-- enabled in skel). It autostarts at login but before Hyprland exists, so
|
||||
-- push the compositor's Wayland env into the user manager and restart breadd
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
# Lock screen (hyprlock). Solid dark background (no runtime-generated wallpaper
|
||||
# dependency), accent matched to the Hyprland border colour.
|
||||
general {
|
||||
hide_cursor = true
|
||||
}
|
||||
|
||||
background {
|
||||
monitor =
|
||||
color = rgba(46, 52, 64, 1.0)
|
||||
blur_passes = 0
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor =
|
||||
size = 20%, 5%
|
||||
outline_thickness = 3
|
||||
inner_color = rgba(0, 0, 0, 0.2)
|
||||
outer_color = rgba(136, 192, 208, 0.8)
|
||||
check_color = rgba(120, 220, 140, 0.95)
|
||||
fail_color = rgba(255, 90, 90, 0.95)
|
||||
font_color = rgba(255, 255, 255, 0.95)
|
||||
fade_on_empty = false
|
||||
rounding = 12
|
||||
placeholder_text = <i>Password…</i>
|
||||
position = 0, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[Desktop Entry]
|
||||
Name=breadclip
|
||||
Comment=Clipboard history
|
||||
Exec=breadclip
|
||||
Icon=edit-paste
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
StartupWMClass=breadclip
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[Desktop Entry]
|
||||
Name=breadman
|
||||
Comment=Notes and reminders manager
|
||||
Exec=breadman
|
||||
Icon=accessories-text-editor
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;Office;
|
||||
StartupWMClass=breadman
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[Desktop Entry]
|
||||
Name=breadmon
|
||||
Comment=Monitor layout manager (TUI)
|
||||
Exec=breadmon
|
||||
Icon=video-display
|
||||
Terminal=true
|
||||
Type=Application
|
||||
Categories=Settings;System;
|
||||
StartupWMClass=breadmon
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[Desktop Entry]
|
||||
Name=breadsearch
|
||||
Comment=Semantic system-wide search
|
||||
Exec=breadsearch
|
||||
Icon=system-search
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
StartupWMClass=breadsearch
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Auto-start Hyprland on tty1 in the live session
|
||||
if [[ "$(tty)" == "/dev/tty1" ]] && [[ -z "$WAYLAND_DISPLAY" ]]; then
|
||||
# Allow a software-rendering fallback so the live session comes up even
|
||||
# without a GPU (VMs, headless, exotic hardware). On real hardware wlroots
|
||||
# still selects the hardware renderer; this only permits llvmpipe when no
|
||||
# GPU renderer is available. Must be exported before Hyprland starts —
|
||||
# wlroots reads it at renderer init, earlier than any Hyprland `env=` line.
|
||||
export WLR_RENDERER_ALLOW_SOFTWARE=1
|
||||
# Software cursors: hardware-cursor planes are often unusable in VMs and
|
||||
# show as invisible/garbled; this is the reliable choice for a live medium.
|
||||
export WLR_NO_HARDWARE_CURSORS=1
|
||||
# Run the compositor, capturing its output so a failed live boot is
|
||||
# diagnosable (Hyprland also keeps its own log under $XDG_RUNTIME_DIR/hypr/).
|
||||
# On exit, drop to an interactive shell with the error in view instead of
|
||||
# letting the getty autologin respawn-loop hide it behind a blank cursor.
|
||||
Hyprland &>/var/log/hyprland-live.log
|
||||
echo "Hyprland exited (rc=$?). Log: /var/log/hyprland-live.log"
|
||||
exec bash -i
|
||||
fi
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
# Live-session Hyprland config — launches Calamares on start.
|
||||
# This is NOT the installed system config; that lives in dotfiles/hypr/.
|
||||
|
||||
monitor=,preferred,auto,1
|
||||
|
||||
exec-once = calamares
|
||||
|
||||
general {
|
||||
border_size = 2
|
||||
col.active_border = rgba(88c0d0ff)
|
||||
col.inactive_border = rgba(4c566aff)
|
||||
}
|
||||
|
||||
decoration {
|
||||
rounding = 4
|
||||
}
|
||||
|
||||
input {
|
||||
kb_layout = us
|
||||
follow_mouse = 1
|
||||
}
|
||||
|
||||
misc {
|
||||
disable_hyprland_logo = true
|
||||
disable_splash_rendering = true
|
||||
# Keep compositor running if calamares exits (user can relaunch)
|
||||
exit_window_request_force = false
|
||||
}
|
||||
|
|
@ -18,16 +18,18 @@ if ! id liveuser &>/dev/null; then
|
|||
passwd -d liveuser >/dev/null
|
||||
fi
|
||||
|
||||
# Layer the installer onto the live desktop: auto-launch it, and bind Super+I to
|
||||
# relaunch it after it's been closed. Appended (in Lua) to the skel hyprland.lua
|
||||
# native config so the full desktop stays intact.
|
||||
# Layer the installer onto the live desktop: auto-launch it, and bind
|
||||
# Super+Shift+I to relaunch it after it's been closed. Appended (in Lua) to
|
||||
# the skel hyprland.lua native config so the full desktop stays intact.
|
||||
# NOTE: plain SUPER+I is float-toggle in the skel config — don't reuse it
|
||||
# here, it was tried once and silently double-bound both actions.
|
||||
HYPR=/home/liveuser/.config/hypr/hyprland.lua
|
||||
install -d -m 0755 -o liveuser -g liveuser /home/liveuser/.config/hypr
|
||||
if ! grep -q bos-launch-calamares "$HYPR" 2>/dev/null; then
|
||||
cat >>"$HYPR" <<'EOF'
|
||||
|
||||
-- --- live-media installer (added by bos-live-setup; absent on installed system) ---
|
||||
hl.bind("SUPER + I", hl.dsp.exec_cmd("bos-launch-calamares"))
|
||||
hl.bind("SUPER + SHIFT + I", hl.dsp.exec_cmd("bos-launch-calamares"))
|
||||
hl.on("hyprland.start", function() hl.dispatch(hl.dsp.exec_cmd("bos-launch-calamares")) end)
|
||||
EOF
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,24 +1,36 @@
|
|||
#!/bin/bash
|
||||
# First-run welcome. Shows a short getting-started message once, then drops a
|
||||
# marker so it never shows again. Launched from the Hyprland autostart; the
|
||||
# bos-welcome window class is floated/centred by a Hyprland window rule.
|
||||
# First-run welcome + first-run/every-login network check. Launched from the
|
||||
# Hyprland autostart; the bos-welcome window class is floated/centred by a
|
||||
# Hyprland window rule.
|
||||
set -u
|
||||
|
||||
# Never run in the live/installer session — only on an installed system.
|
||||
[[ "$(id -un)" == "liveuser" ]] && exit 0
|
||||
|
||||
marker="${XDG_CONFIG_HOME:-$HOME/.config}/bos/.welcomed"
|
||||
[[ -f "$marker" ]] && exit 0
|
||||
mkdir -p "$(dirname "$marker")"
|
||||
welcomed_marker="${XDG_CONFIG_HOME:-$HOME/.config}/bos/.welcomed"
|
||||
mkdir -p "$(dirname "$welcomed_marker")"
|
||||
|
||||
# First-run network check. A fresh install usually boots with no connection
|
||||
# (Wi-Fi isn't configured during install), and the first `bos-update`/pacman run
|
||||
# Network check. A fresh install usually boots with no connection (Wi-Fi
|
||||
# isn't configured during install), and the first `bos-update`/pacman run
|
||||
# then fails with confusing DNS/"could not resolve host" errors. If
|
||||
# NetworkManager reports we're not fully online, open nmtui so the user can join
|
||||
# a network before anything else. Best-effort: missing nmcli/nmtui/kitty, or the
|
||||
# user quitting nmtui, must never block the welcome below.
|
||||
# NetworkManager reports we're not fully online, open nmtui so the user can
|
||||
# join a network before anything else. This runs on EVERY login, not just
|
||||
# the first, and isn't gated by any marker — it keeps re-prompting until the
|
||||
# machine is actually online, then naturally stops (the "full" check below
|
||||
# short-circuits). Best-effort: missing nmcli/nmtui/kitty, or the user
|
||||
# quitting nmtui, must never block the welcome text below.
|
||||
if command -v nmcli &>/dev/null; then
|
||||
conn="$(nmcli networking connectivity check 2>/dev/null)"
|
||||
# NetworkManager may still be associating right at compositor start —
|
||||
# give it a few short retries before concluding we're actually offline,
|
||||
# so a machine with working Wi-Fi doesn't get a spurious nmtui popup.
|
||||
tries=0
|
||||
while [[ "$conn" != "full" && "$tries" -lt 3 ]]; do
|
||||
sleep 1
|
||||
conn="$(nmcli networking connectivity check 2>/dev/null)"
|
||||
tries=$((tries + 1))
|
||||
done
|
||||
|
||||
if [[ "$conn" != "full" ]]; then
|
||||
notify-send -u normal "BOS" "No internet yet — opening network setup so updates work." 2>/dev/null || true
|
||||
if command -v nmtui &>/dev/null; then
|
||||
|
|
@ -27,8 +39,10 @@ if command -v nmcli &>/dev/null; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# Mark welcomed only now, so an interrupted/aborted network step still re-prompts
|
||||
# next login rather than being suppressed forever.
|
||||
touch "$marker"
|
||||
# Welcome text: shown once ever, independent of network status above (an
|
||||
# offline machine still gets useful onboarding text — it just also keeps
|
||||
# getting the network prompt on future logins until it connects).
|
||||
[[ -f "$welcomed_marker" ]] && exit 0
|
||||
touch "$welcomed_marker"
|
||||
|
||||
exec kitty --class bos-welcome --title "Welcome to BOS" -- less -R /usr/share/bos/welcome.txt
|
||||
|
|
|
|||
|
|
@ -10,14 +10,16 @@
|
|||
SUPER + E files (nautilus)
|
||||
SUPER + B browser (zen)
|
||||
SUPER + U notes / reminders (breadpad)
|
||||
SUPER + M package manager (breadman)
|
||||
SUPER + M notes / task manager (breadman)
|
||||
SUPER + , BOS Settings
|
||||
SUPER + / this keybind cheatsheet
|
||||
SUPER + L lock screen
|
||||
SUPER + Backspace close window
|
||||
SUPER + F fullscreen
|
||||
SUPER + V toggle floating
|
||||
SUPER + Shift + V clipboard history
|
||||
SUPER + I toggle floating
|
||||
SUPER + P toggle pseudotile
|
||||
SUPER + R resize mode
|
||||
SUPER + V / Shift + V clipboard history (breadclip)
|
||||
SUPER + T toggle split direction
|
||||
SUPER + Tab last window
|
||||
SUPER + N exit Hyprland (log out)
|
||||
|
|
@ -45,6 +47,7 @@
|
|||
|
||||
MEDIA & HARDWARE KEYS
|
||||
volume / brightness / play-pause / next / prev (work on lock screen)
|
||||
calculator key opens gnome-calculator
|
||||
|
||||
──────────────────────────────────────────────────────────
|
||||
Press q to close. Configure everything in BOS Settings (SUPER + ,).
|
||||
|
|
|
|||
5
iso/airootfs/usr/share/wayland-sessions/bos.desktop
Normal file
5
iso/airootfs/usr/share/wayland-sessions/bos.desktop
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[Desktop Entry]
|
||||
Name=BOS
|
||||
Comment=Bread OS (Hyprland)
|
||||
Exec=/usr/local/bin/bos-session
|
||||
Type=Application
|
||||
Loading…
Add table
Add a link
Reference in a new issue