-
Notifications
You must be signed in to change notification settings - Fork 0
Widgets
Widgets are configured under [widgets] in config.toml. The panel renders quick controls,
media, toggles, stats, and cards in that order. Widgets can be disabled by setting
enabled = false or removing entries from the list.
-
refresh_interval_ms: fast polling interval (milliseconds). -
refresh_interval_slow_ms: slower interval used during stable periods.
Widgets with watch_cmd can update based on events and reduce polling. When a watch
command is missing or fails, the widget falls back to polling.
- Quick controls (
[widgets.volume],[widgets.brightness]) - Media (
[media], when enabled and an active player is present) - Toggles (
[[widgets.toggles]]) - Stats (
[[widgets.stats]]) - Cards (
[[widgets.cards]])
Default slider backends:
- Volume:
wpctl(PipeWire/WirePlumber) - Brightness:
brightnessctl
Default toggles:
- Wi-Fi:
nmcli - Bluetooth:
bluetoothctl(watch:dbus-monitor) - Airplane:
rfkill(watch:udevadm) - Night:
gammastep(Hyprland prefershyprsunsetwhen available)
Default stats:
- CPU:
builtin:cpu - RAM:
builtin:memory - Battery:
builtin:battery
Default cards:
- Calendar: built-in GTK calendar
- Weather: styled card with no built-in data (set
cmdto populate)
Runtime backends can migrate to alternatives when a preferred command is missing.
- Simple commands run directly (no shell).
- Commands containing shell syntax are run through
sh -c. - Simple commands are faster and avoid shell overhead.
When a pipeline is required, use an explicit shell command:
cmd = "sh -c 'sensors | awk \"/Package id 0/ { print $4 }\"'"[widgets.volume] and [widgets.brightness] share the same schema:
[widgets.volume]
enabled = true
label = "Volume"
icon = "audio-volume-high-symbolic"
icon_muted = "audio-volume-muted-symbolic"
get_cmd = "wpctl get-volume @DEFAULT_AUDIO_SINK@"
set_cmd = "wpctl set-volume @DEFAULT_AUDIO_SINK@ {value}%"
toggle_cmd = "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
# watch_cmd = "pactl subscribe"
min = 0.0
max = 100.0
step = 1.0
parse_mode = "auto" # auto | percent | ratioNotes:
-
{value}is replaced with the slider value. -
parse_mode = "ratio"treats0.0..=1.0output as a percentage.
Each toggle entry describes commands for a binary control:
[[widgets.toggles]]
kind = "bluetooth"
label = "Bluetooth"
icon = "bluetooth-active-symbolic"
state_cmd = "bluetoothctl show"
on_cmd = "bluetoothctl power on"
off_cmd = "bluetoothctl power off"
watch_cmd = "dbus-monitor --system type=signal,sender=org.bluez"Notes:
-
kind(orid) applies runtime defaults and is the stable backend identifier. -
watch_cmdis optional and may be disabled at runtime if unavailable.
Each toggle always has the base class:
.unixnotis-toggle
In addition, when kind is set, the UI adds a stable kind-specific class:
.unixnotis-toggle-kind-<kind>
This enables per-toggle styling (for example: Wi-Fi and Bluetooth can have different accent colors) without duplicating widget configs.
Class generation rules:
- Lowercases ASCII letters.
- Converts
_and non-alphanumeric characters to-. - Collapses repeated
-and trims leading/trailing-. - If the result is empty, no kind-specific class is added.
Example:
.unixnotis-toggle.unixnotis-toggle-kind-wifi {
border-color: alpha(@unixnotis-accent, 0.5);
}
.unixnotis-toggle.unixnotis-toggle-kind-bluetooth {
border-color: alpha(@unixnotis-accent-2, 0.5);
}Stats can use built-in readers or custom commands. Built-ins read from procfs/sysfs and avoid process spawns.
Built-in tags:
builtin:cpubuiltin:memorybuiltin:loadbuiltin:battery-
builtin:netorbuiltin:net:INTERFACE
Example:
[[widgets.stats]]
label = "Network"
icon = "network-wired-symbolic"
cmd = "builtin:net:enp3s0"
min_height = 72If cmd is a shell command, its stdout is used as the widget value.
Cards show multi-line content and are commonly used for calendar or custom scripts.
[[widgets.cards]]
kind = "calendar"
title = "Calendar"
subtitle = "Today"
icon = "x-office-calendar-symbolic"
cmd = "date '+%A, %B %d'"
min_height = 180
monospace = falseNotes:
- When
kind = "calendar"andcmdis omitted, a GTK calendar is rendered. - When
kind = "weather"andcmdis omitted, the card shows the configured subtitle.
The calendar card is a GTK GtkCalendar widget. Its CSS node tree (per GTK4 docs)
looks like:
calendar.view
+-- header
| +-- button
| +-- stack.month
| +-- button
| +-- button
| +-- label.year
| +-- button
+-- grid
+-- label[.day-name][.week-number][.day-number][.other-month][.today]
Useful selectors in widgets.css:
-
.unixnotis-calendarfor the card root -
.unixnotis-calendar .headerfor the header row -
.unixnotis-calendar .day-name,.day-number,.other-month,.today,:selected -
.unixnotis-calendar header > button:nth-child(1)(prev month) -
.unixnotis-calendar header > button:nth-child(3)(next month) -
.unixnotis-calendar header > button:nth-child(4)(prev year) -
.unixnotis-calendar header > button:nth-child(6)(next year)
Example (icon-forced month navigation):
.unixnotis-calendar header > button:nth-child(1) {
-gtk-icon-source: -gtk-icontheme("go-previous-symbolic");
}
.unixnotis-calendar header > button:nth-child(3) {
-gtk-icon-source: -gtk-icontheme("go-next-symbolic");
}Stats and cards support an external plugin block:
[[widgets.stats]].plugin[[widgets.cards]].plugin
When plugin is set, it takes precedence over cmd.
[[widgets.stats]]
label = "VPN"
icon = "network-vpn-symbolic"
min_height = 72
[widgets.stats.plugin]
api_version = 1
command = "scripts/vpn_widget"
timeout_ms = 1500
max_output_bytes = 8192Fields:
-
api_version: currently1. -
command: executable command path + args. -
timeout_ms: command timeout in milliseconds. -
max_output_bytes: maximum accepted stdout payload size.
Security/runtime notes:
- Plugin commands must be simple commands (no shell metacharacters, no
sh -c). - Invalid plugin configs are disabled at runtime with a warning.
- Oversized payloads, invalid JSON, and version mismatches are rejected.
Stdout must be JSON:
{
"api_version": 1,
"text": "42%"
}Stdout must be JSON:
{
"api_version": 1,
"title": "Weather",
"text": "72F, clear"
}Notes:
-
titleis optional; when omitted, configured card title is kept. -
textis required and becomes the card body.
Existing cmd fields remain fully supported:
[[widgets.cards]]
title = "Weather"
icon = "weather-clear-symbolic"
cmd = "scripts/weather.sh"
min_height = 180
monospace = trueGuidelines:
-
cmdstdout becomes the card body (multi-line output is supported). - Prefer watch-based flows where possible to reduce polling pressure.
- Keep scripts fast and deterministic.