From 237470c8f45190b213e3a173ce6ae1a74b3e11fe Mon Sep 17 00:00:00 2001 From: "Adrian C. (anrxc)" Date: Sun, 14 Mar 2010 01:55:33 +0100 Subject: API: transform widgets namespace table to a directory --- bat.lua | 79 -------------------------------------------------- cpu.lua | 78 ------------------------------------------------- cpufreq.lua | 54 ---------------------------------- cpuinf.lua | 44 ---------------------------- date.lua | 23 --------------- dio.lua | 71 --------------------------------------------- entropy.lua | 33 --------------------- fs.lua | 52 --------------------------------- gmail.lua | 83 ----------------------------------------------------- hddtemp.lua | 38 ------------------------ init.lua | 54 ++++------------------------------ mbox.lua | 50 -------------------------------- mboxc.lua | 55 ----------------------------------- mdir.lua | 38 ------------------------ mem.lua | 49 ------------------------------- mpd.lua | 59 ------------------------------------- net.lua | 75 ----------------------------------------------- org.lua | 59 ------------------------------------- os.lua | 58 ------------------------------------- pkg.lua | 41 -------------------------- thermal.lua | 42 --------------------------- uptime.lua | 37 ------------------------ volume.lua | 50 -------------------------------- weather.lua | 83 ----------------------------------------------------- widgets/bat.lua | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ widgets/cpu.lua | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ widgets/cpufreq.lua | 54 ++++++++++++++++++++++++++++++++++ widgets/cpuinf.lua | 44 ++++++++++++++++++++++++++++ widgets/date.lua | 23 +++++++++++++++ widgets/dio.lua | 71 +++++++++++++++++++++++++++++++++++++++++++++ widgets/entropy.lua | 33 +++++++++++++++++++++ widgets/fs.lua | 52 +++++++++++++++++++++++++++++++++ widgets/gmail.lua | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ widgets/hddtemp.lua | 38 ++++++++++++++++++++++++ widgets/init.lua | 36 +++++++++++++++++++++++ widgets/mbox.lua | 50 ++++++++++++++++++++++++++++++++ widgets/mboxc.lua | 55 +++++++++++++++++++++++++++++++++++ widgets/mdir.lua | 38 ++++++++++++++++++++++++ widgets/mem.lua | 49 +++++++++++++++++++++++++++++++ widgets/mpd.lua | 59 +++++++++++++++++++++++++++++++++++++ widgets/net.lua | 75 +++++++++++++++++++++++++++++++++++++++++++++++ widgets/org.lua | 59 +++++++++++++++++++++++++++++++++++++ widgets/os.lua | 58 +++++++++++++++++++++++++++++++++++++ widgets/pkg.lua | 41 ++++++++++++++++++++++++++ widgets/thermal.lua | 42 +++++++++++++++++++++++++++ widgets/uptime.lua | 37 ++++++++++++++++++++++++ widgets/volume.lua | 50 ++++++++++++++++++++++++++++++++ widgets/weather.lua | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ widgets/wifi.lua | 72 ++++++++++++++++++++++++++++++++++++++++++++++ wifi.lua | 72 ---------------------------------------------- 50 files changed, 1364 insertions(+), 1372 deletions(-) delete mode 100644 bat.lua delete mode 100644 cpu.lua delete mode 100644 cpufreq.lua delete mode 100644 cpuinf.lua delete mode 100644 date.lua delete mode 100644 dio.lua delete mode 100644 entropy.lua delete mode 100644 fs.lua delete mode 100644 gmail.lua delete mode 100644 hddtemp.lua delete mode 100644 mbox.lua delete mode 100644 mboxc.lua delete mode 100644 mdir.lua delete mode 100644 mem.lua delete mode 100644 mpd.lua delete mode 100644 net.lua delete mode 100644 org.lua delete mode 100644 os.lua delete mode 100644 pkg.lua delete mode 100644 thermal.lua delete mode 100644 uptime.lua delete mode 100644 volume.lua delete mode 100644 weather.lua create mode 100644 widgets/bat.lua create mode 100644 widgets/cpu.lua create mode 100644 widgets/cpufreq.lua create mode 100644 widgets/cpuinf.lua create mode 100644 widgets/date.lua create mode 100644 widgets/dio.lua create mode 100644 widgets/entropy.lua create mode 100644 widgets/fs.lua create mode 100644 widgets/gmail.lua create mode 100644 widgets/hddtemp.lua create mode 100644 widgets/init.lua create mode 100644 widgets/mbox.lua create mode 100644 widgets/mboxc.lua create mode 100644 widgets/mdir.lua create mode 100644 widgets/mem.lua create mode 100644 widgets/mpd.lua create mode 100644 widgets/net.lua create mode 100644 widgets/org.lua create mode 100644 widgets/os.lua create mode 100644 widgets/pkg.lua create mode 100644 widgets/thermal.lua create mode 100644 widgets/uptime.lua create mode 100644 widgets/volume.lua create mode 100644 widgets/weather.lua create mode 100644 widgets/wifi.lua delete mode 100644 wifi.lua diff --git a/bat.lua b/bat.lua deleted file mode 100644 index e728155..0000000 --- a/bat.lua +++ /dev/null @@ -1,79 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/cpu.lua b/cpu.lua deleted file mode 100644 index 7c4907c..0000000 --- a/cpu.lua +++ /dev/null @@ -1,78 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (c) 2009, Lucas de Vries ---------------------------------------------------- - --- {{{ 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.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/cpufreq.lua b/cpufreq.lua deleted file mode 100644 index aa36151..0000000 --- a/cpufreq.lua +++ /dev/null @@ -1,54 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/cpuinf.lua b/cpuinf.lua deleted file mode 100644 index f9df451..0000000 --- a/cpuinf.lua +++ /dev/null @@ -1,44 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/date.lua b/date.lua deleted file mode 100644 index f6295ec..0000000 --- a/date.lua +++ /dev/null @@ -1,23 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (c) 2009, Lucas de Vries ---------------------------------------------------- - --- {{{ Grab environment -local os = { date = os.date } -local setmetatable = setmetatable --- }}} - - --- Date: provides access to os.date with optional custom formatting -module("vicious.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/dio.lua b/dio.lua deleted file mode 100644 index 33f1f34..0000000 --- a/dio.lua +++ /dev/null @@ -1,71 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/entropy.lua b/entropy.lua deleted file mode 100644 index 8ca0c30..0000000 --- a/entropy.lua +++ /dev/null @@ -1,33 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/fs.lua b/fs.lua deleted file mode 100644 index 87aa243..0000000 --- a/fs.lua +++ /dev/null @@ -1,52 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (c) 2009, Lucas de Vries ---------------------------------------------------- - --- {{{ 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.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/gmail.lua b/gmail.lua deleted file mode 100644 index b4bd081..0000000 --- a/gmail.lua +++ /dev/null @@ -1,83 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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, "([%d]+)")) or mail["{count}"] - - -- Find subject tags - local title = string.match(line, "(.*)") - -- 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/hddtemp.lua b/hddtemp.lua deleted file mode 100644 index 7c1e1e0..0000000 --- a/hddtemp.lua +++ /dev/null @@ -1,38 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/init.lua b/init.lua index 73d382d..7eb0159 100644 --- a/init.lua +++ b/init.lua @@ -6,71 +6,27 @@ -- * (c) 2009, Lucas de Vries --------------------------------------------------- --- {{{ Grab environment +-- {{{ Setup environment local type = type local pairs = pairs local tonumber = tonumber -local helpers = require("vicious.helpers") local capi = { timer = timer } local os = { time = os.time } local table = { insert = table.insert, remove = table.remove } --- }}} - - --- {{{ Configure widgets -require("vicious.cpu") -require("vicious.cpuinf") -require("vicious.cpufreq") -require("vicious.thermal") -require("vicious.uptime") -require("vicious.bat") -require("vicious.mem") -require("vicious.os") -require("vicious.fs") -require("vicious.dio") -require("vicious.hddtemp") -require("vicious.net") -require("vicious.wifi") -require("vicious.mbox") -require("vicious.mboxc") -require("vicious.mdir") -require("vicious.gmail") -require("vicious.entropy") -require("vicious.org") -require("vicious.pkg") -require("vicious.mpd") -require("vicious.volume") -require("vicious.weather") -require("vicious.date") --- }}} +require("vicious.helpers") +require("vicious.widgets") -- Vicious: widgets for the awesome window manager module("vicious") --- {{{ Initialize tables +-- Initialize tables local timers = {} local registered = {} local widget_cache = {} - --- Initialize the function table -widgets = {} --- }}} - --- {{{ Widget types -for i, w in pairs(_M) do - -- Ensure we don't call ourselves - if w and w ~= _M and type(w) == "table" then - -- Ignore the function table and helpers - if i ~= "widgets" and i ~= "helpers" then - -- Place widgets in the namespace table - widgets[i] = w - end - end -end -- }}} @@ -173,7 +129,7 @@ end -- }}} --- {{{ Exposed functions +-- {{{ Global functions -- {{{ Register a widget function register(widget, wtype, format, timer, warg) local reg = {} diff --git a/mbox.lua b/mbox.lua deleted file mode 100644 index bc815ae..0000000 --- a/mbox.lua +++ /dev/null @@ -1,50 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/mboxc.lua b/mboxc.lua deleted file mode 100644 index ff8ff65..0000000 --- a/mboxc.lua +++ /dev/null @@ -1,55 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/mdir.lua b/mdir.lua deleted file mode 100644 index 0e0b27b..0000000 --- a/mdir.lua +++ /dev/null @@ -1,38 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (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.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/mem.lua b/mem.lua deleted file mode 100644 index 7c18c89..0000000 --- a/mem.lua +++ /dev/null @@ -1,49 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (c) 2009, Lucas de Vries ---------------------------------------------------- - --- {{{ 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.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/mpd.lua b/mpd.lua deleted file mode 100644 index 0764e53..0000000 --- a/mpd.lua +++ /dev/null @@ -1,59 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/net.lua b/net.lua deleted file mode 100644 index 0550557..0000000 --- a/net.lua +++ /dev/null @@ -1,75 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (c) 2009, Lucas de Vries ---------------------------------------------------- - --- {{{ 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.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/org.lua b/org.lua deleted file mode 100644 index 6b034cc..0000000 --- a/org.lua +++ /dev/null @@ -1,59 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (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.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/os.lua b/os.lua deleted file mode 100644 index eb0a2b1..0000000 --- a/os.lua +++ /dev/null @@ -1,58 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/pkg.lua b/pkg.lua deleted file mode 100644 index 014bb86..0000000 --- a/pkg.lua +++ /dev/null @@ -1,41 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/thermal.lua b/thermal.lua deleted file mode 100644 index d7e98fc..0000000 --- a/thermal.lua +++ /dev/null @@ -1,42 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/uptime.lua b/uptime.lua deleted file mode 100644 index fdf45ea..0000000 --- a/uptime.lua +++ /dev/null @@ -1,37 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. --- * (c) 2009, Lucas de Vries ---------------------------------------------------- - --- {{{ 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.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/volume.lua b/volume.lua deleted file mode 100644 index 070f3bf..0000000 --- a/volume.lua +++ /dev/null @@ -1,50 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/weather.lua b/weather.lua deleted file mode 100644 index 8e78e8b..0000000 --- a/weather.lua +++ /dev/null @@ -1,83 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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/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. +--------------------------------------------------- + +-- {{{ 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. +-- * (c) 2009, Lucas de Vries +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +-- * (c) 2009, Lucas de Vries +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +-- * (c) 2009, Lucas de Vries +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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, "([%d]+)")) or mail["{count}"] + + -- Find subject tags + local title = string.match(line, "(.*)") + -- 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +-- * (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. +-- * (c) 2009, Lucas de Vries +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +-- * (c) 2009, Lucas de Vries +--------------------------------------------------- + +-- {{{ 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. +-- * (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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +-- * (c) 2009, Lucas de Vries +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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. +--------------------------------------------------- + +-- {{{ 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 }) diff --git a/wifi.lua b/wifi.lua deleted file mode 100644 index fc3d52e..0000000 --- a/wifi.lua +++ /dev/null @@ -1,72 +0,0 @@ ---------------------------------------------------- --- Licensed under the GNU General Public License v2 --- * (c) 2010, Adrian C. ---------------------------------------------------- - --- {{{ 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.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 }) -- cgit v1.2.3