From: martin f. krafft Date: Sat, 2 Nov 2019 09:41:23 +0000 (+1300) Subject: Merge commit '33c0e0c2360a04fcc6f51bccb0ad2a7a9e9c07b3' X-Git-Url: https://git.madduck.net/etc/awesome.git/commitdiff_plain/66d9f3db4596e43efa55488569e06365a2125750?hp=-c Merge commit '33c0e0c2360a04fcc6f51bccb0ad2a7a9e9c07b3' --- 66d9f3db4596e43efa55488569e06365a2125750 diff --combined .config/awesome/lain/.gitmodules index a50818f,d95bcb5..d95bcb5 --- a/.config/awesome/lain/.gitmodules +++ b/.config/awesome/lain/.gitmodules @@@ -1,3 -1,3 +1,3 @@@ [submodule "lain.wiki"] path = wiki - url = https://github.com/copycat-killer/lain.wiki.git + url = https://github.com/lcpz/lain.wiki.git diff --combined .config/awesome/lain/ISSUE_TEMPLATE.md index 37c2141,e9dcc0b..e9dcc0b --- a/.config/awesome/lain/ISSUE_TEMPLATE.md +++ b/.config/awesome/lain/ISSUE_TEMPLATE.md @@@ -1,21 -1,33 +1,33 @@@ - # If you have a question + # Please, read me! - Take the following steps: - - 1. [Google it](https://encrypted.google.com) - 2. Search [Awesome doc](https://awesomewm.org/doc) - 3. Ask [community](https://awesomewm.org/community) - - and, if you still don't have an answer, you can ask here. - - **Please be warned:** if your question is __unrelated__ to this repository, a reply is only an act of kindness. + So that I can help you quickly and without having to redirect you here. # If you have an issue - **Please read the [wiki](https://github.com/copycat-killer/lain/wiki) and search the [Issues section](https://github.com/copycat-killer/lain/issues) first.** + **Please read the [wiki](https://github.com/lcpz/lain/wiki) and search the [Issues section](https://github.com/lcpz/lain/issues) first.** If you can't find a solution there, then go ahead and provide: * output of `awesome -v` and `lua -v` * expected behavior and actual behavior * steps to reproduce the problem + * X error log + + # How to provide X error log + + There are two ways: + + * (Physically) Restart X like this: + ```shell + startx -- -keeptty -nolisten tcp > $HOME/.xorg.log 2>&1 + ``` + the error log will be output into `$HOME/.xorg.log`. + + * (Virtually) Use [Xephyr](https://wikipedia.org/wiki/Xephyr): + ```shell + # set screen size as you like + Xephyr :1 -screen 1280x800 2> stdout.txt & DISPLAY=:1 awesome + ``` + the error log will be output in the file `stdout.txt`. + + Before reporting, read the log and see if you can solve it yourself. diff --combined .config/awesome/lain/README.rst index 4515be7,2b77f9a..2b77f9a --- a/.config/awesome/lain/README.rst +++ b/.config/awesome/lain/README.rst @@@ -5,50 -5,34 +5,34 @@@ Lai Layouts, widgets and utilities for Awesome WM 4.x ------------------------------------------------- - :Author: Luke Bonham + :Author: Luca CPZ :Version: git :License: GNU-GPL2_ - :Source: https://github.com/copycat-killer/lain - - Warning - ------- - - If you still have to use branch 3.5.x, you can refer to the commit 301faf5_, but be aware that it's no longer supported. + :Source: https://github.com/lcpz/lain Description ----------- - Successor of awesome-vain_, this module provides alternative layouts, asynchronous widgets and utility functions for Awesome_ WM. - - Read the wiki_ for all the info. + Successor of awesome-vain_, this module provides alternative layouts, asynchronous widgets and utility functions for Awesome_. Contributions ------------- - Any contribution is welcome! Feel free to make a pull request. + Constructive criticism and suggestions are welcome. - Just make sure that: + If you want to create a pull request, make sure that: - Your code fits with the general style of the module. In particular, you should use the same indentation pattern that the code uses, and also avoid adding space at the ends of lines. - - Your code its easy to understand, maintainable, and modularized. You should also avoid code duplication wherever possible by adding functions or using lain.helpers_. If something is unclear, and you can't write it in such a way that it will be clear, explain it with a comment. + - Your code its easy to understand, maintainable, and modularized. You should also avoid code duplication wherever possible by adding functions to or using lain.helpers_. If something is unclear, or you can not write it in such a way that it will be clear, explain it with a comment. - - You test your changes before submitting to make sure that not only your code works, but did not break other parts of the module too! + - You test your changes before submitting to make sure that you code works and does not break other parts of the module. - - You eventually update ``wiki`` submodule with a thorough section. + - You update ``wiki`` submodule with a thorough section, if necessary. Contributed widgets have to be put in ``widget/contrib``. - Screenshots - ----------- - - .. image:: http://i.imgur.com/8D9A7lW.png - .. image:: http://i.imgur.com/9Iv3OR3.png - .. image:: http://i.imgur.com/STCPcaJ.png - .. _GNU-GPL2: http://www.gnu.org/licenses/gpl-2.0.html - .. _301faf5: https://github.com/copycat-killer/lain/tree/301faf5370d045e94c9c344acb0fdac84a2f25a6 .. _awesome-vain: https://github.com/vain/awesome-vain .. _Awesome: https://github.com/awesomeWM/awesome - .. _wiki: https://github.com/copycat-killer/lain/wiki - .. _lain.helpers: https://github.com/copycat-killer/lain/blob/master/helpers.lua + .. _lain.helpers: https://github.com/lcpz/lain/blob/master/helpers.lua diff --combined .config/awesome/lain/helpers.lua index 4e5ce1f,d6f6b3c..d6f6b3c --- a/.config/awesome/lain/helpers.lua +++ b/.config/awesome/lain/helpers.lua @@@ -1,19 -1,19 +1,19 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - - --]] + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + + --]] - local easy_async = require("awful.spawn").easy_async + local spawn = require("awful.spawn") local timer = require("gears.timer") local debug = require("debug") local io = { lines = io.lines, open = io.open } + local pairs = pairs local rawget = rawget - local table = { sort = table.sort } + local table = { sort = table.sort, unpack = table.unpack } + local unpack = unpack or table.unpack -- lua 5.1 retro-compatibility -- Lain helper functions for internal use -- lain.helpers @@@ -34,53 -34,49 +34,49 @@@ en -- {{{ File operations - -- see if the file exists and is readable - function helpers.file_exists(file) - local f = io.open(file) - if f then - local s = f:read() - f:close() - f = s - end - return f ~= nil - end - - -- get all lines from a file, returns an empty - -- list/table if the file does not exist - function helpers.lines_from(file) - if not helpers.file_exists(file) then return {} end - local lines = {} - for line in io.lines(file) do - lines[#lines + 1] = line - end - return lines - end - - -- match all lines from a file, returns an empty - -- list/table if the file or match does not exist - function helpers.lines_match(regexp, file) - local lines = {} - for index,line in pairs(helpers.lines_from(file)) do - if string.match(line, regexp) then - lines[index] = line - end - end - return lines - end - - -- get first line of a file, return nil if - -- the file does not exist - function helpers.first_line(file) - return helpers.lines_from(file)[1] - end - - -- get first non empty line from a file, - -- returns nil otherwise - function helpers.first_nonempty_line(file) - for k,v in pairs(helpers.lines_from(file)) do - if #v then return v end - end - return nil + -- check if the file exists and is readable + function helpers.file_exists(path) + local file = io.open(path, "rb") + if file then file:close() end + return file ~= nil + end + + -- get a table with all lines from a file + function helpers.lines_from(path) + local lines = {} + for line in io.lines(path) do + lines[#lines + 1] = line + end + return lines + end + + -- get a table with all lines from a file matching regexp + function helpers.lines_match(regexp, path) + local lines = {} + for line in io.lines(path) do + if string.match(line, regexp) then + lines[#lines + 1] = line + end + end + return lines + end + + -- get first line of a file + function helpers.first_line(path) + local file, first = io.open(path, "rb"), nil + if file then + first = file:read("*l") + file:close() + end + return first + end + + -- get first non empty line from a file + function helpers.first_nonempty_line(path) + for line in io.lines(path) do + if #line then return line end + end + return nil end -- }}} @@@ -112,12 -108,29 +108,29 @@@ en -- @param callback function to execute on cmd output -- @return cmd PID function helpers.async(cmd, callback) - return easy_async(cmd, + return spawn.easy_async(cmd, + function (stdout, stderr, reason, exit_code) + callback(stdout, exit_code) + end) + end + + -- like above, but call spawn.easy_async with a shell + function helpers.async_with_shell(cmd, callback) + return spawn.easy_async_with_shell(cmd, function (stdout, stderr, reason, exit_code) - callback(stdout) + callback(stdout, exit_code) end) end + -- run a command and execute a function on its output line by line + function helpers.line_callback(cmd, callback) + return spawn.with_line_callback(cmd, { + stdout = function (line) + callback(line) + end, + }) + end + -- }}} -- {{{ A map utility @@@ -164,6 -177,28 +177,28 @@@ function helpers.spairs(t end end + -- create the partition of singletons of a given set + -- example: the trivial partition set of {a, b, c}, is {{a}, {b}, {c}} + function helpers.trivial_partition_set(set) + local ss = {} + for _,e in pairs(set) do + ss[#ss+1] = {e} + end + return ss + end + + -- create the powerset of a given set + function helpers.powerset(s) + if not s then return {} end + local t = {{}} + for i = 1, #s do + for j = 1, #t do + t[#t+1] = {s[i],unpack(t[j])} + end + end + return t + end + -- }}} return helpers diff --combined .config/awesome/lain/icons/cal/black/1.png index 0000000,d2fb62e..d2fb62e mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/10.png index 0000000,507b079..507b079 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/11.png index 0000000,336141b..336141b mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/12.png index 0000000,c589729..c589729 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/13.png index 0000000,377518b..377518b mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/14.png index 0000000,6f4a9fe..6f4a9fe mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/15.png index 0000000,1a271c1..1a271c1 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/16.png index 0000000,5e65835..5e65835 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/17.png index 0000000,f3fa0a9..f3fa0a9 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/18.png index 0000000,7acb37a..7acb37a mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/19.png index 0000000,a557957..a557957 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/2.png index 0000000,17b33e0..17b33e0 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/20.png index 0000000,558d111..558d111 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/21.png index 0000000,0bbedc8..0bbedc8 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/22.png index 0000000,762d262..762d262 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/23.png index 0000000,a39dcee..a39dcee mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/24.png index 0000000,c00dbca..c00dbca mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/25.png index 0000000,dc9243c..dc9243c mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/26.png index 0000000,50bb182..50bb182 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/27.png index 0000000,0fbf9fc..0fbf9fc mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/28.png index 0000000,def6ab2..def6ab2 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/29.png index 0000000,531923c..531923c mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/3.png index 0000000,98b552d..98b552d mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/30.png index 0000000,ca58151..ca58151 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/31.png index 0000000,6e8da21..6e8da21 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/4.png index 0000000,4335979..4335979 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/5.png index 0000000,576ec11..576ec11 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/6.png index 0000000,56fa8ab..56fa8ab mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/7.png index 0000000,7c90b3a..7c90b3a mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/8.png index 0000000,9d1f28e..9d1f28e mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/black/9.png index 0000000,00d0933..00d0933 mode 000000,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/1.png index 90b696c,a0faa20..a0faa20 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/10.png index b462ffb,7d9343b..7d9343b Binary files differ diff --combined .config/awesome/lain/icons/cal/white/11.png index cf43296,7af5e99..7af5e99 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/12.png index 42cf092,b164f85..b164f85 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/13.png index 37db670,fef74f3..fef74f3 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/14.png index 0188504,d747a6b..d747a6b Binary files differ diff --combined .config/awesome/lain/icons/cal/white/18.png index 817c426,0cf1c24..0cf1c24 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/19.png index 0e6dafc,bfd3530..bfd3530 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/2.png index b93789a,e7f3fa4..e7f3fa4 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/20.png index 3d8d7c6,9a5a1fb..9a5a1fb Binary files differ diff --combined .config/awesome/lain/icons/cal/white/21.png index 79a74f3,266ab9f..266ab9f Binary files differ diff --combined .config/awesome/lain/icons/cal/white/22.png index e8845ce,f486289..f486289 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/23.png index a8d4dfb,244dceb..244dceb Binary files differ diff --combined .config/awesome/lain/icons/cal/white/24.png index 1a3b38a,0ce1c75..0ce1c75 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/25.png index c3621b7,48d279c..48d279c Binary files differ diff --combined .config/awesome/lain/icons/cal/white/26.png index f26731b,7535855..7535855 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/27.png index e4dde77,2aa9074..2aa9074 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/28.png index b924c22,0201976..0201976 Binary files differ diff --combined .config/awesome/lain/icons/cal/white/29.png index e9a74f8,9305b9b..9305b9b Binary files differ diff --combined .config/awesome/lain/icons/cal/white/3.png index 1124271,f1eb5de..f1eb5de Binary files differ diff --combined .config/awesome/lain/icons/cal/white/30.png index 8147d78,1ba61aa..1ba61aa Binary files differ diff --combined .config/awesome/lain/icons/cal/white/31.png index a1be3e8,e9a873b..e9a873b Binary files differ diff --combined .config/awesome/lain/icons/cal/white/4.png index 16713bc,ee1ed6a..ee1ed6a Binary files differ diff --combined .config/awesome/lain/icons/cal/white/6.png index a1c9798,0a7bf4d..0a7bf4d Binary files differ diff --combined .config/awesome/lain/icons/cal/white/8.png index 909b726,cb03d0b..cb03d0b Binary files differ diff --combined .config/awesome/lain/icons/cal/white/9.png index dc636c4,fca554a..fca554a Binary files differ diff --combined .config/awesome/lain/icons/layout/default/cascadetile.png index 2f12ada,ba30f43..ba30f43 Binary files differ diff --combined .config/awesome/lain/icons/layout/default/cascadetilew.png index c46b48b,d15eb70..d15eb70 Binary files differ diff --combined .config/awesome/lain/icons/layout/default/centerwork.png index 826b331,51e06bc..51e06bc Binary files differ diff --combined .config/awesome/lain/icons/layout/default/centerworkh.png index 4fb4fdd,c59092f..c59092f Binary files differ diff --combined .config/awesome/lain/icons/layout/default/centerworkhw.png index fd27766,7820f8c..7820f8c Binary files differ diff --combined .config/awesome/lain/icons/layout/default/centerworkw.png index fcfa7e3,85e6996..85e6996 Binary files differ diff --combined .config/awesome/lain/icons/layout/zenburn/cascade.png index 532842d,fbe4fac..fbe4fac Binary files differ diff --combined .config/awesome/lain/icons/layout/zenburn/cascadetile.png index 87be658,2e03a80..2e03a80 Binary files differ diff --combined .config/awesome/lain/icons/layout/zenburn/centerfair.png index 01cda8e,75dc993..75dc993 Binary files differ diff --combined .config/awesome/lain/icons/layout/zenburn/centerwork.png index 6a2cecc,af7a863..af7a863 Binary files differ diff --combined .config/awesome/lain/icons/layout/zenburn/centerworkh.png index 00beeb5,88019b3..88019b3 Binary files differ diff --combined .config/awesome/lain/icons/layout/zenburn/termfair.png index b7d5880,f7640b5..f7640b5 Binary files differ diff --combined .config/awesome/lain/icons/mail.png index 60ba6e0,9c0c7a3..9c0c7a3 Binary files differ diff --combined .config/awesome/lain/icons/no_net.png index 1a3e8a8,3613372..3613372 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/01d.png index d9e2745,569965e..569965e mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/01n.png index 84ea140,ce5b135..ce5b135 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/02d.png index 8fd0a5b,2ba9799..2ba9799 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/02n.png index 9e4404d,12e4283..12e4283 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/03d.png index 22b929c,1cf0e9d..1cf0e9d mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/03n.png index d8b3673,89a42b8..89a42b8 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/04d.png index bac1e7e,e7fb67f..e7fb67f mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/09d.png index d00552a,cfa066a..cfa066a mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/10d.png index 3cc6665,712d0c8..712d0c8 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/11d.png index d30e120,3b62f7c..3b62f7c mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/13d.png index ddcb8f3,e265b01..e265b01 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/50d.png index 009039f,905ace3..905ace3 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/openweathermap/na.png index 62a5350,1cc5132..1cc5132 mode 100755,100644..100644 Binary files differ diff --combined .config/awesome/lain/icons/taskwarrior.png index 859ca29,c64fe86..c64fe86 Binary files differ diff --combined .config/awesome/lain/init.lua index 46ab825,b59d5dd..b59d5dd --- a/.config/awesome/lain/init.lua +++ b/.config/awesome/lain/init.lua @@@ -1,12 -1,11 +1,11 @@@ - --[[ - - Lain - Layouts, widgets and utilities for Awesome WM - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - + + Lain + Layouts, widgets and utilities for Awesome WM + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + --]] return { diff --combined .config/awesome/lain/lain-scm-1.rockspec index 0000000,fb1eaaf..fb1eaaf mode 000000,100644..100644 --- a/.config/awesome/lain/lain-scm-1.rockspec +++ b/.config/awesome/lain/lain-scm-1.rockspec @@@ -1,0 -1,27 +1,27 @@@ + package = "lain" + version = "scm-1" + source = { + url = "https://github.com/lcpz/lain", + tag = "scm-1`" + } + description = { + summary = "Layout, widgets and utilities for Awesome WM", + detailed = [[ + Successor of awesome-vain, this module provides alternative layouts, asynchronous widgets and utility functions for Awesome WM. + + Dependencies: curl (for IMAP, MPD and weather widgets); Glib >= 2.54 (for filesystems widget). + ]], + homepage = "https://github.com/lcpz/lain", + license = "GPL-2.0" + } + dependencies = { + "lua >= 5.1", + "awesome >= 4.0", + "Glib >= 2.54", + "curl" + } + supported_platforms = { "linux" } + build = { + type = "builtin", + modules = { lain = "init.lua" } + } diff --combined .config/awesome/lain/layout/cascade.lua index 204ce40,cbc3877..cbc3877 --- a/.config/awesome/lain/layout/cascade.lua +++ b/.config/awesome/lain/layout/cascade.lua @@@ -1,11 -1,10 +1,10 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2014, projektile - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2014, projektile + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local floor = math.floor diff --combined .config/awesome/lain/layout/centerwork.lua index eafab78,2b38a69..2b38a69 --- a/.config/awesome/lain/layout/centerwork.lua +++ b/.config/awesome/lain/layout/centerwork.lua @@@ -1,34 -1,32 +1,32 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2016, Henrik Antonsson - * (c) 2015, Joerg Jaspert - * (c) 2014, projektile - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2018, Eugene Pakhomov + * (c) 2016, Henrik Antonsson + * (c) 2015, Joerg Jaspert + * (c) 2014, projektile + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] - local floor = math.floor - local screen = screen + local floor, max, mouse, mousegrabber, screen = math.floor, math.max, mouse, mousegrabber, screen local centerwork = { - name = "centerwork", - horizontal = { name = "centerworkh" } + name = "centerwork", + horizontal = { name = "centerworkh" } } - local function do_centerwork(p, orientation) - local t = p.tag or screen[p.screen].selected_tag - local wa = p.workarea + local function arrange(p, layout) + local t = p.tag or screen[p.screen].selected_tag + local wa = p.workarea local cls = p.clients if #cls == 0 then return end - local c = cls[1] - local g = {} + local c, g = cls[1], {} - -- Main column, fixed width and height. + -- Main column, fixed width and height local mwfact = t.master_width_factor local mainhei = floor(wa.height * mwfact) local mainwid = floor(wa.width * mwfact) @@@ -43,7 -41,7 +41,7 @@@ local slaveFirstDim, slaveSecondDim = 0, 0 - if orientation == "vertical" then + if layout.name == "centerwork" then -- vertical if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.height / nbrFirstSlaves) end if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.height / nbrSecondSlaves) end @@@ -52,7 -50,7 +50,7 @@@ g.x = wa.x + slaveLwid g.y = wa.y - else + else -- horizontal if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.width / nbrFirstSlaves) end if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.width / nbrSecondSlaves) end @@@ -63,92 -61,134 +61,134 @@@ g.y = wa.y + slaveThei end - if g.width < 1 then g.width = 1 end - if g.height < 1 then g.height = 1 end + g.width = max(g.width, 1) + g.height = max(g.height, 1) p.geometries[c] = g - -- Auxiliary windows. + -- Auxiliary clients if #cls <= 1 then return end - for i = 2,#cls do - local c = cls[i] - local g = {} + for i = 2, #cls do + local c, g = cls[i], {} + local idxChecker, dimToAssign local rowIndex = floor(i/2) - if orientation == "vertical" then - if i % 2 == 0 then - -- left slave - g.x = wa.x - g.y = wa.y + (rowIndex-1)*slaveFirstDim - + if layout.name == "centerwork" then + if i % 2 == 0 then -- left slave + g.x = wa.x + g.y = wa.y + (rowIndex - 1) * slaveFirstDim g.width = slaveLwid - -- if last slave in left row use remaining space for that slave - if rowIndex == nbrFirstSlaves then - g.height = wa.y + wa.height - g.y - else - g.height = slaveFirstDim - end - else - -- right slave - g.x = wa.x + slaveLwid + mainwid - g.y = wa.y + (rowIndex-1)*slaveSecondDim - + idxChecker, dimToAssign = nbrFirstSlaves, slaveFirstDim + else -- right slave + g.x = wa.x + slaveLwid + mainwid + g.y = wa.y + (rowIndex - 1) * slaveSecondDim g.width = slaveRwid - -- if last slave in right row use remaining space for that slave - if rowIndex == nbrSecondSlaves then - g.height = wa.y + wa.height - g.y - else - g.height = slaveSecondDim - end + idxChecker, dimToAssign = nbrSecondSlaves, slaveSecondDim end - else - if i % 2 == 0 then - -- top slave - g.x = wa.x + (rowIndex-1)*slaveFirstDim - g.y = wa.y - - g.height = slaveThei - -- if last slave in top row use remaining space for that slave - if rowIndex == nbrFirstSlaves then - g.width = wa.x + wa.width - g.x - else - g.width = slaveFirstDim - end + -- if last slave in row, use remaining space for it + if rowIndex == idxChecker then + g.height = wa.y + wa.height - g.y else - -- bottom slave - g.x = wa.x + (rowIndex-1)*slaveSecondDim - g.y = wa.y + slaveThei + mainhei + g.height = dimToAssign + end + else + if i % 2 == 0 then -- top slave + g.x = wa.x + (rowIndex - 1) * slaveFirstDim + g.y = wa.y + g.height = slaveThei + idxChecker, dimToAssign = nbrFirstSlaves, slaveFirstDim + else -- bottom slave + g.x = wa.x + (rowIndex - 1) * slaveSecondDim + g.y = wa.y + slaveThei + mainhei g.height = slaveBhei - -- if last slave in bottom row use remaining space for that slave - if rowIndex == nbrSecondSlaves then - g.width = wa.x + wa.width - g.x - else - g.width = slaveSecondDim - end + idxChecker, dimToAssign = nbrSecondSlaves, slaveSecondDim + end + -- if last slave in row, use remaining space for it + if rowIndex == idxChecker then + g.width = wa.x + wa.width - g.x + else + g.width = dimToAssign end end - if g.width < 1 then g.width = 1 end - if g.height < 1 then g.height = 1 end + g.width = max(g.width, 1) + g.height = max(g.height, 1) p.geometries[c] = g end end + local function mouse_resize_handler(c, corner, x, y, orientation) + local wa = c.screen.workarea + local mwfact = c.screen.selected_tag.master_width_factor + local g = c:geometry() + local offset = 0 + local cursor = "cross" + + local corner_coords + + if orientation == 'vertical' then + if g.height + 15 >= wa.height then + offset = g.height * .5 + cursor = "sb_h_double_arrow" + elseif not (g.y + g.height + 15 > wa.y + wa.height) then + offset = g.height + end + corner_coords = { x = wa.x + wa.width * (1 - mwfact) / 2, y = g.y + offset } + else + if g.width + 15 >= wa.width then + offset = g.width * .5 + cursor = "sb_v_double_arrow" + elseif not (g.x + g.width + 15 > wa.x + wa.width) then + offset = g.width + end + corner_coords = { y = wa.y + wa.height * (1 - mwfact) / 2, x = g.x + offset } + end + + mouse.coords(corner_coords) - function centerwork.horizontal.arrange(p) - return do_centerwork(p, "horizontal") + local prev_coords = {} + + mousegrabber.run(function(_mouse) + if not c.valid then return false end + for _, v in ipairs(_mouse.buttons) do + if v then + prev_coords = { x = _mouse.x, y = _mouse.y } + local new_mwfact + if orientation == 'vertical' then + new_mwfact = 1 - (_mouse.x - wa.x) / wa.width * 2 + else + new_mwfact = 1 - (_mouse.y - wa.y) / wa.height * 2 + end + c.screen.selected_tag.master_width_factor = math.min(math.max(new_mwfact, 0.01), 0.99) + return true + end + end + return prev_coords.x == _mouse.x and prev_coords.y == _mouse.y + end, cursor) end function centerwork.arrange(p) - return do_centerwork(p, "vertical") + return arrange(p, centerwork) + end + + function centerwork.horizontal.arrange(p) + return arrange(p, centerwork.horizontal) + end + + function centerwork.mouse_resize_handler(c, corner, x, y) + return mouse_resize_handler(c, corner, x, y, 'vertical') + end + + function centerwork.horizontal.mouse_resize_handler(c, corner, x, y) + return mouse_resize_handler(c, corner, x, y, 'horizontal') end return centerwork diff --combined .config/awesome/lain/layout/init.lua index d79679a,6478b06..6478b06 --- a/.config/awesome/lain/layout/init.lua +++ b/.config/awesome/lain/layout/init.lua @@@ -1,15 -1,14 +1,14 @@@ - --[[ - - Lain - Layouts, widgets and utilities for Awesome WM - - Layouts section - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Lain + Layouts, widgets and utilities for Awesome WM + + Layouts section + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local wrequire = require("lain.helpers").wrequire diff --combined .config/awesome/lain/layout/termfair.lua index 33b7ffc,e33894e..e33894e --- a/.config/awesome/lain/layout/termfair.lua +++ b/.config/awesome/lain/layout/termfair.lua @@@ -1,17 -1,14 +1,14 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2014, projektile - * (c) 2013, Luke Bonham - * (c) 2010, Nicolas Estibals - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2014, projektile + * (c) 2013, Luca CPZ + * (c) 2010, Nicolas Estibals + * (c) 2010-2012, Peter Hofmann + --]] - local math = { ceil = math.ceil, - floor = math.floor, - max = math.max } + local math = math local screen = screen local tonumber = tonumber diff --combined .config/awesome/lain/util/init.lua index 1fc5805,55bfa26..55bfa26 --- a/.config/awesome/lain/util/init.lua +++ b/.config/awesome/lain/util/init.lua @@@ -1,15 -1,14 +1,14 @@@ - --[[ - - Lain - Layouts, widgets and utilities for Awesome WM - - Utilities section - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Lain + Layouts, widgets and utilities for Awesome WM + + Utilities section + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local awful = require("awful") @@@ -77,7 -76,7 +76,7 @@@ function util.magnify_client(c, width_f end end - -- https://github.com/copycat-killer/lain/issues/195 + -- https://github.com/lcpz/lain/issues/195 function util.mc(c, width_f, height_f) c = c or util.magnified_client if not c then return end @@@ -117,7 -116,7 +116,7 @@@ function util.add_tag(layout textbox = awful.screen.focused().mypromptbox.widget, exe_callback = function(name) if not name or #name == 0 then return end - awful.tag.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.layouts[0] }):view_only() + awful.tag.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile }):view_only() end } end @@@ -159,9 -158,10 +158,10 @@@ en -- }}} -- On the fly useless gaps change - function util.useless_gaps_resize(thatmuch) - local scr = awful.screen.focused() - scr.selected_tag.gap = scr.selected_tag.gap + tonumber(thatmuch) + function util.useless_gaps_resize(thatmuch, s, t) + local scr = s or awful.screen.focused() + local tag = t or scr.selected_tag + tag.gap = tag.gap + tonumber(thatmuch) awful.layout.arrange(scr) end diff --combined .config/awesome/lain/util/markup.lua index 0d3b17a,63f9486..63f9486 --- a/.config/awesome/lain/util/markup.lua +++ b/.config/awesome/lain/util/markup.lua @@@ -1,62 -1,61 +1,61 @@@ - --[[ - - Licensed under MIT License - * (c) 2013, Luke Bonham - * (c) 2009, Uli Schlachter - * (c) 2009, Majic - + + Licensed under MIT License + * (c) 2013, Luca CPZ + * (c) 2009, Uli Schlachter + * (c) 2009, Majic + --]] - local string = { format = string.format } + local format = string.format local setmetatable = setmetatable -- Lain markup util submodule -- lain.util.markup local markup = { fg = {}, bg = {} } - -- Convenience tags. - function markup.bold(text) return '' .. text .. '' end - function markup.italic(text) return '' .. text .. '' end - function markup.strike(text) return '' .. text .. '' end - function markup.underline(text) return '' .. text .. '' end - function markup.monospace(text) return '' .. text .. '' end - function markup.big(text) return '' .. text .. '' end - function markup.small(text) return '' .. text .. '' end + -- Convenience tags + function markup.bold(text) return format("%s", text) end + function markup.italic(text) return format("%s", text) end + function markup.strike(text) return format("%s", text) end + function markup.underline(text) return format("%s", text) end + function markup.monospace(text) return format("%s", text) end + function markup.big(text) return format("%s", text) end + function markup.small(text) return format("%s", text) end - -- Set the font. + -- Set the font function markup.font(font, text) - return '' .. text ..'' + return format("%s", font, text) end - -- Set the foreground. + -- Set the foreground function markup.fg.color(color, text) - return '' .. text .. '' + return format("%s", color, text) end - -- Set the background. + -- Set the background function markup.bg.color(color, text) - return '' .. text .. '' + return format("%s", color, text) end - -- Set foreground and background. + -- Set foreground and background function markup.color(fg, bg, text) - return string.format('%s', fg, bg, text) + return format("%s", fg, bg, text) end - -- Set font and foreground. + -- Set font and foreground function markup.fontfg(font, fg, text) - return string.format('%s', font, fg, text) + return format("%s", font, fg, text) end - -- Set font and background. + -- Set font and background function markup.fontbg(font, bg, text) - return string.format('%s', font, bg, text) + return format("%s", font, bg, text) end - -- Set font, foreground and background. + -- Set font, foreground and background function markup.fontcolor(font, fg, bg, text) - return string.format('%s', font, fg, bg, text) + return format("%s", font, fg, bg, text) end -- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...) diff --combined .config/awesome/lain/util/menu_iterator.lua index 0000000,9959b25..9959b25 mode 000000,100644..100644 --- a/.config/awesome/lain/util/menu_iterator.lua +++ b/.config/awesome/lain/util/menu_iterator.lua @@@ -1,0 -1,145 +1,145 @@@ + --[[ + + Licensed under GNU General Public License v2 + * (c) 2017, Simon Désaulniers + * (c) 2017, Uli Schlachter + * (c) 2017, Jeferson Siqueira + + --]] + + -- Menu iterator with Naughty notifications + -- lain.util.menu_iterator + + local naughty = require("naughty") + local helpers = require("lain.helpers") + local util = require("lain.util") + local atable = require("awful.util").table + local assert = assert + local pairs = pairs + local tconcat = table.concat + local unpack = unpack or table.unpack -- lua 5.1 retro-compatibility + + local state = { cid = nil } + + local function naughty_destroy_callback(reason) + local closed = naughty.notificationClosedReason + if reason == closed.expired or reason == closed.dismissedByUser then + local actions = state.index and state.menu[state.index - 1][2] + if actions then + for _,action in pairs(actions) do + -- don't try to call nil callbacks + if action then action() end + end + state.index = nil + end + end + end + + -- Iterates over a menu. + -- After the timeout, callbacks associated to the last visited choice are + -- executed. Inputs: + -- * menu: a list of {label, {callbacks}} pairs + -- * timeout: time to wait before confirming the menu selection + -- * icon: icon to display in the notification of the chosen label + local function iterate(menu, timeout, icon) + local timeout = timeout or 4 -- default timeout for each menu entry + local icon = icon or nil -- icon to display on the menu + + -- Build the list of choices + if not state.index then + state.menu = menu + state.index = 1 + end + + -- Select one and display the appropriate notification + local label + local next = state.menu[state.index] + state.index = state.index + 1 + + if not next then + label = "Cancel" + state.index = nil + else + label, _ = unpack(next) + end + + state.cid = naughty.notify({ + text = label, + icon = icon, + timeout = timeout, + screen = mouse.screen, + replaces_id = state.cid, + destroy = naughty_destroy_callback + }).id + end + + -- Generates a menu compatible with the first argument of `iterate` function and + -- suitable for the following cases: + -- * all possible choices individually (partition of singletons); + -- * all possible subsets of the set of choices (powerset). + -- + -- Inputs: + -- * args: an array containing the following members: + -- * choices: Array of choices (string) on which the menu will be + -- generated. + -- * name: Displayed name of the menu (in the form "name: choices"). + -- * selected_cb: Callback to execute for each selected choice. Takes + -- the choice as a string argument. Can be `nil` (no action + -- to execute). + -- * rejected_cb: Callback to execute for each rejected choice (possible + -- choices which are not selected). Takes the choice as a + -- string argument. Can be `nil` (no action to execute). + -- * extra_choices: An array of extra { choice_str, callback_fun } pairs to be + -- added to the menu. Each callback_fun can be `nil`. + -- * combination: The combination of choices to generate. Possible values: + -- "powerset" and "single" (default). + -- Output: + -- * m: menu to be iterated over. + local function menu(args) + local choices = assert(args.choices or args[1]) + local name = assert(args.name or args[2]) + local selected_cb = args.selected_cb + local rejected_cb = args.rejected_cb + local extra_choices = args.extra_choices or {} + + local ch_combinations = args.combination == "powerset" and helpers.powerset(choices) or helpers.trivial_partition_set(choices) + + for _,c in pairs(extra_choices) do + ch_combinations = atable.join(ch_combinations, {{c[1]}}) + end + + local m = {} -- the menu + + for _,c in pairs(ch_combinations) do + if #c > 0 then + local cbs = {} + + -- selected choices + for _,ch in pairs(c) do + if atable.hasitem(choices, ch) then + cbs[#cbs + 1] = selected_cb and function() selected_cb(ch) end or nil + end + end + + -- rejected choices + for _,ch in pairs(choices) do + 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 + end + end + + -- add user extra choices (like the choice "None" for example) + for _,x in pairs(extra_choices) do + if x[1] == c[1] then + cbs[#cbs + 1] = x[2] + end + end + + m[#m + 1] = { name .. ": " .. tconcat(c, " + "), cbs } + end + end + + return m + end + + return { iterate = iterate, menu = menu } diff --combined .config/awesome/lain/util/quake.lua index 4c42803,01891b0..01891b0 --- a/.config/awesome/lain/util/quake.lua +++ b/.config/awesome/lain/util/quake.lua @@@ -1,21 -1,17 +1,17 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2016, Luke Bonham - * (c) 2015, unknown - + + Licensed under GNU General Public License v2 + * (c) 2016, Luca CPZ + * (c) 2015, unknown + --]] local awful = require("awful") local capi = { client = client } - - local math = { floor = math.floor } - local string = { format = string.format } - + local math = math + local string = string local pairs = pairs local screen = screen - local setmetatable = setmetatable -- Quake-like Dropdown application spawn @@@ -34,7 -30,7 +30,7 @@@ function quake:display( for c in awful.client.iterate(function (c) -- c.name may be changed! return c.instance == self.name - end, nil, self.screen) + end) do i = i + 1 if i == 1 then @@@ -64,7 -60,7 +60,7 @@@ client.floating = true client.border_width = self.border client.size_hints_honor = false - client:geometry(self:compute_size()) + client:geometry(self.geometry[self.screen.index] or self:compute_size()) -- Set not sticky and on top client.sticky = false @@@ -96,12 -92,12 +92,12 @@@ en function quake:compute_size() -- skip if we already have a geometry for this screen - if not self.geometry[self.screen] then + if not self.geometry[self.screen.index] then local geom if not self.overlap then - geom = screen[self.screen].workarea + geom = screen[self.screen.index].workarea else - geom = screen[self.screen].geometry + geom = screen[self.screen.index].geometry end local width, height = self.width, self.height if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end @@@ -113,9 -109,9 +109,9 @@@ 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] = { x = x, y = y, width = width, height = height } + self.geometry[self.screen.index] = { x = x, y = y, width = width, height = height } end - return self.geometry[self.screen] + return self.geometry[self.screen.index] end function quake:new(config) @@@ -159,7 -155,10 +155,10 @@@ function quake:toggle( if self.followtag then self.screen = awful.screen.focused() end local current_tag = self.screen.selected_tag if current_tag and self.last_tag ~= current_tag and self.visible then - self:display():move_to_tag(current_tag) + local c=self:display() + if c then + c:move_to_tag(current_tag) + end else self.visible = not self.visible self:display() diff --combined .config/awesome/lain/util/separators.lua index abf57c4,465132d..465132d --- a/.config/awesome/lain/util/separators.lua +++ b/.config/awesome/lain/util/separators.lua @@@ -1,14 -1,13 +1,13 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2015, Luke Bonham - * (c) 2015, plotnikovanton - + + Licensed under GNU General Public License v2 + * (c) 2015, Luca CPZ + * (c) 2015, plotnikovanton + --]] - local wibox = require("wibox") - local gears = require("gears") + local wibox = require("wibox") + local gears = require("gears") -- Lain Cairo separators util submodule -- lain.util.separators @@@ -19,14 -18,22 +18,22 @@@ local separators = { height = 0, width -- Right function separators.arrow_right(col1, col2) local widget = wibox.widget.base.make_widget() + widget.col1 = col1 + widget.col2 = col2 widget.fit = function(m, w, h) return separators.width, separators.height end + widget.update = function(col1, col2) + widget.col1 = col1 + widget.col2 = col2 + widget:emit_signal("widget::redraw_needed") + end + widget.draw = function(mycross, wibox, cr, width, height) - if col2 ~= "alpha" then - cr:set_source_rgb(gears.color.parse_color(col2)) + if widget.col2 ~= "alpha" then + cr:set_source_rgb(gears.color.parse_color(widget.col2)) cr:new_path() cr:move_to(0, 0) cr:line_to(width, height/2) @@@ -42,8 -49,8 +49,8 @@@ cr:fill() end - if col1 ~= "alpha" then - cr:set_source_rgb(gears.color.parse_color(col1)) + if widget.col1 ~= "alpha" then + cr:set_source_rgb(gears.color.parse_color(widget.col1)) cr:new_path() cr:move_to(0, 0) cr:line_to(width, height/2) @@@ -59,14 -66,22 +66,22 @@@ en -- Left function separators.arrow_left(col1, col2) local widget = wibox.widget.base.make_widget() + widget.col1 = col1 + widget.col2 = col2 widget.fit = function(m, w, h) return separators.width, separators.height end + widget.update = function(col1, col2) + widget.col1 = col1 + widget.col2 = col2 + widget:emit_signal("widget::redraw_needed") + end + widget.draw = function(mycross, wibox, cr, width, height) - if col1 ~= "alpha" then - cr:set_source_rgb(gears.color.parse_color(col1)) + if widget.col1 ~= "alpha" then + cr:set_source_rgb(gears.color.parse_color(widget.col1)) cr:new_path() cr:move_to(width, 0) cr:line_to(0, height/2) @@@ -82,14 -97,14 +97,14 @@@ cr:fill() end - if col2 ~= "alpha" then + if widget.col2 ~= "alpha" then cr:new_path() cr:move_to(width, 0) cr:line_to(0, height/2) cr:line_to(width, height) cr:close_path() - cr:set_source_rgb(gears.color.parse_color(col2)) + cr:set_source_rgb(gears.color.parse_color(widget.col2)) cr:fill() end end diff --combined .config/awesome/lain/widget/alsa.lua index 36ccc71,3b6c6d6..3b6c6d6 --- a/.config/awesome/lain/widget/alsa.lua +++ b/.config/awesome/lain/widget/alsa.lua @@@ -1,17 -1,15 +1,15 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010, Adrian C. - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010, Adrian C. + --]] local helpers = require("lain.helpers") local shell = require("awful.util").shell local wibox = require("wibox") - local string = { match = string.match, - format = string.format } + local string = string -- ALSA volume -- lain.widget.alsa diff --combined .config/awesome/lain/widget/alsabar.lua index 2ad0210,b2f7b44..b2f7b44 --- a/.config/awesome/lain/widget/alsabar.lua +++ b/.config/awesome/lain/widget/alsabar.lua @@@ -1,21 -1,19 +1,19 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2013, Rman - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2013, Rman + --]] - local helpers = require("lain.helpers") - local awful = require("awful") - local naughty = require("naughty") - local wibox = require("wibox") - local math = { modf = math.modf } - local string = { format = string.format, - match = string.match, - rep = string.rep } - local type, tonumber = type, tonumber + local helpers = require("lain.helpers") + local awful = require("awful") + local naughty = require("naughty") + local wibox = require("wibox") + local math = math + local string = string + local type = type + local tonumber = tonumber -- ALSA volume bar -- lain.widget.alsabar @@@ -29,7 -27,7 +27,7 @@@ local function factory(args }, _current_level = 0, - _muted = false + _playback = "off" } local args = args or {} @@@ -37,8 -35,14 +35,14 @@@ local settings = args.settings or function() end local width = args.width or 63 local height = args.height or 1 + local margins = args.margins or 1 + local paddings = args.paddings or 1 local ticks = args.ticks or false local ticks_size = args.ticks_size or 7 + local tick = args.tick or "|" + local tick_pre = args.tick_pre or "[" + local tick_post = args.tick_post or "]" + local tick_none = args.tick_none or " " alsabar.cmd = args.cmd or "amixer" alsabar.channel = args.channel or "Master" @@@ -48,8 -52,7 +52,7 @@@ alsabar.notification_preset = args.notification_preset if not alsabar.notification_preset then - alsabar.notification_preset = {} - alsabar.notification_preset.font = "Monospace 10" + alsabar.notification_preset = { font = "Monospace 10" } end local format_cmd = string.format("%s get %s", alsabar.cmd, alsabar.channel) @@@ -60,12 -63,12 +63,12 @@@ end alsabar.bar = wibox.widget { - forced_height = height, - forced_width = width, color = alsabar.colors.unmute, background_color = alsabar.colors.background, - margins = 1, - paddings = 1, + forced_height = height, + forced_width = width, + margins = margins, + paddings = margins, ticks = ticks, ticks_size = ticks_size, widget = wibox.widget.progressbar @@@ -75,23 -78,27 +78,27 @@@ function alsabar.update(callback) helpers.async(format_cmd, function(mixer) - local volu,mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)") - if (volu and tonumber(volu) ~= alsabar._current_level) or (mute and string.match(mute, "on") ~= alsabar._muted) then - alsabar._current_level = tonumber(volu) or alsabar._current_level + local vol, playback = string.match(mixer, "([%d]+)%%.*%[([%l]*)") + + if not vol or not playback then return end + + if vol ~= alsabar._current_level or playback ~= alsabar._playback then + alsabar._current_level = tonumber(vol) alsabar.bar:set_value(alsabar._current_level / 100) - if (not mute and tonumber(volu) == 0) or mute == "off" then - alsabar._muted = true - alsabar.tooltip:set_text ("[Muted]") + if alsabar._current_level == 0 or playback == "off" then + alsabar._playback = playback + alsabar.tooltip:set_text("[Muted]") alsabar.bar.color = alsabar.colors.mute else - alsabar._muted = false - alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, volu)) + alsabar._playback = "on" + alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, vol)) alsabar.bar.color = alsabar.colors.unmute end - volume_now = {} - volume_now.level = tonumber(volu) - volume_now.status = mute + volume_now = { + level = alsabar._current_level, + status = alsabar._playback + } settings() @@@ -104,15 -111,39 +111,39 @@@ alsabar.update(function() local preset = alsabar.notification_preset - if alsabar._muted then - preset.title = string.format("%s - Muted", alsabar.channel) - else - 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 + preset.title = preset.title .. " Muted" + end + + -- tot is the maximum number of ticks to display in the notification + local tot = alsabar.notification_preset.max_ticks + + if not tot then + local wib = awful.screen.focused().mywibox + -- if we can grab mywibox, tot is defined as its height if + -- horizontal, or width otherwise + if wib then + if wib.position == "left" or wib.position == "right" then + tot = wib.width + else + tot = wib.height + end + -- fallback: default horizontal wibox height + else + tot = 20 + end end - int = math.modf((alsabar._current_level / 100) * awful.screen.focused().mywibox.height) - preset.text = string.format("[%s%s]", string.rep("|", int), - string.rep(" ", awful.screen.focused().mywibox.height - int)) + int = math.modf((alsabar._current_level / 100) * tot) + preset.text = string.format( + "%s%s%s%s", + tick_pre, + string.rep(tick, int), + string.rep(tick_none, tot - int), + tick_post + ) if alsabar.followtag then preset.screen = awful.screen.focused() end diff --combined .config/awesome/lain/widget/bat.lua index e901842,3cb801c..3cb801c --- a/.config/awesome/lain/widget/bat.lua +++ b/.config/awesome/lain/widget/bat.lua @@@ -1,36 -1,53 +1,53 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] - local first_line = require("lain.helpers").first_line - local newtimer = require("lain.helpers").newtimer - local naughty = require("naughty") - local wibox = require("wibox") - local math = { abs = math.abs, - floor = math.floor, - log10 = math.log10, - min = math.min } - local string = { format = string.format } - local ipairs = ipairs - local tonumber = tonumber + local helpers = require("lain.helpers") + local fs = require("gears.filesystem") + local naughty = require("naughty") + local wibox = require("wibox") + local math = math + local string = string + local ipairs = ipairs + local tonumber = tonumber -- Battery infos -- lain.widget.bat local function factory(args) - local bat = { widget = wibox.widget.textbox() } - local args = args or {} - local timeout = args.timeout or 30 - local batteries = args.batteries or (args.battery and {args.battery}) or {"BAT0"} - local ac = args.ac or "AC0" - local notify = args.notify or "on" - local n_perc = args.n_perc or { 5, 15 } - local settings = args.settings or function() end + local pspath = args.pspath or "/sys/class/power_supply/" + + if not fs.is_dir(pspath) then + naughty.notify { text = "lain.widget.bat: invalid power supply path", timeout = 0 } + return + end + + local bat = { widget = wibox.widget.textbox() } + local args = args or {} + local timeout = args.timeout or 30 + local notify = args.notify or "on" + local full_notify = args.full_notify or notify + local n_perc = args.n_perc or { 5, 15 } + local batteries = args.batteries or (args.battery and {args.battery}) or {} + local ac = args.ac or "AC0" + local settings = args.settings or function() end + + function bat.get_batteries() + helpers.line_callback("ls -1 " .. pspath, function(line) + local bstr = string.match(line, "BAT%w+") + if bstr then + batteries[#batteries + 1] = bstr + else + ac = string.match(line, "A%w+") or "AC0" + end + end) + end + + if #batteries == 0 then bat.get_batteries() end bat_notification_critical_preset = { title = "Battery exhausted", @@@ -48,6 -65,14 +65,14 @@@ bg = "#CDCDCD" } + bat_notification_charged_preset = { + title = "Battery full", + text = "You can unplug the cable", + timeout = 15, + fg = "#202020", + bg = "#CDCDCD" + } + bat_now = { status = "N/A", ac_status = "N/A", @@@ -63,6 -88,9 +88,9 @@@ bat_now.n_perc[i] = 0 end + -- used to notify full charge only once before discharging + local fullnotification = false + function bat.update() local sum_rate_current = 0 local sum_rate_voltage = 0 @@@ -70,30 -98,29 +98,29 @@@ local sum_rate_energy = 0 local sum_energy_now = 0 local sum_energy_full = 0 - local pspath = "/sys/class/power_supply/" for i, battery in ipairs(batteries) do local bstr = pspath .. battery - local present = first_line(bstr .. "/present") + local present = helpers.first_line(bstr .. "/present") if tonumber(present) == 1 then -- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW] - local rate_current = tonumber(first_line(bstr .. "/current_now")) - local rate_voltage = tonumber(first_line(bstr .. "/voltage_now")) - local rate_power = tonumber(first_line(bstr .. "/power_now")) + local rate_current = tonumber(helpers.first_line(bstr .. "/current_now")) + local rate_voltage = tonumber(helpers.first_line(bstr .. "/voltage_now")) + local rate_power = tonumber(helpers.first_line(bstr .. "/power_now")) -- energy_now(P)[uWh], charge_now(I)[uAh] - local energy_now = tonumber(first_line(bstr .. "/energy_now") or - first_line(bstr .. "/charge_now")) + local energy_now = tonumber(helpers.first_line(bstr .. "/energy_now") or + helpers.first_line(bstr .. "/charge_now")) -- energy_full(P)[uWh], charge_full(I)[uAh] - local energy_full = tonumber(first_line(bstr .. "/energy_full") or - first_line(bstr .. "/charge_full")) + local energy_full = tonumber(helpers.first_line(bstr .. "/energy_full") or + helpers.first_line(bstr .. "/charge_full")) - local energy_percentage = tonumber(first_line(bstr .. "/capacity")) or + local energy_percentage = tonumber(helpers.first_line(bstr .. "/capacity")) or math.floor((energy_now / energy_full) * 100) - bat_now.n_status[i] = 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] sum_rate_current = sum_rate_current + (rate_current or 0) @@@ -115,7 -142,7 +142,7 @@@ bat_now.status = status end end - bat_now.ac_status = tonumber(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 ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 then @@@ -157,23 -184,32 +184,32 @@@ widget = bat.widget settings() - -- notifications for critical and low levels - if notify == "on" and bat_now.status == "Discharging" then - if tonumber(bat_now.perc) <= n_perc[1] then - bat.id = naughty.notify({ - preset = bat_notification_critical_preset, - replaces_id = bat.id - }).id - elseif tonumber(bat_now.perc) <= n_perc[2] then + -- notifications for critical, low, and full levels + if notify == "on" then + if bat_now.status == "Discharging" then + if tonumber(bat_now.perc) <= n_perc[1] then + bat.id = naughty.notify({ + preset = bat_notification_critical_preset, + replaces_id = bat.id + }).id + elseif tonumber(bat_now.perc) <= n_perc[2] then + bat.id = naughty.notify({ + preset = bat_notification_low_preset, + replaces_id = bat.id + }).id + end + fullnotification = false + elseif bat_now.status == "Full" and full_notify == "on" and not fullnotification then bat.id = naughty.notify({ - preset = bat_notification_low_preset, + preset = bat_notification_charged_preset, replaces_id = bat.id }).id + fullnotification = true end end end - newtimer("batteries", timeout, bat.update) + helpers.newtimer("batteries", timeout, bat.update) return bat end diff --combined .config/awesome/lain/widget/cal.lua index 0000000,928a7bd..928a7bd mode 000000,100644..100644 --- a/.config/awesome/lain/widget/cal.lua +++ b/.config/awesome/lain/widget/cal.lua @@@ -1,0 -1,175 +1,175 @@@ + --[[ + + Licensed under GNU General Public License v2 + * (c) 2018, Luca CPZ + + --]] + + local helpers = require("lain.helpers") + local markup = require("lain.util.markup") + local awful = require("awful") + local naughty = require("naughty") + local floor = math.floor + local os = os + local pairs = pairs + local string = string + local tconcat = table.concat + local type = type + local tonumber = tonumber + local tostring = tostring + + -- Calendar notification + -- lain.widget.cal + + local function factory(args) + args = args or {} + local cal = { + attach_to = args.attach_to or {}, + week_start = args.week_start or 2, + three = args.three or false, + followtag = args.followtag or false, + week_number = args.week_number or "none", + week_number_format = args.week_number_format or args.week_number == "left" and "%3d | " or "| %-3d", + icons = args.icons or helpers.icons_dir .. "cal/white/", + notification_preset = args.notification_preset or { + font = "Monospace 10", fg = "#FFFFFF", bg = "#000000" + } + } + + function cal.get_week_number(m, st_day, x) + return string.format(cal.week_number_format, os.date("%V", m) + (x ~= 0 and floor((x + st_day) / 7) - 1 or 0)) + end + + function cal.sum_week_days(x, y) + return (x + y) % 7 + end + + function cal.build(month, year) + local current_month, current_year = tonumber(os.date("%m")), tonumber(os.date("%Y")) + local is_current_month = (not month or not year) or (month == current_month and year == current_year) + local today = is_current_month and tonumber(os.date("%d")) -- otherwise nil and not highlighted + local t = os.time { year = year or current_year, month = month and month+1 or current_month+1, day = 0 } + local d = os.date("*t", t) + local mth_days, st_day, this_month = d.day, (d.wday-d.day-cal.week_start+1)%7, os.date("%B %Y", t) + local notifytable = { [1] = string.format("%s%s\n", string.rep(" ", floor((28 - this_month:len())/2)), markup.bold(this_month)) } + for x = 0,6 do notifytable[#notifytable+1] = os.date("%a", os.time { year=2006, month=1, day=x+cal.week_start }):sub(1, 3) .. " " end + notifytable[#notifytable] = string.format("%s\n%s", notifytable[#notifytable]:sub(1, -2), string.rep(" ", st_day*4)) + local strx + for x = 1,mth_days do + strx = x + if x == today then + if x < 10 then x = " " .. x end + strx = markup.bold(markup.color(cal.notification_preset.bg, cal.notification_preset.fg, x) .. " ") + end + strx = string.format("%s%s", string.rep(" ", 3 - tostring(x):len()), strx) + notifytable[#notifytable+1] = string.format("%-4s%s", strx, (x+st_day)%7==0 and x ~= mth_days and "\n" or "") + end + if string.len(cal.icons or "") > 0 and today then cal.icon = cal.icons .. today .. ".png" end + cal.month, cal.year = d.month, d.year + + if cal.week_number ~= "none" then + local m = os.time { year = year or current_year, month = month and month or current_month, day = 0 } + local head_prepend = string.rep(" ", tostring(string.format(cal.week_number_format, 0)):len()) + + if cal.week_number == "left" then + notifytable[1] = head_prepend .. notifytable[1] -- month-year row + notifytable[2] = head_prepend .. notifytable[2] -- weekdays row + notifytable[8] = notifytable[8]:gsub("\n", "\n" .. cal.get_week_number(m, st_day, 0)) -- first week of the month + + for x = 10,#notifytable do + if cal.sum_week_days(st_day, x) == 2 then + notifytable[x] = cal.get_week_number(m, st_day, x) .. notifytable[x] + end + end + elseif cal.week_number == "right" then + notifytable[8] = notifytable[8]:gsub("\n", head_prepend .. "\n") -- weekdays row + for x = 9,#notifytable do + if cal.sum_week_days(st_day, x) == 1 then + notifytable[x] = notifytable[x]:gsub("\n", cal.get_week_number(m, st_day, x - 7) .. "\n") + end + end + -- last week of the month + local end_days = cal.sum_week_days(st_day, mth_days) + if end_days ~= 0 then end_days = 7 - end_days end + notifytable[#notifytable] = notifytable[#notifytable] .. string.rep(" ", 4 * end_days) .. cal.get_week_number(m, st_day, mth_days + end_days) + end + end + + return notifytable + end + + function cal.getdate(month, year, offset) + if not month or not year then + month = tonumber(os.date("%m")) + year = tonumber(os.date("%Y")) + end + + month = month + offset + + while month > 12 do + month = month - 12 + year = year + 1 + end + + while month < 1 do + month = month + 12 + year = year - 1 + end + + return month, year + end + + function cal.hide() + if not cal.notification then return end + naughty.destroy(cal.notification) + cal.notification = nil + end + + function cal.show(seconds, month, year, scr) + cal.notification_preset.text = tconcat(cal.build(month, year)) + + if cal.three then + local current_month, current_year = cal.month, cal.year + local prev_month, prev_year = cal.getdate(cal.month, cal.year, -1) + local next_month, next_year = cal.getdate(cal.month, cal.year, 1) + cal.notification_preset.text = string.format("%s\n\n%s\n\n%s", + tconcat(cal.build(prev_month, prev_year)), cal.notification_preset.text, + tconcat(cal.build(next_month, next_year))) + cal.month, cal.year = current_month, current_year + end + + cal.hide() + cal.notification = naughty.notify { + preset = cal.notification_preset, + screen = cal.followtag and awful.screen.focused() or scr or 1, + icon = cal.icon, + timeout = type(seconds) == "number" and seconds or cal.notification_preset.timeout or 5 + } + end + + function cal.hover_on() cal.show(0) end + function cal.move(offset) + local offset = offset or 0 + cal.month, cal.year = cal.getdate(cal.month, cal.year, offset) + cal.show(0, cal.month, cal.year) + end + function cal.prev() cal.move(-1) end + function cal.next() cal.move( 1) end + + function cal.attach(widget) + widget:connect_signal("mouse::enter", cal.hover_on) + widget:connect_signal("mouse::leave", cal.hide) + widget:buttons(awful.util.table.join( + awful.button({}, 1, cal.prev), + awful.button({}, 3, cal.next), + awful.button({}, 2, cal.hover_on), + awful.button({}, 5, cal.prev), + awful.button({}, 4, cal.next))) + end + + for _, widget in pairs(cal.attach_to) do cal.attach(widget) end + + return cal + end + + return factory diff --combined .config/awesome/lain/widget/contrib/init.lua index d7f130e,9e863a5..9e863a5 --- a/.config/awesome/lain/widget/contrib/init.lua +++ b/.config/awesome/lain/widget/contrib/init.lua @@@ -1,14 -1,13 +1,13 @@@ - --[[ - - Lain - Layouts, widgets and utilities for Awesome WM - - Users contributed widgets section - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - + + Lain + Layouts, widgets and utilities for Awesome WM + + Users contributed widgets section + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + --]] local wrequire = require("lain.helpers").wrequire diff --combined .config/awesome/lain/widget/contrib/moc.lua index 83d8aaf,f429c77..f429c77 --- a/.config/awesome/lain/widget/contrib/moc.lua +++ b/.config/awesome/lain/widget/contrib/moc.lua @@@ -1,9 -1,8 +1,8 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2014, anticlockwise - + + Licensed under GNU General Public License v2 + * (c) 2014, anticlockwise + --]] local helpers = require("lain.helpers") @@@ -12,9 -11,8 +11,8 @@@ local focused = require("awful.scr local escape_f = require("awful.util").escape local naughty = require("naughty") local wibox = require("wibox") - local os = { getenv = os.getenv } - local string = { format = string.format, - gmatch = string.gmatch } + local os = os + local string = string -- MOC audio player -- lain.widget.contrib.moc diff --combined .config/awesome/lain/widget/contrib/redshift.lua index 0babb3a,d0e5eed..d0e5eed --- a/.config/awesome/lain/widget/contrib/redshift.lua +++ b/.config/awesome/lain/widget/contrib/redshift.lua @@@ -1,9 -1,9 +1,9 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2014, blueluke - + + Licensed under GNU General Public License v2 + * (c) 2017, Luca CPZ + * (c) 2014, blueluke + --]] local async = require("lain.helpers").async diff --combined .config/awesome/lain/widget/contrib/task.lua index ba79553,536e006..536e006 --- a/.config/awesome/lain/widget/contrib/task.lua +++ b/.config/awesome/lain/widget/contrib/task.lua @@@ -1,16 -1,16 +1,16 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Jan Xie - + + Licensed under GNU General Public License v2 + * (c) 2013, Jan Xie + --]] local helpers = require("lain.helpers") local markup = require("lain.util").markup local awful = require("awful") local naughty = require("naughty") - local string = { format = string.format, gsub = string.gsub } + local mouse = mouse + local string = string -- Taskwarrior notification -- lain.widget.contrib.task @@@ -23,21 -23,30 +23,30 @@@ function task.hide( end function task.show(scr) - task.hide() + task.notification_preset.screen = task.followtag and awful.screen.focused() or scr or 1 - if task.followtag then - task.notification_preset.screen = awful.screen.focused() - elseif scr then - task.notification_preset.screen = scr - end + helpers.async({ awful.util.shell, "-c", task.show_cmd }, function(f) + local widget_focused = true + + if mouse.current_widgets then + widget_focused = false + for _,v in ipairs(mouse.current_widgets) do + if task.widget == v then + widget_focused = true + break + end + end + end - helpers.async(task.show_cmd, function(f) - task.notification = naughty.notify({ - preset = task.notification_preset, - title = task.show_cmd, - text = markup.font(task.notification_preset.font, - awful.util.escape(f:gsub("\n*$", ""))) - }) + if widget_focused then + task.hide() + task.notification = naughty.notify { + preset = task.notification_preset, + title = "task next", + text = markup.font(task.notification_preset.font, + awful.util.escape(f:gsub("\n*$", ""))) + } + end end) end @@@ -49,9 -58,9 +58,9 @@@ function task.prompt( helpers.async(t, function(f) naughty.notify { preset = task.notification_preset, - title = t, - text = markup.font(task.notification_preset.font, - awful.util.escape(f:gsub("\n*$", ""))) + title = t, + text = markup.font(task.notification_preset.font, + awful.util.escape(f:gsub("\n*$", ""))) } end) end, @@@ -65,6 -74,7 +74,7 @@@ function task.attach(widget, args task.prompt_text = args.prompt_text or "Enter task command: " task.followtag = args.followtag or false task.notification_preset = args.notification_preset + task.widget = widget if not task.notification_preset then task.notification_preset = { diff --combined .config/awesome/lain/widget/contrib/tp_smapi.lua index 0000000,b8acbe2..b8acbe2 mode 000000,100644..100644 --- a/.config/awesome/lain/widget/contrib/tp_smapi.lua +++ b/.config/awesome/lain/widget/contrib/tp_smapi.lua @@@ -1,0 -1,147 +1,147 @@@ + --[[ + + Licensed under GNU General Public License v2 + * (c) 2018, Luca CPZ + * (c) 2013, Conor Heine + + --]] + + local helpers = require("lain.helpers") + local focused = require("awful.screen").focused + local gears = require("gears") + local naughty = require("naughty") + local wibox = require("wibox") + local string = string + local type = type + + -- ThinkPad battery infos and widget creator + -- http://www.thinkwiki.org/wiki/Tp_smapi + -- lain.widget.contrib.tp_smapi + + local function factory(apipath) + local tp_smapi = { + path = apipath or "/sys/devices/platform/smapi" + } + + function tp_smapi.get(batid, feature) + return helpers.first_line(string.format("%s/%s/%s", tp_smapi.path, batid or "BAT0", feature or "")) + end + + function tp_smapi.installed(batid) + return tp_smapi.get(batid, "installed") == "1" + end + + function tp_smapi.status(batid) + return tp_smapi.get(batid, "state") + end + + function tp_smapi.percentage(batid) + return tp_smapi.get(batid, "remaining_percent") + end + + -- either running or charging time + function tp_smapi.time(batid) + local status = tp_smapi.status(batid) + local mins_left = tp_smapi.get(batid, string.match(string.lower(status), "discharging") and "remaining_running_time" or "remaining_charging_time") + if not string.find(mins_left, "^%d+") then return "N/A" end + return string.format("%02d:%02d", math.floor(mins_left / 60), mins_left % 60) -- HH:mm + end + + function tp_smapi.hide() + if not tp_smapi.notification then return end + naughty.destroy(tp_smapi.notification) + tp_smapi.notification = nil + end + + function tp_smapi.show(batid, seconds, scr) + if not tp_smapi.installed(batid) then return end + + local mfgr = tp_smapi.get(batid, "manufacturer") or "no_mfgr" + local model = tp_smapi.get(batid, "model") or "no_model" + local chem = tp_smapi.get(batid, "chemistry") or "no_chem" + local status = tp_smapi.get(batid, "state") + local time = tp_smapi.time(batid) + local msg = "" + + if status and status ~= "idle" then + msg = string.format("[%s] %s %s", status, time ~= "N/A" and time or "unknown remaining time", + string.lower(status):gsub(" ", ""):gsub("\n", "") == "charging" and " until charged" or " remaining") + else + msg = "On AC power" + end + + tp_smapi.hide() + tp_smapi.notification = naughty.notify { + title = string.format("%s: %s %s (%s)", batid, mfgr, model, chem), + text = msg, + timeout = type(seconds) == "number" and seconds or 0, + screen = scr or focused() + } + end + + function tp_smapi.create_widget(args) + local args = args or {} + local pspath = args.pspath or "/sys/class/power_supply/" + local batteries = args.batteries or (args.battery and {args.battery}) or {} + local timeout = args.timeout or 30 + local settings = args.settings or function() end + + if #batteries == 0 then + helpers.line_callback("ls -1 " .. pspath, function(line) + local bstr = string.match(line, "BAT%w+") + if bstr then batteries[#batteries + 1] = bstr end + end) + end + + local all_batteries_installed = true + + for i, battery in ipairs(batteries) do + if not tp_smapi.installed(battery) then + naughty.notify { + preset = naughty.config.critical, + title = "tp_smapi: error while creating widget", + text = string.format("battery %s is not installed", battery) + } + all_batteries_installed = false + break + end + end + + if not all_batteries_installed then return end + + tpbat = { + batteries = batteries, + widget = args.widget or wibox.widget.textbox() + } + + function tpbat.update() + tpbat_now = { + n_status = {}, + n_perc = {}, + n_time = {}, + status = "N/A" + } + + for i = 1, #batteries do + tpbat_now.n_status[i] = tp_smapi.status(batteries[i]) or "N/A" + tpbat_now.n_perc[i] = tp_smapi.percentage(batteries[i]) + tpbat_now.n_time[i] = tp_smapi.time(batteries[i]) or "N/A" + + if not tpbat_now.n_status[i]:lower():match("full") then + tpbat_now.status = tpbat_now.n_status[i] + end + end + + widget = tpbat.widget -- backwards compatibility + settings() + end + + helpers.newtimer("thinkpad-batteries", timeout, tpbat.update) + + return tpbat + end + + return tp_smapi + end + + return factory diff --combined .config/awesome/lain/widget/cpu.lua index 9a5a964,f4cce73..f4cce73 --- a/.config/awesome/lain/widget/cpu.lua +++ b/.config/awesome/lain/widget/cpu.lua @@@ -1,17 -1,15 +1,15 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local helpers = require("lain.helpers") local wibox = require("wibox") - local math = { ceil = math.ceil } - local string = { format = string.format, - gmatch = string.gmatch } + local math = math + local string = string local tostring = tostring -- CPU usage @@@ -27,9 -25,7 +25,7 @@@ local function factory(args -- Read the amount of time the CPUs have spent performing -- different kinds of work. Read the first line of /proc/stat -- which is the sum of all CPUs. - local times = helpers.lines_match("cpu","/proc/stat") - - for index,time in pairs(times) do + for index,time in pairs(helpers.lines_match("cpu","/proc/stat")) do local coreid = index - 1 local core = cpu.core[coreid] or { last_active = 0 , last_total = 0, usage = 0 } diff --combined .config/awesome/lain/widget/fs.lua index 473bd33,58fbf93..58fbf93 --- a/.config/awesome/lain/widget/fs.lua +++ b/.config/awesome/lain/widget/fs.lua @@@ -1,24 -1,39 +1,39 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - - --]] - local helpers = require("lain.helpers") - local shell = require("awful.util").shell - local focused = require("awful.screen").focused - local wibox = require("wibox") - local naughty = require("naughty") - local string = string - local tonumber = tonumber + Licensed under GNU General Public License v2 + * (c) 2018, Uli Schlacter + * (c) 2018, Otto Modinos + * (c) 2013, Luca CPZ + + --]] - -- File system disk space usage + local helpers = require("lain.helpers") + local Gio = require("lgi").Gio + local focused = require("awful.screen").focused + local wibox = require("wibox") + local naughty = require("naughty") + local math = math + local string = string + local tconcat = table.concat + local type = type + local tonumber = tonumber + local query_size = Gio.FILE_ATTRIBUTE_FILESYSTEM_SIZE + local query_free = Gio.FILE_ATTRIBUTE_FILESYSTEM_FREE + local query_used = Gio.FILE_ATTRIBUTE_FILESYSTEM_USED + local query = query_size .. "," .. query_free .. "," .. query_used + + -- File systems info -- lain.widget.fs local function factory(args) - local fs = { unit = { ["mb"] = 1024, ["gb"] = 1024^2 }, widget = wibox.widget.textbox() } + local fs = { + widget = wibox.widget.textbox(), + units = { + [1] = "Kb", [2] = "Mb", [3] = "Gb", + [4] = "Tb", [5] = "Pb", [6] = "Eb", + [7] = "Zb", [8] = "Yb" + } + } function fs.hide() if not fs.notification then return end @@@ -27,29 -42,21 +42,21 @@@ end function fs.show(seconds, scr) - fs.update() - fs.hide() - - if fs.followtag then - fs.notification_preset.screen = focused() - else - fs.notification_preset.screen = scr or 1 - end - - fs.notification = naughty.notify({ + fs.hide(); fs.update() + fs.notification_preset.screen = fs.followtag and focused() or scr or 1 + fs.notification = naughty.notify { preset = fs.notification_preset, - timeout = seconds or 5 - }) + timeout = type(seconds) == "number" and seconds or 5 + } end - local args = args or {} - local timeout = args.timeout or 600 - local partition = args.partition or "/" - local showpopup = args.showpopup or "on" - local notify = args.notify or "on" - local settings = args.settings or function() end + local args = args or {} + local timeout = args.timeout or 600 + local partition = args.partition + local threshold = args.threshold or 99 + local showpopup = args.showpopup or "on" + local settings = args.settings or function() end - fs.options = args.options fs.followtag = args.followtag or false fs.notification_preset = args.notification_preset @@@ -61,54 -68,74 +68,74 @@@ } end - helpers.set_map(partition, false) - function fs.update() - fs_info, fs_now = {}, {} - helpers.async({ shell, "-c", "/usr/bin/env LC_ALL=C df -k --output=target,size,used,avail,pcent" }, function(f) - for line in string.gmatch(f, "\n[^\n]+") do - local m,s,u,a,p = string.match(line, "(/.-%s).-(%d+).-(%d+).-(%d+).-([%d]+)%%") - m = m:gsub(" ", "") -- clean target from any whitespace - - fs_info[m .. " size_mb"] = string.format("%.1f", tonumber(s) / fs.unit["mb"]) - fs_info[m .. " size_gb"] = string.format("%.1f", tonumber(s) / fs.unit["gb"]) - fs_info[m .. " used_mb"] = string.format("%.1f", tonumber(u) / fs.unit["mb"]) - fs_info[m .. " used_gb"] = string.format("%.1f", tonumber(u) / fs.unit["gb"]) - fs_info[m .. " used_p"] = p - fs_info[m .. " avail_mb"] = string.format("%.1f", tonumber(a) / fs.unit["mb"]) - fs_info[m .. " avail_gb"] = string.format("%.1f", tonumber(a) / fs.unit["gb"]) - fs_info[m .. " avail_p"] = string.format("%d", 100 - tonumber(p)) + local notifytable = { [1] = string.format("%-10s %4s\t%6s\t%6s\t\n", "path", "used", "free", "size") } + local pathlen = 10 + local maxpathidx = 1 + fs_now = {} + + for _, mount in ipairs(Gio.unix_mounts_get()) do + local path = Gio.unix_mount_get_mount_path(mount) + local root = Gio.File.new_for_path(path) + local info = root:query_filesystem_info(query) + + if info then + local size = info:get_attribute_uint64(query_size) + local used = info:get_attribute_uint64(query_used) + local free = info:get_attribute_uint64(query_free) + + if size > 0 then + local units = math.floor(math.log(size)/math.log(1024)) + + fs_now[path] = { + units = fs.units[units], + percentage = math.floor(100 * used / size), -- used percentage + size = size / math.pow(1024, math.floor(units)), + used = used / math.pow(1024, math.floor(units)), + free = free / math.pow(1024, math.floor(units)) + } + + if fs_now[path].percentage > 0 then -- don't notify unused file systems + notifytable[#notifytable+1] = string.format("\n%-10s %3s%%\t%6.2f\t%6.2f\t%s", path, + math.floor(fs_now[path].percentage), fs_now[path].free, fs_now[path].size, + fs_now[path].units) + + if #path > pathlen then + pathlen = #path + maxpathidx = #notifytable + end + end + end end + end + + widget = fs.widget + settings() - fs_now.size_mb = fs_info[partition .. " size_mb"] or "N/A" - fs_now.size_gb = fs_info[partition .. " size_gb"] or "N/A" - fs_now.used = fs_info[partition .. " used_p"] or "N/A" - fs_now.used_mb = fs_info[partition .. " used_mb"] or "N/A" - fs_now.used_gb = fs_info[partition .. " used_gb"] or "N/A" - fs_now.available = fs_info[partition .. " avail_p"] or "N/A" - fs_now.available_mb = fs_info[partition .. " avail_mb"] or "N/A" - fs_now.available_gb = fs_info[partition .. " avail_gb"] or "N/A" - - notification_preset = fs.notification_preset - widget = fs.widget - settings() - - if notify == "on" and #fs_now.used > 0 and tonumber(fs_now.used) >= 99 and not helpers.get_map(partition) then - naughty.notify({ + if partition and fs_now[partition] and fs_now[partition].percentage >= threshold then + if not helpers.get_map(partition) then + naughty.notify { preset = naughty.config.presets.critical, title = "Warning", - text = partition .. " is full", - }) + text = string.format("%s is above %d%% (%d%%)", partition, threshold, fs_now[partition].percentage) + } helpers.set_map(partition, true) else helpers.set_map(partition, false) end - end) + end + + if pathlen > 10 then -- if are there paths longer than 10 chars, reformat first column accordingly + local pathspaces + for i = 1, #notifytable do + pathspaces = notifytable[i]:match("[ ]+") + if i ~= maxpathidx and pathspaces then + notifytable[i] = notifytable[i]:gsub(pathspaces, pathspaces .. string.rep(" ", pathlen - 10)) + end + end + end - local notifycmd = (fs.options and string.format("dfs %s", fs.options)) or "dfs" - helpers.async(helpers.scripts_dir .. notifycmd, function(ws) - fs.notification_preset.text = ws:gsub("\n*$", "") - end) + fs.notification_preset.text = tconcat(notifytable) end if showpopup == "on" then @@@ -116,7 -143,7 +143,7 @@@ fs.widget:connect_signal('mouse::leave', function () fs.hide() end) end - helpers.newtimer(partition, timeout, fs.update) + helpers.newtimer(partition or "fs", timeout, fs.update) return fs end diff --combined .config/awesome/lain/widget/imap.lua index 0f7fde5,b3d9dc7..b3d9dc7 --- a/.config/awesome/lain/widget/imap.lua +++ b/.config/awesome/lain/widget/imap.lua @@@ -1,16 -1,15 +1,15 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + --]] local helpers = require("lain.helpers") local naughty = require("naughty") local wibox = require("wibox") - local string = { format = string.format, - gsub = string.gsub } + local awful = require("awful") + local string = string local type = type local tonumber = tonumber @@@ -18,67 -17,75 +17,75 @@@ -- lain.widget.imap local function factory(args) - local imap = { widget = wibox.widget.textbox() } - local args = args or {} - local server = args.server - local mail = args.mail - local password = args.password - local port = args.port or 993 - local timeout = args.timeout or 60 - local is_plain = args.is_plain or false - local followtag = args.followtag or false - local settings = args.settings or function() end + local imap = { widget = wibox.widget.textbox() } + local args = args or {} + local server = args.server + local mail = args.mail + local password = args.password + local port = args.port or 993 + local timeout = args.timeout or 60 + local pwdtimeout = args.pwdtimeout or 10 + local is_plain = args.is_plain or false + local followtag = args.followtag or false + local notify = args.notify or "on" + local settings = args.settings or function() end local head_command = "curl --connect-timeout 3 -fsm 3" - local request = "-X 'SEARCH (UNSEEN)'" + local request = "-X 'STATUS INBOX (MESSAGES RECENT UNSEEN)'" if not server or not mail or not password then return end + mail_notification_preset = { + icon = helpers.icons_dir .. "mail.png", + position = "top_left" + } + helpers.set_map(mail, 0) if not is_plain then if type(password) == "string" or type(password) == "table" then helpers.async(password, function(f) password = f:gsub("\n", "") end) elseif type(password) == "function" then - local p = password() + imap.pwdtimer = helpers.newtimer(mail .. "-password", pwdtimeout, function() + local retrieved_password, try_again = password() + if not try_again then + imap.pwdtimer:stop() -- stop trying to retrieve + password = retrieved_password or "" -- failsafe + end + end, true, true) end end - function update() - mail_notification_preset = { - icon = helpers.icons_dir .. "mail.png", - position = "top_left" - } + function imap.update() + -- do not update if the password has not been retrieved yet + if type(password) ~= "string" then return end - if followtag then - mail_notification_preset.screen = awful.screen.focused() - end - - curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:%q %s -k", - head_command, server, port, mail, password, request) + local curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:'%s' %s -k", + head_command, server, port, mail, password, request) helpers.async(curl, function(f) - _, mailcount = string.gsub(f, "%d+", "") - _ = nil + imap_now = { ["MESSAGES"] = 0, ["RECENT"] = 0, ["UNSEEN"] = 0 } + for s,d in f:gmatch("(%w+)%s+(%d+)") do imap_now[s] = tonumber(d) end + mailcount = imap_now["UNSEEN"] -- backwards compatibility widget = imap.widget + settings() - if mailcount >= 1 and mailcount > helpers.get_map(mail) then - if mailcount == 1 then - nt = mail .. " has one new message" - else - nt = mail .. " has " .. mailcount .. " new messages" - end - naughty.notify({ preset = mail_notification_preset, text = nt }) + if notify == "on" and mailcount and mailcount >= 1 and mailcount > helpers.get_map(mail) then + if followtag then mail_notification_preset.screen = awful.screen.focused() end + naughty.notify { + preset = mail_notification_preset, + text = string.format("%s has %d new message%s", mail, mailcount, mailcount == 1 and "" or "s") + } end - helpers.set_map(mail, mailcount) + helpers.set_map(mail, imap_now["UNSEEN"]) end) end - imap.timer = helpers.newtimer(mail, timeout, update, true, true) + imap.timer = helpers.newtimer(mail, timeout, imap.update, true, true) return imap end diff --combined .config/awesome/lain/widget/init.lua index f77f872,57b86bb..57b86bb --- a/.config/awesome/lain/widget/init.lua +++ b/.config/awesome/lain/widget/init.lua @@@ -1,15 -1,14 +1,14 @@@ - --[[ - - Lain - Layouts, widgets and utilities for Awesome WM - - Widgets section - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Lain + Layouts, widgets and utilities for Awesome WM + + Widgets section + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local wrequire = require("lain.helpers").wrequire diff --combined .config/awesome/lain/widget/mem.lua index 50fff3b,3dcae2b..3dcae2b --- a/.config/awesome/lain/widget/mem.lua +++ b/.config/awesome/lain/widget/mem.lua @@@ -1,10 -1,9 +1,9 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local helpers = require("lain.helpers") diff --combined .config/awesome/lain/widget/mpd.lua index d0b37d7,01f28e6..01f28e6 --- a/.config/awesome/lain/widget/mpd.lua +++ b/.config/awesome/lain/widget/mpd.lua @@@ -1,22 -1,19 +1,19 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010, Adrian C. - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010, Adrian C. + --]] - local helpers = require("lain.helpers") - local shell = require("awful.util").shell - local escape_f = require("awful.util").escape - local focused = require("awful.screen").focused - local naughty = require("naughty") - local wibox = require("wibox") - local os = { getenv = os.getenv } - local string = { format = string.format, - gmatch = string.gmatch, - match = string.match } + local helpers = require("lain.helpers") + local shell = require("awful.util").shell + local escape_f = require("awful.util").escape + local focused = require("awful.screen").focused + local naughty = require("naughty") + local wibox = require("wibox") + local os = os + local string = string -- MPD infos -- lain.widget.mpd @@@ -26,8 -23,8 +23,8 @@@ local function factory(args local args = args or {} local timeout = args.timeout or 2 local password = (args.password and #args.password > 0 and string.format("password %s\\n", args.password)) or "" - local host = args.host or "127.0.0.1" - local port = args.port or "6600" + local host = args.host or os.getenv("MPD_HOST") or "127.0.0.1" + local port = args.port or os.getenv("MPD_PORT") or "6600" local music_dir = args.music_dir or os.getenv("HOME") .. "/Music" local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$" local cover_size = args.cover_size or 100 diff --combined .config/awesome/lain/widget/net.lua index f42ec25,805b577..805b577 --- a/.config/awesome/lain/widget/net.lua +++ b/.config/awesome/lain/widget/net.lua @@@ -1,37 -1,37 +1,37 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local helpers = require("lain.helpers") local naughty = require("naughty") local wibox = require("wibox") - local string = { format = string.format, match = string.match } + local string = string -- Network infos -- lain.widget.net local function factory(args) - local net = { widget = wibox.widget.textbox(), devices = {} } - local args = args or {} - local timeout = args.timeout or 2 - local units = args.units or 1024 -- KB - local notify = args.notify or "on" - local screen = args.screen or 1 - local settings = args.settings or function() end + local net = { widget = wibox.widget.textbox(), devices = {} } + local args = args or {} + local timeout = args.timeout or 2 + local units = args.units or 1024 -- KB + local notify = args.notify or "on" + local wifi_state = args.wifi_state or "off" + local eth_state = args.eth_state or "off" + local screen = args.screen or 1 + local settings = args.settings or function() end -- Compatibility with old API where iface was a string corresponding to 1 interface net.iface = (args.iface and (type(args.iface) == "string" and {args.iface}) or (type(args.iface) == "table" and args.iface)) or {} function net.get_device() - helpers.async(string.format("ip link show", device_cmd), function(ws) - ws = ws:match("(%w+): ") - net.iface = ws and { ws } or {} + helpers.line_callback("ip link", function(line) + net.iface[#net.iface + 1] = not string.match(line, "LOOPBACK") and string.match(line, "(%w+): <") or nil end) end @@@ -46,7 -46,7 +46,7 @@@ received = 0 } - for i, dev in ipairs(net.iface) do + for _, dev in ipairs(net.iface) do local dev_now = {} local dev_before = net.devices[dev] or { last_t = 0, last_r = 0 } local now_t = tonumber(helpers.first_line(string.format("/sys/class/net/%s/statistics/tx_bytes", dev)) or 0) @@@ -67,9 -67,18 +67,18 @@@ dev_now.last_t = now_t dev_now.last_r = now_r + if wifi_state == "on" and helpers.first_line(string.format("/sys/class/net/%s/uevent", dev)) == "DEVTYPE=wlan" and string.match(dev_now.carrier, "1") then + dev_now.wifi = true + dev_now.signal = tonumber(string.match(helpers.lines_from("/proc/net/wireless")[3], "(%-%d+%.)")) or nil + end + + if eth_state == "on" and helpers.first_line(string.format("/sys/class/net/%s/uevent", dev)) ~= "DEVTYPE=wlan" and string.match(dev_now.carrier, "1") then + dev_now.ethernet = true + end + net.devices[dev] = dev_now - -- Notify only once when connection is loss + -- Notify only once when connection is lost if string.match(dev_now.carrier, "0") and notify == "on" and helpers.get_map(dev) then naughty.notify { title = dev, @@@ -85,7 -94,7 +94,7 @@@ net_now.carrier = dev_now.carrier net_now.state = dev_now.state net_now.devices[dev] = dev_now - -- new_now.sent and net_now.received will be + -- net_now.sent and net_now.received will be -- the totals across all specified devices end diff --combined .config/awesome/lain/widget/pulse.lua index 0000000,f63fe55..f63fe55 mode 000000,100644..100644 --- a/.config/awesome/lain/widget/pulse.lua +++ b/.config/awesome/lain/widget/pulse.lua @@@ -1,0 -1,57 +1,57 @@@ + --[[ + + Licensed under GNU General Public License v2 + * (c) 2016, Luca CPZ + + --]] + + local helpers = require("lain.helpers") + local shell = require("awful.util").shell + local wibox = require("wibox") + local string = string + local type = type + + -- PulseAudio volume + -- lain.widget.pulse + + local function factory(args) + local pulse = { widget = wibox.widget.textbox(), device = "N/A" } + local args = args or {} + local timeout = args.timeout or 5 + local settings = args.settings or function() end + + pulse.devicetype = args.devicetype or "sink" + pulse.cmd = args.cmd or "pacmd list-" .. pulse.devicetype .. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'" + + function pulse.update() + helpers.async({ shell, "-c", type(pulse.cmd) == "string" and pulse.cmd or pulse.cmd() }, + function(s) + volume_now = { + index = string.match(s, "index: (%S+)") or "N/A", + device = string.match(s, "device.string = \"(%S+)\"") or "N/A", + muted = string.match(s, "muted: (%S+)") or "N/A" + } + + pulse.device = volume_now.index + + local ch = 1 + volume_now.channel = {} + for v in string.gmatch(s, ":.-(%d+)%%") do + volume_now.channel[ch] = v + ch = ch + 1 + end + + volume_now.left = volume_now.channel[1] or "N/A" + volume_now.right = volume_now.channel[2] or "N/A" + + widget = pulse.widget + settings() + end) + end + + helpers.newtimer("pulse", timeout, pulse.update) + + return pulse + end + + return factory diff --combined .config/awesome/lain/widget/pulsebar.lua index 41a8ce3,51290f8..51290f8 --- a/.config/awesome/lain/widget/pulsebar.lua +++ b/.config/awesome/lain/widget/pulsebar.lua @@@ -1,24 -1,21 +1,21 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2013, Rman - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2013, Rman + --]] - local helpers = require("lain.helpers") - local awful = require("awful") - local naughty = require("naughty") - local wibox = require("wibox") - local math = { modf = math.modf } - local string = { format = string.format, - match = string.match, - gmatch = string.gmatch, - rep = string.rep } - local type, tonumber = type, tonumber - - -- Pulseaudio volume bar + local helpers = require("lain.helpers") + local awful = require("awful") + local naughty = require("naughty") + local wibox = require("wibox") + local math = math + local string = string + local type = type + local tonumber = tonumber + + -- PulseAudio volume bar -- lain.widget.pulsebar local function factory(args) @@@ -30,37 -27,43 +27,43 @@@ }, _current_level = 0, - _muted = false + _mute = "no", + device = "N/A" } local args = args or {} local timeout = args.timeout or 5 local settings = args.settings or function() end local width = args.width or 63 - local height = args.heigth or 1 + local height = args.height or 1 + local margins = args.margins or 1 + local paddings = args.paddings or 1 local ticks = args.ticks or false local ticks_size = args.ticks_size or 7 - local scallback = args.scallback + local tick = args.tick or "|" + local tick_pre = args.tick_pre or "[" + local tick_post = args.tick_post or "]" + local tick_none = args.tick_none or " " - pulsebar.cmd = args.cmd or "pacmd list-sinks | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'" - pulsebar.sink = args.sink or 0 - pulsebar.colors = args.colors or pulsebar.colors - pulsebar.followtag = args.followtag or false - pulsebar.notifications = args.notification_preset - pulsebar.device = "N/A" + pulsebar.colors = args.colors or pulsebar.colors + pulsebar.followtag = args.followtag or false + pulsebar.notification_preset = args.notification_preset + pulsebar.devicetype = args.devicetype or "sink" + pulsebar.cmd = args.cmd or "pacmd list-" .. pulsebar.devicetype .. "s | sed -n -e '/*/,$!d' -e '/index/p' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'" if not pulsebar.notification_preset then - pulsebar.notification_preset = {} - pulsebar.notification_preset.font = "Monospace 10" + pulsebar.notification_preset = { + font = "Monospace 10" + } end pulsebar.bar = wibox.widget { - forced_height = height, - forced_width = width, color = pulsebar.colors.unmute, background_color = pulsebar.colors.background, - margins = 1, - paddings = 1, + forced_height = height, + forced_width = width, + margins = margins, + paddings = paddings, ticks = ticks, ticks_size = ticks_size, widget = wibox.widget.progressbar, @@@ -69,13 -72,12 +72,12 @@@ pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } }) function pulsebar.update(callback) - if scallback then pulsebar.cmd = scallback() end - - helpers.async({ awful.util.shell, "-c", pulsebar.cmd }, function(s) + helpers.async({ awful.util.shell, "-c", type(pulsebar.cmd) == "string" and pulsebar.cmd or pulsebar.cmd() }, + function(s) volume_now = { - index = string.match(s, "index: (%S+)") or "N/A", - sink = string.match(s, "device.string = \"(%S+)\"") or "N/A", - muted = string.match(s, "muted: (%S+)") or "N/A" + index = string.match(s, "index: (%S+)") or "N/A", + device = string.match(s, "device.string = \"(%S+)\"") or "N/A", + muted = string.match(s, "muted: (%S+)") or "N/A" } pulsebar.device = volume_now.index @@@ -93,16 -95,18 +95,18 @@@ local volu = volume_now.left local mute = volume_now.muted - if (volu and volu ~= pulsebar._current_level) or (mute and mute ~= pulsebar._muted) then - pulsebar._current_level = volu + if volu:match("N/A") or mute:match("N/A") then return end + + if volu ~= pulsebar._current_level or mute ~= pulsebar._mute then + pulsebar._current_level = tonumber(volu) pulsebar.bar:set_value(pulsebar._current_level / 100) - if (not mute and volu == 0) or mute == "yes" then - pulsebar._muted = true - pulsebar.tooltip:set_text ("[Muted]") + if pulsebar._current_level == 0 or mute == "yes" then + pulsebar._mute = mute + pulsebar.tooltip:set_text ("[muted]") pulsebar.bar.color = pulsebar.colors.mute else - pulsebar._muted = false - pulsebar.tooltip:set_text(string.format("%s: %s", pulsebar.sink, volu)) + pulsebar._mute = "no" + pulsebar.tooltip:set_text(string.format("%s %s: %s", pulsebar.devicetype, pulsebar.device, volu)) pulsebar.bar.color = pulsebar.colors.unmute end @@@ -117,15 -121,34 +121,34 @@@ pulsebar.update(function() local preset = pulsebar.notification_preset - if pulsebar._muted then - preset.title = string.format("Sink %s - Muted", pulsebar.sink) - else - preset.title = string.format("%s - %s%%", pulsebar.sink, pulsebar._current_level) + preset.title = string.format("%s %s - %s%%", pulsebar.devicetype, pulsebar.device, pulsebar._current_level) + + if pulsebar._mute == "yes" then + preset.title = preset.title .. " muted" + end + + -- tot is the maximum number of ticks to display in the notification + -- fallback: default horizontal wibox height + local wib, tot = awful.screen.focused().mywibox, 20 + + -- if we can grab mywibox, tot is defined as its height if + -- horizontal, or width otherwise + if wib then + if wib.position == "left" or wib.position == "right" then + tot = wib.width + else + tot = wib.height + end end - int = math.modf((pulsebar._current_level / 100) * awful.screen.focused().mywibox.height) - preset.text = string.format("[%s%s]", string.rep("|", int), - string.rep(" ", awful.screen.focused().mywibox.height - int)) + int = math.modf((pulsebar._current_level / 100) * tot) + preset.text = string.format( + "%s%s%s%s", + tick_pre, + string.rep(tick, int), + string.rep(tick_none, tot - int), + tick_post + ) if pulsebar.followtag then preset.screen = awful.screen.focused() end @@@ -140,7 -163,7 +163,7 @@@ end) end - helpers.newtimer(string.format("pulsebar-%s", pulsebar.sink), timeout, pulsebar.update) + helpers.newtimer(string.format("pulsebar-%s-%s", pulsebar.devicetype, pulsebar.device), timeout, pulsebar.update) return pulsebar end diff --combined .config/awesome/lain/widget/sysload.lua index d358687,adf3e03..adf3e03 --- a/.config/awesome/lain/widget/sysload.lua +++ b/.config/awesome/lain/widget/sysload.lua @@@ -1,10 -1,9 +1,9 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - * (c) 2010-2012, Peter Hofmann - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + * (c) 2010-2012, Peter Hofmann + --]] local helpers = require("lain.helpers") diff --combined .config/awesome/lain/widget/temp.lua index efe2ab9,e909b32..e909b32 --- a/.config/awesome/lain/widget/temp.lua +++ b/.config/awesome/lain/widget/temp.lua @@@ -1,40 -1,42 +1,42 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2013, Luke Bonham - + + Licensed under GNU General Public License v2 + * (c) 2013, Luca CPZ + --]] local helpers = require("lain.helpers") local wibox = require("wibox") - local open = io.open local tonumber = tonumber - -- coretemp + -- {thermal,core} temperature info -- lain.widget.temp local function factory(args) local temp = { widget = wibox.widget.textbox() } local args = args or {} - local timeout = args.timeout or 2 - local tempfile = args.tempfile or "/sys/class/thermal/thermal_zone0/temp" + local timeout = args.timeout or 30 + local tempfile = args.tempfile or "/sys/devices/virtual/thermal/thermal_zone0/temp" local settings = args.settings or function() end function temp.update() - local f = open(tempfile) - if f then - coretemp_now = tonumber(f:read("*all")) / 1000 - f:close() - else - coretemp_now = "N/A" - end - - widget = temp.widget - settings() + helpers.async({"find", "/sys/devices", "-type", "f", "-name", "*temp*"}, function(f) + temp_now = {} + local temp_fl, temp_value + for t in f:gmatch("[^\n]+") do + temp_fl = helpers.first_line(t) + if temp_fl then + temp_value = tonumber(temp_fl) + temp_now[t] = temp_value and temp_value/1e3 or temp_fl + end + end + coretemp_now = temp_now[tempfile] or "N/A" + widget = temp.widget + settings() + end) end - helpers.newtimer("coretemp", timeout, temp.update) + helpers.newtimer("thermal", timeout, temp.update) return temp end diff --combined .config/awesome/lain/widget/weather.lua index 1098146,9c1e797..9c1e797 --- a/.config/awesome/lain/widget/weather.lua +++ b/.config/awesome/lain/widget/weather.lua @@@ -1,9 -1,8 +1,8 @@@ - --[[ - - Licensed under GNU General Public License v2 - * (c) 2015, Luke Bonham - + + Licensed under GNU General Public License v2 + * (c) 2015, Luca CPZ + --]] local helpers = require("lain.helpers") @@@ -11,12 -10,10 +10,10 @@@ local json = require("lain.util").d local focused = require("awful.screen").focused local naughty = require("naughty") local wibox = require("wibox") - local math = { floor = math.floor } - local os = { time = os.time, - date = os.date, - difftime = os.difftime } - local string = { format = string.format, - gsub = string.gsub } + local math = math + local os = os + local string = string + local type = type local tonumber = tonumber -- OpenWeatherMap @@@ -26,17 -23,12 +23,12 @@@ local function factory(args) local weather = { widget = wibox.widget.textbox() } local args = args or {} - local APPID = args.APPID or "3e321f9414eaedbfab34983bda77a66e" -- lain default - local timeout = args.timeout or 900 -- 15 min - local timeout_forecast = args.timeout or 86400 -- 24 hrs + local APPID = args.APPID or "3e321f9414eaedbfab34983bda77a66e" -- lain's default + local timeout = args.timeout or 60 * 15 -- 15 min + local timeout_forecast = args.timeout or 60 * 60 * 24 -- 24 hrs local current_call = args.current_call or "curl -s 'http://api.openweathermap.org/data/2.5/weather?id=%s&units=%s&lang=%s&APPID=%s'" local forecast_call = args.forecast_call or "curl -s 'http://api.openweathermap.org/data/2.5/forecast/daily?id=%s&units=%s&lang=%s&cnt=%s&APPID=%s'" local city_id = args.city_id or 0 -- placeholder - local utc_offset = args.utc_offset or - function () - local now = os.time() - return os.difftime(now, os.time(os.date("!*t", now))) + ((os.date("*t").isdst and 1 or 0) * 3600) - end local units = args.units or "metric" local lang = args.lang or "en" local cnt = args.cnt or 5 @@@ -53,13 -45,14 +45,14 @@@ end local weather_na_markup = args.weather_na_markup or " N/A " local followtag = args.followtag or false + local showpopup = args.showpopup or "on" local settings = args.settings or function() end weather.widget:set_markup(weather_na_markup) weather.icon_path = icons_path .. "na.png" weather.icon = wibox.widget.imagebox(weather.icon_path) - function weather.show(t_out) + function weather.show(seconds) weather.hide() if followtag then @@@ -71,12 -64,12 +64,12 @@@ weather.forecast_update() end - weather.notification = naughty.notify({ + weather.notification = naughty.notify { + preset = notification_preset, text = weather.notification_text, icon = weather.icon_path, - timeout = t_out, - preset = notification_preset - }) + timeout = type(seconds == "number") and seconds or notification_preset.timeout + } end function weather.hide() @@@ -102,11 -95,10 +95,10 @@@ weather_now, pos, err = json.decode(f, 1, nil) 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"] do weather.notification_text = weather.notification_text .. notification_text_fun(weather_now["list"][i]) - if i < weather_now["cnt"] then weather.notification_text = weather.notification_text .. "\n" end @@@ -122,29 -114,12 +114,12 @@@ weather_now, pos, err = json.decode(f, 1, nil) if not err and type(weather_now) == "table" and tonumber(weather_now["cod"]) == 200 then - -- weather icon based on localtime - local now = os.time() local sunrise = tonumber(weather_now["sys"]["sunrise"]) local sunset = tonumber(weather_now["sys"]["sunset"]) local icon = weather_now["weather"][1]["icon"] - local loc_m = os.time { year = os.date("%Y"), month = os.date("%m"), day = os.date("%d"), hour = 0 } - local offset = utc_offset() - local utc_m = loc_m - offset - - if offset > 0 and (now - utc_m)>=86400 then - utc_m = utc_m + 86400 - elseif offset < 0 and (utc_m - now)>=86400 then - utc_m = utc_m - 86400 - end - - -- if we are 1 day after the GMT, return 1 day back, and viceversa - if offset > 0 and loc_m >= utc_m then - now = now - 86400 - elseif offset < 0 and loc_m <= utc_m then - now = now + 86400 - end + local loc_now = os.time() - if sunrise <= now and now <= sunset then + if sunrise <= loc_now and loc_now <= sunset then icon = string.gsub(icon, "n", "d") else icon = string.gsub(icon, "d", "n") @@@ -162,7 -137,7 +137,7 @@@ end) end - weather.attach(weather.widget) + if showpopup == "on" then weather.attach(weather.widget) end weather.timer = helpers.newtimer("weather-" .. city_id, timeout, weather.update, false, true) weather.timer_forecast = helpers.newtimer("weather_forecast-" .. city_id, timeout, weather.forecast_update, false, true) diff --combined .config/awesome/lain/wiki index d6cf027,2899629..2899629 --- a/.config/awesome/lain/wiki +++ b/.config/awesome/lain/wiki @@@ -1,1 -1,1 +1,1 @@@ - Subproject commit d6cf027a4c2535c179a8112137d065a5bc740fea + Subproject commit 2899629c445cb12efb72cc538e36cfc2ec812201