fix(waybar): launch from exec-once, not a systemd user service

Waybar vanished after a logout→login (no reboot): the bar's systemd user
service landed in `failed`. HM's Hyprland integration cycles
hyprland-session.target on every launch (exec-once stop && start), which
re-pulls WantedBy units — including waybar.service — very early, before
Hyprland's IPC socket is ready. Waybar's hyprland/workspaces & window
modules can't connect, so it exits non-zero and is never retried. A cold
boot's extra latency hid the race, so it only bit on warm relogins. The
non-IPC session services (swaync/hypridle/hyprsunset) survive the same
cycling fine, which is why night-light kept working.

Launch waybar from Hyprland's own exec-once instead (systemd.enable =
false). exec-once entries are dispatched once the compositor is up, so the
IPC socket is ready — the same reliable pattern awww-daemon, the wallpaper
sync and the keyboard watcher already use across relogins. Since the unit
no longer exists to be restarted on a home-manager switch, nudge the
running bar to re-read its rebuilt config/style with SIGUSR2 from
nomarchy-theme-sync so theme switches still reapply the bar live.

Found on the Latitude 5410 hardware sweep (systemctl --user status showed
waybar.service loaded/failed; manual start worked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-06-18 19:00:39 +01:00
parent b4fe52261b
commit c2281dbc61
3 changed files with 20 additions and 2 deletions

View File

@@ -152,7 +152,13 @@ in
# Paint the wallpaper as soon as the session is up (waits for
# the daemon internally).
"nomarchy-theme-sync wallpaper"
] ++ lib.optional kbAutoSwitch "${keyboardWatch}/bin/nomarchy-keyboard-watch";
# Waybar is launched here rather than as a systemd user service: bound
# to graphical-session.target the unit raced Hyprland's IPC on relogin
# and landed in `failed`; exec-once only fires once the compositor is
# up. Reloaded on theme switch via SIGUSR2 (nomarchy-theme-sync). See
# waybar.nix.
] ++ lib.optional config.nomarchy.waybar.enable "waybar"
++ lib.optional kbAutoSwitch "${keyboardWatch}/bin/nomarchy-keyboard-watch";
# ── Theme-driven look ──────────────────────────────────────────
# These flow from theme-state.json and stay at NORMAL priority:

View File

@@ -228,7 +228,14 @@ in
{
programs.waybar = lib.mkIf config.nomarchy.waybar.enable {
enable = true;
systemd.enable = true; # started/stopped with graphical-session.target
# Launched from Hyprland's exec-once (hyprland.nix), NOT a systemd user
# service. Bound to graphical-session.target the unit raced Hyprland's IPC
# on a warm relogin — it started before the socket was up, exited, landed
# in `failed`, and was never retried, so the bar vanished. exec-once only
# fires once Hyprland is up, dodging the race; theme switches reload the
# running bar via SIGUSR2 (nomarchy-theme-sync). No uwsm here to manage the
# session target, so we don't depend on its lifecycle.
systemd.enable = false;
# mkDefault so downstream can replace the whole bar config/style with
# a plain home.nix assignment. For per-theme identity, prefer the

View File

@@ -171,6 +171,11 @@ def run_switch() -> None:
notify("Theme rebuild FAILED — see terminal / journal", urgency="critical")
die("rebuild failed (state file already updated; fix and re-run)")
notify("Theme applied ✓")
# Waybar runs from Hyprland's exec-once (not a systemd unit HM would restart
# on switch), so nudge the running bar to re-read its freshly rebuilt
# config/style. SIGUSR2 = reload; harmless no-op if waybar isn't running.
if shutil.which("pkill"):
subprocess.run(["pkill", "--signal", "SIGUSR2", "-x", "waybar"], check=False)
# ─── Theme assets (wallpapers) ────────────────────────────────────────────