Event Driven Awesomewm Statusbar
Because creating thousands of processes a day to repeatedly learn that my brightness hadn’t changed was bothering me more than it probably should have.
TL;DR
Single long running process monitors metrics like battery, volume, brightness, wifi
and emits events to stdout. awesomewm parses events and emits signals, based on which
widgets can modify state.
On git: https://codeberg.org/ishmael/statusmon
Root cause
Almost all widget library options for awesomewm involve long-polling. While it’s acceptable for some metrics like battery where there is no async option available, it’s utterly inefficient for things like volume and brightness that rarely change.
Moreover, it results in creating a new process every two seconds, and end up not doing anything at all.
Solution
So instead of polling on every metric like volume, brightness, etc. I start a
single process statusmon that writes events to stdout. Then, I’ll have awesomewm
read from it and emit lua signals.
The Monitor
I chose golang for writing the statusmon monitor. This application is a perfect
usecase for go’s goroutines and channels concurrency model.
Each metric component (volume, wifi, brightness, battery) will recieve a channel, to which events will be emitted. Since lua lacks a encoding / decoding library, emitted events will be serialized into an constant expression that reutrns lua tables, which will then be evaluated in a sandbox inside awesomewm.
Example:
return {percent=45, provider="brightness"}
return {capacity=85, charging=true, batname="BAT0", provider="battery"}
return {connected=true, ssid="RAP", ip="10.147.11.89", provider="wifi"}
return {volume=0.289998, muted=false, provider="volume"}Awesomewm integration
In awesomewm, I simply start the process with a line callback that safely evaluates lua tables and emits events based on the provider.
LUA
|
|
Safe evaluation of lua is important, since we don’t want possible bugs in statusmon to result in
arbitrary lua code execution inside awesomewm. So I created this safeeval function
that sandboxes expressions to text-only lua code, with no access to any functions.
LUA
|
|
Integration with widgets is simple. Attach callbacks to appropriate statusd event, and modify state accordingly.
LUA
|
|
End result
This ended up being one of the more successful side quests to come out of my binary exploitation rabbit holes.
Most importantly, I no longer have to think about all those unnecessary CPU cycles and battery power being spent polling brightness and volume every couple of seconds. That’s one less thing for my inner performance gremlin to obsess over.