-- Grab environment
local awful = require('awful')
+-- Avoid discrepancies across multiple shells
+awful.util.shell = '/bin/sh'
+
-- Initialize tables for module
asyncshell = { request_table = {}, id_counter = 0 }
lines = io.lines,
popen = io.popen }
local rawget = rawget
+local table = { sort = table.sort }
-- Lain helper functions for internal use
-- lain.helpers
-- }}}
+--{{{ Iterate over table of records sorted by keys
+function helpers.spairs(t)
+ -- collect the keys
+ local keys = {}
+ for k in pairs(t) do keys[#keys+1] = k end
+
+ table.sort(keys)
+
+ -- return the iterator function
+ local i = 0
+ return function()
+ i = i + 1
+ if keys[i] then
+ return keys[i], t[keys[i]]
+ end
+ end
+end
+--}}}
+
return helpers
printf ("\n%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
- print " Used Free Total ";
+ print " Used Free Total ";
if (! NARROW_MODE)
print "";
}
# printf ("stars_number = %d\n", stars_number);
printf ("|");
- for (i = 1; i <= stars_number; i++)
+ for (i = 1; i <= stars_number && i <= 49; i++)
{
printf ("%s", "*");
}
bat_now.time = string.format("%02d:%02d", hrs, min)
- bat_now.perc = first_line(bstr .. "/capacity")
-
- if not bat_now.perc then
- local perc = (rem / tot) * 100
- if perc <= 100 then
- bat_now.perc = string.format("%d", perc)
- elseif perc > 100 then
- bat_now.perc = "100"
- elseif perc < 0 then
- bat_now.perc = "0"
- end
+ local perc = tonumber(first_line(bstr .. "/capacity")) or math.floor((rem / tot) * 100)
+
+ if perc <= 100 then
+ bat_now.perc = string.format("%d", perc)
+ elseif perc > 100 then
+ bat_now.perc = "100"
+ elseif perc < 0 then
+ bat_now.perc = "0"
end
if rate ~= nil and ratev ~= nil then
local setmetatable = setmetatable
+-- Keyboard layout switcher
+-- lain.widgets.contrib.kblayout
+
local function worker (args)
local kbdlayout = {}
kbdlayout.widget = wibox.widget.textbox('')
local settings = args.settings or function () end
local add_us_secondary = true
local timeout = args.timeout or 5
-
local idx = 1
-
+
if args.add_us_secondary == false then add_us_secondary = false end
-- Mouse bindings
local setmetatable = setmetatable
+-- MOC audio player
+-- lain.widgets.contrib.moc
local moc = {}
local function worker(args)
local newtimer = require("lain.helpers").newtimer
local read_pipe = require("lain.helpers").read_pipe
+local spairs = require("lain.helpers").spairs
local wibox = require("wibox")
+local awful = require("awful")
local util = require("lain.util")
local io = { popen = io.popen }
local pairs = pairs
local string = { len = string.len,
match = string.match }
-local table = { sort = table.sort }
local setmetatable = setmetatable
local mailpath = args.mailpath or os.getenv("HOME") .. "/Mail"
local ignore_boxes = args.ignore_boxes or {}
local settings = args.settings or function() end
+ local ext_mail_cmd = args.external_mail_cmd
maildir.widget = wibox.widget.textbox('')
function update()
+ if ext_mail_cmd ~= nil
+ then
+ awful.util.spawn(ext_mail_cmd)
+ end
+
-- Find pathes to mailboxes.
local p = io.popen("find " .. mailpath ..
- " -mindepth 1 -maxdepth 1 -type d" ..
+ " -mindepth 1 -maxdepth 2 -type d" ..
" -not -name .git")
local boxes = {}
repeat
"-not -name '.*' -printf a")
-- Strip off leading mailpath.
- local box = string.match(line, mailpath .. "/*([^/]+)")
+ local box = string.match(line, mailpath .. "/(.*)")
local nummails = string.len(mailstring)
if nummails > 0
then
end
until line == nil
- p:close()
- table.sort(boxes)
+ p:close()
newmail = "no mail"
-- Count the total number of mails irrespective of where it was found
total = 0
- for box, number in pairs(boxes)
+ for box, number in spairs(boxes)
do
-- Add this box only if it's not to be ignored.
if not util.element_in_table(box, ignore_boxes)
mpd_now = {
state = "N/A",
file = "N/A",
+ name = "N/A",
artist = "N/A",
title = "N/A",
album = "N/A",
-- Network infos
-- lain.widgets.net
-local net = {
- last_t = 0,
- last_r = 0
-}
-
-function net.get_device()
- local ws = helpers.read_pipe("ip link show | cut -d' ' -f2,9")
- ws = ws:match("%w+: UP") or ws:match("ppp%w+: UNKNOWN")
- if ws ~= nil then
- return ws:match("(%w+):")
- else
- return "network off"
- end
-end
local function worker(args)
- local args = args or {}
- local timeout = args.timeout or 2
- local units = args.units or 1024 --kb
- local notify = args.notify or "on"
- local screen = args.screen or 1
- local settings = args.settings or function() end
+ local net = { last_t = 0, last_r = 0 }
- iface = args.iface or net.get_device()
+ function net.get_device()
+ local ws = helpers.read_pipe("ip link show | cut -d' ' -f2,9")
+ ws = ws:match("%w+: UP") or ws:match("ppp%w+: UNKNOWN")
+ if ws ~= nil then
+ return ws:match("(%w+):")
+ else
+ return "network off"
+ end
+ end
+
+ local args = args or {}
+ local timeout = args.timeout or 2
+ local units = args.units or 1024 --kb
+ local notify = args.notify or "on"
+ local screen = args.screen or 1
+ local settings = args.settings or function() end
+ local iface = args.iface or net.get_device()
net.widget = wibox.widget.textbox('')
end
helpers.newtimer(iface, timeout, update)
- return net.widget
+
+ return setmetatable(net, { __index = net.widget })
end
-return setmetatable(net, { __call = function(_, ...) return worker(...) end })
+return setmetatable({}, { __call = function(_, ...) return worker(...) end })
--- /dev/null
+
+--[[
+
+ Licensed under GNU General Public License v2
+ * (c) 2016, Luke Bonham
+
+--]]
+
+local read_pipe = require("lain.helpers").read_pipe
+local newtimer = require("lain.helpers").newtimer
+local wibox = require("wibox")
+
+local string = { match = string.match,
+ format = string.format }
+
+local setmetatable = setmetatable
+
+-- PulseAudio volume
+-- lain.widgets.pulseaudio
+local pulseaudio = {}
+
+local function worker(args)
+ local args = args or {}
+ local timeout = args.timeout or 5
+ local settings = args.settings or function() end
+
+ pulseaudio.sink = args.sink or 0 -- user defined or first one
+ pulseaudio.cmd = args.cmd or string.format("pacmd list-sinks | grep -e 'index: %d' -e 'volume: front' -e 'muted'", pulseaudio.sink)
+ pulseaudio.widget = wibox.widget.textbox('')
+
+ function pulseaudio.update()
+ local s = read_pipe(pulseaudio.cmd)
+
+ volume_now = {}
+ volume_now.left = tonumber(string.match(s, "left.-(%d+)%%"))
+ volume_now.right = tonumber(string.match(s, "right.-(%d+)%%"))
+ volume_now.muted = string.match(s, "muted: (%S+)")
+
+ widget = pulseaudio.widget
+ settings()
+ end
+
+ newtimer(string.format("pulseaudio-%s", pulseaudio.sink), timeout, pulseaudio.update)
+
+ return setmetatable(pulseaudio, { __index = pulseaudio.widget })
+end
+
+return setmetatable(pulseaudio, { __call = function(_, ...) return worker(...) end })
local function worker(args)
local weather = {}
local args = args or {}
+ local APPID = args.APPID or "3e321f9414eaedbfab34983bda77a66e" -- lain default
local timeout = args.timeout or 900 -- 15 min
local timeout_forecast = args.timeout or 86400 -- 24 hrs
- local current_call = "curl -s 'http://api.openweathermap.org/data/2.5/weather?id=%s&units=%s&lang=%s'"
- local forecast_call = "curl -s 'http://api.openweathermap.org/data/2.5/forecast/daily?id=%s&units=%s&lang=%s&cnt=%s'"
+ local current_call = "curl -s 'http://api.openweathermap.org/data/2.5/weather?id=%s&units=%s&lang=%s&APPID=%s'"
+ local forecast_call = "curl -s 'http://api.openweathermap.org/data/2.5/forecast/daily?id=%s&units=%s&lang=%s&cnt=%s&APPID=%s'"
local city_id = args.city_id or 0 -- placeholder
local units = args.units or "metric"
local lang = args.lang or "en"
function (day, desc, tmin, tmax)
return string.format("<b>%s</b>: %s, %d - %d ", day, desc, tmin, tmax)
end
+ local weather_na_markup = args.weather_na_markup or " N/A "
local followmouse = args.followmouse or false
local settings = args.settings or function() end
- weather.widget = wibox.widget.textbox('')
- weather.icon = wibox.widget.imagebox()
+ weather.widget = wibox.widget.textbox(weather_na_markup)
+ weather.icon_path = icons_path .. "na.png"
+ weather.icon = wibox.widget.imagebox(weather.icon_path)
function weather.show(t_out)
weather.hide()
end
weather.notification = naughty.notify({
- text = weather.notification_text,
+ text = weather.notification_text
+ or "Waiting for the server to respond...",
icon = weather.icon_path,
timeout = t_out,
preset = notification_preset
end
function weather.forecast_update()
- local cmd = string.format(forecast_call, city_id, units, lang, cnt)
+ local cmd = string.format(forecast_call, city_id, units, lang, cnt, APPID)
async.request(cmd, function(f)
local pos, err
weather_now, pos, err = json.decode(f, 1, nil)
end
end
else
- weather.icon_path = icons_path .. "na.png"
weather.notification_text = "API/connection error or bad/not set city ID"
end
end)
end
function weather.update()
- local cmd = string.format(current_call, city_id, units, lang)
+ local cmd = string.format(current_call, city_id, units, lang, APPID)
async.request(cmd, function(f)
local pos, err
weather_now, pos, err = json.decode(f, 1, nil)
if not err and weather_now ~= nil and tonumber(weather_now["cod"]) == 200 then
weather.icon_path = icons_path .. weather_now["weather"][1]["icon"] .. ".png"
- weather.icon:set_image(weather.icon_path)
widget = weather.widget
settings()
else
- weather.widget._layout.text = " N/A " -- tries to avoid textbox bugs
- weather.icon:set_image(icons_path .. "na.png")
+ weather.icon_path = icons_path .. "na.png"
+ weather.widget:set_markup(weather_na_markup)
end
+
+ weather.icon:set_image(weather.icon_path)
end)
end
-Subproject commit d7aa1a7b8428211a1c4c71865fd64302e013d62b
+Subproject commit dcce6dd58791c7c1d2e2e3f046b4da0d5b9700a7