diff options
Diffstat (limited to '.config/awesome/lain/widgets')
62 files changed, 2223 insertions, 0 deletions
diff --git a/.config/awesome/lain/widgets/alsa.lua b/.config/awesome/lain/widgets/alsa.lua new file mode 100644 index 0000000..28bb05c --- /dev/null +++ b/.config/awesome/lain/widgets/alsa.lua @@ -0,0 +1,65 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010, Adrian C. <anrxc@sysphere.org> + +--]] + +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") + +local io = { popen = io.popen } +local string = { match = string.match } + +local setmetatable = setmetatable + +-- ALSA volume +-- lain.widgets.alsa +local alsa = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 5 + local channel = args.channel or "Master" + local settings = args.settings or function() end + + alsa.widget = wibox.widget.textbox('') + + function alsa.update() + local f = assert(io.popen('amixer get ' .. channel)) + local mixer = f:read("*all") + f:close() + + volume_now = {} + + volume_now.level, volume_now.status = string.match(mixer, "([%d]+)%%.*%[([%l]*)") + + if volume_now.level == nil + then + volume_now.level = "0" + volume_now.status = "off" + end + + if volume_now.status == "" + then + if volume_now.level == "0" + then + volume_now.status = "off" + else + volume_now.status = "on" + end + end + + widget = alsa.widget + settings() + end + + newtimer("alsa", timeout, alsa.update) + + return setmetatable(alsa, { __index = alsa.widget }) +end + +return setmetatable(alsa, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/alsabar.lua b/.config/awesome/lain/widgets/alsabar.lua new file mode 100644 index 0000000..365ac2d --- /dev/null +++ b/.config/awesome/lain/widgets/alsabar.lua @@ -0,0 +1,175 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2013, Rman + +--]] + +local newtimer = require("lain.helpers").newtimer + +local awful = require("awful") +local beautiful = require("beautiful") +local naughty = require("naughty") + +local io = { popen = io.popen } +local math = { modf = math.modf } +local string = { format = string.format, + match = string.match, + rep = string.rep } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- ALSA volume bar +-- lain.widgets.alsabar +local alsabar = +{ + channel = "Master", + step = "5%", + + colors = + { + background = beautiful.bg_normal, + mute = "#EB8F8F", + unmute = "#A4CE8A" + }, + + terminal = terminal or "xterm", + mixer = terminal .. " -e alsamixer", + + notifications = + { + font = beautiful.font:sub(beautiful.font:find(""), beautiful.font:find(" ")), + font_size = "11", + color = beautiful.fg_normal, + bar_size = 18 + }, + + _current_level = 0, + _muted = false +} + +function alsabar.notify() + alsabar.update() + + local preset = + { + title = "", + text = "", + timeout = 4, + font = alsabar.notifications.font .. " " .. + alsabar.notifications.font_size, + fg = alsabar.notifications.color + } + + if alsabar._muted + then + preset.title = alsabar.channel .. " - Muted" + else + preset.title = alsabar.channel .. " - " .. alsabar._current_level * 100 .. "%" + end + + int = math.modf(alsabar._current_level * alsabar.notifications.bar_size) + preset.text = "[" + .. string.rep("|", int) + .. string.rep(" ", alsabar.notifications.bar_size - int) + .. "]" + + if alsabar._notify ~= nil then + alsabar._notify = naughty.notify ({ + replaces_id = alsabar._notify.id, + preset = preset + }) + else + alsabar._notify = naughty.notify ({ + preset = preset + }) + end +end + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 4 + local settings = args.settings or function() end + local width = args.width or 63 + local height = args.heigth or 1 + local ticks = args.ticks or false + local ticks_size = args.ticks_size or 7 + local vertical = args.vertical or false + + alsabar.channel = args.channel or alsabar.channel + alsabar.step = args.step or alsabar.step + alsabar.colors = args.colors or alsabar.colors + alsabar.notifications = args.notifications or alsabar.notifications + + alsabar.bar = awful.widget.progressbar() + + alsabar.bar:set_background_color(alsabar.colors.background) + alsabar.bar:set_color(alsabar.colors.unmute) + alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } }) + alsabar.bar:set_width(width) + alsabar.bar:set_height(height) + alsabar.bar:set_ticks(ticks) + alsabar.bar:set_ticks_size(ticks_size) + alsabar.bar:set_vertical(vertical) + + function alsabar.update() + -- Get mixer control contents + local f = io.popen("amixer get " .. alsabar.channel) + local mixer = f:read("*all") + f:close() + + -- Capture mixer control state: [5%] ... ... [on] + local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)") + + if volu == nil then + volu = 0 + mute = "off" + end + + alsabar._current_level = tonumber(volu) / 100 + alsabar.bar:set_value(alsabar._current_level) + + if not mute and tonumber(volu) == 0 or mute == "off" + then + alsabar._muted = true + alsabar.tooltip:set_text (" [Muted] ") + alsabar.bar:set_color(alsabar.colors.mute) + else + alsabar._muted = false + alsabar.tooltip:set_text(string.format(" %s:%s ", alsabar.channel, volu)) + alsabar.bar:set_color(alsabar.colors.unmute) + end + + volume_now = {} + volume_now.level = tonumber(volu) + volume_now.status = mute + settings() + end + + newtimer("alsabar", timeout, alsabar.update) + + alsabar.bar:buttons (awful.util.table.join ( + awful.button ({}, 1, function() + awful.util.spawn(alsabar.mixer) + end), + awful.button ({}, 3, function() + awful.util.spawn(string.format("amixer set %s toggle", alsabar.channel)) + alsabar.update() + end), + awful.button ({}, 4, function() + awful.util.spawn(string.format("amixer set %s %s+", alsabar.channel, alsabar.step)) + alsabar.update() + end), + awful.button ({}, 5, function() + awful.util.spawn(string.format("amixer set %s %s-", alsabar.channel, alsabar.step)) + alsabar.update() + end) + )) + + return alsabar +end + +return setmetatable(alsabar, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/base.lua b/.config/awesome/lain/widgets/base.lua new file mode 100644 index 0000000..3d4ce9e --- /dev/null +++ b/.config/awesome/lain/widgets/base.lua @@ -0,0 +1,40 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2014, Luke Bonham + +--]] + +local newtimer = require("lain.helpers").newtimer +local wibox = require("wibox") + +local io = io +local setmetatable = setmetatable + +-- Basic template for custom widgets +-- lain.widgets.base +local base = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 5 + local cmd = args.cmd or "" + local settings = args.settings or function() end + + base.widget = wibox.widget.textbox('') + + function base.update() + local f = assert(io.popen(cmd)) + output = f:read("*all") + f:close() + widget = base.widget + settings() + end + + newtimer(cmd, timeout, base.update) + + return setmetatable(base, { __index = base.widget }) +end + +return setmetatable(base, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/bat.lua b/.config/awesome/lain/widgets/bat.lua new file mode 100644 index 0000000..485fd57 --- /dev/null +++ b/.config/awesome/lain/widgets/bat.lua @@ -0,0 +1,149 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local newtimer = require("lain.helpers").newtimer +local first_line = require("lain.helpers").first_line + +local naughty = require("naughty") +local wibox = require("wibox") + +local math = { floor = math.floor } +local string = { format = string.format } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- Battery infos +-- lain.widgets.bat +local bat = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 30 + local battery = args.battery or "BAT0" + local notify = args.notify or "on" + local settings = args.settings or function() end + + bat.widget = wibox.widget.textbox('') + + bat_notification_low_preset = { + title = "Battery low", + text = "Plug the cable!", + timeout = 15, + fg = "#202020", + bg = "#CDCDCD" + } + + bat_notification_critical_preset = { + title = "Battery exhausted", + text = "Shutdown imminent", + timeout = 15, + fg = "#000000", + bg = "#FFFFFF" + } + + function update() + bat_now = { + status = "Not present", + perc = "N/A", + time = "N/A", + watt = "N/A" + } + + local bstr = "/sys/class/power_supply/" .. battery + + local present = first_line(bstr .. "/present") + + if present == "1" + then + local rate = first_line(bstr .. "/power_now") or + first_line(bstr .. "/current_now") + + local ratev = first_line(bstr .. "/voltage_now") + + local rem = first_line(bstr .. "/energy_now") or + first_line(bstr .. "/charge_now") + + local tot = first_line(bstr .. "/energy_full") or + first_line(bstr .. "/charge_full") + + bat_now.status = first_line(bstr .. "/status") or "N/A" + + rate = tonumber(rate) or 1 + ratev = tonumber(ratev) + rem = tonumber(rem) + tot = tonumber(tot) + + local time_rat = 0 + if bat_now.status == "Charging" + then + time_rat = (tot - rem) / rate + elseif bat_now.status == "Discharging" + then + time_rat = rem / rate + end + + local hrs = math.floor(time_rat) + if hrs < 0 then hrs = 0 elseif hrs > 23 then hrs = 23 end + + local min = math.floor((time_rat - hrs) * 60) + if min < 0 then min = 0 elseif min > 59 then min = 59 end + + 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 + end + + if rate ~= nil and ratev ~= nil then + bat_now.watt = string.format("%.2fW", (rate * ratev) / 1e12) + else + bat_now.watt = "N/A" + end + + end + + widget = bat.widget + settings() + + -- notifications for low and critical states + bat_now.perc = tonumber(bat_now.perc) + if bat_now.status == "Discharging" and notify == "on" and bat_now.perc ~= nil + then + if bat_now.perc <= 5 + then + bat.id = naughty.notify({ + preset = bat_notification_critical_preset, + replaces_id = bat.id + }).id + elseif bat_now.perc <= 15 + then + bat.id = naughty.notify({ + preset = bat_notification_low_preset, + replaces_id = bat.id + }).id + end + end + end + + newtimer("bat", timeout, update) + + return bat.widget +end + +return setmetatable(bat, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/borderbox.lua b/.config/awesome/lain/widgets/borderbox.lua new file mode 100644 index 0000000..c251ea8 --- /dev/null +++ b/.config/awesome/lain/widgets/borderbox.lua @@ -0,0 +1,61 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local wibox = require("awful.wibox") +local setmetatable = setmetatable + +-- Creates a thin wibox at a position relative to another wibox +-- lain.widgets.borderbox +local borderbox = {} + +local function worker(relbox, s, args) + local where = args.position or 'top' + local color = args.color or '#FFFFFF' + local size = args.size or 1 + local box = nil + local wiboxarg = { + position = nil, + bg = color + } + + if where == 'top' + then + wiboxarg.width = relbox.width + wiboxarg.height = size + box = wibox(wiboxarg) + box.x = relbox.x + box.y = relbox.y - size + elseif where == 'bottom' + then + wiboxarg.width = relbox.width + wiboxarg.height = size + box = wibox(wiboxarg) + box.x = relbox.x + box.y = relbox.y + relbox.height + elseif where == 'left' + then + wiboxarg.width = size + wiboxarg.height = relbox.height + box = wibox(wiboxarg) + box.x = relbox.x - size + box.y = relbox.y + elseif where == 'right' + then + wiboxarg.width = size + wiboxarg.height = relbox.height + box = wibox(wiboxarg) + box.x = relbox.x + relbox.width + box.y = relbox.y + end + + box.screen = s + return box +end + +return setmetatable(borderbox, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/calendar.lua b/.config/awesome/lain/widgets/calendar.lua new file mode 100644 index 0000000..c9e265a --- /dev/null +++ b/.config/awesome/lain/widgets/calendar.lua @@ -0,0 +1,125 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + +--]] + +local icons_dir = require("lain.helpers").icons_dir + +local awful = require("awful") +local beautiful = require("beautiful") +local naughty = require("naughty") + +local io = io +local os = { date = os.date } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- Calendar notification +-- lain.widgets.calendar +local calendar = {} +local cal_notification = nil + +function calendar:hide() + if cal_notification ~= nil then + naughty.destroy(cal_notification) + cal_notification = nil + end +end + +function calendar:show(t_out, inc_offset) + calendar:hide() + + local offs = inc_offset or 0 + local tims = t_out or 0 + local f, c_text + local today = tonumber(os.date('%d')) + local init_t = '/usr/bin/cal | sed -r -e "s/(^| )( ' + + if offs == 0 + then -- current month showing, today highlighted + if today >= 10 + then + init_t = '/usr/bin/cal | sed -r -e "s/(^| )(' + end + + calendar.offset = 0 + calendar.notify_icon = calendar.icons .. today .. ".png" + + -- bg and fg inverted to highlight today + f = io.popen( init_t .. today .. + ')($| )/\\1<b><span foreground=\\"' + .. calendar.bg .. + '\\" background=\\"' + .. calendar.fg .. + '\\">\\2<\\/span><\\/b>\\3/"' ) + + else -- no current month showing, no day to highlight + local month = tonumber(os.date('%m')) + local year = tonumber(os.date('%Y')) + + calendar.offset = calendar.offset + offs + month = month + calendar.offset + + if month > 12 then + month = month % 12 + year = year + 1 + if month <= 0 then + month = 12 + end + elseif month < 1 then + month = month + 12 + year = year - 1 + if month <= 0 then + month = 1 + end + end + + calendar.notify_icon = nil + + f = io.popen('/usr/bin/cal ' .. month .. ' ' .. year) + end + + c_text = "<tt><span font='" .. calendar.font .. " " + .. calendar.font_size .. "'><b>" + .. f:read() .. "</b>\n\n" + .. f:read() .. "\n" + .. f:read("*all"):gsub("\n*$", "") + .. "</span></tt>" + f:close() + + cal_notification = naughty.notify({ + text = c_text, + icon = calendar.notify_icon, + position = calendar.position, + fg = calendar.fg, + bg = calendar.bg, + timeout = tims + }) +end + +function calendar:attach(widget, args) + local args = args or {} + calendar.icons = args.icons or icons_dir .. "cal/white/" + calendar.font = args.font or beautiful.font:sub(beautiful.font:find(""), + beautiful.font:find(" ")) + calendar.font_size = tonumber(args.font_size) or 11 + calendar.fg = args.fg or beautiful.fg_normal or "#FFFFFF" + calendar.bg = args.bg or beautiful.bg_normal or "#FFFFFF" + calendar.position = args.position or "top_right" + + calendar.offset = 0 + calendar.notify_icon = nil + + widget:connect_signal("mouse::enter", function () calendar:show() end) + widget:connect_signal("mouse::leave", function () calendar:hide() end) + widget:buttons(awful.util.table.join( awful.button({ }, 1, function () + calendar:show(0, -1) end), + awful.button({ }, 3, function () + calendar:show(0, 1) end) )) +end + +return setmetatable(calendar, { __call = function(_, ...) return create(...) end }) diff --git a/.config/awesome/lain/widgets/contrib/ccurr.lua b/.config/awesome/lain/widgets/contrib/ccurr.lua new file mode 100644 index 0000000..f696a35 --- /dev/null +++ b/.config/awesome/lain/widgets/contrib/ccurr.lua @@ -0,0 +1,82 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2014, Aaron Lebo + +--]] + +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") +local json = require("dkjson") + +local string = { format = string.format } +local tonumber = tonumber + +-- Crypto currencies widget +-- lain.widgets.contrib.ccurr +local ccurr = {} + +-- Currently gets +-- * BTC/USD +-- * DOGE/USD +-- using Coinbase and Cryptsy APIs. + +-- requires http://dkolf.de/src/dkjson-lua.fsl/home +-- based upon http://awesome.naquadah.org/wiki/Bitcoin_Price_Widget + +local function get(url) + local f = io.popen('curl -m 5 -s "' .. url .. '"') + if not f then + return 0 + else + local s = f:read("*all") + f:close() + return s + end +end + +local function parse(j) + local obj, pos, err = json.decode(j, 1, nil) + if err then + return nil + else + return obj + end +end + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 600 + local btc_url = args.btc_url or "https://coinbase.com/api/v1/prices/buy" + local doge_url = args.doge_url or "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=132" + local settings = args.settings or function() end + + ccurr.widget = wibox.widget.textbox('') + + local function update() + price_now = { + btc = "N/A", + doge = "N/A" + } + + btc = parse(get(btc_url)) + doge = parse(get(doge_url)) + + if btc and doge then + price_now.btc = tonumber(btc["subtotal"]["amount"]) + price_now.doge = tonumber(doge["return"]["markets"]["DOGE"]["lasttradeprice"]) + price_now.doge = string.format("%.4f", price_now.btc * price_now.doge) + end + + widget = ccurr.widget + settings() + end + + newtimer("ccurr", timeout, update) + + return ccurr.widget +end + +return setmetatable(ccurr, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/contrib/init.lua b/.config/awesome/lain/widgets/contrib/init.lua new file mode 100644 index 0000000..9a9fa63 --- /dev/null +++ b/.config/awesome/lain/widgets/contrib/init.lua @@ -0,0 +1,20 @@ + +--[[ + + Lain + Layouts, widgets and utilities for Awesome WM + + Users contributed widgets section + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local wrequire = require("lain.helpers").wrequire +local setmetatable = setmetatable + +local widgets = { _NAME = "lain.widgets.contrib" } + +return setmetatable(widgets, { __index = wrequire }) diff --git a/.config/awesome/lain/widgets/contrib/task.lua b/.config/awesome/lain/widgets/contrib/task.lua new file mode 100644 index 0000000..a6c9f31 --- /dev/null +++ b/.config/awesome/lain/widgets/contrib/task.lua @@ -0,0 +1,133 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2013, Jan Xie + +--]] + +local icons_dir = require("lain.helpers").icons_dir + +local awful = require("awful") +local beautiful = require("beautiful") +local naughty = require("naughty") + +local io = io +local string = { len = string.len } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- Taskwarrior notification +-- lain.widgets.task +local task = {} + +local task_notification = nil + +function task:hide() + if task_notification ~= nil then + naughty.destroy(task_notification) + task_notification = nil + end +end + +function task:show() + task:hide() + + local f, c_text + + f = io.popen('task') + c_text = "<span font='" + .. task.font .. " " + .. task.font_size .. "'>" + .. f:read("*all"):gsub("\n*$", "") + .. "</span>" + f:close() + + task_notification = naughty.notify({ title = "[task next]", + text = c_text, + icon = task.notify_icon, + position = task.position, + fg = task.fg, + bg = task.bg, + timeout = task.timeout }) +end + +function task:prompt_add() + awful.prompt.run({ prompt = "Add task: " }, + mypromptbox[mouse.screen].widget, + function (...) + local f = io.popen("task add " .. ...) + c_text = "\n<span font='" + .. task.font .. " " + .. task.font_size .. "'>" + .. f:read("*all") + .. "</span>" + f:close() + + naughty.notify({ + text = c_text, + icon = task.notify_icon, + position = task.position, + fg = task.fg, + bg = task.bg, + timeout = task.timeout + }) + end, + nil, + awful.util.getdir("cache") .. "/history_task_add") +end + +function task:prompt_search() + awful.prompt.run({ prompt = "Search task: " }, + mypromptbox[mouse.screen].widget, + function (...) + local f = io.popen("task " .. ...) + c_text = f:read("*all"):gsub(" \n*$", "") + f:close() + + if string.len(c_text) == 0 + then + c_text = "No results found." + else + c_text = "<span font='" + .. task.font .. " " + .. task.font_size .. "'>" + .. c_text + .. "</span>" + end + + naughty.notify({ + title = "[task next " .. ... .. "]", + text = c_text, + icon = task.notify_icon, + position = task.position, + fg = task.fg, + bg = task.bg, + timeout = task.timeout + }) + end, + nil, + awful.util.getdir("cache") .. "/history_task") +end + +function task:attach(widget, args) + local args = args or {} + + task.font_size = tonumber(args.font_size) or 12 + task.font = beautiful.font:sub(beautiful.font:find(""), + beautiful.font:find(" ")) + task.fg = args.fg or beautiful.fg_normal or "#FFFFFF" + task.bg = args.bg or beautiful.bg_normal or "#FFFFFF" + task.position = args.position or "top_right" + task.timeout = args.timeout or 7 + + task.notify_icon = icons_dir .. "/taskwarrior/task.png" + task.notify_icon_small = icons_dir .. "/taskwarrior/tasksmall.png" + + widget:connect_signal("mouse::enter", function () task:show() end) + widget:connect_signal("mouse::leave", function () task:hide() end) +end + +return setmetatable(task, { __call = function(_, ...) return create(...) end }) diff --git a/.config/awesome/lain/widgets/contrib/tpbat/init.lua b/.config/awesome/lain/widgets/contrib/tpbat/init.lua new file mode 100644 index 0000000..72d6453 --- /dev/null +++ b/.config/awesome/lain/widgets/contrib/tpbat/init.lua @@ -0,0 +1,166 @@ + +--[[ + + tpbat.lua + Battery status widget for ThinkPad laptops that use SMAPI + lain.widgets.contrib.tpbat + + More on tp_smapi: http://www.thinkwiki.org/wiki/Tp_smapi + + Licensed under GNU General Public License v2 + * (c) 2013, Conor Heine + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local debug = { getinfo = debug.getinfo } +local newtimer = require("lain.helpers").newtimer +local first_line = require("lain.helpers").first_line +local beautiful = require("beautiful") +local naughty = require("naughty") +local wibox = require("wibox") + +local string = { format = string.format } +local math = { floor = math.floor } +local tostring = tostring +local setmetatable = setmetatable + +package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])[^\/]-$]] .. "?.lua;" .. package.path +local smapi = require("smapi") + +-- ThinkPad SMAPI-enabled battery info widget +-- lain.widgets.contrib.tpbat +local tpbat = { } +local tpbat_notification = nil + +function tpbat:hide() + if tpbat_notification ~= nil + then + naughty.destroy(tpbat_notification) + tpbat_notification = nil + end +end + +function tpbat:show(t_out) + tpbat:hide() + + local bat = self.bat + local t_out = t_out or 0 + + if bat == nil or not bat:installed() then return end + + local mfgr = bat:get('manufacturer') or "no_mfgr" + local model = bat:get('model') or "no_model" + local chem = bat:get('chemistry') or "no_chem" + local status = bat:get('state') or "nil" + local time = bat:remaining_time() + local msg = "\t" + + if status ~= "idle" and status ~= "nil" + then + if time == "N/A" + then + msg = "...Calculating time remaining..." + else + msg = time .. (status == "charging" and " until charged" or " remaining") + end + else + msg = "On AC Power" + end + + local str = string.format("%s : %s %s (%s)\n", bat.name, mfgr, model, chem) + .. string.format("\n%s \t\t\t %s", status:upper(), msg) + + tpbat_notification = naughty.notify({ + preset = { fg = beautiful.fg_normal }, + text = str, + timeout = t_out + }) +end + +function tpbat.register(args) + local args = args or {} + local timeout = args.timeout or 30 + local battery = args.battery or "BAT0" + local settings = args.settings or function() end + + tpbat.bat = smapi:battery(battery) -- Create a new battery + local bat = tpbat.bat + + tpbat.widget = wibox.widget.textbox('') + + bat_notification_low_preset = { + title = "Battery low", + text = "Plug the cable!", + timeout = 15, + fg = "#202020", + bg = "#CDCDCD" + } + + bat_notification_critical_preset = { + title = "Battery exhausted", + text = "Shutdown imminent", + timeout = 15, + fg = "#000000", + bg = "#FFFFFF" + } + + if bat:get('state') == nil + then + local n = naughty.notify({ + preset = bat_notification_low_preset, + title = "SMAPI Battery Warning: Unable to read battery state!", + text = "This widget is intended for ThinkPads. Is tp_smapi installed? Check your configs & paths." + }) + end + + function update() + bat_now = { + status = "Not present", + perc = "N/A", + time = "N/A", + watt = "N/A" + } + + if bat:installed() + then + bat_now.status = bat:status() or "N/A" + bat_now.perc = bat:percent() + bat_now.time = bat:remaining_time() + -- bat_now.watt = string.format("%.2fW", (VOLTS * AMPS) / 1e12) + + -- notifications for low and critical states (when discharging) + if bat_now.status == "discharging" + then + if bat_now.perc <= 5 + then + tpbat.id = naughty.notify({ + preset = bat_notification_critical_preset, + replaces_id = tpbat.id + }).id + elseif bat_now.perc <= 15 + then + tpbat.id = naughty.notify({ + preset = bat_notification_low_preset, + replaces_id = tpbat.id + }).id + end + end + + bat_now.perc = tostring(bat_now.perc) + end + + widget = tpbat.widget + settings() + end + + newtimer("tpbat", timeout, update) + + widget:connect_signal('mouse::enter', function () tpbat:show() end) + widget:connect_signal('mouse::leave', function () tpbat:hide() end) + + return tpbat.widget +end + +return setmetatable(tpbat, { __call = function(_, ...) return tpbat.register(...) end }) diff --git a/.config/awesome/lain/widgets/contrib/tpbat/smapi.lua b/.config/awesome/lain/widgets/contrib/tpbat/smapi.lua new file mode 100644 index 0000000..862d4cd --- /dev/null +++ b/.config/awesome/lain/widgets/contrib/tpbat/smapi.lua @@ -0,0 +1,102 @@ + +--[[ + + smapi.lua + Interface with thinkpad battery information + + Licensed under GNU General Public License v2 + * (c) 2013, Conor Heine + +--]] + +local first_line = require("lain.helpers").first_line + +local string = { format = string.format } +local tonumber = tonumber +local setmetatable = setmetatable + +local smapi = {} + +local apipath = "/sys/devices/platform/smapi" + +-- Most are readable values, but some can be written to (not implemented, yet?) +local readable = { + barcoding = true, + charging_max_current = true, + charging_max_voltage = true, + chemistry = true, + current_avg = true, + current_now = true, + cycle_count = true, + design_capacity = true, + design_voltage = true, + dump = true, + first_use_date = true, + force_discharge = false, + group0_voltage = true, + group1_voltage = true, + group2_voltage = true, + group3_voltage = true, + inhibit_charge_minutes = false, + installed = true, + last_full_capacity = true, + manufacture_date = true, + manufacturer = true, + model = true, + power_avg = true, + power_now = true, + remaining_capacity = true, + remaining_charging_time = true, + remaining_percent = true, + remaining_percent_error = true, + remaining_running_time = true, + remaining_running_time_now = true, + serial = true, + start_charge_thresh = false, + state = true, + stop_charge_thresh = false, + temperature = true, + voltage = true, +} + +function smapi:battery(name) + local bat = {} + + bat.name = name + bat.path = apipath .. "/" .. name + + function bat:get(item) + return self.path ~= nil and readable[item] and first_line(self.path .. "/" .. item) or nil + end + + function bat:installed() + return self:get("installed") == "1" + end + + function bat:status() + return self:get('state') + end + + -- Remaining time can either be time until battery dies or time until charging completes + function bat:remaining_time() + local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time' + local mins_left = self:get(time_val) + + if mins_left:find("^%d+") == nil + then + return "N/A" + end + + local hrs = mins_left / 60 + local min = mins_left % 60 + return string.format("%02d:%02d", hrs, min) + end + + function bat:percent() + return tonumber(self:get("remaining_percent")) + end + + return setmetatable(bat, {__metatable = false, __newindex = false}) +end + +return smapi diff --git a/.config/awesome/lain/widgets/cpu.lua b/.config/awesome/lain/widgets/cpu.lua new file mode 100644 index 0000000..0b21edc --- /dev/null +++ b/.config/awesome/lain/widgets/cpu.lua @@ -0,0 +1,77 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local first_line = require("lain.helpers").first_line +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") + +local math = { ceil = math.ceil } +local string = { format = string.format, + gmatch = string.gmatch } +local tostring = tostring + +local setmetatable = setmetatable + +-- CPU usage +-- lain.widgets.cpu +local cpu = { + last_total = 0, + last_active = 0 +} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 5 + local settings = args.settings or function() end + + cpu.widget = wibox.widget.textbox('') + + function update() + -- Read the amount of time the CPUs have spent performing + -- different kinds of work. Read the first line of /proc/stat + -- which is the sum of all CPUs. + local times = first_line("/proc/stat") + local at = 1 + local idle = 0 + local total = 0 + for field in string.gmatch(times, "[%s]+([^%s]+)") + do + -- 3 = idle, 4 = ioWait. Essentially, the CPUs have done + -- nothing during these times. + if at == 3 or at == 4 + then + idle = idle + field + end + total = total + field + at = at + 1 + end + local active = total - idle + + -- Read current data and calculate relative values. + local dactive = active - cpu.last_active + local dtotal = total - cpu.last_total + + cpu_now = {} + cpu_now.usage = tostring(math.ceil((dactive / dtotal) * 100)) + + widget = cpu.widget + settings() + + -- Save current data for the next run. + cpu.last_active = active + cpu.last_total = total + end + + newtimer("cpu", timeout, update) + + return cpu.widget +end + +return setmetatable(cpu, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/fs.lua b/.config/awesome/lain/widgets/fs.lua new file mode 100644 index 0000000..7406e05 --- /dev/null +++ b/.config/awesome/lain/widgets/fs.lua @@ -0,0 +1,120 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010, Adrian C. <anrxc@sysphere.org> + * (c) 2009, Lucas de Vries <lucas@glacicle.com> + +--]] + +local helpers = require("lain.helpers") + +local beautiful = require("beautiful") +local wibox = require("wibox") +local naughty = require("naughty") + +local io = io +local pairs = pairs +local string = { match = string.match, + format = string.format } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- File system disk space usage +-- lain.widgets.fs +local fs = {} + +local notification = nil +fs_notification_preset = { fg = beautiful.fg_normal } + +function fs:hide() + if notification ~= nil then + naughty.destroy(notification) + notification = nil + end +end + +function fs:show(t_out) + fs:hide() + + local f = io.popen(helpers.scripts_dir .. "dfs") + ws = f:read("*all"):gsub("\n*$", "") + f:close() + + notification = naughty.notify({ + preset = fs_notification_preset, + text = ws, + timeout = t_out + }) +end + +-- Units definitions +local unit = { ["mb"] = 1024, ["gb"] = 1024^2 } + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 600 + local partition = args.partition or "/" + local settings = args.settings or function() end + + fs.widget = wibox.widget.textbox('') + + helpers.set_map("fs", false) + + function update() + fs_info = {} + fs_now = {} + + local f = io.popen("LC_ALL=C df -kP") + + 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 + fs_info[m .. " size_mb"] = string.format("%.1f", tonumber(s) / unit["mb"]) + fs_info[m .. " size_gb"] = string.format("%.1f", tonumber(s) / unit["gb"]) + fs_info[m .. " used_p"] = tonumber(p) + fs_info[m .. " avail_p"] = 100 - tonumber(p) + end + end + + f:close() + + -- chosen partition easy stuff + -- you can however check whatever partition else + fs_now.used = tonumber(fs_info[partition .. " used_p"]) or 0 + fs_now.available = tonumber(fs_info[partition .. " avail_p"]) or 0 + fs_now.size_mb = tonumber(fs_info[partition .. " size_mb"]) or 0 + fs_now.size_gb = tonumber(fs_info[partition .. " size_gb"]) or 0 + + widget = fs.widget + settings() + + if fs_now.used >= 99 and not helpers.get_map("fs") + then + naughty.notify({ + title = "warning", + text = partition .. " ran out!\nmake some room", + timeout = 8, + fg = "#000000", + bg = "#FFFFFF" + }) + helpers.set_map("fs", true) + else + helpers.set_map("fs", false) + end + end + + helpers.newtimer(partition, timeout, update) + + widget:connect_signal('mouse::enter', function () fs:show(0) end) + widget:connect_signal('mouse::leave', function () fs:hide() end) + + return setmetatable(fs, { __index = fs.widget }) +end + +return setmetatable(fs, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/imap.lua b/.config/awesome/lain/widgets/imap.lua new file mode 100644 index 0000000..39518bd --- /dev/null +++ b/.config/awesome/lain/widgets/imap.lua @@ -0,0 +1,87 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + +--]] + +local helpers = require("lain.helpers") + +local naughty = require("naughty") +local wibox = require("wibox") + +local io = { popen = io.popen } +local string = { format = string.format, + gsub = string.gsub } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- Mail IMAP check +-- lain.widgets.imap +local imap = {} + +local function worker(args) + local args = args or {} + + local server = args.server + local mail = args.mail + local password = args.password + + local port = args.port or 993 + local timeout = args.timeout or 60 + local is_plain = args.is_plain or false + local settings = args.settings or function() end + + local head_command = "curl --connect-timeout 1 -fsm 3" + local request = "-X 'SEARCH (UNSEEN)'" + + helpers.set_map(mail, 0) + + if not is_plain + then + local f = io.popen(password) + password = f:read("*all"):gsub("\n", "") + f:close() + end + + imap.widget = wibox.widget.textbox('') + + function update() + mail_notification_preset = { + icon = helpers.icons_dir .. "mail.png", + position = "top_left" + } + + curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:%s %s -k", + head_command, server, port, mail, password, request) + + f = io.popen(curl) + ws = f:read("*all") + f:close() + + _, mailcount = string.gsub(ws, "%d+", "") + _ = nil + + widget = imap.widget + settings() + + if mailcount > helpers.get_map(mail) and mailcount >= 1 + then + if mailcount == 1 then + nt = mail .. " has one new message" + else + nt = mail .. " has <b>" .. mailcount .. "</b> new messages" + end + naughty.notify({ preset = mail_notification_preset, text = nt }) + end + + helpers.set_map(mail, mailcount) + end + + helpers.newtimer(mail, timeout, update, true) + return imap.widget +end + +return setmetatable(imap, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/init.lua b/.config/awesome/lain/widgets/init.lua new file mode 100644 index 0000000..0e863ba --- /dev/null +++ b/.config/awesome/lain/widgets/init.lua @@ -0,0 +1,20 @@ + +--[[ + + Lain + Layouts, widgets and utilities for Awesome WM + + Widgets section + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local wrequire = require("lain.helpers").wrequire +local setmetatable = setmetatable + +local widgets = { _NAME = "lain.widgets" } + +return setmetatable(widgets, { __index = wrequire }) diff --git a/.config/awesome/lain/widgets/maildir.lua b/.config/awesome/lain/widgets/maildir.lua new file mode 100644 index 0000000..d460881 --- /dev/null +++ b/.config/awesome/lain/widgets/maildir.lua @@ -0,0 +1,95 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") + +local io = io +local os = { getenv = os.getenv } +local pairs = pairs +local string = { len = string.len, + match = string.match } +local table = { sort = table.sort } + +local setmetatable = setmetatable + +-- Maildir check +-- lain.widgets.maildir +local maildir = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 60 + local mailpath = args.mailpath or os.getenv("HOME") .. "/Mail" + local ignore_boxes = args.ignore_boxes or {} + local settings = args.settings or function() end + + maildir.widget = wibox.widget.textbox('') + + function update() + -- Find pathes to mailboxes. + local p = io.popen("find " .. mailpath .. + " -mindepth 1 -maxdepth 1 -type d" .. + " -not -name .git") + local boxes = {} + repeat + line = p:read("*l") + if line ~= nil + then + -- Find all files in the "new" subdirectory. For each + -- file, print a single character (no newline). Don't + -- match files that begin with a dot. + -- Afterwards the length of this string is the number of + -- new mails in that box. + local np = io.popen("find " .. line .. + "/new -mindepth 1 -type f " .. + "-not -name '.*' -printf a") + local mailstring = np:read("*all") + + -- Strip off leading mailpath. + local box = string.match(line, mailpath .. "/*([^/]+)") + local nummails = string.len(mailstring) + if nummails > 0 + then + boxes[box] = nummails + end + end + until line == nil + + table.sort(boxes) + + newmail = "no mail" + + local count = 0 + for box, number in pairs(boxes) + do + count = count + 1 + -- Add this box only if it's not to be ignored. + if not util.element_in_table(box, ignore_boxes) + then + if newmail == "" + then + newmail = box .. "(" .. number .. ")" + else + newmail = newmail .. ", " .. + box .. "(" .. number .. ")" + end + end + end + + widget = maildir.widget + settings() + end + + newtimer(mailpath, timeout, update, true) + return maildir.widget +end + +return setmetatable(maildir, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/mem.lua b/.config/awesome/lain/widgets/mem.lua new file mode 100644 index 0000000..986fa76 --- /dev/null +++ b/.config/awesome/lain/widgets/mem.lua @@ -0,0 +1,61 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") + +local io = { lines = io.lines } +local math = { floor = math.floor } +local string = { format = string.format, + gmatch = string.gmatch, + len = string.len } + +local setmetatable = setmetatable + +-- Memory usage (ignoring caches) +-- lain.widgets.mem +local mem = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 3 + local settings = args.settings or function() end + + mem.widget = wibox.widget.textbox('') + + function update() + mem_now = {} + for line in io.lines("/proc/meminfo") + do + for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+") + do + if k == "MemTotal" then mem_now.total = math.floor(v / 1024) + elseif k == "MemFree" then mem_now.free = math.floor(v / 1024) + elseif k == "Buffers" then mem_now.buf = math.floor(v / 1024) + elseif k == "Cached" then mem_now.cache = math.floor(v / 1024) + elseif k == "SwapTotal" then mem_now.swap = math.floor(v / 1024) + elseif k == "SwapFree" then mem_now.swapf = math.floor(v / 1024) + end + end + end + + mem_now.used = mem_now.total - (mem_now.free + mem_now.buf + mem_now.cache) + mem_now.swapused = mem_now.swap - mem_now.swapf + + widget = mem.widget + settings() + end + + newtimer("mem", timeout, update) + + return mem.widget +end + +return setmetatable(mem, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/mpd.lua b/.config/awesome/lain/widgets/mpd.lua new file mode 100644 index 0000000..600dbac --- /dev/null +++ b/.config/awesome/lain/widgets/mpd.lua @@ -0,0 +1,110 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010, Adrian C. <anrxc@sysphere.org> + +--]] + +local helpers = require("lain.helpers") + +local escape_f = require("awful.util").escape +local naughty = require("naughty") +local wibox = require("wibox") + +local io = { popen = io.popen } +local os = { execute = os.execute, + getenv = os.getenv } +local string = { format = string.format, + gmatch = string.gmatch } + +local setmetatable = setmetatable + +-- MPD infos +-- lain.widgets.mpd +local mpd = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 2 + local password = args.password or "" + local host = args.host or "127.0.0.1" + local port = args.port or "6600" + local music_dir = args.music_dir or os.getenv("HOME") .. "/Music" + local cover_size = args.cover_size or 100 + local default_art = args.default_art or "" + local settings = args.settings or function() end + + local mpdcover = helpers.scripts_dir .. "mpdcover" + local mpdh = "telnet://" .. host .. ":" .. port + local echo = "echo 'password " .. password .. "\nstatus\ncurrentsong\nclose'" + + mpd.widget = wibox.widget.textbox('') + + mpd_notification_preset = { + -- title = "now playing\n░░░░▒▒▒▒▓▓▓▓▓▓████████▓▓▓▓▓▓▒▒▒▒░░░░", + title = "now playing", + timeout = 6 + } + + helpers.set_map("current mpd track", nil) + + function mpd.update() + mpd_now = { + state = "N/A", + file = "N/A", + artist = "N/A", + title = "N/A", + album = "N/A", + date = "N/A" + } + + 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 == "state" then mpd_now.state = v + elseif k == "file" then mpd_now.file = v + elseif k == "Artist" then mpd_now.artist = escape_f(v) + elseif k == "Title" then mpd_now.title = escape_f(v) + elseif k == "Album" then mpd_now.album = escape_f(v) + elseif k == "Date" then mpd_now.date = escape_f(v) + end + end + end + + f:close() + + mpd_notification_preset.text = string.format("%s (%s) - %s\n%s", mpd_now.artist, + mpd_now.album, mpd_now.date, mpd_now.title) + widget = mpd.widget + settings() + + if mpd_now.state == "play" + then + if mpd_now.title ~= helpers.get_map("current mpd track") + then + helpers.set_map("current mpd track", mpd_now.title) + + os.execute(string.format("%s %q %q %d %q", mpdcover, music_dir, + mpd_now.file, cover_size, default_art)) + + mpd.id = naughty.notify({ + preset = mpd_notification_preset, + icon = "/tmp/mpdcover.png", + replaces_id = mpd.id + }).id + end + elseif mpd_now.state ~= "pause" + then + helpers.set_map("current mpd track", nil) + end + end + + helpers.newtimer("mpd", timeout, mpd.update) + + return setmetatable(mpd, { __index = mpd.widget }) +end + +return setmetatable(mpd, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/net.lua b/.config/awesome/lain/widgets/net.lua new file mode 100644 index 0000000..af97201 --- /dev/null +++ b/.config/awesome/lain/widgets/net.lua @@ -0,0 +1,102 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local helpers = require("lain.helpers") + +local notify_fg = require("beautiful").fg_focus +local naughty = require("naughty") +local wibox = require("wibox") + +local io = io +local tostring = tostring +local string = { format = string.format, + gsub = string.gsub } + +local setmetatable = setmetatable + +-- Network infos +-- lain.widgets.net +local net = { + last_t = 0, + last_r = 0 +} + +function net.get_device() + f = io.popen("ip link show | cut -d' ' -f2,9") + ws = f:read("*all") + f:close() + ws = ws:match("%w+: UP") + if ws ~= nil then + return ws:gsub(": UP", "") + else + return "network off" + end +end + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 2 + local iface = args.iface or net.get_device() + local units = args.units or 1024 --kb + local settings = args.settings or function() end + + net.widget = wibox.widget.textbox('') + + helpers.set_map(iface, true) + + function update() + net_now = {} + + if iface == "" then iface = net.get_device() end + + net_now.carrier = helpers.first_line('/sys/class/net/' .. iface .. + '/carrier') or "0" + net_now.state = helpers.first_line('/sys/class/net/' .. iface .. + '/operstate') or "down" + local now_t = helpers.first_line('/sys/class/net/' .. iface .. + '/statistics/tx_bytes') or 0 + local now_r = helpers.first_line('/sys/class/net/' .. iface .. + '/statistics/rx_bytes') or 0 + + net_now.sent = tostring((now_t - net.last_t) / timeout / units) + net_now.sent = string.gsub(string.format('%.1f', net_now.sent), ",", ".") + + net_now.received = tostring((now_r - net.last_r) / timeout / units) + net_now.received = string.gsub(string.format('%.1f', net_now.received), ",", ".") + + widget = net.widget + settings() + + net.last_t = now_t + net.last_r = now_r + + if net_now.carrier ~= "1" + then + if helpers.get_map(iface) + then + naughty.notify({ + title = iface, + text = "no carrier", + timeout = 7, + position = "top_left", + icon = helpers.icons_dir .. "no_net.png", + fg = notify_fg or "#FFFFFF" + }) + helpers.set_map(iface, false) + end + else + helpers.set_map(iface, true) + end + end + + helpers.newtimer(iface, timeout, update) + return net.widget +end + +return setmetatable(net, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/sysload.lua b/.config/awesome/lain/widgets/sysload.lua new file mode 100644 index 0000000..2abac33 --- /dev/null +++ b/.config/awesome/lain/widgets/sysload.lua @@ -0,0 +1,46 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + * (c) 2010-2012, Peter Hofmann + +--]] + +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") + +local io = { open = io.open } +local string = { format = string.format, + match = string.match } + +local setmetatable = setmetatable + +-- System load +-- lain.widgets.sysload +local sysload = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 5 + local settings = args.settings or function() end + + sysload.widget = wibox.widget.textbox('') + + function update() + local f = io.open("/proc/loadavg") + local ret = f:read("*all") + f:close() + + load_1, load_5, load_15 = string.match(ret, "([^%s]+) ([^%s]+) ([^%s]+)") + + widget = sysload.widget + settings() + end + + newtimer("sysload", timeout, update) + return sysload.widget +end + +return setmetatable(sysload, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/temp.lua b/.config/awesome/lain/widgets/temp.lua new file mode 100644 index 0000000..61a9aa5 --- /dev/null +++ b/.config/awesome/lain/widgets/temp.lua @@ -0,0 +1,48 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + +--]] + +local newtimer = require("lain.helpers").newtimer + +local wibox = require("wibox") + +local io = io +local tonumber = tonumber + +local setmetatable = setmetatable + +-- coretemp +-- lain.widgets.temp +local temp = {} + +local function worker(args) + local args = args or {} + local timeout = args.timeout or 5 + local tempfile = args.tempfile or "/sys/class/thermal/thermal_zone0/temp" + local settings = args.settings or function() end + + temp.widget = wibox.widget.textbox('') + + function update() + local f = io.open(tempfile) + if f ~= nil + then + coretemp_now = tonumber(f:read("*all")) / 1000 + f:close() + else + coretemp_now = "N/A" + end + + widget = temp.widget + settings() + end + + newtimer("coretemp", timeout, update) + return temp.widget +end + +return setmetatable(temp, { __call = function(_, ...) return worker(...) end }) diff --git a/.config/awesome/lain/widgets/yawn/icons/BlowingSnow.png b/.config/awesome/lain/widgets/yawn/icons/BlowingSnow.png Binary files differnew file mode 100755 index 0000000..6223f8f --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/BlowingSnow.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Cloudy.png b/.config/awesome/lain/widgets/yawn/icons/Cloudy.png Binary files differnew file mode 100755 index 0000000..bac1e7e --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Cloudy.png diff --git a/.config/awesome/lain/widgets/yawn/icons/DayClear.png b/.config/awesome/lain/widgets/yawn/icons/DayClear.png Binary files differnew file mode 100755 index 0000000..d9e2745 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/DayClear.png diff --git a/.config/awesome/lain/widgets/yawn/icons/DayFair.png b/.config/awesome/lain/widgets/yawn/icons/DayFair.png new file mode 120000 index 0000000..8ee94d1 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/DayFair.png @@ -0,0 +1 @@ +DayClear.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/DayMostlyCloudy.png b/.config/awesome/lain/widgets/yawn/icons/DayMostlyCloudy.png Binary files differnew file mode 100755 index 0000000..22b929c --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/DayMostlyCloudy.png diff --git a/.config/awesome/lain/widgets/yawn/icons/DayPartlyCloudy.png b/.config/awesome/lain/widgets/yawn/icons/DayPartlyCloudy.png Binary files differnew file mode 100755 index 0000000..8fd0a5b --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/DayPartlyCloudy.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Drizzle.png b/.config/awesome/lain/widgets/yawn/icons/Drizzle.png new file mode 120000 index 0000000..df34463 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Drizzle.png @@ -0,0 +1 @@ +Rain.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/Fog.png b/.config/awesome/lain/widgets/yawn/icons/Fog.png new file mode 120000 index 0000000..b615645 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Fog.png @@ -0,0 +1 @@ +Foggy.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/Foggy.png b/.config/awesome/lain/widgets/yawn/icons/Foggy.png Binary files differnew file mode 100755 index 0000000..009039f --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Foggy.png diff --git a/.config/awesome/lain/widgets/yawn/icons/FreezingDrizzle.png b/.config/awesome/lain/widgets/yawn/icons/FreezingDrizzle.png Binary files differnew file mode 100755 index 0000000..6a66140 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/FreezingDrizzle.png diff --git a/.config/awesome/lain/widgets/yawn/icons/FreezingRain.png b/.config/awesome/lain/widgets/yawn/icons/FreezingRain.png Binary files differnew file mode 100755 index 0000000..c924fac --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/FreezingRain.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Hail.png b/.config/awesome/lain/widgets/yawn/icons/Hail.png Binary files differnew file mode 100755 index 0000000..009039f --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Hail.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Haze.png b/.config/awesome/lain/widgets/yawn/icons/Haze.png new file mode 120000 index 0000000..0874a83 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Haze.png @@ -0,0 +1 @@ +Hail.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/HeavyRain.png b/.config/awesome/lain/widgets/yawn/icons/HeavyRain.png new file mode 120000 index 0000000..ace2a94 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/HeavyRain.png @@ -0,0 +1 @@ +Showers.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/HeavySnow.png b/.config/awesome/lain/widgets/yawn/icons/HeavySnow.png Binary files differnew file mode 100755 index 0000000..ddcb8f3 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/HeavySnow.png diff --git a/.config/awesome/lain/widgets/yawn/icons/LightRain.png b/.config/awesome/lain/widgets/yawn/icons/LightRain.png new file mode 120000 index 0000000..df34463 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/LightRain.png @@ -0,0 +1 @@ +Rain.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/LightSnow.png b/.config/awesome/lain/widgets/yawn/icons/LightSnow.png new file mode 120000 index 0000000..aa8b28e --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/LightSnow.png @@ -0,0 +1 @@ +LightSnowShowers.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/LightSnowShowers.png b/.config/awesome/lain/widgets/yawn/icons/LightSnowShowers.png Binary files differnew file mode 100755 index 0000000..d797ee9 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/LightSnowShowers.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Mist.png b/.config/awesome/lain/widgets/yawn/icons/Mist.png new file mode 120000 index 0000000..b615645 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Mist.png @@ -0,0 +1 @@ +Foggy.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/MixedRainAndHail.png b/.config/awesome/lain/widgets/yawn/icons/MixedRainAndHail.png Binary files differnew file mode 100755 index 0000000..758b01e --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/MixedRainAndHail.png diff --git a/.config/awesome/lain/widgets/yawn/icons/MixedRainAndSleet.png b/.config/awesome/lain/widgets/yawn/icons/MixedRainAndSleet.png Binary files differnew file mode 100755 index 0000000..7f0d252 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/MixedRainAndSleet.png diff --git a/.config/awesome/lain/widgets/yawn/icons/MixedRainAndSnow.png b/.config/awesome/lain/widgets/yawn/icons/MixedRainAndSnow.png Binary files differnew file mode 100755 index 0000000..0a07b7b --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/MixedRainAndSnow.png diff --git a/.config/awesome/lain/widgets/yawn/icons/NightClear.png b/.config/awesome/lain/widgets/yawn/icons/NightClear.png Binary files differnew file mode 100755 index 0000000..84ea140 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/NightClear.png diff --git a/.config/awesome/lain/widgets/yawn/icons/NightFair.png b/.config/awesome/lain/widgets/yawn/icons/NightFair.png new file mode 120000 index 0000000..23df45a --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/NightFair.png @@ -0,0 +1 @@ +NightClear.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/NightMostlyCloudy.png b/.config/awesome/lain/widgets/yawn/icons/NightMostlyCloudy.png Binary files differnew file mode 100755 index 0000000..d8b3673 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/NightMostlyCloudy.png diff --git a/.config/awesome/lain/widgets/yawn/icons/NightPartlyCloudy.png b/.config/awesome/lain/widgets/yawn/icons/NightPartlyCloudy.png Binary files differnew file mode 100755 index 0000000..9e4404d --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/NightPartlyCloudy.png diff --git a/.config/awesome/lain/widgets/yawn/icons/README.md b/.config/awesome/lain/widgets/yawn/icons/README.md new file mode 100644 index 0000000..e4dc111 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/README.md @@ -0,0 +1,6 @@ +Yawn icons +========== + +These are [Plain Weather Icons](http://merlinthered.deviantart.com/art/plain-weather-icons-157162192), created by [MerlinTheRed](http://merlinthered.deviantart.com/). + +<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/"><img src="http://i.creativecommons.org/l/by-nc-sa/2.5/80x15.png" align="right"></a> diff --git a/.config/awesome/lain/widgets/yawn/icons/Rain.png b/.config/awesome/lain/widgets/yawn/icons/Rain.png Binary files differnew file mode 100755 index 0000000..d00552a --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Rain.png diff --git a/.config/awesome/lain/widgets/yawn/icons/RainThunder.png b/.config/awesome/lain/widgets/yawn/icons/RainThunder.png Binary files differnew file mode 100755 index 0000000..d30e120 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/RainThunder.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Showers.png b/.config/awesome/lain/widgets/yawn/icons/Showers.png Binary files differnew file mode 100755 index 0000000..3cc6665 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Showers.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Sleet.png b/.config/awesome/lain/widgets/yawn/icons/Sleet.png new file mode 120000 index 0000000..f8f9693 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Sleet.png @@ -0,0 +1 @@ +SnowShowers.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/Snow.png b/.config/awesome/lain/widgets/yawn/icons/Snow.png new file mode 120000 index 0000000..f8f9693 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Snow.png @@ -0,0 +1 @@ +SnowShowers.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/SnowFlurries.png b/.config/awesome/lain/widgets/yawn/icons/SnowFlurries.png new file mode 120000 index 0000000..2e090cd --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/SnowFlurries.png @@ -0,0 +1 @@ +BlowingSnow.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/SnowShowers.png b/.config/awesome/lain/widgets/yawn/icons/SnowShowers.png Binary files differnew file mode 100755 index 0000000..30534a2 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/SnowShowers.png diff --git a/.config/awesome/lain/widgets/yawn/icons/Sunny.png b/.config/awesome/lain/widgets/yawn/icons/Sunny.png Binary files differnew file mode 100755 index 0000000..cf08c5c --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Sunny.png diff --git a/.config/awesome/lain/widgets/yawn/icons/ThunderintheVicinity.png b/.config/awesome/lain/widgets/yawn/icons/ThunderintheVicinity.png new file mode 120000 index 0000000..1fb3b9c --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/ThunderintheVicinity.png @@ -0,0 +1 @@ +Cloudy.png
\ No newline at end of file diff --git a/.config/awesome/lain/widgets/yawn/icons/Wind.png b/.config/awesome/lain/widgets/yawn/icons/Wind.png Binary files differnew file mode 100755 index 0000000..5dc1356 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/Wind.png diff --git a/.config/awesome/lain/widgets/yawn/icons/na.png b/.config/awesome/lain/widgets/yawn/icons/na.png Binary files differnew file mode 100755 index 0000000..62a5350 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/icons/na.png diff --git a/.config/awesome/lain/widgets/yawn/init.lua b/.config/awesome/lain/widgets/yawn/init.lua new file mode 100644 index 0000000..3f08cd5 --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/init.lua @@ -0,0 +1,200 @@ + +--[[ + + Licensed under GNU General Public License v2 + * (c) 2013, Luke Bonham + +--]] + +local newtimer = require("lain.helpers").newtimer + +local naughty = require("naughty") +local wibox = require("wibox") + +local debug = { getinfo = debug.getinfo } +local io = io +local os = { date = os.date, + getenv = os.getenv } +local string = { find = string.find, + match = string.match, + gsub = string.gsub, + sub = string.sub } +local tonumber = tonumber + +local setmetatable = setmetatable + +-- YAhoo! Weather Notification +-- lain.widgets.yawn +local yawn = +{ + icon = wibox.widget.imagebox(), + widget = wibox.widget.textbox('') +} + +local project_path = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]] +local localizations_path = project_path .. 'localizations/' +local icon_path = project_path .. 'icons/' +local api_url = 'http://weather.yahooapis.com/forecastrss' +local units_set = '?u=c&w=' -- Default is Celsius +local language = string.match(os.getenv("LANG"), "(%S*$*)[.]") +local weather_data = nil +local notification = nil +local city_id = nil +local sky = nil +local settings = function() end + +yawn_notification_preset = {} + +local function fetch_weather() + local url = api_url .. units_set .. city_id + local f = io.popen("curl --connect-timeout 1 -fsm 3 '" .. url .. "'" ) + local text = f:read("*all") + f:close() + + -- In case of no connection or invalid city ID + -- widgets won't display + if text == "" or text:match("City not found") + then + yawn.icon:set_image(icon_path .. "na.png") + if text == "" then + weather_data = "Service not available at the moment." + yawn.widget:set_text(" N/A ") + else + weather_data = "City not found!\n" .. + "Are you sure " .. city_id .. + " is your Yahoo city ID?" + yawn.widget:set_text(" ? ") + end + return + end + + -- Processing raw data + weather_data = text:gsub("<.->", "") + weather_data = weather_data:match("Current Conditions:.-Full") or "" + + -- may still happens in case of bad connectivity + if weather_data == "" then + yawn.icon:set_image(icon_path .. "na.png") + yawn.widget:set_text(" ? ") + return + end + + weather_data = weather_data:gsub("Current Conditions:.-\n", "Now: ") + weather_data = weather_data:gsub("Forecast:.-\n", "") + weather_data = weather_data:gsub("\nFull", "") + weather_data = weather_data:gsub("[\n]$", "") + weather_data = weather_data:gsub(" [-] " , ": ") + weather_data = weather_data:gsub("[.]", ",") + weather_data = weather_data:gsub("High: ", "") + weather_data = weather_data:gsub(" Low: ", " - ") + + -- Getting info for text widget + local now = weather_data:sub(weather_data:find("Now:")+5, + weather_data:find("\n")-1) + forecast = now:sub(1, now:find(",")-1) + units = now:sub(now:find(",")+2, -2) + + -- Day/Night icon change + local hour = tonumber(os.date("%H")) + sky = icon_path + + if forecast == "Clear" or + forecast == "Fair" or + forecast == "Partly Cloudy" or + forecast == "Mostly Cloudy" + then + if hour >= 6 and hour <= 18 + then + sky = sky .. "Day" + else + sky = sky .. "Night" + end + end + + sky = sky .. forecast:gsub(" ", ""):gsub("/", "") .. ".png" + + -- In case there's no defined icon for current forecast + if io.open(sky) == nil then + sky = icon_path .. "na.png" + end + + -- Localization + local f = io.open(localizations_path .. language, "r") + if language:find("en_") == nil and f ~= nil + then + f:close() + for line in io.lines(localizations_path .. language) + do + word = string.sub(line, 1, line:find("|")-1) + translation = string.sub(line, line:find("|")+1) + weather_data = string.gsub(weather_data, word, translation) + end + end + + -- Finally setting infos + yawn.icon:set_image(sky) + widget = yawn.widget + + forecast = weather_data:match(": %S.-,"):gsub(": ", ""):gsub(",", "") + units = units:gsub(" ", "") + + settings() +end + +function yawn.hide() + if notification ~= nil then + naughty.destroy(notification) + notification = nil + end +end + +function yawn.show(t_out) + if yawn.widget._layout.text:match("?") + then + fetch_weather(settings) + end + + yawn.hide() + + notification = naughty.notify({ + preset = yawn_notification_preset, + text = weather_data, + icon = sky, + timeout = t_out + }) +end + +function yawn.register(id, args) + local args = args or {} + local timeout = args.timeout or 600 + settings = args.settings or function() end + + if args.u == "f" then units_set = '?u=f&w=' end + + city_id = id + + newtimer("yawn", timeout, fetch_weather) + + yawn.icon:connect_signal("mouse::enter", function() + yawn.show(0) + end) + yawn.icon:connect_signal("mouse::leave", function() + yawn.hide() + end) + + return yawn +end + +function yawn.attach(widget, id, args) + yawn.register(id, args) + + widget:connect_signal("mouse::enter", function() + yawn.show(0) + end) + + widget:connect_signal("mouse::leave", function() + yawn.hide() + end) +end + +return setmetatable(yawn, { __call = function(_, ...) return yawn.register(...) end }) diff --git a/.config/awesome/lain/widgets/yawn/localizations/it_IT b/.config/awesome/lain/widgets/yawn/localizations/it_IT new file mode 100644 index 0000000..70b0eef --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/localizations/it_IT @@ -0,0 +1,60 @@ +Now:|Ora: +Sun:|Dom: +Mon:|Lun: +Tue:|Mar: +Wed:|Mer: +Thu:|Gio: +Fri:|Ven: +Sat:|Sab: +Mostly Sunny|Abbastanza Soleggiato +Sunny|Soleggiato +Sun|Soleggiato +Rain/Thunder|Temporali +Isolated Thunderstorms|Temporali Isolati +Scattered Thunderstorms|Temporali Sparsi +Thundershowers|Rovesci Temporaleschi +Thunderstorms|Temporali +Thunder in the Vicinity|Tuoni in prossimità +Thunder|Temporale +AM|In Mattinata +PM|Nel Pomeriggio +Early|In Mattinata +Late|In Serata +Few|Sporadiche +Severe|Forti +Clear|Sereno +Fair|Sereno +Partly|Parzialmente +Mostly|Molto +Cloudy|Nuvoloso +Clouds|Nuvoloso +Scattered Showers|Temporali Sparsi +Light Snow Showers|Nevicate Leggere +Snow Showers|Nevicate +aeavy Snow|Forti Nevicate +Scattered Snow Showers|Nevicate Sparse +Mixed Rain And Snow|Pioggia E Neve +Mixed Rain And Sleet|Pioggia E Nevischio +Mixed Snow And Sleet|Neve E Nevischio +Mixed Rain And Hail|Pioggia E Grandine +Snow Flurries|Folate Di Neve +Blowing Snow|Neve Battente +Blowing Rain|Pioggia Battente +Heavy Rain|Forti Piogge +Freezing Rain|Pioggia Congelantesi +Showers|Piogge +Light Rain|Pioggia Leggera +Heavy|Forti +Rain|Piovoso +Windy|Ventoso +Wind|Ventoso +Snow|Neve +Sleet|Nevischio +Light Drizzle|Pioggia Leggera +Drizzle|Pioggia Leggera +Freezing Drizzle|Pioggerella Congelantesi +Hail|Grandine +Fog|Nebbia +Foggy|Nebbioso +Haze|Nebbia +Light|Leggere diff --git a/.config/awesome/lain/widgets/yawn/localizations/localization_template b/.config/awesome/lain/widgets/yawn/localizations/localization_template new file mode 100644 index 0000000..453807e --- /dev/null +++ b/.config/awesome/lain/widgets/yawn/localizations/localization_template @@ -0,0 +1,60 @@ +Now:| +Sun:| +Mon:| +Tue:| +Wed:| +Thu:| +Fri:| +Sat:| +Mostly Sunny| +Sunny| +Sun| +Rain/Thunder| +Isolated Thunderstorms| +Scattered Thunderstorms| +Thundershowers| +Thunderstorms| +Thunder in the Vicinity| +Thunder| +AM| +PM| +Early| +Late| +Few| +Severe| +Clear| +Fair| +Partly| +Mostly| +Cloudy| +Clouds| +Scattered Showers| +Light Snow Showers| +Snow Showers| +Heavy Snow| +Scattered Snow Showers| +Mixed Rain And Snow| +Mixed Rain And Sleet| +Mixed Snow And Sleet| +Mixed Rain And Hail| +Snow Flurries| +Blowing Snow| +Blowing Rain| +Heavy Rain| +Freezing Rain| +Showers| +Light Rain| +Heavy| +Rain| +Windy| +Wind| +Snow| +Sleet| +Freezing Drizzle| +Light Drizzle| +Drizzle| +Hail| +Fog| +Foggy| +Haze| +Light| |