From e601c536ec79e9c46105cdbc67825e0cd97e7818 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 25 Jan 2026 20:29:28 -0600 Subject: feat(waybar): enhance status bar with icons, modules, and interactivity - Add nerd font icons (large size) for cpu, memory, disk, temperature, volume - Add temperature module next to CPU in sysmonitor group - Add battery module with warning/critical states - Add custom netspeed module with fixed-width output and SSID tooltip - Add layout indicator with clickable cycling through layouts - Add window title module to left panel - Add network scratchpad with nmtui (click netspeed to toggle) - Add toggle-scratchpad script to handle focus-loss auto-close - Make sysmonitor modules clickable to toggle monitor scratchpad - Add right-click on volume to toggle audio scratchpad - Update clock format to "Sun, Jan 25 2025 08:04 PM CST" - Remove nm-applet from autostart (replaced by nmtui scratchpad) Co-Authored-By: Claude Opus 4.5 --- dotfiles/hyprland/.config/hypr/hyprland.conf | 7 ++- dotfiles/hyprland/.config/waybar/config | 74 +++++++++++++++++++++----- dotfiles/hyprland/.config/waybar/style.css | 22 ++++++-- dotfiles/hyprland/.local/bin/cycle-layout | 30 +++++++++++ dotfiles/hyprland/.local/bin/toggle-scratchpad | 29 ++++++++++ dotfiles/hyprland/.local/bin/waybar-layout | 54 +++++++++++++++++++ dotfiles/hyprland/.local/bin/waybar-netspeed | 52 ++++++++++++++++++ 7 files changed, 252 insertions(+), 16 deletions(-) create mode 100755 dotfiles/hyprland/.local/bin/cycle-layout create mode 100755 dotfiles/hyprland/.local/bin/toggle-scratchpad create mode 100755 dotfiles/hyprland/.local/bin/waybar-layout create mode 100755 dotfiles/hyprland/.local/bin/waybar-netspeed diff --git a/dotfiles/hyprland/.config/hypr/hyprland.conf b/dotfiles/hyprland/.config/hypr/hyprland.conf index d7bb431..e2afa07 100644 --- a/dotfiles/hyprland/.config/hypr/hyprland.conf +++ b/dotfiles/hyprland/.config/hypr/hyprland.conf @@ -15,7 +15,6 @@ exec-once = swww-daemon && sleep 1 && swww img ~/pictures/wallpaper/dark-lion.jp exec-once = dunst exec-once = hypridle exec-once = gammastep -exec-once = nm-applet exec-once = blueman-applet exec-once = /usr/bin/gnome-keyring-daemon --start --components=pkcs11,secrets,ssh exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP @@ -230,6 +229,7 @@ workspace = special:monitor, on-created-empty:foot --app-id foot-monitor gotop workspace = special:music, on-created-empty:foot --app-id foot-music ncmpcpp workspace = special:files, on-created-empty:foot --app-id foot-files ranger workspace = special:htop, on-created-empty:foot --app-id foot-htop htop +workspace = special:network, on-created-empty:foot --app-id foot-network nmtui # Keybindings (single bind per scratchpad - just toggle visibility) bind = $mod SHIFT, RETURN, togglespecialworkspace, term @@ -270,6 +270,11 @@ windowrule = match:class ^(foot-htop)$, float on windowrule = match:class ^(foot-htop)$, size (monitor_w*0.6) (monitor_h*0.6) windowrule = match:class ^(foot-htop)$, center on +# Network manager +windowrule = match:class ^(foot-network)$, float on +windowrule = match:class ^(foot-network)$, size (monitor_w*0.6) (monitor_h*0.6) +windowrule = match:class ^(foot-network)$, center on + # Calculator (not a scratchpad, just launches app) bind = $mod, X, exec, qalculate-gtk bind = $mod, C, exec, qalculate-gtk diff --git a/dotfiles/hyprland/.config/waybar/config b/dotfiles/hyprland/.config/waybar/config index 5481a86..c7cc0a7 100644 --- a/dotfiles/hyprland/.config/waybar/config +++ b/dotfiles/hyprland/.config/waybar/config @@ -8,22 +8,27 @@ "margin-right": 10, "modules-left": [ - "hyprland/workspaces" + "hyprland/workspaces", + "custom/layout", + "hyprland/window" ], "modules-center": [], "modules-right": [ "group/sysmonitor", + "custom/netspeed", + "wireplumber", "tray", - "clock", - "wireplumber" + "clock" ], "group/sysmonitor": { "orientation": "horizontal", "modules": [ "cpu", + "temperature", "memory", - "disk" + "disk", + "battery" ] }, @@ -34,20 +39,65 @@ "sort-by-number": true }, + "custom/layout": { + "exec": "waybar-layout", + "return-type": "json", + "interval": 1, + "on-click": "cycle-layout" + }, + + "hyprland/window": { + "max-length": 50, + "separate-outputs": true + }, + "cpu": { "interval": 10, - "format": "CPU {}%" + "format": "󰍛 {}%", + "on-click": "toggle-scratchpad monitor" + }, + + "temperature": { + "interval": 10, + "hwmon-path-abs": "/sys/devices/pci0000:00/0000:00:18.3/hwmon", + "input-filename": "temp1_input", + "critical-threshold": 80, + "format": "󰔏 {temperatureC}°C", + "format-critical": "󰸁 {temperatureC}°C", + "on-click": "toggle-scratchpad monitor" }, "memory": { "interval": 30, - "format": "MEM {}%" + "format": "󰘚 {}%", + "on-click": "toggle-scratchpad monitor" }, "disk": { "interval": 30, - "format": "DSK {percentage_used}%", - "path": "/" + "format": "󰆼 {percentage_used}%", + "path": "/", + "on-click": "toggle-scratchpad monitor" + }, + + "custom/netspeed": { + "exec": "waybar-netspeed", + "return-type": "json", + "interval": 2, + "on-click": "toggle-scratchpad network" + }, + + "battery": { + "interval": 30, + "states": { + "warning": 30, + "critical": 15 + }, + "format": "{icon} {capacity}%", + "format-charging": "󰂄 {capacity}%", + "format-plugged": "󰚥 {capacity}%", + "format-icons": ["󰂎", "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"], + "tooltip-format": "{timeTo}" }, "tray": { @@ -56,7 +106,7 @@ }, "clock": { - "format": "{:%a %d-%m-%Y %I:%M %p}", + "format": "{:%a, %b %d %Y %I:%M %p %Z}", "tooltip-format": "{calendar}", "calendar": { "format": { @@ -66,10 +116,10 @@ }, "wireplumber": { - "format": "{volume}% {icon}", - "format-muted": "Muted 󰝟", - "format-icons": ["", "", ""], + "format": "󰕾 {volume}%", + "format-muted": "󰝟 Muted", "on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", + "on-click-right": "toggle-scratchpad audio", "on-scroll-up": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+", "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" } diff --git a/dotfiles/hyprland/.config/waybar/style.css b/dotfiles/hyprland/.config/waybar/style.css index 88dd0f8..6b760a2 100644 --- a/dotfiles/hyprland/.config/waybar/style.css +++ b/dotfiles/hyprland/.config/waybar/style.css @@ -46,11 +46,16 @@ window#waybar { } #cpu, +#temperature, #memory, #disk, +#custom-netspeed, +#battery, #wireplumber, #tray, -#clock { +#clock, +#custom-layout, +#window { padding: 0.4rem; margin: 0.3rem; color: #bbbbbb; @@ -65,10 +70,13 @@ window#waybar { } #cpu:hover, +#temperature:hover, #memory:hover, #disk:hover, +#custom-netspeed:hover, #wireplumber:hover, -#sysmonitor:hover { +#sysmonitor:hover, +#custom-layout:hover { background-color: #444444; border-radius: 1rem; } @@ -78,13 +86,21 @@ window#waybar { } #wireplumber { - color: #daa520; + color: #bbbbbb; } #wireplumber.muted { color: #666666; } +#battery.warning { + color: #daa520; +} + +#battery.critical { + color: #ff5858; +} + #tray > .passive { -gtk-icon-effect: dim; } diff --git a/dotfiles/hyprland/.local/bin/cycle-layout b/dotfiles/hyprland/.local/bin/cycle-layout new file mode 100755 index 0000000..a3b1b1a --- /dev/null +++ b/dotfiles/hyprland/.local/bin/cycle-layout @@ -0,0 +1,30 @@ +#!/bin/sh +# Cycle through Hyprland layouts + +LAYOUT=$(hyprctl getoption general:layout -j | jq -r '.str') +ORIENTATION="" + +if [ "$LAYOUT" = "master" ]; then + ORIENTATION=$(hyprctl getoption master:orientation -j | jq -r '.str') +fi + +# Cycle: master-left -> master-top -> master-center -> dwindle -> master-left +if [ "$LAYOUT" = "dwindle" ]; then + hyprctl keyword general:layout master + hyprctl keyword master:orientation left +elif [ "$LAYOUT" = "master" ]; then + case "$ORIENTATION" in + left) + hyprctl keyword master:orientation top + ;; + top) + hyprctl keyword master:orientation center + ;; + center) + hyprctl keyword general:layout dwindle + ;; + *) + hyprctl keyword master:orientation left + ;; + esac +fi diff --git a/dotfiles/hyprland/.local/bin/toggle-scratchpad b/dotfiles/hyprland/.local/bin/toggle-scratchpad new file mode 100755 index 0000000..bb10ef7 --- /dev/null +++ b/dotfiles/hyprland/.local/bin/toggle-scratchpad @@ -0,0 +1,29 @@ +#!/bin/sh +# Toggle a special workspace from waybar click +# Tracks state to handle focus-loss auto-close issue +# Usage: toggle-scratchpad + +NAME="$1" +if [ -z "$NAME" ]; then + echo "Usage: toggle-scratchpad " + exit 1 +fi + +STATEFILE="/tmp/scratchpad-$NAME-open" +NOW=$(date +%s) + +# If state file exists and recent, scratchpad was open and just closed by focus loss +# Don't reopen it - user intended to close +if [ -f "$STATEFILE" ]; then + LAST=$(cat "$STATEFILE") + AGE=$((NOW - LAST)) + rm -f "$STATEFILE" + if [ "$AGE" -lt 2 ]; then + # Was just open, user clicked to close - don't reopen + exit 0 + fi +fi + +# Opening the scratchpad - mark timestamp +echo "$NOW" > "$STATEFILE" +hyprctl dispatch togglespecialworkspace "$NAME" diff --git a/dotfiles/hyprland/.local/bin/waybar-layout b/dotfiles/hyprland/.local/bin/waybar-layout new file mode 100755 index 0000000..7ffb8a8 --- /dev/null +++ b/dotfiles/hyprland/.local/bin/waybar-layout @@ -0,0 +1,54 @@ +#!/bin/sh +# Hyprland layout indicator for waybar +# Shows current layout with nerd font icons + +# Get current layout +LAYOUT=$(hyprctl getoption general:layout -j | jq -r '.str') + +# Get master orientation if using master layout +ORIENTATION="" +if [ "$LAYOUT" = "master" ]; then + ORIENTATION=$(hyprctl getoption master:orientation -j | jq -r '.str') +fi + +# Check if active window is fullscreen (monocle) +FULLSCREEN=$(hyprctl activewindow -j | jq -r '.fullscreen') + +# Check if active window is floating +FLOATING=$(hyprctl activewindow -j | jq -r '.floating') + +# Determine icon and tooltip +if [ "$FULLSCREEN" = "2" ] || [ "$FULLSCREEN" = "1" ]; then + ICON="󰊓" + TOOLTIP="Monocle (fullscreen)" +elif [ "$FLOATING" = "true" ]; then + ICON="󰖲" + TOOLTIP="Floating" +elif [ "$LAYOUT" = "dwindle" ]; then + ICON="󱒎" + TOOLTIP="Dwindle" +elif [ "$LAYOUT" = "master" ]; then + case "$ORIENTATION" in + left) + ICON="󰕰" + TOOLTIP="Master (left)" + ;; + top) + ICON="󱂩" + TOOLTIP="Master (top)" + ;; + center) + ICON="󰘸" + TOOLTIP="Master (center)" + ;; + *) + ICON="󰕰" + TOOLTIP="Master" + ;; + esac +else + ICON="󰕰" + TOOLTIP="Unknown" +fi + +echo "{\"text\": \"$ICON\", \"tooltip\": \"$TOOLTIP\"}" diff --git a/dotfiles/hyprland/.local/bin/waybar-netspeed b/dotfiles/hyprland/.local/bin/waybar-netspeed new file mode 100755 index 0000000..504ad8c --- /dev/null +++ b/dotfiles/hyprland/.local/bin/waybar-netspeed @@ -0,0 +1,52 @@ +#!/bin/sh +# Network speed monitor with fixed-width output for waybar +# Outputs JSON with upload/download speeds padded to consistent width + +INTERFACE=$(ip route | awk '/default/ {print $5; exit}') + +if [ -z "$INTERFACE" ]; then + echo '{"text": "No network", "class": "disconnected"}' + exit 0 +fi + +RX1=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes) +TX1=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes) +sleep 1 +RX2=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes) +TX2=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes) + +RX_RATE=$((RX2 - RX1)) +TX_RATE=$((TX2 - TX1)) + +format_speed() { + local bytes=$1 + if [ $bytes -ge 1073741824 ]; then + printf "%6.2f G" $(echo "scale=2; $bytes / 1073741824" | bc) + elif [ $bytes -ge 1048576 ]; then + printf "%6.2f M" $(echo "scale=2; $bytes / 1048576" | bc) + elif [ $bytes -ge 1024 ]; then + printf "%6.2f K" $(echo "scale=2; $bytes / 1024" | bc) + else + printf "%6d B" $bytes + fi +} + +UP=$(format_speed $TX_RATE) +DOWN=$(format_speed $RX_RATE) + +# Get IP for tooltip +IP=$(ip -4 addr show $INTERFACE | awk '/inet / {print $2}') + +# Check if WiFi and get SSID +SSID="" +if command -v iwgetid >/dev/null 2>&1; then + SSID=$(iwgetid -r 2>/dev/null) +fi + +if [ -n "$SSID" ]; then + TOOLTIP="$SSID ($INTERFACE: $IP)" +else + TOOLTIP="$INTERFACE: $IP" +fi + +echo "{\"text\": \"${UP} 󰕒 ${DOWN} 󰇚\", \"tooltip\": \"$TOOLTIP\", \"class\": \"connected\"}" -- cgit v1.2.3