aboutsummaryrefslogtreecommitdiff
path: root/widgets
diff options
context:
space:
mode:
authorAdrian C. (anrxc) <anrxc@sysphere.org>2010-03-14 01:55:33 +0100
committerAdrian C. (anrxc) <anrxc@sysphere.org>2010-03-14 01:55:33 +0100
commit237470c8f45190b213e3a173ce6ae1a74b3e11fe (patch)
tree7f53c8144761947d4bde20715bcad34f4be0d6c0 /widgets
parent9a82d4113a8271b7dfc7506f2b07379e3ede89a8 (diff)
downloadvicious-legacy-237470c8f45190b213e3a173ce6ae1a74b3e11fe.tar.xz
API: transform widgets namespace table to a directory
Diffstat (limited to 'widgets')
-rw-r--r--widgets/bat.lua79
-rw-r--r--widgets/cpu.lua78
-rw-r--r--widgets/cpufreq.lua54
-rw-r--r--widgets/cpuinf.lua44
-rw-r--r--widgets/date.lua23
-rw-r--r--widgets/dio.lua71
-rw-r--r--widgets/entropy.lua33
-rw-r--r--widgets/fs.lua52
-rw-r--r--widgets/gmail.lua83
-rw-r--r--widgets/hddtemp.lua38
-rw-r--r--widgets/init.lua36
-rw-r--r--widgets/mbox.lua50
-rw-r--r--widgets/mboxc.lua55
-rw-r--r--widgets/mdir.lua38
-rw-r--r--widgets/mem.lua49
-rw-r--r--widgets/mpd.lua59
-rw-r--r--widgets/net.lua75
-rw-r--r--widgets/org.lua59
-rw-r--r--widgets/os.lua58
-rw-r--r--widgets/pkg.lua41
-rw-r--r--widgets/thermal.lua42
-rw-r--r--widgets/uptime.lua37
-rw-r--r--widgets/volume.lua50
-rw-r--r--widgets/weather.lua83
-rw-r--r--widgets/wifi.lua72
25 files changed, 1359 insertions, 0 deletions
diff --git a/widgets/bat.lua b/widgets/bat.lua
new file mode 100644
index 0000000..d6e3e6b
--- /dev/null
+++ b/widgets/bat.lua
@@ -0,0 +1,79 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local setmetatable = setmetatable
+local string = { format = string.format }
+local helpers = require("vicious.helpers")
+local math = {
+ min = math.min,
+ floor = math.floor
+}
+-- }}}
+
+
+-- Batsys: provides state, charge, and remaining time for a requested battery
+module("vicious.widgets.bat")
+
+
+-- {{{ Battery widget type
+local function worker(format, batid)
+ -- Apple PMU and ACPI/procfs battery widgets are in the [contrib] branch
+ local battery = helpers.pathtotable("/sys/class/power_supply/" .. batid)
+ local battery_state = {
+ ["Full\n"] = "↯",
+ ["Unknown\n"] = "⌁",
+ ["Charged\n"] = "↯",
+ ["Charging\n"] = "+",
+ ["Discharging\n"] = "-"
+ }
+
+ -- Check if the battery is present
+ if not battery.present == "1\n" then
+ return {battery_state["Unknown\n"], 0, "N/A"}
+ end
+
+
+ -- Get state information
+ local state = battery_state[battery.status] or battery_state["Unknown\n"]
+
+ -- Get capacity information
+ if battery.charge_now then
+ remaining, capacity = battery.charge_now, battery.charge_full
+ elseif battery.energy_now then
+ remaining, capacity = battery.energy_now, battery.energy_full
+ else
+ return {battery_state["Unknown\n"], 0, "N/A"}
+ end
+
+ -- Calculate percentage (but work around broken BAT/ACPI implementations)
+ local percent = math.min(math.floor(remaining / capacity * 100), 100)
+
+
+ -- Get charge information
+ if battery.current_now then
+ rate = battery.current_now
+ else -- Todo: other rate sources, as with capacity?
+ return {state, percent, "N/A"}
+ end
+
+ -- Calculate remaining (charging or discharging) time
+ if state == "+" then
+ timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate)
+ elseif state == "-" then
+ timeleft = tonumber(remaining) / tonumber(rate)
+ else
+ return {state, percent, "N/A"}
+ end
+ local hoursleft = math.floor(timeleft)
+ local minutesleft = math.floor((timeleft - hoursleft) * 60 )
+ local time = string.format("%02d:%02d", hoursleft, minutesleft)
+
+ return {state, percent, time}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/cpu.lua b/widgets/cpu.lua
new file mode 100644
index 0000000..3dfc22f
--- /dev/null
+++ b/widgets/cpu.lua
@@ -0,0 +1,78 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local ipairs = ipairs
+local io = { lines = io.lines }
+local setmetatable = setmetatable
+local math = { floor = math.floor }
+local table = { insert = table.insert }
+local string = {
+ find = string.find,
+ gmatch = string.gmatch
+}
+-- }}}
+
+
+-- Cpu: provides CPU usage for all available CPUs/cores
+module("vicious.widgets.cpu")
+
+
+-- Initialise function tables
+local cpu_usage = {}
+local cpu_total = {}
+local cpu_active = {}
+
+-- {{{ CPU widget type
+local function worker(format)
+ local cpu_lines = {}
+
+ -- Get CPU stats
+ for line in io.lines("/proc/stat") do
+ if string.find(line, "^cpu") then
+ cpu_lines[#cpu_lines+1] = {}
+
+ for i in string.gmatch(line, "[%s]+([%d]+)") do
+ table.insert(cpu_lines[#cpu_lines], i)
+ end
+ end
+ end
+
+ -- Ensure tables are initialized correctly
+ while #cpu_total < #cpu_lines do
+ table.insert(cpu_total, 0)
+ table.insert(cpu_active, 0)
+ table.insert(cpu_usage, 0)
+ end
+
+ local total_new = {}
+ local active_new = {}
+ local diff_total = {}
+ local diff_active = {}
+
+ for i, v in ipairs(cpu_lines) do
+ -- Calculate totals
+ total_new[i] = 0
+ for j = 1, #v do
+ total_new[i] = total_new[i] + v[j]
+ end
+ active_new[i] = v[1] + v[2] + v[3]
+
+ -- Calculate percentage
+ diff_total[i] = total_new[i] - cpu_total[i]
+ diff_active[i] = active_new[i] - cpu_active[i]
+ cpu_usage[i] = math.floor(diff_active[i] / diff_total[i] * 100)
+
+ -- Store totals
+ cpu_total[i] = total_new[i]
+ cpu_active[i] = active_new[i]
+ end
+
+ return cpu_usage
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/cpufreq.lua b/widgets/cpufreq.lua
new file mode 100644
index 0000000..7f60f5a
--- /dev/null
+++ b/widgets/cpufreq.lua
@@ -0,0 +1,54 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local setmetatable = setmetatable
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Cpufreq: provides freq, voltage and governor info for a requested CPU
+module("vicious.widgets.cpufreq")
+
+
+-- {{{ CPU frequency widget type
+local function worker(format, cpuid)
+ local cpufreq = helpers.pathtotable("/sys/devices/system/cpu/"..cpuid.."/cpufreq")
+ local governor_state = {
+ ["ondemand\n"] = "↯",
+ ["powersave\n"] = "⌁",
+ ["userspace\n"] = "¤",
+ ["performance\n"] = "⚡",
+ ["conservative\n"] = "↯"
+ }
+ -- Default voltage values
+ local voltage = { v = "N/A", mv = "N/A" }
+
+
+ -- Get the current frequency
+ local freq = tonumber(cpufreq.scaling_cur_freq)
+ -- Calculate MHz and GHz
+ local freqmhz = freq / 1000
+ local freqghz = freqmhz / 1000
+
+ -- Get the current voltage
+ if cpufreq.scaling_voltages then
+ voltage.mv = tonumber(string.match(cpufreq.scaling_voltages, freq.."[%s]([%d]+)"))
+ -- Calculate voltage from mV
+ voltage.v = voltage.mv / 1000
+ end
+
+ -- Get the current governor
+ local governor = cpufreq.scaling_governor
+ -- Represent the governor as a symbol
+ governor = governor_state[governor] or governor
+
+ return {freqmhz, freqghz, voltage.mv, voltage.v, governor}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/cpuinf.lua b/widgets/cpuinf.lua
new file mode 100644
index 0000000..8bee530
--- /dev/null
+++ b/widgets/cpuinf.lua
@@ -0,0 +1,44 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local io = { lines = io.lines }
+local setmetatable = setmetatable
+local string = { gmatch = string.gmatch }
+-- }}}
+
+
+-- Cpuinf: provides speed and cache information for all available CPUs/cores
+module("vicious.widgets.cpuinf")
+
+
+-- {{{ CPU Information widget type
+local function worker(format)
+ local id = nil
+ local cpu_info = {}
+
+ -- Get CPU info
+ for line in io.lines("/proc/cpuinfo") do
+ for k, v in string.gmatch(line, "([%a%s]+)[%s]+:[%s]([%d]+).-$") do
+ if k == "processor" then
+ id = v
+ elseif k == "cpu MHz\t" or k == "cpu MHz" then
+ local speed = tonumber(v)
+ cpu_info["{cpu"..id.." mhz}"] = speed
+ cpu_info["{cpu"..id.." ghz}"] = speed / 1000
+ elseif k == "cache size" then
+ local cache = tonumber(v)
+ cpu_info["{cpu"..id.." kb}"] = cache
+ cpu_info["{cpu"..id.." mb}"] = cache / 1024
+ end
+ end
+ end
+
+ return cpu_info
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/date.lua b/widgets/date.lua
new file mode 100644
index 0000000..68a803d
--- /dev/null
+++ b/widgets/date.lua
@@ -0,0 +1,23 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local os = { date = os.date }
+local setmetatable = setmetatable
+-- }}}
+
+
+-- Date: provides access to os.date with optional custom formatting
+module("vicious.widgets.date")
+
+
+-- {{{ Date widget type
+local function worker(format)
+ return os.date(format or nil)
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/dio.lua b/widgets/dio.lua
new file mode 100644
index 0000000..9731d57
--- /dev/null
+++ b/widgets/dio.lua
@@ -0,0 +1,71 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local ipairs = ipairs
+local setmetatable = setmetatable
+local table = { insert = table.insert }
+local string = { gmatch = string.gmatch }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Disk I/O: provides I/O statistics for requested storage devices
+module("vicious.widgets.dio")
+
+
+-- Initialise function tables
+local disk_usage = {}
+local disk_total = {}
+-- Variable definitions
+local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 }
+
+-- {{{ Disk I/O widget type
+local function worker(format, disk)
+ local disk_lines = { [disk] = {} }
+ local disk_stats = helpers.pathtotable("/sys/block/" .. disk)
+ local disk_queue = helpers.pathtotable("/sys/block/" .. disk .. "/queue")
+
+ if disk_stats.stat then
+ local match = string.gmatch(disk_stats.stat, "[%s]+([%d]+)")
+ for i = 1, 11 do -- Store disk stats
+ table.insert(disk_lines[disk], match())
+ end
+ end
+
+ -- Ensure tables are initialized correctly
+ local diff_total = { [disk] = {} }
+ if not disk_total[disk] then
+ disk_usage[disk] = {}
+ disk_total[disk] = {}
+
+ while #disk_total[disk] < #disk_lines[disk] do
+ table.insert(disk_total[disk], 0)
+ end
+ end
+
+ for i, v in ipairs(disk_lines[disk]) do
+ -- Diskstats are absolute, substract our last reading
+ diff_total[disk][i] = v - disk_total[disk][i]
+
+ -- Store totals
+ disk_total[disk][i] = v
+ end
+
+ -- Calculate and store I/O
+ helpers.uformat(disk_usage[disk], "read", diff_total[disk][3], unit)
+ helpers.uformat(disk_usage[disk], "write", diff_total[disk][7], unit)
+ helpers.uformat(disk_usage[disk], "total", diff_total[disk][7] + diff_total[disk][3], unit)
+
+ -- Store I/O scheduler
+ if disk_queue.scheduler then
+ disk_usage[disk]["{sched}"] = string.gmatch(disk_queue.scheduler, "%[([%a]+)%]")
+ end
+
+ return disk_usage[disk]
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/entropy.lua b/widgets/entropy.lua
new file mode 100644
index 0000000..395d5d9
--- /dev/null
+++ b/widgets/entropy.lua
@@ -0,0 +1,33 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local setmetatable = setmetatable
+local math = { ceil = math.ceil }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Entropy: provides available system entropy
+module("vicious.widgets.entropy")
+
+
+-- {{{ Entropy widget type
+local function worker(format)
+ local random = helpers.pathtotable("/proc/sys/kernel/random")
+
+ -- Linux 2.6 has a default entropy pool of 4096-bits
+ local poolsize = tonumber(random.poolsize)
+ -- Get available entropy
+ local ent = tonumber(random.entropy_avail)
+ -- Calculate percentage
+ local ent_percent = math.ceil(ent * 100 / poolsize)
+
+ return {ent, ent_percent}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/fs.lua b/widgets/fs.lua
new file mode 100644
index 0000000..a85b903
--- /dev/null
+++ b/widgets/fs.lua
@@ -0,0 +1,52 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- FS: provides file system disk space usage
+module("vicious.widgets.fs")
+
+
+-- Variable definitions
+local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
+
+-- {{{ Filesystem widget type
+local function worker(format, nfs)
+ -- Fallback to listing local filesystems
+ if nfs then nfs = "" else nfs = "-l" end
+
+ -- Get (non-localized)data from df
+ local f = io.popen("LC_ALL=C df -kP " .. nfs)
+ local fs_info = {}
+
+ for line in f:lines() do -- Match: (size) (used)(avail)(use%) (mount)
+ local s = string.match(line, "^.-[%s]([%d]+)")
+ local u,a,p = string.match(line, "([%d]+)[%D]+([%d]+)[%D]+([%d]+)%%")
+ local m = string.match(line, "%%[%s]([%p%w]+)")
+
+ if u and m then -- Handle 1st line and broken regexp
+ helpers.uformat(fs_info, m .. " size", s, unit)
+ helpers.uformat(fs_info, m .. " used", u, unit)
+ helpers.uformat(fs_info, m .. " avail", a, unit)
+
+ fs_info["{" .. m .. " used_p}"] = tonumber(p)
+ fs_info["{" .. m .. " avail_p}"] = 100 - tonumber(p)
+ end
+ end
+ f:close()
+
+ return fs_info
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/gmail.lua b/widgets/gmail.lua
new file mode 100644
index 0000000..b2f0d8c
--- /dev/null
+++ b/widgets/gmail.lua
@@ -0,0 +1,83 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local type = type
+local tonumber = tonumber
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+local helpers = require("vicious.helpers")
+local string = {
+ find = string.find,
+ match = string.match
+}
+-- }}}
+
+
+-- Gmail: provides count of new and subject of last e-mail on Gmail
+module("vicious.widgets.gmail")
+
+
+-- {{{ Variable definitions
+local rss = {
+ inbox = {
+ "https://mail.google.com/mail/feed/atom",
+ "Gmail %- Inbox"
+ },
+ unread = {
+ "https://mail.google.com/mail/feed/atom/unread",
+ "Gmail %- Label"
+ },
+ --labelname = {
+ -- "https://mail.google.com/mail/feed/atom/labelname",
+ -- "Gmail %- Label"
+ --},
+}
+
+-- Default is all unread
+local feed = rss.unread
+-- }}}
+
+
+-- {{{ Gmail widget type
+local function worker(format, warg)
+ local mail = {
+ ["{count}"] = 0,
+ ["{subject}"] = "N/A"
+ }
+
+ -- Get info from the Gmail atom feed
+ local f = io.popen("curl --connect-timeout 1 -m 3 -fsn " .. feed[1])
+
+ -- Could be huge don't read it all at once, info we are after is at the top
+ for line in f:lines() do
+ mail["{count}"] = -- Count comes before messages and matches at least 0
+ tonumber(string.match(line, "<fullcount>([%d]+)</fullcount>")) or mail["{count}"]
+
+ -- Find subject tags
+ local title = string.match(line, "<title>(.*)</title>")
+ -- If the subject changed then break out of the loop
+ if title ~= nil and not string.find(title, feed[2]) then
+ -- Check if we should scroll, or maybe truncate
+ if warg then
+ if type(warg) == "table" then
+ title = helpers.scroll(title, warg[1], warg[2])
+ else
+ title = helpers.truncate(title, warg)
+ end
+ end
+
+ -- Spam sanitize the subject and store
+ mail["{subject}"] = helpers.escape(title)
+ break
+ end
+ end
+ f:close()
+
+ return mail
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/hddtemp.lua b/widgets/hddtemp.lua
new file mode 100644
index 0000000..6fcd05f
--- /dev/null
+++ b/widgets/hddtemp.lua
@@ -0,0 +1,38 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+local string = { gmatch = string.gmatch }
+-- }}}
+
+
+-- Hddtemp: provides hard drive temperatures using the hddtemp daemon
+module("vicious.widgets.hddtemp")
+
+
+-- {{{ HDD Temperature widget type
+local function worker(format, port)
+ -- Fallback to default hddtemp port
+ if port == nil then port = 7634 end
+
+ -- Get info from the hddtemp daemon
+ local f = io.popen("curl --connect-timeout 1 -fsm 3 telnet://127.0.0.1:"..port)
+ local hdd_temp = {}
+
+ for line in f:lines() do
+ for d, t in string.gmatch(line, "|([%/%a%d]+)|.-|([%d]+)|[CF]+|") do
+ hdd_temp["{"..d.."}"] = tonumber(t)
+ end
+ end
+ f:close()
+
+ return hdd_temp
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/init.lua b/widgets/init.lua
new file mode 100644
index 0000000..5b8ae04
--- /dev/null
+++ b/widgets/init.lua
@@ -0,0 +1,36 @@
+---------------------------------------------------
+-- Vicious widgets for the awesome window manager
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Configure widgets
+require("vicious.widgets.cpu")
+require("vicious.widgets.cpuinf")
+require("vicious.widgets.cpufreq")
+require("vicious.widgets.thermal")
+require("vicious.widgets.uptime")
+require("vicious.widgets.bat")
+require("vicious.widgets.mem")
+require("vicious.widgets.os")
+require("vicious.widgets.fs")
+require("vicious.widgets.dio")
+require("vicious.widgets.hddtemp")
+require("vicious.widgets.net")
+require("vicious.widgets.wifi")
+require("vicious.widgets.mbox")
+require("vicious.widgets.mboxc")
+require("vicious.widgets.mdir")
+require("vicious.widgets.gmail")
+require("vicious.widgets.entropy")
+require("vicious.widgets.org")
+require("vicious.widgets.pkg")
+require("vicious.widgets.mpd")
+require("vicious.widgets.volume")
+require("vicious.widgets.weather")
+require("vicious.widgets.date")
+-- }}}
+
+-- Vicious: widgets for the awesome window manager
+module("vicious.widgets")
diff --git a/widgets/mbox.lua b/widgets/mbox.lua
new file mode 100644
index 0000000..eca5403
--- /dev/null
+++ b/widgets/mbox.lua
@@ -0,0 +1,50 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local type = type
+local io = { open = io.open }
+local setmetatable = setmetatable
+local string = { gfind = string.gfind }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Mbox: provides the subject of last e-mail in a mbox file
+module("vicious.widgets.mbox")
+
+
+-- {{{ Mailbox widget type
+local function worker(format, warg)
+ if type(warg) ~= "table" then mbox = warg end
+ -- mbox could be huge, get a 30kb chunk from EOF
+ -- * attachments could be much bigger than this
+ local f = io.open(mbox or warg[1])
+ f:seek("end", -30720)
+ local txt = f:read("*all")
+ f:close()
+
+ -- Default value
+ local subject = "N/A"
+
+ -- Find all Subject lines
+ for i in string.gfind(txt, "Subject: ([^\n]*)") do
+ subject = i
+ end
+
+ -- Check if we should scroll, or maybe truncate
+ if type(warg) == "table" then
+ if warg[3] ~= nil then
+ subject = helpers.scroll(subject, warg[2], warg[3])
+ else
+ subject = helpers.truncate(subject, warg[2])
+ end
+ end
+
+ return {helpers.escape(subject)}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/mboxc.lua b/widgets/mboxc.lua
new file mode 100644
index 0000000..c5f694c
--- /dev/null
+++ b/widgets/mboxc.lua
@@ -0,0 +1,55 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local io = { open = io.open }
+local setmetatable = setmetatable
+local string = { find = string.find }
+-- }}}
+
+
+-- Mboxc: provides the count of total, old and new messages in mbox files
+module("vicious.widgets.mboxc")
+
+
+-- {{{ Mbox count widget type
+local function worker(format, warg)
+ -- Initialise counters
+ local count = { old = 0, total = 0, new = 0 }
+
+ -- Get data from mbox files
+ for i=1, #warg do
+ local f = io.open(warg[i])
+
+ while true do
+ -- Read the mbox line by line, if we are going to read
+ -- some *HUGE* folders then switch to reading chunks
+ local lines = f:read("*line")
+ if not lines then break end
+
+ -- Find all messages
+ -- * http://www.jwz.org/doc/content-length.html
+ local _, from = string.find(lines, "^From[%s]")
+ if from ~= nil then count.total = count.total + 1 end
+
+ -- Read messages have the Status header
+ local _, status = string.find(lines, "^Status:[%s]RO$")
+ if status ~= nil then count.old = count.old + 1 end
+
+ -- Skip the folder internal data
+ local _, int = string.find(lines, "^Subject:[%s].*FOLDER[%s]INTERNAL[%s]DATA")
+ if int ~= nil then count.total = count.total - 1 end
+ end
+ f:close()
+ end
+
+ -- Substract total from old to get the new count
+ count.new = count.total - count.old
+
+ return {count.total, count.old, count.new}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/mdir.lua b/widgets/mdir.lua
new file mode 100644
index 0000000..858a9b1
--- /dev/null
+++ b/widgets/mdir.lua
@@ -0,0 +1,38 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) Maildir Biff Widget, Fredrik Ax
+---------------------------------------------------
+
+-- {{{ Grab environment
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+-- }}}
+
+
+-- Mdir: provides the number of new and unread messages in Maildir structures/dirs
+module("vicious.widgets.mdir")
+
+
+-- {{{ Maildir widget type
+local function worker(format, warg)
+ -- Initialise counters
+ local count = { new = 0, cur = 0 }
+
+ for i=1, #warg do
+ -- Recursively find new messages
+ local f = io.popen("find "..warg[i].." -type f -wholename '*/new/*'")
+ for line in f:lines() do count.new = count.new + 1 end
+ f:close()
+
+ -- Recursively find "old" messages lacking the Seen flag
+ local f = io.popen("find "..warg[i].." -type f -regex '.*/cur/.*2,[^S]*$'")
+ for line in f:lines() do count.cur = count.cur + 1 end
+ f:close()
+ end
+
+ return {count.new, count.cur}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/mem.lua b/widgets/mem.lua
new file mode 100644
index 0000000..c2f5886
--- /dev/null
+++ b/widgets/mem.lua
@@ -0,0 +1,49 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local io = { lines = io.lines }
+local setmetatable = setmetatable
+local math = { floor = math.floor }
+local string = { gmatch = string.gmatch }
+-- }}}
+
+
+-- Mem: provides RAM and Swap usage statistics
+module("vicious.widgets.mem")
+
+
+-- {{{ Memory widget type
+local function worker(format)
+ local mem = { buf = {}, swp = {} }
+
+ -- Get MEM info
+ for line in io.lines("/proc/meminfo") do
+ for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+") do
+ if k == "MemTotal" then mem.total = math.floor(v/1024)
+ elseif k == "MemFree" then mem.buf.f = math.floor(v/1024)
+ elseif k == "Buffers" then mem.buf.b = math.floor(v/1024)
+ elseif k == "Cached" then mem.buf.c = math.floor(v/1024)
+ elseif k == "SwapTotal" then mem.swp.t = math.floor(v/1024)
+ elseif k == "SwapFree" then mem.swp.f = math.floor(v/1024)
+ end
+ end
+ end
+
+ -- Calculate memory percentage
+ mem.free = mem.buf.f + mem.buf.b + mem.buf.c
+ mem.inuse = mem.total - mem.free
+ mem.usep = math.floor(mem.inuse / mem.total * 100)
+ -- Calculate swap percentage
+ mem.swp.inuse = mem.swp.t - mem.swp.f
+ mem.swp.usep = math.floor(mem.swp.inuse / mem.swp.t * 100)
+
+ return {mem.usep, mem.inuse, mem.total, mem.free,
+ mem.swp.usep, mem.swp.inuse, mem.swp.t, mem.swp.f}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/mpd.lua b/widgets/mpd.lua
new file mode 100644
index 0000000..009ae7d
--- /dev/null
+++ b/widgets/mpd.lua
@@ -0,0 +1,59 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+local string = { gmatch = string.gmatch }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Mpd: provides Music Player Daemon information
+module("vicious.widgets.mpd")
+
+
+-- {{{ MPD widget type
+local function worker(format, warg)
+ local mpd_state = {
+ ["{volume}"] = 0,
+ ["{state}"] = "N/A",
+ ["{Artist}"] = "N/A",
+ ["{Title}"] = "N/A",
+ ["{Album}"] = "N/A",
+ ["{Genre}"] = "N/A"
+ }
+
+ -- Fallback to MPD defaults
+ local pass = warg and warg[1] or "\"\""
+ local host = warg and warg[2] or "127.0.0.1"
+ local port = warg and warg[3] or "6600"
+
+ -- Construct MPD client options
+ local mpdh = "telnet://"..host..":"..port
+ local echo = "echo 'password "..pass.."\nstatus\ncurrentsong\nclose'"
+
+ -- Get data from MPD server
+ local f = io.popen(echo.." | curl --connect-timeout 1 -fsm 3 "..mpdh)
+
+ for line in f:lines() do
+ for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
+ if k == "volume" then mpd_state["{"..k.."}"] = v and tonumber(v)
+ elseif k == "state" then mpd_state["{"..k.."}"] = helpers.capitalize(v)
+ elseif k == "Artist" then mpd_state["{"..k.."}"] = helpers.escape(v)
+ elseif k == "Title" then mpd_state["{"..k.."}"] = helpers.escape(v)
+ elseif k == "Album" then mpd_state["{"..k.."}"] = helpers.escape(v)
+ elseif k == "Genre" then mpd_state["{"..k.."}"] = helpers.escape(v)
+ end
+ end
+ end
+ f:close()
+
+ return mpd_state
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/net.lua b/widgets/net.lua
new file mode 100644
index 0000000..9fd221f
--- /dev/null
+++ b/widgets/net.lua
@@ -0,0 +1,75 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local os = { time = os.time }
+local io = { lines = io.lines }
+local setmetatable = setmetatable
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Net: provides usage statistics for all network interfaces
+module("vicious.widgets.net")
+
+
+-- Initialise function tables
+local nets = {}
+-- Variable definitions
+local unit = { ["b"] = 1, ["kb"] = 1024,
+ ["mb"] = 1024^2, ["gb"] = 1024^3
+}
+
+-- {{{ Net widget type
+local function worker(format)
+ local args = {}
+
+ -- Get NET stats
+ for line in io.lines("/proc/net/dev") do
+ -- Match wmaster0 as well as rt0 (multiple leading spaces)
+ local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):")
+ if name ~= nil then
+ -- Received bytes, first value after the name
+ local recv = tonumber(string.match(line, ":[%s]*([%d]+)"))
+ -- Transmited bytes, 7 fields from end of the line
+ local send = tonumber(string.match(line,
+ "([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$"))
+
+ helpers.uformat(args, name .. " rx", recv, unit)
+ helpers.uformat(args, name .. " tx", send, unit)
+
+ if nets[name] == nil then
+ -- Default values on the first run
+ nets[name] = {}
+ helpers.uformat(args, name .. " down", 0, unit)
+ helpers.uformat(args, name .. " up", 0, unit)
+
+ nets[name].time = os.time()
+ else -- Net stats are absolute, substract our last reading
+ local interval = os.time() - nets[name].time > 0 and
+ os.time() - nets[name].time or 1
+ nets[name].time = os.time()
+
+ local down = (recv - nets[name][1]) / interval
+ local up = (send - nets[name][2]) / interval
+
+ helpers.uformat(args, name .. " down", down, unit)
+ helpers.uformat(args, name .. " up", up, unit)
+ end
+
+ -- Store totals
+ nets[name][1] = recv
+ nets[name][2] = send
+ end
+ end
+
+ return args
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/org.lua b/widgets/org.lua
new file mode 100644
index 0000000..8764e3a
--- /dev/null
+++ b/widgets/org.lua
@@ -0,0 +1,59 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) org-awesome, Damien Leone
+---------------------------------------------------
+
+-- {{{ Grab environment
+local io = { lines = io.lines }
+local setmetatable = setmetatable
+local string = { find = string.find }
+local os = {
+ time = os.time,
+ date = os.date
+}
+-- }}}
+
+
+-- Org: provides agenda statistics for Emacs org-mode
+module("vicious.widgets.org")
+
+
+-- {{{ OrgMode widget type
+local function worker(format, warg)
+ -- Compute delays
+ local today = os.time{ year=os.date("%Y"), month=os.date("%m"), day=os.date("%d") }
+ local soon = today + 24 * 3600 * 3 -- 3 days ahead is close
+ local future = today + 24 * 3600 * 7 -- 7 days ahead is maximum
+
+ -- Initialise counters
+ local count = { past = 0, today = 0, soon = 0, future = 0 }
+
+ -- Get data from agenda files
+ for i=1, #warg do
+ for line in io.lines(warg[i]) do
+ local scheduled = string.find(line, "SCHEDULED:")
+ local closed = string.find(line, "CLOSED:")
+ local deadline = string.find(line, "DEADLINE:")
+
+ if (scheduled and not closed) or (deadline and not closed) then
+ local b, e, y, m, d = string.find(line, "(%d%d%d%d)-(%d%d)-(%d%d)")
+
+ if b then
+ local t = os.time{ year = y, month = m, day = d }
+
+ if t < today then count.past = count.past + 1
+ elseif t == today then count.today = count.today + 1
+ elseif t <= soon then count.soon = count.soon + 1
+ elseif t <= future then count.future = count.future + 1
+ end
+ end
+ end
+ end
+ end
+
+ return {count.past, count.today, count.soon, count.future}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/os.lua b/widgets/os.lua
new file mode 100644
index 0000000..8b1d11e
--- /dev/null
+++ b/widgets/os.lua
@@ -0,0 +1,58 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local pairs = pairs
+local io = { popen = io.popen }
+local os = { getenv = os.getenv }
+local setmetatable = setmetatable
+local helpers = require("vicious.helpers")
+local string = {
+ gsub = string.gsub,
+ match = string.match
+}
+-- }}}
+
+
+-- OS: provides operating system information
+module("vicious.widgets.os")
+
+
+-- {{{ Operating system widget type
+local function worker(format)
+ local system = {
+ ["ostype"] = "N/A",
+ ["hostname"] = "N/A",
+ ["osrelease"] = "N/A",
+ ["username"] = "N/A"
+ }
+
+ -- Linux manual page: uname(2)
+ local kernel = helpers.pathtotable("/proc/sys/kernel")
+ for k, v in pairs(system) do
+ if kernel[k] then
+ system[k] = string.gsub(kernel[k], "[%s]*$", "")
+ end
+ end
+
+ -- BSD manual page: uname(1)
+ if system["ostype"] == "N/A" then
+ local f = io.popen("uname -snr")
+ local uname = f:read("*line")
+ f:close()
+
+ system["ostype"], system["hostname"], system["osrelease"] =
+ string.match(uname, "([%w]+)[%s]([%w%p]+)[%s]([%w%p]+)")
+ end
+
+ -- Get user from the environment
+ system["username"] = os.getenv("USER")
+
+ return {system["ostype"], system["osrelease"],
+ system["username"], system["hostname"]}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/pkg.lua b/widgets/pkg.lua
new file mode 100644
index 0000000..fa2375b
--- /dev/null
+++ b/widgets/pkg.lua
@@ -0,0 +1,41 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local io = { popen = io.popen }
+local math = { max = math.max }
+local setmetatable = setmetatable
+-- }}}
+
+
+-- Pkg: provides number of pending updates on GNU/Linux
+module("vicious.widgets.pkg")
+
+
+-- {{{ Packages widget type
+local function worker(format, dist)
+ -- Initialise counters
+ local updates = 0
+ local manager = {
+ ["Arch"] = { cmd = "pacman -Qu" },
+ ["Arch S"] = { cmd = "yes | pacman -Sup", sub = 2 },
+ ["Debian"] = { cmd = "apt-show-versions -u -b" },
+ ["Fedora"] = { cmd = "yum list updates", sub = 3 }
+ }
+
+ -- Check if updates are available
+ local pkg = manager[dist]
+ local f = io.popen(pkg.cmd)
+
+ for line in f:lines() do
+ updates = updates + 1
+ end
+ f:close()
+
+ return {pkg.sub and math.max(updates-pkg.sub, 0) or updates}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/thermal.lua b/widgets/thermal.lua
new file mode 100644
index 0000000..9768c57
--- /dev/null
+++ b/widgets/thermal.lua
@@ -0,0 +1,42 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local type = type
+local tonumber = tonumber
+local setmetatable = setmetatable
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Thermal: provides temperature levels of ACPI and coretemp thermal zones
+module("vicious.widgets.thermal")
+
+
+-- {{{ Thermal widget type
+local function worker(format, warg)
+ local zone = { -- Known temperature data sources
+ ["sys"] = {"/sys/class/thermal/", file = "temp", div = 1000},
+ ["core"] = {"/sys/devices/platform/", file = "temp1_input",div = 1000},
+ ["proc"] = {"/proc/acpi/thermal_zone/",file = "temperature"}
+ } -- Default to /sys/class/thermal
+ local warg = type(warg) == "table" and warg or {warg, "sys"}
+ local thermal = helpers.pathtotable(zone[warg[2]][1] .. warg[1])
+
+ -- Get temperature from thermal zone
+ if thermal[zone[warg[2]].file] then
+ if zone[warg[2]].div then
+ return {thermal[zone[warg[2]].file] / zone[warg[2]].div}
+ else -- /proc/acpi "temperature: N C"
+ return {tonumber(string.match(thermal[zone[warg[2]].file], "[%d]+"))}
+ end
+ end
+
+ return {0}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/uptime.lua b/widgets/uptime.lua
new file mode 100644
index 0000000..ebc5af8
--- /dev/null
+++ b/widgets/uptime.lua
@@ -0,0 +1,37 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local setmetatable = setmetatable
+local math = { floor = math.floor }
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Uptime: provides system uptime and load information
+module("vicious.widgets.uptime")
+
+
+-- {{{ Uptime widget type
+local function worker(format)
+ local proc = helpers.pathtotable("/proc")
+
+ -- Get system uptime
+ local up_t = math.floor(string.match(proc.uptime, "[%d]+"))
+ local up_d = math.floor(up_t / (3600 * 24))
+ local up_h = math.floor((up_t % (3600 * 24)) / 3600)
+ local up_m = math.floor(((up_t % (3600 * 24)) % 3600) / 60)
+
+ -- Get load averages
+ local l1, l5, l15 = -- Get load averages for past 1, 5 and 15 minutes
+ string.match(proc.loadavg, "([%d]*%.[%d]*)%s([%d]*%.[%d]*)%s([%d]*%.[%d]*)")
+
+ return {up_d, up_h, up_m, l1, l5, l15}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/volume.lua b/widgets/volume.lua
new file mode 100644
index 0000000..42f72e4
--- /dev/null
+++ b/widgets/volume.lua
@@ -0,0 +1,50 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+local string = { match = string.match }
+-- }}}
+
+
+-- Volume: provides volume levels and state of requested ALSA mixers
+module("vicious.widgets.volume")
+
+
+-- {{{ Volume widget type
+local function worker(format, warg)
+ local mixer_state = {
+ ["on"] = "♫", -- "",
+ ["off"] = "♩" -- "M"
+ }
+
+ -- Get mixer control contents
+ local f = io.popen("amixer get " .. warg)
+ local mixer = f:read("*all")
+ f:close()
+
+ -- Capture mixer control state: [5%] ... ... [on]
+ local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
+ -- Handle mixers without data
+ if volu == nil then
+ return {0, mixer_state["off"]}
+ end
+
+ -- Handle mixers without mute
+ if mute == "" and volu == "0"
+ -- Handle mixers that are muted
+ or mute == "off" then
+ mute = mixer_state["off"]
+ else
+ mute = mixer_state["on"]
+ end
+
+ return {tonumber(volu), mute}
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/weather.lua b/widgets/weather.lua
new file mode 100644
index 0000000..effa138
--- /dev/null
+++ b/widgets/weather.lua
@@ -0,0 +1,83 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local io = { popen = io.popen }
+local setmetatable = setmetatable
+local math = { ceil = math.ceil }
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+-- }}}
+
+
+-- Weather: provides weather information for a requested station
+module("vicious.widgets.weather")
+
+
+-- {{{ Weather widget type
+local function worker(format, station)
+ -- Default values
+ local weather = {
+ ["{city}"] = "N/A",
+ ["{wind}"] = "N/A",
+ ["{windmph}"] = "N/A",
+ ["{windkmh}"] = "N/A",
+ ["{sky}"] = "N/A",
+ ["{weather}"] = "N/A",
+ ["{tempf}"] = "N/A",
+ ["{tempc}"] = "N/A",
+ ["{humid}"] = "N/A",
+ ["{press}"] = "N/A"
+ }
+
+ -- Get weather forceast by the station ICAO code, from:
+ -- * US National Oceanic and Atmospheric Administration
+ local noaa = "http://weather.noaa.gov/pub/data/observations/metar/decoded/"
+ local f = io.popen("curl --connect-timeout 1 -fsm 3 "..noaa..station..".TXT")
+ local ws = f:read("*all")
+ f:close()
+
+ -- Check if there was a timeout or a problem with the station
+ if ws == nil then return weather end
+
+ weather["{city}"] = -- City and/or area
+ string.match(ws, "^(.+)%,.*%([%u]+%)") or weather["{city}"]
+ weather["{wind}"] = -- Wind direction and degrees if available
+ string.match(ws, "Wind:[%s][%a]+[%s][%a]+[%s](.+)[%s]at.+$") or weather["{wind}"]
+ weather["{windmph}"] = -- Wind speed in MPH if available
+ string.match(ws, "Wind:[%s].+[%s]at[%s]([%d]+)[%s]MPH") or weather["{windmph}"]
+ weather["{sky}"] = -- Sky conditions if available
+ string.match(ws, "Sky[%s]conditions:[%s](.-)[%c]") or weather["{sky}"]
+ weather["{weather}"] = -- Weather conditions if available
+ string.match(ws, "Weather:[%s](.-)[%c]") or weather["{weather}"]
+ weather["{tempf}"] = -- Temperature in fahrenheit
+ string.match(ws, "Temperature:[%s]([%-]?[%d%.]+).*[%c]") or weather["{tempf}"]
+ weather["{humid}"] = -- Relative humidity in percent
+ string.match(ws, "Relative[%s]Humidity:[%s]([%d]+)%%") or weather["{humid}"]
+ weather["{press}"] = -- Pressure in hPa
+ string.match(ws, "Pressure[%s].+%((.+)[%s]hPa%)") or weather["{press}"]
+
+ -- Wind speed in km/h if MPH was available
+ if weather["{windmph}"] ~= "N/A" then
+ weather["{windmph}"] = tonumber(weather["{windmph}"])
+ weather["{windkmh}"] = math.ceil(weather["{windmph}"] * 1.6)
+ end -- Temperature in °C if °F was available
+ if weather["{tempf}"] ~= "N/A" then
+ weather["{tempf}"] = tonumber(weather["{tempf}"])
+ weather["{tempc}"] = math.ceil((weather["{tempf}"] - 32) * 5/9)
+ end -- Capitalize some stats so they don't look so out of place
+ if weather["{sky}"] ~= "N/A" then
+ weather["{sky}"] = helpers.capitalize(weather["{sky}"])
+ end
+ if weather["{weather}"] ~= "N/A" then
+ weather["{weather}"] = helpers.capitalize(weather["{weather}"])
+ end
+
+ return weather
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/wifi.lua b/widgets/wifi.lua
new file mode 100644
index 0000000..65ffb79
--- /dev/null
+++ b/widgets/wifi.lua
@@ -0,0 +1,72 @@
+---------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
+---------------------------------------------------
+
+-- {{{ Grab environment
+local tonumber = tonumber
+local setmetatable = setmetatable
+local io = {
+ open = io.open,
+ popen = io.popen
+}
+local string = {
+ find = string.find,
+ match = string.match
+}
+-- }}}
+
+
+-- Wifi: provides wireless information for a requested interface
+module("vicious.widgets.wifi")
+
+
+-- {{{ Wireless widget type
+local function worker(format, iface)
+ -- Default values
+ local winfo = {
+ ["{ssid}"] = "N/A",
+ ["{mode}"] = "N/A",
+ ["{chan}"] = "N/A",
+ ["{rate}"] = 0,
+ ["{link}"] = 0,
+ ["{sign}"] = 0
+ }
+
+ -- Get data from iwconfig where available
+ local iwconfig = "/sbin/iwconfig"
+ local f = io.open(iwconfig, "rb")
+ if not f then
+ iwconfig = "/usr/sbin/iwconfig"
+ else
+ f:close()
+ end
+ local f = io.popen(iwconfig .." ".. iface .. " 2>&1")
+ local iw = f:read("*all")
+ f:close()
+
+ -- iwconfig wasn't found, isn't executable, or non-wireless interface
+ if iw == nil or string.find(iw, "No such device") then
+ return winfo
+ end
+
+ -- Output differs from system to system, some stats can be
+ -- separated by =, and not all drivers report all stats
+ winfo["{ssid}"] = -- SSID can have almost anything in it
+ string.match(iw, 'ESSID[=:]"([%w%p]+[%s]*[%w%p]*]*)"') or winfo["{ssid}"]
+ winfo["{mode}"] = -- Modes are simple, but also match the "-" in Ad-Hoc
+ string.match(iw, "Mode[=:]([%w%-]*)") or winfo["{mode}"]
+ winfo["{chan}"] = -- Channels are plain digits
+ tonumber(string.match(iw, "Channel[=:]([%d]+)") or winfo["{chan}"])
+ winfo["{rate}"] = -- Bitrate can start with a space, we don't want to display Mb/s
+ tonumber(string.match(iw, "Bit Rate[=:]([%s]?[%d%.]*)") or winfo["{rate}"])
+ winfo["{link}"] = -- Link quality can contain a slash (32/70), match only the first number
+ tonumber(string.match(iw, "Link Quality[=:]([%d]+)") or winfo["{link}"])
+ winfo["{sign}"] = -- Signal level can be a negative value, don't display decibel notation
+ tonumber(string.match(iw, "Signal level[=:]([%-]?[%d]+)") or winfo["{sign}"])
+
+ return winfo
+end
+-- }}}
+
+setmetatable(_M, { __call = function(_, ...) return worker(...) end })