Files
nixos/scripts/hakase-scripts.nix
T

144 lines
4.8 KiB
Nix

{pkgs, ...}: let
# 1. The Brain: Logic to find a window or launch a new one
hakase-launch-or-focus = pkgs.writeShellScriptBin "hakase-launch-or-focus" ''
if (($# == 0)); then
echo "Usage: hakase-launch-or-focus [window-pattern] [launch-command]"
exit 1
fi
WINDOW_PATTERN="$1"
# Escaped Nix interpolation for shell default value logic
LAUNCH_COMMAND="''${2:-"uwsm-app -- $WINDOW_PATTERN"}"
# Locate window address via hyprctl and jq
WINDOW_ADDRESS=$(${pkgs.hyprland}/bin/hyprctl clients -j | ${pkgs.jq}/bin/jq -r --arg p "$WINDOW_PATTERN" \
'.[] | select((.class | test("\\b" + $p + "\\b"; "i")) or (.title | test("\\b" + $p + "\\b"; "i"))) | .address' | head -n1)
if [[ -n $WINDOW_ADDRESS ]]; then
# If found, focus the existing window
${pkgs.hyprland}/bin/hyprctl dispatch focuswindow "address:$WINDOW_ADDRESS"
else
# If not found, execute the launch command
eval exec setsid $LAUNCH_COMMAND
fi
'';
hakase-launch-tui = pkgs.writeShellScriptBin "hakase-launch-tui" ''
APP_NAME=$(basename "$1")
# Using org.hakase prefix so the focus script can find it via class name
exec setsid uwsm-app -- xdg-terminal-exec --app-id=org.hakase."$APP_NAME" -e "$@"
'';
hakase-focus-wrapper = pkgs.writeShellScriptBin "hakase-focus-wrapper" ''
APP_NAME=$(basename "$1")
WINDOW_PATTERN="org.hakase.$APP_NAME"
LAUNCH_CMD="hakase-launch-tui $*"
exec hakase-launch-or-focus "$WINDOW_PATTERN" "$LAUNCH_CMD"
'';
hakase-launch-wifi = pkgs.writeShellScriptBin "hakase-launch-wifi" ''
# Unblock the WiFi radio (requires appropriate user groups/permissions)
# ${pkgs.util-linux}/bin/rfkill unblock wifi
# Use the focus wrapper to launch or switch to Impala
exec hakase-focus-wrapper impala
'';
hakase-launch-bluetooth =
pkgs.writeShellScriptBin "hakase-launch-bluetooth"
''
# ${pkgs.util-linux}/bin/rfkill unblock wifi
exec hakase-focus-wrapper bluetui
'';
hakase-launch-popup = pkgs.writeShellScriptBin "hakase-launch-popup" ''
if (($# == 0)); then
echo "Usage: hakase-launch-popup [command]"
exit 1
fi
CMD_NAME=$(basename "$1")
# Define a specific class for popups so Hyprland rules can catch them
CLASS_NAME="org.hakase.popup.$CMD_NAME"
# Check if already running; if so, toggle/close it
EXISTING_ADDR=$(${pkgs.hyprland}/bin/hyprctl clients -j | ${pkgs.jq}/bin/jq -r --arg c "$CLASS_NAME" '.[] | select(.class == $c) | .address')
if [[ -n "$EXISTING_ADDR" ]]; then
${pkgs.hyprland}/bin/hyprctl dispatch closewindow "address:$EXISTING_ADDR"
exit 0
fi
# Launch the application
# We use setsid to detach, but keep the PID to kill it later
xdg-terminal-exec --app-id="$CLASS_NAME" -e "$@" &
APP_PID=$!
# Wait for the window to appear and grab its address
TIMEOUT=0
WINDOW_ADDR=""
while [[ -z "$WINDOW_ADDR" && $TIMEOUT -lt 20 ]]; do
sleep 0.1
WINDOW_ADDR=$(${pkgs.hyprland}/bin/hyprctl clients -j | ${pkgs.jq}/bin/jq -r --arg c "$CLASS_NAME" '.[] | select(.class == $c) | .address')
((TIMEOUT++))
done
if [[ -z "$WINDOW_ADDR" ]]; then
echo "Failed to find window for $CLASS_NAME"
exit 1
fi
# Monitor Hyprland socket for focus changes
# We use socat to stream events. If activewindow changes to something else, kill the app.
${pkgs.socat}/bin/socat -U - UNIX-CONNECT:"$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" | while read -r line; do
if [[ "$line" == "activewindow>>"* ]]; then
# Extract the new focused address
NEW_FOCUS="0x$(echo "$line" | cut -d '>' -f3 | cut -d ',' -f1)"
# If the new focus is NOT our popup window, kill the popup
if [[ "$WINDOW_ADDR" != "$NEW_FOCUS" ]]; then
kill "$APP_PID" 2>/dev/null
# Also force close in Hyprland to be sure
${pkgs.hyprland}/bin/hyprctl dispatch closewindow "address:$WINDOW_ADDR"
break
fi
fi
done
'';
# 2. Specific Launchers using the Popup logic
hakase-popup-wifi = pkgs.writeShellScriptBin "hakase-popup-wifi" ''
exec hakase-launch-popup impala
'';
hakase-popup-bluetooth = pkgs.writeShellScriptBin "hakase-popup-bluetooth" ''
exec hakase-launch-popup bluetui
'';
hakase-popup-volume = pkgs.writeShellScriptBin "hakase-popup-volume" ''
exec hakase-launch-popup wiremix
'';
in {
environment.systemPackages = [
pkgs.jq
pkgs.socat # Required for the socket listener
pkgs.util-linux
pkgs.bluetui
pkgs.impala
pkgs.wiremix
pkgs.pamixer
hakase-launch-popup
hakase-popup-wifi
hakase-popup-bluetooth
hakase-popup-volume
hakase-launch-or-focus
hakase-launch-tui
hakase-focus-wrapper
hakase-launch-wifi
hakase-launch-bluetooth
];
}