Intervals¶
Use interval with on_interval when a widget needs to poll.
EasyBar schedules intervals per widget. If a widget sets interval = 1800,
the backend starts that widget's timer when the widget registers its interval
handler and fires on_interval 1800 seconds later, then every 1800 seconds
after that. It does not wait for the next wall-clock boundary.
local clock
clock = easybar.add(easybar.kind.item, "clock", {
position = "right",
order = 10,
interval = 60,
label = os.date("%H:%M"),
on_interval = function()
clock:set({
label = os.date("%H:%M"),
})
end,
})
Flow¶
flowchart TD
A["Widget loads in Lua"] --> B["Widget declares interval and on_interval"]
B --> C["Lua publishes widget-scoped interval subscription"]
C --> D["Swift EventManager stores widget schedule"]
D --> E["Swift TimerEvents starts repeating timer for that widget"]
E --> F["Interval elapses"]
F --> G["Swift emits targeted interval_tick for that widget"]
G --> H["Lua dispatches only that widget's on_interval handler"]
H --> I["Widget updates state and re-renders"]
I --> E
Timing semantics¶
interval = 60means 60 seconds after registration, then every 60 seconds after that.- Each widget owns its own cadence.
- Changing
intervalreplaces that widget's schedule with a new one. - Removing the widget removes its interval schedule.
Referencing the node itself¶
When an interval callback needs to reference its own handle, declare the variable before assigning it:
local clock
clock = easybar.add(easybar.kind.item, "clock", {
interval = 60,
on_interval = function()
clock:set({
label = os.date("%H:%M"),
})
end,
})
Do not write this:
local clock = easybar.add(easybar.kind.item, "clock", {
interval = 60,
on_interval = function()
clock:set({
label = os.date("%H:%M"),
})
end,
})
The callback may close over clock before it has been assigned.
When to use intervals¶
Use intervals for polling:
- package manager state
- shell command output
- API checks
- periodic time-based updates
Use event subscriptions for real events:
network_changewifi_changevolume_changesystem_woke- mouse events
One-shot delays¶
Use easybar.after(delay_seconds, callback) for one non-blocking callback. The delay is owned by the
Swift host, so it does not launch sleep, consume an async command slot, or block the Lua runtime.
local pending_refresh
local function schedule_refresh()
if pending_refresh ~= nil then
pending_refresh:cancel()
end
pending_refresh = easybar.after(3, function()
pending_refresh = nil
refresh()
end)
end
The returned timer handle supports timer:cancel(). Cancellation returns true only while the
callback is still pending. Timer handles belong to the current Lua runtime session and should not be
persisted across reloads.
Network work after wake¶
system_woke is emitted promptly after macOS reports wake. EasyBar does not delay the event globally
because non-network widgets may need to react immediately. A widget that depends on Wi-Fi, VPN
routes, or DNS should schedule its own short delay and then use bounded retries for transient network
failures.
The bundled GitHub, GitLab, and Homebrew inbox widgets use a three-second wake delay and retry read-only checks after two and five seconds. Authentication failures and mutating operations are not retried.