Added settings.lua

This commit is contained in:
Mutzi 2023-01-25 20:10:58 +01:00
parent 80cc950271
commit 5cf452e053
38 changed files with 3880 additions and 3450 deletions

View File

@ -11,10 +11,10 @@
--]] --]]
local awful = require("awful") local awful = require('awful')
local theme = require("beautiful") local theme = require('beautiful')
local utils = require("menubar.utils") local utils = require('menubar.utils')
local wibox = require("wibox") local wibox = require('wibox')
local io = io local io = io
local ipairs = ipairs local ipairs = ipairs
@ -30,20 +30,20 @@ local desktop = {
-- Default desktop basic icons -- Default desktop basic icons
baseicons = { baseicons = {
[1] = { [1] = {
label = "This PC", label = 'This PC',
icon = "computer", icon = 'computer',
onclick = "computer://" onclick = 'computer://',
}, },
[2] = { [2] = {
label = "Home", label = 'Home',
icon = "user-home", icon = 'user-home',
onclick = os.getenv("HOME") onclick = os.getenv('HOME'),
}, },
[3] = { [3] = {
label = "Trash", label = 'Trash',
icon = "user-trash", icon = 'user-trash',
onclick = "trash://" onclick = 'trash://',
} },
}, },
-- Default parameters -- Default parameters
iconsize = { width = 48, height = 48 }, iconsize = { width = 48, height = 48 },
@ -62,7 +62,9 @@ local function pipelines(...)
local f = assert(io.popen(...)) local f = assert(io.popen(...))
return function() return function()
local data = f:read() local data = f:read()
if data == nil then f:close() end if data == nil then
f:close()
end
return data return data
end end
end end
@ -78,18 +80,23 @@ function desktop.add_single_icon(args, label, icon, onclick)
-- define icon dimensions and position -- define icon dimensions and position
if not dcp[s] then if not dcp[s] then
dcp[s] = { x = (screen[s].geometry.x + args.iconsize.width + args.margin.x), y = screen[s].geometry.y + 20 + args.margin.y } dcp[s] = {
x = (screen[s].geometry.x + args.iconsize.width + args.margin.x),
y = screen[s].geometry.y + 20 + args.margin.y,
}
end end
local tot_height = (icon and args.iconsize.height or 0) + (label and args.labelsize.height or 0) local tot_height = (icon and args.iconsize.height or 0) + (label and args.labelsize.height or 0)
if tot_height == 0 then return end if tot_height == 0 then
return
end
if dcp[s].y + tot_height > screen[s].geometry.y + screen[s].geometry.height - 20 - args.margin.y then if dcp[s].y + tot_height > screen[s].geometry.y + screen[s].geometry.height - 20 - args.margin.y then
dcp[s].x = dcp[s].x + args.labelsize.width + args.iconsize.width + args.margin.x dcp[s].x = dcp[s].x + args.labelsize.width + args.iconsize.width + args.margin.x
dcp[s].y = 20 + args.margin.y dcp[s].y = 20 + args.margin.y
end end
local common = { screen = s, bg = "#00000000", visible = true, type = "desktop" } local common = { screen = s, bg = '#00000000', visible = true, type = 'desktop' }
-- create icon container -- create icon container
if icon then if icon then
@ -98,11 +105,11 @@ function desktop.add_single_icon(args, label, icon, onclick)
common.x = dcp[s].x common.x = dcp[s].x
common.y = dcp[s].y common.y = dcp[s].y
icon = wibox.widget { icon = wibox.widget({
image = icon, image = icon,
resize = false, resize = false,
widget = wibox.widget.imagebox widget = wibox.widget.imagebox,
} })
icon:buttons(awful.button({}, 1, nil, onclick)) icon:buttons(awful.button({}, 1, nil, onclick))
@ -119,14 +126,14 @@ function desktop.add_single_icon(args, label, icon, onclick)
common.x = dcp[s].x - (args.labelsize.width / 2) + args.iconsize.width / 2 common.x = dcp[s].x - (args.labelsize.width / 2) + args.iconsize.width / 2
common.y = dcp[s].y common.y = dcp[s].y
caption = wibox.widget { caption = wibox.widget({
text = label, text = label,
align = "center", align = 'center',
forced_width = common.width, forced_width = common.width,
forced_height = common.height, forced_height = common.height,
ellipsize = "middle", ellipsize = 'middle',
widget = wibox.widget.textbox widget = wibox.widget.textbox,
} })
caption:buttons(awful.button({}, 1, onclick)) caption:buttons(awful.button({}, 1, onclick))
caption_container = wibox(common) caption_container = wibox(common)
@ -156,15 +163,15 @@ end
function desktop.lookup_file_icon(filename) function desktop.lookup_file_icon(filename)
-- load system MIME types -- load system MIME types
if #mime_types == 0 then if #mime_types == 0 then
for line in io.lines("/etc/mime.types") do for line in io.lines('/etc/mime.types') do
if not line:find("^#") then if not line:find('^#') then
local parsed = {} local parsed = {}
for w in line:gmatch("[^%s]+") do for w in line:gmatch('[^%s]+') do
table.insert(parsed, w) table.insert(parsed, w)
end end
if #parsed > 1 then if #parsed > 1 then
for i = 2, #parsed do for i = 2, #parsed do
mime_types[parsed[i]] = parsed[1]:gsub("/", "-") mime_types[parsed[i]] = parsed[1]:gsub('/', '-')
end end
end end
end end
@ -172,23 +179,27 @@ function desktop.lookup_file_icon(filename)
end end
-- try to search a possible icon among standards -- try to search a possible icon among standards
local extension = filename:match("%a+$") local extension = filename:match('%a+$')
local mime = mime_types[extension] or "" local mime = mime_types[extension] or ''
local mime_family = mime:match("^%a+") or "" local mime_family = mime:match('^%a+') or ''
local possible_filenames = { local possible_filenames = {
mime, "gnome-mime-" .. mime, mime,
mime_family, "gnome-mime-" .. mime_family, 'gnome-mime-' .. mime,
extension mime_family,
'gnome-mime-' .. mime_family,
extension,
} }
for i, filename in ipairs(possible_filenames) do for i, filename in ipairs(possible_filenames) do
local icon = utils.lookup_icon(filename) local icon = utils.lookup_icon(filename)
if icon then return icon end if icon then
return icon
end
end end
-- if we don"t find ad icon, then pretend is a plain text file -- if we don"t find ad icon, then pretend is a plain text file
return utils.lookup_icon("text-x-generic") return utils.lookup_icon('text-x-generic')
end end
-- Parse subdirectories and files list from input directory -- Parse subdirectories and files list from input directory
@ -198,20 +209,20 @@ function desktop.parse_dirs_and_files(dir)
local files = {} local files = {}
local paths = pipelines('find ' .. dir .. ' -maxdepth 1 -type d |sort|tail -n +1') local paths = pipelines('find ' .. dir .. ' -maxdepth 1 -type d |sort|tail -n +1')
for path in paths do for path in paths do
if path:match("[^/]+$") then if path:match('[^/]+$') then
local file = {} local file = {}
file.filename = path:match("[^/]+$") file.filename = path:match('[^/]+$')
file.path = path file.path = path
file.show = true file.show = true
file.icon = utils.lookup_icon("folder") file.icon = utils.lookup_icon('folder')
table.insert(files, file) table.insert(files, file)
end end
end end
local paths = pipelines('find ' .. dir .. ' -maxdepth 1 -type f') local paths = pipelines('find ' .. dir .. ' -maxdepth 1 -type f')
for path in paths do for path in paths do
if not path:find("%.desktop$") then if not path:find('%.desktop$') then
local file = {} local file = {}
file.filename = path:match("[^/]+$") file.filename = path:match('[^/]+$')
file.path = path file.path = path
file.show = true file.show = true
file.icon = desktop.lookup_file_icon(file.filename) file.icon = desktop.lookup_file_icon(file.filename)
@ -227,7 +238,9 @@ function desktop.add_dirs_and_files_icons(args)
for _, file in ipairs(desktop.parse_dirs_and_files(args.dir)) do for _, file in ipairs(desktop.parse_dirs_and_files(args.dir)) do
if file.show then if file.show then
local label = args.showlabels and file.filename or nil local label = args.showlabels and file.filename or nil
local onclick = function () awful.spawn(string.format("%s '%s'", args.open_with, file.path)) end local onclick = function()
awful.spawn(string.format("%s '%s'", args.open_with, file.path))
end
desktop.add_single_icon(args, label, file.icon, onclick) desktop.add_single_icon(args, label, file.icon, onclick)
end end
end end
@ -238,9 +251,9 @@ end
function desktop.add_icons(args) function desktop.add_icons(args)
args = args or {} args = args or {}
args.screen = args.screen or mouse.screen args.screen = args.screen or mouse.screen
args.dir = args.dir or os.getenv("HOME") .. "/Desktop" args.dir = args.dir or os.getenv('HOME') .. '/Desktop'
args.showlabels = args.showlabel or true args.showlabels = args.showlabel or true
args.open_with = args.open_with or "xdg_open" args.open_with = args.open_with or 'xdg_open'
args.baseicons = args.baseicons or desktop.baseicons args.baseicons = args.baseicons or desktop.baseicons
args.iconsize = args.iconsize or desktop.iconsize args.iconsize = args.iconsize or desktop.iconsize
args.labelsize = args.labelsize or desktop.labelsize args.labelsize = args.labelsize or desktop.labelsize
@ -249,7 +262,7 @@ function desktop.add_icons(args)
-- trying to fallback on Adwaita if theme.icon_theme is not defined -- trying to fallback on Adwaita if theme.icon_theme is not defined
-- if Adwaita is missing too, no icons will be shown -- if Adwaita is missing too, no icons will be shown
if not theme.icon_theme then if not theme.icon_theme then
theme.icon_theme = args.icon_theme or "Adwaita" theme.icon_theme = args.icon_theme or 'Adwaita'
end end
desktop.add_base_icons(args) desktop.add_base_icons(args)

View File

@ -10,6 +10,6 @@
--]] --]]
return { return {
desktop = require("freedesktop.desktop"), desktop = require('freedesktop.desktop'),
menu = require("freedesktop.menu") menu = require('freedesktop.menu'),
} }

View File

@ -1,4 +1,3 @@
--[[ --[[
Awesome-Freedesktop Awesome-Freedesktop
@ -12,15 +11,15 @@
--]] --]]
local Gio = require("lgi").Gio local Gio = require('lgi').Gio
local awful_menu = require("awful.menu") local awful_menu = require('awful.menu')
local menu_gen = require("menubar.menu_gen") local menu_gen = require('menubar.menu_gen')
local menu_utils = require("menubar.utils") local menu_utils = require('menubar.utils')
local io, pairs, string, table, os = io, pairs, string, table, os local io, pairs, string, table, os = io, pairs, string, table, os
-- Expecting a wm_name of awesome omits too many applications and tools -- Expecting a wm_name of awesome omits too many applications and tools
menu_utils.wm_name = "" menu_utils.wm_name = ''
-- Menu -- Menu
-- freedesktop.menu -- freedesktop.menu
@ -30,7 +29,7 @@ local menu = {}
-- @tparam string path The directory path -- @tparam string path The directory path
-- @treturn boolean True if path exists and is a directory -- @treturn boolean True if path exists and is a directory
function menu.is_dir(path) function menu.is_dir(path)
return Gio.File.new_for_path(path):query_file_type({}) == "DIRECTORY" return Gio.File.new_for_path(path):query_file_type({}) == 'DIRECTORY'
end end
-- Remove non existent paths in order to avoid issues -- Remove non existent paths in order to avoid issues
@ -93,14 +92,18 @@ function menu.build(args)
table.remove(result, i) table.remove(result, i)
else else
--Sort entries alphabetically (by name) --Sort entries alphabetically (by name)
table.sort(v[2], function (a, b) return string.byte(a[1]) < string.byte(b[1]) end) table.sort(v[2], function(a, b)
return string.byte(a[1]) < string.byte(b[1])
end)
-- Replace category name with nice name -- Replace category name with nice name
v[1] = menu_gen.all_categories[v[1]].name v[1] = menu_gen.all_categories[v[1]].name
end end
end end
-- Sort categories alphabetically also -- Sort categories alphabetically also
table.sort(result, function(a, b) return string.byte(a[1]) < string.byte(b[1]) end) table.sort(result, function(a, b)
return string.byte(a[1]) < string.byte(b[1])
end)
-- Add menu item to hold the generated menu -- Add menu item to hold the generated menu
if sub_menu then if sub_menu then
@ -108,8 +111,12 @@ function menu.build(args)
end end
-- Add items to menu -- Add items to menu
for _, v in pairs(result) do _menu:add(v) end for _, v in pairs(result) do
for _, v in pairs(after) do _menu:add(v) end _menu:add(v)
end
for _, v in pairs(after) do
_menu:add(v)
end
end) end)
-- Hold the menu in the module -- Hold the menu in the module

View File

@ -5,11 +5,10 @@
--]] --]]
local spawn = require("awful.spawn") local spawn = require('awful.spawn')
local timer = require("gears.timer") local timer = require('gears.timer')
local debug = require("debug") local debug = require('debug')
local io = { lines = io.lines, local io = { lines = io.lines, open = io.open }
open = io.open }
local pairs = pairs local pairs = pairs
local rawget = rawget local rawget = rawget
local tsort = table.sort local tsort = table.sort
@ -19,7 +18,7 @@ local unpack = unpack or table.unpack -- lua 5.1 retro-compatibility
-- lain.helpers -- lain.helpers
local helpers = {} local helpers = {}
helpers.lain_dir = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]] helpers.lain_dir = debug.getinfo(1, 'S').source:match([[^@(.*/).*$]])
helpers.icons_dir = helpers.lain_dir .. 'icons/' helpers.icons_dir = helpers.lain_dir .. 'icons/'
helpers.scripts_dir = helpers.lain_dir .. 'scripts/' helpers.scripts_dir = helpers.lain_dir .. 'scripts/'
@ -35,8 +34,10 @@ end
-- check if the file exists and is readable -- check if the file exists and is readable
function helpers.file_exists(path) function helpers.file_exists(path)
local file = io.open(path, "rb") local file = io.open(path, 'rb')
if file then file:close() end if file then
file:close()
end
return file ~= nil return file ~= nil
end end
@ -62,9 +63,9 @@ end
-- get first line of a file -- get first line of a file
function helpers.first_line(path) function helpers.first_line(path)
local file, first = io.open(path, "rb"), nil local file, first = io.open(path, 'rb'), nil
if file then if file then
first = file:read("*l") first = file:read('*l')
file:close() file:close()
end end
return first return first
@ -73,7 +74,9 @@ end
-- get first non empty line from a file -- get first non empty line from a file
function helpers.first_nonempty_line(path) function helpers.first_nonempty_line(path)
for line in io.lines(path) do for line in io.lines(path) do
if #line then return line end if #line then
return line
end
end end
return nil return nil
end end
@ -85,15 +88,17 @@ end
helpers.timer_table = {} helpers.timer_table = {}
function helpers.newtimer(name, timeout, fun, nostart, stoppable) function helpers.newtimer(name, timeout, fun, nostart, stoppable)
if not name or #name == 0 then return end if not name or #name == 0 then
return
end
name = (stoppable and name) or timeout name = (stoppable and name) or timeout
if not helpers.timer_table[name] then if not helpers.timer_table[name] then
helpers.timer_table[name] = timer({ timeout = timeout }) helpers.timer_table[name] = timer({ timeout = timeout })
helpers.timer_table[name]:start() helpers.timer_table[name]:start()
end end
helpers.timer_table[name]:connect_signal("timeout", fun) helpers.timer_table[name]:connect_signal('timeout', fun)
if not nostart then if not nostart then
helpers.timer_table[name]:emit_signal("timeout") helpers.timer_table[name]:emit_signal('timeout')
end end
return stoppable and helpers.timer_table[name] return stoppable and helpers.timer_table[name]
end end
@ -107,16 +112,14 @@ end
-- @param callback function to execute on cmd output -- @param callback function to execute on cmd output
-- @return cmd PID -- @return cmd PID
function helpers.async(cmd, callback) function helpers.async(cmd, callback)
return spawn.easy_async(cmd, return spawn.easy_async(cmd, function(stdout, _, _, exit_code)
function (stdout, _, _, exit_code)
callback(stdout, exit_code) callback(stdout, exit_code)
end) end)
end end
-- like above, but call spawn.easy_async with a shell -- like above, but call spawn.easy_async with a shell
function helpers.async_with_shell(cmd, callback) function helpers.async_with_shell(cmd, callback)
return spawn.easy_async_with_shell(cmd, return spawn.easy_async_with_shell(cmd, function(stdout, _, _, exit_code)
function (stdout, _, _, exit_code)
callback(stdout, exit_code) callback(stdout, exit_code)
end) end)
end end
@ -162,7 +165,9 @@ end
function helpers.spairs(t) function helpers.spairs(t)
-- collect the keys -- collect the keys
local keys = {} local keys = {}
for k in pairs(t) do keys[#keys+1] = k end for k in pairs(t) do
keys[#keys + 1] = k
end
tsort(keys) tsort(keys)
@ -188,7 +193,9 @@ end
-- create the powerset of a given set -- create the powerset of a given set
function helpers.powerset(s) function helpers.powerset(s)
if not s then return {} end if not s then
return {}
end
local t = { {} } local t = { {} }
for i = 1, #s do for i = 1, #s do
for j = 1, #t do for j = 1, #t do

View File

@ -9,7 +9,7 @@
--]] --]]
return { return {
layout = require("lain.layout"), layout = require('lain.layout'),
util = require("lain.util"), util = require('lain.util'),
widget = require("lain.widget") widget = require('lain.widget'),
} }

View File

@ -11,19 +11,19 @@ local floor = math.floor
local screen = screen local screen = screen
local cascade = { local cascade = {
name = "cascade", name = 'cascade',
nmaster = 0, nmaster = 0,
offset_x = 32, offset_x = 32,
offset_y = 8, offset_y = 8,
tile = { tile = {
name = "cascadetile", name = 'cascadetile',
nmaster = 0, nmaster = 0,
ncol = 0, ncol = 0,
mwfact = 0, mwfact = 0,
offset_x = 5, offset_x = 5,
offset_y = 32, offset_y = 32,
extra_padding = 0 extra_padding = 0,
} },
} }
local function do_cascade(p, tiling) local function do_cascade(p, tiling)
@ -31,7 +31,9 @@ local function do_cascade(p, tiling)
local wa = p.workarea local wa = p.workarea
local cls = p.clients local cls = p.clients
if #cls == 0 then return end if #cls == 0 then
return
end
if not tiling then if not tiling then
-- Cascade windows. -- Cascade windows.
@ -62,8 +64,12 @@ local function do_cascade(p, tiling)
g.width = wa.width - current_offset_x g.width = wa.width - current_offset_x
g.height = wa.height - current_offset_y g.height = wa.height - current_offset_y
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g p.geometries[c] = g
end end
@ -109,7 +115,9 @@ local function do_cascade(p, tiling)
local current_offset_x = cascade.tile.offset_x * (how_many - 1) local current_offset_x = cascade.tile.offset_x * (how_many - 1)
local current_offset_y = cascade.tile.offset_y * (how_many - 1) local current_offset_y = cascade.tile.offset_y * (how_many - 1)
if #cls <= 0 then return end if #cls <= 0 then
return
end
-- Main column, fixed width and height. -- Main column, fixed width and height.
local c = cls[1] local c = cls[1]
@ -136,13 +144,19 @@ local function do_cascade(p, tiling)
g.x = wa.x g.x = wa.x
g.y = wa.y g.y = wa.y
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g p.geometries[c] = g
-- Remaining clients stacked in slave column, new ones on top. -- Remaining clients stacked in slave column, new ones on top.
if #cls <= 1 then return end if #cls <= 1 then
return
end
for i = 2, #cls do for i = 2, #cls do
c = cls[i] c = cls[i]
g = {} g = {}
@ -153,8 +167,12 @@ local function do_cascade(p, tiling)
g.x = wa.x + mainwid + (how_many - (i - 1)) * cascade.tile.offset_x g.x = wa.x + mainwid + (how_many - (i - 1)) * cascade.tile.offset_x
g.y = wa.y + (i - 2) * cascade.tile.offset_y g.y = wa.y + (i - 2) * cascade.tile.offset_y
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g p.geometries[c] = g
end end

View File

@ -17,8 +17,8 @@ local mousegrabber = mousegrabber
local screen = screen local screen = screen
local centerwork = { local centerwork = {
name = "centerwork", name = 'centerwork',
horizontal = { name = "centerworkh" } horizontal = { name = 'centerworkh' },
} }
local function arrange(p, layout) local function arrange(p, layout)
@ -26,7 +26,9 @@ local function arrange(p, layout)
local wa = p.workarea local wa = p.workarea
local cls = p.clients local cls = p.clients
if #cls == 0 then return end if #cls == 0 then
return
end
local g = {} local g = {}
@ -45,9 +47,13 @@ local function arrange(p, layout)
local slaveFirstDim, slaveSecondDim = 0, 0 local slaveFirstDim, slaveSecondDim = 0, 0
if layout.name == "centerwork" then -- vertical if layout.name == 'centerwork' then -- vertical
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.height / nbrFirstSlaves) end if nbrFirstSlaves > 0 then
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.height / nbrSecondSlaves) end slaveFirstDim = floor(wa.height / nbrFirstSlaves)
end
if nbrSecondSlaves > 0 then
slaveSecondDim = floor(wa.height / nbrSecondSlaves)
end
g.height = wa.height g.height = wa.height
g.width = mainwid g.width = mainwid
@ -55,8 +61,12 @@ local function arrange(p, layout)
g.x = wa.x + slaveLwid g.x = wa.x + slaveLwid
g.y = wa.y g.y = wa.y
else -- horizontal else -- horizontal
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.width / nbrFirstSlaves) end if nbrFirstSlaves > 0 then
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.width / nbrSecondSlaves) end slaveFirstDim = floor(wa.width / nbrFirstSlaves)
end
if nbrSecondSlaves > 0 then
slaveSecondDim = floor(wa.width / nbrSecondSlaves)
end
g.height = mainhei g.height = mainhei
g.width = wa.width g.width = wa.width
@ -71,14 +81,16 @@ local function arrange(p, layout)
p.geometries[cls[1]] = g p.geometries[cls[1]] = g
-- Auxiliary clients -- Auxiliary clients
if #cls <= 1 then return end if #cls <= 1 then
return
end
for i = 2, #cls do for i = 2, #cls do
g = {} g = {}
local idxChecker, dimToAssign local idxChecker, dimToAssign
local rowIndex = floor(i / 2) local rowIndex = floor(i / 2)
if layout.name == "centerwork" then if layout.name == 'centerwork' then
if i % 2 == 0 then -- left slave if i % 2 == 0 then -- left slave
g.x = wa.x g.x = wa.x
g.y = wa.y + (rowIndex - 1) * slaveFirstDim g.y = wa.y + (rowIndex - 1) * slaveFirstDim
@ -134,22 +146,22 @@ local function mouse_resize_handler(c, _, _, _, orientation)
local mwfact = c.screen.selected_tag.master_width_factor local mwfact = c.screen.selected_tag.master_width_factor
local g = c:geometry() local g = c:geometry()
local offset = 0 local offset = 0
local cursor = "cross" local cursor = 'cross'
local corner_coords local corner_coords
if orientation == 'vertical' then if orientation == 'vertical' then
if g.height + 15 >= wa.height then if g.height + 15 >= wa.height then
offset = g.height * .5 offset = g.height * 0.5
cursor = "sb_h_double_arrow" cursor = 'sb_h_double_arrow'
elseif g.y + g.height + 15 <= wa.y + wa.height then elseif g.y + g.height + 15 <= wa.y + wa.height then
offset = g.height offset = g.height
end end
corner_coords = { x = wa.x + wa.width * (1 - mwfact) / 2, y = g.y + offset } corner_coords = { x = wa.x + wa.width * (1 - mwfact) / 2, y = g.y + offset }
else else
if g.width + 15 >= wa.width then if g.width + 15 >= wa.width then
offset = g.width * .5 offset = g.width * 0.5
cursor = "sb_v_double_arrow" cursor = 'sb_v_double_arrow'
elseif g.x + g.width + 15 <= wa.x + wa.width then elseif g.x + g.width + 15 <= wa.x + wa.width then
offset = g.width offset = g.width
end end
@ -161,7 +173,9 @@ local function mouse_resize_handler(c, _, _, _, orientation)
local prev_coords = {} local prev_coords = {}
mousegrabber.run(function(m) mousegrabber.run(function(m)
if not c.valid then return false end if not c.valid then
return false
end
for _, v in ipairs(m.buttons) do for _, v in ipairs(m.buttons) do
if v then if v then
prev_coords = { x = m.x, y = m.y } prev_coords = { x = m.x, y = m.y }
@ -195,13 +209,12 @@ function centerwork.horizontal.mouse_resize_handler(c, corner, x, y)
return mouse_resize_handler(c, corner, x, y, 'horizontal') return mouse_resize_handler(c, corner, x, y, 'horizontal')
end end
--[[ --[[
Make focus.byidx and swap.byidx behave more consistently with other layouts. Make focus.byidx and swap.byidx behave more consistently with other layouts.
--]] --]]
local awful = require("awful") local awful = require('awful')
local gears = require("gears") local gears = require('gears')
local client = client local client = client
local function compare_position(a, b) local function compare_position(a, b)
@ -217,7 +230,9 @@ local function clients_by_position()
if this then if this then
local sorted = {} local sorted = {}
for _, c in ipairs(client.focus.first_tag:clients()) do for _, c in ipairs(client.focus.first_tag:clients()) do
if not c.minimized then sorted[#sorted+1] = c end if not c.minimized then
sorted[#sorted + 1] = c
end
end end
table.sort(sorted, compare_position) table.sort(sorted, compare_position)
@ -236,12 +251,11 @@ local function clients_by_position()
end end
local function in_centerwork() local function in_centerwork()
return client.focus and client.focus.first_tag.layout.name == "centerwork" return client.focus and client.focus.first_tag.layout.name == 'centerwork'
end end
centerwork.focus = {} centerwork.focus = {}
--[[ --[[
Drop in replacements for awful.client.focus.byidx and awful.client.swap.byidx Drop in replacements for awful.client.focus.byidx and awful.client.swap.byidx
that behaves consistently with other layouts. that behaves consistently with other layouts.

View File

@ -11,9 +11,9 @@
--]] --]]
local wrequire = require("lain.helpers").wrequire local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable local setmetatable = setmetatable
local layout = { _NAME = "lain.layout" } local layout = { _NAME = 'lain.layout' }
return setmetatable(layout, { __index = wrequire }) return setmetatable(layout, { __index = wrequire })

View File

@ -12,25 +12,31 @@ local math = math
local screen = screen local screen = screen
local tonumber = tonumber local tonumber = tonumber
local termfair = { name = "termfair" } local termfair = { name = 'termfair' }
termfair.center = { name = "centerfair" } termfair.center = { name = 'centerfair' }
termfair.stable = { name = "stablefair" } termfair.stable = { name = 'stablefair' }
local function do_fair(p, orientation) local function do_fair(p, orientation)
local t = p.tag or screen[p.screen].selected_tag local t = p.tag or screen[p.screen].selected_tag
local wa = p.workarea local wa = p.workarea
local cls = p.clients local cls = p.clients
if #cls == 0 then return end if #cls == 0 then
return
end
-- How many vertical columns? Read from nmaster on the tag. -- How many vertical columns? Read from nmaster on the tag.
local num_x = tonumber(termfair.nmaster) or t.master_count local num_x = tonumber(termfair.nmaster) or t.master_count
local ncol = tonumber(termfair.ncol) or t.column_count local ncol = tonumber(termfair.ncol) or t.column_count
if num_x <= 2 then num_x = 2 end if num_x <= 2 then
if ncol <= 1 then ncol = 1 end num_x = 2
end
if ncol <= 1 then
ncol = 1
end
local width = math.floor(wa.width / num_x) local width = math.floor(wa.width / num_x)
if orientation == "west" then if orientation == 'west' then
-- Layout with fixed number of vertical columns (read from nmaster). -- Layout with fixed number of vertical columns (read from nmaster).
-- New windows align from left to right. When a row is full, a new -- New windows align from left to right. When a row is full, a new
-- one above it is created. Like this: -- one above it is created. Like this:
@ -87,8 +93,12 @@ local function do_fair(p, orientation)
g.x = wa.x + this_x * width g.x = wa.x + this_x * width
g.y = wa.y + this_y * height g.y = wa.y + this_y * height
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g p.geometries[c] = g
@ -107,7 +117,7 @@ local function do_fair(p, orientation)
end end
end end
end end
elseif orientation == "stable" then elseif orientation == 'stable' then
-- Layout with fixed number of vertical columns (read from nmaster). -- Layout with fixed number of vertical columns (read from nmaster).
-- New windows align from left to right. When a row is full, a new -- New windows align from left to right. When a row is full, a new
-- one below it is created. Like this: -- one below it is created. Like this:
@ -152,12 +162,16 @@ local function do_fair(p, orientation)
g.x = wa.x + this_x * width g.x = wa.x + this_x * width
g.y = wa.y + this_y * height g.y = wa.y + this_y * height
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[c] = g p.geometries[c] = g
end end
elseif orientation == "center" then elseif orientation == 'center' then
-- Layout with fixed number of vertical columns (read from nmaster). -- Layout with fixed number of vertical columns (read from nmaster).
-- Cols are centerded until there is nmaster columns, then windows -- Cols are centerded until there is nmaster columns, then windows
-- are stacked in the slave columns, with at most ncol clients per -- are stacked in the slave columns, with at most ncol clients per
@ -185,8 +199,12 @@ local function do_fair(p, orientation)
local g = { y = wa.y } local g = { y = wa.y }
g.width = width g.width = width
g.height = wa.height g.height = wa.height
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
g.x = offset_x + (i - 1) * width g.x = offset_x + (i - 1) * width
p.geometries[cls[i]] = g p.geometries[cls[i]] = g
end end
@ -196,8 +214,12 @@ local function do_fair(p, orientation)
local g = {} local g = {}
g.width = wa.width - (num_x - 1) * width g.width = wa.width - (num_x - 1) * width
g.height = wa.height g.height = wa.height
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
g.x = wa.x g.x = wa.x
g.y = wa.y g.y = wa.y
p.geometries[cls[1]] = g p.geometries[cls[1]] = g
@ -246,8 +268,12 @@ local function do_fair(p, orientation)
g.y = wy g.y = wy
g.height = height g.height = height
g.width = width g.width = width
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[cls[nclient]] = g p.geometries[cls[nclient]] = g
nclient = nclient + 1 nclient = nclient + 1
wy = wy + height wy = wy + height
@ -257,8 +283,12 @@ local function do_fair(p, orientation)
g.y = wy g.y = wy
g.height = wa.height - (num_y[i] - 1) * height g.height = wa.height - (num_y[i] - 1) * height
g.width = width g.width = width
if g.width < 1 then g.width = 1 end if g.width < 1 then
if g.height < 1 then g.height = 1 end g.width = 1
end
if g.height < 1 then
g.height = 1
end
p.geometries[cls[nclient]] = g p.geometries[cls[nclient]] = g
nclient = nclient + 1 nclient = nclient + 1
wx = wx + width wx = wx + width
@ -268,15 +298,15 @@ local function do_fair(p, orientation)
end end
function termfair.center.arrange(p) function termfair.center.arrange(p)
return do_fair(p, "center") return do_fair(p, 'center')
end end
function termfair.stable.arrange(p) function termfair.stable.arrange(p)
return do_fair(p, "stable") return do_fair(p, 'stable')
end end
function termfair.arrange(p) function termfair.arrange(p)
return do_fair(p, "west") return do_fair(p, 'west')
end end
return termfair return termfair

View File

@ -47,12 +47,11 @@ local pairs, type, tostring, tonumber, getmetatable, setmetatable =
local error, require, pcall, select = error, require, pcall, select local error, require, pcall, select = error, require, pcall, select
local floor, huge = math.floor, math.huge local floor, huge = math.floor, math.huge
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat = local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
string.rep, string.gsub, string.sub, string.byte, string.char, string.rep, string.gsub, string.sub, string.byte, string.char, string.find, string.len, string.format
string.find, string.len, string.format
local strmatch = string.match local strmatch = string.match
local concat = table.concat local concat = table.concat
local json = { version = "dkjson 2.6" } local json = { version = 'dkjson 2.6' }
local jsonlpeg = {} local jsonlpeg = {}
@ -69,12 +68,16 @@ _ENV = nil -- blocking globals in Lua 5.2 and later
pcall(function() pcall(function()
-- Enable access to blocked metatables. -- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them. -- Don't worry, this module doesn't change anything in them.
local debmeta = require "debug".getmetatable local debmeta = require('debug').getmetatable
if debmeta then getmetatable = debmeta end if debmeta then
getmetatable = debmeta
end
end) end)
json.null = setmetatable({}, { json.null = setmetatable({}, {
__tojson = function () return "null" end __tojson = function()
return 'null'
end,
}) })
local function isarray(tbl) local function isarray(tbl)
@ -102,8 +105,13 @@ local function isarray (tbl)
end end
local escapecodes = { local escapecodes = {
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f", ['"'] = '\\"',
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t" ['\\'] = '\\\\',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t',
} }
local function escapeutf8(uchar) local function escapeutf8(uchar)
@ -122,17 +130,17 @@ local function escapeutf8 (uchar)
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80 value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
else else
return "" return ''
end end
if value <= 0xffff then if value <= 0xffff then
return strformat ("\\u%.4x", value) return strformat('\\u%.4x', value)
elseif value <= 0x10ffff then elseif value <= 0x10ffff then
-- encode as UTF-16 surrogate pair -- encode as UTF-16 surrogate pair
value = value - 0x10000 value = value - 0x10000
local highsur, lowsur = 0xD800 + floor(value / 0x400), 0xDC00 + (value % 0x400) local highsur, lowsur = 0xD800 + floor(value / 0x400), 0xDC00 + (value % 0x400)
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur) return strformat('\\u%.4x\\u%.4x', highsur, lowsur)
else else
return "" return ''
end end
end end
@ -149,18 +157,18 @@ end
local function quotestring(value) local function quotestring(value)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js -- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8) value = fsub(value, '[%z\1-\31"\\\127]', escapeutf8)
if strfind (value, "[\194\216\220\225\226\239]") then if strfind(value, '[\194\216\220\225\226\239]') then
value = fsub (value, "\194[\128-\159\173]", escapeutf8) value = fsub(value, '\194[\128-\159\173]', escapeutf8)
value = fsub (value, "\216[\128-\132]", escapeutf8) value = fsub(value, '\216[\128-\132]', escapeutf8)
value = fsub (value, "\220\143", escapeutf8) value = fsub(value, '\220\143', escapeutf8)
value = fsub (value, "\225\158[\180\181]", escapeutf8) value = fsub(value, '\225\158[\180\181]', escapeutf8)
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8) value = fsub(value, '\226\128[\140-\143\168-\175]', escapeutf8)
value = fsub (value, "\226\129[\160-\175]", escapeutf8) value = fsub(value, '\226\129[\160-\175]', escapeutf8)
value = fsub (value, "\239\187\191", escapeutf8) value = fsub(value, '\239\187\191', escapeutf8)
value = fsub (value, "\239\191[\176-\191]", escapeutf8) value = fsub(value, '\239\191[\176-\191]', escapeutf8)
end end
return "\"" .. value .. "\"" return '"' .. value .. '"'
end end
json.quotestring = quotestring json.quotestring = quotestring
@ -177,37 +185,36 @@ end
local decpoint, numfilter local decpoint, numfilter
local function updatedecpoint() local function updatedecpoint()
decpoint = strmatch(tostring(0.5), "([^05+])") decpoint = strmatch(tostring(0.5), '([^05+])')
-- build a filter that can be used to remove group separators -- build a filter that can be used to remove group separators
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+" numfilter = '[^0-9%-%+eE' .. gsub(decpoint, '[%^%$%(%)%%%.%[%]%*%+%-%?]', '%%%0') .. ']+'
end end
updatedecpoint() updatedecpoint()
local function num2str(num) local function num2str(num)
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".") return replace(fsub(tostring(num), numfilter, ''), decpoint, '.')
end end
local function str2num(str) local function str2num(str)
local num = tonumber(replace(str, ".", decpoint)) local num = tonumber(replace(str, '.', decpoint))
if not num then if not num then
updatedecpoint() updatedecpoint()
num = tonumber(replace(str, ".", decpoint)) num = tonumber(replace(str, '.', decpoint))
end end
return num return num
end end
local function addnewline2(level, buffer, buflen) local function addnewline2(level, buffer, buflen)
buffer[buflen+1] = "\n" buffer[buflen + 1] = '\n'
buffer[buflen+2] = strrep (" ", level) buffer[buflen + 2] = strrep(' ', level)
buflen = buflen + 2 buflen = buflen + 2
return buflen return buflen
end end
function json.addnewline(state) function json.addnewline(state)
if state.indent then if state.indent then
state.bufferlen = addnewline2 (state.level or 0, state.bufferlen = addnewline2(state.level or 0, state.buffer, state.bufferlen or #state.buffer)
state.buffer, state.bufferlen or #(state.buffer))
end end
end end
@ -220,13 +227,13 @@ local function addpair (key, value, prev, indent, level, buffer, buflen, tables,
end end
if prev then if prev then
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "," buffer[buflen] = ','
end end
if indent then if indent then
buflen = addnewline2(level, buffer, buflen) buflen = addnewline2(level, buffer, buflen)
end end
buffer[buflen + 1] = quotestring(key) buffer[buflen + 1] = quotestring(key)
buffer[buflen+2] = ":" buffer[buflen + 2] = ':'
return encode2(value, indent, level, buffer, buflen + 2, tables, globalorder, state) return encode2(value, indent, level, buffer, buflen + 2, tables, globalorder, state)
end end
@ -247,13 +254,15 @@ local function exception(reason, value, state, buffer, buflen, defaultmessage)
else else
state.bufferlen = buflen state.bufferlen = buflen
local ret, msg = handler(reason, value, state, defaultmessage) local ret, msg = handler(reason, value, state, defaultmessage)
if not ret then return nil, msg or defaultmessage end if not ret then
return nil, msg or defaultmessage
end
return appendcustom(ret, buffer, state) return appendcustom(ret, buffer, state)
end end
end end
function json.encodeexception(_reason, _value, _state, defaultmessage) function json.encodeexception(_reason, _value, _state, defaultmessage)
return quotestring("<" .. defaultmessage .. ">") return quotestring('<' .. defaultmessage .. '>')
end end
encode2 = function(value, indent, level, buffer, buflen, tables, globalorder, state) encode2 = function(value, indent, level, buffer, buflen, tables, globalorder, state)
@ -268,17 +277,19 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
tables[value] = true tables[value] = true
state.bufferlen = buflen state.bufferlen = buflen
local ret, msg = valtojson(value, state) local ret, msg = valtojson(value, state)
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end if not ret then
return exception('custom encoder failed', value, state, buffer, buflen, msg)
end
tables[value] = nil tables[value] = nil
buflen = appendcustom(ret, buffer, state) buflen = appendcustom(ret, buffer, state)
elseif value == nil then elseif value == nil then
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "null" buffer[buflen] = 'null'
elseif valtype == 'number' then elseif valtype == 'number' then
local s local s
if value ~= value or value >= huge or -value >= huge then if value ~= value or value >= huge or -value >= huge then
-- This is the behaviour of the original JSON implementation. -- This is the behaviour of the original JSON implementation.
s = "null" s = 'null'
else else
s = num2str(value) s = num2str(value)
end end
@ -286,7 +297,7 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
buffer[buflen] = s buffer[buflen] = s
elseif valtype == 'boolean' then elseif valtype == 'boolean' then
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = value and "true" or "false" buffer[buflen] = value and 'true' or 'false'
elseif valtype == 'string' then elseif valtype == 'string' then
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = quotestring(value) buffer[buflen] = quotestring(value)
@ -303,21 +314,23 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
local msg local msg
if isa then -- JSON array if isa then -- JSON array
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "[" buffer[buflen] = '['
for i = 1, n do for i = 1, n do
buflen, msg = encode2(value[i], indent, level, buffer, buflen, tables, globalorder, state) buflen, msg = encode2(value[i], indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end if not buflen then
return nil, msg
end
if i < n then if i < n then
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "," buffer[buflen] = ','
end end
end end
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "]" buffer[buflen] = ']'
else -- JSON object else -- JSON object
local prev = false local prev = false
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "{" buffer[buflen] = '{'
local order = valmeta and valmeta.__jsonorder or globalorder local order = valmeta and valmeta.__jsonorder or globalorder
if order then if order then
local used = {} local used = {}
@ -334,14 +347,18 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
for k, v in pairs(value) do for k, v in pairs(value) do
if not used[k] then if not used[k] then
buflen, msg = addpair(k, v, prev, indent, level, buffer, buflen, tables, globalorder, state) buflen, msg = addpair(k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end if not buflen then
return nil, msg
end
prev = true -- add a seperator before the next element prev = true -- add a seperator before the next element
end end
end end
else -- unordered else -- unordered
for k, v in pairs(value) do for k, v in pairs(value) do
buflen, msg = addpair(k, v, prev, indent, level, buffer, buflen, tables, globalorder, state) buflen, msg = addpair(k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end if not buflen then
return nil, msg
end
prev = true -- add a seperator before the next element prev = true -- add a seperator before the next element
end end
end end
@ -349,12 +366,18 @@ encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, s
buflen = addnewline2(level - 1, buffer, buflen) buflen = addnewline2(level - 1, buffer, buflen)
end end
buflen = buflen + 1 buflen = buflen + 1
buffer[buflen] = "}" buffer[buflen] = '}'
end end
tables[value] = nil tables[value] = nil
else else
return exception ('unsupported type', value, state, buffer, buflen, return exception(
"type '" .. valtype .. "' is not supported by JSON.") 'unsupported type',
value,
state,
buffer,
buflen,
"type '" .. valtype .. "' is not supported by JSON."
)
end end
return buflen return buflen
end end
@ -365,8 +388,16 @@ function json.encode (value, state)
local buffer = oldbuffer or {} local buffer = oldbuffer or {}
state.buffer = buffer state.buffer = buffer
updatedecpoint() updatedecpoint()
local ret, msg = encode2 (value, state.indent, state.level or 0, local ret, msg = encode2(
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state) value,
state.indent,
state.level or 0,
buffer,
state.bufferlen or 0,
state.tables or {},
state.keyorder,
state
)
if not ret then if not ret then
error(msg, 2) error(msg, 2)
elseif oldbuffer == buffer then elseif oldbuffer == buffer then
@ -382,7 +413,7 @@ end
local function loc(str, where) local function loc(str, where)
local line, pos, linepos = 1, 1, 0 local line, pos, linepos = 1, 1, 0
while true do while true do
pos = strfind (str, "\n", pos, true) pos = strfind(str, '\n', pos, true)
if pos and pos < where then if pos and pos < where then
line = line + 1 line = line + 1
linepos = pos linepos = pos
@ -391,27 +422,33 @@ local function loc (str, where)
break break
end end
end end
return "line " .. line .. ", column " .. (where - linepos) return 'line ' .. line .. ', column ' .. (where - linepos)
end end
local function unterminated(str, what, where) local function unterminated(str, what, where)
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where) return nil, strlen(str) + 1, 'unterminated ' .. what .. ' at ' .. loc(str, where)
end end
local function scanwhite(str, pos) local function scanwhite(str, pos)
while true do while true do
pos = strfind (str, "%S", pos) pos = strfind(str, '%S', pos)
if not pos then return nil end if not pos then
return nil
end
local sub2 = strsub(str, pos, pos + 1) local sub2 = strsub(str, pos, pos + 1)
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then if sub2 == '\239\187' and strsub(str, pos + 2, pos + 2) == '\191' then
-- UTF-8 Byte Order Mark -- UTF-8 Byte Order Mark
pos = pos + 3 pos = pos + 3
elseif sub2 == "//" then elseif sub2 == '//' then
pos = strfind (str, "[\n\r]", pos + 2) pos = strfind(str, '[\n\r]', pos + 2)
if not pos then return nil end if not pos then
elseif sub2 == "/*" then return nil
pos = strfind (str, "*/", pos + 2) end
if not pos then return nil end elseif sub2 == '/*' then
pos = strfind(str, '*/', pos + 2)
if not pos then
return nil
end
pos = pos + 2 pos = pos + 2
else else
return pos return pos
@ -420,8 +457,14 @@ local function scanwhite (str, pos)
end end
local escapechars = { local escapechars = {
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f", ['"'] = '"',
["n"] = "\n", ["r"] = "\r", ["t"] = "\t" ['\\'] = '\\',
['/'] = '/',
['b'] = '\b',
['f'] = '\f',
['n'] = '\n',
['r'] = '\r',
['t'] = '\t',
} }
local function unichar(value) local function unichar(value)
@ -430,17 +473,16 @@ local function unichar (value)
elseif value <= 0x007f then elseif value <= 0x007f then
return strchar(value) return strchar(value)
elseif value <= 0x07ff then elseif value <= 0x07ff then
return strchar (0xc0 + floor(value/0x40), return strchar(0xc0 + floor(value / 0x40), 0x80 + (floor(value) % 0x40))
0x80 + (floor(value) % 0x40))
elseif value <= 0xffff then elseif value <= 0xffff then
return strchar (0xe0 + floor(value/0x1000), return strchar(0xe0 + floor(value / 0x1000), 0x80 + (floor(value / 0x40) % 0x40), 0x80 + (floor(value) % 0x40))
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0x10ffff then elseif value <= 0x10ffff then
return strchar (0xf0 + floor(value/0x40000), return strchar(
0xf0 + floor(value / 0x40000),
0x80 + (floor(value / 0x1000) % 0x40), 0x80 + (floor(value / 0x1000) % 0x40),
0x80 + (floor(value / 0x40) % 0x40), 0x80 + (floor(value / 0x40) % 0x40),
0x80 + (floor(value) % 0x40)) 0x80 + (floor(value) % 0x40)
)
else else
return nil return nil
end end
@ -450,28 +492,28 @@ local function scanstring (str, pos)
local lastpos = pos + 1 local lastpos = pos + 1
local buffer, n = {}, 0 local buffer, n = {}, 0
while true do while true do
local nextpos = strfind (str, "[\"\\]", lastpos) local nextpos = strfind(str, '["\\]', lastpos)
if not nextpos then if not nextpos then
return unterminated (str, "string", pos) return unterminated(str, 'string', pos)
end end
if nextpos > lastpos then if nextpos > lastpos then
n = n + 1 n = n + 1
buffer[n] = strsub(str, lastpos, nextpos - 1) buffer[n] = strsub(str, lastpos, nextpos - 1)
end end
if strsub (str, nextpos, nextpos) == "\"" then if strsub(str, nextpos, nextpos) == '"' then
lastpos = nextpos + 1 lastpos = nextpos + 1
break break
else else
local escchar = strsub(str, nextpos + 1, nextpos + 1) local escchar = strsub(str, nextpos + 1, nextpos + 1)
local value local value
if escchar == "u" then if escchar == 'u' then
value = tonumber(strsub(str, nextpos + 2, nextpos + 5), 16) value = tonumber(strsub(str, nextpos + 2, nextpos + 5), 16)
if value then if value then
local value2 local value2
if 0xD800 <= value and value <= 0xDBff then if 0xD800 <= value and value <= 0xDBff then
-- we have the high surrogate of UTF-16. Check if there is a -- we have the high surrogate of UTF-16. Check if there is a
-- low surrogate escaped nearby to combine them. -- low surrogate escaped nearby to combine them.
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then if strsub(str, nextpos + 6, nextpos + 7) == '\\u' then
value2 = tonumber(strsub(str, nextpos + 8, nextpos + 11), 16) value2 = tonumber(strsub(str, nextpos + 8, nextpos + 11), 16)
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000 value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
@ -503,7 +545,7 @@ local function scanstring (str, pos)
elseif n > 1 then elseif n > 1 then
return concat(buffer), lastpos return concat(buffer), lastpos
else else
return "", lastpos return '', lastpos
end end
end end
@ -519,35 +561,47 @@ local function scantable (what, closechar, str, startpos, nullval, objectmeta, a
end end
while true do while true do
pos = scanwhite(str, pos) pos = scanwhite(str, pos)
if not pos then return unterminated (str, what, startpos) end if not pos then
return unterminated(str, what, startpos)
end
local char = strsub(str, pos, pos) local char = strsub(str, pos, pos)
if char == closechar then if char == closechar then
return tbl, pos + 1 return tbl, pos + 1
end end
local val1, err local val1, err
val1, pos, err = scanvalue(str, pos, nullval, objectmeta, arraymeta) val1, pos, err = scanvalue(str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end if err then
return nil, pos, err
end
pos = scanwhite(str, pos) pos = scanwhite(str, pos)
if not pos then return unterminated (str, what, startpos) end if not pos then
return unterminated(str, what, startpos)
end
char = strsub(str, pos, pos) char = strsub(str, pos, pos)
if char == ":" then if char == ':' then
if val1 == nil then if val1 == nil then
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")" return nil, pos, 'cannot use nil as table index (at ' .. loc(str, pos) .. ')'
end end
pos = scanwhite(str, pos + 1) pos = scanwhite(str, pos + 1)
if not pos then return unterminated (str, what, startpos) end if not pos then
return unterminated(str, what, startpos)
end
local val2 local val2
val2, pos, err = scanvalue(str, pos, nullval, objectmeta, arraymeta) val2, pos, err = scanvalue(str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end if err then
return nil, pos, err
end
tbl[val1] = val2 tbl[val1] = val2
pos = scanwhite(str, pos) pos = scanwhite(str, pos)
if not pos then return unterminated (str, what, startpos) end if not pos then
return unterminated(str, what, startpos)
end
char = strsub(str, pos, pos) char = strsub(str, pos, pos)
else else
n = n + 1 n = n + 1
tbl[n] = val1 tbl[n] = val1
end end
if char == "," then if char == ',' then
pos = pos + 1 pos = pos + 1
end end
end end
@ -557,40 +611,40 @@ scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
pos = pos or 1 pos = pos or 1
pos = scanwhite(str, pos) pos = scanwhite(str, pos)
if not pos then if not pos then
return nil, strlen (str) + 1, "no valid JSON value (reached the end)" return nil, strlen(str) + 1, 'no valid JSON value (reached the end)'
end end
local char = strsub(str, pos, pos) local char = strsub(str, pos, pos)
if char == "{" then if char == '{' then
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta) return scantable('object', '}', str, pos, nullval, objectmeta, arraymeta)
elseif char == "[" then elseif char == '[' then
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta) return scantable('array', ']', str, pos, nullval, objectmeta, arraymeta)
elseif char == "\"" then elseif char == '"' then
return scanstring(str, pos) return scanstring(str, pos)
else else
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos) local pstart, pend = strfind(str, '^%-?[%d%.]+[eE]?[%+%-]?%d*', pos)
if pstart then if pstart then
local number = str2num(strsub(str, pstart, pend)) local number = str2num(strsub(str, pstart, pend))
if number then if number then
return number, pend + 1 return number, pend + 1
end end
end end
pstart, pend = strfind (str, "^%a%w*", pos) pstart, pend = strfind(str, '^%a%w*', pos)
if pstart then if pstart then
local name = strsub(str, pstart, pend) local name = strsub(str, pstart, pend)
if name == "true" then if name == 'true' then
return true, pend + 1 return true, pend + 1
elseif name == "false" then elseif name == 'false' then
return false, pend + 1 return false, pend + 1
elseif name == "null" then elseif name == 'null' then
return nullval, pend + 1 return nullval, pend + 1
end end
end end
return nil, pos, "no valid JSON value at " .. loc (str, pos) return nil, pos, 'no valid JSON value at ' .. loc(str, pos)
end end
end end
local function optionalmetatables(...) local function optionalmetatables(...)
if select("#", ...) > 0 then if select('#', ...) > 0 then
return ... return ...
else else
return { __jsontype = 'object' }, { __jsontype = 'array' } return { __jsontype = 'object' }, { __jsontype = 'array' }
@ -603,10 +657,10 @@ function json.decode (str, pos, nullval, ...)
end end
function json.use_lpeg() function json.use_lpeg()
local g = require ("lpeg") local g = require('lpeg')
if g.version() == "0.11" then if g.version() == '0.11' then
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching" error('due to a bug in LPeg 0.11, it cannot be used for JSON matching')
end end
local pegmatch = g.match local pegmatch = g.match
@ -614,7 +668,7 @@ function json.use_lpeg ()
local function ErrorCall(str, pos, msg, state) local function ErrorCall(str, pos, msg, state)
if not state.msg then if not state.msg then
state.msg = msg .. " at " .. loc (str, pos) state.msg = msg .. ' at ' .. loc(str, pos)
state.pos = pos state.pos = pos
end end
return false return false
@ -625,20 +679,20 @@ function json.use_lpeg ()
end end
local function ErrorUnterminatedCall(str, pos, what, state) local function ErrorUnterminatedCall(str, pos, what, state)
return ErrorCall (str, pos - 1, "unterminated " .. what, state) return ErrorCall(str, pos - 1, 'unterminated ' .. what, state)
end end
local SingleLineComment = P"//" * (1 - S"\n\r")^0 local SingleLineComment = P('//') * (1 - S('\n\r')) ^ 0
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/" local MultiLineComment = P('/*') * (1 - P('*/')) ^ 0 * P('*/')
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0 local Space = (S(' \n\r\t') + P('\239\187\191') + SingleLineComment + MultiLineComment) ^ 0
local function ErrUnterminated(what) local function ErrUnterminated(what)
return g.Cmt(g.Cc(what) * g.Carg(2), ErrorUnterminatedCall) return g.Cmt(g.Cc(what) * g.Carg(2), ErrorUnterminatedCall)
end end
local PlainChar = 1 - S"\"\\\n\r" local PlainChar = 1 - S('"\\\n\r')
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars local EscapeSequence = (P('\\') * g.C(S('"\\/bfnrt') + Err('unsupported escape sequence'))) / escapechars
local HexDigit = R("09", "af", "AF") local HexDigit = R('09', 'af', 'AF')
local function UTF16Surrogate(_match, _pos, high, low) local function UTF16Surrogate(_match, _pos, high, low)
high, low = tonumber(high, 16), tonumber(low, 16) high, low = tonumber(high, 16), tonumber(low, 16)
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
@ -650,15 +704,15 @@ function json.use_lpeg ()
local function UTF16BMP(hex) local function UTF16BMP(hex)
return unichar(tonumber(hex, 16)) return unichar(tonumber(hex, 16))
end end
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit)) local U16Sequence = (P('\\u') * g.C(HexDigit * HexDigit * HexDigit * HexDigit))
local UnicodeEscape = g.Cmt(U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence / UTF16BMP local UnicodeEscape = g.Cmt(U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence / UTF16BMP
local Char = UnicodeEscape + EscapeSequence + PlainChar local Char = UnicodeEscape + EscapeSequence + PlainChar
local String = P"\"" * (g.Cs (Char ^ 0) * P"\"" + ErrUnterminated "string") local String = P('"') * (g.Cs(Char ^ 0) * P('"') + ErrUnterminated('string'))
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0)) local Integer = P('-') ^ -1 * (P('0') + (R('19') * R('09') ^ 0))
local Fractal = P"." * R"09"^0 local Fractal = P('.') * R('09') ^ 0
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1 local Exponent = (S('eE')) * (S('+-')) ^ -1 * R('09') ^ 1
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num local Number = (Integer * Fractal ^ -1 * Exponent ^ -1) / str2num
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1) local Constant = P('true') * g.Cc(true) + P('false') * g.Cc(false) + P('null') * g.Carg(1)
local SimpleValue = Number + String + Constant local SimpleValue = Number + String + Constant
local ArrayContent, ObjectContent local ArrayContent, ObjectContent
@ -672,7 +726,7 @@ function json.use_lpeg ()
repeat repeat
obj, cont, npos = pegmatch(ArrayContent, str, pos, nullval, state) obj, cont, npos = pegmatch(ArrayContent, str, pos, nullval, state)
if cont == 'end' then if cont == 'end' then
return ErrorUnterminatedCall (str, start, "array", state) return ErrorUnterminatedCall(str, start, 'array', state)
end end
pos = npos pos = npos
if cont == 'cont' or cont == 'last' then if cont == 'cont' or cont == 'last' then
@ -691,7 +745,7 @@ function json.use_lpeg ()
repeat repeat
key, obj, cont, npos = pegmatch(ObjectContent, str, pos, nullval, state) key, obj, cont, npos = pegmatch(ObjectContent, str, pos, nullval, state)
if cont == 'end' then if cont == 'end' then
return ErrorUnterminatedCall (str, start, "object", state) return ErrorUnterminatedCall(str, start, 'object', state)
end end
pos = npos pos = npos
if cont == 'cont' or cont == 'last' then if cont == 'cont' or cont == 'last' then
@ -701,16 +755,23 @@ function json.use_lpeg ()
return pos, setmetatable(t, state.objectmeta) return pos, setmetatable(t, state.objectmeta)
end end
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) local Array = P('[') * g.Cmt(g.Carg(1) * g.Carg(2), parsearray)
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) local Object = P('{') * g.Cmt(g.Carg(1) * g.Carg(2), parseobject)
local Value = Space * (Array + Object + SimpleValue) local Value = Space * (Array + Object + SimpleValue)
local ExpectedValue = Value + Space * Err "value expected" local ExpectedValue = Value + Space * Err('value expected')
local ExpectedKey = String + Err "key expected" local ExpectedKey = String + Err('key expected')
local End = P(-1) * g.Cc'end' local End = P(-1) * g.Cc('end')
local ErrInvalid = Err "invalid JSON" local ErrInvalid = Err('invalid JSON')
ArrayContent = (Value * Space * (P"," * g.Cc'cont' + P"]" * g.Cc'last'+ End + ErrInvalid) + g.Cc(nil) * (P"]" * g.Cc'empty' + End + ErrInvalid)) * g.Cp() ArrayContent = (
local Pair = g.Cg (Space * ExpectedKey * Space * (P":" + Err "colon expected") * ExpectedValue) Value * Space * (P(',') * g.Cc('cont') + P(']') * g.Cc('last') + End + ErrInvalid)
ObjectContent = (g.Cc(nil) * g.Cc(nil) * P"}" * g.Cc'empty' + End + (Pair * Space * (P"," * g.Cc'cont' + P"}" * g.Cc'last' + End + ErrInvalid) + ErrInvalid)) * g.Cp() + g.Cc(nil) * (P(']') * g.Cc('empty') + End + ErrInvalid)
) * g.Cp()
local Pair = g.Cg(Space * ExpectedKey * Space * (P(':') + Err('colon expected')) * ExpectedValue)
ObjectContent = (
g.Cc(nil) * g.Cc(nil) * P('}') * g.Cc('empty')
+ End
+ (Pair * Space * (P(',') * g.Cc('cont') + P('}') * g.Cc('last') + End + ErrInvalid) + ErrInvalid)
) * g.Cp()
local DecodeValue = ExpectedValue * g.Cp() local DecodeValue = ExpectedValue * g.Cp()
jsonlpeg.version = json.version jsonlpeg.version = json.version
@ -733,7 +794,9 @@ function json.use_lpeg ()
end end
-- cache result of this function: -- cache result of this function:
json.use_lpeg = function () return jsonlpeg end json.use_lpeg = function()
return jsonlpeg
end
jsonlpeg.use_lpeg = json.use_lpeg jsonlpeg.use_lpeg = json.use_lpeg
return jsonlpeg return jsonlpeg
@ -744,4 +807,3 @@ if always_use_lpeg then
end end
return json return json

View File

@ -11,24 +11,26 @@
--]] --]]
local awful = require("awful") local awful = require('awful')
local sqrt = math.sqrt local sqrt = math.sqrt
local pairs = pairs local pairs = pairs
local client = client local client = client
local tonumber = tonumber local tonumber = tonumber
local wrequire = require("lain.helpers").wrequire local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable local setmetatable = setmetatable
-- Lain utilities submodule -- Lain utilities submodule
-- lain.util -- lain.util
local util = { _NAME = "lain.util" } local util = { _NAME = 'lain.util' }
-- Like awful.menu.clients, but only show clients of currently selected tags -- Like awful.menu.clients, but only show clients of currently selected tags
function util.menu_clients_current_tags(menu, args) function util.menu_clients_current_tags(menu, args)
-- List of currently selected tags. -- List of currently selected tags.
local cls_tags = awful.screen.focused().selected_tags local cls_tags = awful.screen.focused().selected_tags
if cls_tags == nil then return nil end if cls_tags == nil then
return nil
end
-- Final list of menu items. -- Final list of menu items.
local cls_t = {} local cls_t = {}
@ -40,22 +42,28 @@ function util.menu_clients_current_tags(menu, args)
local cls = t:clients() local cls = t:clients()
for _, c in pairs(cls) do for _, c in pairs(cls) do
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "", cls_t[#cls_t + 1] = {
awful.util.escape(c.name) or '',
function() function()
c.minimized = false c.minimized = false
client.focus = c client.focus = c
c:raise() c:raise()
end, end,
c.icon } c.icon,
}
end end
end end
-- No clients? Then quit. -- No clients? Then quit.
if #cls_t <= 0 then return nil end if #cls_t <= 0 then
return nil
end
-- menu may contain some predefined values, otherwise start with a -- menu may contain some predefined values, otherwise start with a
-- fresh menu. -- fresh menu.
if not menu then menu = {} end if not menu then
menu = {}
end
-- Set the list of items and show the menu. -- Set the list of items and show the menu.
menu.items = cls_t menu.items = cls_t
@ -79,7 +87,9 @@ end
-- https://github.com/lcpz/lain/issues/195 -- https://github.com/lcpz/lain/issues/195
function util.mc(c, width_f, height_f) function util.mc(c, width_f, height_f)
c = c or util.magnified_client c = c or util.magnified_client
if not c then return end if not c then
return
end
c.floating = true c.floating = true
local s = awful.screen.focused() local s = awful.screen.focused()
@ -91,7 +101,9 @@ function util.mc(c, width_f, height_f)
g.x = mg.x + (mg.width - g.width) / 2 g.x = mg.x + (mg.width - g.width) / 2
g.y = mg.y + (mg.height - g.height) / 2 g.y = mg.y + (mg.height - g.height) / 2
if c then c:geometry(g) end -- if c is still a valid object if c then
c:geometry(g)
end -- if c is still a valid object
end end
-- Non-empty tag browsing -- Non-empty tag browsing
@ -133,29 +145,35 @@ end
-- Add a new tag -- Add a new tag
function util.add_tag(layout) function util.add_tag(layout)
awful.prompt.run { awful.prompt.run({
prompt = "New tag name: ", prompt = 'New tag name: ',
textbox = awful.screen.focused().mypromptbox.widget, textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(name) exe_callback = function(name)
if not name or #name == 0 then return end if not name or #name == 0 then
awful.tag.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile }):view_only() return
end end
} awful.tag
.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile })
:view_only()
end,
})
end end
-- Rename current tag -- Rename current tag
function util.rename_tag() function util.rename_tag()
awful.prompt.run { awful.prompt.run({
prompt = "Rename tag: ", prompt = 'Rename tag: ',
textbox = awful.screen.focused().mypromptbox.widget, textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(new_name) exe_callback = function(new_name)
if not new_name or #new_name == 0 then return end if not new_name or #new_name == 0 then
return
end
local t = awful.screen.focused().selected_tag local t = awful.screen.focused().selected_tag
if t then if t then
t.name = new_name t.name = new_name
end end
end end,
} })
end end
-- Move current tag -- Move current tag
@ -173,7 +191,9 @@ end
-- Any rule set on the tag shall be broken -- Any rule set on the tag shall be broken
function util.delete_tag() function util.delete_tag()
local t = awful.screen.focused().selected_tag local t = awful.screen.focused().selected_tag
if not t then return end if not t then
return
end
t:delete() t:delete()
end end

View File

@ -15,13 +15,27 @@ local setmetatable = setmetatable
local markup = { fg = {}, bg = {} } local markup = { fg = {}, bg = {} }
-- Convenience tags -- Convenience tags
function markup.bold(text) return format("<b>%s</b>", text) end function markup.bold(text)
function markup.italic(text) return format("<i>%s</i>", text) end return format('<b>%s</b>', text)
function markup.strike(text) return format("<s>%s</s>", text) end end
function markup.underline(text) return format("<u>%s</u>", text) end function markup.italic(text)
function markup.monospace(text) return format("<tt>%s</tt>", text) end return format('<i>%s</i>', text)
function markup.big(text) return format("<big>%s</big>", text) end end
function markup.small(text) return format("<small>%s</small>", text) end function markup.strike(text)
return format('<s>%s</s>', text)
end
function markup.underline(text)
return format('<u>%s</u>', text)
end
function markup.monospace(text)
return format('<tt>%s</tt>', text)
end
function markup.big(text)
return format('<big>%s</big>', text)
end
function markup.small(text)
return format('<small>%s</small>', text)
end
-- Set the font -- Set the font
function markup.font(font, text) function markup.font(font, text)
@ -59,8 +73,20 @@ function markup.fontcolor(font, fg, bg, text)
end end
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...) -- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end }) setmetatable(markup.fg, {
setmetatable(markup.bg, { __call = function(_, ...) return markup.bg.color(...) end }) __call = function(_, ...)
return markup.fg.color(...)
end,
})
setmetatable(markup.bg, {
__call = function(_, ...)
return markup.bg.color(...)
end,
})
-- link markup(...) calls to markup.fg.color(...) -- link markup(...) calls to markup.fg.color(...)
return setmetatable(markup, { __call = function(_, ...) return markup.fg.color(...) end }) return setmetatable(markup, {
__call = function(_, ...)
return markup.fg.color(...)
end,
})

View File

@ -10,9 +10,9 @@
-- Menu iterator with Naughty notifications -- Menu iterator with Naughty notifications
-- lain.util.menu_iterator -- lain.util.menu_iterator
local naughty = require("naughty") local naughty = require('naughty')
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local atable = require("awful.util").table local atable = require('awful.util').table
local assert = assert local assert = assert
local pairs = pairs local pairs = pairs
local tconcat = table.concat local tconcat = table.concat
@ -27,7 +27,9 @@ local function naughty_destroy_callback(reason)
if actions then if actions then
for _, action in pairs(actions) do for _, action in pairs(actions) do
-- don't try to call nil callbacks -- don't try to call nil callbacks
if action then action() end if action then
action()
end
end end
state.index = nil state.index = nil
end end
@ -56,7 +58,7 @@ local function iterate(menu, timeout, icon)
state.index = state.index + 1 state.index = state.index + 1
if not next then if not next then
label = "Cancel" label = 'Cancel'
state.index = nil state.index = nil
else else
label, _ = unpack(next) label, _ = unpack(next)
@ -68,7 +70,7 @@ local function iterate(menu, timeout, icon)
timeout = timeout, timeout = timeout,
screen = mouse.screen, screen = mouse.screen,
replaces_id = state.cid, replaces_id = state.cid,
destroy = naughty_destroy_callback destroy = naughty_destroy_callback,
}).id }).id
end end
@ -101,7 +103,8 @@ local function menu(args)
local rejected_cb = args.rejected_cb local rejected_cb = args.rejected_cb
local extra_choices = args.extra_choices or {} local extra_choices = args.extra_choices or {}
local ch_combinations = args.combination == "powerset" and helpers.powerset(choices) or helpers.trivial_partition_set(choices) local ch_combinations = args.combination == 'powerset' and helpers.powerset(choices)
or helpers.trivial_partition_set(choices)
for _, c in pairs(extra_choices) do for _, c in pairs(extra_choices) do
ch_combinations = atable.join(ch_combinations, { { c[1] } }) ch_combinations = atable.join(ch_combinations, { { c[1] } })
@ -116,14 +119,18 @@ local function menu(args)
-- selected choices -- selected choices
for _, ch in pairs(c) do for _, ch in pairs(c) do
if atable.hasitem(choices, ch) then if atable.hasitem(choices, ch) then
cbs[#cbs + 1] = selected_cb and function() selected_cb(ch) end or nil cbs[#cbs + 1] = selected_cb and function()
selected_cb(ch)
end or nil
end end
end end
-- rejected choices -- rejected choices
for _, ch in pairs(choices) do for _, ch in pairs(choices) do
if not atable.hasitem(c, ch) and atable.hasitem(choices, ch) then if not atable.hasitem(c, ch) and atable.hasitem(choices, ch) then
cbs[#cbs + 1] = rejected_cb and function() rejected_cb(ch) end or nil cbs[#cbs + 1] = rejected_cb and function()
rejected_cb(ch)
end or nil
end end
end end
@ -134,7 +141,7 @@ local function menu(args)
end end
end end
m[#m + 1] = { name .. ": " .. tconcat(c, " + "), cbs } m[#m + 1] = { name .. ': ' .. tconcat(c, ' + '), cbs }
end end
end end

View File

@ -6,7 +6,7 @@
--]] --]]
local awful = require("awful") local awful = require('awful')
local capi = { client = client } local capi = { client = client }
local math = math local math = math
local string = string local string = string
@ -22,12 +22,15 @@ local quake = {}
-- run into problems with focus. -- run into problems with focus.
function quake:display() function quake:display()
if self.followtag then self.screen = awful.screen.focused() end if self.followtag then
self.screen = awful.screen.focused()
end
-- First, we locate the client -- First, we locate the client
local client = nil local client = nil
local i = 0 local i = 0
for c in awful.client.iterate(function (c) for c in
awful.client.iterate(function(c)
-- c.name may be changed! -- c.name may be changed!
return c.instance == self.name return c.instance == self.name
end) end)
@ -46,12 +49,13 @@ function quake:display()
end end
end end
if not client and not self.visible then return end if not client and not self.visible then
return
end
if not client then if not client then
-- The client does not exist, we spawn it -- The client does not exist, we spawn it
local cmd = string.format("%s %s %s", self.app, local cmd = string.format('%s %s %s', self.app, string.format(self.argname, self.name), self.extra)
string.format(self.argname, self.name), self.extra)
awful.spawn(cmd, { tag = self.screen.selected_tag }) awful.spawn(cmd, { tag = self.screen.selected_tag })
return return
end end
@ -71,7 +75,9 @@ function quake:display()
client.skip_taskbar = true client.skip_taskbar = true
-- Additional user settings -- Additional user settings
if self.settings then self.settings(client) end if self.settings then
self.settings(client)
end
-- Toggle display -- Toggle display
if self.visible then if self.visible then
@ -108,22 +114,36 @@ function quake:compute_size()
geom = screen[self.screen.index].geometry geom = screen[self.screen.index].geometry
end end
local width, height = self.width, self.height local width, height = self.width, self.height
if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end if width <= 1 then
if height <= 1 then height = math.floor(geom.height * height) end width = math.floor(geom.width * width) - 2 * self.border
end
if height <= 1 then
height = math.floor(geom.height * height)
end
local x, y local x, y
if self.horiz == "left" then x = geom.x if self.horiz == 'left' then
elseif self.horiz == "right" then x = geom.width + geom.x - width x = geom.x
else x = geom.x + (geom.width - width)/2 end elseif self.horiz == 'right' then
if self.vert == "top" then y = geom.y x = geom.width + geom.x - width
elseif self.vert == "bottom" then y = geom.height + geom.y - height else
else y = geom.y + (geom.height - height)/2 end x = geom.x + (geom.width - width) / 2
end
if self.vert == 'top' then
y = geom.y
elseif self.vert == 'bottom' then
y = geom.height + geom.y - height
else
y = geom.y + (geom.height - height) / 2
end
self.geometry[self.screen.index] = { x = x, y = y, width = width, height = height } self.geometry[self.screen.index] = { x = x, y = y, width = width, height = height }
end end
return self.geometry[self.screen.index] return self.geometry[self.screen.index]
end end
function quake:toggle() function quake:toggle()
if self.followtag then self.screen = awful.screen.focused() end if self.followtag then
self.screen = awful.screen.focused()
end
local current_tag = self.screen.selected_tag local current_tag = self.screen.selected_tag
if current_tag and self.last_tag ~= current_tag and self.visible then if current_tag and self.last_tag ~= current_tag and self.visible then
local c = self:display() local c = self:display()
@ -139,10 +159,10 @@ end
function quake.new(conf) function quake.new(conf)
conf = conf or {} conf = conf or {}
conf.app = conf.app or "xterm" -- application to spawn conf.app = conf.app or 'xterm' -- application to spawn
conf.name = conf.name or "QuakeDD" -- window name conf.name = conf.name or 'QuakeDD' -- window name
conf.argname = conf.argname or "-name %s" -- how to specify window name conf.argname = conf.argname or '-name %s' -- how to specify window name
conf.extra = conf.extra or "" -- extra arguments conf.extra = conf.extra or '' -- extra arguments
conf.border = conf.border or 1 -- client border width conf.border = conf.border or 1 -- client border width
conf.visible = conf.visible or false -- initially not visible conf.visible = conf.visible or false -- initially not visible
conf.followtag = conf.followtag or false -- spawn on currently focused screen conf.followtag = conf.followtag or false -- spawn on currently focused screen
@ -153,8 +173,8 @@ function quake.new(conf)
-- If width or height <= 1 this is a proportion of the workspace -- If width or height <= 1 this is a proportion of the workspace
conf.height = conf.height or 0.25 -- height conf.height = conf.height or 0.25 -- height
conf.width = conf.width or 1 -- width conf.width = conf.width or 1 -- width
conf.vert = conf.vert or "top" -- top, bottom or center conf.vert = conf.vert or 'top' -- top, bottom or center
conf.horiz = conf.horiz or "left" -- left, right or center conf.horiz = conf.horiz or 'left' -- left, right or center
conf.geometry = {} -- internal use conf.geometry = {} -- internal use
conf.maximized = false conf.maximized = false
@ -162,12 +182,12 @@ function quake.new(conf)
local dropdown = setmetatable(conf, { __index = quake }) local dropdown = setmetatable(conf, { __index = quake })
capi.client.connect_signal("manage", function(c) capi.client.connect_signal('manage', function(c)
if c.instance == dropdown.name and c.screen == dropdown.screen then if c.instance == dropdown.name and c.screen == dropdown.screen then
dropdown:display() dropdown:display()
end end
end) end)
capi.client.connect_signal("unmanage", function(c) capi.client.connect_signal('unmanage', function(c)
if c.instance == dropdown.name and c.screen == dropdown.screen then if c.instance == dropdown.name and c.screen == dropdown.screen then
dropdown.visible = false dropdown.visible = false
end end
@ -176,4 +196,8 @@ function quake.new(conf)
return dropdown return dropdown
end end
return setmetatable(quake, { __call = function(_, ...) return quake.new(...) end }) return setmetatable(quake, {
__call = function(_, ...)
return quake.new(...)
end,
})

View File

@ -6,9 +6,9 @@
--]] --]]
local wibox = require("wibox") local wibox = require('wibox')
local gears = require("gears") local gears = require('gears')
local beautiful = require("beautiful") local beautiful = require('beautiful')
-- Lain Cairo separators util submodule -- Lain Cairo separators util submodule
-- lain.util.separators -- lain.util.separators
@ -29,11 +29,11 @@ function separators.arrow_right(col1, col2)
widget.update = function(_, _) widget.update = function(_, _)
widget.col1 = col1 widget.col1 = col1
widget.col2 = col2 widget.col2 = col2
widget:emit_signal("widget::redraw_needed") widget:emit_signal('widget::redraw_needed')
end end
widget.draw = function(_, _, cr, width, height) widget.draw = function(_, _, cr, width, height)
if widget.col2 ~= "alpha" then if widget.col2 ~= 'alpha' then
cr:set_source_rgba(gears.color.parse_color(widget.col2)) cr:set_source_rgba(gears.color.parse_color(widget.col2))
cr:new_path() cr:new_path()
cr:move_to(0, 0) cr:move_to(0, 0)
@ -50,7 +50,7 @@ function separators.arrow_right(col1, col2)
cr:fill() cr:fill()
end end
if widget.col1 ~= "alpha" then if widget.col1 ~= 'alpha' then
cr:set_source_rgba(gears.color.parse_color(widget.col1)) cr:set_source_rgba(gears.color.parse_color(widget.col1))
cr:new_path() cr:new_path()
cr:move_to(0, 0) cr:move_to(0, 0)
@ -77,11 +77,11 @@ function separators.arrow_left(col1, col2)
widget.update = function(c1, c2) widget.update = function(c1, c2)
widget.col1 = c1 widget.col1 = c1
widget.col2 = c2 widget.col2 = c2
widget:emit_signal("widget::redraw_needed") widget:emit_signal('widget::redraw_needed')
end end
widget.draw = function(_, _, cr, width, height) widget.draw = function(_, _, cr, width, height)
if widget.col1 ~= "alpha" then if widget.col1 ~= 'alpha' then
cr:set_source_rgba(gears.color.parse_color(widget.col1)) cr:set_source_rgba(gears.color.parse_color(widget.col1))
cr:new_path() cr:new_path()
cr:move_to(width, 0) cr:move_to(width, 0)
@ -98,7 +98,7 @@ function separators.arrow_left(col1, col2)
cr:fill() cr:fill()
end end
if widget.col2 ~= "alpha" then if widget.col2 ~= 'alpha' then
cr:new_path() cr:new_path()
cr:move_to(width, 0) cr:move_to(width, 0)
cr:line_to(0, height / 2) cr:line_to(0, height / 2)

View File

@ -6,9 +6,9 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local shell = require("awful.util").shell local shell = require('awful.util').shell
local wibox = require("wibox") local wibox = require('wibox')
local string = string local string = string
-- ALSA volume -- ALSA volume
@ -20,22 +20,25 @@ local function factory(args)
local timeout = args.timeout or 5 local timeout = args.timeout or 5
local settings = args.settings or function() end local settings = args.settings or function() end
alsa.cmd = args.cmd or "amixer" alsa.cmd = args.cmd or 'amixer'
alsa.channel = args.channel or "Master" alsa.channel = args.channel or 'Master'
alsa.togglechannel = args.togglechannel alsa.togglechannel = args.togglechannel
local format_cmd = string.format("%s get %s", alsa.cmd, alsa.channel) local format_cmd = string.format('%s get %s', alsa.cmd, alsa.channel)
if alsa.togglechannel then if alsa.togglechannel then
format_cmd = { shell, "-c", string.format("%s get %s; %s get %s", format_cmd = {
alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel) } shell,
'-c',
string.format('%s get %s; %s get %s', alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel),
}
end end
alsa.last = {} alsa.last = {}
function alsa.update() function alsa.update()
helpers.async(format_cmd, function(mixer) helpers.async(format_cmd, function(mixer)
local l,s = string.match(mixer, "([%d]+)%%.*%[([%l]*)") local l, s = string.match(mixer, '([%d]+)%%.*%[([%l]*)')
l = tonumber(l) l = tonumber(l)
if alsa.last.level ~= l or alsa.last.status ~= s then if alsa.last.level ~= l or alsa.last.status ~= s then
volume_now = { level = l, status = s } volume_now = { level = l, status = s }
@ -46,7 +49,7 @@ local function factory(args)
end) end)
end end
helpers.newtimer(string.format("alsa-%s-%s", alsa.cmd, alsa.channel), timeout, alsa.update) helpers.newtimer(string.format('alsa-%s-%s', alsa.cmd, alsa.channel), timeout, alsa.update)
return alsa return alsa
end end

View File

@ -6,10 +6,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local awful = require("awful") local awful = require('awful')
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local math = math local math = math
local string = string local string = string
local type = type local type = type
@ -21,13 +21,13 @@ local tonumber = tonumber
local function factory(args) local function factory(args)
local alsabar = { local alsabar = {
colors = { colors = {
background = "#000000", background = '#000000',
mute = "#EB8F8F", mute = '#EB8F8F',
unmute = "#A4CE8A" unmute = '#A4CE8A',
}, },
_current_level = 0, _current_level = 0,
_playback = "off" _playback = 'off',
} }
args = args or {} args = args or {}
@ -39,30 +39,33 @@ local function factory(args)
local margins = args.margins or 1 local margins = args.margins or 1
local ticks = args.ticks or false local ticks = args.ticks or false
local ticks_size = args.ticks_size or 7 local ticks_size = args.ticks_size or 7
local tick = args.tick or "|" local tick = args.tick or '|'
local tick_pre = args.tick_pre or "[" local tick_pre = args.tick_pre or '['
local tick_post = args.tick_post or "]" local tick_post = args.tick_post or ']'
local tick_none = args.tick_none or " " local tick_none = args.tick_none or ' '
alsabar.cmd = args.cmd or "amixer" alsabar.cmd = args.cmd or 'amixer'
alsabar.channel = args.channel or "Master" alsabar.channel = args.channel or 'Master'
alsabar.togglechannel = args.togglechannel alsabar.togglechannel = args.togglechannel
alsabar.colors = args.colors or alsabar.colors alsabar.colors = args.colors or alsabar.colors
alsabar.followtag = args.followtag or false alsabar.followtag = args.followtag or false
alsabar.notification_preset = args.notification_preset alsabar.notification_preset = args.notification_preset
if not alsabar.notification_preset then if not alsabar.notification_preset then
alsabar.notification_preset = { font = "Monospace 10" } alsabar.notification_preset = { font = 'Monospace 10' }
end end
local format_cmd = string.format("%s get %s", alsabar.cmd, alsabar.channel) local format_cmd = string.format('%s get %s', alsabar.cmd, alsabar.channel)
if alsabar.togglechannel then if alsabar.togglechannel then
format_cmd = { awful.util.shell, "-c", string.format("%s get %s; %s get %s", format_cmd = {
alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel) } awful.util.shell,
'-c',
string.format('%s get %s; %s get %s', alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel),
}
end end
alsabar.bar = wibox.widget { alsabar.bar = wibox.widget({
color = alsabar.colors.unmute, color = alsabar.colors.unmute,
background_color = alsabar.colors.background, background_color = alsabar.colors.background,
forced_height = height, forced_height = height,
@ -71,38 +74,42 @@ local function factory(args)
paddings = margins, paddings = margins,
ticks = ticks, ticks = ticks,
ticks_size = ticks_size, ticks_size = ticks_size,
widget = wibox.widget.progressbar widget = wibox.widget.progressbar,
} })
alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } }) alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
function alsabar.update(callback) function alsabar.update(callback)
helpers.async(format_cmd, function(mixer) helpers.async(format_cmd, function(mixer)
local vol, playback = string.match(mixer, "([%d]+)%%.*%[([%l]*)") local vol, playback = string.match(mixer, '([%d]+)%%.*%[([%l]*)')
if not vol or not playback then return end if not vol or not playback then
return
end
if vol ~= alsabar._current_level or playback ~= alsabar._playback then if vol ~= alsabar._current_level or playback ~= alsabar._playback then
alsabar._current_level = tonumber(vol) alsabar._current_level = tonumber(vol)
alsabar.bar:set_value(alsabar._current_level / 100) alsabar.bar:set_value(alsabar._current_level / 100)
if alsabar._current_level == 0 or playback == "off" then if alsabar._current_level == 0 or playback == 'off' then
alsabar._playback = playback alsabar._playback = playback
alsabar.tooltip:set_text("[Muted]") alsabar.tooltip:set_text('[Muted]')
alsabar.bar.color = alsabar.colors.mute alsabar.bar.color = alsabar.colors.mute
else else
alsabar._playback = "on" alsabar._playback = 'on'
alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, vol)) alsabar.tooltip:set_text(string.format('%s: %s', alsabar.channel, vol))
alsabar.bar.color = alsabar.colors.unmute alsabar.bar.color = alsabar.colors.unmute
end end
volume_now = { volume_now = {
level = alsabar._current_level, level = alsabar._current_level,
status = alsabar._playback status = alsabar._playback,
} }
settings() settings()
if type(callback) == "function" then callback() end if type(callback) == 'function' then
callback()
end
end end
end) end)
end end
@ -111,10 +118,10 @@ local function factory(args)
alsabar.update(function() alsabar.update(function()
local preset = alsabar.notification_preset local preset = alsabar.notification_preset
preset.title = string.format("%s - %s%%", alsabar.channel, alsabar._current_level) preset.title = string.format('%s - %s%%', alsabar.channel, alsabar._current_level)
if alsabar._playback == "off" then if alsabar._playback == 'off' then
preset.title = preset.title .. " Muted" preset.title = preset.title .. ' Muted'
end end
-- tot is the maximum number of ticks to display in the notification -- tot is the maximum number of ticks to display in the notification
@ -125,7 +132,7 @@ local function factory(args)
-- if we can grab mywibox, tot is defined as its height if -- if we can grab mywibox, tot is defined as its height if
-- horizontal, or width otherwise -- horizontal, or width otherwise
if wib then if wib then
if wib.position == "left" or wib.position == "right" then if wib.position == 'left' or wib.position == 'right' then
tot = wib.width tot = wib.width
else else
tot = wib.height tot = wib.height
@ -137,28 +144,27 @@ local function factory(args)
end end
local int = math.modf((alsabar._current_level / 100) * tot) local int = math.modf((alsabar._current_level / 100) * tot)
preset.text = string.format( preset.text =
"%s%s%s%s", string.format('%s%s%s%s', tick_pre, string.rep(tick, int), string.rep(tick_none, tot - int), tick_post)
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 alsabar.followtag then
preset.screen = awful.screen.focused()
end
if not alsabar.notification then if not alsabar.notification then
alsabar.notification = naughty.notify { alsabar.notification = naughty.notify({
preset = preset, preset = preset,
destroy = function() alsabar.notification = nil end destroy = function()
} alsabar.notification = nil
end,
})
else else
naughty.replace_text(alsabar.notification, preset.title, preset.text) naughty.replace_text(alsabar.notification, preset.title, preset.text)
end end
end) end)
end end
helpers.newtimer(string.format("alsabar-%s-%s", alsabar.cmd, alsabar.channel), timeout, alsabar.update) helpers.newtimer(string.format('alsabar-%s-%s', alsabar.cmd, alsabar.channel), timeout, alsabar.update)
return alsabar return alsabar
end end

View File

@ -6,10 +6,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local fs = require("gears.filesystem") local fs = require('gears.filesystem')
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local math = math local math = math
local string = string local string = string
local ipairs = ipairs local ipairs = ipairs
@ -19,10 +19,10 @@ local tonumber = tonumber
-- lain.widget.bat -- lain.widget.bat
local function factory(args) local function factory(args)
local pspath = args.pspath or "/sys/class/power_supply/" local pspath = args.pspath or '/sys/class/power_supply/'
if not fs.is_dir(pspath) then if not fs.is_dir(pspath) then
naughty.notify { text = "lain.widget.bat: invalid power supply path", timeout = 0 } naughty.notify({ text = 'lain.widget.bat: invalid power supply path', timeout = 0 })
return return
end end
@ -30,64 +30,66 @@ local function factory(args)
local bat = { widget = args.widget or wibox.widget.textbox() } local bat = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 30 local timeout = args.timeout or 30
local notify = args.notify or "on" local notify = args.notify or 'on'
local full_notify = args.full_notify or notify local full_notify = args.full_notify or notify
local n_perc = args.n_perc or { 5, 15 } local n_perc = args.n_perc or { 5, 15 }
local batteries = args.batteries or (args.battery and { args.battery }) or {} local batteries = args.batteries or (args.battery and { args.battery }) or {}
local ac = args.ac or "AC0" local ac = args.ac or 'AC0'
local settings = args.settings or function() end local settings = args.settings or function() end
function bat.get_batteries() function bat.get_batteries()
helpers.line_callback("ls -1 " .. pspath, function(line) helpers.line_callback('ls -1 ' .. pspath, function(line)
local bstr = string.match(line, "BAT%w+") local bstr = string.match(line, 'BAT%w+')
if bstr then if bstr then
batteries[#batteries + 1] = bstr batteries[#batteries + 1] = bstr
else else
ac = string.match(line, "A%w+") or ac ac = string.match(line, 'A%w+') or ac
end end
end) end)
end end
if #batteries == 0 then bat.get_batteries() end if #batteries == 0 then
bat.get_batteries()
end
bat_notification_critical_preset = { bat_notification_critical_preset = {
title = "Battery exhausted", title = 'Battery exhausted',
text = "Shutdown imminent", text = 'Shutdown imminent',
timeout = 15, timeout = 15,
fg = "#000000", fg = '#000000',
bg = "#FFFFFF" bg = '#FFFFFF',
} }
bat_notification_low_preset = { bat_notification_low_preset = {
title = "Battery low", title = 'Battery low',
text = "Plug the cable!", text = 'Plug the cable!',
timeout = 15, timeout = 15,
fg = "#202020", fg = '#202020',
bg = "#CDCDCD" bg = '#CDCDCD',
} }
bat_notification_charged_preset = { bat_notification_charged_preset = {
title = "Battery full", title = 'Battery full',
text = "You can unplug the cable", text = 'You can unplug the cable',
timeout = 15, timeout = 15,
fg = "#202020", fg = '#202020',
bg = "#CDCDCD" bg = '#CDCDCD',
} }
bat_now = { bat_now = {
status = "N/A", status = 'N/A',
ac_status = "N/A", ac_status = 'N/A',
perc = "N/A", perc = 'N/A',
time = "N/A", time = 'N/A',
watt = "N/A", watt = 'N/A',
capacity = "N/A" capacity = 'N/A',
} }
bat_now.n_status = {} bat_now.n_status = {}
bat_now.n_perc = {} bat_now.n_perc = {}
bat_now.n_capacity = {} bat_now.n_capacity = {}
for i = 1, #batteries do for i = 1, #batteries do
bat_now.n_status[i] = "N/A" bat_now.n_status[i] = 'N/A'
bat_now.n_perc[i] = 0 bat_now.n_perc[i] = 0
bat_now.n_capacity[i] = 0 bat_now.n_capacity[i] = 0
end end
@ -108,28 +110,27 @@ local function factory(args)
for i, battery in ipairs(batteries) do for i, battery in ipairs(batteries) do
local bstr = pspath .. battery local bstr = pspath .. battery
local present = helpers.first_line(bstr .. "/present") local present = helpers.first_line(bstr .. '/present')
if tonumber(present) == 1 then if tonumber(present) == 1 then
-- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW] -- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
local rate_current = tonumber(helpers.first_line(bstr .. "/current_now")) local rate_current = tonumber(helpers.first_line(bstr .. '/current_now'))
local rate_voltage = tonumber(helpers.first_line(bstr .. "/voltage_now")) local rate_voltage = tonumber(helpers.first_line(bstr .. '/voltage_now'))
local rate_power = tonumber(helpers.first_line(bstr .. "/power_now")) local rate_power = tonumber(helpers.first_line(bstr .. '/power_now'))
local charge_full = tonumber(helpers.first_line(bstr .. "/charge_full")) local charge_full = tonumber(helpers.first_line(bstr .. '/charge_full'))
local charge_design = tonumber(helpers.first_line(bstr .. "/charge_full_design")) local charge_design = tonumber(helpers.first_line(bstr .. '/charge_full_design'))
-- energy_now(P)[uWh], charge_now(I)[uAh] -- energy_now(P)[uWh], charge_now(I)[uAh]
local energy_now = tonumber(helpers.first_line(bstr .. "/energy_now") or local energy_now =
helpers.first_line(bstr .. "/charge_now")) tonumber(helpers.first_line(bstr .. '/energy_now') or helpers.first_line(bstr .. '/charge_now'))
-- energy_full(P)[uWh], charge_full(I)[uAh] -- energy_full(P)[uWh], charge_full(I)[uAh]
local energy_full = tonumber(helpers.first_line(bstr .. "/energy_full") or local energy_full = tonumber(helpers.first_line(bstr .. '/energy_full') or charge_full)
charge_full)
local energy_percentage = tonumber(helpers.first_line(bstr .. "/capacity")) or local energy_percentage = tonumber(helpers.first_line(bstr .. '/capacity'))
math.floor((energy_now / energy_full) * 100) or math.floor((energy_now / energy_full) * 100)
bat_now.n_status[i] = helpers.first_line(bstr .. "/status") or "N/A" 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] bat_now.n_perc[i] = energy_percentage or bat_now.n_perc[i]
if not charge_design or charge_design == 0 then if not charge_design or charge_design == 0 then
@ -155,28 +156,28 @@ local function factory(args)
-- "Full", "Unknown" or "Charging". When the laptop is not plugged in, -- "Full", "Unknown" or "Charging". When the laptop is not plugged in,
-- one or more of the batteries may be full, but only one battery -- one or more of the batteries may be full, but only one battery
-- discharging suffices to set global status to "Discharging". -- discharging suffices to set global status to "Discharging".
bat_now.status = bat_now.n_status[1] or "N/A" bat_now.status = bat_now.n_status[1] or 'N/A'
for _, status in ipairs(bat_now.n_status) do for _, status in ipairs(bat_now.n_status) do
if status == "Discharging" or status == "Charging" then if status == 'Discharging' or status == 'Charging' then
bat_now.status = status bat_now.status = status
end end
end end
bat_now.ac_status = tonumber(helpers.first_line(string.format("%s%s/online", pspath, ac))) or "N/A" 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 ~= 'N/A' then
if bat_now.status ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 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.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
bat_now.time = "00:00" bat_now.time = '00:00'
bat_now.watt = 0 bat_now.watt = 0
-- update {perc,time,watt} iff battery not full and rate > 0 -- update {perc,time,watt} iff battery not full and rate > 0
elseif bat_now.status ~= "Full" then elseif bat_now.status ~= 'Full' then
local rate_time = 0 local rate_time = 0
-- Calculate time and watt if rates are greater then 0 -- Calculate time and watt if rates are greater then 0
if (sum_rate_power > 0 or sum_rate_current > 0) then 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 local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
if bat_now.status == "Charging" then if bat_now.status == 'Charging' then
rate_time = (sum_energy_full - sum_energy_now) / div rate_time = (sum_energy_full - sum_energy_now) / div
else -- Discharging else -- Discharging
rate_time = sum_energy_now / div rate_time = sum_energy_now / div
@ -191,11 +192,11 @@ local function factory(args)
local hours = math.floor(rate_time) local hours = math.floor(rate_time)
local minutes = math.floor((rate_time - hours) * 60) 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.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
bat_now.time = string.format("%02d:%02d", hours, minutes) bat_now.time = string.format('%02d:%02d', hours, minutes)
bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6)) bat_now.watt = tonumber(string.format('%.2f', sum_rate_energy / 1e6))
elseif bat_now.status == "Full" then elseif bat_now.status == 'Full' then
bat_now.perc = 100 bat_now.perc = 100
bat_now.time = "00:00" bat_now.time = '00:00'
bat_now.watt = 0 bat_now.watt = 0
end end
end end
@ -204,31 +205,31 @@ local function factory(args)
settings() settings()
-- notifications for critical, low, and full levels -- notifications for critical, low, and full levels
if notify == "on" then if notify == 'on' then
if bat_now.status == "Discharging" then if bat_now.status == 'Discharging' then
if tonumber(bat_now.perc) <= n_perc[1] then if tonumber(bat_now.perc) <= n_perc[1] then
bat.id = naughty.notify({ bat.id = naughty.notify({
preset = bat_notification_critical_preset, preset = bat_notification_critical_preset,
replaces_id = bat.id replaces_id = bat.id,
}).id }).id
elseif tonumber(bat_now.perc) <= n_perc[2] then elseif tonumber(bat_now.perc) <= n_perc[2] then
bat.id = naughty.notify({ bat.id = naughty.notify({
preset = bat_notification_low_preset, preset = bat_notification_low_preset,
replaces_id = bat.id replaces_id = bat.id,
}).id }).id
end end
fullnotification = false fullnotification = false
elseif bat_now.status == "Full" and full_notify == "on" and not fullnotification then elseif bat_now.status == 'Full' and full_notify == 'on' and not fullnotification then
bat.id = naughty.notify({ bat.id = naughty.notify({
preset = bat_notification_charged_preset, preset = bat_notification_charged_preset,
replaces_id = bat.id replaces_id = bat.id,
}).id }).id
fullnotification = true fullnotification = true
end end
end end
end end
helpers.newtimer("batteries", timeout, bat.update) helpers.newtimer('batteries', timeout, bat.update)
return bat return bat
end end

View File

@ -5,10 +5,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local markup = require("lain.util.markup") local markup = require('lain.util.markup')
local awful = require("awful") local awful = require('awful')
local naughty = require("naughty") local naughty = require('naughty')
local floor = math.floor local floor = math.floor
local os = os local os = os
local pairs = pairs local pairs = pairs
@ -28,24 +28,28 @@ local function factory(args)
week_start = args.week_start or 2, week_start = args.week_start or 2,
three = args.three or false, three = args.three or false,
followtag = args.followtag or false, followtag = args.followtag or false,
week_number = args.week_number or "none", week_number = args.week_number or 'none',
week_number_format = args.week_number_format or args.week_number == "left" and "%3d | " or "| %-3d", 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/", icons = args.icons or helpers.icons_dir .. 'cal/white/',
notification_preset = args.notification_preset or { notification_preset = args.notification_preset or {
font = "Monospace 10", fg = "#FFFFFF", bg = "#000000" font = 'Monospace 10',
} fg = '#FFFFFF',
bg = '#000000',
},
} }
function cal.get_week_number(m, st_day, x) function cal.get_week_number(m, st_day, x)
local date = os.date("*t", m) local date = os.date('*t', m)
local week_step = (x ~= 0 and floor((x + st_day) / 7) - 1 or 0); local week_step = (x ~= 0 and floor((x + st_day) / 7) - 1 or 0)
local display_time = os.time { local display_time = os.time({
year = date.year, month = date.month, day = date.day + 7 * week_step year = date.year,
} month = date.month,
day = date.day + 7 * week_step,
})
return string.format(cal.week_number_format, os.date("%V", display_time)) return string.format(cal.week_number_format, os.date('%V', display_time))
end end
function cal.sum_week_days(x, y) function cal.sum_week_days(x, y)
@ -53,55 +57,70 @@ local function factory(args)
end end
function cal.build(month, year) function cal.build(month, year)
local current_month, current_year = tonumber(os.date("%m")), tonumber(os.date("%Y")) 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 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 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 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 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 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)) } 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 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 })) notifytable[#notifytable + 1] = string.format(
'%3s ',
os.date('%a', os.time({ year = 2006, month = 1, day = day_num + cal.week_start }))
)
end end
notifytable[#notifytable] = string.format("%s\n%s", notifytable[#notifytable]:sub(1, -2), string.rep(" ", st_day*4)) notifytable[#notifytable] =
string.format('%s\n%s', notifytable[#notifytable]:sub(1, -2), string.rep(' ', st_day * 4))
local strx local strx
for x = 1, mth_days do for x = 1, mth_days do
strx = x strx = x
if x == today then if x == today then
if x < 10 then x = " " .. x end if x < 10 then
strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. " ") x = ' ' .. x
end end
strx = string.format("%s%s", string.rep(" ", 3 - tostring(x):len()), strx) strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. ' ')
notifytable[#notifytable+1] = string.format("%-4s%s", strx, (x+st_day)%7==0 and x ~= mth_days and "\n" or "") 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 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 cal.month, cal.year = d.month, d.year
if cal.week_number ~= "none" then 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 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()) local head_prepend = string.rep(' ', tostring(string.format(cal.week_number_format, 0)):len())
if cal.week_number == "left" then if cal.week_number == 'left' then
notifytable[1] = head_prepend .. notifytable[1] -- month-year row notifytable[1] = head_prepend .. notifytable[1] -- month-year row
notifytable[2] = head_prepend .. notifytable[2] -- weekdays 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 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 for x = 10, #notifytable do
if cal.sum_week_days(st_day, x) == 2 then if cal.sum_week_days(st_day, x) == 2 then
notifytable[x] = cal.get_week_number(m, st_day, x) .. notifytable[x] notifytable[x] = cal.get_week_number(m, st_day, x) .. notifytable[x]
end end
end end
elseif cal.week_number == "right" then elseif cal.week_number == 'right' then
notifytable[8] = notifytable[8]:gsub("\n", head_prepend .. "\n") -- weekdays row notifytable[8] = notifytable[8]:gsub('\n', head_prepend .. '\n') -- weekdays row
for x = 9, #notifytable do for x = 9, #notifytable do
if cal.sum_week_days(st_day, x) == 1 then 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") notifytable[x] = notifytable[x]:gsub('\n', cal.get_week_number(m, st_day, x - 7) .. '\n')
end end
end end
-- last week of the month -- last week of the month
local end_days = cal.sum_week_days(st_day, mth_days) local end_days = cal.sum_week_days(st_day, mth_days)
if end_days ~= 0 then end_days = 7 - end_days end if end_days ~= 0 then
notifytable[#notifytable] = notifytable[#notifytable] .. string.rep(" ", 4 * end_days) .. cal.get_week_number(m, st_day, mth_days + end_days) 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
end end
@ -110,8 +129,8 @@ local function factory(args)
function cal.getdate(month, year, offset) function cal.getdate(month, year, offset)
if not month or not year then if not month or not year then
month = tonumber(os.date("%m")) month = tonumber(os.date('%m'))
year = tonumber(os.date("%Y")) year = tonumber(os.date('%Y'))
end end
month = month + offset month = month + offset
@ -130,7 +149,9 @@ local function factory(args)
end end
function cal.hide() function cal.hide()
if not cal.notification then return end if not cal.notification then
return
end
naughty.destroy(cal.notification) naughty.destroy(cal.notification)
cal.notification = nil cal.notification = nil
end end
@ -142,9 +163,12 @@ local function factory(args)
local current_month, current_year = cal.month, cal.year local current_month, current_year = cal.month, cal.year
local prev_month, prev_year = cal.getdate(cal.month, cal.year, -1) local prev_month, prev_year = cal.getdate(cal.month, cal.year, -1)
local next_month, next_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", text = string.format(
tconcat(cal.build(prev_month, prev_year)), text, '%s\n\n%s\n\n%s',
tconcat(cal.build(next_month, next_year))) tconcat(cal.build(prev_month, prev_year)),
text,
tconcat(cal.build(next_month, next_year))
)
cal.month, cal.year = current_month, current_year cal.month, cal.year = current_month, current_year
end end
@ -154,36 +178,47 @@ local function factory(args)
return return
end end
cal.notification = naughty.notify { cal.notification = naughty.notify({
preset = cal.notification_preset, preset = cal.notification_preset,
screen = cal.followtag and awful.screen.focused() or scr or 1, screen = cal.followtag and awful.screen.focused() or scr or 1,
icon = cal.icon, icon = cal.icon,
timeout = type(seconds) == "number" and seconds or cal.notification_preset.timeout or 5, timeout = type(seconds) == 'number' and seconds or cal.notification_preset.timeout or 5,
text = text text = text,
} })
end end
function cal.hover_on() cal.show(0) end function cal.hover_on()
cal.show(0)
end
function cal.move(offset) function cal.move(offset)
offset = offset or 0 offset = offset or 0
cal.month, cal.year = cal.getdate(cal.month, cal.year, offset) cal.month, cal.year = cal.getdate(cal.month, cal.year, offset)
cal.show(0, cal.month, cal.year) cal.show(0, cal.month, cal.year)
end end
function cal.prev() cal.move(-1) end function cal.prev()
function cal.next() cal.move( 1) end cal.move(-1)
end
function cal.next()
cal.move(1)
end
function cal.attach(widget) function cal.attach(widget)
widget:connect_signal("mouse::enter", cal.hover_on) widget:connect_signal('mouse::enter', cal.hover_on)
widget:connect_signal("mouse::leave", cal.hide) widget:connect_signal('mouse::leave', cal.hide)
widget:buttons(awful.util.table.join( widget:buttons(
awful.util.table.join(
awful.button({}, 1, cal.prev), awful.button({}, 1, cal.prev),
awful.button({}, 3, cal.next), awful.button({}, 3, cal.next),
awful.button({}, 2, cal.hover_on), awful.button({}, 2, cal.hover_on),
awful.button({}, 5, cal.prev), awful.button({}, 5, cal.prev),
awful.button({}, 4, cal.next))) awful.button({}, 4, cal.next)
)
)
end end
for _, widget in pairs(cal.attach_to) do cal.attach(widget) end for _, widget in pairs(cal.attach_to) do
cal.attach(widget)
end
return cal return cal
end end

View File

@ -10,9 +10,9 @@
--]] --]]
local wrequire = require("lain.helpers").wrequire local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable local setmetatable = setmetatable
local widget = { _NAME = "lain.widget.contrib" } local widget = { _NAME = 'lain.widget.contrib' }
return setmetatable(widget, { __index = wrequire }) return setmetatable(widget, { __index = wrequire })

View File

@ -5,12 +5,12 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local shell = require("awful.util").shell local shell = require('awful.util').shell
local focused = require("awful.screen").focused local focused = require('awful.screen').focused
local escape_f = require("awful.util").escape local escape_f = require('awful.util').escape
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local os = os local os = os
local string = string local string = string
@ -22,52 +22,61 @@ local function factory(args)
local moc = { widget = args.widget or wibox.widget.textbox() } local moc = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 2 local timeout = args.timeout or 2
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music" local music_dir = args.music_dir or os.getenv('HOME') .. '/Music'
local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$" local cover_pattern = args.cover_pattern or '*\\.(jpg|jpeg|png|gif)$'
local cover_size = args.cover_size or 100 local cover_size = args.cover_size or 100
local default_art = args.default_art or "" local default_art = args.default_art or ''
local followtag = args.followtag or false local followtag = args.followtag or false
local settings = args.settings or function() end local settings = args.settings or function() end
moc_notification_preset = { title = "Now playing", timeout = 6 } moc_notification_preset = { title = 'Now playing', timeout = 6 }
helpers.set_map("current moc track", nil) helpers.set_map('current moc track', nil)
function moc.update() function moc.update()
helpers.async("mocp -i", function(f) helpers.async('mocp -i', function(f)
moc_now = { moc_now = {
state = "N/A", state = 'N/A',
file = "N/A", file = 'N/A',
artist = "N/A", artist = 'N/A',
title = "N/A", title = 'N/A',
album = "N/A", album = 'N/A',
elapsed = "N/A", elapsed = 'N/A',
total = "N/A" total = 'N/A',
} }
for line in string.gmatch(f, "[^\n]+") do for line in string.gmatch(f, '[^\n]+') do
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do for k, v in string.gmatch(line, '([%w]+):[%s](.*)$') do
if k == "State" then moc_now.state = v if k == 'State' then
elseif k == "File" then moc_now.file = v moc_now.state = v
elseif k == "Artist" then moc_now.artist = escape_f(v) elseif k == 'File' then
elseif k == "SongTitle" then moc_now.title = escape_f(v) moc_now.file = v
elseif k == "Album" then moc_now.album = escape_f(v) elseif k == 'Artist' then
elseif k == "CurrentTime" then moc_now.elapsed = escape_f(v) moc_now.artist = escape_f(v)
elseif k == "TotalTime" then moc_now.total = 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 end
end end
moc_notification_preset.text = string.format("%s (%s) - %s\n%s", moc_now.artist, moc_notification_preset.text =
moc_now.album, moc_now.total, moc_now.title) string.format('%s (%s) - %s\n%s', moc_now.artist, moc_now.album, moc_now.total, moc_now.title)
widget = moc.widget widget = moc.widget
settings() settings()
if moc_now.state == "PLAY" then if moc_now.state == 'PLAY' then
if moc_now.title ~= helpers.get_map("current moc track") then if moc_now.title ~= helpers.get_map('current moc track') then
helpers.set_map("current moc track", moc_now.title) helpers.set_map('current moc track', moc_now.title)
if followtag then moc_notification_preset.screen = focused() end if followtag then
moc_notification_preset.screen = focused()
end
local common = { local common = {
preset = moc_notification_preset, preset = moc_notification_preset,
@ -76,20 +85,21 @@ local function factory(args)
replaces_id = moc.id, replaces_id = moc.id,
} }
local path = string.format("%s/%s", music_dir, string.match(moc_now.file, ".*/")) 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) local cover =
helpers.async({ shell, "-c", cover }, function(current_icon) string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'", path, cover_pattern)
common.icon = current_icon:gsub("\n", "") helpers.async({ shell, '-c', cover }, function(current_icon)
common.icon = current_icon:gsub('\n', '')
moc.id = naughty.notify(common).id moc.id = naughty.notify(common).id
end) end)
end end
elseif moc_now.state ~= "PAUSE" then elseif moc_now.state ~= 'PAUSE' then
helpers.set_map("current moc track", nil) helpers.set_map('current moc track', nil)
end end
end) end)
end end
moc.timer = helpers.newtimer("moc", timeout, moc.update, true, true) moc.timer = helpers.newtimer('moc', timeout, moc.update, true, true)
return moc return moc
end end

View File

@ -6,8 +6,8 @@
--]] --]]
local async = require("lain.helpers").async local async = require('lain.helpers').async
local awful = require("awful") local awful = require('awful')
local execute = os.execute local execute = os.execute
local type = type local type = type
@ -16,20 +16,20 @@ local type = type
local redshift = { active = false, pid = nil } local redshift = { active = false, pid = nil }
function redshift.start() function redshift.start()
execute("pkill redshift") execute('pkill redshift')
awful.spawn.with_shell("redshift -x") -- clear adjustments awful.spawn.with_shell('redshift -x') -- clear adjustments
redshift.pid = awful.spawn.with_shell("redshift") redshift.pid = awful.spawn.with_shell('redshift')
redshift.active = true redshift.active = true
if type(redshift.update_fun) == "function" then if type(redshift.update_fun) == 'function' then
redshift.update_fun(redshift.active) redshift.update_fun(redshift.active)
end end
end end
function redshift.toggle() function redshift.toggle()
async({ awful.util.shell, "-c", string.format("ps -p %d -o pid=", redshift.pid) }, function(f) 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 if f and #f > 0 then -- redshift is running
-- Sending -USR1 toggles redshift (See project website) -- Sending -USR1 toggles redshift (See project website)
execute("pkill -USR1 redshift") execute('pkill -USR1 redshift')
redshift.active = not redshift.active redshift.active = not redshift.active
else -- not started or killed, (re)start it else -- not started or killed, (re)start it
redshift.start() redshift.start()
@ -45,9 +45,13 @@ end
-- Use it to update widget text or icons on status change. -- Use it to update widget text or icons on status change.
function redshift.attach(widget, fun) function redshift.attach(widget, fun)
redshift.update_fun = fun or function() end redshift.update_fun = fun or function() end
if not redshift.pid then redshift.start() end if not redshift.pid then
redshift.start()
end
if widget then if widget then
widget:buttons(awful.util.table.join(awful.button({}, 1, function () redshift.toggle() end))) widget:buttons(awful.util.table.join(awful.button({}, 1, function()
redshift.toggle()
end)))
end end
end end

View File

@ -5,10 +5,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local markup = require("lain.util").markup local markup = require('lain.util').markup
local awful = require("awful") local awful = require('awful')
local naughty = require("naughty") local naughty = require('naughty')
local mouse = mouse local mouse = mouse
-- Taskwarrior notification -- Taskwarrior notification
@ -16,7 +16,9 @@ local mouse = mouse
local task = {} local task = {}
function task.hide() function task.hide()
if not task.notification then return end if not task.notification then
return
end
naughty.destroy(task.notification) naughty.destroy(task.notification)
task.notification = nil task.notification = nil
end end
@ -24,7 +26,7 @@ end
function task.show(scr) function task.show(scr)
task.notification_preset.screen = task.followtag and awful.screen.focused() or scr or 1 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) helpers.async({ awful.util.shell, '-c', task.show_cmd }, function(f)
local widget_focused = true local widget_focused = true
if mouse.current_widgets then if mouse.current_widgets then
@ -39,53 +41,55 @@ function task.show(scr)
if widget_focused then if widget_focused then
task.hide() task.hide()
task.notification = naughty.notify { task.notification = naughty.notify({
preset = task.notification_preset, preset = task.notification_preset,
title = "task next", title = 'task next',
text = markup.font(task.notification_preset.font, text = markup.font(task.notification_preset.font, awful.util.escape(f:gsub('\n*$', ''))),
awful.util.escape(f:gsub("\n*$", ""))) })
}
end end
end) end)
end end
function task.prompt() function task.prompt()
awful.prompt.run { awful.prompt.run({
prompt = task.prompt_text, prompt = task.prompt_text,
textbox = awful.screen.focused().mypromptbox.widget, textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(t) exe_callback = function(t)
helpers.async(t, function(f) helpers.async(t, function(f)
naughty.notify { naughty.notify({
preset = task.notification_preset, preset = task.notification_preset,
title = t, title = t,
text = markup.font(task.notification_preset.font, text = markup.font(task.notification_preset.font, awful.util.escape(f:gsub('\n*$', ''))),
awful.util.escape(f:gsub("\n*$", ""))) })
}
end) end)
end, end,
history_path = awful.util.getdir("cache") .. "/history_task" history_path = awful.util.getdir('cache') .. '/history_task',
} })
end end
function task.attach(widget, args) function task.attach(widget, args)
args = args or {} args = args or {}
task.show_cmd = args.show_cmd or "task next" task.show_cmd = args.show_cmd or 'task next'
task.prompt_text = args.prompt_text or "Enter task command: " task.prompt_text = args.prompt_text or 'Enter task command: '
task.followtag = args.followtag or false task.followtag = args.followtag or false
task.notification_preset = args.notification_preset task.notification_preset = args.notification_preset
task.widget = widget task.widget = widget
if not task.notification_preset then if not task.notification_preset then
task.notification_preset = { task.notification_preset = {
font = "Monospace 10", font = 'Monospace 10',
icon = helpers.icons_dir .. "/taskwarrior.png" icon = helpers.icons_dir .. '/taskwarrior.png',
} }
end end
if widget then if widget then
widget:connect_signal("mouse::enter", function () task.show() end) widget:connect_signal('mouse::enter', function()
widget:connect_signal("mouse::leave", function () task.hide() end) task.show()
end)
widget:connect_signal('mouse::leave', function()
task.hide()
end)
end end
end end

View File

@ -6,10 +6,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local focused = require("awful.screen").focused local focused = require('awful.screen').focused
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local string = string local string = string
local type = type local type = type
@ -19,77 +19,92 @@ local type = type
local function factory(apipath) local function factory(apipath)
local tp_smapi = { local tp_smapi = {
path = apipath or "/sys/devices/platform/smapi" path = apipath or '/sys/devices/platform/smapi',
} }
function tp_smapi.get(batid, feature) function tp_smapi.get(batid, feature)
return helpers.first_line(string.format("%s/%s/%s", tp_smapi.path, batid or "BAT0", feature or "")) return helpers.first_line(string.format('%s/%s/%s', tp_smapi.path, batid or 'BAT0', feature or ''))
end end
function tp_smapi.installed(batid) function tp_smapi.installed(batid)
return tp_smapi.get(batid, "installed") == "1" return tp_smapi.get(batid, 'installed') == '1'
end end
function tp_smapi.status(batid) function tp_smapi.status(batid)
return tp_smapi.get(batid, "state") return tp_smapi.get(batid, 'state')
end end
function tp_smapi.percentage(batid) function tp_smapi.percentage(batid)
return tp_smapi.get(batid, "remaining_percent") return tp_smapi.get(batid, 'remaining_percent')
end end
-- either running or charging time -- either running or charging time
function tp_smapi.time(batid) function tp_smapi.time(batid)
local status = tp_smapi.status(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") local mins_left = tp_smapi.get(
if not string.find(mins_left, "^%d+") then return "N/A" end batid,
return string.format("%02d:%02d", math.floor(mins_left / 60), mins_left % 60) -- HH:mm 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 end
function tp_smapi.hide() function tp_smapi.hide()
if not tp_smapi.notification then return end if not tp_smapi.notification then
return
end
naughty.destroy(tp_smapi.notification) naughty.destroy(tp_smapi.notification)
tp_smapi.notification = nil tp_smapi.notification = nil
end end
function tp_smapi.show(batid, seconds, scr) function tp_smapi.show(batid, seconds, scr)
if not tp_smapi.installed(batid) then return end if not tp_smapi.installed(batid) then
return
end
local mfgr = tp_smapi.get(batid, "manufacturer") or "no_mfgr" local mfgr = tp_smapi.get(batid, 'manufacturer') or 'no_mfgr'
local model = tp_smapi.get(batid, "model") or "no_model" local model = tp_smapi.get(batid, 'model') or 'no_model'
local chem = tp_smapi.get(batid, "chemistry") or "no_chem" local chem = tp_smapi.get(batid, 'chemistry') or 'no_chem'
local status = tp_smapi.get(batid, "state") local status = tp_smapi.get(batid, 'state')
local time = tp_smapi.time(batid) local time = tp_smapi.time(batid)
local msg local msg
if status and status ~= "idle" then if status and status ~= 'idle' then
msg = string.format("[%s] %s %s", status, time ~= "N/A" and time or "unknown remaining time", msg = string.format(
string.lower(status):gsub(" ", ""):gsub("\n", "") == "charging" and " until charged" or " remaining") '[%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 else
msg = "On AC power" msg = 'On AC power'
end end
tp_smapi.hide() tp_smapi.hide()
tp_smapi.notification = naughty.notify { tp_smapi.notification = naughty.notify({
title = string.format("%s: %s %s (%s)", batid, mfgr, model, chem), title = string.format('%s: %s %s (%s)', batid, mfgr, model, chem),
text = msg, text = msg,
timeout = type(seconds) == "number" and seconds or 0, timeout = type(seconds) == 'number' and seconds or 0,
screen = scr or focused() screen = scr or focused(),
} })
end end
function tp_smapi.create_widget(args) function tp_smapi.create_widget(args)
args = args or {} args = args or {}
local pspath = args.pspath or "/sys/class/power_supply/" local pspath = args.pspath or '/sys/class/power_supply/'
local batteries = args.batteries or (args.battery and { args.battery }) or {} local batteries = args.batteries or (args.battery and { args.battery }) or {}
local timeout = args.timeout or 30 local timeout = args.timeout or 30
local settings = args.settings or function() end local settings = args.settings or function() end
if #batteries == 0 then if #batteries == 0 then
helpers.line_callback("ls -1 " .. pspath, function(line) helpers.line_callback('ls -1 ' .. pspath, function(line)
local bstr = string.match(line, "BAT%w+") local bstr = string.match(line, 'BAT%w+')
if bstr then batteries[#batteries + 1] = bstr end if bstr then
batteries[#batteries + 1] = bstr
end
end) end)
end end
@ -97,21 +112,23 @@ local function factory(apipath)
for _, battery in ipairs(batteries) do for _, battery in ipairs(batteries) do
if not tp_smapi.installed(battery) then if not tp_smapi.installed(battery) then
naughty.notify { naughty.notify({
preset = naughty.config.critical, preset = naughty.config.critical,
title = "tp_smapi: error while creating widget", title = 'tp_smapi: error while creating widget',
text = string.format("battery %s is not installed", battery) text = string.format('battery %s is not installed', battery),
} })
all_batteries_installed = false all_batteries_installed = false
break break
end end
end end
if not all_batteries_installed then return end if not all_batteries_installed then
return
end
tpbat = { tpbat = {
batteries = batteries, batteries = batteries,
widget = args.widget or wibox.widget.textbox() widget = args.widget or wibox.widget.textbox(),
} }
function tpbat.update() function tpbat.update()
@ -119,15 +136,15 @@ local function factory(apipath)
n_status = {}, n_status = {},
n_perc = {}, n_perc = {},
n_time = {}, n_time = {},
status = "N/A" status = 'N/A',
} }
for i = 1, #batteries do for i = 1, #batteries do
tpbat_now.n_status[i] = tp_smapi.status(batteries[i]) or "N/A" 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_perc[i] = tp_smapi.percentage(batteries[i])
tpbat_now.n_time[i] = tp_smapi.time(batteries[i]) or "N/A" tpbat_now.n_time[i] = tp_smapi.time(batteries[i]) or 'N/A'
if not tpbat_now.n_status[i]:lower():match("full") then if not tpbat_now.n_status[i]:lower():match('full') then
tpbat_now.status = tpbat_now.n_status[i] tpbat_now.status = tpbat_now.n_status[i]
end end
end end
@ -136,7 +153,7 @@ local function factory(apipath)
settings() settings()
end end
helpers.newtimer("thinkpad-batteries", timeout, tpbat.update) helpers.newtimer('thinkpad-batteries', timeout, tpbat.update)
return tpbat return tpbat
end end

View File

@ -6,8 +6,8 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local wibox = require("wibox") local wibox = require('wibox')
local math = math local math = math
local string = string local string = string
@ -25,15 +25,14 @@ local function factory(args)
-- Read the amount of time the CPUs have spent performing -- Read the amount of time the CPUs have spent performing
-- different kinds of work. Read the first line of /proc/stat -- different kinds of work. Read the first line of /proc/stat
-- which is the sum of all CPUs. -- which is the sum of all CPUs.
for index,time in pairs(helpers.lines_match("cpu","/proc/stat")) do for index, time in pairs(helpers.lines_match('cpu', '/proc/stat')) do
local coreid = index - 1 local coreid = index - 1
local core = cpu.core[coreid] or local core = cpu.core[coreid] or { last_active = 0, last_total = 0, usage = 0 }
{ last_active = 0 , last_total = 0, usage = 0 }
local at = 1 local at = 1
local idle = 0 local idle = 0
local total = 0 local total = 0
for field in string.gmatch(time, "[%s]+([^%s]+)") do for field in string.gmatch(time, '[%s]+([^%s]+)') do
-- 4 = idle, 5 = ioWait. Essentially, the CPUs have done -- 4 = idle, 5 = ioWait. Essentially, the CPUs have done
-- nothing during these times. -- nothing during these times.
if at == 4 or at == 5 then if at == 4 or at == 5 then
@ -67,7 +66,7 @@ local function factory(args)
settings() settings()
end end
helpers.newtimer("cpu", timeout, cpu.update) helpers.newtimer('cpu', timeout, cpu.update)
return cpu return cpu
end end

View File

@ -7,12 +7,12 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local Gio = require("lgi").Gio local Gio = require('lgi').Gio
local focused = require("awful.screen").focused local focused = require('awful.screen').focused
local wibox = require("wibox") local wibox = require('wibox')
local naughty = require("naughty") local naughty = require('naughty')
local gears = require("gears") local gears = require('gears')
local math = math local math = math
local string = string local string = string
local tconcat = table.concat local tconcat = table.concat
@ -20,7 +20,7 @@ local type = type
local query_size = Gio.FILE_ATTRIBUTE_FILESYSTEM_SIZE local query_size = Gio.FILE_ATTRIBUTE_FILESYSTEM_SIZE
local query_free = Gio.FILE_ATTRIBUTE_FILESYSTEM_FREE local query_free = Gio.FILE_ATTRIBUTE_FILESYSTEM_FREE
local query_used = Gio.FILE_ATTRIBUTE_FILESYSTEM_USED local query_used = Gio.FILE_ATTRIBUTE_FILESYSTEM_USED
local query = query_size .. "," .. query_free .. "," .. query_used local query = query_size .. ',' .. query_free .. ',' .. query_used
-- File systems info -- File systems info
-- lain.widget.fs -- lain.widget.fs
@ -31,14 +31,21 @@ local function factory(args)
local fs = { local fs = {
widget = args.widget or wibox.widget.textbox(), widget = args.widget or wibox.widget.textbox(),
units = { units = {
[1] = "Kb", [2] = "Mb", [3] = "Gb", [1] = 'Kb',
[4] = "Tb", [5] = "Pb", [6] = "Eb", [2] = 'Mb',
[7] = "Zb", [8] = "Yb" [3] = 'Gb',
} [4] = 'Tb',
[5] = 'Pb',
[6] = 'Eb',
[7] = 'Zb',
[8] = 'Yb',
},
} }
function fs.hide() function fs.hide()
if not fs.notification then return end if not fs.notification then
return
end
naughty.destroy(fs.notification) naughty.destroy(fs.notification)
fs.notification = nil fs.notification = nil
end end
@ -47,17 +54,17 @@ local function factory(args)
fs.hide() fs.hide()
fs.update(function() fs.update(function()
fs.notification_preset.screen = fs.followtag and focused() or scr or 1 fs.notification_preset.screen = fs.followtag and focused() or scr or 1
fs.notification = naughty.notify { fs.notification = naughty.notify({
preset = fs.notification_preset, preset = fs.notification_preset,
timeout = type(seconds) == "number" and seconds or 5 timeout = type(seconds) == 'number' and seconds or 5,
} })
end) end)
end end
local timeout = args.timeout or 600 local timeout = args.timeout or 600
local partition = args.partition local partition = args.partition
local threshold = args.threshold or 99 local threshold = args.threshold or 99
local showpopup = args.showpopup or "on" local showpopup = args.showpopup or 'on'
local settings = args.settings or function() end local settings = args.settings or function() end
fs.followtag = args.followtag or false fs.followtag = args.followtag or false
@ -65,9 +72,9 @@ local function factory(args)
if not fs.notification_preset then if not fs.notification_preset then
fs.notification_preset = { fs.notification_preset = {
font = "Monospace 10", font = 'Monospace 10',
fg = "#FFFFFF", fg = '#FFFFFF',
bg = "#000000" bg = '#000000',
} }
end end
@ -94,7 +101,7 @@ local function factory(args)
percentage = math.floor(100 * used / size), -- used percentage percentage = math.floor(100 * used / size), -- used percentage
size = size / math.pow(1024, units), size = size / math.pow(1024, units),
used = used / math.pow(1024, units), used = used / math.pow(1024, units),
free = free / math.pow(1024, units) free = free / math.pow(1024, units),
} }
if fs_now[path].percentage > 0 then -- don't notify unused file systems if fs_now[path].percentage > 0 then -- don't notify unused file systems
@ -113,22 +120,29 @@ local function factory(args)
if partition and fs_now[partition] and fs_now[partition].percentage >= threshold then if partition and fs_now[partition] and fs_now[partition].percentage >= threshold then
if not helpers.get_map(partition) then if not helpers.get_map(partition) then
naughty.notify { naughty.notify({
preset = naughty.config.presets.critical, preset = naughty.config.presets.critical,
title = "Warning", title = 'Warning',
text = string.format("%s is above %d%% (%d%%)", partition, threshold, fs_now[partition].percentage) text = string.format('%s is above %d%% (%d%%)', partition, threshold, fs_now[partition].percentage),
} })
helpers.set_map(partition, true) helpers.set_map(partition, true)
else else
helpers.set_map(partition, false) helpers.set_map(partition, false)
end end
end end
local fmt = "%-" .. tostring(pathlen) .. "s %4s\t%6s\t%6s\n" local fmt = '%-' .. tostring(pathlen) .. 's %4s\t%6s\t%6s\n'
local notifytable = { [1] = string.format(fmt, "path", "used", "free", "size") } local notifytable = { [1] = string.format(fmt, 'path', 'used', 'free', 'size') }
fmt = "\n%-" .. tostring(pathlen) .. "s %3s%%\t%6.2f\t%6.2f %s" fmt = '\n%-' .. tostring(pathlen) .. 's %3s%%\t%6.2f\t%6.2f %s'
for _, path in ipairs(notifypaths) do 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) notifytable[#notifytable + 1] = string.format(
fmt,
path,
fs_now[path].percentage,
fs_now[path].free,
fs_now[path].size,
fs_now[path].units
)
end end
fs.notification_preset.text = tconcat(notifytable) fs.notification_preset.text = tconcat(notifytable)
@ -137,18 +151,22 @@ local function factory(args)
function fs.update(callback) function fs.update(callback)
Gio.Async.start(gears.protected_call.call)(function() Gio.Async.start(gears.protected_call.call)(function()
update_synced() update_synced()
if type(callback) == "function" and callback then if type(callback) == 'function' and callback then
callback() callback()
end end
end) end)
end end
if showpopup == "on" then if showpopup == 'on' then
fs.widget:connect_signal('mouse::enter', function () fs.show(0) end) fs.widget:connect_signal('mouse::enter', function()
fs.widget:connect_signal('mouse::leave', function () fs.hide() end) fs.show(0)
end)
fs.widget:connect_signal('mouse::leave', function()
fs.hide()
end)
end end
helpers.newtimer(partition or "fs", timeout, fs.update) helpers.newtimer(partition or 'fs', timeout, fs.update)
return fs return fs
end end

View File

@ -5,10 +5,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local awful = require("awful") local awful = require('awful')
local string = string local string = string
local type = type local type = type
local tonumber = tonumber local tonumber = tonumber
@ -28,30 +28,34 @@ local function factory(args)
local pwdtimeout = args.pwdtimeout or 10 local pwdtimeout = args.pwdtimeout or 10
local is_plain = args.is_plain or false local is_plain = args.is_plain or false
local followtag = args.followtag or false local followtag = args.followtag or false
local notify = args.notify or "on" local notify = args.notify or 'on'
local settings = args.settings or function() end local settings = args.settings or function() end
local head_command = "curl --connect-timeout 3 -fsm 3" local head_command = 'curl --connect-timeout 3 -fsm 3'
local request = "-X 'STATUS INBOX (MESSAGES RECENT UNSEEN)'" local request = "-X 'STATUS INBOX (MESSAGES RECENT UNSEEN)'"
if not server or not mail or not password then return end if not server or not mail or not password then
return
end
mail_notification_preset = { mail_notification_preset = {
icon = helpers.icons_dir .. "mail.png", icon = helpers.icons_dir .. 'mail.png',
position = "top_left" position = 'top_left',
} }
helpers.set_map(mail, 0) helpers.set_map(mail, 0)
if not is_plain then if not is_plain then
if type(password) == "string" or type(password) == "table" then if type(password) == 'string' or type(password) == 'table' then
helpers.async(password, function(f) password = f:gsub("\n", "") end) helpers.async(password, function(f)
elseif type(password) == "function" then password = f:gsub('\n', '')
imap.pwdtimer = helpers.newtimer(mail .. "-password", pwdtimeout, function() end)
elseif type(password) == 'function' then
imap.pwdtimer = helpers.newtimer(mail .. '-password', pwdtimeout, function()
local retrieved_password, try_again = password() local retrieved_password, try_again = password()
if not try_again then if not try_again then
imap.pwdtimer:stop() -- stop trying to retrieve imap.pwdtimer:stop() -- stop trying to retrieve
password = retrieved_password or "" -- failsafe password = retrieved_password or '' -- failsafe
end end
end, true, true) end, true, true)
end end
@ -59,31 +63,48 @@ local function factory(args)
function imap.update() function imap.update()
-- do not update if the password has not been retrieved yet -- do not update if the password has not been retrieved yet
if type(password) ~= "string" then return end if type(password) ~= 'string' then
return
end
local curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:'%s' %s -k", local curl = string.format(
head_command, server, port, mail, password, request) "%s --url imaps://%s:%s/INBOX -u %s:'%s' %s -k",
head_command,
server,
port,
mail,
password,
request
)
helpers.async(curl, function(f) helpers.async(curl, function(f)
imap_now = { ["MESSAGES"] = 0, ["RECENT"] = 0, ["UNSEEN"] = 0 } imap_now = { ['MESSAGES'] = 0, ['RECENT'] = 0, ['UNSEEN'] = 0 }
for s,d in f:gmatch("(%w+)%s+(%d+)") do imap_now[s] = tonumber(d) end for s, d in f:gmatch('(%w+)%s+(%d+)') do
mailcount = imap_now["UNSEEN"] -- backwards compatibility imap_now[s] = tonumber(d)
end
mailcount = imap_now['UNSEEN'] -- backwards compatibility
widget = imap.widget widget = imap.widget
settings() settings()
if notify == "on" and mailcount and mailcount >= 1 and mailcount > helpers.get_map(mail) then 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 if followtag then
naughty.notify { mail_notification_preset.screen = awful.screen.focused()
end
naughty.notify({
preset = mail_notification_preset, preset = mail_notification_preset,
text = string.format("%s has <b>%d</b> new message%s", mail, mailcount, mailcount == 1 and "" or "s") text = string.format(
} '%s has <b>%d</b> new message%s',
mail,
mailcount,
mailcount == 1 and '' or 's'
),
})
end end
helpers.set_map(mail, imap_now["UNSEEN"]) helpers.set_map(mail, imap_now['UNSEEN'])
end) end)
end end
imap.timer = helpers.newtimer(mail, timeout, imap.update, true, true) imap.timer = helpers.newtimer(mail, timeout, imap.update, true, true)

View File

@ -11,9 +11,9 @@
--]] --]]
local wrequire = require("lain.helpers").wrequire local wrequire = require('lain.helpers').wrequire
local setmetatable = setmetatable local setmetatable = setmetatable
local widget = { _NAME = "lain.widget" } local widget = { _NAME = 'lain.widget' }
return setmetatable(widget, { __index = wrequire }) return setmetatable(widget, { __index = wrequire })

View File

@ -6,8 +6,8 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local wibox = require("wibox") local wibox = require('wibox')
local gmatch, lines, floor = string.gmatch, io.lines, math.floor local gmatch, lines, floor = string.gmatch, io.lines, math.floor
-- Memory usage (ignoring caches) -- Memory usage (ignoring caches)
@ -22,15 +22,22 @@ local function factory(args)
function mem.update() function mem.update()
mem_now = {} mem_now = {}
for line in lines("/proc/meminfo") do for line in lines('/proc/meminfo') do
for k, v in gmatch(line, "([%a]+):[%s]+([%d]+).+") do for k, v in gmatch(line, '([%a]+):[%s]+([%d]+).+') do
if k == "MemTotal" then mem_now.total = floor(v / 1024 + 0.5) if k == 'MemTotal' then
elseif k == "MemFree" then mem_now.free = floor(v / 1024 + 0.5) mem_now.total = floor(v / 1024 + 0.5)
elseif k == "Buffers" then mem_now.buf = floor(v / 1024 + 0.5) elseif k == 'MemFree' then
elseif k == "Cached" then mem_now.cache = floor(v / 1024 + 0.5) mem_now.free = floor(v / 1024 + 0.5)
elseif k == "SwapTotal" then mem_now.swap = floor(v / 1024 + 0.5) elseif k == 'Buffers' then
elseif k == "SwapFree" then mem_now.swapf = floor(v / 1024 + 0.5) mem_now.buf = floor(v / 1024 + 0.5)
elseif k == "SReclaimable" then mem_now.srec = 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 end
end end
@ -43,7 +50,7 @@ local function factory(args)
settings() settings()
end end
helpers.newtimer("mem", timeout, mem.update) helpers.newtimer('mem', timeout, mem.update)
return mem return mem
end end

View File

@ -6,12 +6,12 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local shell = require("awful.util").shell local shell = require('awful.util').shell
local escape_f = require("awful.util").escape local escape_f = require('awful.util').escape
local focused = require("awful.screen").focused local focused = require('awful.screen').focused
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local os = os local os = os
local string = string local string = string
@ -23,111 +23,135 @@ local function factory(args)
local mpd = { widget = args.widget or wibox.widget.textbox() } local mpd = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 2 local timeout = args.timeout or 2
local password = (args.password and #args.password > 0 and string.format("password %s\\n", args.password)) or "" 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 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 port = args.port or os.getenv('MPD_PORT') or '6600'
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music" local music_dir = args.music_dir or os.getenv('HOME') .. '/Music'
local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$" local cover_pattern = args.cover_pattern or '*\\.(jpg|jpeg|png|gif)$'
local cover_size = args.cover_size or 100 local cover_size = args.cover_size or 100
local default_art = args.default_art local default_art = args.default_art
local notify = args.notify or "on" local notify = args.notify or 'on'
local followtag = args.followtag or false local followtag = args.followtag or false
local settings = args.settings or function() end local settings = args.settings or function() end
local mpdh = string.format("telnet://%s:%s", host, port) local mpdh = string.format('telnet://%s:%s', host, port)
local echo = string.format("printf \"%sstatus\\ncurrentsong\\nclose\\n\"", password) local echo = string.format('printf "%sstatus\\ncurrentsong\\nclose\\n"', password)
local cmd = string.format("%s | curl --connect-timeout 1 -fsm 3 %s", echo, mpdh) local cmd = string.format('%s | curl --connect-timeout 1 -fsm 3 %s', echo, mpdh)
mpd_notification_preset = { title = "Now playing", timeout = 6 } mpd_notification_preset = { title = 'Now playing', timeout = 6 }
helpers.set_map("current mpd track", nil) helpers.set_map('current mpd track', nil)
function mpd.update() function mpd.update()
helpers.async({ shell, "-c", cmd }, function(f) helpers.async({ shell, '-c', cmd }, function(f)
mpd_now = { mpd_now = {
random_mode = false, random_mode = false,
single_mode = false, single_mode = false,
repeat_mode = false, repeat_mode = false,
consume_mode = false, consume_mode = false,
pls_pos = "N/A", pls_pos = 'N/A',
pls_len = "N/A", pls_len = 'N/A',
state = "N/A", state = 'N/A',
file = "N/A", file = 'N/A',
name = "N/A", name = 'N/A',
artist = "N/A", artist = 'N/A',
title = "N/A", title = 'N/A',
album = "N/A", album = 'N/A',
genre = "N/A", genre = 'N/A',
track = "N/A", track = 'N/A',
date = "N/A", date = 'N/A',
time = "N/A", time = 'N/A',
elapsed = "N/A", elapsed = 'N/A',
volume = "N/A" volume = 'N/A',
} }
for line in string.gmatch(f, "[^\n]+") do for line in string.gmatch(f, '[^\n]+') do
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do for k, v in string.gmatch(line, '([%w]+):[%s](.*)$') do
if k == "state" then mpd_now.state = v if k == 'state' then
elseif k == "file" then mpd_now.file = v mpd_now.state = v
elseif k == "Name" then mpd_now.name = escape_f(v) elseif k == 'file' then
elseif k == "Artist" then mpd_now.artist = escape_f(v) mpd_now.file = v
elseif k == "Title" then mpd_now.title = escape_f(v) elseif k == 'Name' then
elseif k == "Album" then mpd_now.album = escape_f(v) mpd_now.name = escape_f(v)
elseif k == "Genre" then mpd_now.genre = escape_f(v) elseif k == 'Artist' then
elseif k == "Track" then mpd_now.track = escape_f(v) mpd_now.artist = escape_f(v)
elseif k == "Date" then mpd_now.date = escape_f(v) elseif k == 'Title' then
elseif k == "Time" then mpd_now.time = v mpd_now.title = escape_f(v)
elseif k == "elapsed" then mpd_now.elapsed = string.match(v, "%d+") elseif k == 'Album' then
elseif k == "song" then mpd_now.pls_pos = v mpd_now.album = escape_f(v)
elseif k == "playlistlength" then mpd_now.pls_len = v elseif k == 'Genre' then
elseif k == "repeat" then mpd_now.repeat_mode = v ~= "0" mpd_now.genre = escape_f(v)
elseif k == "single" then mpd_now.single_mode = v ~= "0" elseif k == 'Track' then
elseif k == "random" then mpd_now.random_mode = v ~= "0" mpd_now.track = escape_f(v)
elseif k == "consume" then mpd_now.consume_mode = v ~= "0" elseif k == 'Date' then
elseif k == "volume" then mpd_now.volume = v 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 end
end end
mpd_notification_preset.text = string.format("%s (%s) - %s\n%s", mpd_now.artist, mpd_notification_preset.text =
mpd_now.album, mpd_now.date, mpd_now.title) string.format('%s (%s) - %s\n%s', mpd_now.artist, mpd_now.album, mpd_now.date, mpd_now.title)
widget = mpd.widget widget = mpd.widget
settings() settings()
if mpd_now.state == "play" then if mpd_now.state == 'play' then
if notify == "on" and mpd_now.title ~= helpers.get_map("current mpd track") then if notify == 'on' and mpd_now.title ~= helpers.get_map('current mpd track') then
helpers.set_map("current mpd track", mpd_now.title) helpers.set_map('current mpd track', mpd_now.title)
if followtag then mpd_notification_preset.screen = focused() end if followtag then
mpd_notification_preset.screen = focused()
end
local common = { local common = {
preset = mpd_notification_preset, preset = mpd_notification_preset,
icon = default_art, icon = default_art,
icon_size = cover_size, icon_size = cover_size,
replaces_id = mpd.id replaces_id = mpd.id,
} }
if not string.match(mpd_now.file, "http.*://") then -- local file instead of http stream 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 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'", local cover = string.format(
path:gsub("'", "'\\''"), cover_pattern) "find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'",
helpers.async({ shell, "-c", cover }, function(current_icon) path:gsub("'", "'\\''"),
common.icon = current_icon:gsub("\n", "") cover_pattern
if #common.icon == 0 then common.icon = nil end )
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 mpd.id = naughty.notify(common).id
end) end)
else else
mpd.id = naughty.notify(common).id mpd.id = naughty.notify(common).id
end end
end end
elseif mpd_now.state ~= "pause" then elseif mpd_now.state ~= 'pause' then
helpers.set_map("current mpd track", nil) helpers.set_map('current mpd track', nil)
end end
end) end)
end end
mpd.timer = helpers.newtimer("mpd", timeout, mpd.update, true, true) mpd.timer = helpers.newtimer('mpd', timeout, mpd.update, true, true)
return mpd return mpd
end end

View File

@ -6,9 +6,9 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local string = string local string = string
-- Network infos -- Network infos
@ -20,25 +20,29 @@ local function factory(args)
local net = { widget = args.widget or wibox.widget.textbox(), devices = {} } local net = { widget = args.widget or wibox.widget.textbox(), devices = {} }
local timeout = args.timeout or 2 local timeout = args.timeout or 2
local units = args.units or 1024 -- KB local units = args.units or 1024 -- KB
local notify = args.notify or "on" local notify = args.notify or 'on'
local wifi_state = args.wifi_state or "off" local wifi_state = args.wifi_state or 'off'
local eth_state = args.eth_state or "off" local eth_state = args.eth_state or 'off'
local screen = args.screen or 1 local screen = args.screen or 1
local format = args.format or "%.1f" local format = args.format or '%.1f'
local settings = args.settings or function() end local settings = args.settings or function() end
-- Compatibility with old API where iface was a string corresponding to 1 interface -- 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 net.iface = (
(type(args.iface) == "table" and args.iface)) or {} args.iface and (type(args.iface) == 'string' and { args.iface })
or (type(args.iface) == 'table' and args.iface)
) or {}
function net.get_devices() function net.get_devices()
net.iface = {} -- reset at every call net.iface = {} -- reset at every call
helpers.line_callback("ip link", function(line) helpers.line_callback('ip link', function(line)
net.iface[#net.iface + 1] = not string.match(line, "LOOPBACK") and string.match(line, "(%w+): <") or nil net.iface[#net.iface + 1] = not string.match(line, 'LOOPBACK') and string.match(line, '(%w+): <') or nil
end) end)
end end
if #net.iface == 0 then net.get_devices() end if #net.iface == 0 then
net.get_devices()
end
function net.update() function net.update()
-- These are the totals over all specified interfaces -- These are the totals over all specified interfaces
@ -46,17 +50,17 @@ local function factory(args)
devices = {}, devices = {},
-- Bytes since last iteration -- Bytes since last iteration
sent = 0, sent = 0,
received = 0 received = 0,
} }
for _, dev in ipairs(net.iface) do for _, dev in ipairs(net.iface) do
local dev_now = {} local dev_now = {}
local dev_before = net.devices[dev] or { last_t = 0, last_r = 0 } 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_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) 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.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.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.sent = (now_t - dev_before.last_t) / timeout / units
dev_now.received = (now_r - dev_before.last_r) / timeout / units dev_now.received = (now_r - dev_before.last_r) / timeout / units
@ -70,16 +74,23 @@ local function factory(args)
dev_now.last_t = now_t dev_now.last_t = now_t
dev_now.last_r = now_r 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 if
wifi_state == 'on'
and helpers.first_line(string.format('/sys/class/net/%s/uevent', dev)) == 'DEVTYPE=wlan'
then
dev_now.wifi = true dev_now.wifi = true
if string.match(dev_now.carrier, "1") then if string.match(dev_now.carrier, '1') then
dev_now.signal = tonumber(string.match(helpers.lines_from("/proc/net/wireless")[3], "(%-%d+%.)")) or nil dev_now.signal = tonumber(string.match(helpers.lines_from('/proc/net/wireless')[3], '(%-%d+%.)'))
or nil
end end
else else
dev_now.wifi = false dev_now.wifi = false
end end
if eth_state == "on" and helpers.first_line(string.format("/sys/class/net/%s/uevent", dev)) ~= "DEVTYPE=wlan" then if
eth_state == 'on'
and helpers.first_line(string.format('/sys/class/net/%s/uevent', dev)) ~= 'DEVTYPE=wlan'
then
dev_now.ethernet = true dev_now.ethernet = true
else else
dev_now.ethernet = false dev_now.ethernet = false
@ -88,15 +99,15 @@ local function factory(args)
net.devices[dev] = dev_now net.devices[dev] = dev_now
-- Notify only once when connection is lost -- Notify only once when connection is lost
if string.match(dev_now.carrier, "0") and notify == "on" and helpers.get_map(dev) then if string.match(dev_now.carrier, '0') and notify == 'on' and helpers.get_map(dev) then
naughty.notify { naughty.notify({
title = dev, title = dev,
text = "No carrier", text = 'No carrier',
icon = helpers.icons_dir .. "no_net.png", icon = helpers.icons_dir .. 'no_net.png',
screen = screen screen = screen,
} })
helpers.set_map(dev, false) helpers.set_map(dev, false)
elseif string.match(dev_now.carrier, "1") then elseif string.match(dev_now.carrier, '1') then
helpers.set_map(dev, true) helpers.set_map(dev, true)
end end
@ -114,7 +125,7 @@ local function factory(args)
settings() settings()
end end
helpers.newtimer("network", timeout, net.update) helpers.newtimer('network', timeout, net.update)
return net return net
end end

View File

@ -5,9 +5,9 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local shell = require("awful.util").shell local shell = require('awful.util').shell
local wibox = require("wibox") local wibox = require('wibox')
local string = string local string = string
local type = type local type = type
@ -17,40 +17,42 @@ local type = type
local function factory(args) local function factory(args)
args = args or {} args = args or {}
local pulse = { widget = args.widget or wibox.widget.textbox(), device = "N/A" } local pulse = { widget = args.widget or wibox.widget.textbox(), device = 'N/A' }
local timeout = args.timeout or 5 local timeout = args.timeout or 5
local settings = args.settings or function() end local settings = args.settings or function() end
pulse.devicetype = args.devicetype or "sink" 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'" 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() function pulse.update()
helpers.async({ shell, "-c", type(pulse.cmd) == "string" and pulse.cmd or pulse.cmd() }, helpers.async({ shell, '-c', type(pulse.cmd) == 'string' and pulse.cmd or pulse.cmd() }, function(s)
function(s)
volume_now = { volume_now = {
index = string.match(s, "index: (%S+)") or "N/A", index = string.match(s, 'index: (%S+)') or 'N/A',
device = string.match(s, "device.string = \"(%S+)\"") or "N/A", device = string.match(s, 'device.string = "(%S+)"') or 'N/A',
muted = string.match(s, "muted: (%S+)") or "N/A" muted = string.match(s, 'muted: (%S+)') or 'N/A',
} }
pulse.device = volume_now.index pulse.device = volume_now.index
local ch = 1 local ch = 1
volume_now.channel = {} volume_now.channel = {}
for v in string.gmatch(s, ":.-(%d+)%%") do for v in string.gmatch(s, ':.-(%d+)%%') do
volume_now.channel[ch] = v volume_now.channel[ch] = v
ch = ch + 1 ch = ch + 1
end end
volume_now.left = volume_now.channel[1] or "N/A" volume_now.left = volume_now.channel[1] or 'N/A'
volume_now.right = volume_now.channel[2] or "N/A" volume_now.right = volume_now.channel[2] or 'N/A'
widget = pulse.widget widget = pulse.widget
settings() settings()
end) end)
end end
helpers.newtimer("pulse", timeout, pulse.update) helpers.newtimer('pulse', timeout, pulse.update)
return pulse return pulse
end end

View File

@ -6,10 +6,10 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local awful = require("awful") local awful = require('awful')
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local math = math local math = math
local string = string local string = string
local type = type local type = type
@ -21,15 +21,15 @@ local tonumber = tonumber
local function factory(args) local function factory(args)
local pulsebar = { local pulsebar = {
colors = { colors = {
background = "#000000", background = '#000000',
mute_background = "#000000", mute_background = '#000000',
mute = "#EB8F8F", mute = '#EB8F8F',
unmute = "#A4CE8A" unmute = '#A4CE8A',
}, },
_current_level = 0, _current_level = 0,
_mute = "no", _mute = 'no',
device = "N/A" device = 'N/A',
} }
args = args or {} args = args or {}
@ -42,24 +42,27 @@ local function factory(args)
local paddings = args.paddings or 1 local paddings = args.paddings or 1
local ticks = args.ticks or false local ticks = args.ticks or false
local ticks_size = args.ticks_size or 7 local ticks_size = args.ticks_size or 7
local tick = args.tick or "|" local tick = args.tick or '|'
local tick_pre = args.tick_pre or "[" local tick_pre = args.tick_pre or '['
local tick_post = args.tick_post or "]" local tick_post = args.tick_post or ']'
local tick_none = args.tick_none or " " local tick_none = args.tick_none or ' '
pulsebar.colors = args.colors or pulsebar.colors pulsebar.colors = args.colors or pulsebar.colors
pulsebar.followtag = args.followtag or false pulsebar.followtag = args.followtag or false
pulsebar.notification_preset = args.notification_preset pulsebar.notification_preset = args.notification_preset
pulsebar.devicetype = args.devicetype or "sink" 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'" 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 if not pulsebar.notification_preset then
pulsebar.notification_preset = { pulsebar.notification_preset = {
font = "Monospace 10" font = 'Monospace 10',
} }
end end
pulsebar.bar = wibox.widget { pulsebar.bar = wibox.widget({
color = pulsebar.colors.unmute, color = pulsebar.colors.unmute,
background_color = pulsebar.colors.background, background_color = pulsebar.colors.background,
forced_height = height, forced_height = height,
@ -69,66 +72,74 @@ local function factory(args)
ticks = ticks, ticks = ticks,
ticks_size = ticks_size, ticks_size = ticks_size,
widget = wibox.widget.progressbar, widget = wibox.widget.progressbar,
} })
pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } }) pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
function pulsebar.update(callback) function pulsebar.update(callback)
helpers.async({ awful.util.shell, "-c", type(pulsebar.cmd) == "string" and pulsebar.cmd or pulsebar.cmd() }, helpers.async(
{ awful.util.shell, '-c', type(pulsebar.cmd) == 'string' and pulsebar.cmd or pulsebar.cmd() },
function(s) function(s)
volume_now = { volume_now = {
index = string.match(s, "index: (%S+)") or "N/A", index = string.match(s, 'index: (%S+)') or 'N/A',
device = string.match(s, "device.string = \"(%S+)\"") or "N/A", device = string.match(s, 'device.string = "(%S+)"') or 'N/A',
muted = string.match(s, "muted: (%S+)") or "N/A" muted = string.match(s, 'muted: (%S+)') or 'N/A',
} }
pulsebar.device = volume_now.index pulsebar.device = volume_now.index
local ch = 1 local ch = 1
volume_now.channel = {} volume_now.channel = {}
for v in string.gmatch(s, ":.-(%d+)%%") do for v in string.gmatch(s, ':.-(%d+)%%') do
volume_now.channel[ch] = v volume_now.channel[ch] = v
ch = ch + 1 ch = ch + 1
end end
volume_now.left = volume_now.channel[1] or "N/A" volume_now.left = volume_now.channel[1] or 'N/A'
volume_now.right = volume_now.channel[2] or "N/A" volume_now.right = volume_now.channel[2] or 'N/A'
local volu = volume_now.left local volu = volume_now.left
local mute = volume_now.muted local mute = volume_now.muted
if volu:match("N/A") or mute:match("N/A") then return end if volu:match('N/A') or mute:match('N/A') then
return
end
if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then
pulsebar._current_level = tonumber(volu) pulsebar._current_level = tonumber(volu)
pulsebar.bar:set_value(pulsebar._current_level / 100) pulsebar.bar:set_value(pulsebar._current_level / 100)
if pulsebar._current_level == 0 or mute == "yes" then if pulsebar._current_level == 0 or mute == 'yes' then
pulsebar._mute = mute pulsebar._mute = mute
pulsebar.tooltip:set_text ("[muted]") pulsebar.tooltip:set_text('[muted]')
pulsebar.bar.color = pulsebar.colors.mute pulsebar.bar.color = pulsebar.colors.mute
pulsebar.bar.background_color = pulsebar.colors.mute_background pulsebar.bar.background_color = pulsebar.colors.mute_background
else else
pulsebar._mute = "no" pulsebar._mute = 'no'
pulsebar.tooltip:set_text(string.format("%s %s: %s", pulsebar.devicetype, pulsebar.device, volu)) pulsebar.tooltip:set_text(
string.format('%s %s: %s', pulsebar.devicetype, pulsebar.device, volu)
)
pulsebar.bar.color = pulsebar.colors.unmute pulsebar.bar.color = pulsebar.colors.unmute
pulsebar.bar.background_color = pulsebar.colors.background pulsebar.bar.background_color = pulsebar.colors.background
end end
settings() settings()
if type(callback) == "function" then callback() end if type(callback) == 'function' then
callback()
end end
end) end
end
)
end end
function pulsebar.notify() function pulsebar.notify()
pulsebar.update(function() pulsebar.update(function()
local preset = pulsebar.notification_preset local preset = pulsebar.notification_preset
preset.title = string.format("%s %s - %s%%", pulsebar.devicetype, pulsebar.device, pulsebar._current_level) preset.title = string.format('%s %s - %s%%', pulsebar.devicetype, pulsebar.device, pulsebar._current_level)
if pulsebar._mute == "yes" then if pulsebar._mute == 'yes' then
preset.title = preset.title .. " muted" preset.title = preset.title .. ' muted'
end end
-- tot is the maximum number of ticks to display in the notification -- tot is the maximum number of ticks to display in the notification
@ -138,7 +149,7 @@ local function factory(args)
-- if we can grab mywibox, tot is defined as its height if -- if we can grab mywibox, tot is defined as its height if
-- horizontal, or width otherwise -- horizontal, or width otherwise
if wib then if wib then
if wib.position == "left" or wib.position == "right" then if wib.position == 'left' or wib.position == 'right' then
tot = wib.width tot = wib.width
else else
tot = wib.height tot = wib.height
@ -146,28 +157,27 @@ local function factory(args)
end end
local int = math.modf((pulsebar._current_level / 100) * tot) local int = math.modf((pulsebar._current_level / 100) * tot)
preset.text = string.format( preset.text =
"%s%s%s%s", string.format('%s%s%s%s', tick_pre, string.rep(tick, int), string.rep(tick_none, tot - int), tick_post)
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 pulsebar.followtag then
preset.screen = awful.screen.focused()
end
if not pulsebar.notification then if not pulsebar.notification then
pulsebar.notification = naughty.notify { pulsebar.notification = naughty.notify({
preset = preset, preset = preset,
destroy = function() pulsebar.notification = nil end destroy = function()
} pulsebar.notification = nil
end,
})
else else
naughty.replace_text(pulsebar.notification, preset.title, preset.text) naughty.replace_text(pulsebar.notification, preset.title, preset.text)
end end
end) end)
end end
helpers.newtimer(string.format("pulsebar-%s-%s", pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update) helpers.newtimer(string.format('pulsebar-%s-%s', pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update)
return pulsebar return pulsebar
end end

View File

@ -6,8 +6,8 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local wibox = require("wibox") local wibox = require('wibox')
local open, match = io.open, string.match local open, match = io.open, string.match
-- System load -- System load
@ -21,17 +21,17 @@ local function factory(args)
local settings = args.settings or function() end local settings = args.settings or function() end
function sysload.update() function sysload.update()
local f = open("/proc/loadavg") local f = open('/proc/loadavg')
local ret = f:read("*all") local ret = f:read('*all')
f:close() f:close()
load_1, load_5, load_15 = match(ret, "([^%s]+) ([^%s]+) ([^%s]+)") load_1, load_5, load_15 = match(ret, '([^%s]+) ([^%s]+) ([^%s]+)')
widget = sysload.widget widget = sysload.widget
settings() settings()
end end
helpers.newtimer("sysload", timeout, sysload.update) helpers.newtimer('sysload', timeout, sysload.update)
return sysload return sysload
end end

View File

@ -5,8 +5,8 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local wibox = require("wibox") local wibox = require('wibox')
local tonumber = tonumber local tonumber = tonumber
-- {thermal,core} temperature info -- {thermal,core} temperature info
@ -17,15 +17,15 @@ local function factory(args)
local temp = { widget = args.widget or wibox.widget.textbox() } local temp = { widget = args.widget or wibox.widget.textbox() }
local timeout = args.timeout or 30 local timeout = args.timeout or 30
local tempfile = args.tempfile or "/sys/devices/virtual/thermal/thermal_zone0/temp" local tempfile = args.tempfile or '/sys/devices/virtual/thermal/thermal_zone0/temp'
local format = args.format or "%.1f" local format = args.format or '%.1f'
local settings = args.settings or function() end local settings = args.settings or function() end
function temp.update() function temp.update()
helpers.async({"find", "/sys/devices", "-type", "f", "-name", "*temp*"}, function(f) helpers.async({ 'find', '/sys/devices', '-type', 'f', '-name', '*temp*' }, function(f)
temp_now = {} temp_now = {}
local temp_fl, temp_value local temp_fl, temp_value
for t in f:gmatch("[^\n]+") do for t in f:gmatch('[^\n]+') do
temp_fl = helpers.first_line(t) temp_fl = helpers.first_line(t)
if temp_fl then if temp_fl then
temp_value = tonumber(temp_fl) temp_value = tonumber(temp_fl)
@ -35,14 +35,14 @@ local function factory(args)
if temp_now[tempfile] then if temp_now[tempfile] then
coretemp_now = string.format(format, temp_now[tempfile]) coretemp_now = string.format(format, temp_now[tempfile])
else else
coretemp_now = "N/A" coretemp_now = 'N/A'
end end
widget = temp.widget widget = temp.widget
settings() settings()
end) end)
end end
helpers.newtimer("thermal", timeout, temp.update) helpers.newtimer('thermal', timeout, temp.update)
return temp return temp
end end

View File

@ -5,11 +5,11 @@
--]] --]]
local helpers = require("lain.helpers") local helpers = require('lain.helpers')
local json = require("lain.util").dkjson local json = require('lain.util').dkjson
local focused = require("awful.screen").focused local focused = require('awful.screen').focused
local naughty = require("naughty") local naughty = require('naughty')
local wibox = require("wibox") local wibox = require('wibox')
local math = math local math = math
local os = os local os = os
local string = string local string = string
@ -26,28 +26,30 @@ local function factory(args)
local weather = { widget = args.widget or wibox.widget.textbox() } local weather = { widget = args.widget or wibox.widget.textbox() }
local APPID = args.APPID -- mandatory local APPID = args.APPID -- mandatory
local timeout = args.timeout or 60 * 15 -- 15 min 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 current_call = args.current_call
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'" 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 city_id = args.city_id or 0 -- placeholder
local units = args.units or "metric" local units = args.units or 'metric'
local lang = args.lang or "en" local lang = args.lang or 'en'
local cnt = args.cnt or 5 local cnt = args.cnt or 5
local icons_path = args.icons_path or helpers.icons_dir .. "openweathermap/" local icons_path = args.icons_path or helpers.icons_dir .. 'openweathermap/'
local notification_preset = args.notification_preset or {} local notification_preset = args.notification_preset or {}
local notification_text_fun = args.notification_text_fun or local notification_text_fun = args.notification_text_fun
function (wn) or function(wn)
local day = os.date("%a %d", wn["dt"]) local day = os.date('%a %d', wn['dt'])
local temp = math.floor(wn["main"]["temp"]) local temp = math.floor(wn['main']['temp'])
local desc = wn["weather"][1]["description"] local desc = wn['weather'][1]['description']
return string.format("<b>%s</b>: %s, %d ", day, desc, temp) return string.format('<b>%s</b>: %s, %d ', day, desc, temp)
end end
local weather_na_markup = args.weather_na_markup or " N/A " local weather_na_markup = args.weather_na_markup or ' N/A '
local followtag = args.followtag or false local followtag = args.followtag or false
local showpopup = args.showpopup or "on" local showpopup = args.showpopup or 'on'
local settings = args.settings or function() end local settings = args.settings or function() end
weather.widget:set_markup(weather_na_markup) weather.widget:set_markup(weather_na_markup)
weather.icon_path = icons_path .. "na.png" weather.icon_path = icons_path .. 'na.png'
weather.icon = wibox.widget.imagebox(weather.icon_path) weather.icon = wibox.widget.imagebox(weather.icon_path)
function weather.show(seconds) function weather.show(seconds)
@ -62,12 +64,12 @@ local function factory(args)
weather.forecast_update() weather.forecast_update()
end end
weather.notification = naughty.notify { weather.notification = naughty.notify({
preset = notification_preset, preset = notification_preset,
text = weather.notification_text, text = weather.notification_text,
icon = weather.icon_path, icon = weather.icon_path,
timeout = type(seconds) == "number" and seconds or notification_preset.timeout timeout = type(seconds) == 'number' and seconds or notification_preset.timeout,
} })
end end
function weather.hide() function weather.hide()
@ -78,10 +80,10 @@ local function factory(args)
end end
function weather.attach(obj) function weather.attach(obj)
obj:connect_signal("mouse::enter", function() obj:connect_signal('mouse::enter', function()
weather.show(0) weather.show(0)
end) end)
obj:connect_signal("mouse::leave", function() obj:connect_signal('mouse::leave', function()
weather.hide() weather.hide()
end) end)
end end
@ -92,13 +94,13 @@ local function factory(args)
local err local err
weather_now, _, err = json.decode(f, 1, nil) weather_now, _, err = json.decode(f, 1, nil)
if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then if not err and type(weather_now) == 'table' and tonumber(weather_now['cod']) == 200 then
weather.notification_text = "" weather.notification_text = ''
for i = 1, weather_now["cnt"], math.floor(weather_now["cnt"] / cnt) do for i = 1, weather_now['cnt'], math.floor(weather_now['cnt'] / cnt) do
weather.notification_text = weather.notification_text .. weather.notification_text = weather.notification_text
notification_text_fun(weather_now["list"][i]) .. notification_text_fun(weather_now['list'][i])
if i < weather_now["cnt"] then if i < weather_now['cnt'] then
weather.notification_text = weather.notification_text .. "\n" weather.notification_text = weather.notification_text .. '\n'
end end
end end
end end
@ -111,23 +113,23 @@ local function factory(args)
local err local err
weather_now, _, err = json.decode(f, 1, nil) weather_now, _, err = json.decode(f, 1, nil)
if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then if not err and type(weather_now) == 'table' and tonumber(weather_now['cod']) == 200 then
local sunrise = tonumber(weather_now["sys"]["sunrise"]) local sunrise = tonumber(weather_now['sys']['sunrise'])
local sunset = tonumber(weather_now["sys"]["sunset"]) local sunset = tonumber(weather_now['sys']['sunset'])
local icon = weather_now["weather"][1]["icon"] local icon = weather_now['weather'][1]['icon']
local loc_now = os.time() local loc_now = os.time()
if sunrise <= loc_now and loc_now <= sunset then if sunrise <= loc_now and loc_now <= sunset then
icon = string.gsub(icon, "n", "d") icon = string.gsub(icon, 'n', 'd')
else else
icon = string.gsub(icon, "d", "n") icon = string.gsub(icon, 'd', 'n')
end end
weather.icon_path = icons_path .. icon .. ".png" weather.icon_path = icons_path .. icon .. '.png'
widget = weather.widget widget = weather.widget
settings() settings()
else else
weather.icon_path = icons_path .. "na.png" weather.icon_path = icons_path .. 'na.png'
weather.widget:set_markup(weather_na_markup) weather.widget:set_markup(weather_na_markup)
end end
@ -135,10 +137,13 @@ local function factory(args)
end) end)
end end
if showpopup == "on" then weather.attach(weather.widget) end if showpopup == 'on' then
weather.attach(weather.widget)
end
weather.timer = helpers.newtimer("weather-" .. city_id, timeout, weather.update, false, true) 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) weather.timer_forecast =
helpers.newtimer('weather_forecast-' .. city_id, timeout, weather.forecast_update, false, true)
return weather return weather
end end

View File

@ -10,13 +10,29 @@ local lain = require('lain')
local awful = require('awful') local awful = require('awful')
local wibox = require('wibox') local wibox = require('wibox')
local dpi = require('beautiful.xresources').apply_dpi local dpi = require('beautiful.xresources').apply_dpi
local naughty = require('naughty')
local settings = (function()
local status, settings = pcall(function()
return dofile(os.getenv('HOME') .. '/.config/awesome/settings.lua')
end)
if status then
return settings
else
naughty.notify({
preset = naughty.config.presets.critical,
title = 'Error while parsing settings!',
text = settings,
})
return {}
end
end)()
local os = os local os = os
local my_table = awful.util.table or gears.table -- 4.{0,1} compatibility local my_table = awful.util.table or gears.table -- 4.{0,1} compatibility
local theme = {} local theme = {}
theme.confdir = os.getenv('HOME') .. '/.config/awesome/' theme.confdir = os.getenv('HOME') .. '/.config/awesome/'
theme.wallpaper = os.getenv('HOME') .. '/.config/awesome/wall.png' theme.wallpaper = os.getenv('HOME') .. '/.config/awesome/' .. (settings['wallpaper'] or 'wall.png')
theme.font = 'Terminus 8' theme.font = 'Terminus 8'
theme.menu_bg_normal = '#000000' theme.menu_bg_normal = '#000000'
theme.menu_bg_focus = '#000000' theme.menu_bg_focus = '#000000'
@ -146,29 +162,39 @@ local cpu = lain.widget.cpu({
end, end,
}) })
local optional = {}
-- Coretemp -- Coretemp
--[[local tempicon = wibox.widget.imagebox(theme.widget_temp) if settings['show_temp'] == true then
local tempicon = wibox.widget.imagebox(theme.widget_temp)
local temp = lain.widget.temp({ local temp = lain.widget.temp({
settings = function() settings = function()
widget:set_markup(markup.fontfg(theme.font, "#f1af5f", coretemp_now .. "°C ")) -- luacheck: globals widget coretemp_now
widget:set_markup(markup.fontfg(theme.font, '#f1af5f', coretemp_now .. '°C '))
end,
})
table.insert(optional, tempicon)
table.insert(optional, temp)
end end
})]]
--
-- Battery -- Battery
--[[local baticon = wibox.widget.imagebox(theme.widget_batt) if settings['show_battery'] == true then
local baticon = wibox.widget.imagebox(theme.widget_batt)
local bat = lain.widget.bat({ local bat = lain.widget.bat({
settings = function() settings = function()
local perc = bat_now.perc ~= "N/A" and bat_now.perc .. "%" or bat_now.perc -- luacheck: globals widget bat_now
local perc = bat_now.perc ~= 'N/A' and bat_now.perc .. '%' or bat_now.perc
if bat_now.ac_status == 1 then if bat_now.ac_status == 1 then
perc = perc .. " plug" perc = perc .. ' plug'
end end
widget:set_markup(markup.fontfg(theme.font, theme.fg_normal, perc .. " ")) widget:set_markup(markup.fontfg(theme.font, theme.fg_normal, perc .. ' '))
end,
})
table.insert(optional, baticon)
table.insert(optional, bat)
end end
})]]
--
-- ALSA volume -- ALSA volume
local volicon = wibox.widget.imagebox(theme.widget_vol) local volicon = wibox.widget.imagebox(theme.widget_vol)
@ -331,6 +357,7 @@ function theme.at_screen_connect(s)
}, },
s.mytasklist, -- Middle widget s.mytasklist, -- Middle widget
--nil, --nil,
gears.table.join(
{ -- Right widgets { -- Right widgets
layout = wibox.layout.fixed.horizontal, layout = wibox.layout.fixed.horizontal,
wibox.widget.systray(), wibox.widget.systray(),
@ -360,15 +387,13 @@ function theme.at_screen_connect(s)
cpu.widget, cpu.widget,
fsicon, fsicon,
theme.fs.widget, theme.fs.widget,
--weathericon, },
--theme.weather.widget, optional,
--tempicon, {
--temp.widget,
--baticon,
--bat.widget,
clockicon, clockicon,
mytextclock, mytextclock,
}, }
),
}) })
end end

BIN
awesome/wall2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB