Broke everything up into smaller files
This commit is contained in:
		
							
								
								
									
										57
									
								
								awesome/lib/lain/widget/alsa.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								awesome/lib/lain/widget/alsa.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
      * (c) 2010, Adrian C. <anrxc@sysphere.org>
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local shell = require('awful.util').shell
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local string = string
 | 
			
		||||
 | 
			
		||||
-- ALSA volume
 | 
			
		||||
-- lain.widget.alsa
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
	local alsa = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 5
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	alsa.cmd = args.cmd or 'amixer'
 | 
			
		||||
	alsa.channel = args.channel or 'Master'
 | 
			
		||||
	alsa.togglechannel = args.togglechannel
 | 
			
		||||
 | 
			
		||||
	local format_cmd = string.format('%s get %s', alsa.cmd, alsa.channel)
 | 
			
		||||
 | 
			
		||||
	if alsa.togglechannel then
 | 
			
		||||
		format_cmd = {
 | 
			
		||||
			shell,
 | 
			
		||||
			'-c',
 | 
			
		||||
			string.format('%s get %s; %s get %s', alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel),
 | 
			
		||||
		}
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	alsa.last = {}
 | 
			
		||||
 | 
			
		||||
	function alsa.update()
 | 
			
		||||
		helpers.async(format_cmd, function(mixer)
 | 
			
		||||
			local l, s = string.match(mixer, '([%d]+)%%.*%[([%l]*)')
 | 
			
		||||
			l = tonumber(l)
 | 
			
		||||
			if alsa.last.level ~= l or alsa.last.status ~= s then
 | 
			
		||||
				volume_now = { level = l, status = s }
 | 
			
		||||
				widget = alsa.widget
 | 
			
		||||
				settings()
 | 
			
		||||
				alsa.last = volume_now
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer(string.format('alsa-%s-%s', alsa.cmd, alsa.channel), timeout, alsa.update)
 | 
			
		||||
 | 
			
		||||
	return alsa
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										172
									
								
								awesome/lib/lain/widget/alsabar.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								awesome/lib/lain/widget/alsabar.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
      * (c) 2013, Rman
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local awful = require('awful')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local math = math
 | 
			
		||||
local string = string
 | 
			
		||||
local type = type
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
 | 
			
		||||
-- ALSA volume bar
 | 
			
		||||
-- lain.widget.alsabar
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	local alsabar = {
 | 
			
		||||
		colors = {
 | 
			
		||||
			background = '#000000',
 | 
			
		||||
			mute = '#EB8F8F',
 | 
			
		||||
			unmute = '#A4CE8A',
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_current_level = 0,
 | 
			
		||||
		_playback = 'off',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local timeout = args.timeout or 5
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
	local width = args.width or 63
 | 
			
		||||
	local height = args.height or 1
 | 
			
		||||
	local margins = args.margins or 1
 | 
			
		||||
	local ticks = args.ticks or false
 | 
			
		||||
	local ticks_size = args.ticks_size or 7
 | 
			
		||||
	local tick = args.tick or '|'
 | 
			
		||||
	local tick_pre = args.tick_pre or '['
 | 
			
		||||
	local tick_post = args.tick_post or ']'
 | 
			
		||||
	local tick_none = args.tick_none or ' '
 | 
			
		||||
 | 
			
		||||
	alsabar.cmd = args.cmd or 'amixer'
 | 
			
		||||
	alsabar.channel = args.channel or 'Master'
 | 
			
		||||
	alsabar.togglechannel = args.togglechannel
 | 
			
		||||
	alsabar.colors = args.colors or alsabar.colors
 | 
			
		||||
	alsabar.followtag = args.followtag or false
 | 
			
		||||
	alsabar.notification_preset = args.notification_preset
 | 
			
		||||
 | 
			
		||||
	if not alsabar.notification_preset then
 | 
			
		||||
		alsabar.notification_preset = { font = 'Monospace 10' }
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local format_cmd = string.format('%s get %s', alsabar.cmd, alsabar.channel)
 | 
			
		||||
 | 
			
		||||
	if alsabar.togglechannel then
 | 
			
		||||
		format_cmd = {
 | 
			
		||||
			awful.util.shell,
 | 
			
		||||
			'-c',
 | 
			
		||||
			string.format('%s get %s; %s get %s', alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel),
 | 
			
		||||
		}
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	alsabar.bar = wibox.widget({
 | 
			
		||||
		color = alsabar.colors.unmute,
 | 
			
		||||
		background_color = alsabar.colors.background,
 | 
			
		||||
		forced_height = height,
 | 
			
		||||
		forced_width = width,
 | 
			
		||||
		margins = margins,
 | 
			
		||||
		paddings = margins,
 | 
			
		||||
		ticks = ticks,
 | 
			
		||||
		ticks_size = ticks_size,
 | 
			
		||||
		widget = wibox.widget.progressbar,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
 | 
			
		||||
 | 
			
		||||
	function alsabar.update(callback)
 | 
			
		||||
		helpers.async(format_cmd, function(mixer)
 | 
			
		||||
			local vol, playback = string.match(mixer, '([%d]+)%%.*%[([%l]*)')
 | 
			
		||||
 | 
			
		||||
			if not vol or not playback then
 | 
			
		||||
				return
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			if vol ~= alsabar._current_level or playback ~= alsabar._playback then
 | 
			
		||||
				alsabar._current_level = tonumber(vol)
 | 
			
		||||
				alsabar.bar:set_value(alsabar._current_level / 100)
 | 
			
		||||
				if alsabar._current_level == 0 or playback == 'off' then
 | 
			
		||||
					alsabar._playback = playback
 | 
			
		||||
					alsabar.tooltip:set_text('[Muted]')
 | 
			
		||||
					alsabar.bar.color = alsabar.colors.mute
 | 
			
		||||
				else
 | 
			
		||||
					alsabar._playback = 'on'
 | 
			
		||||
					alsabar.tooltip:set_text(string.format('%s: %s', alsabar.channel, vol))
 | 
			
		||||
					alsabar.bar.color = alsabar.colors.unmute
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				volume_now = {
 | 
			
		||||
					level = alsabar._current_level,
 | 
			
		||||
					status = alsabar._playback,
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				settings()
 | 
			
		||||
 | 
			
		||||
				if type(callback) == 'function' then
 | 
			
		||||
					callback()
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function alsabar.notify()
 | 
			
		||||
		alsabar.update(function()
 | 
			
		||||
			local preset = alsabar.notification_preset
 | 
			
		||||
 | 
			
		||||
			preset.title = string.format('%s - %s%%', alsabar.channel, alsabar._current_level)
 | 
			
		||||
 | 
			
		||||
			if alsabar._playback == 'off' then
 | 
			
		||||
				preset.title = preset.title .. ' Muted'
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			-- tot is the maximum number of ticks to display in the notification
 | 
			
		||||
			local tot = alsabar.notification_preset.max_ticks
 | 
			
		||||
 | 
			
		||||
			if not tot then
 | 
			
		||||
				local wib = awful.screen.focused().mywibox
 | 
			
		||||
				-- if we can grab mywibox, tot is defined as its height if
 | 
			
		||||
				-- horizontal, or width otherwise
 | 
			
		||||
				if wib then
 | 
			
		||||
					if wib.position == 'left' or wib.position == 'right' then
 | 
			
		||||
						tot = wib.width
 | 
			
		||||
					else
 | 
			
		||||
						tot = wib.height
 | 
			
		||||
					end
 | 
			
		||||
				-- fallback: default horizontal wibox height
 | 
			
		||||
				else
 | 
			
		||||
					tot = 20
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			local int = math.modf((alsabar._current_level / 100) * tot)
 | 
			
		||||
			preset.text =
 | 
			
		||||
				string.format('%s%s%s%s', tick_pre, string.rep(tick, int), string.rep(tick_none, tot - int), tick_post)
 | 
			
		||||
 | 
			
		||||
			if alsabar.followtag then
 | 
			
		||||
				preset.screen = awful.screen.focused()
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			if not alsabar.notification then
 | 
			
		||||
				alsabar.notification = naughty.notify({
 | 
			
		||||
					preset = preset,
 | 
			
		||||
					destroy = function()
 | 
			
		||||
						alsabar.notification = nil
 | 
			
		||||
					end,
 | 
			
		||||
				})
 | 
			
		||||
			else
 | 
			
		||||
				naughty.replace_text(alsabar.notification, preset.title, preset.text)
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer(string.format('alsabar-%s-%s', alsabar.cmd, alsabar.channel), timeout, alsabar.update)
 | 
			
		||||
 | 
			
		||||
	return alsabar
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										237
									
								
								awesome/lib/lain/widget/bat.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								awesome/lib/lain/widget/bat.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,237 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
	 Licensed under GNU General Public License v2
 | 
			
		||||
	  * (c) 2013,      Luca CPZ
 | 
			
		||||
	  * (c) 2010-2012, Peter Hofmann
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local fs = require('gears.filesystem')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local math = math
 | 
			
		||||
local string = string
 | 
			
		||||
local ipairs = ipairs
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
 | 
			
		||||
-- Battery infos
 | 
			
		||||
-- lain.widget.bat
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	local pspath = args.pspath or '/sys/class/power_supply/'
 | 
			
		||||
 | 
			
		||||
	if not fs.is_dir(pspath) then
 | 
			
		||||
		naughty.notify({ text = 'lain.widget.bat: invalid power supply path', timeout = 0 })
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local bat = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 30
 | 
			
		||||
	local notify = args.notify or 'on'
 | 
			
		||||
	local full_notify = args.full_notify or notify
 | 
			
		||||
	local n_perc = args.n_perc or { 5, 15 }
 | 
			
		||||
	local batteries = args.batteries or (args.battery and { args.battery }) or {}
 | 
			
		||||
	local ac = args.ac or 'AC0'
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	function bat.get_batteries()
 | 
			
		||||
		helpers.line_callback('ls -1 ' .. pspath, function(line)
 | 
			
		||||
			local bstr = string.match(line, 'BAT%w+')
 | 
			
		||||
			if bstr then
 | 
			
		||||
				batteries[#batteries + 1] = bstr
 | 
			
		||||
			else
 | 
			
		||||
				ac = string.match(line, 'A%w+') or ac
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if #batteries == 0 then
 | 
			
		||||
		bat.get_batteries()
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	bat_notification_critical_preset = {
 | 
			
		||||
		title = 'Battery exhausted',
 | 
			
		||||
		text = 'Shutdown imminent',
 | 
			
		||||
		timeout = 15,
 | 
			
		||||
		fg = '#000000',
 | 
			
		||||
		bg = '#FFFFFF',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bat_notification_low_preset = {
 | 
			
		||||
		title = 'Battery low',
 | 
			
		||||
		text = 'Plug the cable!',
 | 
			
		||||
		timeout = 15,
 | 
			
		||||
		fg = '#202020',
 | 
			
		||||
		bg = '#CDCDCD',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bat_notification_charged_preset = {
 | 
			
		||||
		title = 'Battery full',
 | 
			
		||||
		text = 'You can unplug the cable',
 | 
			
		||||
		timeout = 15,
 | 
			
		||||
		fg = '#202020',
 | 
			
		||||
		bg = '#CDCDCD',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bat_now = {
 | 
			
		||||
		status = 'N/A',
 | 
			
		||||
		ac_status = 'N/A',
 | 
			
		||||
		perc = 'N/A',
 | 
			
		||||
		time = 'N/A',
 | 
			
		||||
		watt = 'N/A',
 | 
			
		||||
		capacity = 'N/A',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bat_now.n_status = {}
 | 
			
		||||
	bat_now.n_perc = {}
 | 
			
		||||
	bat_now.n_capacity = {}
 | 
			
		||||
	for i = 1, #batteries do
 | 
			
		||||
		bat_now.n_status[i] = 'N/A'
 | 
			
		||||
		bat_now.n_perc[i] = 0
 | 
			
		||||
		bat_now.n_capacity[i] = 0
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- used to notify full charge only once before discharging
 | 
			
		||||
	local fullnotification = false
 | 
			
		||||
 | 
			
		||||
	function bat.update()
 | 
			
		||||
		-- luacheck: globals bat_now
 | 
			
		||||
		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_charge_full = 0
 | 
			
		||||
		local sum_charge_design = 0
 | 
			
		||||
 | 
			
		||||
		for i, battery in ipairs(batteries) do
 | 
			
		||||
			local bstr = pspath .. battery
 | 
			
		||||
			local present = helpers.first_line(bstr .. '/present')
 | 
			
		||||
 | 
			
		||||
			if tonumber(present) == 1 then
 | 
			
		||||
				-- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
 | 
			
		||||
				local rate_current = tonumber(helpers.first_line(bstr .. '/current_now'))
 | 
			
		||||
				local rate_voltage = tonumber(helpers.first_line(bstr .. '/voltage_now'))
 | 
			
		||||
				local rate_power = tonumber(helpers.first_line(bstr .. '/power_now'))
 | 
			
		||||
				local charge_full = tonumber(helpers.first_line(bstr .. '/charge_full'))
 | 
			
		||||
				local charge_design = tonumber(helpers.first_line(bstr .. '/charge_full_design'))
 | 
			
		||||
 | 
			
		||||
				-- energy_now(P)[uWh], charge_now(I)[uAh]
 | 
			
		||||
				local energy_now =
 | 
			
		||||
					tonumber(helpers.first_line(bstr .. '/energy_now') or helpers.first_line(bstr .. '/charge_now'))
 | 
			
		||||
 | 
			
		||||
				-- energy_full(P)[uWh], charge_full(I)[uAh]
 | 
			
		||||
				local energy_full = tonumber(helpers.first_line(bstr .. '/energy_full') or charge_full)
 | 
			
		||||
 | 
			
		||||
				local energy_percentage = tonumber(helpers.first_line(bstr .. '/capacity'))
 | 
			
		||||
					or math.floor((energy_now / energy_full) * 100)
 | 
			
		||||
 | 
			
		||||
				bat_now.n_status[i] = helpers.first_line(bstr .. '/status') or 'N/A'
 | 
			
		||||
				bat_now.n_perc[i] = energy_percentage or bat_now.n_perc[i]
 | 
			
		||||
 | 
			
		||||
				if not charge_design or charge_design == 0 then
 | 
			
		||||
					bat_now.n_capacity[i] = 0
 | 
			
		||||
				else
 | 
			
		||||
					bat_now.n_capacity[i] = math.floor((charge_full / charge_design) * 100)
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				sum_rate_current = sum_rate_current + (rate_current or 0)
 | 
			
		||||
				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 or 0)
 | 
			
		||||
				sum_charge_full = sum_charge_full + (charge_full or 0)
 | 
			
		||||
				sum_charge_design = sum_charge_design + (charge_design or 0)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		bat_now.capacity = math.floor(math.min(100, (sum_charge_full / sum_charge_design) * 100))
 | 
			
		||||
 | 
			
		||||
		-- When one of the battery is charging, others' status are either
 | 
			
		||||
		-- "Full", "Unknown" or "Charging". When the laptop is not plugged in,
 | 
			
		||||
		-- one or more of the batteries may be full, but only one battery
 | 
			
		||||
		-- discharging suffices to set global status to "Discharging".
 | 
			
		||||
		bat_now.status = bat_now.n_status[1] or 'N/A'
 | 
			
		||||
		for _, status in ipairs(bat_now.n_status) do
 | 
			
		||||
			if status == 'Discharging' or status == 'Charging' then
 | 
			
		||||
				bat_now.status = status
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
		bat_now.ac_status = tonumber(helpers.first_line(string.format('%s%s/online', pspath, ac))) or 'N/A'
 | 
			
		||||
 | 
			
		||||
		if bat_now.status ~= 'N/A' then
 | 
			
		||||
			if bat_now.status ~= 'Full' and sum_rate_power == 0 and bat_now.ac_status == 1 then
 | 
			
		||||
				bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
 | 
			
		||||
				bat_now.time = '00:00'
 | 
			
		||||
				bat_now.watt = 0
 | 
			
		||||
 | 
			
		||||
			-- update {perc,time,watt} iff battery not full and rate > 0
 | 
			
		||||
			elseif bat_now.status ~= 'Full' then
 | 
			
		||||
				local rate_time = 0
 | 
			
		||||
				-- Calculate time and watt if rates are greater then 0
 | 
			
		||||
				if sum_rate_power > 0 or sum_rate_current > 0 then
 | 
			
		||||
					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) / div
 | 
			
		||||
					else -- Discharging
 | 
			
		||||
						rate_time = sum_energy_now / div
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					if 0 < rate_time and 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
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				local hours = math.floor(rate_time)
 | 
			
		||||
				local minutes = math.floor((rate_time - hours) * 60)
 | 
			
		||||
				bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
 | 
			
		||||
				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
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		widget = bat.widget
 | 
			
		||||
		settings()
 | 
			
		||||
 | 
			
		||||
		-- notifications for critical, low, and full levels
 | 
			
		||||
		if notify == 'on' then
 | 
			
		||||
			if bat_now.status == 'Discharging' then
 | 
			
		||||
				if tonumber(bat_now.perc) <= n_perc[1] then
 | 
			
		||||
					bat.id = naughty.notify({
 | 
			
		||||
						preset = bat_notification_critical_preset,
 | 
			
		||||
						replaces_id = bat.id,
 | 
			
		||||
					}).id
 | 
			
		||||
				elseif tonumber(bat_now.perc) <= n_perc[2] then
 | 
			
		||||
					bat.id = naughty.notify({
 | 
			
		||||
						preset = bat_notification_low_preset,
 | 
			
		||||
						replaces_id = bat.id,
 | 
			
		||||
					}).id
 | 
			
		||||
				end
 | 
			
		||||
				fullnotification = false
 | 
			
		||||
			elseif bat_now.status == 'Full' and full_notify == 'on' and not fullnotification then
 | 
			
		||||
				bat.id = naughty.notify({
 | 
			
		||||
					preset = bat_notification_charged_preset,
 | 
			
		||||
					replaces_id = bat.id,
 | 
			
		||||
				}).id
 | 
			
		||||
				fullnotification = true
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('batteries', timeout, bat.update)
 | 
			
		||||
 | 
			
		||||
	return bat
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										226
									
								
								awesome/lib/lain/widget/cal.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								awesome/lib/lain/widget/cal.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,226 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2018, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local markup = require('lain.util.markup')
 | 
			
		||||
local awful = require('awful')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local floor = math.floor
 | 
			
		||||
local os = os
 | 
			
		||||
local pairs = pairs
 | 
			
		||||
local string = string
 | 
			
		||||
local tconcat = table.concat
 | 
			
		||||
local type = type
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
local tostring = tostring
 | 
			
		||||
 | 
			
		||||
-- Calendar notification
 | 
			
		||||
-- lain.widget.cal
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
	local cal = {
 | 
			
		||||
		attach_to = args.attach_to or {},
 | 
			
		||||
		week_start = args.week_start or 2,
 | 
			
		||||
		three = args.three or false,
 | 
			
		||||
		followtag = args.followtag or false,
 | 
			
		||||
		week_number = args.week_number or 'none',
 | 
			
		||||
		week_number_format = args.week_number_format or args.week_number == 'left' and '%3d | ' or '| %-3d',
 | 
			
		||||
		icons = args.icons or helpers.icons_dir .. 'cal/white/',
 | 
			
		||||
		notification_preset = args.notification_preset or {
 | 
			
		||||
			font = 'Monospace 10',
 | 
			
		||||
			fg = '#FFFFFF',
 | 
			
		||||
			bg = '#000000',
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function cal.get_week_number(m, st_day, x)
 | 
			
		||||
		local date = os.date('*t', m)
 | 
			
		||||
 | 
			
		||||
		local week_step = (x ~= 0 and floor((x + st_day) / 7) - 1 or 0)
 | 
			
		||||
 | 
			
		||||
		local display_time = os.time({
 | 
			
		||||
			year = date.year,
 | 
			
		||||
			month = date.month,
 | 
			
		||||
			day = date.day + 7 * week_step,
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		return string.format(cal.week_number_format, os.date('%V', display_time))
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.sum_week_days(x, y)
 | 
			
		||||
		return (x + y) % 7
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.build(month, year)
 | 
			
		||||
		local current_month, current_year = tonumber(os.date('%m')), tonumber(os.date('%Y'))
 | 
			
		||||
		local is_current_month = (not month or not year) or (month == current_month and year == current_year)
 | 
			
		||||
		local today = is_current_month and tonumber(os.date('%d')) -- otherwise nil and not highlighted
 | 
			
		||||
		local t = os.time({ year = year or current_year, month = month and month + 1 or current_month + 1, day = 0 })
 | 
			
		||||
		local d = os.date('*t', t)
 | 
			
		||||
		local mth_days, st_day, this_month = d.day, (d.wday - d.day - cal.week_start + 1) % 7, os.date('%B %Y', t)
 | 
			
		||||
		local notifytable = {
 | 
			
		||||
			[1] = string.format('%s%s\n', string.rep(' ', floor((28 - this_month:len()) / 2)), markup.bold(this_month)),
 | 
			
		||||
		}
 | 
			
		||||
		for day_num = 0, 6 do
 | 
			
		||||
			notifytable[#notifytable + 1] = string.format(
 | 
			
		||||
				'%3s ',
 | 
			
		||||
				os.date('%a', os.time({ year = 2006, month = 1, day = day_num + cal.week_start }))
 | 
			
		||||
			)
 | 
			
		||||
		end
 | 
			
		||||
		notifytable[#notifytable] =
 | 
			
		||||
			string.format('%s\n%s', notifytable[#notifytable]:sub(1, -2), string.rep(' ', st_day * 4))
 | 
			
		||||
		local strx
 | 
			
		||||
		for x = 1, mth_days do
 | 
			
		||||
			strx = x
 | 
			
		||||
			if x == today then
 | 
			
		||||
				if x < 10 then
 | 
			
		||||
					x = ' ' .. x
 | 
			
		||||
				end
 | 
			
		||||
				strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. ' ')
 | 
			
		||||
			end
 | 
			
		||||
			strx = string.format('%s%s', string.rep(' ', 3 - tostring(x):len()), strx)
 | 
			
		||||
			notifytable[#notifytable + 1] =
 | 
			
		||||
				string.format('%-4s%s', strx, (x + st_day) % 7 == 0 and x ~= mth_days and '\n' or '')
 | 
			
		||||
		end
 | 
			
		||||
		if string.len(cal.icons or '') > 0 and today then
 | 
			
		||||
			cal.icon = cal.icons .. today .. '.png'
 | 
			
		||||
		end
 | 
			
		||||
		cal.month, cal.year = d.month, d.year
 | 
			
		||||
 | 
			
		||||
		if cal.week_number ~= 'none' then
 | 
			
		||||
			local m = os.time({ year = year or current_year, month = month and month or current_month, day = 1 })
 | 
			
		||||
			local head_prepend = string.rep(' ', tostring(string.format(cal.week_number_format, 0)):len())
 | 
			
		||||
 | 
			
		||||
			if cal.week_number == 'left' then
 | 
			
		||||
				notifytable[1] = head_prepend .. notifytable[1] -- month-year row
 | 
			
		||||
				notifytable[2] = head_prepend .. notifytable[2] -- weekdays row
 | 
			
		||||
				notifytable[8] = notifytable[8]:gsub('\n', '\n' .. cal.get_week_number(m, st_day, 0)) -- first week of the month
 | 
			
		||||
 | 
			
		||||
				for x = 10, #notifytable do
 | 
			
		||||
					if cal.sum_week_days(st_day, x) == 2 then
 | 
			
		||||
						notifytable[x] = cal.get_week_number(m, st_day, x) .. notifytable[x]
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			elseif cal.week_number == 'right' then
 | 
			
		||||
				notifytable[8] = notifytable[8]:gsub('\n', head_prepend .. '\n') -- weekdays row
 | 
			
		||||
				for x = 9, #notifytable do
 | 
			
		||||
					if cal.sum_week_days(st_day, x) == 1 then
 | 
			
		||||
						notifytable[x] = notifytable[x]:gsub('\n', cal.get_week_number(m, st_day, x - 7) .. '\n')
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
				-- last week of the month
 | 
			
		||||
				local end_days = cal.sum_week_days(st_day, mth_days)
 | 
			
		||||
				if end_days ~= 0 then
 | 
			
		||||
					end_days = 7 - end_days
 | 
			
		||||
				end
 | 
			
		||||
				notifytable[#notifytable] = notifytable[#notifytable]
 | 
			
		||||
					.. string.rep(' ', 4 * end_days)
 | 
			
		||||
					.. cal.get_week_number(m, st_day, mth_days + end_days)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		return notifytable
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.getdate(month, year, offset)
 | 
			
		||||
		if not month or not year then
 | 
			
		||||
			month = tonumber(os.date('%m'))
 | 
			
		||||
			year = tonumber(os.date('%Y'))
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		month = month + offset
 | 
			
		||||
 | 
			
		||||
		while month > 12 do
 | 
			
		||||
			month = month - 12
 | 
			
		||||
			year = year + 1
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		while month < 1 do
 | 
			
		||||
			month = month + 12
 | 
			
		||||
			year = year - 1
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		return month, year
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.hide()
 | 
			
		||||
		if not cal.notification then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		naughty.destroy(cal.notification)
 | 
			
		||||
		cal.notification = nil
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.show(seconds, month, year, scr)
 | 
			
		||||
		local text = tconcat(cal.build(month, year))
 | 
			
		||||
 | 
			
		||||
		if cal.three then
 | 
			
		||||
			local current_month, current_year = cal.month, cal.year
 | 
			
		||||
			local prev_month, prev_year = cal.getdate(cal.month, cal.year, -1)
 | 
			
		||||
			local next_month, next_year = cal.getdate(cal.month, cal.year, 1)
 | 
			
		||||
			text = string.format(
 | 
			
		||||
				'%s\n\n%s\n\n%s',
 | 
			
		||||
				tconcat(cal.build(prev_month, prev_year)),
 | 
			
		||||
				text,
 | 
			
		||||
				tconcat(cal.build(next_month, next_year))
 | 
			
		||||
			)
 | 
			
		||||
			cal.month, cal.year = current_month, current_year
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if cal.notification then
 | 
			
		||||
			local title = cal.notification_preset.title or nil
 | 
			
		||||
			naughty.replace_text(cal.notification, title, text)
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		cal.notification = naughty.notify({
 | 
			
		||||
			preset = cal.notification_preset,
 | 
			
		||||
			screen = cal.followtag and awful.screen.focused() or scr or 1,
 | 
			
		||||
			icon = cal.icon,
 | 
			
		||||
			timeout = type(seconds) == 'number' and seconds or cal.notification_preset.timeout or 5,
 | 
			
		||||
			text = text,
 | 
			
		||||
		})
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.hover_on()
 | 
			
		||||
		cal.show(0)
 | 
			
		||||
	end
 | 
			
		||||
	function cal.move(offset)
 | 
			
		||||
		offset = offset or 0
 | 
			
		||||
		cal.month, cal.year = cal.getdate(cal.month, cal.year, offset)
 | 
			
		||||
		cal.show(0, cal.month, cal.year)
 | 
			
		||||
	end
 | 
			
		||||
	function cal.prev()
 | 
			
		||||
		cal.move(-1)
 | 
			
		||||
	end
 | 
			
		||||
	function cal.next()
 | 
			
		||||
		cal.move(1)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function cal.attach(widget)
 | 
			
		||||
		widget:connect_signal('mouse::enter', cal.hover_on)
 | 
			
		||||
		widget:connect_signal('mouse::leave', cal.hide)
 | 
			
		||||
		widget:buttons(
 | 
			
		||||
			awful.util.table.join(
 | 
			
		||||
				awful.button({}, 1, cal.prev),
 | 
			
		||||
				awful.button({}, 3, cal.next),
 | 
			
		||||
				awful.button({}, 2, cal.hover_on),
 | 
			
		||||
				awful.button({}, 5, cal.prev),
 | 
			
		||||
				awful.button({}, 4, cal.next)
 | 
			
		||||
			)
 | 
			
		||||
		)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	for _, widget in pairs(cal.attach_to) do
 | 
			
		||||
		cal.attach(widget)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	return cal
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										18
									
								
								awesome/lib/lain/widget/contrib/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								awesome/lib/lain/widget/contrib/init.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Lain
 | 
			
		||||
     Layouts, widgets and utilities for Awesome WM
 | 
			
		||||
 | 
			
		||||
     Users contributed widgets section
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local wrequire = require('lain.helpers').wrequire
 | 
			
		||||
local setmetatable = setmetatable
 | 
			
		||||
 | 
			
		||||
local widget = { _NAME = 'lain.widget.contrib' }
 | 
			
		||||
 | 
			
		||||
return setmetatable(widget, { __index = wrequire })
 | 
			
		||||
							
								
								
									
										107
									
								
								awesome/lib/lain/widget/contrib/moc.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								awesome/lib/lain/widget/contrib/moc.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2014, anticlockwise <http://github.com/anticlockwise>
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local shell = require('awful.util').shell
 | 
			
		||||
local focused = require('awful.screen').focused
 | 
			
		||||
local escape_f = require('awful.util').escape
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local os = os
 | 
			
		||||
local string = string
 | 
			
		||||
 | 
			
		||||
-- MOC audio player
 | 
			
		||||
-- lain.widget.contrib.moc
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local moc = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 2
 | 
			
		||||
	local music_dir = args.music_dir or os.getenv('HOME') .. '/Music'
 | 
			
		||||
	local cover_pattern = args.cover_pattern or '*\\.(jpg|jpeg|png|gif)$'
 | 
			
		||||
	local cover_size = args.cover_size or 100
 | 
			
		||||
	local default_art = args.default_art or ''
 | 
			
		||||
	local followtag = args.followtag or false
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	moc_notification_preset = { title = 'Now playing', timeout = 6 }
 | 
			
		||||
 | 
			
		||||
	helpers.set_map('current moc track', nil)
 | 
			
		||||
 | 
			
		||||
	function moc.update()
 | 
			
		||||
		helpers.async('mocp -i', function(f)
 | 
			
		||||
			moc_now = {
 | 
			
		||||
				state = 'N/A',
 | 
			
		||||
				file = 'N/A',
 | 
			
		||||
				artist = 'N/A',
 | 
			
		||||
				title = 'N/A',
 | 
			
		||||
				album = 'N/A',
 | 
			
		||||
				elapsed = 'N/A',
 | 
			
		||||
				total = 'N/A',
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for line in string.gmatch(f, '[^\n]+') do
 | 
			
		||||
				for k, v in string.gmatch(line, '([%w]+):[%s](.*)$') do
 | 
			
		||||
					if k == 'State' then
 | 
			
		||||
						moc_now.state = v
 | 
			
		||||
					elseif k == 'File' then
 | 
			
		||||
						moc_now.file = v
 | 
			
		||||
					elseif k == 'Artist' then
 | 
			
		||||
						moc_now.artist = escape_f(v)
 | 
			
		||||
					elseif k == 'SongTitle' then
 | 
			
		||||
						moc_now.title = escape_f(v)
 | 
			
		||||
					elseif k == 'Album' then
 | 
			
		||||
						moc_now.album = escape_f(v)
 | 
			
		||||
					elseif k == 'CurrentTime' then
 | 
			
		||||
						moc_now.elapsed = escape_f(v)
 | 
			
		||||
					elseif k == 'TotalTime' then
 | 
			
		||||
						moc_now.total = escape_f(v)
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			moc_notification_preset.text =
 | 
			
		||||
				string.format('%s (%s) - %s\n%s', moc_now.artist, moc_now.album, moc_now.total, moc_now.title)
 | 
			
		||||
			widget = moc.widget
 | 
			
		||||
			settings()
 | 
			
		||||
 | 
			
		||||
			if moc_now.state == 'PLAY' then
 | 
			
		||||
				if moc_now.title ~= helpers.get_map('current moc track') then
 | 
			
		||||
					helpers.set_map('current moc track', moc_now.title)
 | 
			
		||||
 | 
			
		||||
					if followtag then
 | 
			
		||||
						moc_notification_preset.screen = focused()
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					local common = {
 | 
			
		||||
						preset = moc_notification_preset,
 | 
			
		||||
						icon = default_art,
 | 
			
		||||
						icon_size = cover_size,
 | 
			
		||||
						replaces_id = moc.id,
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					local path = string.format('%s/%s', music_dir, string.match(moc_now.file, '.*/'))
 | 
			
		||||
					local cover =
 | 
			
		||||
						string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'", path, cover_pattern)
 | 
			
		||||
					helpers.async({ shell, '-c', cover }, function(current_icon)
 | 
			
		||||
						common.icon = current_icon:gsub('\n', '')
 | 
			
		||||
						moc.id = naughty.notify(common).id
 | 
			
		||||
					end)
 | 
			
		||||
				end
 | 
			
		||||
			elseif moc_now.state ~= 'PAUSE' then
 | 
			
		||||
				helpers.set_map('current moc track', nil)
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	moc.timer = helpers.newtimer('moc', timeout, moc.update, true, true)
 | 
			
		||||
 | 
			
		||||
	return moc
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										58
									
								
								awesome/lib/lain/widget/contrib/redshift.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								awesome/lib/lain/widget/contrib/redshift.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2017, Luca CPZ
 | 
			
		||||
      * (c) 2014, blueluke <http://github.com/blueluke>
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local async = require('lain.helpers').async
 | 
			
		||||
local awful = require('awful')
 | 
			
		||||
local execute = os.execute
 | 
			
		||||
local type = type
 | 
			
		||||
 | 
			
		||||
-- Redshift
 | 
			
		||||
-- lain.widget.contrib.redshift
 | 
			
		||||
local redshift = { active = false, pid = nil }
 | 
			
		||||
 | 
			
		||||
function redshift.start()
 | 
			
		||||
	execute('pkill redshift')
 | 
			
		||||
	awful.spawn.with_shell('redshift -x') -- clear adjustments
 | 
			
		||||
	redshift.pid = awful.spawn.with_shell('redshift')
 | 
			
		||||
	redshift.active = true
 | 
			
		||||
	if type(redshift.update_fun) == 'function' then
 | 
			
		||||
		redshift.update_fun(redshift.active)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function redshift.toggle()
 | 
			
		||||
	async({ awful.util.shell, '-c', string.format('ps -p %d -o pid=', redshift.pid) }, function(f)
 | 
			
		||||
		if f and #f > 0 then -- redshift is running
 | 
			
		||||
			-- Sending -USR1 toggles redshift (See project website)
 | 
			
		||||
			execute('pkill -USR1 redshift')
 | 
			
		||||
			redshift.active = not redshift.active
 | 
			
		||||
		else -- not started or killed, (re)start it
 | 
			
		||||
			redshift.start()
 | 
			
		||||
		end
 | 
			
		||||
		redshift.update_fun(redshift.active)
 | 
			
		||||
	end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Attach to a widget
 | 
			
		||||
-- Provides a button which toggles redshift on/off on click
 | 
			
		||||
-- @param widget:  Widget to attach to.
 | 
			
		||||
-- @param fun:     Function to be run each time redshift is toggled (optional).
 | 
			
		||||
--                 Use it to update widget text or icons on status change.
 | 
			
		||||
function redshift.attach(widget, fun)
 | 
			
		||||
	redshift.update_fun = fun or function() end
 | 
			
		||||
	if not redshift.pid then
 | 
			
		||||
		redshift.start()
 | 
			
		||||
	end
 | 
			
		||||
	if widget then
 | 
			
		||||
		widget:buttons(awful.util.table.join(awful.button({}, 1, function()
 | 
			
		||||
			redshift.toggle()
 | 
			
		||||
		end)))
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return redshift
 | 
			
		||||
							
								
								
									
										96
									
								
								awesome/lib/lain/widget/contrib/task.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								awesome/lib/lain/widget/contrib/task.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Jan Xie
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local markup = require('lain.util').markup
 | 
			
		||||
local awful = require('awful')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local mouse = mouse
 | 
			
		||||
 | 
			
		||||
-- Taskwarrior notification
 | 
			
		||||
-- lain.widget.contrib.task
 | 
			
		||||
local task = {}
 | 
			
		||||
 | 
			
		||||
function task.hide()
 | 
			
		||||
	if not task.notification then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	naughty.destroy(task.notification)
 | 
			
		||||
	task.notification = nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function task.show(scr)
 | 
			
		||||
	task.notification_preset.screen = task.followtag and awful.screen.focused() or scr or 1
 | 
			
		||||
 | 
			
		||||
	helpers.async({ awful.util.shell, '-c', task.show_cmd }, function(f)
 | 
			
		||||
		local widget_focused = true
 | 
			
		||||
 | 
			
		||||
		if mouse.current_widgets then
 | 
			
		||||
			widget_focused = false
 | 
			
		||||
			for _, v in ipairs(mouse.current_widgets) do
 | 
			
		||||
				if task.widget == v then
 | 
			
		||||
					widget_focused = true
 | 
			
		||||
					break
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if widget_focused then
 | 
			
		||||
			task.hide()
 | 
			
		||||
			task.notification = naughty.notify({
 | 
			
		||||
				preset = task.notification_preset,
 | 
			
		||||
				title = 'task next',
 | 
			
		||||
				text = markup.font(task.notification_preset.font, awful.util.escape(f:gsub('\n*$', ''))),
 | 
			
		||||
			})
 | 
			
		||||
		end
 | 
			
		||||
	end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function task.prompt()
 | 
			
		||||
	awful.prompt.run({
 | 
			
		||||
		prompt = task.prompt_text,
 | 
			
		||||
		textbox = awful.screen.focused().mypromptbox.widget,
 | 
			
		||||
		exe_callback = function(t)
 | 
			
		||||
			helpers.async(t, function(f)
 | 
			
		||||
				naughty.notify({
 | 
			
		||||
					preset = task.notification_preset,
 | 
			
		||||
					title = t,
 | 
			
		||||
					text = markup.font(task.notification_preset.font, awful.util.escape(f:gsub('\n*$', ''))),
 | 
			
		||||
				})
 | 
			
		||||
			end)
 | 
			
		||||
		end,
 | 
			
		||||
		history_path = awful.util.getdir('cache') .. '/history_task',
 | 
			
		||||
	})
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function task.attach(widget, args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	task.show_cmd = args.show_cmd or 'task next'
 | 
			
		||||
	task.prompt_text = args.prompt_text or 'Enter task command: '
 | 
			
		||||
	task.followtag = args.followtag or false
 | 
			
		||||
	task.notification_preset = args.notification_preset
 | 
			
		||||
	task.widget = widget
 | 
			
		||||
 | 
			
		||||
	if not task.notification_preset then
 | 
			
		||||
		task.notification_preset = {
 | 
			
		||||
			font = 'Monospace 10',
 | 
			
		||||
			icon = helpers.icons_dir .. '/taskwarrior.png',
 | 
			
		||||
		}
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if widget then
 | 
			
		||||
		widget:connect_signal('mouse::enter', function()
 | 
			
		||||
			task.show()
 | 
			
		||||
		end)
 | 
			
		||||
		widget:connect_signal('mouse::leave', function()
 | 
			
		||||
			task.hide()
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return task
 | 
			
		||||
							
								
								
									
										164
									
								
								awesome/lib/lain/widget/contrib/tp_smapi.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								awesome/lib/lain/widget/contrib/tp_smapi.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2018, Luca CPZ
 | 
			
		||||
      * (c) 2013, Conor Heine
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local focused = require('awful.screen').focused
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local string = string
 | 
			
		||||
local type = type
 | 
			
		||||
 | 
			
		||||
-- ThinkPad battery infos and widget creator
 | 
			
		||||
-- http://www.thinkwiki.org/wiki/Tp_smapi
 | 
			
		||||
-- lain.widget.contrib.tp_smapi
 | 
			
		||||
 | 
			
		||||
local function factory(apipath)
 | 
			
		||||
	local tp_smapi = {
 | 
			
		||||
		path = apipath or '/sys/devices/platform/smapi',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.get(batid, feature)
 | 
			
		||||
		return helpers.first_line(string.format('%s/%s/%s', tp_smapi.path, batid or 'BAT0', feature or ''))
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.installed(batid)
 | 
			
		||||
		return tp_smapi.get(batid, 'installed') == '1'
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.status(batid)
 | 
			
		||||
		return tp_smapi.get(batid, 'state')
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.percentage(batid)
 | 
			
		||||
		return tp_smapi.get(batid, 'remaining_percent')
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	-- either running or charging time
 | 
			
		||||
	function tp_smapi.time(batid)
 | 
			
		||||
		local status = tp_smapi.status(batid)
 | 
			
		||||
		local mins_left = tp_smapi.get(
 | 
			
		||||
			batid,
 | 
			
		||||
			string.match(string.lower(status), 'discharging') and 'remaining_running_time' or 'remaining_charging_time'
 | 
			
		||||
		)
 | 
			
		||||
		if not string.find(mins_left, '^%d+') then
 | 
			
		||||
			return 'N/A'
 | 
			
		||||
		end
 | 
			
		||||
		return string.format('%02d:%02d', math.floor(mins_left / 60), mins_left % 60) -- HH:mm
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.hide()
 | 
			
		||||
		if not tp_smapi.notification then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		naughty.destroy(tp_smapi.notification)
 | 
			
		||||
		tp_smapi.notification = nil
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.show(batid, seconds, scr)
 | 
			
		||||
		if not tp_smapi.installed(batid) then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local mfgr = tp_smapi.get(batid, 'manufacturer') or 'no_mfgr'
 | 
			
		||||
		local model = tp_smapi.get(batid, 'model') or 'no_model'
 | 
			
		||||
		local chem = tp_smapi.get(batid, 'chemistry') or 'no_chem'
 | 
			
		||||
		local status = tp_smapi.get(batid, 'state')
 | 
			
		||||
		local time = tp_smapi.time(batid)
 | 
			
		||||
		local msg
 | 
			
		||||
 | 
			
		||||
		if status and status ~= 'idle' then
 | 
			
		||||
			msg = string.format(
 | 
			
		||||
				'[%s] %s %s',
 | 
			
		||||
				status,
 | 
			
		||||
				time ~= 'N/A' and time or 'unknown remaining time',
 | 
			
		||||
				string.lower(status):gsub(' ', ''):gsub('\n', '') == 'charging' and ' until charged' or ' remaining'
 | 
			
		||||
			)
 | 
			
		||||
		else
 | 
			
		||||
			msg = 'On AC power'
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		tp_smapi.hide()
 | 
			
		||||
		tp_smapi.notification = naughty.notify({
 | 
			
		||||
			title = string.format('%s: %s %s (%s)', batid, mfgr, model, chem),
 | 
			
		||||
			text = msg,
 | 
			
		||||
			timeout = type(seconds) == 'number' and seconds or 0,
 | 
			
		||||
			screen = scr or focused(),
 | 
			
		||||
		})
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function tp_smapi.create_widget(args)
 | 
			
		||||
		args = args or {}
 | 
			
		||||
 | 
			
		||||
		local pspath = args.pspath or '/sys/class/power_supply/'
 | 
			
		||||
		local batteries = args.batteries or (args.battery and { args.battery }) or {}
 | 
			
		||||
		local timeout = args.timeout or 30
 | 
			
		||||
		local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
		if #batteries == 0 then
 | 
			
		||||
			helpers.line_callback('ls -1 ' .. pspath, function(line)
 | 
			
		||||
				local bstr = string.match(line, 'BAT%w+')
 | 
			
		||||
				if bstr then
 | 
			
		||||
					batteries[#batteries + 1] = bstr
 | 
			
		||||
				end
 | 
			
		||||
			end)
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local all_batteries_installed = true
 | 
			
		||||
 | 
			
		||||
		for _, battery in ipairs(batteries) do
 | 
			
		||||
			if not tp_smapi.installed(battery) then
 | 
			
		||||
				naughty.notify({
 | 
			
		||||
					preset = naughty.config.critical,
 | 
			
		||||
					title = 'tp_smapi: error while creating widget',
 | 
			
		||||
					text = string.format('battery %s is not installed', battery),
 | 
			
		||||
				})
 | 
			
		||||
				all_batteries_installed = false
 | 
			
		||||
				break
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if not all_batteries_installed then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		tpbat = {
 | 
			
		||||
			batteries = batteries,
 | 
			
		||||
			widget = args.widget or wibox.widget.textbox(),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		function tpbat.update()
 | 
			
		||||
			tpbat_now = {
 | 
			
		||||
				n_status = {},
 | 
			
		||||
				n_perc = {},
 | 
			
		||||
				n_time = {},
 | 
			
		||||
				status = 'N/A',
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for i = 1, #batteries do
 | 
			
		||||
				tpbat_now.n_status[i] = tp_smapi.status(batteries[i]) or 'N/A'
 | 
			
		||||
				tpbat_now.n_perc[i] = tp_smapi.percentage(batteries[i])
 | 
			
		||||
				tpbat_now.n_time[i] = tp_smapi.time(batteries[i]) or 'N/A'
 | 
			
		||||
 | 
			
		||||
				if not tpbat_now.n_status[i]:lower():match('full') then
 | 
			
		||||
					tpbat_now.status = tpbat_now.n_status[i]
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			widget = tpbat.widget -- backwards compatibility
 | 
			
		||||
			settings()
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		helpers.newtimer('thinkpad-batteries', timeout, tpbat.update)
 | 
			
		||||
 | 
			
		||||
		return tpbat
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	return tp_smapi
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										74
									
								
								awesome/lib/lain/widget/cpu.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								awesome/lib/lain/widget/cpu.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013,      Luca CPZ
 | 
			
		||||
      * (c) 2010-2012, Peter Hofmann
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local math = math
 | 
			
		||||
local string = string
 | 
			
		||||
 | 
			
		||||
-- CPU usage
 | 
			
		||||
-- lain.widget.cpu
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local cpu = { core = {}, widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 2
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	function cpu.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.
 | 
			
		||||
		for index, time in pairs(helpers.lines_match('cpu', '/proc/stat')) do
 | 
			
		||||
			local coreid = index - 1
 | 
			
		||||
			local core = cpu.core[coreid] or { last_active = 0, last_total = 0, usage = 0 }
 | 
			
		||||
			local at = 1
 | 
			
		||||
			local idle = 0
 | 
			
		||||
			local total = 0
 | 
			
		||||
 | 
			
		||||
			for field in string.gmatch(time, '[%s]+([^%s]+)') do
 | 
			
		||||
				-- 4 = idle, 5 = ioWait. Essentially, the CPUs have done
 | 
			
		||||
				-- nothing during these times.
 | 
			
		||||
				if at == 4 or at == 5 then
 | 
			
		||||
					idle = idle + field
 | 
			
		||||
				end
 | 
			
		||||
				total = total + field
 | 
			
		||||
				at = at + 1
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			local active = total - idle
 | 
			
		||||
 | 
			
		||||
			if core.last_active ~= active or core.last_total ~= total then
 | 
			
		||||
				-- Read current data and calculate relative values.
 | 
			
		||||
				local dactive = active - core.last_active
 | 
			
		||||
				local dtotal = total - core.last_total
 | 
			
		||||
				local usage = math.ceil(math.abs((dactive / dtotal) * 100))
 | 
			
		||||
 | 
			
		||||
				core.last_active = active
 | 
			
		||||
				core.last_total = total
 | 
			
		||||
				core.usage = usage
 | 
			
		||||
 | 
			
		||||
				-- Save current data for the next run.
 | 
			
		||||
				cpu.core[coreid] = core
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		cpu_now = cpu.core
 | 
			
		||||
		cpu_now.usage = cpu_now[0].usage
 | 
			
		||||
		widget = cpu.widget
 | 
			
		||||
 | 
			
		||||
		settings()
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('cpu', timeout, cpu.update)
 | 
			
		||||
 | 
			
		||||
	return cpu
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										174
									
								
								awesome/lib/lain/widget/fs.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								awesome/lib/lain/widget/fs.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2018, Uli Schlacter
 | 
			
		||||
      * (c) 2018, Otto Modinos
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local Gio = require('lgi').Gio
 | 
			
		||||
local focused = require('awful.screen').focused
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local gears = require('gears')
 | 
			
		||||
local math = math
 | 
			
		||||
local string = string
 | 
			
		||||
local tconcat = table.concat
 | 
			
		||||
local type = type
 | 
			
		||||
local query_size = Gio.FILE_ATTRIBUTE_FILESYSTEM_SIZE
 | 
			
		||||
local query_free = Gio.FILE_ATTRIBUTE_FILESYSTEM_FREE
 | 
			
		||||
local query_used = Gio.FILE_ATTRIBUTE_FILESYSTEM_USED
 | 
			
		||||
local query = query_size .. ',' .. query_free .. ',' .. query_used
 | 
			
		||||
 | 
			
		||||
-- File systems info
 | 
			
		||||
-- lain.widget.fs
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local fs = {
 | 
			
		||||
		widget = args.widget or wibox.widget.textbox(),
 | 
			
		||||
		units = {
 | 
			
		||||
			[1] = 'Kb',
 | 
			
		||||
			[2] = 'Mb',
 | 
			
		||||
			[3] = 'Gb',
 | 
			
		||||
			[4] = 'Tb',
 | 
			
		||||
			[5] = 'Pb',
 | 
			
		||||
			[6] = 'Eb',
 | 
			
		||||
			[7] = 'Zb',
 | 
			
		||||
			[8] = 'Yb',
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	function fs.hide()
 | 
			
		||||
		if not fs.notification then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		naughty.destroy(fs.notification)
 | 
			
		||||
		fs.notification = nil
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function fs.show(seconds, scr)
 | 
			
		||||
		fs.hide()
 | 
			
		||||
		fs.update(function()
 | 
			
		||||
			fs.notification_preset.screen = fs.followtag and focused() or scr or 1
 | 
			
		||||
			fs.notification = naughty.notify({
 | 
			
		||||
				preset = fs.notification_preset,
 | 
			
		||||
				timeout = type(seconds) == 'number' and seconds or 5,
 | 
			
		||||
			})
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local timeout = args.timeout or 600
 | 
			
		||||
	local partition = args.partition
 | 
			
		||||
	local threshold = args.threshold or 99
 | 
			
		||||
	local showpopup = args.showpopup or 'on'
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	fs.followtag = args.followtag or false
 | 
			
		||||
	fs.notification_preset = args.notification_preset
 | 
			
		||||
 | 
			
		||||
	if not fs.notification_preset then
 | 
			
		||||
		fs.notification_preset = {
 | 
			
		||||
			font = 'Monospace 10',
 | 
			
		||||
			fg = '#FFFFFF',
 | 
			
		||||
			bg = '#000000',
 | 
			
		||||
		}
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	local function update_synced()
 | 
			
		||||
		local pathlen = 10
 | 
			
		||||
		fs_now = {}
 | 
			
		||||
 | 
			
		||||
		local notifypaths = {}
 | 
			
		||||
		for _, mount in ipairs(Gio.unix_mounts_get()) do
 | 
			
		||||
			local path = Gio.unix_mount_get_mount_path(mount)
 | 
			
		||||
			local root = Gio.File.new_for_path(path)
 | 
			
		||||
			local info = root:query_filesystem_info(query)
 | 
			
		||||
 | 
			
		||||
			if info then
 | 
			
		||||
				local size = info:get_attribute_uint64(query_size)
 | 
			
		||||
				local used = info:get_attribute_uint64(query_used)
 | 
			
		||||
				local free = info:get_attribute_uint64(query_free)
 | 
			
		||||
 | 
			
		||||
				if size > 0 then
 | 
			
		||||
					local units = math.floor(math.log(size) / math.log(1024))
 | 
			
		||||
 | 
			
		||||
					fs_now[path] = {
 | 
			
		||||
						units = fs.units[units],
 | 
			
		||||
						percentage = math.floor(100 * used / size), -- used percentage
 | 
			
		||||
						size = size / math.pow(1024, units),
 | 
			
		||||
						used = used / math.pow(1024, units),
 | 
			
		||||
						free = free / math.pow(1024, units),
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if fs_now[path].percentage > 0 then -- don't notify unused file systems
 | 
			
		||||
						notifypaths[#notifypaths + 1] = path
 | 
			
		||||
 | 
			
		||||
						if #path > pathlen then
 | 
			
		||||
							pathlen = #path
 | 
			
		||||
						end
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		widget = fs.widget
 | 
			
		||||
		settings()
 | 
			
		||||
 | 
			
		||||
		if partition and fs_now[partition] and fs_now[partition].percentage >= threshold then
 | 
			
		||||
			if not helpers.get_map(partition) then
 | 
			
		||||
				naughty.notify({
 | 
			
		||||
					preset = naughty.config.presets.critical,
 | 
			
		||||
					title = 'Warning',
 | 
			
		||||
					text = string.format('%s is above %d%% (%d%%)', partition, threshold, fs_now[partition].percentage),
 | 
			
		||||
				})
 | 
			
		||||
				helpers.set_map(partition, true)
 | 
			
		||||
			else
 | 
			
		||||
				helpers.set_map(partition, false)
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local fmt = '%-' .. tostring(pathlen) .. 's %4s\t%6s\t%6s\n'
 | 
			
		||||
		local notifytable = { [1] = string.format(fmt, 'path', 'used', 'free', 'size') }
 | 
			
		||||
		fmt = '\n%-' .. tostring(pathlen) .. 's %3s%%\t%6.2f\t%6.2f %s'
 | 
			
		||||
		for _, path in ipairs(notifypaths) do
 | 
			
		||||
			notifytable[#notifytable + 1] = string.format(
 | 
			
		||||
				fmt,
 | 
			
		||||
				path,
 | 
			
		||||
				fs_now[path].percentage,
 | 
			
		||||
				fs_now[path].free,
 | 
			
		||||
				fs_now[path].size,
 | 
			
		||||
				fs_now[path].units
 | 
			
		||||
			)
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		fs.notification_preset.text = tconcat(notifytable)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function fs.update(callback)
 | 
			
		||||
		Gio.Async.start(gears.protected_call.call)(function()
 | 
			
		||||
			update_synced()
 | 
			
		||||
			if type(callback) == 'function' and callback then
 | 
			
		||||
				callback()
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if showpopup == 'on' then
 | 
			
		||||
		fs.widget:connect_signal('mouse::enter', function()
 | 
			
		||||
			fs.show(0)
 | 
			
		||||
		end)
 | 
			
		||||
		fs.widget:connect_signal('mouse::leave', function()
 | 
			
		||||
			fs.hide()
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer(partition or 'fs', timeout, fs.update)
 | 
			
		||||
 | 
			
		||||
	return fs
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										115
									
								
								awesome/lib/lain/widget/imap.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								awesome/lib/lain/widget/imap.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local awful = require('awful')
 | 
			
		||||
local string = string
 | 
			
		||||
local type = type
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
 | 
			
		||||
-- Mail IMAP check
 | 
			
		||||
-- lain.widget.imap
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local imap = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	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 pwdtimeout = args.pwdtimeout or 10
 | 
			
		||||
	local is_plain = args.is_plain or false
 | 
			
		||||
	local followtag = args.followtag or false
 | 
			
		||||
	local notify = args.notify or 'on'
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	local head_command = 'curl --connect-timeout 3 -fsm 3'
 | 
			
		||||
	local request = "-X 'STATUS INBOX (MESSAGES RECENT UNSEEN)'"
 | 
			
		||||
 | 
			
		||||
	if not server or not mail or not password then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	mail_notification_preset = {
 | 
			
		||||
		icon = helpers.icons_dir .. 'mail.png',
 | 
			
		||||
		position = 'top_left',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	helpers.set_map(mail, 0)
 | 
			
		||||
 | 
			
		||||
	if not is_plain then
 | 
			
		||||
		if type(password) == 'string' or type(password) == 'table' then
 | 
			
		||||
			helpers.async(password, function(f)
 | 
			
		||||
				password = f:gsub('\n', '')
 | 
			
		||||
			end)
 | 
			
		||||
		elseif type(password) == 'function' then
 | 
			
		||||
			imap.pwdtimer = helpers.newtimer(mail .. '-password', pwdtimeout, function()
 | 
			
		||||
				local retrieved_password, try_again = password()
 | 
			
		||||
				if not try_again then
 | 
			
		||||
					imap.pwdtimer:stop() -- stop trying to retrieve
 | 
			
		||||
					password = retrieved_password or '' -- failsafe
 | 
			
		||||
				end
 | 
			
		||||
			end, true, true)
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function imap.update()
 | 
			
		||||
		-- do not update if the password has not been retrieved yet
 | 
			
		||||
		if type(password) ~= 'string' then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		local curl = string.format(
 | 
			
		||||
			"%s --url imaps://%s:%s/INBOX -u %s:'%s' %s -k",
 | 
			
		||||
			head_command,
 | 
			
		||||
			server,
 | 
			
		||||
			port,
 | 
			
		||||
			mail,
 | 
			
		||||
			password,
 | 
			
		||||
			request
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		helpers.async(curl, function(f)
 | 
			
		||||
			imap_now = { ['MESSAGES'] = 0, ['RECENT'] = 0, ['UNSEEN'] = 0 }
 | 
			
		||||
 | 
			
		||||
			for s, d in f:gmatch('(%w+)%s+(%d+)') do
 | 
			
		||||
				imap_now[s] = tonumber(d)
 | 
			
		||||
			end
 | 
			
		||||
			mailcount = imap_now['UNSEEN'] -- backwards compatibility
 | 
			
		||||
			widget = imap.widget
 | 
			
		||||
 | 
			
		||||
			settings()
 | 
			
		||||
 | 
			
		||||
			if notify == 'on' and mailcount and mailcount >= 1 and mailcount > helpers.get_map(mail) then
 | 
			
		||||
				if followtag then
 | 
			
		||||
					mail_notification_preset.screen = awful.screen.focused()
 | 
			
		||||
				end
 | 
			
		||||
				naughty.notify({
 | 
			
		||||
					preset = mail_notification_preset,
 | 
			
		||||
					text = string.format(
 | 
			
		||||
						'%s has <b>%d</b> new message%s',
 | 
			
		||||
						mail,
 | 
			
		||||
						mailcount,
 | 
			
		||||
						mailcount == 1 and '' or 's'
 | 
			
		||||
					),
 | 
			
		||||
				})
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			helpers.set_map(mail, imap_now['UNSEEN'])
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	imap.timer = helpers.newtimer(mail, timeout, imap.update, true, true)
 | 
			
		||||
 | 
			
		||||
	return imap
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										19
									
								
								awesome/lib/lain/widget/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								awesome/lib/lain/widget/init.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Lain
 | 
			
		||||
     Layouts, widgets and utilities for Awesome WM
 | 
			
		||||
 | 
			
		||||
     Widgets section
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013,      Luca CPZ
 | 
			
		||||
      * (c) 2010-2012, Peter Hofmann
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local wrequire = require('lain.helpers').wrequire
 | 
			
		||||
local setmetatable = setmetatable
 | 
			
		||||
 | 
			
		||||
local widget = { _NAME = 'lain.widget' }
 | 
			
		||||
 | 
			
		||||
return setmetatable(widget, { __index = wrequire })
 | 
			
		||||
							
								
								
									
										58
									
								
								awesome/lib/lain/widget/mem.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								awesome/lib/lain/widget/mem.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013,      Luca CPZ
 | 
			
		||||
      * (c) 2010-2012, Peter Hofmann
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local gmatch, lines, floor = string.gmatch, io.lines, math.floor
 | 
			
		||||
 | 
			
		||||
-- Memory usage (ignoring caches)
 | 
			
		||||
-- lain.widget.mem
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local mem = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 2
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	function mem.update()
 | 
			
		||||
		mem_now = {}
 | 
			
		||||
		for line in lines('/proc/meminfo') do
 | 
			
		||||
			for k, v in gmatch(line, '([%a]+):[%s]+([%d]+).+') do
 | 
			
		||||
				if k == 'MemTotal' then
 | 
			
		||||
					mem_now.total = floor(v / 1024 + 0.5)
 | 
			
		||||
				elseif k == 'MemFree' then
 | 
			
		||||
					mem_now.free = floor(v / 1024 + 0.5)
 | 
			
		||||
				elseif k == 'Buffers' then
 | 
			
		||||
					mem_now.buf = floor(v / 1024 + 0.5)
 | 
			
		||||
				elseif k == 'Cached' then
 | 
			
		||||
					mem_now.cache = floor(v / 1024 + 0.5)
 | 
			
		||||
				elseif k == 'SwapTotal' then
 | 
			
		||||
					mem_now.swap = floor(v / 1024 + 0.5)
 | 
			
		||||
				elseif k == 'SwapFree' then
 | 
			
		||||
					mem_now.swapf = floor(v / 1024 + 0.5)
 | 
			
		||||
				elseif k == 'SReclaimable' then
 | 
			
		||||
					mem_now.srec = floor(v / 1024 + 0.5)
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		mem_now.used = mem_now.total - mem_now.free - mem_now.buf - mem_now.cache - mem_now.srec
 | 
			
		||||
		mem_now.swapused = mem_now.swap - mem_now.swapf
 | 
			
		||||
		mem_now.perc = math.floor(mem_now.used / mem_now.total * 100)
 | 
			
		||||
 | 
			
		||||
		widget = mem.widget
 | 
			
		||||
		settings()
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('mem', timeout, mem.update)
 | 
			
		||||
 | 
			
		||||
	return mem
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										159
									
								
								awesome/lib/lain/widget/mpd.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								awesome/lib/lain/widget/mpd.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
      * (c) 2010, Adrian C. <anrxc@sysphere.org>
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local shell = require('awful.util').shell
 | 
			
		||||
local escape_f = require('awful.util').escape
 | 
			
		||||
local focused = require('awful.screen').focused
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local os = os
 | 
			
		||||
local string = string
 | 
			
		||||
 | 
			
		||||
-- MPD infos
 | 
			
		||||
-- lain.widget.mpd
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local mpd = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 2
 | 
			
		||||
	local password = (args.password and #args.password > 0 and string.format('password %s\\n', args.password)) or ''
 | 
			
		||||
	local host = args.host or os.getenv('MPD_HOST') or '127.0.0.1'
 | 
			
		||||
	local port = args.port or os.getenv('MPD_PORT') or '6600'
 | 
			
		||||
	local music_dir = args.music_dir or os.getenv('HOME') .. '/Music'
 | 
			
		||||
	local cover_pattern = args.cover_pattern or '*\\.(jpg|jpeg|png|gif)$'
 | 
			
		||||
	local cover_size = args.cover_size or 100
 | 
			
		||||
	local default_art = args.default_art
 | 
			
		||||
	local notify = args.notify or 'on'
 | 
			
		||||
	local followtag = args.followtag or false
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	local mpdh = string.format('telnet://%s:%s', host, port)
 | 
			
		||||
	local echo = string.format('printf "%sstatus\\ncurrentsong\\nclose\\n"', password)
 | 
			
		||||
	local cmd = string.format('%s | curl --connect-timeout 1 -fsm 3 %s', echo, mpdh)
 | 
			
		||||
 | 
			
		||||
	mpd_notification_preset = { title = 'Now playing', timeout = 6 }
 | 
			
		||||
 | 
			
		||||
	helpers.set_map('current mpd track', nil)
 | 
			
		||||
 | 
			
		||||
	function mpd.update()
 | 
			
		||||
		helpers.async({ shell, '-c', cmd }, function(f)
 | 
			
		||||
			mpd_now = {
 | 
			
		||||
				random_mode = false,
 | 
			
		||||
				single_mode = false,
 | 
			
		||||
				repeat_mode = false,
 | 
			
		||||
				consume_mode = false,
 | 
			
		||||
				pls_pos = 'N/A',
 | 
			
		||||
				pls_len = 'N/A',
 | 
			
		||||
				state = 'N/A',
 | 
			
		||||
				file = 'N/A',
 | 
			
		||||
				name = 'N/A',
 | 
			
		||||
				artist = 'N/A',
 | 
			
		||||
				title = 'N/A',
 | 
			
		||||
				album = 'N/A',
 | 
			
		||||
				genre = 'N/A',
 | 
			
		||||
				track = 'N/A',
 | 
			
		||||
				date = 'N/A',
 | 
			
		||||
				time = 'N/A',
 | 
			
		||||
				elapsed = 'N/A',
 | 
			
		||||
				volume = 'N/A',
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for line in string.gmatch(f, '[^\n]+') 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 == 'Name' then
 | 
			
		||||
						mpd_now.name = escape_f(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 == 'Genre' then
 | 
			
		||||
						mpd_now.genre = escape_f(v)
 | 
			
		||||
					elseif k == 'Track' then
 | 
			
		||||
						mpd_now.track = escape_f(v)
 | 
			
		||||
					elseif k == 'Date' then
 | 
			
		||||
						mpd_now.date = escape_f(v)
 | 
			
		||||
					elseif k == 'Time' then
 | 
			
		||||
						mpd_now.time = v
 | 
			
		||||
					elseif k == 'elapsed' then
 | 
			
		||||
						mpd_now.elapsed = string.match(v, '%d+')
 | 
			
		||||
					elseif k == 'song' then
 | 
			
		||||
						mpd_now.pls_pos = v
 | 
			
		||||
					elseif k == 'playlistlength' then
 | 
			
		||||
						mpd_now.pls_len = v
 | 
			
		||||
					elseif k == 'repeat' then
 | 
			
		||||
						mpd_now.repeat_mode = v ~= '0'
 | 
			
		||||
					elseif k == 'single' then
 | 
			
		||||
						mpd_now.single_mode = v ~= '0'
 | 
			
		||||
					elseif k == 'random' then
 | 
			
		||||
						mpd_now.random_mode = v ~= '0'
 | 
			
		||||
					elseif k == 'consume' then
 | 
			
		||||
						mpd_now.consume_mode = v ~= '0'
 | 
			
		||||
					elseif k == 'volume' then
 | 
			
		||||
						mpd_now.volume = v
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			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 notify == 'on' and mpd_now.title ~= helpers.get_map('current mpd track') then
 | 
			
		||||
					helpers.set_map('current mpd track', mpd_now.title)
 | 
			
		||||
 | 
			
		||||
					if followtag then
 | 
			
		||||
						mpd_notification_preset.screen = focused()
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					local common = {
 | 
			
		||||
						preset = mpd_notification_preset,
 | 
			
		||||
						icon = default_art,
 | 
			
		||||
						icon_size = cover_size,
 | 
			
		||||
						replaces_id = mpd.id,
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if not string.match(mpd_now.file, 'http.*://') then -- local file instead of http stream
 | 
			
		||||
						local path = string.format('%s/%s', music_dir, string.match(mpd_now.file, '.*/'))
 | 
			
		||||
						local cover = string.format(
 | 
			
		||||
							"find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'",
 | 
			
		||||
							path:gsub("'", "'\\''"),
 | 
			
		||||
							cover_pattern
 | 
			
		||||
						)
 | 
			
		||||
						helpers.async({ shell, '-c', cover }, function(current_icon)
 | 
			
		||||
							common.icon = current_icon:gsub('\n', '')
 | 
			
		||||
							if #common.icon == 0 then
 | 
			
		||||
								common.icon = nil
 | 
			
		||||
							end
 | 
			
		||||
							mpd.id = naughty.notify(common).id
 | 
			
		||||
						end)
 | 
			
		||||
					else
 | 
			
		||||
						mpd.id = naughty.notify(common).id
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			elseif mpd_now.state ~= 'pause' then
 | 
			
		||||
				helpers.set_map('current mpd track', nil)
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	mpd.timer = helpers.newtimer('mpd', timeout, mpd.update, true, true)
 | 
			
		||||
 | 
			
		||||
	return mpd
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										133
									
								
								awesome/lib/lain/widget/net.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								awesome/lib/lain/widget/net.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013,      Luca CPZ
 | 
			
		||||
      * (c) 2010-2012, Peter Hofmann
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local string = string
 | 
			
		||||
 | 
			
		||||
-- Network infos
 | 
			
		||||
-- lain.widget.net
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local net = { widget = args.widget or wibox.widget.textbox(), devices = {} }
 | 
			
		||||
	local timeout = args.timeout or 2
 | 
			
		||||
	local units = args.units or 1024 -- KB
 | 
			
		||||
	local notify = args.notify or 'on'
 | 
			
		||||
	local wifi_state = args.wifi_state or 'off'
 | 
			
		||||
	local eth_state = args.eth_state or 'off'
 | 
			
		||||
	local screen = args.screen or 1
 | 
			
		||||
	local format = args.format or '%.1f'
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	-- Compatibility with old API where iface was a string corresponding to 1 interface
 | 
			
		||||
	net.iface = (
 | 
			
		||||
		args.iface and (type(args.iface) == 'string' and { args.iface })
 | 
			
		||||
		or (type(args.iface) == 'table' and args.iface)
 | 
			
		||||
	) or {}
 | 
			
		||||
 | 
			
		||||
	function net.get_devices()
 | 
			
		||||
		net.iface = {} -- reset at every call
 | 
			
		||||
		helpers.line_callback('ip link', function(line)
 | 
			
		||||
			net.iface[#net.iface + 1] = not string.match(line, 'LOOPBACK') and string.match(line, '(%w+): <') or nil
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if #net.iface == 0 then
 | 
			
		||||
		net.get_devices()
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function net.update()
 | 
			
		||||
		-- These are the totals over all specified interfaces
 | 
			
		||||
		net_now = {
 | 
			
		||||
			devices = {},
 | 
			
		||||
			-- Bytes since last iteration
 | 
			
		||||
			sent = 0,
 | 
			
		||||
			received = 0,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, dev in ipairs(net.iface) do
 | 
			
		||||
			local dev_now = {}
 | 
			
		||||
			local dev_before = net.devices[dev] or { last_t = 0, last_r = 0 }
 | 
			
		||||
			local now_t = tonumber(helpers.first_line(string.format('/sys/class/net/%s/statistics/tx_bytes', dev)) or 0)
 | 
			
		||||
			local now_r = tonumber(helpers.first_line(string.format('/sys/class/net/%s/statistics/rx_bytes', dev)) or 0)
 | 
			
		||||
 | 
			
		||||
			dev_now.carrier = helpers.first_line(string.format('/sys/class/net/%s/carrier', dev)) or '0'
 | 
			
		||||
			dev_now.state = helpers.first_line(string.format('/sys/class/net/%s/operstate', dev)) or 'down'
 | 
			
		||||
 | 
			
		||||
			dev_now.sent = (now_t - dev_before.last_t) / timeout / units
 | 
			
		||||
			dev_now.received = (now_r - dev_before.last_r) / timeout / units
 | 
			
		||||
 | 
			
		||||
			net_now.sent = net_now.sent + dev_now.sent
 | 
			
		||||
			net_now.received = net_now.received + dev_now.received
 | 
			
		||||
 | 
			
		||||
			dev_now.sent = string.format(format, dev_now.sent)
 | 
			
		||||
			dev_now.received = string.format(format, dev_now.received)
 | 
			
		||||
 | 
			
		||||
			dev_now.last_t = now_t
 | 
			
		||||
			dev_now.last_r = now_r
 | 
			
		||||
 | 
			
		||||
			if
 | 
			
		||||
				wifi_state == 'on'
 | 
			
		||||
				and helpers.first_line(string.format('/sys/class/net/%s/uevent', dev)) == 'DEVTYPE=wlan'
 | 
			
		||||
			then
 | 
			
		||||
				dev_now.wifi = true
 | 
			
		||||
				if string.match(dev_now.carrier, '1') then
 | 
			
		||||
					dev_now.signal = tonumber(string.match(helpers.lines_from('/proc/net/wireless')[3], '(%-%d+%.)'))
 | 
			
		||||
						or nil
 | 
			
		||||
				end
 | 
			
		||||
			else
 | 
			
		||||
				dev_now.wifi = false
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			if
 | 
			
		||||
				eth_state == 'on'
 | 
			
		||||
				and helpers.first_line(string.format('/sys/class/net/%s/uevent', dev)) ~= 'DEVTYPE=wlan'
 | 
			
		||||
			then
 | 
			
		||||
				dev_now.ethernet = true
 | 
			
		||||
			else
 | 
			
		||||
				dev_now.ethernet = false
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			net.devices[dev] = dev_now
 | 
			
		||||
 | 
			
		||||
			-- Notify only once when connection is lost
 | 
			
		||||
			if string.match(dev_now.carrier, '0') and notify == 'on' and helpers.get_map(dev) then
 | 
			
		||||
				naughty.notify({
 | 
			
		||||
					title = dev,
 | 
			
		||||
					text = 'No carrier',
 | 
			
		||||
					icon = helpers.icons_dir .. 'no_net.png',
 | 
			
		||||
					screen = screen,
 | 
			
		||||
				})
 | 
			
		||||
				helpers.set_map(dev, false)
 | 
			
		||||
			elseif string.match(dev_now.carrier, '1') then
 | 
			
		||||
				helpers.set_map(dev, true)
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			net_now.carrier = dev_now.carrier
 | 
			
		||||
			net_now.state = dev_now.state
 | 
			
		||||
			net_now.devices[dev] = dev_now
 | 
			
		||||
			-- net_now.sent and net_now.received will be
 | 
			
		||||
			-- the totals across all specified devices
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		net_now.sent = string.format(format, net_now.sent)
 | 
			
		||||
		net_now.received = string.format(format, net_now.received)
 | 
			
		||||
 | 
			
		||||
		widget = net.widget
 | 
			
		||||
		settings()
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('network', timeout, net.update)
 | 
			
		||||
 | 
			
		||||
	return net
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										60
									
								
								awesome/lib/lain/widget/pulse.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								awesome/lib/lain/widget/pulse.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2016, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local shell = require('awful.util').shell
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local string = string
 | 
			
		||||
local type = type
 | 
			
		||||
 | 
			
		||||
-- PulseAudio volume
 | 
			
		||||
-- lain.widget.pulse
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local pulse = { widget = args.widget or wibox.widget.textbox(), device = 'N/A' }
 | 
			
		||||
	local timeout = args.timeout or 5
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	pulse.devicetype = args.devicetype or 'sink'
 | 
			
		||||
	pulse.cmd = args.cmd
 | 
			
		||||
		or 'pacmd list-'
 | 
			
		||||
			.. pulse.devicetype
 | 
			
		||||
			.. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
 | 
			
		||||
 | 
			
		||||
	function pulse.update()
 | 
			
		||||
		helpers.async({ shell, '-c', type(pulse.cmd) == 'string' and pulse.cmd or pulse.cmd() }, function(s)
 | 
			
		||||
			volume_now = {
 | 
			
		||||
				index = string.match(s, 'index: (%S+)') or 'N/A',
 | 
			
		||||
				device = string.match(s, 'device.string = "(%S+)"') or 'N/A',
 | 
			
		||||
				muted = string.match(s, 'muted: (%S+)') or 'N/A',
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			pulse.device = volume_now.index
 | 
			
		||||
 | 
			
		||||
			local ch = 1
 | 
			
		||||
			volume_now.channel = {}
 | 
			
		||||
			for v in string.gmatch(s, ':.-(%d+)%%') do
 | 
			
		||||
				volume_now.channel[ch] = v
 | 
			
		||||
				ch = ch + 1
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			volume_now.left = volume_now.channel[1] or 'N/A'
 | 
			
		||||
			volume_now.right = volume_now.channel[2] or 'N/A'
 | 
			
		||||
 | 
			
		||||
			widget = pulse.widget
 | 
			
		||||
			settings()
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('pulse', timeout, pulse.update)
 | 
			
		||||
 | 
			
		||||
	return pulse
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										185
									
								
								awesome/lib/lain/widget/pulsebar.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								awesome/lib/lain/widget/pulsebar.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,185 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
      * (c) 2013, Rman
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local awful = require('awful')
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local math = math
 | 
			
		||||
local string = string
 | 
			
		||||
local type = type
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
 | 
			
		||||
-- PulseAudio volume bar
 | 
			
		||||
-- lain.widget.pulsebar
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	local pulsebar = {
 | 
			
		||||
		colors = {
 | 
			
		||||
			background = '#000000',
 | 
			
		||||
			mute_background = '#000000',
 | 
			
		||||
			mute = '#EB8F8F',
 | 
			
		||||
			unmute = '#A4CE8A',
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		_current_level = 0,
 | 
			
		||||
		_mute = 'no',
 | 
			
		||||
		device = 'N/A',
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local timeout = args.timeout or 5
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
	local width = args.width or 63
 | 
			
		||||
	local height = args.height or 1
 | 
			
		||||
	local margins = args.margins or 1
 | 
			
		||||
	local paddings = args.paddings or 1
 | 
			
		||||
	local ticks = args.ticks or false
 | 
			
		||||
	local ticks_size = args.ticks_size or 7
 | 
			
		||||
	local tick = args.tick or '|'
 | 
			
		||||
	local tick_pre = args.tick_pre or '['
 | 
			
		||||
	local tick_post = args.tick_post or ']'
 | 
			
		||||
	local tick_none = args.tick_none or ' '
 | 
			
		||||
 | 
			
		||||
	pulsebar.colors = args.colors or pulsebar.colors
 | 
			
		||||
	pulsebar.followtag = args.followtag or false
 | 
			
		||||
	pulsebar.notification_preset = args.notification_preset
 | 
			
		||||
	pulsebar.devicetype = args.devicetype or 'sink'
 | 
			
		||||
	pulsebar.cmd = args.cmd
 | 
			
		||||
		or 'pacmd list-'
 | 
			
		||||
			.. pulsebar.devicetype
 | 
			
		||||
			.. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
 | 
			
		||||
 | 
			
		||||
	if not pulsebar.notification_preset then
 | 
			
		||||
		pulsebar.notification_preset = {
 | 
			
		||||
			font = 'Monospace 10',
 | 
			
		||||
		}
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	pulsebar.bar = wibox.widget({
 | 
			
		||||
		color = pulsebar.colors.unmute,
 | 
			
		||||
		background_color = pulsebar.colors.background,
 | 
			
		||||
		forced_height = height,
 | 
			
		||||
		forced_width = width,
 | 
			
		||||
		margins = margins,
 | 
			
		||||
		paddings = paddings,
 | 
			
		||||
		ticks = ticks,
 | 
			
		||||
		ticks_size = ticks_size,
 | 
			
		||||
		widget = wibox.widget.progressbar,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
 | 
			
		||||
 | 
			
		||||
	function pulsebar.update(callback)
 | 
			
		||||
		helpers.async(
 | 
			
		||||
			{ awful.util.shell, '-c', type(pulsebar.cmd) == 'string' and pulsebar.cmd or pulsebar.cmd() },
 | 
			
		||||
			function(s)
 | 
			
		||||
				volume_now = {
 | 
			
		||||
					index = string.match(s, 'index: (%S+)') or 'N/A',
 | 
			
		||||
					device = string.match(s, 'device.string = "(%S+)"') or 'N/A',
 | 
			
		||||
					muted = string.match(s, 'muted: (%S+)') or 'N/A',
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				pulsebar.device = volume_now.index
 | 
			
		||||
 | 
			
		||||
				local ch = 1
 | 
			
		||||
				volume_now.channel = {}
 | 
			
		||||
				for v in string.gmatch(s, ':.-(%d+)%%') do
 | 
			
		||||
					volume_now.channel[ch] = v
 | 
			
		||||
					ch = ch + 1
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				volume_now.left = volume_now.channel[1] or 'N/A'
 | 
			
		||||
				volume_now.right = volume_now.channel[2] or 'N/A'
 | 
			
		||||
 | 
			
		||||
				local volu = volume_now.left
 | 
			
		||||
				local mute = volume_now.muted
 | 
			
		||||
 | 
			
		||||
				if volu:match('N/A') or mute:match('N/A') then
 | 
			
		||||
					return
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then
 | 
			
		||||
					pulsebar._current_level = tonumber(volu)
 | 
			
		||||
					pulsebar.bar:set_value(pulsebar._current_level / 100)
 | 
			
		||||
					if pulsebar._current_level == 0 or mute == 'yes' then
 | 
			
		||||
						pulsebar._mute = mute
 | 
			
		||||
						pulsebar.tooltip:set_text('[muted]')
 | 
			
		||||
						pulsebar.bar.color = pulsebar.colors.mute
 | 
			
		||||
						pulsebar.bar.background_color = pulsebar.colors.mute_background
 | 
			
		||||
					else
 | 
			
		||||
						pulsebar._mute = 'no'
 | 
			
		||||
						pulsebar.tooltip:set_text(
 | 
			
		||||
							string.format('%s %s: %s', pulsebar.devicetype, pulsebar.device, volu)
 | 
			
		||||
						)
 | 
			
		||||
						pulsebar.bar.color = pulsebar.colors.unmute
 | 
			
		||||
						pulsebar.bar.background_color = pulsebar.colors.background
 | 
			
		||||
					end
 | 
			
		||||
 | 
			
		||||
					settings()
 | 
			
		||||
 | 
			
		||||
					if type(callback) == 'function' then
 | 
			
		||||
						callback()
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function pulsebar.notify()
 | 
			
		||||
		pulsebar.update(function()
 | 
			
		||||
			local preset = pulsebar.notification_preset
 | 
			
		||||
 | 
			
		||||
			preset.title = string.format('%s %s - %s%%', pulsebar.devicetype, pulsebar.device, pulsebar._current_level)
 | 
			
		||||
 | 
			
		||||
			if pulsebar._mute == 'yes' then
 | 
			
		||||
				preset.title = preset.title .. ' muted'
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			-- tot is the maximum number of ticks to display in the notification
 | 
			
		||||
			-- fallback: default horizontal wibox height
 | 
			
		||||
			local wib, tot = awful.screen.focused().mywibox, 20
 | 
			
		||||
 | 
			
		||||
			-- if we can grab mywibox, tot is defined as its height if
 | 
			
		||||
			-- horizontal, or width otherwise
 | 
			
		||||
			if wib then
 | 
			
		||||
				if wib.position == 'left' or wib.position == 'right' then
 | 
			
		||||
					tot = wib.width
 | 
			
		||||
				else
 | 
			
		||||
					tot = wib.height
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			local int = math.modf((pulsebar._current_level / 100) * tot)
 | 
			
		||||
			preset.text =
 | 
			
		||||
				string.format('%s%s%s%s', tick_pre, string.rep(tick, int), string.rep(tick_none, tot - int), tick_post)
 | 
			
		||||
 | 
			
		||||
			if pulsebar.followtag then
 | 
			
		||||
				preset.screen = awful.screen.focused()
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			if not pulsebar.notification then
 | 
			
		||||
				pulsebar.notification = naughty.notify({
 | 
			
		||||
					preset = preset,
 | 
			
		||||
					destroy = function()
 | 
			
		||||
						pulsebar.notification = nil
 | 
			
		||||
					end,
 | 
			
		||||
				})
 | 
			
		||||
			else
 | 
			
		||||
				naughty.replace_text(pulsebar.notification, preset.title, preset.text)
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer(string.format('pulsebar-%s-%s', pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update)
 | 
			
		||||
 | 
			
		||||
	return pulsebar
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										39
									
								
								awesome/lib/lain/widget/sysload.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								awesome/lib/lain/widget/sysload.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013,      Luca CPZ
 | 
			
		||||
      * (c) 2010-2012, Peter Hofmann
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local open, match = io.open, string.match
 | 
			
		||||
 | 
			
		||||
-- System load
 | 
			
		||||
-- lain.widget.sysload
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local sysload = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 2
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	function sysload.update()
 | 
			
		||||
		local f = open('/proc/loadavg')
 | 
			
		||||
		local ret = f:read('*all')
 | 
			
		||||
		f:close()
 | 
			
		||||
 | 
			
		||||
		load_1, load_5, load_15 = match(ret, '([^%s]+) ([^%s]+) ([^%s]+)')
 | 
			
		||||
 | 
			
		||||
		widget = sysload.widget
 | 
			
		||||
		settings()
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('sysload', timeout, sysload.update)
 | 
			
		||||
 | 
			
		||||
	return sysload
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										50
									
								
								awesome/lib/lain/widget/temp.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								awesome/lib/lain/widget/temp.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2013, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
 | 
			
		||||
-- {thermal,core} temperature info
 | 
			
		||||
-- lain.widget.temp
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local temp = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local timeout = args.timeout or 30
 | 
			
		||||
	local tempfile = args.tempfile or '/sys/devices/virtual/thermal/thermal_zone0/temp'
 | 
			
		||||
	local format = args.format or '%.1f'
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	function temp.update()
 | 
			
		||||
		helpers.async({ 'find', '/sys/devices', '-type', 'f', '-name', '*temp*' }, function(f)
 | 
			
		||||
			temp_now = {}
 | 
			
		||||
			local temp_fl, temp_value
 | 
			
		||||
			for t in f:gmatch('[^\n]+') do
 | 
			
		||||
				temp_fl = helpers.first_line(t)
 | 
			
		||||
				if temp_fl then
 | 
			
		||||
					temp_value = tonumber(temp_fl)
 | 
			
		||||
					temp_now[t] = temp_value and temp_value / 1e3 or temp_fl
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
			if temp_now[tempfile] then
 | 
			
		||||
				coretemp_now = string.format(format, temp_now[tempfile])
 | 
			
		||||
			else
 | 
			
		||||
				coretemp_now = 'N/A'
 | 
			
		||||
			end
 | 
			
		||||
			widget = temp.widget
 | 
			
		||||
			settings()
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	helpers.newtimer('thermal', timeout, temp.update)
 | 
			
		||||
 | 
			
		||||
	return temp
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
							
								
								
									
										151
									
								
								awesome/lib/lain/widget/weather.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								awesome/lib/lain/widget/weather.lua
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
--[[
 | 
			
		||||
 | 
			
		||||
     Licensed under GNU General Public License v2
 | 
			
		||||
      * (c) 2015, Luca CPZ
 | 
			
		||||
 | 
			
		||||
--]]
 | 
			
		||||
 | 
			
		||||
local helpers = require('lain.helpers')
 | 
			
		||||
local json = require('lain.util').dkjson
 | 
			
		||||
local focused = require('awful.screen').focused
 | 
			
		||||
local naughty = require('naughty')
 | 
			
		||||
local wibox = require('wibox')
 | 
			
		||||
local math = math
 | 
			
		||||
local os = os
 | 
			
		||||
local string = string
 | 
			
		||||
local type = type
 | 
			
		||||
local tonumber = tonumber
 | 
			
		||||
 | 
			
		||||
-- OpenWeatherMap
 | 
			
		||||
-- current weather and X-days forecast
 | 
			
		||||
-- lain.widget.weather
 | 
			
		||||
 | 
			
		||||
local function factory(args)
 | 
			
		||||
	args = args or {}
 | 
			
		||||
 | 
			
		||||
	local weather = { widget = args.widget or wibox.widget.textbox() }
 | 
			
		||||
	local APPID = args.APPID -- mandatory
 | 
			
		||||
	local timeout = args.timeout or 60 * 15 -- 15 min
 | 
			
		||||
	local current_call = args.current_call
 | 
			
		||||
		or "curl -s 'https://api.openweathermap.org/data/2.5/weather?id=%s&units=%s&lang=%s&APPID=%s'"
 | 
			
		||||
	local forecast_call = args.forecast_call
 | 
			
		||||
		or "curl -s 'https://api.openweathermap.org/data/2.5/forecast?id=%s&units=%s&lang=%s&APPID=%s'"
 | 
			
		||||
	local city_id = args.city_id or 0 -- placeholder
 | 
			
		||||
	local units = args.units or 'metric'
 | 
			
		||||
	local lang = args.lang or 'en'
 | 
			
		||||
	local cnt = args.cnt or 5
 | 
			
		||||
	local icons_path = args.icons_path or helpers.icons_dir .. 'openweathermap/'
 | 
			
		||||
	local notification_preset = args.notification_preset or {}
 | 
			
		||||
	local notification_text_fun = args.notification_text_fun
 | 
			
		||||
		or function(wn)
 | 
			
		||||
			local day = os.date('%a %d', wn['dt'])
 | 
			
		||||
			local temp = math.floor(wn['main']['temp'])
 | 
			
		||||
			local desc = wn['weather'][1]['description']
 | 
			
		||||
			return string.format('<b>%s</b>: %s, %d ', day, desc, temp)
 | 
			
		||||
		end
 | 
			
		||||
	local weather_na_markup = args.weather_na_markup or ' N/A '
 | 
			
		||||
	local followtag = args.followtag or false
 | 
			
		||||
	local showpopup = args.showpopup or 'on'
 | 
			
		||||
	local settings = args.settings or function() end
 | 
			
		||||
 | 
			
		||||
	weather.widget:set_markup(weather_na_markup)
 | 
			
		||||
	weather.icon_path = icons_path .. 'na.png'
 | 
			
		||||
	weather.icon = wibox.widget.imagebox(weather.icon_path)
 | 
			
		||||
 | 
			
		||||
	function weather.show(seconds)
 | 
			
		||||
		weather.hide()
 | 
			
		||||
 | 
			
		||||
		if followtag then
 | 
			
		||||
			notification_preset.screen = focused()
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		if not weather.notification_text then
 | 
			
		||||
			weather.update()
 | 
			
		||||
			weather.forecast_update()
 | 
			
		||||
		end
 | 
			
		||||
 | 
			
		||||
		weather.notification = naughty.notify({
 | 
			
		||||
			preset = notification_preset,
 | 
			
		||||
			text = weather.notification_text,
 | 
			
		||||
			icon = weather.icon_path,
 | 
			
		||||
			timeout = type(seconds) == 'number' and seconds or notification_preset.timeout,
 | 
			
		||||
		})
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function weather.hide()
 | 
			
		||||
		if weather.notification then
 | 
			
		||||
			naughty.destroy(weather.notification)
 | 
			
		||||
			weather.notification = nil
 | 
			
		||||
		end
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function weather.attach(obj)
 | 
			
		||||
		obj:connect_signal('mouse::enter', function()
 | 
			
		||||
			weather.show(0)
 | 
			
		||||
		end)
 | 
			
		||||
		obj:connect_signal('mouse::leave', function()
 | 
			
		||||
			weather.hide()
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function weather.forecast_update()
 | 
			
		||||
		local cmd = string.format(forecast_call, city_id, units, lang, APPID)
 | 
			
		||||
		helpers.async(cmd, function(f)
 | 
			
		||||
			local err
 | 
			
		||||
			weather_now, _, err = json.decode(f, 1, nil)
 | 
			
		||||
 | 
			
		||||
			if not err and type(weather_now) == 'table' and tonumber(weather_now['cod']) == 200 then
 | 
			
		||||
				weather.notification_text = ''
 | 
			
		||||
				for i = 1, weather_now['cnt'], math.floor(weather_now['cnt'] / cnt) do
 | 
			
		||||
					weather.notification_text = weather.notification_text
 | 
			
		||||
						.. notification_text_fun(weather_now['list'][i])
 | 
			
		||||
					if i < weather_now['cnt'] then
 | 
			
		||||
						weather.notification_text = weather.notification_text .. '\n'
 | 
			
		||||
					end
 | 
			
		||||
				end
 | 
			
		||||
			end
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	function weather.update()
 | 
			
		||||
		local cmd = string.format(current_call, city_id, units, lang, APPID)
 | 
			
		||||
		helpers.async(cmd, function(f)
 | 
			
		||||
			local err
 | 
			
		||||
			weather_now, _, err = json.decode(f, 1, nil)
 | 
			
		||||
 | 
			
		||||
			if not err and type(weather_now) == 'table' and tonumber(weather_now['cod']) == 200 then
 | 
			
		||||
				local sunrise = tonumber(weather_now['sys']['sunrise'])
 | 
			
		||||
				local sunset = tonumber(weather_now['sys']['sunset'])
 | 
			
		||||
				local icon = weather_now['weather'][1]['icon']
 | 
			
		||||
				local loc_now = os.time()
 | 
			
		||||
 | 
			
		||||
				if sunrise <= loc_now and loc_now <= sunset then
 | 
			
		||||
					icon = string.gsub(icon, 'n', 'd')
 | 
			
		||||
				else
 | 
			
		||||
					icon = string.gsub(icon, 'd', 'n')
 | 
			
		||||
				end
 | 
			
		||||
 | 
			
		||||
				weather.icon_path = icons_path .. icon .. '.png'
 | 
			
		||||
				widget = weather.widget
 | 
			
		||||
				settings()
 | 
			
		||||
			else
 | 
			
		||||
				weather.icon_path = icons_path .. 'na.png'
 | 
			
		||||
				weather.widget:set_markup(weather_na_markup)
 | 
			
		||||
			end
 | 
			
		||||
 | 
			
		||||
			weather.icon:set_image(weather.icon_path)
 | 
			
		||||
		end)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	if showpopup == 'on' then
 | 
			
		||||
		weather.attach(weather.widget)
 | 
			
		||||
	end
 | 
			
		||||
 | 
			
		||||
	weather.timer = helpers.newtimer('weather-' .. city_id, timeout, weather.update, false, true)
 | 
			
		||||
	weather.timer_forecast =
 | 
			
		||||
		helpers.newtimer('weather_forecast-' .. city_id, timeout, weather.forecast_update, false, true)
 | 
			
		||||
 | 
			
		||||
	return weather
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
return factory
 | 
			
		||||
		Reference in New Issue
	
	Block a user