Files
dotfiles/nixos/taffybar.nix

304 lines
10 KiB
Nix

{
config,
inputs,
lib,
pkgs,
makeEnable,
...
}: let
system = pkgs.stdenv.hostPlatform.system;
hyprlandPackage = config.programs.hyprland.package;
taffybarPackage = inputs.imalison-taffybar.defaultPackage.${system};
taffybarStart = pkgs.writeShellScript "taffybar-start" ''
runtime_dir="''${XDG_RUNTIME_DIR:-/run/user/$(${pkgs.coreutils}/bin/id -u)}"
find_hyprland_instance() {
instances_json="$(${hyprlandPackage}/bin/hyprctl instances -j 2>/dev/null || true)"
[ -n "$instances_json" ] || return 1
if [ -n "''${WAYLAND_DISPLAY:-}" ]; then
inst_row="$(
printf '%s\n' "$instances_json" |
${pkgs.jq}/bin/jq -r --arg sock "$WAYLAND_DISPLAY" \
'.[] | select(.instance and .wl_socket and .wl_socket == $sock) | [.time, .instance, .wl_socket] | @tsv' 2>/dev/null |
${pkgs.coreutils}/bin/sort -n |
${pkgs.coreutils}/bin/tail -n 1
)"
else
inst_row=""
fi
if [ -z "''${inst_row:-}" ]; then
inst_row="$(
printf '%s\n' "$instances_json" |
${pkgs.jq}/bin/jq -r \
'.[] | select(.instance and .wl_socket) | [.time, .instance, .wl_socket] | @tsv' 2>/dev/null |
${pkgs.coreutils}/bin/sort -n |
${pkgs.coreutils}/bin/tail -n 1
)"
fi
[ -n "''${inst_row:-}" ] || return 1
set -- $inst_row
signature="$2"
socket_name="$3"
[ -n "$signature" ] && [ -n "$socket_name" ] || return 1
printf '%s\t%s\n' "$signature" "$socket_name"
}
find_wayland_socket() {
if [ -n "''${WAYLAND_DISPLAY:-}" ] && [ -S "$runtime_dir/$WAYLAND_DISPLAY" ]; then
printf '%s\n' "$WAYLAND_DISPLAY"
return 0
fi
for socket in "$runtime_dir"/wayland-*; do
case "$socket" in
*.lock) continue ;;
esac
if [ -S "$socket" ]; then
printf '%s\n' "''${socket##*/}"
return 0
fi
done
return 1
}
x11_socket_ready() {
display_number="''${DISPLAY#:}"
display_number="''${display_number%%.*}"
[ -n "$display_number" ] && [ -S "/tmp/.X11-unix/X$display_number" ]
}
current_desktop="''${XDG_CURRENT_DESKTOP:-}"
desktop_session="''${DESKTOP_SESSION:-}"
window_manager="''${IMALISON_WINDOW_MANAGER:-}"
is_hyprland=0
case "''${current_desktop}:''${desktop_session}:''${window_manager}" in
*Hyprland*|*hyprland*) is_hyprland=1 ;;
esac
if [ "$is_hyprland" = 1 ] && [ -z "''${XDG_SESSION_TYPE:-}" ]; then
export XDG_SESSION_TYPE=wayland
fi
if [ "$is_hyprland" = 1 ]; then
if inst_row="$(find_hyprland_instance)"; then
set -- $inst_row
signature="$1"
socket_name="$2"
if [ "''${HYPRLAND_INSTANCE_SIGNATURE:-}" != "$signature" ]; then
echo "taffybar-start: correcting HYPRLAND_INSTANCE_SIGNATURE=''${HYPRLAND_INSTANCE_SIGNATURE:-<unset>} to $signature" >&2
export HYPRLAND_INSTANCE_SIGNATURE="$signature"
fi
if [ "''${WAYLAND_DISPLAY:-}" != "$socket_name" ]; then
echo "taffybar-start: correcting WAYLAND_DISPLAY=''${WAYLAND_DISPLAY:-<unset>} to $socket_name" >&2
export WAYLAND_DISPLAY="$socket_name"
fi
fi
fi
if [ "''${XDG_SESSION_TYPE:-}" = "wayland" ] || [ -n "''${WAYLAND_DISPLAY:-}" ] || [ "$is_hyprland" = 1 ]; then
if [ -z "''${WAYLAND_DISPLAY:-}" ] || [ ! -S "$runtime_dir/$WAYLAND_DISPLAY" ]; then
if socket_name="$(find_wayland_socket)"; then
echo "taffybar-start: correcting WAYLAND_DISPLAY=''${WAYLAND_DISPLAY:-<unset>} to $socket_name" >&2
export WAYLAND_DISPLAY="$socket_name"
fi
fi
fi
if [ -n "''${DISPLAY:-}" ] && [ "''${XDG_SESSION_TYPE:-}" != "wayland" ] && x11_socket_ready; then
unset WAYLAND_DISPLAY
unset HYPRLAND_INSTANCE_SIGNATURE
exec ${taffybarPackage}/bin/taffybar "$@"
fi
if [ -z "''${WAYLAND_DISPLAY:-}" ] || [ ! -S "$runtime_dir/$WAYLAND_DISPLAY" ]; then
if socket_name="$(find_wayland_socket)"; then
echo "taffybar-start: correcting WAYLAND_DISPLAY=''${WAYLAND_DISPLAY:-<unset>} to $socket_name" >&2
export WAYLAND_DISPLAY="$socket_name"
fi
fi
if [ -n "''${HYPRLAND_INSTANCE_SIGNATURE:-}" ] && [ ! -S "$runtime_dir/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket.sock" ]; then
echo "taffybar-start: unsetting stale HYPRLAND_INSTANCE_SIGNATURE=$HYPRLAND_INSTANCE_SIGNATURE" >&2
unset HYPRLAND_INSTANCE_SIGNATURE
fi
if [ "$is_hyprland" = 1 ]; then
if [ -z "''${HYPRLAND_INSTANCE_SIGNATURE:-}" ]; then
for socket in "$runtime_dir"/hypr/*/.socket.sock; do
if [ -S "$socket" ]; then
socket_dir="''${socket%/.socket.sock}"
signature="''${socket_dir##*/}"
echo "taffybar-start: correcting HYPRLAND_INSTANCE_SIGNATURE=''${HYPRLAND_INSTANCE_SIGNATURE:-<unset>} to $signature" >&2
export HYPRLAND_INSTANCE_SIGNATURE="$signature"
break
fi
done
fi
fi
exec ${taffybarPackage}/bin/taffybar "$@"
'';
waitForGraphicalSocket = pkgs.writeShellScript "wait-for-taffybar-display" ''
runtime_dir="''${XDG_RUNTIME_DIR:-/run/user/$(${pkgs.coreutils}/bin/id -u)}"
find_wayland_socket() {
if [ -n "''${WAYLAND_DISPLAY:-}" ] && [ -S "$runtime_dir/$WAYLAND_DISPLAY" ]; then
return 0
fi
for socket in "$runtime_dir"/wayland-*; do
case "$socket" in
*.lock) continue ;;
esac
if [ -S "$socket" ]; then
return 0
fi
done
return 1
}
x11_socket_ready() {
display_number="''${DISPLAY#:}"
display_number="''${display_number%%.*}"
[ -n "$display_number" ] && [ -S "/tmp/.X11-unix/X$display_number" ]
}
for _ in $(${pkgs.coreutils}/bin/seq 1 50); do
current_desktop="''${XDG_CURRENT_DESKTOP:-}"
desktop_session="''${DESKTOP_SESSION:-}"
window_manager="''${IMALISON_WINDOW_MANAGER:-}"
case "''${current_desktop}:''${desktop_session}:''${window_manager}" in
*Hyprland*|*hyprland*) find_wayland_socket && exit 0 ;;
esac
if [ "''${XDG_SESSION_TYPE:-}" = "wayland" ] || [ -n "''${WAYLAND_DISPLAY:-}" ]; then
find_wayland_socket && exit 0
elif [ -n "''${DISPLAY:-}" ]; then
x11_socket_ready && exit 0
find_wayland_socket && exit 0
else
find_wayland_socket && exit 0
fi
${pkgs.coreutils}/bin/sleep 0.1
done
echo "taffybar: display socket not ready: XDG_SESSION_TYPE=''${XDG_SESSION_TYPE:-<unset>} WAYLAND_DISPLAY=''${WAYLAND_DISPLAY:-<unset>} DISPLAY=''${DISPLAY:-<unset>} XDG_RUNTIME_DIR=$runtime_dir" >&2
exit 1
'';
skipTaffybarInOtherShells = pkgs.writeShellScript "skip-taffybar-in-other-shells" ''
current_desktop="''${XDG_CURRENT_DESKTOP:-}"
desktop_session="''${DESKTOP_SESSION:-}"
case "''${current_desktop}:''${desktop_session}" in
*KDE*|*kde*|*Plasma*|*plasma*) exit 1 ;;
esac
exit 0
'';
taffybarExecCondition = pkgs.writeShellScript "taffybar-exec-condition" ''
${skipTaffybarInOtherShells} || exit 1
if [ -x /run/current-system/sw/bin/desktop_shell_ui ]; then
exec /run/current-system/sw/bin/desktop_shell_ui exec-condition taffybar
fi
exit 0
'';
statusNotifierWatcherPreStart = pkgs.writeShellScript "status-notifier-watcher-pre-start" ''
owner_pid="$(
${pkgs.systemd}/bin/busctl --user status org.kde.StatusNotifierWatcher 2>/dev/null |
while IFS='=' read -r key value; do
if [ "$key" = PID ]; then
printf '%s' "$value"
break
fi
done
)"
if [ -z "$owner_pid" ]; then
exit 0
fi
if ${pkgs.systemd}/bin/busctl --user introspect org.kde.StatusNotifierWatcher /StatusNotifierWatcher >/dev/null 2>&1; then
exit 0
fi
cmdline="$(${pkgs.coreutils}/bin/tr '\0' ' ' < "/proc/$owner_pid/cmdline" 2>/dev/null || true)"
case "$cmdline" in
*kded6*)
echo "status-notifier-watcher-pre-start: killing stale kded6 StatusNotifierWatcher owner pid=$owner_pid" >&2
kill "$owner_pid" 2>/dev/null || true
attempts=0
while ${pkgs.systemd}/bin/busctl --user status org.kde.StatusNotifierWatcher >/dev/null 2>&1; do
attempts=$((attempts + 1))
if [ "$attempts" -ge 20 ]; then
break
fi
${pkgs.coreutils}/bin/sleep 0.1
done
;;
esac
'';
in
makeEnable config "myModules.taffybar" false {
myModules.sni.enable = true;
myModules.chrome-favicon-dbus.enable = true;
environment.systemPackages = [
taffybarPackage
];
home-manager.sharedModules = [
({lib, ...}: {
services."status-notifier-watcher".enable = true;
# home-manager's module defaults to nixpkgs' status-notifier-item, which can lag.
# Point it at the pinned flake version instead.
services."status-notifier-watcher".package =
pkgs.lib.mkForce
inputs.imalison-taffybar.packages.${system}.status-notifier-item;
systemd.user.targets.tray.Unit = {
PartOf = ["graphical-session.target"];
StopWhenUnneeded = true;
};
systemd.user.services."status-notifier-watcher" = {
Unit.Before = ["taffybar.service" "plasma-kded6.service"];
Service.ExecStartPre = "${statusNotifierWatcherPreStart}";
};
# Disable kded6's statusnotifierwatcher module so it doesn't race with
# the Haskell status-notifier-watcher for the org.kde.StatusNotifierWatcher bus name.
xdg.configFile."kded6rc".text = ''
[Module-statusnotifierwatcher]
autoload=false
'';
services.taffybar = {
enable = true;
package = taffybarPackage;
};
xdg.configFile."systemd/user/taffybar.service".force = true;
home.activation.removeStaleTaffybarOverride = lib.hm.dag.entryAfter ["writeBoundary"] ''
rm -f "$HOME/.config/systemd/user/taffybar.service.d/override.conf"
rmdir --ignore-fail-on-non-empty "$HOME/.config/systemd/user/taffybar.service.d" 2>/dev/null || true
'';
systemd.user.services.taffybar.Service = {
ExecCondition = "${taffybarExecCondition}";
ExecStartPre = "${waitForGraphicalSocket}";
ExecStart = lib.mkForce "${taffybarStart}";
StandardOutput = "journal";
StandardError = "journal";
};
})
];
}