Awesome WM widgets configuration

Posted by jason on July 21, 2011, 3:45 p.m.
Tags: arch awesome config linux widgets

I've been using Awesome WM for about six months, and I love it. The hard part was configuring everything--especially the widgets. Before using Awesome, I'd never seen nor heard of lua--the scripting language that awesome uses for its configuration files--but I am a programmer by trade, so it wasn't that hard to hack around until I got what I wanted.

As a first step, if the file ~/.config/awesome/rc.lua doesn't exist, then copy the /etc/xdg/awesome/rc.lua file to your ~/.config/awesome/ directory. Create that directory if need be. Note that I'm using Arch Linux, so things might vary slightly depending on your distribution.

Anyway, here's a list of widgets that I put in awesome's task bar. I hope they help somebody:

Here's a screenshot of what these widgets look like:



Disk Usage Widget

This widget, written by Peter J. Kranz, lists all the partitions that are mounted on your machine and says how much space is used / available on each. The output can be green, yellow, or red depending on what % of the disk is being used. Just edit the rc.lua to change the behaviour.

To use this widget, download the diskusage.lua file, save it in your ~/.config/awesome directory, and add the following to your rc.lua before the line "-- Create a systray":

-- Disk usage widget
diskwidget = widget({ type = 'imagebox' })
diskwidget.image = image("/home/username/.config/awesome/du.png")
disk = require("diskusage")
-- the first argument is the widget to trigger the diskusage
-- the second/third is the percentage at which a line gets orange/red
-- true = show only local filesystems
disk.addToWidget(diskwidget, 75, 90, false)

Notice the reference to "du.png"? That's the icon that will be shown in the task bar. Find an icon you like and save it in the same spot or modify the code block above accordingly.

Now, add the diskwidget you created to the "mywibox" array, which should be in the default rc.lua file already.

    -- Create the wibox
    mywibox[s] = awful.wibox({ position = "top", height = "30", screen = s })
    -- Add widgets to the wibox - order matters
    mywibox[s].widgets = {
        {
            mylauncher,
            mytaglist[s],
            mypromptbox[s],
            layout = awful.widget.layout.horizontal.leftright
        },
        mylayoutbox[s],

        ....
        <Some other custom widgets...>
        ....
        
        diskwidget,
        
        ....
        <Some other custom widgets...>
        ....

Gmail Checker Widget

This widget tells you how many unread messages you have in your gmail account and displays the subject of the latest message on hover. First, you need to put your gmail credentials in ~/.netrc file, like so:

machine mail.google.com login <e-mail address> password <password>

Second, save a gmail icon of your choosing as ~/.config/awesome/gmail.png, or modify the code below.

Third, add the following to your widget declarations in rc.lua, before the "-- Create a systray" line:

-- gmail widget and tooltip
mygmail = widget({ type = "textbox" })
gmail_t = awful.tooltip({ objects = { mygmail },})

mygmailimg = widget({ type = "imagebox" })
mygmailimg.image = image("/home/username/.config/awesome/gmail.png")

vicious.register(mygmail, vicious.widgets.gmail,
                function (widget, args)
                    gmail_t:set_text(args["{subject}"])
                    gmail_t:add_to_object(mygmailimg)
                    return args["{count}"]
                 end, 120) 
                 --the '120' here means check every 2 minutes.

Note that this widget uses the vicious gmail widget. On my Arch Linux system, there's a gmail.lua file in the /usr/share/awesome/lib/vicious/widgets/ directory. See if you can find that directory on your system and take a look: there might be some widgets there that you'd like to use.

Ok, finally, add "mygmail" to the wibox as you did for the disk usage widget. Here's a sample of what it looks like on my desktop when I hover over the gmail icon with my mouse:



Pacman Notifier

This widget is Arch specific: it tells you how many updates are available for your system. If you hover over it, it'll list the updates.

-- Pacman Widget
pacwidget = widget({type = "textbox"})

pacwidget_t = awful.tooltip({ objects = { pacwidget},})

vicious.register(pacwidget, vicious.widgets.pkg,
                function(widget,args)
                    local io = { popen = io.popen }
                    local s = io.popen("pacman -Qu")
                    local str = ''

                    for line in s:lines() do
                        str = str .. line .. "\n"
                    end
                    pacwidget_t:set_text(str)
                    s:close()
                    return "UPDATES: " .. args[1]
                end, 1800, "Arch")

                --'1800' means check every 30 minutes

Note the last parameter of the register.vicious function, "Arch". If you look at the /usr/share/awesome/lib/vicious/widgets/pkg.lua file, you can see different options for various distributions: Arch, Arch S, Debian, Ubuntu, Fedora, FreeBSD, and Mandriva are all valid values here.

Okay, next just add "pacwidget" to the mywibox array, just like we did for the disk usage widget. Here's what the pacman widget looks like:



RAM Usage Widget

The RAM widget shows the memory usage vs. total memory as a vertical progress bar.

Here's the widget code to add to rc.lua with the rest of your widgets:

-- RAM usage widget
memwidget = awful.widget.progressbar()
memwidget:set_width(15)
memwidget:set_height(30)
memwidget:set_vertical(true)
memwidget:set_background_color('#494B4F')
memwidget:set_color('#AECF96')
memwidget:set_gradient_colors({ '#AECF96', '#88A175', '#FF5656' })

-- RAM usage tooltip
memwidget_t = awful.tooltip({ objects = { memwidget.widget },})

vicious.cache(vicious.widgets.mem)
vicious.register(memwidget, vicious.widgets.mem,
                function (widget, args)
                    memwidget_t:set_text(" RAM: " .. args[2] .. "MB / " .. args[3] .. "MB ")
                    return args[1]
                 end, 13)
                 --update every 13 seconds

Add "memwidget" to the mywibox array just like you did for the disk usage widget. Here's the screenshot:



CPU Usage Widget

This widget uses a graph (awful.widget.graph) to display the current and recent CPU usage as a percentage. Like some of the other widgets I use, this widget uses the vicious cpu.lua file, found in /usr/share/awesome/lib/vicious/widgets/cpu.lua on Arch Linux.

Here's the widget code to add to your rc.lua:

-- CPU usage widget
cpuwidget = awful.widget.graph()
cpuwidget:set_width(50)
cpuwidget:set_height(30)
cpuwidget:set_background_color("#494B4F")
cpuwidget:set_color("#FF5656")
cpuwidget:set_gradient_colors({ "#FF5656", "#88A175", "#AECF96" })

cpuwidget_t = awful.tooltip({ objects = { cpuwidget.widget },})

-- Register CPU widget
vicious.register(cpuwidget, vicious.widgets.cpu, 
                    function (widget, args)
                        cpuwidget_t:set_text("CPU Usage: " .. args[1] .. "%")
                        return args[1]
                    end)

Add "cpuwidget" to the mywibox array just like you did for the disk usage widget. Here's the screenshot:



Network Usage Widget

This widget is similar to the CPU usage widget mentioned above. Here's the code for the rc.lua file:

-- Network widget
netwidget = awful.widget.graph()
netwidget:set_width(50)
netwidget:set_height(30)
netwidget:set_background_color("#494B4F")
netwidget:set_color("#FF5656")
netwidget:set_gradient_colors({ "#FF5656", "#88A175", "#AECF96" })

netwidget_t = awful.tooltip({ objects = { netwidget.widget },})

-- Register network widget
vicious.register(netwidget, vicious.widgets.net,
                    function (widget, args)
                        netwidget_t:set_text("Network download: " .. args["{eth0 down_mb}"] .. "mb/s")
                        return args["{eth0 down_mb}"]
                    end)

Add "netwidget" to the mywibox array just like you did for the disk usage widget. Here's the screenshot:



Weather Conditions Widget

Vicious has another nice widget for the weather. Again, you need to have the /usr/share/awesome/lib/vicious/widgets/weather.lua file. You'll also need to know the ICAO code of the location you want to know the weather of. Here's the rc.lua code:

-- Weather widget
weatherwidget = widget({ type = "textbox" })
weather_t = awful.tooltip({ objects = { weatherwidget },})

vicious.register(weatherwidget, vicious.widgets.weather,
                function (widget, args)
                    weather_t:set_text("City: " .. args["{city}"] .."\nWind: " .. args["{windkmh}"] .. "km/h " .. args["{wind}"] .. "\nSky: " .. args["{sky}"] .. "\nHumidity: " .. args["{humid}"] .. "%")
                    return args["{tempc}"] .. "C"
                end, 1800, "CYUL")
                --'1800': check every 30 minutes.
                --'CYUL': the Montreal ICAO code.

You know the drill: add "weatherwidget" to the mywibox array just like you did for the disk usage widget. Here's the screenshot:



Keyboard Layout Switcher Widget

This widget is different from the others so far, because it lets you do something--namely, change between keyboard layouts. It displays the current layout in use, and I set up the left mouse click to change between US, Spanish, and Canadian keyboard layouts. It uses Xorg's "setxkbmap" command to do the switch. Here's the rc.lua widget code:

-- Keyboard widget
kbdcfg = {}
kbdcfg.cmd = "setxkbmap"

--list your own keyboard layouts here
kbdcfg.layout = { "us","es","ca" }

kbdcfg.current = 1
kbdcfg.widget = widget({ type = "textbox", align = "right" })
kbdcfg.widget.text = " " .. kbdcfg.layout[kbdcfg.current] .. " "
kbdcfg.switch = function ()
    kbdcfg.current = kbdcfg.current % #(kbdcfg.layout) + 1
    local t = " " .. kbdcfg.layout[kbdcfg.current] .. " "
    kbdcfg.widget.text = t
    os.execute( kbdcfg.cmd .. t )
end

kbdcfg.widget:buttons(awful.util.table.join(
    awful.button({ }, 1, function () kbdcfg.switch() end)
))

You may have guessed the next step: add "kbdcfg.widget" to the mywibox array just like you did for the disk usage widget. Here's a rather boring screenshot:



Volume Control Widget

This widget is a must-have for Awesome: to be able to control the volume from the taskbar. I've set things up so that when you hover over the volume widget, the scroll wheel will raise and lower the volume. Left-clicking the widget will mute and unmute the volume. I also set up the special keys on my keyboard to control the volume as well.

Here's the basic widget code for the rc.lua file that handles the mouse buttons:

-- Volume widget

volumecfg = {}
volumecfg.cardid  = 0
volumecfg.channel = "Master"
volumecfg.widget = widget({ type = "textbox", name = "volumecfg.widget", align = "right" })

volumecfg_t = awful.tooltip({ objects = { volumecfg.widget },})
volumecfg_t:set_text("Volume")

-- command must start with a space!
volumecfg.mixercommand = function (command)
       local fd = io.popen("amixer -c " .. volumecfg.cardid .. command)
       local status = fd:read("*all")
       fd:close()

       local volume = string.match(status, "(%d?%d?%d)%%")
       volume = string.format("% 3d", volume)
       status = string.match(status, "%[(o[^%]]*)%]")
       if string.find(status, "on", 1, true) then
               volume = volume .. "%"
       else
               volume = volume .. "M"
       end
       volumecfg.widget.text = volume
end
volumecfg.update = function ()
       volumecfg.mixercommand(" sget " .. volumecfg.channel)
end
volumecfg.up = function ()
       volumecfg.mixercommand(" sset " .. volumecfg.channel .. " 1%+")
end
volumecfg.down = function ()
       volumecfg.mixercommand(" sset " .. volumecfg.channel .. " 1%-")
end
volumecfg.toggle = function ()
       volumecfg.mixercommand(" sset " .. volumecfg.channel .. " toggle")
end
volumecfg.widget:buttons({
       button({ }, 4, function () volumecfg.up() end),
       button({ }, 5, function () volumecfg.down() end),
       button({ }, 1, function () volumecfg.toggle() end)
})
volumecfg.update()

Here's the code in rc.lua to bind my special keyboard keys to the different controls. I've put the lines I added in bold. Most of the other stuff should be in the default rc.lua already.

-- Bind all key numbers to tags.
-- Be careful: we use keycodes to make it works on any keyboard layout.
-- This should map on the top row of your keyboard, usually 1 to 9.
for i = 1, keynumber do
    globalkeys = awful.util.table.join(globalkeys,
        awful.key({ modkey }, "#" .. i + 9,
                  function ()
                        local screen = mouse.screen
                        if tags[screen][i] then
                            awful.tag.viewonly(tags[screen][i])
                        end
                  end),
        awful.key({ modkey, "Control" }, "#" .. i + 9,
                  function ()
                      local screen = mouse.screen
                      if tags[screen][i] then
                          awful.tag.viewtoggle(tags[screen][i])
                      end
                  end),
        awful.key({ modkey, "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus and tags[client.focus.screen][i] then
                          awful.client.movetotag(tags[client.focus.screen][i])
                      end
                  end),
        awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
                  function ()
                      if client.focus and tags[client.focus.screen][i] then
                          awful.client.toggletag(tags[client.focus.screen][i])
                      end
                  end),
        awful.key({ }, "XF86AudioRaiseVolume", function () volumecfg.up() end),
        awful.key({ }, "XF86AudioLowerVolume", function () volumecfg.down() end),
        awful.key({ }, "XF86AudioMute", function () volumecfg.toggle() end))

end

Add "volumecfg.widget" to the mywibox array just like you did for the disk usage widget. Here's another boring screenshot:



Date / Time / Calendar Widget

The last widget I added is for date and time. It displays the date and time, and on hover it shows the full month view. A left-click will view the previous month and a right-click will view the next month. Here's the rc.lua widget code:

-- Create a textclock widget
mytextclock = awful.widget.textclock({ align = "right" })

-- Calendar widget to attach to the textclock
require('calendar2')
calendar2.addCalendarToWidget(mytextclock)

Note that you'll need to have a file named ~/.config/awesome/calendar2.lua for this code to work. I've linked to it (and other files) at the bottom of this page. Thanks to Bzed and Marc Dequènes.

Add "mytextclock" to the mywibox array just like you did for the disk usage widget. Here's one last screenshot:



Full Awesome WM Configuration

Below you can find my full rc.lua and theme.lua files, as well as the necessary widget files (diskusage.lua and calendar2.lua). Feel free to hack them to do what you want.

Note that you need to install "awsetbg" if you don't already have it, or you can use a different program to set the desktop background (see the line "theme.wallpaper_cmd = { "awsetbg -a /home/username/.config/awesome/background.jpg" }" in theme.lua).

There are also a bunch of images that I haven't included here. You'll see references to them in the rc.lua and theme.lua files: all of them are "/home/username/.config/awesome/*.png" or .jpg.

Leave a comment below and let me know what you think.


10 comments

Derek #1

Thanks so much for posting this. Very clear and concise. It's exactly what I've been looking for and finally motivated me to personalize my awesome install.

I ended up altering the volume widget so it used an icon that changed based on the level or if it was muted.

My arch install is on my laptop, so I made myself a little battery monitor and stuck it next to the volume icon.

Good find on the calendar. Just what I was looking for.

I ended up adding some mpd controls and didn't end up using the network graphs. I had trouble getting scaling to work well. Maybe I'll give it a try again later

Didn't use the mem widget, either. Don't find myself looking at mem usage that much these days.

And because it's funner, here are some screenies of my desktop
Clean
http://imageshack.us/photo/my-images/214/201112150157181280x1024.png/
Dirty
http://imageshack.us/f/190/201112150155491280x1024.png/

Thanks again.

Derek #2

Well, I never liked those \n anyways :p

jason #3

Hi Derek,

Glad you found it useful. You might be interested in my tooltip example, which gives a specific example of creating / running custom shell scripts and displaying the output in Awesome's wibar.

Thanks for pointing out my lack of nl2br'ing--fixed now ;)

Sorky #4

Used your volume idea - adapted to images

myvolume.widget = widget({ type = "imagebox", name = "myvolume.widget" })
myvolume.widget.image = image(awful.util.getdir("config") .. "/icons/audio-volume-muted.png")
myvolume.tooltip = awful.tooltip({ objects = { myvolume.widget },})
myvolume.mixercommand = function (command)
local fd = io.popen("amixer -c " .. myvolume.cardid .. " " .. command)
local status = fd:read("*all")
fd:close()

local volume = string.match(status, "(%d?%d?%d)%%")

status = string.match(status, "%[(o[^%]]*)%]")
if string.find(status, "on", 1, true) then
if tonumber(volume) < 50 then
myvolume.widget.image = image(awful.util.getdir("config") .. "/icons/audio-volume-low.png")
else
if tonumber(volume) < 100 then
myvolume.widget.image = image(awful.util.getdir("config") .. "/icons/audio-volume-medium.png")
else
myvolume.widget.image = image(awful.util.getdir("config") .. "/icons/audio-volume-high.png")
end
end
else
myvolume.widget.image = image(awful.util.getdir("config") .. "/icons/audio-volume-muted.png")
end

myvolume.tooltip:set_text(volume .. "%")
end

Pascal #5

Really nice !

Pascal #6

Please do other post on awesome!

jason #7

@Pascal:

Hmm, don't know what else I could post on. The truth is, I recently switched to i3 and I'm pretty hooked at the moment. I really like how it handles containers and the windows and containers are part of a tree. The downside is I haven't figured out how to have as much with with widgets as you can in Awesome ;) .

Gnibu #8

Great post, thanks a lot!

Pascha #9

Hey man, thank you so much for volume widget, just what I was looking for! Works as charm on my latitude e5400!

Frew Schmidt #10

Great post, saved me so much time having to look through docs :D