Draw a wallpaper on a machine that has no theme yet

Seeding the config gets the bar and the keybindings up, and then leaves
you looking at a black screen, because the autostart line that sets the
wallpaper named ~/.local/share/wallpapers/hyprcosmic/current directly.
That is a symlink import-theme --assets maintains, so it does not exist
until a theme has been imported -- which on a machine that has just
installed the package it has not.

The same line waited for the daemon with an unbounded loop:

    until awww query >/dev/null 2>&1; do sleep 0.2; done

awww is a Recommends and lives in a COPR, so on a machine that never
enabled that repository nothing ever answered and the loop spun at 5 Hz
for the length of the session.

Both now live in hyprcosmic-wallpaper, which falls back to the
distribution's own images when there is no link yet, gives up on the
daemon after ten seconds, and exits 0 on every path so autostart is never
left supervising a process that cannot finish. Fedora recommends
cosmic-wallpapers so the fallback has something to find; nothing in the
dependency chain pulled it in before.

Verified against all five paths: no awww at all, a daemon that never
answers, a fresh machine with no link, a link pointing at a real file,
and a link left dangling by a deleted theme.
This commit is contained in:
2026-08-11 18:25:24 +07:00
parent 111f3ade7b
commit e006e95e55
5 changed files with 113 additions and 16 deletions
+9
View File
@@ -195,6 +195,15 @@ Runtime dependencies of the shell itself are not COSMIC's and are not built
here: `waybar`, `rofi` (wayland build), `awww` (formerly `swww`), and a Nerd here: `waybar`, `rofi` (wayland build), `awww` (formerly `swww`), and a Nerd
Font for the glyphs the bar and the launcher draw with. Font for the glyphs the bar and the launcher draw with.
The wallpaper is `awww`'s job, and the image it draws is
`~/.local/share/wallpapers/hyprcosmic/current` — a symlink `import-theme
--assets` maintains. Before you have imported a theme there is no such link, so
`hyprcosmic-wallpaper` falls back to whatever the distribution ships,
`/usr/share/backgrounds/cosmic` first; the Fedora package recommends
`cosmic-wallpapers` so there is something there. With no `awww` installed it
says so on the session log and leaves the background alone, rather than waiting
for a daemon that is never coming.
The font is the one thing the packaging cannot do for you on Fedora, which has The font is the one thing the packaging cannot do for you on Fedora, which has
no package that provides a Nerd Font at all: `texlive-inconsolata-nerd-font` no package that provides a Nerd Font at all: `texlive-inconsolata-nerd-font`
installs under `texmf-dist` and kitty's `SymbolsNerdFont` under installs under `texmf-dist` and kitty's `SymbolsNerdFont` under
+14 -16
View File
@@ -60,28 +60,26 @@ awww-daemon
# get a blank screen below the bar with no error anywhere: the failure is that # get a blank screen below the bar with no error anywhere: the failure is that
# nobody asked for a wallpaper, so nothing reports one missing. # nobody asked for a wallpaper, so nothing reports one missing.
# #
# `sh -c` rather than a bare `awww img`, for one reason: awww-daemon above has # It sets ~/.local/share/wallpapers/hyprcosmic/current, a symlink
# only just been forked and is not listening yet, so an immediate `awww img` # `hyprcosmic-conf import-theme --assets` maintains beside the wallpapers it
# loses a race and fails silently. The loop waits for the daemon to answer # copies. The link is used rather than a real path so that this and rofi's
# before setting the image. # local.rasi -- which shows the same image in the launcher's sidebar -- cannot
# drift apart, and so that importing a different theme does not leave either
# pointing at a file that no longer exists.
# #
# This does not weaken the no-shell rule in the header. That rule exists so a # Until a theme has been imported there is no such link, so on a machine that
# file naming programs cannot be escalated into arbitrary execution; naming # has just installed the package it falls back to whatever the distribution
# `sh` explicitly is just naming a program, and anyone able to write this file # ships, /usr/share/backgrounds/cosmic first. A first login gets a desktop.
# could already name any binary on the system.
#
# `current` is a symlink `cosmic-conf import-theme --assets` maintains beside
# the wallpapers it copies, pointing at one of them. It is named here rather
# than a real file so that this line and rofi's local.rasi -- which shows the
# same image in the launcher's sidebar -- cannot drift apart, and so that
# importing a different theme does not leave this pointing at a path that no
# longer exists.
# #
# Change the wallpaper by repointing the link, not by editing this file: # Change the wallpaper by repointing the link, not by editing this file:
# #
# ln -sfn ~/".local/share/wallpapers/hyprcosmic/<theme>/<image>" \ # ln -sfn ~/".local/share/wallpapers/hyprcosmic/<theme>/<image>" \
# ~/.local/share/wallpapers/hyprcosmic/current # ~/.local/share/wallpapers/hyprcosmic/current
sh -c 'until awww query >/dev/null 2>&1; do sleep 0.2; done; exec awww img "$HOME/.local/share/wallpapers/hyprcosmic/current"' #
# A program rather than the `sh -c` this used to be, because waiting for the
# daemon needs a bound: awww is a Recommends in a COPR, and the old unbounded
# `until awww query` loop spun for the whole session on a machine without it.
hyprcosmic-wallpaper
# A terminal, unconditionally, as the way back in. # A terminal, unconditionally, as the way back in.
# #
+81
View File
@@ -0,0 +1,81 @@
#!/bin/sh
# Set the desktop wallpaper once the wallpaper daemon is listening.
#
# The hyprcosmic profile does not start cosmic-bg, so nothing else draws a
# background: without this there is a black screen below the bar, and no error
# anywhere, because the failure is that nobody asked for a wallpaper.
#
# This was three shell fragments on one autostart line. It became a program for
# two reasons, both of which cost a first login its desktop:
#
# - `current` is a symlink `import-theme --assets` maintains, so it does not
# exist until a theme has been imported. Naming it directly meant a machine
# that had just installed the package set no wallpaper at all.
# - The wait for the daemon was `until awww query; do sleep 0.2; done`, with
# nothing to stop it. awww is a Recommends and lives in a COPR, so on a
# machine that never enabled that repository the loop spun at 5 Hz for the
# length of the session.
#
# Both are now bounded and both say so on the session log.
set -eu
link="${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers/hyprcosmic/current"
# Searched in order when the link is not there yet. The first is cosmic-wallpapers,
# which the Fedora package recommends for exactly this; the other two are where
# freedesktop and KDE put theirs, so a machine with neither still has a chance.
fallbacks='/usr/share/backgrounds/cosmic /usr/share/backgrounds /usr/share/wallpapers'
if ! command -v awww >/dev/null 2>&1; then
echo "hyprcosmic-wallpaper: awww is not installed; no wallpaper set" >&2
exit 0
fi
# awww-daemon is started immediately above this in autostart and has only just
# been forked, so an immediate `awww img` loses the race and fails silently.
# Ten seconds is far longer than the daemon has ever taken and short enough that
# a daemon which is never coming does not leave a process spinning all session.
tries=0
until awww query >/dev/null 2>&1; do
tries=$((tries + 1))
if [ "$tries" -ge 50 ]; then
echo "hyprcosmic-wallpaper: awww-daemon did not answer in 10s; no wallpaper set" >&2
exit 0
fi
sleep 0.2
done
# -e rather than -L, deliberately: it follows the link, so a `current` left
# dangling by a deleted theme falls through to the defaults instead of being
# handed to awww as a path that is not there.
img=''
if [ -e "$link" ]; then
img=$link
else
for dir in $fallbacks; do
[ -d "$dir" ] || continue
for candidate in "$dir"/*.jpg "$dir"/*.jpeg "$dir"/*.png; do
# The glob is literal when nothing matches, which is why
# this tests the file rather than trusting the expansion.
[ -f "$candidate" ] || continue
img=$candidate
break
done
# An if, not `[ -n "$img" ] && break`: under set -e a trailing
# false at the end of the loop body would take the script with it.
if [ -n "$img" ]; then
break
fi
done
if [ -n "$img" ]; then
echo "hyprcosmic-wallpaper: no $link yet, falling back to $img" >&2
fi
fi
if [ -z "$img" ]; then
echo "hyprcosmic-wallpaper: no wallpaper found in $link or $fallbacks" >&2
exit 0
fi
exec awww img "$img"
+8
View File
@@ -81,6 +81,14 @@ Requires: rofi-wayland
# unsatisfiable dependency is not. # unsatisfiable dependency is not.
Recommends: awww Recommends: awww
# Something for the wallpaper daemon to draw before a theme has been imported.
# hyprcosmic-wallpaper looks here first when ~/.local/share/wallpapers has no
# `current` link yet, which on a machine that has just installed this package is
# always. Nothing in the dependency chain pulls it in otherwise -- neither
# cosmic-session nor cosmic-comp requires it -- and without it a first login is
# a bar on a black screen.
Recommends: cosmic-wallpapers
# Nerd Font glyphs are most of what the bar and the launcher draw, and Fedora # Nerd Font glyphs are most of what the bar and the launcher draw, and Fedora
# has nothing that provides them. This line used to say `nerd-fonts`, which is # has nothing that provides them. This line used to say `nerd-fonts`, which is
# not a package in any Fedora repository -- so it could never be satisfied, and # not a package in any Fedora repository -- so it could never be satisfied, and
+1
View File
@@ -78,6 +78,7 @@ SHARED=(
"config/bin/hyprcosmic-powermenu:bin/hyprcosmic-powermenu:755" "config/bin/hyprcosmic-powermenu:bin/hyprcosmic-powermenu:755"
"config/bin/hyprcosmic-fan:bin/hyprcosmic-fan:755" "config/bin/hyprcosmic-fan:bin/hyprcosmic-fan:755"
"config/bin/hyprcosmic-keybinds:bin/hyprcosmic-keybinds:755" "config/bin/hyprcosmic-keybinds:bin/hyprcosmic-keybinds:755"
"config/bin/hyprcosmic-wallpaper:bin/hyprcosmic-wallpaper:755"
) )
# The session entry point. Kept apart from SHARED because it is versioned in the # The session entry point. Kept apart from SHARED because it is versioned in the