.. _GNU-GPL2: http://www.gnu.org/licenses/gpl-2.0.html
.. _awesome-vain: https://github.com/vain/awesome-vain
-.. _Awesome: http://awesome.naquadah.org/
+.. _Awesome: https://github.com/awesomeWM/awesome
.. _wiki: https://github.com/copycat-killer/lain/wiki
--- /dev/null
+
+--[[
+
+ Licensed under GNU General Public License v2
+ * (c) 2016, Luke Bonham
+
+--]]
+
+local awful = require("awful")
+local capi = { client = client,
+ mouse = mouse,
+ screen = screen,
+ timer = timer }
+local string = string
+
+local pairs = pairs
+local setmetatable = setmetatable
+local tostring = tostring
+
+-- Quake-like Dropdown application spawn
+-- Original version: https://awesomewm.org/wiki/Drop-down_terminal#Another_solution
+local quake = {}
+
+-- If you have a rule like "awful.client.setslave" for your terminals,
+-- ensure you use an exception for QuakeDD. Otherwise, you may
+-- run into problems with focus.
+
+function quake:display()
+ -- First, we locate the client
+ local client = nil
+ local i = 0
+ for c in awful.client.iterate(function (c)
+ -- c.name may be changed!
+ return c.instance == self.name
+ end, nil, self.screen)
+ do
+ i = i + 1
+ if i == 1 then
+ client = c
+ else
+ -- Additional matching clients, let's remove the sticky bit
+ -- which may persist between awesome restarts. We don't close
+ -- them as they may be valuable. They will just turn into
+ -- normal clients.
+ c.sticky = false
+ c.ontop = false
+ c.above = false
+ end
+ end
+
+ if not client and not self.visible then return end
+
+ if not client then
+ -- The client does not exist, we spawn it
+ awful.util.spawn(self.app .. " " .. string.format(self.argname, self.name),
+ false, self.screen)
+ return
+ end
+
+ -- Resize
+ awful.client.floating.set(client, true)
+ client.border_width = 0
+ client.size_hints_honor = false
+ client:geometry(self.geometry)
+
+ -- Not sticky and on top
+ client.ontop = true
+ client.above = true
+ client.skip_taskbar = true
+ client.sticky = false
+
+ -- Toggle display
+ if self.visible then
+ client.hidden = false
+ client:raise()
+ self.last_tag = tostring(awful.tag.selected(self.screen))
+ client:tags({awful.tag.selected(self.screen)})
+ capi.client.focus = client
+ else
+ client.hidden = true
+ local ctags = client:tags()
+ for i, t in pairs(ctags) do
+ ctags[i] = nil
+ end
+ client:tags(ctags)
+ end
+
+ return client
+end
+
+function quake:new(config)
+ local conf = config or {}
+
+ conf.app = conf.app or "xterm" -- application to spawn
+ conf.name = conf.name or "QuakeDD" -- window name
+ conf.argname = conf.argname or "-name %s" -- how to specify window name
+ conf.visible = conf.visible or false -- initially not visible
+ conf.screen = conf.screen or capi.mouse.screen
+
+ -- If width or height <= 1 this is a proportion of the workspace
+ wibox_height = conf.wibox_height or 18 -- statusbar weight
+ height = conf.height or 0.25 -- height
+ width = conf.width or 1 -- width
+ vert = conf.vert or "top" -- top, bottom or center
+ horiz = conf.horiz or "center" -- left, right or center
+
+ -- Compute size
+ local geom = capi.screen[conf.screen].workarea
+ if width <= 1 then width = geom.width * width end
+ if height <= 1 then height = geom.height * height end
+ local x, y
+ if horiz == "left" then x = geom.x
+ elseif horiz == "right" then x = geom.width + geom.x - width
+ else x = geom.x + (geom.width - width)/2 end
+ if vert == "top" then y = geom.y
+ elseif vert == "bottom" then y = geom.height + geom.y - height
+ else y = geom.y + (geom.height - height)/2 end
+ conf.geometry = { x = x, y = y + wibox_height, width = width, height = height }
+
+ local console = setmetatable(conf, { __index = quake })
+ capi.client.connect_signal("manage", function(c)
+ if c.instance == console.name and c.screen == console.screen then
+ console:display()
+ end
+ end)
+ capi.client.connect_signal("unmanage", function(c)
+ if c.instance == console.name and c.screen == console.screen then
+ console.visible = false
+ end
+ end)
+
+ -- "Reattach" currently running quake application. This is in case awesome is restarted.
+ local reattach = capi.timer { timeout = 0 }
+ reattach:connect_signal("timeout", function()
+ reattach:stop()
+ console:display()
+ end)
+ reattach:start()
+
+ return console
+end
+
+function quake:toggle()
+ current_tag = awful.tag.selected(self.screen)
+ if self.last_tag ~= tostring(current_tag) and self.visible then
+ awful.client.movetotag(current_tag, self:display())
+ else
+ self.visible = not self.visible
+ self:display()
+ end
+end
+
+setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })
+
+return quake
local naughty = require("naughty")
local wibox = require("wibox")
-local math = { floor = math.floor, min = math.min }
+local math = { abs = math.abs,
+ floor = math.floor,
+ log10 = math.log10,
+ min = math.min }
local string = { format = string.format }
-local tonumber = tonumber
+local type = type
+local tonumber = tonumber
local setmetatable = setmetatable
-- Battery infos
end
function update()
- local sum_rate_current = 0
- local sum_rate_voltage = 0
- local sum_rate_power = 0
- local sum_energy_now = 0
- local sum_energy_full = 0
+ local sum_rate_current = 0
+ local sum_rate_voltage = 0
+ local sum_rate_power = 0
+ local sum_rate_energy = 0
+ local sum_energy_now = 0
+ local sum_energy_full = 0
local sum_energy_percentage = 0
+ local pspath = "/sys/class/power_supply/"
for i, battery in ipairs(batteries) do
- local bstr = "/sys/class/power_supply/" .. battery
+ local bstr = pspath .. battery
local present = first_line(bstr .. "/present")
- if tonumber(present) == 1
- then
+ if tonumber(present) == 1 then
-- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
local rate_current = tonumber(first_line(bstr .. "/current_now"))
local rate_voltage = tonumber(first_line(bstr .. "/voltage_now"))
local rate_power = tonumber(first_line(bstr .. "/power_now"))
-
-- energy_now(P)[uWh], charge_now(I)[uAh]
local energy_now = tonumber(first_line(bstr .. "/energy_now") or
first_line(bstr .. "/charge_now"))
bat_now.n_status[i] = first_line(bstr .. "/status") or "N/A"
sum_rate_current = sum_rate_current + (rate_current or 0)
- sum_rate_voltage = sum_rate_voltage + rate_voltage
- sum_rate_power = sum_rate_power + (rate_power or ((rate_voltage * rate_current) / 1e6))
+ sum_rate_voltage = sum_rate_voltage + (rate_voltage or 0)
+ sum_rate_power = sum_rate_power + (rate_power or 0)
+ sum_rate_energy = sum_rate_energy + (rate_power or (((rate_voltage or 0) * (rate_current or 0)) / 1e6))
sum_energy_now = sum_energy_now + (energy_now or 0)
- sum_energy_full = sum_energy_full + energy_full
- sum_energy_percentage = sum_energy_percentage + energy_percentage
+ sum_energy_full = sum_energy_full + (energy_full or 0)
+ sum_energy_percentage = sum_energy_percentage + (energy_percentage or 0)
end
end
bat_now.status = bat_now.n_status[1]
- bat_now.ac_status = tonumber(first_line(string.format("/sys/class/power_supply/%s/online", ac))) or "N/A"
+ bat_now.ac_status = tonumber(first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
if bat_now.status ~= "N/A" then
-- update {perc,time,watt} iff battery not full and rate > 0
- if bat_now.status ~= "Full" and (sum_rate_current > 0 or sum_rate_power > 0) then
+ if bat_now.status ~= "Full" and (sum_rate_power > 0 or sum_rate_current > 0) then
local rate_time = 0
+ local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
if bat_now.status == "Charging" then
- rate_time = (sum_energy_full - sum_energy_now) / (sum_rate_power or sum_rate_current)
- elseif bat_now.status == "Discharging" then
- rate_time = sum_energy_now / (sum_rate_power or sum_rate_current)
+ rate_time = (sum_energy_full - sum_energy_now) / div
+ else -- Discharging
+ rate_time = sum_energy_now / div
+ end
+
+ if rate_time < 0.01 then -- check for magnitude discrepancies (#199)
+ rate_time_magnitude = math.abs(math.floor(math.log10(rate_time)))
+ rate_time = rate_time * 10^(rate_time_magnitude - 2)
end
- local hours = math.floor(rate_time)
- local minutes = math.floor((rate_time - hours) * 60)
- bat_now.perc = tonumber(string.format("%d", math.min(100, sum_energy_percentage / #batteries)))
- bat_now.time = string.format("%02d:%02d", hours, minutes)
- bat_now.watt = tonumber(string.format("%.2f", sum_rate_power / 1e6))
+ local hours = math.floor(rate_time)
+ local minutes = math.floor((rate_time - hours) * 60)
+ bat_now.perc = tonumber(string.format("%d", math.floor(math.min(100, sum_energy_percentage / #batteries))))
+ bat_now.time = string.format("%02d:%02d", hours, minutes)
+ bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6))
elseif bat_now.status == "Full" then
- bat_now.perc = 100
- bat_now.time = "00:00"
- bat_now.watt = 0
+ bat_now.perc = 100
+ bat_now.time = "00:00"
+ bat_now.watt = 0
end
end
settings()
-- notifications for low and critical states
- if notify == "on" and bat_now.perc and bat_now.status == "Discharging" then
+ if notify == "on" and type(bat_now.perc) == "number" and bat_now.status == "Discharging" then
if bat_now.perc <= 5 then
bat.id = naughty.notify({
preset = bat_notification_critical_preset,
+++ /dev/null
-
---[[
-
- Licensed under GNU General Public License v2
- * (c) 2014, Aaron Lebo
-
---]]
-
-local newtimer = require("lain.helpers").newtimer
-local json = require("lain.util").dkjson
-
-local wibox = require("wibox")
-
-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 })
--- /dev/null
+
+--[[
+
+ Licensed under GNU General Public License v2
+ * (c) 2016, Alexandre Terrien
+
+--]]
+
+local helpers = require("lain.helpers")
+local json = require("lain.util.dkjson")
+local pread = require("awful.util").pread
+local naughty = require("naughty")
+local wibox = require("wibox")
+local mouse = mouse
+local os = { getenv = os.getenv }
+
+local setmetatable = setmetatable
+
+-- Google Play Music Desktop infos
+-- lain.widget.contrib.gpmdp
+local gpmdp = {}
+
+local function worker(args)
+ local args = args or {}
+ local timeout = args.timeout or 2
+ local notify = args.notify or "off"
+ local followmouse = args.followmouse or false
+ local file_location = args.file_location or
+ os.getenv("HOME") .. "/.config/Google Play Music Desktop Player/json_store/playback.json"
+ local settings = args.settings or function() end
+
+ gpmdp.widget = wibox.widget.textbox('')
+
+ gpmdp_notification_preset = {
+ title = "Now playing",
+ timeout = 6
+ }
+
+ helpers.set_map("gpmdp_current", nil)
+
+ function gpmdp.update()
+ file, err = io.open(file_location, "r")
+ if not file
+ then
+ gpm_now = { running = false, playing = false }
+ else
+ dict, pos, err = json.decode(file:read "*a", 1, nil)
+ file:close()
+ gpm_now = {}
+ gpm_now.artist = dict.song.artist
+ gpm_now.album = dict.song.album
+ gpm_now.title = dict.song.title
+ gpm_now.cover_url = dict.song.albumArt
+ gpm_now.playing = dict.playing
+ end
+
+ if (pread("pidof 'Google Play Music Desktop Player'") ~= '') then
+ gpm_now.running = true
+ else
+ gpm_now.running = false
+ end
+
+ gpmdp_notification_preset.text = string.format("%s (%s) - %s", gpm_now.artist, gpm_now.album, gpm_now.title)
+ widget = gpmdp.widget
+ settings()
+
+ if gpm_now.playing
+ then
+ if notify == "on" and gpm_now.title ~= helpers.get_map("gpmdp_current")
+ then
+ helpers.set_map("gpmdp_current", gpm_now.title)
+ os.execute("curl " .. gpm_now.cover_url .. " -o /tmp/gpmcover.png")
+
+ if followmouse then
+ gpmdp_notification_preset.screen = mouse.screen
+ end
+
+ gpmdp.id = naughty.notify({
+ preset = gpmdp_notification_preset,
+ icon = "/tmp/gpmcover.png",
+ replaces_id = gpmdp.id,
+ }).id
+ end
+ elseif not gpm_now.running
+ then
+ helpers.set_map("gpmdp_current", nil)
+ end
+ end
+
+ helpers.newtimer("gpmdp", timeout, gpmdp.update)
+
+ return setmetatable(gpmdp, { __index = gpmdp.widget })
+end
+
+return setmetatable(gpmdp, { __call = function(_, ...) return worker(...) end })
fs_now.size_mb = tonumber(fs_info[partition .. " size_mb"]) or 0
fs_now.size_gb = tonumber(fs_info[partition .. " size_gb"]) or 0
+ notification_preset = fs.notification_preset
widget = fs.widget
settings()
net_now.sent = string.gsub(string.format('%.1f', net_now.sent), ',', '.')
net_now.received = string.gsub(string.format('%.1f', net_now.received), ',', '.')
- widget = net.widget
- settings()
-
net.last_t = total_t
net.last_r = total_r
end
+
+ widget = net.widget
+ settings()
end
helpers.newtimer(iface, timeout, update)
-Subproject commit eaa4aaac7fb0123a4dba05ac2ee63a5fa1247525
+Subproject commit 52da2ca514814006be9762fa3ba4f225d555aad4