diff --git a/config/waybar/config.jsonc b/config/waybar/config.jsonc index 2b3783b22c..9f8c16a26a 100644 --- a/config/waybar/config.jsonc +++ b/config/waybar/config.jsonc @@ -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", @@ -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": "\ue900", diff --git a/default/waybar/workspace-windows.sh b/default/waybar/workspace-windows.sh new file mode 100755 index 0000000000..cc7451704c --- /dev/null +++ b/default/waybar/workspace-windows.sh @@ -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+="$label " + 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