# Airplane mode — runtime kill-switch for Wi-Fi + Bluetooth together. # Remembers each radio's prior state so disengage restores what you had # (if Wi-Fi was already off, it stays off). Waybar shows a plane glyph # only while engaged (status prints nothing otherwise → self-hides). # # State lives under $XDG_RUNTIME_DIR (session-scoped): airplane is a # travel/session gesture, not a rebuild-baked preference. Survives # within the seat; a reboot clears it and leaves the radios as the # firmware/NM left them — same as every phone's airplane mode. { config, lib, pkgs, ... }: let # signal 11: poke the bar on toggle so the glyph appears/vanishes # without waiting for the poll interval (same pattern as recording=8, # updates=9, doctor=10). waybarSignal = 11; nomarchy-airplane = pkgs.writeShellScriptBin "nomarchy-airplane" '' set -euo pipefail rt="''${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" state_file="$rt/nomarchy-airplane.state" PATH=${lib.makeBinPath [ pkgs.networkmanager pkgs.util-linux pkgs.bluez pkgs.coreutils pkgs.gnugrep pkgs.gawk pkgs.libnotify pkgs.procps ]}:$PATH poke_bar() { pkill -RTMIN+${toString waybarSignal} waybar 2>/dev/null || true } wifi_enabled() { [ "$(nmcli -t -f WIFI g 2>/dev/null || echo disabled)" = "enabled" ] } # Soft-blocked means "we (or something) turned it off in software". # Hard-blocked is a laptop kill-switch — we never try to fight that. bt_soft_unblocked() { rfkill list bluetooth 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q 'Soft blocked: no' } bt_powered() { bluetoothctl show 2>/dev/null | ${pkgs.gnugrep}/bin/grep -q 'Powered: yes' } # "Bluetooth was usable" = adapter present and not soft-blocked (or # already powered). Desktops without BT leave this false. bt_was_on() { ls /sys/class/bluetooth/hci* >/dev/null 2>&1 || return 1 bt_powered || bt_soft_unblocked } engaged() { [ -f "$state_file" ]; } engage() { if engaged; then notify-send -a Nomarchy "Airplane mode" "Already on." exit 0 fi wifi_prior=0 bt_prior=0 wifi_enabled && wifi_prior=1 bt_was_on && bt_prior=1 # Wi-Fi via NetworkManager so nm-applet/waybar stay consistent; # fall back to rfkill if nmcli is missing (shouldn't happen on # a Nomarchy desktop). if command -v nmcli >/dev/null 2>&1; then nmcli radio wifi off 2>/dev/null || true else rfkill block wlan 2>/dev/null || true fi # Bluetooth: soft-block the radio (covers adapters that ignore # bluetoothctl) and ask the daemon to power off when present. rfkill block bluetooth 2>/dev/null || true bluetoothctl power off >/dev/null 2>&1 || true printf 'wifi_prior=%s\nbt_prior=%s\n' "$wifi_prior" "$bt_prior" > "$state_file" poke_bar notify-send -a Nomarchy "Airplane mode" "On — Wi-Fi and Bluetooth off." } disengage() { if ! engaged; then notify-send -a Nomarchy "Airplane mode" "Already off." exit 0 fi # shellcheck disable=SC1090 . "$state_file" wifi_prior=''${wifi_prior:-0} bt_prior=''${bt_prior:-0} if [ "$wifi_prior" = 1 ]; then if command -v nmcli >/dev/null 2>&1; then nmcli radio wifi on 2>/dev/null || true else rfkill unblock wlan 2>/dev/null || true fi fi if [ "$bt_prior" = 1 ]; then rfkill unblock bluetooth 2>/dev/null || true bluetoothctl power on >/dev/null 2>&1 || true fi rm -f "$state_file" poke_bar notify-send -a Nomarchy "Airplane mode" "Off — prior radio state restored." } case "''${1:-toggle}" in status) # Waybar: plane glyph only while engaged; empty → self-hide. if engaged; then printf '{"text":"󰀝","tooltip":"Airplane mode on — Wi-Fi and Bluetooth off (click to restore)","class":"on"}\n' fi exit 0 ;; is-active) if engaged; then echo on; else echo off; fi ;; on) engage ;; off) disengage ;; toggle) if engaged; then disengage; else engage; fi ;; *) echo "usage: nomarchy-airplane [toggle|status|on|off|is-active]" >&2 exit 64 ;; esac ''; in { config = { home.packages = [ nomarchy-airplane ]; }; }