A simple yet powerful UI overlay made for Wayland WMs built with Quickshell
wayland
qs
linux
ui
ux
1#!/usr/bin/env bash
2
3set -u
4
5cmd="${1:-}"
6
7have_nmcli() { command -v nmcli >/dev/null 2>&1; }
8have() { command -v "$1" >/dev/null 2>&1; }
9
10wifi_power() {
11 local onoff="${1:-off}"
12 nmcli radio wifi "$onoff" >/dev/null 2>&1 || true
13}
14
15wifi_scan() {
16 local ifname="${1:-}"
17 [ -n "$ifname" ] || exit 0
18 nmcli radio wifi on >/dev/null 2>&1 || true
19 sleep 0.2
20 nmcli dev wifi rescan ifname "$ifname" >/dev/null 2>&1 || true
21}
22
23wifi_disconnect() {
24 local ifname="${1:-}"
25 [ -n "$ifname" ] || exit 0
26 nmcli dev disconnect "$ifname" >/dev/null 2>&1 || true
27}
28
29bar_status() {
30 pick_default_iface() {
31 ip route show default 2>/dev/null |
32 awk '{
33 dev=""; metric=0;
34 for(i=1;i<=NF;i++){
35 if($i=="dev") dev=$(i+1);
36 if($i=="metric") metric=$(i+1);
37 }
38 if(dev!="") print metric "\t" dev;
39 }' |
40 while IFS=$'\t' read -r metric dev; do
41 weight=1
42 case "$dev" in
43 usb*|rndis*|wwan*) weight=0 ;;
44 *)
45 if [ -d "/sys/class/net/$dev/wireless" ]; then
46 weight=2
47 else
48 devpath="$(readlink -f "/sys/class/net/$dev/device" 2>/dev/null || true)"
49 if printf '%s' "$devpath" | grep -qi "/usb"; then
50 weight=0
51 else
52 driver="$(basename "$(readlink -f "/sys/class/net/$dev/device/driver" 2>/dev/null || true)" 2>/dev/null || true)"
53 case "$driver" in
54 rndis_host|cdc_ether|cdc_ncm|ipheth|r8152|asix|ax88179_178a) weight=0 ;;
55 esac
56 fi
57 fi
58 ;;
59 esac
60 printf "%s\t%s\t%s\n" "$metric" "$weight" "$dev"
61 done |
62 sort -n -k1,1 -k2,2 |
63 head -n1 |
64 cut -f3
65 }
66
67 iface="$(pick_default_iface || true)"
68 if [ -z "${iface:-}" ]; then
69 iface="$(ip -o route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev"){print $(i+1); exit}}' || true)"
70 fi
71
72 if [ -z "${iface:-}" ] || [ ! -e "/sys/class/net/$iface" ]; then
73 printf "none\t\t0\t0\n\n"
74 exit 0
75 fi
76
77 rx="$(cat "/sys/class/net/$iface/statistics/rx_bytes" 2>/dev/null || echo 0)"
78 tx="$(cat "/sys/class/net/$iface/statistics/tx_bytes" 2>/dev/null || echo 0)"
79
80 kind="ethernet"
81 ssid=""
82
83 if [ -d "/sys/class/net/$iface/wireless" ]; then
84 kind="wifi"
85 fi
86
87 if [ "$kind" = "ethernet" ]; then
88 case "$iface" in
89 usb*|rndis*|wwan*) kind="tether" ;;
90 *)
91 devpath="$(readlink -f "/sys/class/net/$iface/device" 2>/dev/null || true)"
92 if printf '%s' "$devpath" | grep -qi "/usb"; then
93 kind="tether"
94 else
95 driver="$(basename "$(readlink -f "/sys/class/net/$iface/device/driver" 2>/dev/null || true)" 2>/dev/null || true)"
96 case "$driver" in
97 rndis_host|cdc_ether|cdc_ncm|ipheth|r8152|asix|ax88179_178a) kind="tether" ;;
98 esac
99 fi
100 ;;
101 esac
102 fi
103
104 if [ "$kind" = "wifi" ]; then
105 if have iw; then
106 ssid="$(timeout 0.25 iw dev "$iface" link 2>/dev/null | awk -F": " '/SSID:/{print $2; exit}' || true)"
107 fi
108 if [ -z "${ssid:-}" ] && have_nmcli; then
109 ssid="$(nmcli -t -f ACTIVE,SSID dev wifi 2>/dev/null | awk -F: '$1=="yes"{print $2; exit}' || true)"
110 fi
111 fi
112
113 ssid="${ssid//$'\t'/ }"
114
115 printf "%s\t%s\t%s\t%s\n" "$kind" "$iface" "$rx" "$tx"
116 printf "%s\n" "$ssid"
117}
118
119status() {
120 if ! have_nmcli; then
121 echo 'NONMCLI|1'
122 exit 0
123 fi
124
125 local wifi
126 wifi="$(nmcli -t -f WIFI general status 2>/dev/null | head -n1 | tr -d $'\r')"
127 case "$wifi" in
128 enabled|*enabled*) echo 'WIFIPWR|1' ;;
129 *) echo 'WIFIPWR|0' ;;
130 esac
131
132 local wifidev
133 wifidev="$(nmcli -t -f DEVICE,TYPE dev status 2>/dev/null | awk -F: '$2=="wifi"{print $1; exit}')"
134 echo "WIFIDEV|${wifidev:-}"
135
136 local act adev atype
137 act="$(nmcli -t -f DEVICE,TYPE,STATE dev status 2>/dev/null | awk -F: '$3=="connected"{print $1":"$2; exit}')"
138 adev="$(printf '%s' "$act" | awk -F: '{print $1}')"
139 atype="$(printf '%s' "$act" | awk -F: '{print $2}')"
140
141 if [ "$atype" = "wifi" ] && [ -n "${adev:-}" ]; then
142 local assid
143 assid="$(nmcli -t -f ACTIVE,SSID dev wifi list ifname "$adev" 2>/dev/null | awk -F: '$1=="yes"{print $2; exit}')"
144 if [ -z "${assid:-}" ]; then
145 assid="$(nmcli -t -f GENERAL.CONNECTION dev show "$adev" 2>/dev/null | awk -F: '{print $2; exit}')"
146 fi
147 echo "ACTIVE|wifi|${adev}|${assid:-}"
148 elif [ "$atype" = "ethernet" ]; then
149 case "$adev" in
150 usb*|enx*) echo 'ACTIVE|tether||Tether' ;;
151 *) echo 'ACTIVE|ethernet||Ethernet' ;;
152 esac
153 elif [ "$atype" = "gsm" ] || [ "$atype" = "wwan" ]; then
154 echo 'ACTIVE|tether||Tether'
155 elif [ -n "${atype:-}" ]; then
156 echo "ACTIVE|other||${atype}"
157 else
158 echo 'ACTIVE|none||'
159 fi
160
161 if [ -n "${wifidev:-}" ]; then
162 nmcli -t -f IN-USE,SSID,SECURITY,SIGNAL dev wifi list ifname "$wifidev" 2>/dev/null |
163 while IFS=: read -r inuse ssid2 sec sig; do
164 [ -n "${ssid2:-}" ] || continue
165 echo "AP|${inuse:-}|${ssid2:-}|${sec:---}|${sig:-0}"
166 done
167 fi
168
169 true
170}
171
172wifi_connect() {
173 local iface="${1:-}"
174 local ssid="${2:-}"
175 local sec="${3:-}"
176 local pass="${4:-}"
177
178 set +e
179
180 local conn out ec
181 conn="$(
182 nmcli -t -f NAME,TYPE con show 2>/dev/null | awk -F: '$2=="802-11-wireless"{print $1}' |
183 while IFS= read -r c; do
184 [ -n "$c" ] || continue
185 local cs
186 cs="$(nmcli -g 802-11-wireless.ssid con show "$c" 2>/dev/null | tr -d $'\r')"
187 [ "$cs" = "$ssid" ] && { printf '%s' "$c"; exit 0; }
188 done
189 )"
190
191 verify() {
192 local i=0 cur
193 while [ $i -lt 12 ]; do
194 cur="$(nmcli -t -f ACTIVE,SSID dev wifi list ifname "$iface" 2>/dev/null | awk -F: '$1=="yes"{print $2; exit}')"
195 [ "$cur" = "$ssid" ] && return 0
196 sleep 0.3
197 i=$((i+1))
198 done
199 return 1
200 }
201
202 if [ "$sec" = "--" ] || [ "$sec" = "OPEN" ] || [ -z "$sec" ]; then
203 if [ -n "$conn" ]; then
204 out="$(nmcli --wait 25 con up "$conn" 2>&1)"; ec=$?
205 else
206 out="$(nmcli --wait 25 dev wifi connect "$ssid" ifname "$iface" 2>&1)"; ec=$?
207 fi
208
209 if [ $ec -eq 0 ] && verify; then
210 printf 'EC|0\nMSG|connected\n'
211 exit 0
212 fi
213
214 local msg
215 msg="$(printf '%s' "$out" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | cut -c1-360)"
216 [ -n "$msg" ] || msg="nmcli returned exit code $ec"
217 printf 'EC|%s\nMSG|%s\n' "$ec" "$msg"
218 exit 0
219 fi
220
221 if [ -z "$pass" ]; then
222 if [ -n "$conn" ]; then
223 out="$(nmcli --wait 25 con up "$conn" 2>&1)"; ec=$?
224 if [ $ec -eq 0 ] && verify; then
225 printf 'EC|0\nMSG|connected\n'
226 exit 0
227 fi
228
229 if printf '%s' "$out" | grep -Eqi 'secrets.*required|not provided|No agents were available'; then
230 local msg
231 msg="$(printf '%s' "$out" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | cut -c1-360)"
232 [ -n "$msg" ] || msg='Secrets required.'
233 printf 'EC|%s\nMSG|%s\nPROMPT|1\n' "$ec" "$msg"
234 exit 0
235 fi
236
237 local msg
238 msg="$(printf '%s' "$out" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | cut -c1-360)"
239 [ -n "$msg" ] || msg="nmcli returned exit code $ec"
240 printf 'EC|%s\nMSG|%s\n' "$ec" "$msg"
241 exit 0
242 else
243 printf 'EC|1\nMSG|Password required.\nPROMPT|1\n'
244 exit 0
245 fi
246 fi
247
248 if [ -n "$conn" ]; then
249 out="$(printf '%s\n%s\n' "$pass" "$pass" | nmcli --wait 25 --ask con up "$conn" 2>&1)"; ec=$?
250 if [ $ec -eq 0 ] && verify; then
251 printf 'EC|0\nMSG|connected\n'
252 exit 0
253 fi
254 local msg
255 msg="$(printf '%s' "$out" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | cut -c1-360)"
256 [ -n "$msg" ] || msg="nmcli returned exit code $ec"
257 printf 'EC|%s\nMSG|%s\nPROMPT|1\n' "$ec" "$msg"
258 exit 0
259 fi
260
261 local key='wpa-psk'
262 echo "$sec" | grep -Eqi 'WPA3|SAE' && key='sae'
263
264 nmcli -t -f NAME con show 2>/dev/null | grep -Fx "$ssid" >/dev/null 2>&1 && nmcli con delete "$ssid" >/dev/null 2>&1 || true
265
266 local outa eca outb ecb msg
267 outa="$(nmcli con add type wifi ifname "$iface" con-name "$ssid" ssid "$ssid" wifi-sec.key-mgmt "$key" wifi-sec.psk "$pass" 2>&1)"; eca=$?
268 if [ $eca -ne 0 ]; then
269 msg="$(printf '%s' "$outa" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | cut -c1-360)"
270 [ -n "$msg" ] || msg="nmcli returned exit code $eca"
271 printf 'EC|%s\nMSG|%s\n' "$eca" "$msg"
272 exit 0
273 fi
274
275 outb="$(nmcli --wait 25 con up "$ssid" 2>&1)"; ecb=$?
276 if [ $ecb -eq 0 ] && verify; then
277 printf 'EC|0\nMSG|connected\n'
278 exit 0
279 fi
280
281 nmcli con delete "$ssid" >/dev/null 2>&1 || true
282
283 msg="$(printf '%s' "$outb" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | cut -c1-360)"
284 [ -n "$msg" ] || msg="nmcli returned exit code $ecb"
285 printf 'EC|%s\nMSG|%s\nPROMPT|1\n' "$ecb" "$msg"
286 exit 0
287}
288
289case "$cmd" in
290 bar) bar_status ;;
291
292 status) status ;;
293 wifi_power) wifi_power "${2:-}" ;;
294 wifi_scan) wifi_scan "${2:-}" ;;
295 wifi_disconnect) wifi_disconnect "${2:-}" ;;
296 wifi_connect) shift; wifi_connect "$@" ;;
297 *)
298 echo "MSG|unknown command"
299 exit 0
300 ;;
301esac