Better eww
This commit is contained in:
@@ -6,13 +6,15 @@ PANEL="$1"
|
||||
exec 9>"/tmp/eww_panel_toggle.lock"
|
||||
flock -n 9 || exit 0
|
||||
|
||||
CURRENT=$(eww get active-panel 2>/dev/null | tr -d '"')
|
||||
# Every eww call must run with fd 9 closed (9>&-): `eww open` daemonizes and
|
||||
# would inherit the fd, holding the flock forever and wedging all later toggles.
|
||||
CURRENT=$(eww get active-panel 2>/dev/null 9>&- | tr -d '"')
|
||||
|
||||
if [ "$CURRENT" = "$PANEL" ]; then
|
||||
eww update active-panel=""
|
||||
eww close popup 2>/dev/null
|
||||
eww update active-panel="" 9>&-
|
||||
eww close popup 2>/dev/null 9>&-
|
||||
else
|
||||
eww update active-panel="$PANEL"
|
||||
eww close popup 2>/dev/null
|
||||
eww-open-on-current-screen popup
|
||||
eww update active-panel="$PANEL" 9>&-
|
||||
eww close popup 2>/dev/null 9>&-
|
||||
eww-open-on-current-screen popup 9>&-
|
||||
fi
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
let
|
||||
ensureDaemon = pkgs.custom.eww-ensure-daemon;
|
||||
|
||||
openOnCurrentScreen = pkgs.writeShellScriptBin "eww-open-on-current-screen" ''
|
||||
window="$1"
|
||||
shift
|
||||
|
||||
${ensureDaemon}/bin/eww-ensure-daemon || exit 1
|
||||
|
||||
screen="$(hyprctl monitors -j | ${lib.getExe pkgs.jq} -r '.[] | select(.focused == true) | .name' | head -n1)"
|
||||
|
||||
if [ -n "$screen" ]; then
|
||||
@@ -13,6 +17,21 @@ let
|
||||
exec ${lib.getExe pkgs.eww} open "$window" "$@"
|
||||
'';
|
||||
|
||||
# Escape hatch: tears down every eww process (including orphaned daemons that
|
||||
# own unreachable surfaces), clears the stale socket, and brings back a single
|
||||
# daemon with the bar. `pkill -x` matches the process name exactly so it can
|
||||
# never match a wrapper script or a shell that merely mentions eww.
|
||||
ewwReset = pkgs.writeShellScriptBin "eww-reset" ''
|
||||
${pkgs.systemd}/bin/systemctl --user stop eww.service >/dev/null 2>&1 || true
|
||||
${pkgs.procps}/bin/pkill -x -u "$(id -u)" eww >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
${pkgs.procps}/bin/pkill -9 -x -u "$(id -u)" eww >/dev/null 2>&1 || true
|
||||
rm -f "''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"/eww-server_*
|
||||
|
||||
${ensureDaemon}/bin/eww-ensure-daemon || exit 1
|
||||
exec ${lib.getExe pkgs.eww} open bar --screen 0
|
||||
'';
|
||||
|
||||
# Wraps a static script file with a bash launcher that prepends Nix store
|
||||
# bin dirs to PATH — keeps the source files unchanged.
|
||||
mkScript = name: src: inputs: pkgs.writeShellScriptBin name ''
|
||||
@@ -43,7 +62,26 @@ let
|
||||
in {
|
||||
|
||||
config = lib.mkIf (config.usercfg.wm == "Wayland") {
|
||||
home.packages = [ pkgs.eww openOnCurrentScreen ];
|
||||
home.packages = [ pkgs.eww openOnCurrentScreen ensureDaemon ewwReset ];
|
||||
|
||||
# One explicitly-managed daemon, so no client ever races to spawn a rival.
|
||||
# ExecStartPre clears a socket left behind by an unclean exit, which would
|
||||
# otherwise make the fresh daemon look reachable to clients before it binds.
|
||||
systemd.user.services.eww = {
|
||||
Unit = {
|
||||
Description = "eww daemon";
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
After = [ "graphical-session.target" ];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStartPre = "${pkgs.bash}/bin/bash -c 'rm -f \"\${XDG_RUNTIME_DIR:-/run/user/$(id -u)}\"/eww-server_*'";
|
||||
ExecStart = "${lib.getExe pkgs.eww} daemon --no-daemonize";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
};
|
||||
Install.WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
xdg.configFile = lib.mkMerge [
|
||||
{
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
# Close the bar if it's already open (wrong screen), then open on the target screen.
|
||||
# Must go through eww-ensure-daemon: this runs on every monitor hotplug, and a
|
||||
# bare `eww open` against a busy/dead socket spawns a second daemon, leaving the
|
||||
# first one's bar and popups on screen with no way to close them.
|
||||
moveOrOpenBar = screen: "${pkgs.writeShellScript "kanshi-eww-bar-${toString screen}" ''
|
||||
${pkgs.custom.eww-ensure-daemon}/bin/eww-ensure-daemon || exit 1
|
||||
|
||||
if ${pkgs.eww}/bin/eww active-windows 2>/dev/null | grep -qx "bar"; then
|
||||
${pkgs.eww}/bin/eww close bar
|
||||
fi
|
||||
|
||||
@@ -24,7 +24,11 @@
|
||||
|
||||
|
||||
startupScript = pkgs.writeShellScriptBin "hyprland-start" ''
|
||||
${pkgs.eww}/bin/eww open bar &
|
||||
# Wait for the managed daemon rather than letting `eww open` spawn its own:
|
||||
# at login the socket may not be bound yet, and a self-spawned client daemon
|
||||
# would orphan the service's one, leaving unclosable windows behind.
|
||||
(${pkgs.custom.eww-ensure-daemon}/bin/eww-ensure-daemon \
|
||||
&& ${pkgs.eww}/bin/eww open bar --screen 0) &
|
||||
${pkgs.awww}/bin/awww-daemon &
|
||||
${pkgs.awww}/bin/awww restore &
|
||||
|
||||
|
||||
@@ -5,4 +5,6 @@
|
||||
repalette = pkgs.callPackage ./repalette { };
|
||||
|
||||
vosk = pkgs.callPackage ./vosk { };
|
||||
|
||||
eww-ensure-daemon = pkgs.callPackage ./eww-ensure-daemon { };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{ lib, writeShellScriptBin, eww, systemd }:
|
||||
|
||||
# `eww open` silently becomes a NEW daemon when it can't reach the socket,
|
||||
# rebinding the same socket path and orphaning the previous daemon. The old
|
||||
# daemon keeps rendering its layer-shell surfaces but no longer answers any
|
||||
# `eww close` — that is the "zombie panel I can't close" / "bar opened twice".
|
||||
# Every open path must go through here first, so the socket is always live
|
||||
# before a client touches it and no client ever self-daemonizes.
|
||||
writeShellScriptBin "eww-ensure-daemon" ''
|
||||
${lib.getExe eww} ping >/dev/null 2>&1 && exit 0
|
||||
|
||||
${systemd}/bin/systemctl --user start eww.service >/dev/null 2>&1 || true
|
||||
|
||||
for _ in $(seq 1 100); do
|
||||
${lib.getExe eww} ping >/dev/null 2>&1 && exit 0
|
||||
sleep 0.1
|
||||
done
|
||||
exit 1
|
||||
''
|
||||
Reference in New Issue
Block a user