Compare commits

...
4 Commits
19 changed files with 189 additions and 26 deletions
+2 -1
View File
@@ -2,7 +2,8 @@
# blob:summary=Launch the Blob screensaver in the default terminal on the system with the correct font configuration. # blob:summary=Launch the Blob screensaver in the default terminal on the system with the correct font configuration.
if blob-cmd-missing ttfx; then if ! blob-screensaver-effect >/dev/null; then
blob-notify-send -g ✋ "Screensaver needs ttfx or tte" "Install python-terminaltexteffects."
exit 1 exit 1
fi fi
+28 -5
View File
@@ -2,13 +2,37 @@
# blob:summary=Run the Blob screensaver using random effects from TTE. # blob:summary=Run the Blob screensaver using random effects from TTE.
effect_command=$(blob-screensaver-effect) || exit 1
effect_args() {
local input="$HOME/.config/blob/branding/screensaver.txt"
if [[ $effect_command == "ttfx" ]]; then
printf '%s\n' -i "$input" --frame-rate 120 --canvas-width 0 --canvas-height 0 \
--reuse-canvas --anchor-canvas c --anchor-text c --random-effect --no-eol \
--no-restore-cursor
return 0
fi
local effects=(
beams binarypath blackhole bouncyballs bubbles burn colorshift crumble
decrypt errorcorrect expand fireworks middleout orbittingvolley overflow
pour print rain randomsequence rings scattered slice slide spotlights
spray swarm sweep synthgrid unstable vhstape waves wipe
)
printf '%s\n' -i "$input" --frame-rate 120 --canvas-width 0 --canvas-height 0 \
--anchor-canvas c --anchor-text c --no-color \
"${effects[RANDOM % ${#effects[@]}]}"
}
screensaver_in_focus() { screensaver_in_focus() {
hyprctl activewindow -j | jq -e '.class == "org.blob.screensaver"' >/dev/null 2>&1 hyprctl activewindow -j | jq -e '.class == "org.blob.screensaver"' >/dev/null 2>&1
} }
exit_screensaver() { exit_screensaver() {
hyprctl eval 'hl.config({ cursor = { invisible = false } })' &>/dev/null || hyprctl keyword cursor:invisible false &>/dev/null || true hyprctl eval 'hl.config({ cursor = { invisible = false } })' &>/dev/null || hyprctl keyword cursor:invisible false &>/dev/null || true
pkill -x ttfx 2>/dev/null pkill -x "$effect_command" 2>/dev/null
pkill -f '[o]rg.blob.screensaver' 2>/dev/null pkill -f '[o]rg.blob.screensaver' 2>/dev/null
exit 0 exit 0
} }
@@ -36,11 +60,10 @@ wait_for_terminal_resize() {
wait_for_terminal_resize wait_for_terminal_resize
while true; do while true; do
ttfx -i ~/.config/blob/branding/screensaver.txt \ mapfile -t effect_arguments < <(effect_args)
--frame-rate 120 --canvas-width 0 --canvas-height 0 --reuse-canvas --anchor-canvas c --anchor-text c\ "$effect_command" "${effect_arguments[@]}" &
--random-effect --no-eol --no-restore-cursor &
while pgrep -t "${tty#/dev/}" -x ttfx >/dev/null; do while pgrep -t "${tty#/dev/}" -x "$effect_command" >/dev/null; do
if read -n1 -t 1 || ! screensaver_in_focus; then if read -n1 -t 1 || ! screensaver_in_focus; then
exit_screensaver exit_screensaver
fi fi
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
# blob:summary=Print the terminal text effects command the screensaver can use
# blob:hidden=true
for candidate in ttfx tte; do
if command -v "$candidate" &>/dev/null; then
printf '%s\n' "$candidate"
exit 0
fi
done
exit 1
+4 -3
View File
@@ -20,7 +20,8 @@ if pgrep -x "1password" >/dev/null && blob-cmd-present 1password; then
fi fi
# Avoid running screensaver when locked # Avoid running screensaver when locked
pkill -x ttfx 2>/dev/null || true effect_command=$(blob-screensaver-effect 2>/dev/null) && {
# ttfx handles SIGTERM asynchronously, so keep its terminal alive until it exits. pkill -x "$effect_command" 2>/dev/null || true
timeout 1s pidwait -x ttfx 2>/dev/null || true timeout 1s pidwait -x "$effect_command" 2>/dev/null || true
}
pkill -f '[o]rg.blob.screensaver' 2>/dev/null || true pkill -f '[o]rg.blob.screensaver' 2>/dev/null || true
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="pattern">
<test name="family" qual="any">
<string>monospace</string>
</test>
<edit name="family" mode="prepend_first" binding="strong">
<string>JetBrainsMono Nerd Font</string>
</edit>
</match>
</fontconfig>
+2
View File
@@ -0,0 +1,2 @@
#%PAM-1.0
auth include system-auth
+2 -2
View File
@@ -14,7 +14,7 @@ theme[hi_fg]="{{ accent }}"
theme[selected_bg]="{{ selection }}" theme[selected_bg]="{{ selection }}"
# Foreground color of selected item in processes box # Foreground color of selected item in processes box
theme[selected_fg]="{{ accent }}" theme[selected_fg]="{{ selection_foreground }}"
# Color of inactive/disabled text # Color of inactive/disabled text
theme[inactive_fg]="{{ muted }}" theme[inactive_fg]="{{ muted }}"
@@ -23,7 +23,7 @@ theme[inactive_fg]="{{ muted }}"
theme[graph_text]="{{ light_foreground }}" theme[graph_text]="{{ light_foreground }}"
# Background color of the percentage meters # Background color of the percentage meters
theme[meter_bg]="{{ selection }}" theme[meter_bg]="{{ lighter_background }}"
# Misc colors for processes box including mini cpu graphs, details memory graph and details status text # Misc colors for processes box including mini cpu graphs, details memory graph and details status text
theme[proc_misc]="{{ light_foreground }}" theme[proc_misc]="{{ light_foreground }}"
@@ -1,31 +1,41 @@
add_newline = true add_newline = true
command_timeout = 200 command_timeout = 200
format = "[$directory$git_branch$git_status]($style)$character" format = "[$directory$git_branch$git_status]($style)$character"
palette = "blob"
[palettes.blob]
accent = "{{ accent }}"
foreground = "{{ foreground }}"
muted = "{{ muted }}"
success = "{{ green }}"
warning = "{{ yellow }}"
error = "{{ red }}"
[character] [character]
error_symbol = "[✗](bold cyan)" error_symbol = "[✗](bold error)"
success_symbol = "[](bold cyan)" success_symbol = "[](bold accent)"
[directory] [directory]
style = "foreground"
truncation_length = 2 truncation_length = 2
truncation_symbol = "…/" truncation_symbol = "…/"
repo_root_style = "bold cyan" repo_root_style = "bold accent"
repo_root_format = "[$repo_root]($repo_root_style)[$path]($style)[$read_only]($read_only_style) " repo_root_format = "[$repo_root]($repo_root_style)[$path]($style)[$read_only]($read_only_style) "
[git_branch] [git_branch]
format = "[$branch]($style) " format = "[$branch]($style) "
style = "italic cyan" style = "italic accent"
[git_status] [git_status]
format = '[$all_status]($style)' format = '[$all_status]($style)'
style = "cyan" style = "warning"
ahead = "⇡${count} " ahead = "⇡${count} "
diverged = "⇕⇡${ahead_count}⇣${behind_count} " diverged = "⇕⇡${ahead_count}⇣${behind_count} "
behind = "⇣${count} " behind = "⇣${count} "
conflicted = " " conflicted = " "
up_to_date = " " up_to_date = " "
untracked = "? " untracked = "? "
modified = " " modified = " "
stashed = "" stashed = ""
staged = "" staged = ""
renamed = "" renamed = ""
+24 -1
View File
@@ -35,7 +35,17 @@ with `--check`.
resolves cannot cost you the other hundred and the config, service and login resolves cannot cost you the other hundred and the config, service and login
steps below. See [packages.md](packages.md). steps below. See [packages.md](packages.md).
4. **Config** is copied into `~/.config`: `hypr/`, the themed app configs, 4. **Config** is copied into `~/.config`: `hypr/`, the themed app configs,
`blob/shell.json`, the uwsm environment, and the icon font. `blob/shell.json`, the uwsm environment, `fontconfig/fonts.conf`, and the
icon font, and the font cache is refreshed. The shell draws every icon as a
Nerd Font glyph in the `monospace` family, and on a fresh Arch install
fontconfig resolves that to a font with no such glyphs, so the bar and its
panels come up full of blanks. `fonts.conf` binds `monospace` to
`JetBrainsMono Nerd Font`; `blob font set` rewrites the same file, and the
installer then reports it as a local change and keeps your choice.
`~/.bashrc` gets one line sourcing `session/bashrc`, which is what starts
the starship prompt and puts `blob` on `PATH` in an interactive shell. The
line is added once, a `.bak` is kept, and a `~/.bashrc` that already has it
is left alone.
`session/profile.sh` also goes to `/etc/profile.d/blob.sh`, which sources `session/profile.sh` also goes to `/etc/profile.d/blob.sh`, which sources
`session/env-bootstrap` and is what puts `blob` on `PATH` in a login shell. `session/env-bootstrap` and is what puts `blob` on `PATH` in a login shell.
Without it `BLOB_PATH` and `$BLOB_PATH/bin` are only set by Without it `BLOB_PATH` and `$BLOB_PATH/bin` are only set by
@@ -87,6 +97,7 @@ with `--check`.
| `/etc/sddm.conf.d/zz-blob.conf` | Wayland greeter, run on Hyprland, stock theme, remember the last session | | `/etc/sddm.conf.d/zz-blob.conf` | Wayland greeter, run on Hyprland, stock theme, remember the last session |
| `/etc/sddm/hyprland-greeter.lua` | the greeter's own tiny Hyprland config | | `/etc/sddm/hyprland-greeter.lua` | the greeter's own tiny Hyprland config |
| `/usr/local/bin/blob-hw-gpu-accelerated` | the renderer check that config runs, where SDDM's user can read it | | `/usr/local/bin/blob-hw-gpu-accelerated` | the renderer check that config runs, where SDDM's user can read it |
| `/etc/pam.d/blob-lock-password` | the PAM stack the lock screen authenticates against |
The greeter config matters more than it looks: SDDM's stock Wayland greeter The greeter config matters more than it looks: SDDM's stock Wayland greeter
runs on `weston`, which Blob does not install, so a default SDDM would fail runs on `weston`, which Blob does not install, so a default SDDM would fail
@@ -135,6 +146,18 @@ with `--check`.
| `--autologin` | skip the SDDM prompt for this user | | `--autologin` | skip the SDDM prompt for this user |
| `--no-launch` | leave the login screen for the next reboot | | `--no-launch` | leave the login screen for the next reboot |
## The lock screen
The lock plugin watches `/etc/pam.d/blob-lock-password` and refuses to lock at
all when it is not there - `blob system lock` returns `missing-pam` and nothing
appears, which reads as a keybinding that does nothing. The installer writes it;
it is one line including `system-auth`, the same stack every other Wayland
locker on Arch authenticates against.
Fingerprint unlock is separate and opt-in: `blob setup-security-fingerprint`
writes `/etc/pam.d/blob-lock-fingerprint`, and the lock only offers fingerprint
when that file and a reader are both present.
## Choosing a renderer ## Choosing a renderer
Hyprland renders through Mesa, and on an adapter Mesa has no driver for it exits Hyprland renders through Mesa, and on an adapter Mesa has no driver for it exits
+2 -1
View File
@@ -70,7 +70,7 @@ Two are worth knowing about:
``` ```
packages/blob.packages 121 packages from core, extra, multilib packages/blob.packages 121 packages from core, extra, multilib
packages/blob-aur.packages 10 packages with no official equivalent packages/blob-aur.packages 11 packages with no official equivalent
``` ```
Only missing packages are touched, through `pacman -S --needed` and Only missing packages are touched, through `pacman -S --needed` and
@@ -127,6 +127,7 @@ Omarchy's own package list, because they were installed by hand on this machine:
| Package | Needed by | | Package | Needed by |
| --- | --- | | --- | --- |
| `python-pywal16` | `blob-wallpaper-set`, palette extraction | | `python-pywal16` | `blob-wallpaper-set`, palette extraction |
| `python-terminaltexteffects` | `blob-screensaver`, the effects it draws |
| `awww` | the wallpaper daemon `blob-wallpaper-set` and `blob-theme-menu` drive | | `awww` | the wallpaper daemon `blob-wallpaper-set` and `blob-theme-menu` drive |
| `playerctl` | the quick settings media row | | `playerctl` | the quick settings media row |
+19 -4
View File
@@ -30,12 +30,13 @@ the shell and the CLI never disagree about what a slot means.
Each rendered file is picked up differently: `foot.ini` and `kitty.conf` by an Each rendered file is picked up differently: `foot.ini` and `kitty.conf` by an
`include` in the shipped terminal config, `hyprland.lua` through Hyprland's Lua `include` in the shipped terminal config, `hyprland.lua` through Hyprland's Lua
module path, `shell.toml` and `chromium.theme` read straight from the state module path, `shell.toml` and `chromium.theme` read straight from the state
directory, and `btop.theme`, `neovim.lua` and `gtk.css` through symlinks the directory, and `btop.theme`, `neovim.lua`, `gtk.css` and `starship.toml`
installer makes into those apps' own config trees. through symlinks the installer makes into those apps' own config trees.
`default/themed/*.tpl` are rendered per theme into `default/themed/*.tpl` are rendered per theme into
`~/.local/state/blob/current/theme/`. Ten ship: foot, kitty, btop, chromium, `~/.local/state/blob/current/theme/`. Eleven ship: foot, kitty, btop, chromium,
hyprland, the screenshare picker, neovim, `shell.toml`, zen, and `gtk.css`. hyprland, the screenshare picker, neovim, `shell.toml`, zen, `gtk.css`, and
`starship.toml`.
An app picks its colors up in one of two ways. Most include the generated file An app picks its colors up in one of two ways. Most include the generated file
directly, so nothing has to run: directly, so nothing has to run:
@@ -65,6 +66,20 @@ so an app that was already open keeps its old colors until it is restarted.
Adding a template for another app means dropping a `.tpl` in `default/themed/` Adding a template for another app means dropping a `.tpl` in `default/themed/`
and, if it cannot include a file, adding an applier to that list. and, if it cannot include a file, adding an applier to that list.
## The prompt
`starship.toml` is linked to `~/.config/starship.toml`. It carries a
`[palettes.blob]` block built from the theme - `accent`, `foreground`, `muted`,
`success`, `warning`, `error` - and every style in the file names one of those
rather than a literal color, so the prompt moves with the theme. Starship reads
its config on each prompt, so a theme change shows up on the next command, in
shells that are already open.
`starship init bash` runs from `session/bashrc`, which `install.sh` sources from
`~/.bashrc` with a single line. That file returns immediately in a
non-interactive shell, so it cannot disturb `scp` or `rsync`, and it also
sources `session/env-bootstrap` so `blob` is on `PATH` in any interactive shell.
## The three ways to set a theme ## The three ways to set a theme
| Command | Does | | Command | Does |
+2
View File
@@ -63,7 +63,9 @@ link_blob_path
install_packages install_packages
install_shipped_config install_shipped_config
refresh_font_cache
install_shell_profile install_shell_profile
install_bash_integration
install_user_units install_user_units
install_systemd_dropins install_systemd_dropins
install_zen_config install_zen_config
+36
View File
@@ -63,6 +63,42 @@ install_shipped_config() {
install_file "$repo_dir/fonts/omarchy.ttf" "$font_dir/omarchy.ttf" "fonts/omarchy.ttf" install_file "$repo_dir/fonts/omarchy.ttf" "$font_dir/omarchy.ttf" "fonts/omarchy.ttf"
} }
bashrc_line='[ -r "$HOME/.local/share/blob/session/bashrc" ] && . "$HOME/.local/share/blob/session/bashrc"'
install_bash_integration() {
local bashrc="$HOME/.bashrc"
if [[ -f $bashrc ]] && grep -Fqx "$bashrc_line" "$bashrc"; then
say "ok bashrc"
return 0
fi
note_change
if [[ $check == true ]]; then
say "would source session/bashrc from ~/.bashrc"
return 0
fi
[[ -f $bashrc ]] && cp "$bashrc" "$bashrc.bak"
printf '\n%s\n' "$bashrc_line" >>"$bashrc"
say "write bashrc"
}
refresh_font_cache() {
if ! command -v fc-cache &>/dev/null; then
say "SKIP font cache (fc-cache not installed)"
return 0
fi
if [[ $check == true ]]; then
say "would refresh the font cache"
return 0
fi
fc-cache -f "$font_dir" >/dev/null 2>&1 || true
say "ok font cache"
}
install_shell_profile() { install_shell_profile() {
install_root_file "$repo_dir/session/profile.sh" /etc/profile.d/blob.sh "profile.d/blob.sh" install_root_file "$repo_dir/session/profile.sh" /etc/profile.d/blob.sh "profile.d/blob.sh"
} }
+2
View File
@@ -21,6 +21,8 @@ install_login_config() {
"$blob_greeter_conf" "sddm.conf.d/zz-blob.conf" "$blob_greeter_conf" "sddm.conf.d/zz-blob.conf"
install_root_file "$repo_dir/bin/blob-hw-gpu-accelerated" \ install_root_file "$repo_dir/bin/blob-hw-gpu-accelerated" \
"$greeter_gpu_detector" "blob-hw-gpu-accelerated" 0755 "$greeter_gpu_detector" "blob-hw-gpu-accelerated" 0755
install_root_file "$repo_dir/default/pam.d/blob-lock-password" \
/etc/pam.d/blob-lock-password "pam.d/blob-lock-password"
} }
install_session_entry() { install_session_entry() {
+1
View File
@@ -133,6 +133,7 @@ link_app_themes() {
link_theme_file btop.theme "$config_dir/btop/themes/current.theme" "btop theme" link_theme_file btop.theme "$config_dir/btop/themes/current.theme" "btop theme"
link_theme_file gtk.css "$config_dir/gtk-3.0/gtk.css" "gtk-3.0 theme" link_theme_file gtk.css "$config_dir/gtk-3.0/gtk.css" "gtk-3.0 theme"
link_theme_file gtk.css "$config_dir/gtk-4.0/gtk.css" "gtk-4.0 theme" link_theme_file gtk.css "$config_dir/gtk-4.0/gtk.css" "gtk-4.0 theme"
link_theme_file starship.toml "$config_dir/starship.toml" "starship prompt"
if [[ -d $config_dir/nvim/lua/plugins ]]; then if [[ -d $config_dir/nvim/lua/plugins ]]; then
link_theme_file neovim.lua "$config_dir/nvim/lua/plugins/theme.lua" "neovim theme" link_theme_file neovim.lua "$config_dir/nvim/lua/plugins/theme.lua" "neovim theme"
+3
View File
@@ -6,6 +6,9 @@
# Palette extraction behind blob-wallpaper-set; pywal16 is the maintained fork # Palette extraction behind blob-wallpaper-set; pywal16 is the maintained fork
python-pywal16|python-pywal python-pywal16|python-pywal
# Terminal text effects behind the screensaver; ttfx was the Omarchy build
python-terminaltexteffects
# Terminal dispatch; every TUI launcher's Exec= line calls it # Terminal dispatch; every TUI launcher's Exec= line calls it
xdg-terminal-exec xdg-terminal-exec
+8
View File
@@ -0,0 +1,8 @@
case $- in
*i*) ;;
*) return 0 ;;
esac
[ -r "$HOME/.local/share/blob/session/env-bootstrap" ] && . "$HOME/.local/share/blob/session/env-bootstrap"
command -v starship >/dev/null 2>&1 && eval "$(starship init bash)"
@@ -15,6 +15,13 @@ Item {
readonly property string pluginId: (manifest && manifest.id) || "blob.quick-settings" readonly property string pluginId: (manifest && manifest.id) || "blob.quick-settings"
readonly property int barInset: {
var bar = root.shell ? root.shell.bar : null
if (!bar || bar.barHidden === true) return 0
if (String(bar.position || "top") !== "top") return 0
return Math.max(0, bar.barSize || 0)
}
function open(payloadJson) { function open(payloadJson) {
root.opened = true root.opened = true
} }
@@ -187,7 +194,7 @@ Item {
Row { Row {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: Style.spaceReal(10) anchors.topMargin: Style.spaceReal(10) + root.barInset
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.spaceReal(12) spacing: Style.spaceReal(12)
+3
View File
@@ -9,6 +9,7 @@ session_entry="/usr/local/share/wayland-sessions/blob.desktop"
root_files=( root_files=(
/etc/profile.d/blob.sh /etc/profile.d/blob.sh
/usr/local/bin/blob-hw-gpu-accelerated /usr/local/bin/blob-hw-gpu-accelerated
/etc/pam.d/blob-lock-password
/etc/sddm.conf.d/zz-blob.conf /etc/sddm.conf.d/zz-blob.conf
/etc/sddm.conf.d/zzz-blob-autologin.conf /etc/sddm.conf.d/zzz-blob-autologin.conf
/etc/sddm/hyprland-greeter.conf /etc/sddm/hyprland-greeter.conf
@@ -112,6 +113,8 @@ for lua in hyprland.lua monitors.lua input.lua looknfeel.lua bindings.lua autost
restore_or_remove "$config_dir/hypr/$lua" "hypr/$lua" restore_or_remove "$config_dir/hypr/$lua" "hypr/$lua"
done done
[[ -L $config_dir/starship.toml ]] && restore_or_remove "$config_dir/starship.toml" "starship.toml"
for gtk in gtk-3.0 gtk-4.0; do for gtk in gtk-3.0 gtk-4.0; do
[[ -L $config_dir/$gtk/gtk.css ]] && restore_or_remove "$config_dir/$gtk/gtk.css" "$gtk/gtk.css" [[ -L $config_dir/$gtk/gtk.css ]] && restore_or_remove "$config_dir/$gtk/gtk.css" "$gtk/gtk.css"
done done