Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 8 additions & 25 deletions config/waybar/config.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"position": "top",
"spacing": 0,
"height": 26,
"modules-left": ["custom/omarchy", "hyprland/workspaces"],
"modules-left": ["custom/omarchy", "custom/workspace-windows"],
"modules-center": ["clock", "custom/weather", "custom/update", "custom/voxtype", "custom/screenrecording-indicator", "custom/idle-indicator", "custom/notification-silencing-indicator"],
"modules-right": [
"group/tray-expander",
Expand All @@ -14,30 +14,13 @@
"cpu",
"battery"
],
"hyprland/workspaces": {
"on-click": "activate",
"format": "{icon}",
"format-icons": {
"default": "",
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7",
"8": "8",
"9": "9",
"10": "0",
"active": "󱓻"
},
"persistent-workspaces": {
"1": [],
"2": [],
"3": [],
"4": [],
"5": []
}
"custom/workspace-windows": {
"format": "{}",
"exec": "$OMARCHY_PATH/default/waybar/workspace-windows.sh",
"tooltip": false,
"escape": false,
"on-scroll-up": "hyprctl dispatch workspace e-1",
"on-scroll-down": "hyprctl dispatch workspace e+1"
},
"custom/omarchy": {
"format": "<span font='omarchy'>\ue900</span>",
Expand Down
60 changes: 60 additions & 0 deletions default/waybar/workspace-windows.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash
# Waybar custom module: workspaces with a per-workspace window count badge.
# Renders each workspace number followed by a superscript count of its windows,
# highlights the active workspace, and updates instantly via the Hyprland IPC socket.

# Minimum number of (persistent) workspaces always shown.
MIN_WS=5

# Superscript digits 0-9 for the count badge.
SUP=("⁰" "¹" "²" "³" "⁴" "⁵" "⁶" "⁷" "⁸" "⁹")

to_super() {
local n="$1" out="" i
for ((i = 0; i < ${#n}; i++)); do
out+="${SUP[${n:$i:1}]}"
done
printf '%s' "$out"
}

render() {
local active counts max=$MIN_WS ws c label out=""
active=$(hyprctl activeworkspace -j | jq -r '.id')

# Map "id -> window count" for normal (id >= 1) workspaces.
declare -A counts=()
while read -r id win; do
[[ "$id" =~ ^[0-9]+$ ]] && (( id >= 1 )) && counts[$id]=$win
done < <(hyprctl workspaces -j | jq -r '.[] | "\(.id) \(.windows)"')

# Show up to the highest populated/active workspace, but at least MIN_WS.
for id in "${!counts[@]}"; do (( id > max )) && max=$id; done
[[ "$active" =~ ^[0-9]+$ ]] && (( active > max )) && max=$active

for ((ws = 1; ws <= max; ws++)); do
c=${counts[$ws]:-0}
label="$ws"
(( c > 0 )) && label+="$(to_super "$c")"
if [[ "$ws" == "$active" ]]; then
out+="<span color='#ff3b30'><b>$label</b></span> "
else
out+="$label "
fi
done

printf '%s\n' "$out"
}

# Initial paint.
render

# Stream Hyprland events and repaint on anything that changes counts/active ws.
SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
socat -U - "UNIX-CONNECT:$SOCKET" 2>/dev/null | while read -r line; do
case "$line" in
workspace\>*|createworkspace\>*|destroyworkspace\>*|moveworkspace\>*|\
openwindow\>*|closewindow\>*|movewindow\>*|focusedmon\>*|activespecial\>*)
render
;;
esac
done