How to write a simple AwesomeWM widget
Sometimes it's useful to be able to cook up a simple widget for you desktop environment. With AwesomeWM this is easy to do if you can handle some lua. Let's see how to write a simple one that shows us the internal temperature of the computer.
watch
blocks (call collectgarbage()
at the end of the watch
).
See: related issue.
The base
The first step is to create a module to host the base widget.
By default AwesomeWM configuration is stored on ~/.config/awesome/
, so we'll create
a directory there.
mkdir -p ~/.config/awesome/my-widgets
And inside there create a file, say ~/.config/awesome/my-widgets/temperature.lua
.
Inside that module we can add some commands to create and configure the widget, and
export it.
The widget will be composed of two elements, an internal one which contains the text temp_text
,
and another that provides a background for the first, temp_widget
.
The one which provides the background is contains the first one, so is the one that we'll export.
-------------------------------------------------
-- Temperature widget
-------------------------------------------------
local wibox = require("wibox") -- Provides the widgets
local watch = require("awful.widget.watch")
-- Create the text widget
local temp_text = wibox.widget{
font = "Play 9",
widget = wibox.widget.textbox,
}
-- Create the background widget
local temp_widget = wibox.widget.background()
temp_widget:set_widget(temp_text) -- Put the text inside of it
-- Set the colors and some text
temp_widget:set_bg("#008800") -- Green background
temp_widget:set_fg("#ffffff") -- White text
temp_text:set_text(" This is a simple widget ")
-- Export the widget
return temp_widget
Now let's show this widget in our desktop. Check that you have an ~/.config/awesome/rc.lua
file.
If you don't you can copy there the one in /etc/xdg/awesome/rc.lua
.
Ok, so in the rc.lua
file let's import the widget.
Since the route to the module from the rc.lua
is my-widgets/temperature.lua
, we can import it with
local temperature_widget = require("my-widgets.temperature")
So add that line on the rc.lua
after the other require()
's to import it.
We'll also have to place the widget, we could for example add it just left of the systray.
To do that locate with wibox.widget.systray(),
and place the temperature_widget
before, like this:
...
temperature_widget,
wibox.widget.systray(),
...
After this we can reload AwesomeWM with ModKey + Ctrl + R and see the result.
Make it move
Ok, so we already have a working widget, now we have to make it display something interesting. The computer temperature is something useful, so we'll go with that, but in the end is up to what you can come up with.
So, back on the temperature.lua
file we'll import the watch
module, which will allow us to monitor
the output of a command and update the widget according to it:
...
-- Let's say we did everything, just not returning temp_widget yet
local watch = require("awful.widget.watch")
watch("acpi -t", 10, function(widget, stdout, stderr, exitreason, exitcode)
-- Do something, for example
temp_text:set_text(stdout)
end,
temp_widget
)
return temp_widget
The code above will update the widget with the raw output of the command, which will be run every 10 seconds.
Now, let's extract the temperature from the command and set the background depending on it.
...
function(_, stdout, stderr, exitreason, exitcode)
local temp = nil
-- This loop matches the groups number(s).number(s)
-- each pair is converted to a number and saved on `temp`
-- (Only the last group is kept)
for str in string.gmatch(stdout, "([0-9]+.[0-9]+)") do
temp = tonumber(str)
end
-- Set that as text (not just the raw command)
temp_widget_text:set_text(" " .. temp .. "ºC ")
-- Set colors depending on the temperature
if (temp < 70) then
temp_widget:set_bg("#008800") -- Green
temp_widget:set_fg("#ffffff")
elseif (temp < 80) then
temp_widget:set_bg("#AB7300") -- Orange
temp_widget:set_fg("#ffffff")
was_down = true
else
temp_widget:set_bg("#880000") -- Red
temp_widget:set_fg("#ffffff")
was_down = true
end
end,
...
And now we have our widget:
This is the code of the widget all together:
-------------------------------------------------
-- Temperature widget
-------------------------------------------------
local wibox = require("wibox") -- Provides the widgets
local watch = require("awful.widget.watch") -- For periodic command execution
-- Create the text widget
local temp_text = wibox.widget{
font = "Play 9",
widget = wibox.widget.textbox,
}
-- Create the background widget
local temp_widget = wibox.widget.background()
temp_widget:set_widget(temp_text)
-- Set the base colors (will be immediately replaced)
temp_widget:set_bg("#008800") -- Green background
temp_widget:set_fg("#ffffff") -- White text
watch(
"acpi -t", 10,
function(_, stdout, stderr, exitreason, exitcode)
local temp = nil
-- This loop matches the groups number(s).number(s)
-- each pair is converted to a number and saved on `temp`
-- (Only the last group is kept)
for str in string.gmatch(stdout, "([0-9]+.[0-9]+)") do
temp = tonumber(str)
end
-- Set that as text (not just the raw command)
temp_text:set_text(" " .. temp .. "ºC ")
-- Set colors depending on the temperature
if (temp < 70) then
temp_widget:set_bg("#008800")
temp_widget:set_fg("#ffffff")
elseif (temp < 80) then
temp_widget:set_bg("#AB7300")
temp_widget:set_fg("#ffffff")
was_down = true
else
temp_widget:set_bg("#880000")
temp_widget:set_fg("#ffffff")
was_down = true
end
-- Launch the garbage collector, this only has to be on one
-- widget (no problem if there's more though).
-- See: https://github.com/awesomeWM/awesome/issues/2858#issuecomment-980489840
collectgarbage()
end,
temp_widget
)
temp_text:set_text(" ??? ")
-- Export the widget
return temp_widget