diff --git a/.luacheckrc b/.luacheckrc
index 7aacbc1..6c05d07 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -3,7 +3,15 @@ std = "min"
-- Global objects defined by the C code
read_globals = {
- "timer", -- deprecated, but used in older versions.
+ "timer", -- deprecated, but used in older versions.
}
+-- Warnings to be ignored
+ignore = {
+ "212", -- Unused argument.
+}
+
+-- Not enforced, but preferable
+max_code_line_length = 80
+
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/Changes.md b/Changes.md
index cb0f732..bc453fa 100644
--- a/Changes.md
+++ b/Changes.md
@@ -1,11 +1,14 @@
+# Changes in 2.4.0 (WIP)
+
IMPORTANT:
-- `volume_linux` now uses ๐ and ๐ instead of โซ and โฉ to show mute state.
+- `volume` now uses ๐ and ๐ instead of โซ and โฉ to show mute state.
This BREAKS backward compatibility if users substitute custom symbols
from these default.
Added:
+- [wifi_linux] Expose frequency and transmission power
- `spawn` as a fallback for `awful.spawn` in case Vicious is used as
a stand-alone library. This wrapper, however, does NOT provide the facilities
to asynchronously spawn new processes. It also lacks a few features such as
@@ -16,10 +19,22 @@ Added:
Fixed:
-- [volume_linux] Deprecate `io.popen`
+- Deprecate the use of `io.popen` in following widgets:
+ * wifi_linux, wifiiw_linux, hwmontemp_linux, hddtemp_linux
+ * bat_freebsd, mem_freebsd, net_freebsd, thermal_freebsd, uptime_freebsd,
+ cpu_freebsd, cpufreq_freebsd, fanspeed_freebsd
+ * bat_openbsd
+ * volume, gmail, mdir, mpd, fs
- [mpd] Lua 5.3 compatibility (for real this time); also correct a typo
- [pkg,weather,contrib/btc] Allow function call without Awesome
- [pkg] Use more updated front-ends for Debian/Ubuntu (apt) and Fedora (dnf)
+- [os] Splitted os_all into os_linux and os_bsd (and refactored to async)
+- Tweak `.luacheckrc` to suit functional style and soft-limit text width to 80
+
+Removed:
+
+- `helpers.sysctl` and `helpers.sysctl_table` were removed in favour of
+ `helpers.sysctl_async`.
# Changes in 2.3.3
diff --git a/README.md b/README.md
index 4aaba6d..ad391b3 100644
--- a/README.md
+++ b/README.md
@@ -154,6 +154,16 @@ Supported platforms: GNU/Linux (require `sysfs`), FreeBSD (require `acpiconf`),
* `$4`: Wear level in percent
* `$5`: Current (dis)charge rate in Watt
+### vicious.contrib.cmus
+
+Provides cmus player information using `cmus-remote`.
+
+Supported platforms: platform independent.
+
+* Argument: a table whose first field is the socket including host (or nil).
+* Returns a table with string keys: `${status}`, `${artist}`, `${title}`,
+ `${duration}`, `${file}`, `${continue}`, `${shuffle}`, `${repeat}`.
+
### vicious.widgets.cpu
Provides CPU usage for all available CPUs/cores. Since this widget type give
@@ -218,12 +228,13 @@ Returns a table with string keys: `${sda total_s}`, `${sda total_kb}`,
### vicious.widget.fanspeed
-Provides fanspeed information for specified fan.
+Provides fanspeed information for specified fans.
Supported platforms: FreeBSD.
-* Argument: full `sysctl` string to entry, e.g. `"dev.acpi_ibm.0.fan_speed"`
-* Returns speed of specified fan in RPM, `-1` on error (probably wrong string)
+* Argument: full `sysctl` string to one or multiple entries, e.g.
+ `"dev.acpi_ibm.0.fan_speed"`
+* Returns speed of specified fan in RPM, `"N/A"` on error (probably wrong string)
### vicious.widgets.fs
@@ -236,6 +247,7 @@ Supported platforms: platform independent.
* Returns a table with string keys, using mount points as a base, e.g.
`${/ size_mb}`, `${/ size_gb}`, `${/ used_mb}`, `${/ used_gb}`, `${/ used_p}`,
`${/ avail_mb}`, `${/ avail_gb}`, `${/ avail_p}`, `${/home size_mb}`, etc.
+ mb and gb refer to mebibyte and gibibyte respectively.
### vicious.widgets.gmail
@@ -514,8 +526,10 @@ Provides wireless information for a requested interface.
Supported platforms: GNU/Linux.
* Argument: the network interface, e.g. `"wlan0"`
-* Returns a table with string keys: `${ssid}`, `${mode}`, `${chan}`, `${rate}`,
- `${link}`, `${linp}` (link quality in percent) and `${sign}` (signal level)
+* Returns a table with string keys: `${ssid}`, `${mode}`, `${chan}`,
+ `${rate}` (Mb/s), `${freq}` (MHz), `${txpw}` (transmission power, in dBm),
+ `${sign}` (signal level), `${link}` and `${linp}` (link quality
+ per 70 and per cent)
### vicious.widgets.wifiiw
@@ -525,10 +539,9 @@ vicious.widgets.wifi, but uses `iw` instead of `iwconfig`).
Supported platforms: GNU/Linux.
* Argument: the network interface, e.g. `"wlan0"`
-* Returns a table with string keys: `${bssid}`, `${ssid}`, `${mode}`, `${chan}`, `${rate}`,
- `${freq}`, `${linp}` (link quality in percent), `${txpw}` (tx power) and
- `${sign}` (signal level)
-
+* Returns a table with string keys: `${bssid}`, `${ssid}`, `${mode}`, `${chan}`,
+ `${rate}` (Mb/s), `${freq}` (MHz), `${linp}` (link quality in percent),
+ `${txpw}` (transmission power, in dBm) and `${sign}` (signal level, in dBm)
## Custom widget types
diff --git a/contrib/README.md b/contrib/README.md
index 106363f..54a39a7 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -87,6 +87,8 @@ yellow - in progress.
### vicious.contrib.cmus
+NOTE: This widget type has been promoted to `widgets`.
+
Provides cmus player information using `cmus-remote`.
Supported platforms: platform independent.
diff --git a/contrib/cmus_all.lua b/contrib/cmus_all.lua
deleted file mode 100644
index e2567e8..0000000
--- a/contrib/cmus_all.lua
+++ /dev/null
@@ -1,74 +0,0 @@
------------------------------------------------------------
--- Licensed under the GNU General Public License v2
--- * (c) 2017, JuanKman94
------------------------------------------------------------
-
--- {{{ Grab environment
-local tonumber = tonumber
-local io = { popen = io.popen }
-local setmetatable = setmetatable
-local string = { gmatch = string.gmatch, format = string.format }
-local helpers = require("vicious.helpers")
--- }}}
-
--- Cmus: provides CMUS information
--- vicious.widgets.cmus
-local cmus_all = {}
-
--- {{{ CMUS widget type
-local function worker(format, warg)
- local cmus_state = {
- ["{duration}"] = 0,
- ["{file}"] = "N/A",
- ["{status}"] = "N/A",
- ["{title}"] = "N/A",
- ["{artist}"] = "N/A",
- ["{continue}"] = "off",
- ["{shuffle}"] = "off",
- ["{repeat}"] = "off",
- }
-
- -- Fallback to CMUS defaults
- local host = warg and (warg.host or warg[1]) or os.getenv("CMUS_SOCKET")
-
- if not host then
- if os.getenv("XDG_RUNTIME_DIR") then
- host = os.getenv("XDG_RUNTIME_DIR") .. "/cmus-socket"
- else
- host = os.getenv("HOME") .. "/.config/cmus/socket"
- end
- end
-
- -- Get data from CMUS server
- local f = io.popen("cmus-remote --query --server " .. helpers.shellquote(host))
-
- for line in f:lines() do
- for module, value in string.gmatch(line, "([%w]+) (.*)$") do
- if module == "file" or module == "status" then
- cmus_state["{"..module.."}"] = value
- elseif module == "duration" then
- cmus_state["{"..module.."}"] = tonumber(value)
- else
- for k, v in string.gmatch(value, "([%w]+) (.*)$") do
- if module == "tag" then
- if k == "title" or k == "artist" then
- cmus_state["{"..k.."}"] = v
- end
- elseif module == "set" then
- if k == "continue" or k == "shuffle" or k == "repeat" then
- if v == "true" then
- cmus_state["{"..k.."}"] = "on"
- end
- end
- end
- end
- end
- end
- end
- f:close()
-
- return cmus_state
-end
--- }}}
-
-return setmetatable(cmus_all, { __call = function(_, ...) return worker(...) end })
diff --git a/contrib/cmus_all.lua b/contrib/cmus_all.lua
new file mode 120000
index 0000000..4ba2bda
--- /dev/null
+++ b/contrib/cmus_all.lua
@@ -0,0 +1 @@
+../widgets/cmus_all.lua
\ No newline at end of file
diff --git a/helpers.lua b/helpers.lua
index 2f56a2b..c3d4a22 100644
--- a/helpers.lua
+++ b/helpers.lua
@@ -19,10 +19,14 @@ local getmetatable = getmetatable
local string = {
upper = string.upper,
lower = string.lower,
- format = string.format
+ format = string.format,
+ match = string.match,
+ find = string.find,
}
+local table = { concat = table.concat }
local pcall = pcall
local assert = assert
+local spawn = require("vicious.spawn")
-- }}}
@@ -30,6 +34,12 @@ local assert = assert
-- vicious.helpers
local helpers = {}
+-- {{{ Constants definitions
+local OS_UNSUPPORTED_ERR = "Vicious: platform not supported: %s"
+local NOT_FOUND_MSG = "module '%s' not found"
+local NOT_FOUND_ERR = [[
+Vicious: %s is not available for the current platform or does not exist]]
+-- }}}
-- {{{ Variable definitions
local scroller = {}
@@ -52,8 +62,8 @@ end
-- }}}
-- {{{ Loader of vicious modules
-function helpers.wrequire(table, key)
- local ret = rawget(table, key)
+function helpers.wrequire(collection, key)
+ local ret = rawget(collection, key)
if ret then
return ret
@@ -65,27 +75,26 @@ function helpers.wrequire(table, key)
openbsd = { "openbsd", "bsd", "all" }
}
- local os = ostable[helpers.getos()]
- assert(os, "Vicious: platform not supported: " .. helpers.getos())
+ local platform = ostable[helpers.getos()]
+ assert(platform, OS_UNSUPPORTED_ERR:format(helpers.getos()))
- for i = 1, #os do
- local name = table._NAME .. "." .. key .. "_" .. os[i]
+ local basename = collection._NAME .. '.' .. key
+ for i = 1, #platform do
+ local name = basename .. '_' .. platform[i]
local status, value = pcall(require, name)
if status then
ret = value
break
end
- local not_found_msg = "module '"..name.."' not found"
- -- ugly but there is afaik no other way to check if a module exists
- if value:sub(1, #not_found_msg) ~= not_found_msg then
- -- module found, but different issue -> let's raise the real error
- require(name)
+ -- This is ugly but AFAWK there is no other way to check for
+ -- the type of error. If other error get caught, raise it.
+ if value:find(NOT_FOUND_MSG:format(name), 1, true) == nil then
+ require(name)
end
end
- assert(ret, "Vicious: widget " .. table._NAME .. "." .. key .. " not available for current platform or does not exist")
-
+ assert(ret, NOT_FOUND_ERR:format(basename))
return ret
end
-- }}}
@@ -106,8 +115,8 @@ end
-- {{{ Expose path as a Lua table
function helpers.pathtotable(dir)
return setmetatable({ _path = dir },
- { __index = function(table, index)
- local path = table._path .. '/' .. index
+ { __index = function(self, index)
+ local path = self._path .. '/' .. index
local f = io.open(path)
if f then
local s = f:read("*all")
@@ -116,7 +125,7 @@ function helpers.pathtotable(dir)
return s
else
local o = { _path = path }
- setmetatable(o, getmetatable(table))
+ setmetatable(o, getmetatable(self))
return o
end
end
@@ -222,43 +231,28 @@ function helpers.scroll(text, maxlen, widget)
end
-- }}}
--- {{{ Return result from one sysctl variable as string
-function helpers.sysctl(path)
- local fd = io.popen("sysctl -n " .. helpers.shellquote(path))
+-- {{{ Parse output of sysctl command calling the `parse` function
+function helpers.sysctl_async(path_table, parse)
+ local ret = {}
+ local path = {}
- if not fd then
- return
+ for i=1,#path_table do
+ path[i] = helpers.shellquote(path_table[i])
end
- local ret = fd:read()
+ path = table.concat(path, " ")
- fd:close()
-
- return ret
-end
--- }}}
-
--- {{{ Return result from multiple sysctl variables as table
-function helpers.sysctl_table(syspath)
- return setmetatable({ _path = syspath },
- { __index = function(table, index)
- local path = "sysctl -n " .. helpers.shellquote(table._path .. "." .. index)
- local f = io.popen(path)
- if f then
- local s = f:read("*all")
- f:close()
- if select(2, s:gsub("\n", "\n")) > 1 then
- local o = { _path = path}
- setmetatable(o, getmetatable(table))
- return o
- else
- return s
- end
+ spawn.with_line_callback("sysctl " .. path, {
+ stdout = function(line)
+ if not string.find(line, "sysctl: unknown oid") then
+ local key, value = string.match(line, "(.+): (.+)")
+ ret[key] = value
end
- end
+ end,
+ output_done = function() parse(ret) end
})
end
--- }}}
+-- }}}
return helpers
diff --git a/widgets/bat_freebsd.lua b/widgets/bat_freebsd.lua
index 8139b4c..c6e743c 100644
--- a/widgets/bat_freebsd.lua
+++ b/widgets/bat_freebsd.lua
@@ -1,23 +1,23 @@
-- {{{ Grab environment
-local setmetatable = setmetatable
local tonumber = tonumber
-local io = { popen = io.popen }
local math = { floor = math.floor }
-local helpers = require("vicious.helpers")
local string = {
gmatch = string.gmatch,
- match = string.match,
format = string.format
}
+local helpers = require("vicious.helpers")
+local spawn = require("vicious.spawn")
-- }}}
+
+-- Battery: provides battery level of requested battery
+-- vicious.widgets.battery_freebsd
local bat_freebsd = {}
-local function worker(format, warg)
- local battery = warg or "batt"
+-- {{{ Battery widget type
+local function parse(stdout, stderr, exitreason, exitcode)
local bat_info = {}
- local f = io.popen("acpiconf -i " .. helpers.shellquote(battery))
- for line in f:lines("*line") do
+ for line in string.gmatch(stdout, "[^\n]+") do
for key,value in string.gmatch(line, "(.+):%s+(.+)") do
bat_info[key] = value
end
@@ -25,25 +25,18 @@ local function worker(format, warg)
-- current state
-- see: https://github.com/freebsd/freebsd/blob/master/usr.sbin/acpi/acpiconf/acpiconf.c
- local state
- if bat_info["State"] == "high" then
- state = "โฏ"
- elseif bat_info["State"] == "charging" then
- state = "+"
- elseif bat_info["State"] == "critical charging" then
- state = "+"
- elseif bat_info["State"] == "discharging" then
- state = "-"
- elseif bat_info["State"] == "critical discharging" then
- state = "!"
- elseif bat_info["State"] == "critical" then
- state = "!"
- else
- state = "N/A"
- end
+ local battery_state = {
+ ["high"] = "โฏ",
+ ["charging"] = "+",
+ ["critical charging"] = "+",
+ ["discharging"] = "-",
+ ["critical discharging"] = "!",
+ ["critical"] = "!",
+ }
+ local state = battery_state[bat_info["State"]] or "N/A"
-- battery capacity in percent
- local percent = tonumber(string.match(bat_info["Remaining capacity"], "[%d]+"))
+ local percent = tonumber(bat_info["Remaining capacity"]:match"[%d]+")
-- use remaining (charging or discharging) time calculated by acpiconf
local time = bat_info["Remaining time"]
@@ -54,13 +47,13 @@ local function worker(format, warg)
-- calculate wear level from (last full / design) capacity
local wear = "N/A"
if bat_info["Last full capacity"] and bat_info["Design capacity"] then
- local l_full = tonumber(string.match(bat_info["Last full capacity"], "[%d]+"))
- local design = tonumber(string.match(bat_info["Design capacity"], "[%d]+"))
+ local l_full = tonumber(bat_info["Last full capacity"]:match"[%d]+")
+ local design = tonumber(bat_info["Design capacity"]:match"[%d]+")
wear = math.floor(l_full / design * 100)
end
-- dis-/charging rate as presented by battery
- local rate = string.match(bat_info["Present rate"], "([%d]+)%smW")
+ local rate = bat_info["Present rate"]:match"([%d]+)%smW"
rate = string.format("%2.1f", tonumber(rate / 1000))
-- returns
@@ -72,4 +65,11 @@ local function worker(format, warg)
return {state, percent, time, wear, rate}
end
-return setmetatable(bat_freebsd, { __call = function(_, ...) return worker(...) end })
+function bat_freebsd.async(format, warg, callback)
+ local battery = warg or "batt"
+ spawn.easy_async("acpiconf -i " .. helpers.shellquote(battery),
+ function (...) callback(parse(...)) end)
+end
+-- }}}
+
+return helpers.setasyncall(bat_freebsd)
diff --git a/widgets/bat_openbsd.lua b/widgets/bat_openbsd.lua
index 752a666..ced83d8 100644
--- a/widgets/bat_openbsd.lua
+++ b/widgets/bat_openbsd.lua
@@ -1,67 +1,85 @@
+-- bat_openbsd.lua - provide battery information on OpenBSD
+-- Copyright (C) 2019 Enric Morales
+-- Copyright (C) 2019 Nguyแป n Gia Phong
+--
+-- This file is part of Vicious.
+--
+-- Vicious is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation, either version 2 of the
+-- License, or (at your option) any later version.
+--
+-- Vicious is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with Vicious. If not, see .
+
-- {{{ Grab environment
-local setmetatable = setmetatable
local tonumber = tonumber
-local string = { format = string.format, gmatch = string.gmatch }
-local io = { popen = io.popen }
local math = { floor = math.floor, modf = math.modf }
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- }}}
-local bat_openbsd = {}
+local STATES = { [0] = "โฏ", -- not charging
+ [1] = "-", -- discharging
+ [2] = "!", -- critical
+ [3] = "+", -- charging
+ [4] = "N/A", -- unknown status
+ [255] = "N/A" } -- unimplemented by the driver
-local function worker(format, warg)
- local battery = warg or "bat0"
- local filter = string.format("hw.sensors.acpi%s", battery)
- local cmd = string.format("sysctl -a | grep '^%s'", filter)
- local proc = io.popen(cmd)
+return helpers.setasyncall{
+ async = function (format, warg, callback)
+ local filter = "hw.sensors.acpi" .. (warg or "bat0")
+ local pattern = filter .. ".(%S+)=(%S+)"
+ local bat_info = {}
- local bat_info = {}
- for line in proc:lines("*l") do
- for key, value in string.gmatch(line, "(%S+)=(%S+)") do
- key = key:gsub(filter .. ".", "")
- bat_info[key] = value
- end
- end
+ spawn.with_line_callback_with_shell(
+ ("sysctl -a | grep '^%s'"):format(filter),
+ { stdout = function (line)
+ for key, value in line:gmatch(pattern) do
+ bat_info[key] = value
+ end
+ end,
+ output_done = function ()
+ -- current state
+ local state = STATES[tonumber(bat_info.raw0)]
- -- current state
- local states = {[0] = "โฏ", -- not charging
- [1] = "-", -- discharging
- [2] = "!", -- critical
- [3] = "+", -- charging
- [4] = "N/A", -- unknown status
- [255] = "N/A"} -- unimplemented by the driver
- local state = states[tonumber(bat_info.raw0)]
+ -- battery capacity in percent
+ local percent = tonumber(
+ bat_info.watthour3 / bat_info.watthour0 * 100)
- -- battery capacity in percent
- local percent = tonumber(bat_info.watthour3 / bat_info.watthour0 * 100)
+ local time
+ if tonumber(bat_info.power0) < 1 then
+ time = "โ"
+ else
+ local raw_time = bat_info.watthour3 / bat_info.power0
+ local hours, hour_fraction = math.modf(raw_time)
+ local minutes = math.floor(60 * hour_fraction)
+ time = ("%d:%0.2d"):format(hours, minutes)
+ end
- local time
- if tonumber(bat_info.power0) < 1 then
- time = "โ"
- else
- local raw_time = bat_info.watthour3 / bat_info.power0
- local hours, hour_fraction = math.modf(raw_time)
- local minutes = math.floor(60 * hour_fraction)
- time = string.format("%d:%0.2d", hours, minutes)
- end
+ -- calculate wear level from (last full / design) capacity
+ local wear = "N/A"
+ if bat_info.watthour0 and bat_info.watthour4 then
+ local l_full = tonumber(bat_info.watthour0)
+ local design = tonumber(bat_info.watthour4)
+ wear = math.floor(l_full / design * 100)
+ end
- -- calculate wear level from (last full / design) capacity
- local wear = "N/A"
- if bat_info.watthour0 and bat_info.watthour4 then
- local l_full = tonumber(bat_info.watthour0)
- local design = tonumber(bat_info.watthour4)
- wear = math.floor(l_full / design * 100)
- end
+ -- dis-/charging rate as presented by battery
+ local rate = bat_info.power0
- -- dis-/charging rate as presented by battery
- local rate = bat_info.power0
-
- -- returns
- -- * state (high "โฏ", discharging "-", charging "+", N/A "โ" }
- -- * remaining_capacity (percent)
- -- * remaining_time, by battery
- -- * wear level (percent)
- -- * present_rate (W)
- return {state, percent, time, wear, rate}
-end
-
-return setmetatable(bat_openbsd, { __call = function(_, ...) return worker(...) end })
+ -- Pass the following arguments to callback function:
+ -- * battery state symbol (โฏ, -, !, + or N/A)
+ -- * remaining_capacity (in percent)
+ -- * remaining_time, by battery
+ -- * wear level (in percent)
+ -- * present_rate (in Watts)
+ callback{state, percent, time, wear, rate}
+ end })
+ end }
diff --git a/widgets/cmus_all.lua b/widgets/cmus_all.lua
new file mode 100644
index 0000000..25c1a9a
--- /dev/null
+++ b/widgets/cmus_all.lua
@@ -0,0 +1,51 @@
+-----------------------------------------------------------
+-- Licensed under the GNU General Public License v2
+-- * (c) 2017, JuanKman94
+-----------------------------------------------------------
+
+-- {{{ Grab environment
+local type = type
+local tonumber = tonumber
+local os = { getenv = os.getenv }
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
+-- }}}
+
+local CMUS_SOCKET = helpers.shellquote(os.getenv"CMUS_SOCKET")
+
+-- Cmus: provides CMUS information
+-- vicious.widgets.cmus
+return helpers.setasyncall{
+ async = function (format, warg, callback)
+ local server = ""
+ if type(warg) == "table" then
+ server = " --server " .. helpers.shellquote(warg.host or warg[1])
+ elseif CMUS_SOCKET ~= nil then
+ server = " --server " .. CMUS_SOCKET
+ end
+
+ local cmus_state = { ["{duration}"] = 0, ["{file}"] = "N/A",
+ ["{status}"] = "N/A", ["{title}"] = "N/A",
+ ["{artist}"] = "N/A", ["{continue}"] = "off",
+ ["{shuffle}"] = "off", ["{repeat}"] = "off" }
+
+ spawn.with_line_callback("cmus-remote --query" .. server, {
+ stdout = function (line)
+ for module, value in line:gmatch"([%w]+) (.*)$" do
+ if module == "file" or module == "status" then
+ cmus_state["{"..module.."}"] = value
+ elseif module == "duration" then
+ cmus_state["{"..module.."}"] = tonumber(value)
+ else
+ local k, v = value:gmatch("([%w]+) (.*)$")()
+ if module == "tag" then
+ cmus_state["{"..k.."}"] = v
+ elseif module == "set" and v == "true" then
+ cmus_state["{"..k.."}"] = "on"
+ end
+ end
+ end
+ end,
+ output_done = function () callback(cmus_state) end })
+ end }
diff --git a/widgets/cpu_freebsd.lua b/widgets/cpu_freebsd.lua
index 044286c..972eca0 100644
--- a/widgets/cpu_freebsd.lua
+++ b/widgets/cpu_freebsd.lua
@@ -1,9 +1,8 @@
-- {{{ Grab environment
-local helpers = require("vicious.helpers")
-local tonumber = tonumber
-local setmetatable = setmetatable
local math = { floor = math.floor }
local string = { gmatch = string.gmatch }
+
+local helpers = require("vicious.helpers")
-- }}}
@@ -16,54 +15,57 @@ local cpu_total = {}
local cpu_idle = {}
-- {{{ CPU widget type
-local function worker(format)
- local cp_times = helpers.sysctl("kern.cp_times")
+function cpu_freebsd.async(format, warg, callback)
local matches = {}
local tmp_total = {}
local tmp_idle = {}
local tmp_usage = {}
- -- Read input data
- for v in string.gmatch(cp_times, "([%d]+)") do
- table.insert(matches, v)
- end
+ helpers.sysctl_async({ "kern.cp_times" }, function(ret)
+ -- Read input data
+ for v in string.gmatch(ret["kern.cp_times"], "([%d]+)") do
+ table.insert(matches, v)
+ end
- -- Set first value of function tables
- if #cpu_total == 0 then -- check for empty table
+ -- Set first value of function tables
+ if #cpu_total == 0 then -- check for empty table
+ for i = 1, #matches / 5 + 1 do
+ cpu_total[i] = 0
+ cpu_idle[i] = 0
+ end
+ end
for i = 1, #matches / 5 + 1 do
- cpu_total[i] = 0
- cpu_idle[i] = 0
+ tmp_total[i] = 0
+ tmp_idle[i] = 0
+ tmp_usage[i] = 0
end
- end
- for i = 1, #matches / 5 + 1 do
- tmp_total[i] = 0
- tmp_idle[i] = 0
- tmp_usage[i] = 0
- end
- -- CPU usage
- for i, v in ipairs(matches) do
- local index = math.floor((i-1) / 5) + 2 -- current cpu
+ -- CPU usage
+ for i, v in ipairs(matches) do
+ local index = math.floor((i-1) / 5) + 2 -- current cpu
- tmp_total[1] = tmp_total[1] + v
- tmp_total[index] = tmp_total[index] + v
+ tmp_total[1] = tmp_total[1] + v
+ tmp_total[index] = tmp_total[index] + v
- if (i-1) % 5 == 4 then
- tmp_idle[1] = tmp_idle[1] + v
- tmp_idle[index] = tmp_idle[index] + v
+ if (i-1) % 5 == 4 then
+ tmp_idle[1] = tmp_idle[1] + v
+ tmp_idle[index] = tmp_idle[index] + v
+ end
end
- end
- for i = 1, #tmp_usage do
- tmp_usage[i] = tmp_total[i] - cpu_total[i]
- tmp_usage[i] = math.floor((tmp_usage[i] - (tmp_idle[i] - cpu_idle[i])) / tmp_usage[i] * 100)
- end
+ for i = 1, #tmp_usage do
+ tmp_usage[i] = tmp_total[i] - cpu_total[i]
+ tmp_usage[i] = math.floor(
+ (tmp_usage[i] - (tmp_idle[i] - cpu_idle[i]))
+ / tmp_usage[i] * 100)
+ end
- cpu_total = tmp_total
- cpu_idle = tmp_idle
+ cpu_total = tmp_total
+ cpu_idle = tmp_idle
- return tmp_usage
+ return callback(tmp_usage)
+ end)
end
-- }}}
-return setmetatable(cpu_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(cpu_freebsd)
diff --git a/widgets/cpufreq_freebsd.lua b/widgets/cpufreq_freebsd.lua
index 351cc68..6acf2f0 100644
--- a/widgets/cpufreq_freebsd.lua
+++ b/widgets/cpufreq_freebsd.lua
@@ -1,6 +1,5 @@
-- {{{ Grab environment
local tonumber = tonumber
-local setmetatable = setmetatable
local helpers = require("vicious.helpers")
-- }}}
@@ -11,24 +10,31 @@ local cpufreq_freebsd = {}
-- {{{ CPU frequency widget type
-local function worker(format, warg)
- if not warg then return end
+function cpufreq_freebsd.async(format, warg, callback)
+ if not warg then return callback({}) end
-- Default frequency and voltage values
local freqv = {
["mhz"] = "N/A", ["ghz"] = "N/A",
["v"] = "N/A", ["mv"] = "N/A",
+ ["governor"] = "N/A",
}
- local freq = tonumber(helpers.sysctl("dev.cpu." .. warg .. ".freq"))
+ helpers.sysctl_async(
+ { "dev.cpu." .. warg .. ".freq" },
+ function (ret)
+ freqv.mhz = tonumber(ret["dev.cpu." .. warg .. ".freq"])
+ freqv.ghz = freqv.mhz / 1000
- freqv.mhz = freq
- freqv.ghz = freq / 1000
-
- local governor = "N/A"
-
- return {freqv.mhz, freqv.ghz, freqv.mv, freqv.v, governor}
+ return callback({
+ freqv.mhz,
+ freqv.ghz,
+ freqv.mv,
+ freqv.v,
+ freqv.governor
+ })
+ end)
end
-- }}}
-return setmetatable(cpufreq_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(cpufreq_freebsd)
diff --git a/widgets/fanspeed_freebsd.lua b/widgets/fanspeed_freebsd.lua
index 774b0da..a60b272 100644
--- a/widgets/fanspeed_freebsd.lua
+++ b/widgets/fanspeed_freebsd.lua
@@ -1,28 +1,37 @@
-- {{{ Grab environment
-local setmetatable = setmetatable
-local helpers = require("vicious.helpers")
local tonumber = tonumber
+local type = type
+
+local helpers = require("vicious.helpers")
-- }}}
--- fanspeed: provides speed level of main fan
+-- fanspeed: provides speed level of fans
+-- vicious.widgets.fanspeed
--
--- expects one (1) full sysctl string to entry
+-- expects one or multiple full sysctl strings to entry
-- e.g.: "dev.acpi_ibm.0.fan_speed"
-
local fanspeed_freebsd = {}
-local function worker(format, warg)
- if not warg then return end
+-- {{{ fanspeed widget type
+function fanspeed_freebsd.async(format, warg, callback)
+ if not warg then return callback({}) end
+ if type(warg) ~= "table" then warg = { warg } end
- local fanspeed = helpers.sysctl(warg)
+ helpers.sysctl_async(warg, function(ret)
+ local fanspeed = {}
- if not fanspeed then
- -- use negative fanspeed to indicate error
- return {-1}
- else
- return {tonumber(fanspeed)}
- end
+ for i=1,#warg do
+ if ret[warg[i]] ~= nil then
+ fanspeed[i] = tonumber(ret[warg[i]])
+ else
+ fanspeed[i] = "N/A"
+ end
+ end
+
+ callback(fanspeed)
+ end)
end
+-- }}}
-return setmetatable(fanspeed_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(fanspeed_freebsd)
diff --git a/widgets/fs_all.lua b/widgets/fs_all.lua
index b577431..9c4e5d0 100644
--- a/widgets/fs_all.lua
+++ b/widgets/fs_all.lua
@@ -6,50 +6,34 @@
-- {{{ Grab environment
local tonumber = tonumber
-local io = { popen = io.popen }
-local setmetatable = setmetatable
-local string = { match = string.match }
-local helpers = require("vicious.helpers")
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- }}}
+-- Mebibyte and gibibyte respectively, because backward compatibility
+local UNIT = { mb = 1024, gb = 1024^2 }
-- FS: provides file system disk space usage
-- vicious.widgets.fs
-local fs_all = {}
+return helpers.setasyncall{
+ async = function(format, warg, callback)
+ local fs_info = {} -- Get data from df
+ spawn.with_line_callback_with_shell(
+ warg and "LC_ALL=C df -kP" or "LC_ALL=C df -klP",
+ { stdout = function (line)
+ -- (1024-blocks) (Used) (Available) (Capacity)% (Mounted on)
+ local s, u, a, p, m = line:match(
+ "^.-%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%%%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)
--- Variable definitions
-local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
-
--- {{{ Filesystem widget type
-local function worker(format, warg)
- local cmd = "LC_ALL=C df -kP"
- if not warg then
- -- List only local filesystems by default
- cmd = cmd .. " -l"
- end
-
- local fs_info = {} -- Get data from df
- local f = io.popen(cmd)
-
- 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
--- }}}
-
-return setmetatable(fs_all, { __call = function(_, ...) return worker(...) end })
+ fs_info["{" .. m .. " used_p}"] = tonumber(p)
+ fs_info["{" .. m .. " avail_p}"] = 100 - tonumber(p)
+ end
+ end,
+ output_done = function () callback(fs_info) end })
+ end }
diff --git a/widgets/gmail_all.lua b/widgets/gmail_all.lua
index db868c3..7e897b8 100644
--- a/widgets/gmail_all.lua
+++ b/widgets/gmail_all.lua
@@ -6,12 +6,10 @@
-- {{{ Grab environment
local type = type
local tonumber = tonumber
-local io = { popen = io.popen }
-local setmetatable = setmetatable
+local string = { match = string.match }
+
local helpers = require("vicious.helpers")
-local string = {
- match = string.match
-}
+local spawn = require("vicious.spawn")
-- }}}
@@ -19,59 +17,33 @@ local string = {
-- vicious.widgets.gmail
local gmail_all = {}
-
--- {{{ Variable definitions
-local rss = {
- inbox = "https://mail.google.com/mail/feed/atom",
- unread = "https://mail.google.com/mail/feed/atom/unread",
- --labelname = "https://mail.google.com/mail/feed/atom/labelname",
-}
-
--- Default is just Inbox
-local feed = rss.inbox
-local mail = {
- ["{count}"] = 0,
- ["{subject}"] = "N/A"
-}
--- }}}
-
-
-- {{{ Gmail widget type
-local function worker(format, warg)
- -- Get info from the Gmail atom feed
- local f = io.popen("curl --connect-timeout 1 -m 3 -fsn " .. helpers.shellquote(feed))
-
- -- Could be huge don't read it all at once, info we are after is at the top
- local xml = f:read(2000)
-
- if xml == nil then
- return mail
- end
-
- mail["{count}"] = -- Count comes before messages and matches at least 0
- tonumber(string.match(xml, "([%d]+)")) or mail["{count}"]
+local function parse(warg, stdout, stderr, exitreason, exitcode)
+ local count = -- Count comes before messages and matches at least 0
+ tonumber(string.match(stdout, "([%d]+)")) or 0
-- Find subject tag
- local title = string.match(xml, ".-(.-)")
+ local title = string.match(stdout, ".-(.-)") or "N/A"
- if title ~= nil 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}"] = title
+ -- Check if we should scroll, or maybe truncate
+ if type(warg) == "number" then
+ title = helpers.truncate(title, warg)
+ elseif type(warg) == "table" then
+ title = helpers.scroll(title, warg[1], warg[2])
end
- f:close()
+ return { ["{count}"] = count, ["{subject}"] = title }
+end
- return mail
+function gmail_all.async(format, warg, callback)
+ -- Get info from the Gmail atom feed using curl --netrc.
+ -- With username 'user' and password 'pass'
+ -- $HOME/.netrc should look similar to:
+ -- machine mail.google.com login user password pass
+ -- BE AWARE THAT MAKING THESE SETTINGS IS A SECURITY RISK!
+ spawn.easy_async("curl -fsn https://mail.google.com/mail/feed/atom",
+ function (...) callback(parse(warg, ...)) end)
end
-- }}}
-return setmetatable(gmail_all, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(gmail_all)
diff --git a/widgets/hddtemp_linux.lua b/widgets/hddtemp_linux.lua
index c46eb13..b381f2f 100644
--- a/widgets/hddtemp_linux.lua
+++ b/widgets/hddtemp_linux.lua
@@ -5,36 +5,24 @@
-- {{{ Grab environment
local tonumber = tonumber
-local io = { popen = io.popen }
-local setmetatable = setmetatable
-local string = { gmatch = string.gmatch }
-local helpers = require("vicious.helpers")
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- }}}
-- Hddtemp: provides hard drive temperatures using the hddtemp daemon
-- vicious.widgets.hddtemp
-local hddtemp_linux = {}
-
-
--- {{{ HDD Temperature widget type
-local function worker(format, warg)
- -- Fallback to default hddtemp port
- if warg == nil then warg = 7634 end
-
- local hdd_temp = {} -- Get info from the hddtemp daemon
- local quoted = helpers.shellquote(warg)
- local f = io.popen("echo | curl --connect-timeout 1 -fsm 3 telnet://127.0.0.1:"..quoted)
-
- 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
--- }}}
-
-return setmetatable(hddtemp_linux, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall{
+ async = function(format, warg, callback)
+ if warg == nil then warg = 7634 end -- fallback to default hddtemp port
+ local hdd_temp = {} -- get info from the hddtemp daemon
+ spawn.with_line_callback_with_shell(
+ "echo | curl -fs telnet://127.0.0.1:" .. warg,
+ { stdout = function (line)
+ for d, t in line:gmatch"|([%/%w]+)|.-|(%d+)|[CF]|" do
+ hdd_temp["{"..d.."}"] = tonumber(t)
+ end
+ end,
+ output_done = function () callback(hdd_temp) end })
+ end }
diff --git a/widgets/hwmontemp_linux.lua b/widgets/hwmontemp_linux.lua
index d995e72..9182932 100644
--- a/widgets/hwmontemp_linux.lua
+++ b/widgets/hwmontemp_linux.lua
@@ -4,57 +4,37 @@
----------------------------------------------------------------
-- environment
-local io = { popen = io.popen, open = io.open }
-local assert = assert
-local setmetatable = setmetatable
+local type = type
+local tonumber = tonumber
+local io = { open = io.open }
--- sysfs prefix for hwmon devices
-local sys_hwmon = "/sys/class/hwmon/"
--- cache table for hwmon device names
-local paths = {}
-
--- transparently caching hwmon device name lookup
-function name_to_path(name)
- if paths[name] then return paths[name] end
-
- for sensor in io.popen("ls -1 " .. sys_hwmon):lines() do
- local path = sys_hwmon .. sensor
- local f = assert(io.open(path .. "/name", "r"))
- local sname = f:read("*line")
- f:close()
- if sname == name then
- paths[name] = path
- return path
- end
- end
-
- return nil
-end
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- hwmontemp: provides name-indexed temps from /sys/class/hwmon
-- vicious.widgets.hwmontemp
-local hwmontemp_linux = {}
-
-function worker(format, warg)
- assert(type(warg) == "table", "invalid hwmontemp argument: must be a table")
- name = warg[1]
-
- if not warg[2] then
- input = 1
- else
- input = warg[2]
- end
-
- local sensor = name_to_path(name)
- if not sensor then return { "N/A" } end
-
- local f = assert(io.open(("%s/temp%d_input"):format(sensor, input), "r"))
- local temp = f:read("*line")
- f:close()
-
- return { temp / 1000 }
-end
-
-return setmetatable(hwmontemp_linux, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall{
+ async = function (format, warg, callback)
+ if type(warg) ~= "table" or type(warg[1]) ~= "string" then
+ return callback{}
+ end
+ local input = warg[2]
+ if type(input) == "number" then
+ input = ("temp%d_input"):format(input)
+ else
+ input = "temp1_input"
+ end
+ spawn.easy_async_with_shell(
+ "grep " .. warg[1] .. " -wl /sys/class/hwmon/*/name",
+ function (stdout, stderr, exitreason, exitcode)
+ if exitreason == "exit" and exitcode == 0 then
+ local f = io.open(stdout:gsub("name%s+", input), "r")
+ callback{ tonumber(f:read"*line") / 1000 }
+ f:close()
+ else
+ callback{}
+ end
+ end)
+ end }
-- vim: ts=4:sw=4:expandtab
diff --git a/widgets/mdir_all.lua b/widgets/mdir_all.lua
index 793609e..7853d54 100644
--- a/widgets/mdir_all.lua
+++ b/widgets/mdir_all.lua
@@ -5,9 +5,10 @@
---------------------------------------------------
-- {{{ Grab environment
-local io = { popen = io.popen }
-local setmetatable = setmetatable
-local helpers = require("vicious.helpers")
+local type = type
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- }}}
@@ -17,27 +18,25 @@ local mdir_all = {}
-- {{{ Maildir widget type
-local function worker(format, warg)
- if not warg then return end
-
- -- Initialize counters
- local count = { new = 0, cur = 0 }
-
- for i=1, #warg do
- quoted_path = helpers.shellquote(warg[i])
- -- Recursively find new messages
- local f = io.popen("find "..quoted_path.." -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 "..quoted_path.." -type f -regex '.*/cur/.*2,[^S]*$'")
- for line in f:lines() do count.cur = count.cur + 1 end
- f:close()
+function mdir_all.async(format, warg, callback)
+ if type(warg) ~= "table" then return callback{} end
+ local starting_points = ""
+ for _,dir in ipairs(warg) do
+ starting_points = starting_points .. " " .. helpers.shellquote(dir)
end
+ if starting_points == "" then return callback{ 0, 0 } end
- return {count.new, count.cur}
+ local new, cur = 0, 0
+ spawn.with_line_callback(
+ "find" .. starting_points .. " -type f -regex '.*/cur/.*2,[^S]*$';",
+ { stdout = function (filename) cur = cur + 1 end,
+ output_done = function ()
+ spawn.with_line_callback(
+ "find" .. starting_points .. " -type f -path '*/new/*';",
+ { stdout = function (filename) new = new + 1 end,
+ output_done = function () callback{ new, cur } end })
+ end })
end
-- }}}
-return setmetatable(mdir_all, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(mdir_all)
diff --git a/widgets/mem_freebsd.lua b/widgets/mem_freebsd.lua
index 66dbbaf..369039e 100644
--- a/widgets/mem_freebsd.lua
+++ b/widgets/mem_freebsd.lua
@@ -1,9 +1,14 @@
-- {{{ Grab environment
local tonumber = tonumber
-local setmetatable = setmetatable
local math = { floor = math.floor }
-local io = { popen = io.popen }
+local string = {
+ match = string.match,
+ gmatch = string.gmatch,
+ find = string.find
+}
+
local helpers = require("vicious.helpers")
+local spawn = require("vicious.spawn")
-- }}}
-- Mem: provides RAM and Swap usage statistics
@@ -12,74 +17,103 @@ local mem_freebsd = {}
-- {{{ Memory widget type
-local function worker(format)
- local pagesize = tonumber(helpers.sysctl("hw.pagesize"))
- local vm_stats = helpers.sysctl_table("vm.stats.vm")
- local _mem = { buf = {}, total = nil }
+function mem_freebsd.async(format, warg, callback)
+ helpers.sysctl_async({ "hw.pagesize",
+ "vm.stats.vm",
+ "vm.swap_total",
+ "vm.swap_enabled" },
+ function(ret)
- -- Get memory space in bytes
- _mem.total = tonumber(vm_stats.v_page_count) * pagesize
- _mem.buf.free = tonumber(vm_stats.v_free_count) * pagesize
- _mem.buf.laundry = tonumber(vm_stats.v_laundry_count) * pagesize
- _mem.buf.cache = tonumber(vm_stats.v_cache_count) * pagesize
- _mem.buf.wired = tonumber(vm_stats.v_wire_count) * pagesize
+ local pgsz = tonumber(ret["hw.pagesize"])
+ local _mem = { buf = {}, total = nil }
- -- Rework into megabytes
- _mem.total = math.floor(_mem.total/1048576)
- _mem.buf.free = math.floor(_mem.buf.free/1048576)
- _mem.buf.laundry = math.floor(_mem.buf.laundry/1048576)
- _mem.buf.cache = math.floor(_mem.buf.cache/1048576)
- _mem.buf.wired = math.floor(_mem.buf.wired/1048576)
+ -- Get memory space in bytes
+ _mem.total = tonumber(ret["vm.stats.vm.v_page_count"]) * pgsz
+ _mem.buf.free = tonumber(ret["vm.stats.vm.v_free_count"]) * pgsz
+ _mem.buf.laundry = tonumber(ret["vm.stats.vm.v_laundry_count"]) * pgsz
+ _mem.buf.cache = tonumber(ret["vm.stats.vm.v_cache_count"]) * pgsz
+ _mem.buf.wired = tonumber(ret["vm.stats.vm.v_wire_count"]) * pgsz
- -- Calculate memory percentage
- _mem.free = _mem.buf.free + _mem.buf.cache
- -- used memory basically consists of active+inactive+wired
- _mem.inuse = _mem.total - _mem.free
- _mem.notfreeable = _mem.inuse - _mem.buf.laundry
- _mem.wire = _mem.buf.wired
+ -- Rework into megabytes
+ _mem.total = math.floor(_mem.total/1048576)
+ _mem.buf.free = math.floor(_mem.buf.free/1048576)
+ _mem.buf.laundry = math.floor(_mem.buf.laundry/1048576)
+ _mem.buf.cache = math.floor(_mem.buf.cache/1048576)
+ _mem.buf.wired = math.floor(_mem.buf.wired/1048576)
- _mem.usep = math.floor(_mem.inuse / _mem.total * 100)
- _mem.wirep = math.floor(_mem.wire / _mem.total * 100)
- _mem.notfreeablep = math.floor(_mem.notfreeable / _mem.total * 100)
+ -- Calculate memory percentage
+ _mem.free = _mem.buf.free + _mem.buf.cache
+ -- used memory basically consists of active+inactive+wired
+ _mem.inuse = _mem.total - _mem.free
+ _mem.notfreeable = _mem.inuse - _mem.buf.laundry
+ _mem.wire = _mem.buf.wired
- -- Get swap states
- local vm_swap_total = tonumber(helpers.sysctl("vm.swap_total"))
- local vm_swap_enabled = tonumber(helpers.sysctl("vm.swap_enabled"))
- local _swp = { buf = {}, total = nil }
+ _mem.usep = math.floor(_mem.inuse / _mem.total * 100)
+ _mem.wirep = math.floor(_mem.wire / _mem.total * 100)
+ _mem.notfreeablep = math.floor(_mem.notfreeable / _mem.total * 100)
- if vm_swap_enabled == 1 and vm_swap_total > 0 then
- -- Initialise variables
- _swp.usep = 0
- _swp.inuse = 0
- _swp.total = 0
- _swp.buf.free = 0
+ -- Get swap states
+ local vm_swap_total = tonumber(ret["vm.swap_total"])
+ local vm_swap_enabled = tonumber(ret["vm.swap_enabled"])
+ local _swp = { buf = {}, total = nil }
- -- Read output of swapinfo in Mbytes
- local f = io.popen("swapinfo -m")
- -- Skip first line (table header)
- f:read("*line")
- -- Read content and sum up
- for line in f:lines() do
- local ltotal, lused, lfree = string.match(line, "%s+([%d]+)%s+([%d]+)%s+([%d]+)")
- -- Add swap space in Mbytes
- _swp.total = _swp.total + tonumber(ltotal)
- _swp.inuse = _swp.inuse + tonumber(lused)
- _swp.buf.free = _swp.buf.free + tonumber(lfree)
+ if vm_swap_enabled == 1 and vm_swap_total > 0 then
+ -- Initialise variables
+ _swp.usep = 0
+ _swp.inuse = 0
+ _swp.total = 0
+ _swp.buf.free = 0
+
+ -- Read output of swapinfo in Mbytes (from async function call)
+ -- Read content and sum up
+ spawn.with_line_callback("swapinfo -m", {
+ stdout = function(line)
+ if not string.find(line, "Device") then
+ local ltotal, lused, lfree = string.match(
+ line, "%s+([%d]+)%s+([%d]+)%s+([%d]+)")
+ -- Add swap space in Mbytes
+ _swp.total = _swp.total + tonumber(ltotal)
+ _swp.inuse = _swp.inuse + tonumber(lused)
+ _swp.buf.free = _swp.buf.free + tonumber(lfree)
+ end
+ end,
+ output_done = function()
+ print(_swp.inuse, _swp.total)
+ _swp.usep = math.floor(_swp.inuse / _swp.total * 100)
+ callback({ _mem.usep,
+ _mem.inuse,
+ _mem.total,
+ _mem.free,
+ _swp.usep,
+ _swp.inuse,
+ _swp.total,
+ _swp.buf.free,
+ _mem.wirep,
+ _mem.wire,
+ _mem.notfreeablep,
+ _mem.notfreeable })
+ end
+ })
+ else
+ _swp.usep = -1
+ _swp.inuse = -1
+ _swp.total = -1
+ _swp.buf.free = -1
+ callback({ _mem.usep,
+ _mem.inuse,
+ _mem.total,
+ _mem.free,
+ _swp.usep,
+ _swp.inuse,
+ _swp.total,
+ _swp.buf.free,
+ _mem.wirep,
+ _mem.wire,
+ _mem.notfreeablep,
+ _mem.notfreeable })
end
- f:close()
-
- -- Calculate percentage
- _swp.usep = math.floor(_swp.inuse / _swp.total * 100)
- else
- _swp.usep = -1
- _swp.inuse = -1
- _swp.total = -1
- _swp.buf.free = -1
- end
-
- return { _mem.usep, _mem.inuse, _mem.total, _mem.free,
- _swp.usep, _swp.inuse, _swp.total, _swp.buf.free,
- _mem.wirep, _mem.wire, _mem.notfreeablep, _mem.notfreeable }
+ end)
end
+-- }}}
-return setmetatable(mem_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(mem_freebsd)
diff --git a/widgets/mpd_all.lua b/widgets/mpd_all.lua
index 0504c4a..b54a1e2 100644
--- a/widgets/mpd_all.lua
+++ b/widgets/mpd_all.lua
@@ -5,11 +5,11 @@
-- {{{ Grab environment
local tonumber = tonumber
-local io = { popen = io.popen }
-local setmetatable = setmetatable
-local string = { gmatch = string.gmatch }
-local helpers = require("vicious.helpers")
local math = { floor = math.floor }
+local type = type
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- }}}
@@ -25,7 +25,7 @@ end
-- }}}
-- {{{ Format playing progress
-function format_progress(elapsed, duration)
+local function format_progress(elapsed, duration)
local em, es = math.floor(elapsed / 60), math.floor(elapsed % 60)
local dm, ds = math.floor(duration / 60), math.floor(duration % 60)
@@ -33,18 +33,22 @@ function format_progress(elapsed, duration)
return ("%d:%02d"):format(em, es), ("%d:%02d"):format(dm, ds)
elseif dm < 60 then
return ("%02d:%02d"):format(em, es), ("%02d:%02d"):format(dm, ds)
- elseif dm < 600 then
- return ("%d:%02d:%02d"):format(math.floor(em / 60), math.floor(em % 60), es),
- ("%d:%02d:%02d"):format(math.floor(dm / 60), math.floor(dm % 60), ds)
+ end
+
+ local eh, dh = math.floor(em / 60), math.floor(dm / 60)
+ em, dm = math.floor(em % 60), math.floor(dm % 60)
+ if dm < 600 then
+ return ("%d:%02d:%02d"):format(eh, em, es),
+ ("%d:%02d:%02d"):format(dh, dm, ds)
else
- return ("%02d:%02d:%02d"):format(math.floor(em / 60), math.floor(em % 60), es),
- ("%02d:%02d:%02d"):format(math.floor(dm / 60), math.floor(dm % 60), ds)
+ return ("%02d:%02d:%02d"):format(eh, em, es),
+ ("%02d:%02d:%02d"):format(dh, dm, ds)
end
end
-- }}}
-- {{{ Format playing progress (percentage)
-function format_progress_percentage(elapsed, duration)
+local function format_progress_percentage(elapsed, duration)
if duration > 0 then
local percentage = math.floor((elapsed / duration) * 100 + 0.5)
return ("%d%%"):format(percentage)
@@ -55,7 +59,7 @@ end
-- }}}
-- {{{ MPD widget type
-local function worker(format, warg)
+function mpd_all.async(format, warg, callback)
-- Fallback values
local mpd_state = {
["{volume}"] = 0,
@@ -81,36 +85,34 @@ local function worker(format, warg)
warg and (warg.port or warg[3]) or "6600")
-- Get data from MPD server
- local f = io.popen(query .. "|" .. connect)
- for line in f:lines() do
- for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
- local key = "{" .. k .. "}"
- if k == "volume" or k == "bitrate" or
- k == "elapsed" or k == "duration" then
- mpd_state[key] = v and tonumber(v)
- elseif k == "repeat" or k == "random" then
- mpd_state[key] = cbool(v)
- elseif k == "state" then
- mpd_state[key] = helpers.capitalize(v)
- elseif k == "Artist" or k == "Title" or
- --k == "Name" or k == "file" or
- k == "Album" or k == "Genre" then
- mpd_state[key] = v
+ spawn.with_line_callback_with_shell(query .. "|" .. connect, {
+ stdout = function (line)
+ for k, v in line:gmatch"([%w]+):[%s](.*)$" do
+ local key = "{" .. k .. "}"
+ if k == "volume" or k == "bitrate" or
+ k == "elapsed" or k == "duration" then
+ mpd_state[key] = v and tonumber(v)
+ elseif k == "repeat" or k == "random" then
+ mpd_state[key] = cbool(v)
+ elseif k == "state" then
+ mpd_state[key] = helpers.capitalize(v)
+ elseif k == "Artist" or k == "Title" or
+ --k == "Name" or k == "file" or
+ k == "Album" or k == "Genre" then
+ mpd_state[key] = v
+ end
end
- end
- end
- f:close()
-
- -- Formatted elapsed and duration
- mpd_state["{Elapsed}"], mpd_state["{Duration}"] = format_progress(
- mpd_state["{elapsed}"], mpd_state["{duration}"])
-
- -- Formatted playing progress percentage
- mpd_state["{Progress}"] = format_progress_percentage(
- mpd_state["{elapsed}"], mpd_state["{duration}"])
-
- return mpd_state
+ end,
+ output_done = function ()
+ -- Formatted elapsed and duration
+ mpd_state["{Elapsed}"], mpd_state["{Duration}"] = format_progress(
+ mpd_state["{elapsed}"], mpd_state["{duration}"])
+ -- Formatted playing progress percentage
+ mpd_state["{Progress}"] = format_progress_percentage(
+ mpd_state["{elapsed}"], mpd_state["{duration}"])
+ callback(mpd_state)
+ end })
end
-- }}}
-return setmetatable(mpd_all, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(mpd_all)
diff --git a/widgets/net_freebsd.lua b/widgets/net_freebsd.lua
index f78b016..41a2eb7 100644
--- a/widgets/net_freebsd.lua
+++ b/widgets/net_freebsd.lua
@@ -1,10 +1,13 @@
-- {{{ Grab environment
local tonumber = tonumber
local os = { time = os.time }
-local setmetatable = setmetatable
+local string = {
+ match = string.match,
+ gmatch = string.gmatch
+}
+
local helpers = require("vicious.helpers")
-local io = { popen = io.popen }
-local string = { match = string.match }
+local spawn = require("vicious.spawn")
-- }}}
@@ -21,28 +24,25 @@ local unit = { ["b"] = 1, ["kb"] = 1024,
}
-- {{{ Net widget type
-local function worker(format, warg)
- if not warg then return end
+local function parse(stdout, stderr, exitreason, exitcode)
local args = {}
local buffer = nil
- local f = io.popen("netstat -n -b -I " .. helpers.shellquote(warg))
local now = os.time()
-
- for line in f:lines() do
+
+ for line in string.gmatch(stdout, "[^\n]+") do
if not (line:find("
+---------------------------------------------------
+
+-- {{{ Grab environment
+local los = { getenv = os.getenv }
+local string = { match = string.match }
+local helpers = require("vicious.helpers")
+local spawn = require("vicious.spawn")
+-- }}}
+
+
+-- OS: provides operating system information
+-- vicious.widgets.os
+local os_bsd = {}
+
+
+-- {{{ Operating system widget type
+local function parse(stdout, stderr, exitreason, exitcode)
+ local system = {
+ ["ostype"] = "N/A",
+ ["hostname"] = "N/A",
+ ["osrelease"] = "N/A",
+ ["username"] = "N/A",
+ ["entropy"] = "N/A",
+ ["entropy_p"] = "N/A"
+ }
+
+ -- BSD manual page: uname(1)
+ system["ostype"], system["hostname"], system["osrelease"] =
+ string.match(stdout, "([%w]+)[%s]([%w%p]+)[%s]([%w%p]+)")
+
+ -- Get user from the environment
+ system["username"] = los.getenv("USER")
+
+ return {system["ostype"], system["osrelease"], system["username"],
+ system["hostname"], system["entropy"], system["entropy_p"]}
+end
+
+function os_bsd.async(format, warg, callback)
+ spawn.easy_async("uname -snr",
+ function (...) callback(parse(...)) end)
+end
+-- }}}
+
+return helpers.setasyncall(os_bsd)
diff --git a/widgets/os_all.lua b/widgets/os_linux.lua
similarity index 72%
rename from widgets/os_all.lua
rename to widgets/os_linux.lua
index 4c41338..4f1b516 100644
--- a/widgets/os_all.lua
+++ b/widgets/os_linux.lua
@@ -6,21 +6,18 @@
-- {{{ Grab environment
local pairs = pairs
local tonumber = tonumber
-local io = { popen = io.popen }
local math = { ceil = math.ceil }
local los = { getenv = os.getenv }
local setmetatable = setmetatable
-local helpers = require("vicious.helpers")
-local string = {
- gsub = string.gsub,
- match = string.match
-}
+local string = { gsub = string.gsub }
+
+local helpers = require"vicious.helpers"
-- }}}
-- OS: provides operating system information
-- vicious.widgets.os
-local os_all = {}
+local os_linux = {}
-- {{{ Operating system widget type
@@ -36,22 +33,12 @@ local function worker(format)
-- Linux manual page: uname(2)
local kernel = helpers.pathtotable("/proc/sys/kernel")
- for k, v in pairs(system) do
+ for k, _ 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
-
-- Linux manual page: random(4)
if kernel.random then
-- Linux 2.6 default entropy pool is 4096-bits
@@ -70,4 +57,5 @@ local function worker(format)
end
-- }}}
-return setmetatable(os_all, { __call = function(_, ...) return worker(...) end })
+return setmetatable(os_linux,
+ { __call = function(_, ...) return worker(...) end })
diff --git a/widgets/thermal_freebsd.lua b/widgets/thermal_freebsd.lua
index 3387a52..bd3fc4d 100644
--- a/widgets/thermal_freebsd.lua
+++ b/widgets/thermal_freebsd.lua
@@ -1,6 +1,7 @@
-- {{{ Grab environment
-local setmetatable = setmetatable
local string = { match = string.match }
+local type = type
+
local helpers = require("vicious.helpers")
-- }}}
@@ -9,26 +10,25 @@ local helpers = require("vicious.helpers")
-- vicious.widgets.thermal
local thermal_freebsd = {}
-
-- {{{ Thermal widget type
-local function worker(format, warg)
- if not warg then return end
+function thermal_freebsd.async(format, warg, callback)
+ if not warg then return callback{} end
if type(warg) ~= "table" then warg = { warg } end
- local thermals = {}
+ helpers.sysctl_async(warg, function(ret)
+ local thermals = {}
- for i=1, #warg do
- local output = helpers.sysctl(warg[i])
-
- if not output then
- thermals[i] = -1
- else
- thermals[i] = string.match(output, "[%d]+")
+ for i=1,#warg do
+ if ret[warg[i]] ~= nil then
+ thermals[i] = string.match(ret[warg[i]], "[%d]+")
+ else
+ thermals[i] = "N/A"
+ end
end
- end
- return thermals
+ callback(thermals)
+ end)
end
-- }}}
-return setmetatable(thermal_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(thermal_freebsd)
diff --git a/widgets/uptime_freebsd.lua b/widgets/uptime_freebsd.lua
index 9e075e5..cbe6edb 100644
--- a/widgets/uptime_freebsd.lua
+++ b/widgets/uptime_freebsd.lua
@@ -1,10 +1,9 @@
-- {{{ Grab environment
local tonumber = tonumber
-local setmetatable = setmetatable
local math = { floor = math.floor }
-local string = { match = string.match }
-local helpers = require("vicious.helpers")
local os = { time = os.time }
+
+local helpers = require("vicious.helpers")
-- }}}
@@ -14,17 +13,23 @@ local uptime_freebsd = {}
-- {{{ Uptime widget type
-local function worker(format)
- local l1, l5, l15 = string.match(helpers.sysctl("vm.loadavg"), "{ ([%d]+%.[%d]+) ([%d]+%.[%d]+) ([%d]+%.[%d]+) }")
- local up_t = os.time() - tonumber(string.match(helpers.sysctl("kern.boottime"), "sec = ([%d]+)"))
+function uptime_freebsd.async(format, warg, callback)
+ helpers.sysctl_async(
+ { "vm.loadavg", "kern.boottime" },
+ function(ret)
+ local l1, l5, l15 = ret["vm.loadavg"]:match(
+ "{ ([%d]+%.[%d]+) ([%d]+%.[%d]+) ([%d]+%.[%d]+) }")
+ local up_t = os.time() - tonumber(
+ ret["kern.boottime"]:match"sec = ([%d]+)")
- -- Get system uptime
- 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 system uptime
+ 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)
- return {up_d, up_h, up_m, l1, l5, l15}
+ return callback({ up_d, up_h, up_m, l1, l5, l15 })
+ end)
end
-- }}}
-return setmetatable(uptime_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(uptime_freebsd)
diff --git a/widgets/volume_freebsd.lua b/widgets/volume_freebsd.lua
index 200f4b7..d86957a 100644
--- a/widgets/volume_freebsd.lua
+++ b/widgets/volume_freebsd.lua
@@ -1,9 +1,8 @@
-- {{{ Grab environment
local tonumber = tonumber
-local io = { popen = io.popen }
-local setmetatable = setmetatable
local string = { match = string.match }
local helpers = require("vicious.helpers")
+local spawn = require("vicious.spawn")
-- }}}
@@ -13,26 +12,20 @@ local volume_freebsd = {}
-- {{{ Volume widget type
-local function worker(format, warg)
- if not warg then return end
+local STATE = { on = '๐', off = '๐' }
- local mixer_state = { "โซ", "โฉ" }
-
- -- Get mixer control contents
- f = io.popen("mixer -s " .. helpers.shellquote(warg))
- local mixer = f:read()
- f:close()
-
- -- Capture mixer control state: [5%] ... ... [on]
- local voll, volr = string.match(mixer, "([%d]+):([%d]+)$")
-
- if voll == "0" and volr == "0" then
- return {0, 0, mixer_state[2]}
- else
- return {voll, volr, mixer_state[1]}
- end
+local function parse(stdout, stderr, exitreason, exitcode)
+ -- Capture mixer control state, e.g. 42 : 42
+ local voll, volr = string.match(stdout, "([%d]+):([%d]+)\n$")
+ if voll == "0" and volr == "0" then return { 0, 0, STATE.off } end
+ return { tonumber(voll), tonumber(volr), STATE.on }
+end
+function volume_freebsd.async(format, warg, callback)
+ if not warg then return callback{} end
+ spawn.easy_async("mixer " .. helpers.shellquote(warg),
+ function (...) callback(parse(...)) end)
end
-- }}}
-return setmetatable(volume_freebsd, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(volume_freebsd)
diff --git a/widgets/volume_linux.lua b/widgets/volume_linux.lua
index 098017d..3c281af 100644
--- a/widgets/volume_linux.lua
+++ b/widgets/volume_linux.lua
@@ -4,6 +4,7 @@
---------------------------------------------------
-- {{{ Grab environment
+local type = type
local tonumber = tonumber
local string = { match = string.match }
local table = { concat = table.concat }
diff --git a/widgets/wifi_linux.lua b/widgets/wifi_linux.lua
index 423765a..b7a3fd8 100644
--- a/widgets/wifi_linux.lua
+++ b/widgets/wifi_linux.lua
@@ -4,89 +4,50 @@
---------------------------------------------------
-- {{{ Grab environment
+local type = type
local tonumber = tonumber
-local math = { ceil = math.ceil }
-local setmetatable = setmetatable
-local helpers = require("vicious.helpers")
-local io = {
- open = io.open,
- popen = io.popen
-}
-local string = {
- find = string.find,
- match = string.match
-}
+local math = { floor = math.floor }
+
+local helpers = require"vicious.helpers"
+local spawn = require"vicious.spawn"
-- }}}
--- Wifi: provides wireless information for a requested interface
+-- Wifi: provides wireless information for a requested interface using iwconfig
-- vicious.widgets.wifi
local wifi_linux = {}
-
--- {{{ Variable definitions
-local iwconfig = "iwconfig"
-local iwcpaths = { "/sbin", "/usr/sbin", "/usr/local/sbin", "/usr/bin" }
--- }}}
-
-
-- {{{ Wireless widget type
-local function worker(format, warg)
- if not warg then return end
-
- -- Default values
- local winfo = {
- ["{ssid}"] = "N/A",
- ["{mode}"] = "N/A",
- ["{chan}"] = 0,
- ["{rate}"] = 0,
- ["{link}"] = 0,
- ["{linp}"] = 0,
- ["{sign}"] = 0
- }
-
- -- Sbin paths aren't in user PATH, search for the binary
- if iwconfig == "iwconfig" then
- for _, p in ipairs(iwcpaths) do
- local f = io.open(p .. "/iwconfig", "rb")
- if f then
- iwconfig = p .. "/iwconfig"
- f:close()
- break
- end
- end
- end
-
- -- Get data from iwconfig where available
- local f = io.popen(iwconfig .." ".. helpers.shellquote(warg) .. " 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
- -- SSID can have almost anything in it
- winfo["{ssid}"] = string.match(iw, 'ESSID[=:]"(.-)"') 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}"])
-
- -- Link quality percentage if quality was available
- if winfo["{link}"] ~= 0 then winfo["{linp}"] = math.ceil(winfo["{link}"] / 0.7) end
-
+local function parser(stdout, stderr, exitreason, exitcode)
+ local winfo = {}
+ -- Output differs from system to system, stats can be separated by
+ -- either = or :. Some stats may not be supported by driver.
+ -- SSID can have almost anything in it.
+ winfo["{ssid}"] = stdout:match'ESSID[=:]"(.-)"' or "N/A"
+ -- Modes are simple, but also match the "-" in Ad-Hoc
+ winfo["{mode}"] = stdout:match"Mode[=:]([%w%-]+)" or "N/A"
+ winfo["{chan}"] = tonumber(stdout:match"Channel[=:](%d+)" or 0)
+ winfo["{rate}"] = -- Bitrate without unit (Mb/s)
+ tonumber(stdout:match"Bit Rate[=:]%s?([%d%.]+)" or 0)
+ winfo["{freq}"] = -- Frequency in MHz (is output always in GHz?)
+ tonumber(stdout:match"Frequency[=:]%s?([%d%.]+)" or 0) * 1000
+ winfo["{txpw}"] = -- Transmission power in dBm
+ tonumber(stdout:match"Tx%-Power[=:](%d+)" or 0)
+ winfo["{link}"] = -- Link quality over 70
+ tonumber(stdout:match"Link Quality[=:](%d+)" or 0)
+ winfo["{linp}"] = -- Link quality percentage if quality was available
+ winfo["{link}"] ~= 0 and math.floor(winfo["{link}"]/0.7 + 0.5) or 0
+ -- Signal level without unit (dBm), can be negative value
+ winfo["{sign}"] = tonumber(stdout:match"Signal level[=:](%-?%d+)" or 0)
return winfo
end
+
+function wifi_linux.async(format, warg, callback)
+ if type(warg) ~= "string" then return callback{} end
+ spawn.easy_async_with_shell(
+ "PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin iwconfig " .. warg,
+ function (...) callback(parser(...)) end)
+end
-- }}}
-return setmetatable(wifi_linux, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(wifi_linux)
diff --git a/widgets/wifiiw_linux.lua b/widgets/wifiiw_linux.lua
index 47aa5ee..e67ee33 100644
--- a/widgets/wifiiw_linux.lua
+++ b/widgets/wifiiw_linux.lua
@@ -4,65 +4,58 @@
---------------------------------------------------
-- {{{ Grab environment
+local type = type
local tonumber = tonumber
-local setmetatable = setmetatable
+
local helpers = require("vicious.helpers")
-local io = {
- open = io.open,
- popen = io.popen
-}
-local string = {
- find = string.find,
- match = string.match
-}
+local spawn = require("vicious.spawn")
-- }}}
--- Wifiiw: provides wireless information for a requested interface using iw instead of deprecated iwconfig
+-- Wifiiw: provides wireless information for a requested interface
+-- using iw instead of deprecated iwconfig
-- vicious.widgets.wifiiw
local wifiiw_linux = {}
+local LINK = "PATH=$PATH:/sbin/:/usr/sbin:/usr/local/sbin iw dev %s link"
+local INFO = "PATH=$PATH:/sbin/:/usr/sbin:/usr/local/sbin iw dev %s info"
-- {{{ Wireless widget type
-local function worker(format, warg)
- if not warg then return end
-
- -- Default values
+function wifiiw_linux.async(format, warg, callback)
+ if type(warg) ~= "string" then return callback{} end
local winfo = {}
- -- Get data from iw where available
- local f = io.popen("export PATH=$PATH:/sbin/:/usr/sbin:/usr/local/sbin;" ..
- "iw dev ".. helpers.shellquote(tostring(warg)) .. " link 2>&1;" ..
- "iw dev ".. helpers.shellquote(tostring(warg)) .. " info 2>&1")
- local iwresult = f:read("*all")
- f:close()
-
- -- iw wasn't found, isn't executable, or non-wireless interface
- if iwresult == nil or string.find(iwresult, "No such device") then
- return winfo
+ local function parse_link(stdout)
+ winfo["{bssid}"] = stdout:match"Connected to ([%x:]*)" or "N/A"
+ winfo["{ssid}"] = stdout:match"SSID: ([^\n]*)" or "N/A"
+ winfo["{freq}"] = tonumber(stdout:match"freq: (%d+)" or 0)
+ winfo["{sign}"] = -- Signal level can be negative; w/o unit (dBm)
+ tonumber(stdout:match"signal: (%-?%d+)" or 0)
+ winfo["{linp}"] = -- Link Quality (-100dBm->0%, -50dBm->100%)
+ winfo["{sign}"] ~= 0 and 200 + winfo["{sign}"]*2 or 0
+ winfo["{rate}"] = -- Transmission rate, without unit (Mb/s)
+ tonumber(stdout:match"tx bitrate: ([%d%.]+)" or 0)
end
- -- string match is simple in most cases, because iw uses a new line for every info
- winfo["{bssid}"] = -- BSSID has hex digits and colons
- string.match(iwresult, "Connected to ([%x:]*)") or "N/A"
- winfo["{ssid}"] = -- SSID can have almost anything in it until new line
- string.match(iwresult, "SSID: ([^\n]*)") or "N/A"
- winfo["{mode}"] = -- everything after 'type ' until new line
- string.match(iwresult, "type ([^\n]*)") or "N/A"
- winfo["{chan}"] = -- Channels are plain digits
- tonumber(string.match(iwresult, "channel ([%d]+)") or 0)
- winfo["{rate}"] = -- We don't want to display Mb/s
- tonumber(string.match(iwresult, "tx bitrate: ([%d%.]*)") or 0)
- winfo["{freq}"] = -- Frequency are plain digits
- tonumber(string.match(iwresult, "freq: ([%d]+)") or 0)
- winfo["{sign}"] = -- Signal level can be a negative value, don't display decibel notation
- tonumber(string.match(iwresult, "signal: (%-[%d]+)") or 0)
- winfo["{linp}"] = -- Link Quality using the Windows definition (-50dBm->100%, -100dBm->0%)
- (winfo["{sign}"] ~= 0 and 100 - ((winfo["{sign}"] * -2) - 100) or 0)
- winfo["{txpw}"] = -- TX Power can be a negative value, don't display decibel notation
- tonumber(string.match(iwresult, "txpower ([%-]?[%d]+)") or 0)
- return winfo
+ local function parse_info(stdout)
+ winfo["{mode}"] = stdout:match"type ([^\n]*)" or "N/A"
+ winfo["{chan}"] = tonumber(stdout:match"channel (%d+)" or 0)
+ -- Transmission power, without unit (dBm)
+ winfo["{txpw}"] = tonumber(stdout:match"txpower (%-?%d+)" or 0)
+ end
+
+ spawn.easy_async_with_shell(
+ LINK:format(warg),
+ function (std_out, std_err, exit_reason, exit_code)
+ parse_link(std_out)
+ spawn.easy_async_with_shell(
+ INFO:format(warg),
+ function (stdout, stderr, exitreason, exitcode)
+ parse_info(stdout)
+ callback(winfo)
+ end)
+ end)
end
-- }}}
-return setmetatable(wifiiw_linux, { __call = function(_, ...) return worker(...) end })
+return helpers.setasyncall(wifiiw_linux)