Farhavens volume widget

Introduction
This guide walks you through setting up a volume widget for Awesome 3, very much similar to Woffles Volume Widget. In fact, originally this was his volume widget, I adapted it to Awesome 3's Lua syntax and gave it a little pepper with Luas string manipulation functions.

The widget works like this:
 * You'll have the volume displayed in your status bar, followed by a % sign if the channel is unmuted and M if it's muted
 * Pressing the left mouse-button on the widget will toggle muting
 * Scrolling up or down will change the volume
 * (Optional) Your media keys (if you have any) will control the volume as long as you are inside your X session and it is not locked

You'll need the following for this widget to work:


 * amixer
 * awesome 3 (something >= 3.1)

Note on point 2: It should be fairly simple to adapt this widget to the 3.0 release version, it's only that this exact code will not work with the stable release and earlier GIT versions. This widget has been tested and is working on 3.4.10.

Preparation
The preparation is the same as with Woffles Volume Widget.

Adding the widget
Add this widget definition to your rc.lua:

tb_volume = widget({ type = "textbox", name = "tb_volume", align = "right" }) tb_volume:buttons({ 	button({ }, 4, function  volume("up", tb_volume) end),  	button({ }, 5, function  volume("down", tb_volume) end),  	button({ }, 1, function  volume("mute", tb_volume) end)  }) volume("update", tb_volume)

don't forget to add the widget tb_volume to your widget box like this:

wi_widgets[s]:widgets({ 	tl_taglist,  	lb_layout[s],  	tb_prompt,  	tl_tasklist,  	tb_volume,  	tb_clock  	})

Bringing the widget to life
Now it's time to bring the widget to life, using the following code. Paste it right at the beginning of your rc.lua, below those lines starting with require. Change the value of cardid to the ID of your card and the value of channel to the channel you want to manage.

cardid = 0 channel = "Master" function volume (mode, widget) if mode == "update" then local fd = io.popen("amixer -c " .. cardid .. " -- sget " .. channel) 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 widget.text = volume elseif mode == "up" then io.popen("amixer -q -c " .. cardid .. " sset " .. channel .. " 5%+"):read("*all") volume("update", widget) elseif mode == "down" then io.popen("amixer -q -c " .. cardid .. " sset " .. channel .. " 5%-"):read("*all") volume("update", widget) else io.popen("amixer -c " .. cardid .. " sset " .. channel .. " toggle"):read("*all") volume("update", widget) end end

Finally, we will be adding a timer hook to refresh the volume display every 10 seconds to reflect changes made by, for example, alsamixer:

awful.hooks.timer.register(10, function volume("update", tb_volume) end)

This line should be pasted at the end of your rc.lua

Setting keybindings
If you have multimedia keys on your keyboard which currently do nothing but look nice, you may want to add these lines to your rc.lua:

globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "XF86AudioRaiseVolume",function volume("up", tb_volume) end)) globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "XF86AudioLowerVolume",function  volume("down", tb_volume) end)) globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "XF86AudioMute",function  volume("mute", tb_volume) end))

Or use 'xev' and see what keycode those buttons have then do something like: globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "#176",function volume("up", tb_volume) end))

Calmar's mod
Calmar has modded this widget to contain a progressbar instead of a textbox.

An example progressbar for it:

pb_volume = widget({ type = "progressbar", name = "pb_volume", align = "right" }) pb_volume.width = 12 pb_volume.height = 1 pb_volume.border_padding = 1 pb_volume.border_width = 1 pb_volume.ticks_count = 8 pb_volume.gap = 0 pb_volume.vertical = true pb_volume:bar_properties_set("vol",  {     ["bg"] = "#000000",    ["fg"] = "green",    ["fg_center"] = "yellow",    ["fg_end"] = "red",    ["fg_off"] = "black",    ["border_color"] = "#999933",    ["min_value"] = 0,    ["max_value"] = 100,    ["reverse"] = false  })

Note: You need to replace every occurence of the old widget name (e.g. in the keybindings) with the new name (pb_volume)

Replace the 3 lines in the original volume(...) function to do stuff on the progressbar, rather than tweaking 'text':

1. volume = volume .. "%"          --replace with (set 'normal' bg color): widget:bar_properties_set("vol", {["bg"] = "#000000"}) 2. volume = volume .. "M"          --replace with (set 'mute' bg color): widget:bar_properties_set("vol", {["bg"] = "#cc3333"}) 3. widget.text = volume            --replace with (just set the value what has to be shown): widget:bar_data_add("vol", volume)

final function

The widget might looks nicer when using 'ticks'. But since the widget is built always homogenuous, you need to tweak the number of ticks (maybe even the height of the widget) to get a not shrunken widget.

I have a good result with 7. (with 6 the widget is shrunken too much. With 8 it can't get drawn (the box will still get drawn!)).

Screenshot:



Farhavens mod
I myself have also modded this widget to display a an ASCII bar instead of the simple number display. The bar looks like this:

-[||||-]+

The new code for the volume function would be:

function volume (mode, widget) local cardid = 0 local channel = "Master" if mode == "update" then local status = io.popen("amixer -c " .. cardid .. " -- sget " .. channel):read("*all") local volume = tonumber(string.match(status, "(%d?%d?%d)%%")) status = string.match(status, "%[(o[^%]]*)%]") local color = "#FF0000" if string.find(status, "on", 1, true) then color = "#00FF00" end status = "" for i = 1, math.floor(volume / 10) do             status = status .. "|"         end for i = math.floor(volume / 10) + 1, 10 do             status = status .. "-"         end status = "-[" ..status .. "]+"         widget.text = "&lt;span color=\"" .. color .. "\"&gt;" .. status .. "&lt;/span&gt;|" elseif mode == "up" then os.execute("amixer -q -c " .. cardid .. " sset " .. channel .. " 5%+") volume("update", widget) elseif mode == "down" then os.execute("amixer -q -c " .. cardid .. " sset " .. channel .. " 5%-") volume("update", widget) else os.execute("amixer -c " .. cardid .. " sset " .. channel .. " toggle") volume("update", widget) end end

Pavel's mod
It avoids calling amixer twice. Also, the invocation is easier. The widget definition: volumecfg = {} volumecfg.cardid = 0 volumecfg.channel = "Master" volumecfg.widget = widget({ type = "textbox", name = "volumecfg.widget", align = "right" }) -- 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 .. " 5%+") end volumecfg.down = function volumecfg.mixercommand(" sset " .. volumecfg.channel .. " 5%-") end volumecfg.toggle = function volumecfg.mixercommand(" sset " .. volumecfg.channel .. " toggle") end volumecfg.widget:buttons(awful.util.table.join( awful.button({ }, 4, function volumecfg.up end), awful.button({ }, 5, function volumecfg.down end), awful.button({ }, 1, function volumecfg.toggle end) )) volumecfg.update

Add the following to your widget list: volumecfg.widget

And try the following key bindings: globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "XF86AudioRaiseVolume",function volumecfg.up end)) globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "XF86AudioLowerVolume",function  volumecfg.down end)) globalkeys = awful.util.table.join(globalkeys, awful.key({ }, "XF86AudioMute",function  volumecfg.toggle end))

And the following sample hook: awful.hooks.timer.register(60, function        volumecfg.update end)