This wiki will shut down!

Please note that this wiki will be made read-only and eventually be taken offline.

A replacement is being discussed at https://github.com/awesomeWM/awesome-www/issues/7. We'd be happy to have more input for that discussion and volunteers who help us migrate the content of this wiki to its replacement.

Farhavens volume widget

From awesome
Jump to: navigation, search

Introduction[edit]

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[edit]

The preparation is the same as with Woffles Volume Widget.

Adding the widget[edit]

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[edit]

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

Optional stuff[edit]

Setting keybindings[edit]

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[edit]

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:

Example.png

Farhavens mod[edit]

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 = "<span color=\"" .. color .. "\">" .. status .. "</span>|"
     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[edit]

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)