|
@ -0,0 +1,7 @@
|
||||||
|
**Please read the [wiki](https://github.com/copycat-killer/lain/wiki) and search the [Issues section](https://github.com/copycat-killer/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
|
17
README.rst
|
@ -1,19 +1,24 @@
|
||||||
Lain
|
Lain
|
||||||
====
|
====
|
||||||
|
|
||||||
--------------------------------------------------
|
-------------------------------------------------
|
||||||
Layouts, widgets and utilities for Awesome WM 3.5+
|
Layouts, widgets and utilities for Awesome WM 4.x
|
||||||
--------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
:Author: Luke Bonham <dada [at] archlinux [dot] info>
|
:Author: Luke Bonham <dada [at] archlinux [dot] info>
|
||||||
:Version: git
|
:Version: git
|
||||||
:License: GNU-GPL2_
|
:License: GNU-GPL2_
|
||||||
:Source: https://github.com/copycat-killer/lain
|
: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.
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Successor of awesome-vain_, this module provides new layouts, a set of widgets and utility functions, in order to improve Awesome_ usability and configurability.
|
Successor of awesome-vain_, this module provides new layouts, asynchronous widgets and utility functions, with the aim of improving Awesome_ usability and configurability.
|
||||||
|
|
||||||
Read the wiki_ for all the info.
|
Read the wiki_ for all the info.
|
||||||
|
|
||||||
|
@ -26,7 +31,7 @@ Just 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 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 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.
|
||||||
|
|
||||||
- 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 not only your code works, but did not break other parts of the module too!
|
||||||
|
|
||||||
|
@ -42,6 +47,8 @@ Screenshots
|
||||||
.. image:: http://i.imgur.com/STCPcaJ.png
|
.. image:: http://i.imgur.com/STCPcaJ.png
|
||||||
|
|
||||||
.. _GNU-GPL2: http://www.gnu.org/licenses/gpl-2.0.html
|
.. _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-vain: https://github.com/vain/awesome-vain
|
||||||
.. _Awesome: https://github.com/awesomeWM/awesome
|
.. _Awesome: https://github.com/awesomeWM/awesome
|
||||||
.. _wiki: https://github.com/copycat-killer/lain/wiki
|
.. _wiki: https://github.com/copycat-killer/lain/wiki
|
||||||
|
.. _lain.helpers: https://github.com/copycat-killer/lain/blob/master/helpers.lua
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2015, worron
|
|
||||||
* (c) 2013, Alexander Yakushev
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
-- Asynchronous io.popen for Awesome WM.
|
|
||||||
-- How to use:
|
|
||||||
-- asyncshell.request('wscript -Kiev', function(output) wwidget.text = output end)
|
|
||||||
|
|
||||||
-- Grab environment
|
|
||||||
local awful = require('awful')
|
|
||||||
|
|
||||||
-- Avoid discrepancies across multiple shells
|
|
||||||
awful.util.shell = '/bin/sh'
|
|
||||||
|
|
||||||
-- Initialize tables for module
|
|
||||||
asyncshell = { request_table = {}, id_counter = 0 }
|
|
||||||
|
|
||||||
-- Request counter
|
|
||||||
local function next_id()
|
|
||||||
asyncshell.id_counter = (asyncshell.id_counter + 1) % 10000
|
|
||||||
return asyncshell.id_counter
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Remove given request
|
|
||||||
function asyncshell.clear(id)
|
|
||||||
if asyncshell.request_table[id] then
|
|
||||||
if asyncshell.request_table[id].timer then
|
|
||||||
asyncshell.request_table[id].timer:stop()
|
|
||||||
asyncshell.request_table[id].timer = nil
|
|
||||||
end
|
|
||||||
asyncshell.request_table[id] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Sends an asynchronous request for an output of the shell command
|
|
||||||
-- @param command Command to be executed and taken output from
|
|
||||||
-- @param callback Function to be called when the command finishes
|
|
||||||
-- @param timeout Maximum amount of time to wait for the result (optional)
|
|
||||||
function asyncshell.request(command, callback, timeout)
|
|
||||||
local id = next_id()
|
|
||||||
asyncshell.request_table[id] = { callback = callback }
|
|
||||||
|
|
||||||
local formatted_command = string.gsub(command, '"','\"')
|
|
||||||
|
|
||||||
local req = string.format(
|
|
||||||
"echo \"asyncshell.deliver(%s, [[\\\"$(%s)\\\"]])\" | awesome-client &",
|
|
||||||
id, formatted_command
|
|
||||||
)
|
|
||||||
|
|
||||||
if type(awful.spawn) == 'table' and awful.spawn.with_shell then
|
|
||||||
awful.spawn.with_shell(req)
|
|
||||||
else
|
|
||||||
awful.util.spawn_with_shell(req)
|
|
||||||
end
|
|
||||||
|
|
||||||
if timeout then
|
|
||||||
asyncshell.request_table[id].timer = timer({ timeout = timeout })
|
|
||||||
asyncshell.request_table[id].timer:connect_signal("timeout", function() asyncshell.clear(id) end)
|
|
||||||
asyncshell.request_table[id].timer:start()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Calls the remembered callback function on the output of the shell command
|
|
||||||
-- @param id Request ID
|
|
||||||
-- @param output Shell command output to be delievered
|
|
||||||
function asyncshell.deliver(id, output)
|
|
||||||
local output = string.sub(output, 2, -2)
|
|
||||||
if asyncshell.request_table[id] then
|
|
||||||
asyncshell.request_table[id].callback(output)
|
|
||||||
asyncshell.clear(id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return asyncshell
|
|
64
helpers.lua
|
@ -6,15 +6,14 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local debug = require("debug")
|
|
||||||
|
|
||||||
local assert = assert
|
local easy_async = require("awful.spawn").easy_async
|
||||||
local capi = { timer = (type(timer) == 'table' and timer or require ("gears.timer")) }
|
local timer = require("gears.timer")
|
||||||
local io = { open = io.open,
|
local debug = require("debug")
|
||||||
lines = io.lines,
|
local io = { lines = io.lines,
|
||||||
popen = io.popen }
|
open = io.open }
|
||||||
local rawget = rawget
|
local rawget = rawget
|
||||||
local table = { sort = table.sort }
|
local table = { sort = table.sort }
|
||||||
|
|
||||||
-- Lain helper functions for internal use
|
-- Lain helper functions for internal use
|
||||||
-- lain.helpers
|
-- lain.helpers
|
||||||
|
@ -90,38 +89,33 @@ end
|
||||||
|
|
||||||
helpers.timer_table = {}
|
helpers.timer_table = {}
|
||||||
|
|
||||||
function helpers.newtimer(_name, timeout, fun, nostart)
|
function helpers.newtimer(name, timeout, fun, nostart, stoppable)
|
||||||
local name = timeout
|
if not name or #name == 0 then return end
|
||||||
|
name = (stoppable and name) or timeout
|
||||||
if not helpers.timer_table[name] then
|
if not helpers.timer_table[name] then
|
||||||
helpers.timer_table[name] = capi.timer({ timeout = timeout })
|
helpers.timer_table[name] = timer({ timeout = timeout })
|
||||||
helpers.timer_table[name]:start()
|
helpers.timer_table[name]:start()
|
||||||
end
|
end
|
||||||
helpers.timer_table[name]:connect_signal("timeout", fun)
|
helpers.timer_table[name]:connect_signal("timeout", fun)
|
||||||
if not nostart then
|
if not nostart then
|
||||||
helpers.timer_table[name]:emit_signal("timeout")
|
helpers.timer_table[name]:emit_signal("timeout")
|
||||||
end
|
end
|
||||||
|
return stoppable and helpers.timer_table[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
-- {{{ Pipe operations
|
-- {{{ Pipe operations
|
||||||
|
|
||||||
-- read the full output of a command output
|
-- run a command and execute a function on its output (asynchronous pipe)
|
||||||
function helpers.read_pipe(cmd)
|
-- @param cmd the input command
|
||||||
local f = assert(io.popen(cmd))
|
-- @param callback function to execute on cmd output
|
||||||
local output = f:read("*all")
|
-- @return cmd PID
|
||||||
f:close()
|
function helpers.async(cmd, callback)
|
||||||
return output
|
return easy_async(cmd,
|
||||||
end
|
function (stdout, stderr, reason, exit_code)
|
||||||
|
callback(stdout)
|
||||||
-- return line iterator of a command output
|
end)
|
||||||
function helpers.pipelines(...)
|
|
||||||
local f = assert(io.popen(...))
|
|
||||||
return function () -- iterator
|
|
||||||
local data = f:read()
|
|
||||||
if data == nil then f:close() end
|
|
||||||
return data
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- }}}
|
-- }}}
|
||||||
|
@ -140,7 +134,19 @@ end
|
||||||
|
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
--{{{ Iterate over table of records sorted by keys
|
-- {{{ Misc
|
||||||
|
|
||||||
|
-- check if an element exist on a table
|
||||||
|
function helpers.element_in_table(element, tbl)
|
||||||
|
for _, i in pairs(tbl) do
|
||||||
|
if i == element then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- iterate over table of records sorted by keys
|
||||||
function helpers.spairs(t)
|
function helpers.spairs(t)
|
||||||
-- collect the keys
|
-- collect the keys
|
||||||
local keys = {}
|
local keys = {}
|
||||||
|
@ -157,7 +163,7 @@ function helpers.spairs(t)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
--}}}
|
|
||||||
|
|
||||||
|
-- }}}
|
||||||
|
|
||||||
return helpers
|
return helpers
|
||||||
|
|
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 247 B |
Before Width: | Height: | Size: 265 B |
After Width: | Height: | Size: 248 B |
After Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
After Width: | Height: | Size: 251 B |
Before Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 253 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 941 B |
7
init.lua
|
@ -9,13 +9,8 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
package.loaded.lain = nil
|
return {
|
||||||
|
|
||||||
local lain =
|
|
||||||
{
|
|
||||||
layout = require("lain.layout"),
|
layout = require("lain.layout"),
|
||||||
util = require("lain.util"),
|
util = require("lain.util"),
|
||||||
widgets = require("lain.widgets")
|
widgets = require("lain.widgets")
|
||||||
}
|
}
|
||||||
|
|
||||||
return lain
|
|
||||||
|
|
|
@ -7,19 +7,17 @@ source = {
|
||||||
description = {
|
description = {
|
||||||
summary = "Layout, widgets and utilities for Awesome WM",
|
summary = "Layout, widgets and utilities for Awesome WM",
|
||||||
detailed = [[
|
detailed = [[
|
||||||
Successor of awesome-vain, this module provides new layouts, a set of widgets and utility functions, in order to improve Awesome usability and configurability.
|
Successor of awesome-vain, this module provides new layouts, a set of widgets and utility functions, with the aim of improving Awesome usability and configurability.
|
||||||
|
|
||||||
Optional dependencies: alsa-utils (for alsamixer); curl; imagemagick.
|
Optional dependency: curl (for IMAP and weather widgets).
|
||||||
]],
|
]],
|
||||||
homepage = "https://github.com/copycat-killer/lain",
|
homepage = "https://github.com/copycat-killer/lain",
|
||||||
license = "GPL v2"
|
license = "GPL v2"
|
||||||
}
|
}
|
||||||
dependencies = {
|
dependencies = {
|
||||||
"lua >= 5.1",
|
"lua >= 5.3",
|
||||||
"awesome >= 3.5",
|
"awesome >= 4.0",
|
||||||
"alsa-utils",
|
"curl"
|
||||||
"curl",
|
|
||||||
"imagemagick"
|
|
||||||
}
|
}
|
||||||
supported_platforms = { "linux" }
|
supported_platforms = { "linux" }
|
||||||
build = {
|
build = {
|
||||||
|
|
|
@ -8,72 +8,166 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local tag = require("awful.tag")
|
local floor = math.floor
|
||||||
local beautiful = require("beautiful")
|
local screen = screen
|
||||||
|
|
||||||
local cascade =
|
local cascade = {
|
||||||
{
|
|
||||||
name = "cascade",
|
name = "cascade",
|
||||||
nmaster = 0,
|
nmaster = 0,
|
||||||
offset_x = 32,
|
offset_x = 32,
|
||||||
offset_y = 8
|
offset_y = 8,
|
||||||
|
tile = {
|
||||||
|
name = "cascadetile",
|
||||||
|
nmaster = 0,
|
||||||
|
ncol = 0,
|
||||||
|
mwfact = 0,
|
||||||
|
offset_x = 5,
|
||||||
|
offset_y = 32,
|
||||||
|
extra_padding = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cascade.arrange(p)
|
local function do_cascade(p, tiling)
|
||||||
|
local t = p.tag or screen[p.screen].selected_tag
|
||||||
-- Cascade windows.
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width.
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
local wa = p.workarea
|
||||||
local cls = p.clients
|
local cls = p.clients
|
||||||
|
|
||||||
wa.height = wa.height - (global_border * 2)
|
if #cls == 0 then return end
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- Opening a new window will usually force all existing windows to
|
if not tiling then
|
||||||
-- get resized. This wastes a lot of CPU time. So let's set a lower
|
-- Cascade windows.
|
||||||
-- bound to "how_many": This wastes a little screen space but you'll
|
|
||||||
-- get a much better user experience.
|
local num_c
|
||||||
local t = tag.selected(p.screen)
|
if cascade.nmaster > 0 then
|
||||||
local num_c
|
num_c = cascade.nmaster
|
||||||
if cascade.nmaster > 0
|
else
|
||||||
then
|
num_c = t.master_count
|
||||||
num_c = cascade.nmaster
|
end
|
||||||
|
|
||||||
|
-- Opening a new window will usually force all existing windows to
|
||||||
|
-- get resized. This wastes a lot of CPU time. So let's set a lower
|
||||||
|
-- bound to "how_many": This wastes a little screen space but you'll
|
||||||
|
-- get a much better user experience.
|
||||||
|
local how_many = (#cls >= num_c and #cls) or num_c
|
||||||
|
|
||||||
|
local current_offset_x = cascade.offset_x * (how_many - 1)
|
||||||
|
local current_offset_y = cascade.offset_y * (how_many - 1)
|
||||||
|
|
||||||
|
-- Iterate.
|
||||||
|
for i = 1,#cls,1 do
|
||||||
|
local c = cls[i]
|
||||||
|
local g = {}
|
||||||
|
|
||||||
|
g.x = wa.x + (how_many - i) * cascade.offset_x
|
||||||
|
g.y = wa.y + (i - 1) * cascade.offset_y
|
||||||
|
g.width = wa.width - current_offset_x
|
||||||
|
g.height = wa.height - current_offset_y
|
||||||
|
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
|
||||||
|
p.geometries[c] = g
|
||||||
|
end
|
||||||
else
|
else
|
||||||
num_c = tag.getnmaster(t)
|
-- Layout with one fixed column meant for a master window. Its
|
||||||
end
|
-- width is calculated according to mwfact. Other clients are
|
||||||
|
-- cascaded or "tabbed" in a slave column on the right.
|
||||||
|
|
||||||
local how_many = #cls
|
-- (1) (2) (3) (4)
|
||||||
if how_many < num_c
|
-- +----------+---+ +----------+---+ +----------+---+ +----------+---+
|
||||||
then
|
-- | | | | | 3 | | | 4 | | +---+|
|
||||||
how_many = num_c
|
-- | | | -> | | | -> | +---++ -> | +---+|+
|
||||||
end
|
-- | 1 | 2 | | 1 +---++ | 1 | 3 || | 1 +---+|+|
|
||||||
|
-- | | | | | 2 || | +---++| | +---+|+ |
|
||||||
|
-- | | | | | || | | 2 | | | | 2 |+ |
|
||||||
|
-- +----------+---+ +---------+---++ +--------+---+-+ +------+---+---+
|
||||||
|
|
||||||
local current_offset_x = cascade.offset_x * (how_many - 1)
|
local mwfact
|
||||||
local current_offset_y = cascade.offset_y * (how_many - 1)
|
if cascade.tile.mwfact > 0 then
|
||||||
|
mwfact = cascade.tile.mwfact
|
||||||
|
else
|
||||||
|
mwfact = t.master_width_factor
|
||||||
|
end
|
||||||
|
|
||||||
-- Iterate.
|
-- Make slave windows overlap main window? Do this if ncol is 1.
|
||||||
for i = 1,#cls,1
|
local overlap_main
|
||||||
do
|
if cascade.tile.ncol > 0 then
|
||||||
local c = cls[i]
|
overlap_main = cascade.tile.ncol
|
||||||
|
else
|
||||||
|
overlap_main = t.column_count
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Minimum space for slave windows? See cascade.tile.lua.
|
||||||
|
local num_c
|
||||||
|
if cascade.tile.nmaster > 0 then
|
||||||
|
num_c = cascade.tile.nmaster
|
||||||
|
else
|
||||||
|
num_c = t.master_count
|
||||||
|
end
|
||||||
|
|
||||||
|
local how_many = (#cls - 1 >= num_c and (#cls - 1)) or num_c
|
||||||
|
|
||||||
|
local current_offset_x = cascade.tile.offset_x * (how_many - 1)
|
||||||
|
local current_offset_y = cascade.tile.offset_y * (how_many - 1)
|
||||||
|
|
||||||
|
if #cls <= 0 then return end
|
||||||
|
|
||||||
|
-- Main column, fixed width and height.
|
||||||
|
local c = cls[1]
|
||||||
local g = {}
|
local g = {}
|
||||||
|
-- Rounding is necessary to prevent the rendered size of slavewid
|
||||||
|
-- from being 1 pixel off when the result is not an integer.
|
||||||
|
local mainwid = floor(wa.width * mwfact)
|
||||||
|
local slavewid = wa.width - mainwid
|
||||||
|
|
||||||
g.x = wa.x + (how_many - i) * cascade.offset_x
|
if overlap_main == 1 then
|
||||||
g.y = wa.y + (i - 1) * cascade.offset_y
|
g.width = wa.width
|
||||||
g.width = wa.width - current_offset_x - 2*c.border_width
|
|
||||||
g.height = wa.height - current_offset_y - 2*c.border_width
|
-- The size of the main window may be reduced a little bit.
|
||||||
if g.width < 1 then g.width = 1 end
|
-- This allows you to see if there are any windows below the
|
||||||
|
-- main window.
|
||||||
|
-- This only makes sense, though, if the main window is
|
||||||
|
-- overlapping everything else.
|
||||||
|
g.width = g.width - cascade.tile.extra_padding
|
||||||
|
else
|
||||||
|
g.width = mainwid
|
||||||
|
end
|
||||||
|
|
||||||
|
g.height = wa.height
|
||||||
|
g.x = wa.x
|
||||||
|
g.y = wa.y
|
||||||
|
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
if g.height < 1 then g.height = 1 end
|
if g.height < 1 then g.height = 1 end
|
||||||
|
|
||||||
c:geometry(g)
|
p.geometries[c] = g
|
||||||
|
|
||||||
|
-- Remaining clients stacked in slave column, new ones on top.
|
||||||
|
if #cls <= 1 then return end
|
||||||
|
for i = 2,#cls do
|
||||||
|
c = cls[i]
|
||||||
|
g = {}
|
||||||
|
|
||||||
|
g.width = slavewid - current_offset_x
|
||||||
|
g.height = wa.height - current_offset_y
|
||||||
|
|
||||||
|
g.x = wa.x + mainwid + (how_many - (i - 1)) * cascade.tile.offset_x
|
||||||
|
g.y = wa.y + (i - 2) * cascade.tile.offset_y
|
||||||
|
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
|
||||||
|
p.geometries[c] = g
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function cascade.tile.arrange(p)
|
||||||
|
return do_cascade(p, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function cascade.arrange(p)
|
||||||
|
return do_cascade(p, false)
|
||||||
|
end
|
||||||
|
|
||||||
return cascade
|
return cascade
|
||||||
|
|
|
@ -1,174 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2014, projektile
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local tag = require("awful.tag")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local cascadetile =
|
|
||||||
{
|
|
||||||
name = "cascadetile",
|
|
||||||
nmaster = 0,
|
|
||||||
ncol = 0,
|
|
||||||
mwfact = 0,
|
|
||||||
offset_x = 5,
|
|
||||||
offset_y = 32,
|
|
||||||
extra_padding = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function cascadetile.arrange(p)
|
|
||||||
|
|
||||||
-- Layout with one fixed column meant for a master window. Its
|
|
||||||
-- width is calculated according to mwfact. Other clients are
|
|
||||||
-- cascaded or "tabbed" in a slave column on the right.
|
|
||||||
|
|
||||||
-- It's a bit hard to demonstrate the behaviour with ASCII-images...
|
|
||||||
--
|
|
||||||
-- (1) (2) (3) (4)
|
|
||||||
-- +----------+---+ +----------+---+ +----------+---+ +----------+---+
|
|
||||||
-- | | | | | 3 | | | 4 | | +---+|
|
|
||||||
-- | | | -> | | | -> | +---++ -> | +---+|+
|
|
||||||
-- | 1 | 2 | | 1 +---++ | 1 | 3 || | 1 +---+|+|
|
|
||||||
-- | | | | | 2 || | +---++| | +---+|+ |
|
|
||||||
-- | | | | | || | | 2 | | | | 2 |+ |
|
|
||||||
-- +----------+---+ +---------+---++ +--------+---+-+ +------+---+---+
|
|
||||||
|
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
|
||||||
-- beautiful.useless_gap_width.
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
if useless_gap < 0 then useless_gap = 0 end
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
|
|
||||||
-- Borders are factored in.
|
|
||||||
wa.height = wa.height - (global_border * 2)
|
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- Width of main column?
|
|
||||||
local t = tag.selected(p.screen)
|
|
||||||
local mwfact
|
|
||||||
if cascadetile.mwfact > 0
|
|
||||||
then
|
|
||||||
mwfact = cascadetile.mwfact
|
|
||||||
else
|
|
||||||
mwfact = tag.getmwfact(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make slave windows overlap main window? Do this if ncol is 1.
|
|
||||||
local overlap_main
|
|
||||||
if cascadetile.ncol > 0
|
|
||||||
then
|
|
||||||
overlap_main = cascadetile.ncol
|
|
||||||
else
|
|
||||||
overlap_main = tag.getncol(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Minimum space for slave windows? See cascade.lua.
|
|
||||||
local num_c
|
|
||||||
if cascadetile.nmaster > 0
|
|
||||||
then
|
|
||||||
num_c = cascadetile.nmaster
|
|
||||||
else
|
|
||||||
num_c = tag.getnmaster(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
local how_many = #cls - 1
|
|
||||||
if how_many < num_c
|
|
||||||
then
|
|
||||||
how_many = num_c
|
|
||||||
end
|
|
||||||
local current_offset_x = cascadetile.offset_x * (how_many - 1)
|
|
||||||
local current_offset_y = cascadetile.offset_y * (how_many - 1)
|
|
||||||
|
|
||||||
if #cls > 0
|
|
||||||
then
|
|
||||||
-- Main column, fixed width and height.
|
|
||||||
local c = cls[1]
|
|
||||||
local g = {}
|
|
||||||
-- Subtracting the useless_gap width from the work area width here
|
|
||||||
-- makes this mwfact calculation work the same as in uselesstile.
|
|
||||||
-- Rounding is necessary to prevent the rendered size of slavewid
|
|
||||||
-- from being 1 pixel off when the result is not an integer.
|
|
||||||
local mainwid = math.floor((wa.width - useless_gap) * mwfact)
|
|
||||||
local slavewid = wa.width - mainwid
|
|
||||||
|
|
||||||
if overlap_main == 1
|
|
||||||
then
|
|
||||||
g.width = wa.width - 2*c.border_width
|
|
||||||
|
|
||||||
-- The size of the main window may be reduced a little bit.
|
|
||||||
-- This allows you to see if there are any windows below the
|
|
||||||
-- main window.
|
|
||||||
-- This only makes sense, though, if the main window is
|
|
||||||
-- overlapping everything else.
|
|
||||||
g.width = g.width - cascadetile.extra_padding
|
|
||||||
else
|
|
||||||
g.width = mainwid - 2*c.border_width
|
|
||||||
end
|
|
||||||
|
|
||||||
g.height = wa.height - 2*c.border_width
|
|
||||||
g.x = wa.x
|
|
||||||
g.y = wa.y
|
|
||||||
if useless_gap > 0
|
|
||||||
then
|
|
||||||
-- Reduce width once and move window to the right. Reduce
|
|
||||||
-- height twice, however.
|
|
||||||
g.width = g.width - useless_gap
|
|
||||||
g.height = g.height - 2 * useless_gap
|
|
||||||
g.x = g.x + useless_gap
|
|
||||||
g.y = g.y + useless_gap
|
|
||||||
|
|
||||||
-- When there's no window to the right, add an additional
|
|
||||||
-- gap.
|
|
||||||
if overlap_main == 1
|
|
||||||
then
|
|
||||||
g.width = g.width - useless_gap
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
-- Remaining clients stacked in slave column, new ones on top.
|
|
||||||
if #cls > 1
|
|
||||||
then
|
|
||||||
for i = 2,#cls
|
|
||||||
do
|
|
||||||
c = cls[i]
|
|
||||||
g = {}
|
|
||||||
g.width = slavewid - current_offset_x - 2*c.border_width
|
|
||||||
g.height = wa.height - current_offset_y - 2*c.border_width
|
|
||||||
g.x = wa.x + mainwid + (how_many - (i - 1)) * cascadetile.offset_x
|
|
||||||
g.y = wa.y + (i - 2) * cascadetile.offset_y
|
|
||||||
if useless_gap > 0
|
|
||||||
then
|
|
||||||
g.width = g.width - 2 * useless_gap
|
|
||||||
g.height = g.height - 2 * useless_gap
|
|
||||||
g.x = g.x + useless_gap
|
|
||||||
g.y = g.y + useless_gap
|
|
||||||
end
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return cascadetile
|
|
|
@ -1,164 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2014, projektile
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2010, Nicolas Estibals
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local tag = require("awful.tag")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local math = { ceil = math.ceil,
|
|
||||||
floor = math.floor,
|
|
||||||
max = math.max }
|
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local centerfair = { name = "centerfair" }
|
|
||||||
|
|
||||||
function centerfair.arrange(p)
|
|
||||||
-- Layout with fixed number of vertical columns (read from nmaster).
|
|
||||||
-- Cols are centerded until there is nmaster columns, then windows
|
|
||||||
-- are stacked in the slave columns, with at most ncol clients per
|
|
||||||
-- column if possible.
|
|
||||||
|
|
||||||
-- with nmaster=3 and ncol=1 you'll have
|
|
||||||
-- (1) (2) (3)
|
|
||||||
-- +---+---+---+ +-+---+---+-+ +---+---+---+
|
|
||||||
-- | | | | | | | | | | | | |
|
|
||||||
-- | | 1 | | -> | | 1 | 2 | | -> | 1 | 2 | 3 | ->
|
|
||||||
-- | | | | | | | | | | | | |
|
|
||||||
-- +---+---+---+ +-+---+---+-+ +---+---+---+
|
|
||||||
|
|
||||||
-- (4) (5)
|
|
||||||
-- +---+---+---+ +---+---+---+
|
|
||||||
-- | | | 3 | | | 2 | 4 |
|
|
||||||
-- + 1 + 2 +---+ -> + 1 +---+---+
|
|
||||||
-- | | | 4 | | | 3 | 5 |
|
|
||||||
-- +---+---+---+ +---+---+---+
|
|
||||||
|
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
|
||||||
-- beautiful.useless_gap_width .
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
if useless_gap < 0 then useless_gap = 0 end
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
|
|
||||||
-- Borders are factored in.
|
|
||||||
wa.height = wa.height - (global_border * 2)
|
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- How many vertical columns? Read from nmaster on the tag.
|
|
||||||
local t = tag.selected(p.screen)
|
|
||||||
local num_x = centerfair.nmaster or tag.getnmaster(t)
|
|
||||||
local ncol = centerfair.ncol or tag.getncol(t)
|
|
||||||
if num_x <= 2 then num_x = 2 end
|
|
||||||
|
|
||||||
local width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
|
|
||||||
|
|
||||||
if #cls < num_x
|
|
||||||
then
|
|
||||||
-- Less clients than the number of columns, let's center it!
|
|
||||||
local offset_x = wa.x + (wa.width - #cls*width - (#cls - 1)*useless_gap) / 2
|
|
||||||
local g = {}
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
for i = 1, #cls do
|
|
||||||
local c = cls[i]
|
|
||||||
g.width = width - 2*c.border_width
|
|
||||||
g.height = wa.height - 2*useless_gap - 2*c.border_width
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
g.x = offset_x + (i - 1) * (width + useless_gap)
|
|
||||||
c:geometry(g)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- More clients than the number of columns, let's arrange it!
|
|
||||||
-- Master client deserves a special treatement
|
|
||||||
local c = cls[1]
|
|
||||||
local g = {}
|
|
||||||
g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
|
|
||||||
g.height = wa.height - 2*useless_gap - 2*c.border_width
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
g.x = wa.x + useless_gap
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
-- Treat the other clients
|
|
||||||
|
|
||||||
-- Compute distribution of clients among columns
|
|
||||||
local num_y ={}
|
|
||||||
do
|
|
||||||
local remaining_clients = #cls-1
|
|
||||||
local ncol_min = math.ceil(remaining_clients/(num_x-1))
|
|
||||||
if ncol >= ncol_min
|
|
||||||
then
|
|
||||||
for i = (num_x-1), 1, -1 do
|
|
||||||
if (remaining_clients-i+1) < ncol
|
|
||||||
then
|
|
||||||
num_y[i] = remaining_clients-i + 1
|
|
||||||
else
|
|
||||||
num_y[i] = ncol
|
|
||||||
end
|
|
||||||
remaining_clients = remaining_clients - num_y[i]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local rem = remaining_clients % (num_x-1)
|
|
||||||
if rem ==0
|
|
||||||
then
|
|
||||||
for i = 1, num_x-1 do
|
|
||||||
num_y[i] = ncol_min
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i = 1, num_x-1 do
|
|
||||||
num_y[i] = ncol_min - 1
|
|
||||||
end
|
|
||||||
for i = 0, rem-1 do
|
|
||||||
num_y[num_x-1-i] = num_y[num_x-1-i] + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Compute geometry of the other clients
|
|
||||||
local nclient = 2 -- we start with the 2nd client
|
|
||||||
g.x = g.x + g.width + useless_gap + 2*c.border_width
|
|
||||||
|
|
||||||
for i = 1, (num_x-1) do
|
|
||||||
local height = math.floor((wa.height - (num_y[i] + 1)*useless_gap) / num_y[i])
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
for j = 0, (num_y[i]-2) do
|
|
||||||
local c = cls[nclient]
|
|
||||||
g.height = height - 2*c.border_width
|
|
||||||
g.width = width - 2*c.border_width
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
nclient = nclient + 1
|
|
||||||
g.y = g.y + height + useless_gap
|
|
||||||
end
|
|
||||||
local c = cls[nclient]
|
|
||||||
g.height = wa.height - (num_y[i] + 1)*useless_gap - (num_y[i] - 1)*height - 2*c.border_width
|
|
||||||
g.width = width - 2*c.border_width
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
nclient = nclient + 1
|
|
||||||
g.x = g.x + width + useless_gap
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return centerfair
|
|
|
@ -1,136 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2015, Joerg Jaspert
|
|
||||||
* (c) 2014, projektile
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local awful = require("awful")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local centerhwork =
|
|
||||||
{
|
|
||||||
name = "centerhwork",
|
|
||||||
top_left = 0,
|
|
||||||
top_right = 1,
|
|
||||||
bottom_left = 2,
|
|
||||||
bottom_right = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
function centerhwork.arrange(p)
|
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
|
||||||
-- beautiful.useless_gap_width .
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
|
|
||||||
-- Borders are factored in.
|
|
||||||
wa.height = wa.height - (global_border * 2)
|
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- Width of main column?
|
|
||||||
local t = awful.tag.selected(p.screen)
|
|
||||||
local mwfact = awful.tag.getmwfact(t)
|
|
||||||
|
|
||||||
if #cls > 0
|
|
||||||
then
|
|
||||||
-- Main column, fixed width and height.
|
|
||||||
local c = cls[1]
|
|
||||||
local g = {}
|
|
||||||
local mainhei = math.floor(wa.height * mwfact)
|
|
||||||
local slaveLwid = math.floor(wa.width / 2 )
|
|
||||||
local slaveRwid = wa.width - slaveLwid
|
|
||||||
local slavehei = wa.height - mainhei
|
|
||||||
local slaveThei = math.floor(slavehei / 2)
|
|
||||||
local slaveBhei = slavehei - slaveThei
|
|
||||||
local Lhalfgap = math.floor(useless_gap / 2)
|
|
||||||
local Rhalfgap = useless_gap - Lhalfgap
|
|
||||||
|
|
||||||
g.height = mainhei - 2*c.border_width
|
|
||||||
g.width = wa.width - 2*useless_gap - 2*c.border_width
|
|
||||||
g.x = wa.x + useless_gap
|
|
||||||
g.y = wa.y + slaveThei
|
|
||||||
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
-- Auxiliary windows.
|
|
||||||
if #cls > 1
|
|
||||||
then
|
|
||||||
local at = 0
|
|
||||||
for i = 2,#cls
|
|
||||||
do
|
|
||||||
-- It's all fixed. If there are more than 5 clients,
|
|
||||||
-- those additional clients will float. This is
|
|
||||||
-- intentional.
|
|
||||||
if at == 4
|
|
||||||
then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
c = cls[i]
|
|
||||||
g = {}
|
|
||||||
|
|
||||||
if i - 2 == centerhwork.top_left
|
|
||||||
then
|
|
||||||
-- top left
|
|
||||||
g.x = wa.x + useless_gap
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
g.width = slaveLwid - useless_gap - Lhalfgap - 2*c.border_width
|
|
||||||
g.height = slaveThei - 2*useless_gap - 2*c.border_width
|
|
||||||
elseif i - 2 == centerhwork.top_right
|
|
||||||
then
|
|
||||||
-- top right
|
|
||||||
g.x = wa.x + slaveLwid + Rhalfgap
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
g.width = slaveRwid - useless_gap - Rhalfgap - 2*c.border_width
|
|
||||||
g.height = slaveThei - 2*useless_gap - 2*c.border_width
|
|
||||||
elseif i - 2 == centerhwork.bottom_left
|
|
||||||
then
|
|
||||||
-- bottom left
|
|
||||||
g.x = wa.x + useless_gap
|
|
||||||
g.y = wa.y + mainhei + slaveThei + useless_gap
|
|
||||||
g.width = slaveLwid - useless_gap - Lhalfgap - 2*c.border_width
|
|
||||||
g.height = slaveBhei - 2*useless_gap - 2*c.border_width
|
|
||||||
elseif i - 2 == centerhwork.bottom_right
|
|
||||||
then
|
|
||||||
-- bottom right
|
|
||||||
g.x = wa.x + slaveLwid + Rhalfgap
|
|
||||||
g.y = wa.y + mainhei + slaveThei + useless_gap
|
|
||||||
g.width = slaveRwid - useless_gap - Rhalfgap - 2*c.border_width
|
|
||||||
g.height = slaveBhei - 2*useless_gap - 2*c.border_width
|
|
||||||
end
|
|
||||||
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
at = at + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set remaining clients to floating.
|
|
||||||
for i = (#cls - 1 - 4),1,-1
|
|
||||||
do
|
|
||||||
c = cls[i]
|
|
||||||
awful.client.floating.set(c, true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return centerhwork
|
|
|
@ -2,135 +2,153 @@
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
Licensed under GNU General Public License v2
|
||||||
|
* (c) 2016, Henrik Antonsson
|
||||||
|
* (c) 2015, Joerg Jaspert
|
||||||
* (c) 2014, projektile
|
* (c) 2014, projektile
|
||||||
* (c) 2013, Luke Bonham
|
* (c) 2013, Luke Bonham
|
||||||
* (c) 2010-2012, Peter Hofmann
|
* (c) 2010-2012, Peter Hofmann
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local awful = require("awful")
|
local floor = math.floor
|
||||||
local beautiful = require("beautiful")
|
local screen = screen
|
||||||
local tonumber = tonumber
|
|
||||||
local math = { floor = math.floor }
|
|
||||||
|
|
||||||
local centerwork =
|
local centerwork = {
|
||||||
{
|
|
||||||
name = "centerwork",
|
name = "centerwork",
|
||||||
top_right = 0,
|
horizontal = { name = "centerworkh" }
|
||||||
bottom_right = 1,
|
|
||||||
bottom_left = 2,
|
|
||||||
top_left = 3
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function centerwork.arrange(p)
|
local function do_centerwork(p, orientation)
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
local t = p.tag or screen[p.screen].selected_tag
|
||||||
-- beautiful.useless_gap_width .
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
local wa = p.workarea
|
||||||
local cls = p.clients
|
local cls = p.clients
|
||||||
|
|
||||||
-- Borders are factored in.
|
if #cls == 0 then return end
|
||||||
wa.height = wa.height - (global_border * 2)
|
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- Width of main column?
|
local c = cls[1]
|
||||||
local t = awful.tag.selected(p.screen)
|
local g = {}
|
||||||
local mwfact = awful.tag.getmwfact(t)
|
|
||||||
|
|
||||||
if #cls > 0
|
-- Main column, fixed width and height.
|
||||||
then
|
local mwfact = t.master_width_factor
|
||||||
-- Main column, fixed width and height.
|
local mainhei = floor(wa.height * mwfact)
|
||||||
local c = cls[1]
|
local mainwid = floor(wa.width * mwfact)
|
||||||
local g = {}
|
local slavewid = wa.width - mainwid
|
||||||
local mainwid = math.floor(wa.width * mwfact)
|
local slaveLwid = floor(slavewid / 2)
|
||||||
local slavewid = wa.width - mainwid
|
local slaveRwid = slavewid - slaveLwid
|
||||||
local slaveLwid = math.floor(slavewid / 2)
|
local slavehei = wa.height - mainhei
|
||||||
local slaveRwid = slavewid - slaveLwid
|
local slaveThei = floor(slavehei / 2)
|
||||||
local slaveThei = math.floor(wa.height / 2)
|
local slaveBhei = slavehei - slaveThei
|
||||||
local slaveBhei = wa.height - slaveThei
|
local nbrFirstSlaves = floor(#cls / 2)
|
||||||
local Thalfgap = math.floor(useless_gap / 2)
|
local nbrSecondSlaves = floor((#cls - 1) / 2)
|
||||||
local Bhalfgap = useless_gap - Thalfgap
|
|
||||||
|
local slaveFirstDim, slaveSecondDim = 0, 0
|
||||||
|
|
||||||
|
if orientation == "vertical" then
|
||||||
|
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.height / nbrFirstSlaves) end
|
||||||
|
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.height / nbrSecondSlaves) end
|
||||||
|
|
||||||
|
g.height = wa.height
|
||||||
|
g.width = mainwid
|
||||||
|
|
||||||
g.height = wa.height - 2*useless_gap - 2*c.border_width
|
|
||||||
g.width = mainwid - 2*c.border_width
|
|
||||||
g.x = wa.x + slaveLwid
|
g.x = wa.x + slaveLwid
|
||||||
g.y = wa.y + useless_gap
|
g.y = wa.y
|
||||||
|
else
|
||||||
|
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.width / nbrFirstSlaves) end
|
||||||
|
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.width / nbrSecondSlaves) end
|
||||||
|
|
||||||
if g.width < 1 then g.width = 1 end
|
g.height = mainhei
|
||||||
if g.height < 1 then g.height = 1 end
|
g.width = wa.width
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
-- Auxiliary windows.
|
g.x = wa.x
|
||||||
if #cls > 1
|
g.y = wa.y + slaveThei
|
||||||
then
|
end
|
||||||
local at = 0
|
|
||||||
for i = 2,#cls
|
if g.width < 1 then g.width = 1 end
|
||||||
do
|
if g.height < 1 then g.height = 1 end
|
||||||
-- It's all fixed. If there are more than 5 clients,
|
|
||||||
-- those additional clients will float. This is
|
p.geometries[c] = g
|
||||||
-- intentional.
|
|
||||||
if at == 4
|
-- Auxiliary windows.
|
||||||
then
|
if #cls <= 1 then return end
|
||||||
break
|
for i = 2,#cls do
|
||||||
|
local c = cls[i]
|
||||||
|
local g = {}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
end
|
||||||
|
else
|
||||||
|
-- right slave
|
||||||
|
g.x = wa.x + slaveLwid + mainwid
|
||||||
|
g.y = wa.y + (rowIndex-1)*slaveSecondDim
|
||||||
|
|
||||||
c = cls[i]
|
g.width = slaveRwid
|
||||||
g = {}
|
|
||||||
|
|
||||||
if i - 2 == centerwork.top_left
|
-- if last slave in right row use remaining space for that slave
|
||||||
then
|
if rowIndex == nbrSecondSlaves then
|
||||||
-- top left
|
g.height = wa.y + wa.height - g.y
|
||||||
g.x = wa.x + useless_gap
|
else
|
||||||
g.y = wa.y + useless_gap
|
g.height = slaveSecondDim
|
||||||
g.width = slaveLwid - 2*useless_gap - 2*c.border_width
|
|
||||||
g.height = slaveThei - useless_gap - Thalfgap - 2*c.border_width
|
|
||||||
elseif i - 2 == centerwork.top_right
|
|
||||||
then
|
|
||||||
-- top right
|
|
||||||
g.x = wa.x + slaveLwid + mainwid + useless_gap
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
g.width = slaveRwid - 2*useless_gap - 2*c.border_width
|
|
||||||
g.height = slaveThei - useless_gap - Thalfgap - 2*c.border_width
|
|
||||||
elseif i - 2 == centerwork.bottom_left
|
|
||||||
then
|
|
||||||
-- bottom left
|
|
||||||
g.x = wa.x + useless_gap
|
|
||||||
g.y = wa.y + slaveThei + Bhalfgap
|
|
||||||
g.width = slaveLwid - 2*useless_gap - 2*c.border_width
|
|
||||||
g.height = slaveBhei - useless_gap - Bhalfgap - 2*c.border_width
|
|
||||||
elseif i - 2 == centerwork.bottom_right
|
|
||||||
then
|
|
||||||
-- bottom right
|
|
||||||
g.x = wa.x + slaveLwid + mainwid + useless_gap
|
|
||||||
g.y = wa.y + slaveThei + Bhalfgap
|
|
||||||
g.width = slaveRwid - 2*useless_gap - 2*c.border_width
|
|
||||||
g.height = slaveBhei - useless_gap - Bhalfgap - 2*c.border_width
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
at = at + 1
|
|
||||||
end
|
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
|
||||||
|
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
|
||||||
|
|
||||||
-- Set remaining clients to floating.
|
|
||||||
for i = (#cls - 1 - 4),1,-1
|
|
||||||
do
|
|
||||||
c = cls[i]
|
|
||||||
awful.client.floating.set(c, true)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
|
||||||
|
p.geometries[c] = g
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function centerwork.horizontal.arrange(p)
|
||||||
|
return do_centerwork(p, "horizontal")
|
||||||
|
end
|
||||||
|
|
||||||
|
function centerwork.arrange(p)
|
||||||
|
return do_centerwork(p, "vertical")
|
||||||
|
end
|
||||||
|
|
||||||
return centerwork
|
return centerwork
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2016, Henrik Antonsson
|
|
||||||
* (c) 2014, projektile
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
Based on centerwork.lua
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local awful = require("awful")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local tonumber = tonumber
|
|
||||||
local math = { floor = math.floor }
|
|
||||||
|
|
||||||
local centerworkd =
|
|
||||||
{
|
|
||||||
name = "centerworkd",
|
|
||||||
}
|
|
||||||
|
|
||||||
function centerworkd.arrange(p)
|
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
|
||||||
-- beautiful.useless_gap_width .
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
|
|
||||||
-- Borders are factored in.
|
|
||||||
wa.height = wa.height - (global_border * 2)
|
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- Width of main column?
|
|
||||||
local t = awful.tag.selected(p.screen)
|
|
||||||
local mwfact = awful.tag.getmwfact(t)
|
|
||||||
|
|
||||||
if #cls > 0
|
|
||||||
then
|
|
||||||
-- Main column, fixed width and height.
|
|
||||||
local c = cls[1]
|
|
||||||
local g = {}
|
|
||||||
local mainwid = math.floor(wa.width * mwfact)
|
|
||||||
local slavewid = wa.width - mainwid
|
|
||||||
local slaveLwid = math.floor(slavewid / 2)
|
|
||||||
local slaveRwid = slavewid - slaveLwid
|
|
||||||
local nbrLeftSlaves = math.floor(#cls / 2)
|
|
||||||
local nbrRightSlaves = math.floor((#cls - 1) / 2)
|
|
||||||
|
|
||||||
local slaveLeftHeight = 0
|
|
||||||
if nbrLeftSlaves > 0 then slaveLeftHeight = math.floor(wa.height / nbrLeftSlaves) end
|
|
||||||
if nbrRightSlaves > 0 then slaveRightHeight = math.floor(wa.height / nbrRightSlaves) end
|
|
||||||
|
|
||||||
g.height = wa.height - 2*useless_gap - 2*c.border_width
|
|
||||||
g.width = mainwid - 2*c.border_width
|
|
||||||
g.x = wa.x + slaveLwid
|
|
||||||
g.y = wa.y + useless_gap
|
|
||||||
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
-- Auxiliary windows.
|
|
||||||
if #cls > 1
|
|
||||||
then
|
|
||||||
for i = 2,#cls
|
|
||||||
do
|
|
||||||
c = cls[i]
|
|
||||||
g = {}
|
|
||||||
|
|
||||||
local rowIndex = math.floor(i/2)
|
|
||||||
|
|
||||||
-- If i is even it should be placed on the left side
|
|
||||||
if i % 2 == 0
|
|
||||||
then
|
|
||||||
-- left slave
|
|
||||||
g.x = wa.x + useless_gap
|
|
||||||
g.y = wa.y + useless_gap + (rowIndex-1)*slaveLeftHeight
|
|
||||||
|
|
||||||
g.width = slaveLwid - 2*useless_gap - 2*c.border_width
|
|
||||||
|
|
||||||
-- if last slave in left row use remaining space for that slave
|
|
||||||
if rowIndex == nbrLeftSlaves
|
|
||||||
then
|
|
||||||
g.height = wa.y + wa.height - g.y - useless_gap - 2*c.border_width
|
|
||||||
else
|
|
||||||
g.height = slaveLeftHeight - useless_gap - 2*c.border_width
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- right slave
|
|
||||||
g.x = wa.x + slaveLwid + mainwid + useless_gap
|
|
||||||
g.y = wa.y + useless_gap + (rowIndex-1)*slaveRightHeight
|
|
||||||
|
|
||||||
g.width = slaveRwid - 2*useless_gap - 2*c.border_width
|
|
||||||
|
|
||||||
-- if last slave in right row use remaining space for that slave
|
|
||||||
if rowIndex == nbrRightSlaves
|
|
||||||
then
|
|
||||||
g.height = wa.y + wa.height - g.y - useless_gap - 2*c.border_width
|
|
||||||
else
|
|
||||||
g.height = slaveRightHeight - useless_gap - 2*c.border_width
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
|
||||||
c:geometry(g)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return centerworkd
|
|
|
@ -4,136 +4,237 @@
|
||||||
Licensed under GNU General Public License v2
|
Licensed under GNU General Public License v2
|
||||||
* (c) 2014, projektile
|
* (c) 2014, projektile
|
||||||
* (c) 2013, Luke Bonham
|
* (c) 2013, Luke Bonham
|
||||||
|
* (c) 2010, Nicolas Estibals
|
||||||
* (c) 2010-2012, Peter Hofmann
|
* (c) 2010-2012, Peter Hofmann
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local tag = require("awful.tag")
|
local math = { ceil = math.ceil,
|
||||||
local beautiful = require("beautiful")
|
floor = math.floor,
|
||||||
local math = { ceil = math.ceil,
|
max = math.max }
|
||||||
floor = math.floor,
|
local screen = screen
|
||||||
max = math.max }
|
local tonumber = tonumber
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local termfair = { name = "termfair" }
|
local termfair = { name = "termfair" }
|
||||||
|
termfair.center = { name = "centerfair" }
|
||||||
|
|
||||||
function termfair.arrange(p)
|
local function do_fair(p, orientation)
|
||||||
-- Layout with fixed number of vertical columns (read from nmaster).
|
local t = p.tag or screen[p.screen].selected_tag
|
||||||
-- New windows align from left to right. When a row is full, a now
|
|
||||||
-- one above it is created. Like this:
|
|
||||||
|
|
||||||
-- (1) (2) (3)
|
|
||||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
|
||||||
-- | | | | | | | | | | | |
|
|
||||||
-- | 1 | | | -> | 2 | 1 | | -> | 3 | 2 | 1 | ->
|
|
||||||
-- | | | | | | | | | | | |
|
|
||||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
|
||||||
|
|
||||||
-- (4) (5) (6)
|
|
||||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
|
||||||
-- | 4 | | | | 5 | 4 | | | 6 | 5 | 4 |
|
|
||||||
-- +---+---+---+ -> +---+---+---+ -> +---+---+---+
|
|
||||||
-- | 3 | 2 | 1 | | 3 | 2 | 1 | | 3 | 2 | 1 |
|
|
||||||
-- +---+---+---+ +---+---+---+ +---+---+---+
|
|
||||||
|
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
|
||||||
-- beautiful.useless_gap_width.
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
if useless_gap < 0 then useless_gap = 0 end
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Screen.
|
|
||||||
local wa = p.workarea
|
local wa = p.workarea
|
||||||
local cls = p.clients
|
local cls = p.clients
|
||||||
|
|
||||||
-- Borders are factored in.
|
if #cls == 0 then return end
|
||||||
wa.height = wa.height - (global_border * 2)
|
|
||||||
wa.width = wa.width - (global_border * 2)
|
|
||||||
wa.x = wa.x + global_border
|
|
||||||
wa.y = wa.y + global_border
|
|
||||||
|
|
||||||
-- How many vertical columns?
|
if orientation == "west" then
|
||||||
local t = tag.selected(p.screen)
|
-- Layout with fixed number of vertical columns (read from nmaster).
|
||||||
local num_x = termfair.nmaster or tag.getnmaster(t)
|
-- New windows align from left to right. When a row is full, a now
|
||||||
|
-- one above it is created. Like this:
|
||||||
|
|
||||||
-- Do at least "desired_y" rows.
|
-- (1) (2) (3)
|
||||||
local desired_y = termfair.ncol or tag.getncol(t)
|
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||||
|
-- | | | | | | | | | | | |
|
||||||
|
-- | 1 | | | -> | 2 | 1 | | -> | 3 | 2 | 1 | ->
|
||||||
|
-- | | | | | | | | | | | |
|
||||||
|
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||||
|
|
||||||
if #cls > 0
|
-- (4) (5) (6)
|
||||||
then
|
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||||
local num_y = math.max(math.ceil(#cls / num_x), desired_y)
|
-- | 4 | | | | 5 | 4 | | | 6 | 5 | 4 |
|
||||||
|
-- +---+---+---+ -> +---+---+---+ -> +---+---+---+
|
||||||
|
-- | 3 | 2 | 1 | | 3 | 2 | 1 | | 3 | 2 | 1 |
|
||||||
|
-- +---+---+---+ +---+---+---+ +---+---+---+
|
||||||
|
|
||||||
|
-- How many vertical columns? Read from nmaster on the tag.
|
||||||
|
local num_x = tonumber(termfair.nmaster) or t.master_count
|
||||||
|
local ncol = tonumber(termfair.ncol) or t.column_count
|
||||||
|
|
||||||
|
if num_x <= 2 then num_x = 2 end
|
||||||
|
if ncol <= 1 then ncol = 1 end
|
||||||
|
local width = math.floor(wa.width/num_x)
|
||||||
|
|
||||||
|
local num_y = math.max(math.ceil(#cls / num_x), ncol)
|
||||||
|
local height = math.floor(wa.height/num_y)
|
||||||
local cur_num_x = num_x
|
local cur_num_x = num_x
|
||||||
local at_x = 0
|
local at_x = 0
|
||||||
local at_y = 0
|
local at_y = 0
|
||||||
|
|
||||||
local remaining_clients = #cls
|
local remaining_clients = #cls
|
||||||
local width = math.floor((wa.width - (num_x + 1)*useless_gap) / num_x)
|
|
||||||
local height = math.floor((wa.height - (num_y + 1)*useless_gap) / num_y)
|
|
||||||
|
|
||||||
-- We start the first row. Left-align by limiting the number of
|
-- We start the first row. Left-align by limiting the number of
|
||||||
-- available slots.
|
-- available slots.
|
||||||
if remaining_clients < num_x
|
if remaining_clients < num_x then
|
||||||
then
|
|
||||||
cur_num_x = remaining_clients
|
cur_num_x = remaining_clients
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Iterate in reversed order.
|
-- Iterate in reversed order.
|
||||||
for i = #cls,1,-1
|
for i = #cls,1,-1 do
|
||||||
do
|
|
||||||
-- Get x and y position.
|
-- Get x and y position.
|
||||||
local c = cls[i]
|
local c = cls[i]
|
||||||
local this_x = cur_num_x - at_x - 1
|
local this_x = cur_num_x - at_x - 1
|
||||||
local this_y = num_y - at_y - 1
|
local this_y = num_y - at_y - 1
|
||||||
|
|
||||||
-- Calc geometry.
|
-- Calculate geometry.
|
||||||
local g = {}
|
local g = {}
|
||||||
if this_x == (num_x - 1)
|
if this_x == (num_x - 1) then
|
||||||
then
|
g.width = wa.width - (num_x - 1)*width
|
||||||
g.width = wa.width - (num_x - 1)*width - (num_x + 1)*useless_gap - 2*c.border_width
|
|
||||||
else
|
else
|
||||||
g.width = width - 2*c.border_width
|
g.width = width
|
||||||
end
|
end
|
||||||
if this_y == (num_y - 1)
|
|
||||||
then
|
if this_y == (num_y - 1) then
|
||||||
g.height = wa.height - (num_y - 1)*height - (num_y + 1)*useless_gap - 2*c.border_width
|
g.height = wa.height - (num_y - 1)*height
|
||||||
else
|
else
|
||||||
g.height = height - 2*c.border_width
|
g.height = height
|
||||||
end
|
end
|
||||||
|
|
||||||
g.x = wa.x + this_x*width
|
g.x = wa.x + this_x*width
|
||||||
g.y = wa.y + this_y*height
|
g.y = wa.y + this_y*height
|
||||||
|
|
||||||
if useless_gap > 0
|
if g.width < 1 then g.width = 1 end
|
||||||
then
|
|
||||||
-- All clients tile evenly.
|
|
||||||
g.x = g.x + (this_x + 1)*useless_gap
|
|
||||||
g.y = g.y + (this_y + 1)*useless_gap
|
|
||||||
|
|
||||||
end
|
|
||||||
if g.width < 1 then g.width = 1 end
|
|
||||||
if g.height < 1 then g.height = 1 end
|
if g.height < 1 then g.height = 1 end
|
||||||
c:geometry(g)
|
|
||||||
|
p.geometries[c] = g
|
||||||
|
|
||||||
remaining_clients = remaining_clients - 1
|
remaining_clients = remaining_clients - 1
|
||||||
|
|
||||||
-- Next grid position.
|
-- Next grid position.
|
||||||
at_x = at_x + 1
|
at_x = at_x + 1
|
||||||
if at_x == num_x
|
if at_x == num_x then
|
||||||
then
|
|
||||||
-- Row full, create a new one above it.
|
-- Row full, create a new one above it.
|
||||||
at_x = 0
|
at_x = 0
|
||||||
at_y = at_y + 1
|
at_y = at_y + 1
|
||||||
|
|
||||||
-- We start a new row. Left-align.
|
-- We start a new row. Left-align.
|
||||||
if remaining_clients < num_x
|
if remaining_clients < num_x then
|
||||||
then
|
|
||||||
cur_num_x = remaining_clients
|
cur_num_x = remaining_clients
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
elseif orientation == "center" then
|
||||||
|
-- Layout with fixed number of vertical columns (read from nmaster).
|
||||||
|
-- Cols are centerded until there is nmaster columns, then windows
|
||||||
|
-- are stacked in the slave columns, with at most ncol clients per
|
||||||
|
-- column if possible.
|
||||||
|
|
||||||
|
-- with nmaster=3 and ncol=1 you'll have
|
||||||
|
-- (1) (2) (3)
|
||||||
|
-- +---+---+---+ +-+---+---+-+ +---+---+---+
|
||||||
|
-- | | | | | | | | | | | | |
|
||||||
|
-- | | 1 | | -> | | 1 | 2 | | -> | 1 | 2 | 3 | ->
|
||||||
|
-- | | | | | | | | | | | | |
|
||||||
|
-- +---+---+---+ +-+---+---+-+ +---+---+---+
|
||||||
|
|
||||||
|
-- (4) (5)
|
||||||
|
-- +---+---+---+ +---+---+---+
|
||||||
|
-- | | | 3 | | | 2 | 4 |
|
||||||
|
-- + 1 + 2 +---+ -> + 1 +---+---+
|
||||||
|
-- | | | 4 | | | 3 | 5 |
|
||||||
|
-- +---+---+---+ +---+---+---+
|
||||||
|
|
||||||
|
-- How many vertical columns? Read from nmaster on the tag.
|
||||||
|
local num_x = tonumber(termfair.center.nmaster) or t.master_count
|
||||||
|
local ncol = tonumber(termfair.center.ncol) or t.column_count
|
||||||
|
|
||||||
|
if num_x <= 2 then num_x = 2 end
|
||||||
|
if ncol <= 1 then ncol = 1 end
|
||||||
|
|
||||||
|
local width = math.floor(wa.width / num_x)
|
||||||
|
|
||||||
|
if #cls < num_x then
|
||||||
|
-- Less clients than the number of columns, let's center it!
|
||||||
|
local offset_x = wa.x + (wa.width - #cls*width) / 2
|
||||||
|
for i = 1, #cls do
|
||||||
|
local g = { y = wa.y }
|
||||||
|
g.width = width
|
||||||
|
g.height = wa.height
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
g.x = offset_x + (i - 1) * width
|
||||||
|
p.geometries[cls[i]] = g
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- More clients than the number of columns, let's arrange it!
|
||||||
|
-- Master client deserves a special treatement
|
||||||
|
local g = {}
|
||||||
|
g.width = wa.width - (num_x - 1)*width
|
||||||
|
g.height = wa.height
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
g.x = wa.x
|
||||||
|
g.y = wa.y
|
||||||
|
p.geometries[cls[1]] = g
|
||||||
|
|
||||||
|
-- Treat the other clients
|
||||||
|
|
||||||
|
-- Compute distribution of clients among columns
|
||||||
|
local num_y = {}
|
||||||
|
local remaining_clients = #cls-1
|
||||||
|
local ncol_min = math.ceil(remaining_clients/(num_x-1))
|
||||||
|
|
||||||
|
if ncol >= ncol_min then
|
||||||
|
for i = (num_x-1), 1, -1 do
|
||||||
|
if (remaining_clients-i+1) < ncol then
|
||||||
|
num_y[i] = remaining_clients-i + 1
|
||||||
|
else
|
||||||
|
num_y[i] = ncol
|
||||||
|
end
|
||||||
|
remaining_clients = remaining_clients - num_y[i]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local rem = remaining_clients % (num_x-1)
|
||||||
|
if rem == 0 then
|
||||||
|
for i = 1, num_x-1 do
|
||||||
|
num_y[i] = ncol_min
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 1, num_x-1 do
|
||||||
|
num_y[i] = ncol_min - 1
|
||||||
|
end
|
||||||
|
for i = 0, rem-1 do
|
||||||
|
num_y[num_x-1-i] = num_y[num_x-1-i] + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compute geometry of the other clients
|
||||||
|
local nclient = 2 -- we start with the 2nd client
|
||||||
|
local wx = g.x + g.width
|
||||||
|
for i = 1, (num_x-1) do
|
||||||
|
local height = math.floor(wa.height / num_y[i])
|
||||||
|
local wy = wa.y
|
||||||
|
for j = 0, (num_y[i]-2) do
|
||||||
|
local g = {}
|
||||||
|
g.x = wx
|
||||||
|
g.y = wy
|
||||||
|
g.height = height
|
||||||
|
g.width = width
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
p.geometries[cls[nclient]] = g
|
||||||
|
nclient = nclient + 1
|
||||||
|
wy = wy + height
|
||||||
|
end
|
||||||
|
local g = {}
|
||||||
|
g.x = wx
|
||||||
|
g.y = wy
|
||||||
|
g.height = wa.height - (num_y[i] - 1)*height
|
||||||
|
g.width = width
|
||||||
|
if g.width < 1 then g.width = 1 end
|
||||||
|
if g.height < 1 then g.height = 1 end
|
||||||
|
p.geometries[cls[nclient]] = g
|
||||||
|
nclient = nclient + 1
|
||||||
|
wx = wx + width
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function termfair.center.arrange(p)
|
||||||
|
return do_fair(p, "center")
|
||||||
|
end
|
||||||
|
|
||||||
|
function termfair.arrange(p)
|
||||||
|
return do_fair(p, "west")
|
||||||
|
end
|
||||||
|
|
||||||
return termfair
|
return termfair
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2014, projektile, worron
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2012, Josh Komoroske
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local ipairs = ipairs
|
|
||||||
local math = { ceil = math.ceil, sqrt = math.sqrt, floor = math.floor, max = math.max }
|
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local uselessfair = {}
|
|
||||||
|
|
||||||
-- Transformation functions
|
|
||||||
local function swap(geometry)
|
|
||||||
return { x = geometry.y, y = geometry.x, width = geometry.height, height = geometry.width }
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Client geometry correction depending on useless gap and window border
|
|
||||||
local function size_correction(c, geometry, useless_gap)
|
|
||||||
geometry.width = math.max(geometry.width - 2 * c.border_width - useless_gap, 1)
|
|
||||||
geometry.height = math.max(geometry.height - 2 * c.border_width - useless_gap, 1)
|
|
||||||
geometry.x = geometry.x + useless_gap / 2
|
|
||||||
geometry.y = geometry.y + useless_gap / 2
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Main tiling function
|
|
||||||
local function fair(p, orientation)
|
|
||||||
|
|
||||||
-- Theme vars
|
|
||||||
local useless_gap = beautiful.useless_gap_width or 0
|
|
||||||
local global_border = beautiful.global_border_width or 0
|
|
||||||
|
|
||||||
-- Aliases
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
|
|
||||||
-- Nothing to tile here
|
|
||||||
if #cls == 0 then return end
|
|
||||||
|
|
||||||
-- Workarea size correction depending on useless gap and global border
|
|
||||||
wa.height = wa.height - 2 * global_border - useless_gap
|
|
||||||
wa.width = wa.width - 2 * global_border - useless_gap
|
|
||||||
wa.x = wa.x + useless_gap / 2 + global_border
|
|
||||||
wa.y = wa.y + useless_gap / 2 + global_border
|
|
||||||
|
|
||||||
-- Geometry calculation
|
|
||||||
local row, col = 0, 0
|
|
||||||
|
|
||||||
local rows = math.ceil(math.sqrt(#cls))
|
|
||||||
local cols = math.ceil(#cls / rows)
|
|
||||||
|
|
||||||
for i, c in ipairs(cls) do
|
|
||||||
local g = {}
|
|
||||||
|
|
||||||
-- find tile orientation for current client and swap geometry if need
|
|
||||||
local need_swap = (orientation == "east" and #cls <= 2) or (orientation == "south" and #cls > 2)
|
|
||||||
local area = need_swap and swap(wa) or wa
|
|
||||||
|
|
||||||
-- calculate geometry
|
|
||||||
if #cls < (cols * rows) and row == cols - 1 then
|
|
||||||
g.width = area.width / (rows - ((cols * rows) - #cls))
|
|
||||||
else
|
|
||||||
g.width = area.width / rows
|
|
||||||
end
|
|
||||||
|
|
||||||
g.height = area.height / cols
|
|
||||||
g.x = area.x + col * g.width
|
|
||||||
g.y = area.y + row * g.height
|
|
||||||
|
|
||||||
-- turn back to real if geometry was swapped
|
|
||||||
if need_swap then g = swap(g) end
|
|
||||||
|
|
||||||
-- window size correction depending on useless gap and window border
|
|
||||||
size_correction(c, g, useless_gap)
|
|
||||||
|
|
||||||
-- set geometry
|
|
||||||
c:geometry(g)
|
|
||||||
|
|
||||||
-- update tile grid coordinates
|
|
||||||
col = i % rows
|
|
||||||
row = math.floor(i / rows)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Layout constructor
|
|
||||||
local function construct_layout(name, direction)
|
|
||||||
return {
|
|
||||||
name = name,
|
|
||||||
-- @p screen The screen number to tile
|
|
||||||
arrange = function(p) return fair(p, direction) end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Build layouts with different tile direction
|
|
||||||
uselessfair.vertical = construct_layout("uselessfair", "south")
|
|
||||||
uselessfair.horizontal = construct_layout("uselessfairh", "east")
|
|
||||||
|
|
||||||
-- Module aliase
|
|
||||||
uselessfair.arrange = uselessfair.vertical.arrange
|
|
||||||
uselessfair.name = uselessfair.vertical.name
|
|
||||||
|
|
||||||
return uselessfair
|
|
|
@ -1,123 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2014, projektile
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2009, Uli Schlachter
|
|
||||||
* (c) 2008, Julien Danjolu
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local ipairs = ipairs
|
|
||||||
local tonumber = tonumber
|
|
||||||
local math = require("math")
|
|
||||||
|
|
||||||
local uselesspiral = {}
|
|
||||||
|
|
||||||
local function spiral(p, spiral)
|
|
||||||
-- A useless gap (like the dwm patch) can be defined with
|
|
||||||
-- beautiful.useless_gap_width.
|
|
||||||
local useless_gap = tonumber(beautiful.useless_gap_width) or 0
|
|
||||||
if useless_gap < 0 then useless_gap = 0 end
|
|
||||||
|
|
||||||
-- A global border can be defined with
|
|
||||||
-- beautiful.global_border_width
|
|
||||||
local global_border = tonumber(beautiful.global_border_width) or 0
|
|
||||||
if global_border < 0 then global_border = 0 end
|
|
||||||
|
|
||||||
-- Themes border width requires an offset
|
|
||||||
local bw = tonumber(beautiful.border_width) or 0
|
|
||||||
|
|
||||||
-- get our orientation right
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
local n = #cls -- number of windows total; k = which window number
|
|
||||||
|
|
||||||
wa.height = wa.height - ((global_border * 2) + (bw * 2))
|
|
||||||
wa.width = wa.width - ((global_border * 2) + (bw * 2))
|
|
||||||
|
|
||||||
local static_wa = wa
|
|
||||||
|
|
||||||
for k, c in ipairs(cls) do
|
|
||||||
if k < n then
|
|
||||||
if k % 2 == 0 then
|
|
||||||
wa.height = (wa.height / 2)
|
|
||||||
else
|
|
||||||
wa.width = (wa.width / 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if k % 4 == 0 and spiral then
|
|
||||||
wa.x = wa.x - wa.width
|
|
||||||
elseif k % 2 == 0 or
|
|
||||||
(k % 4 == 3 and k < n and spiral) then
|
|
||||||
wa.x = wa.x + wa.width
|
|
||||||
end
|
|
||||||
|
|
||||||
if k % 4 == 1 and k ~= 1 and spiral then
|
|
||||||
wa.y = wa.y - wa.height
|
|
||||||
elseif k % 2 == 1 and k ~= 1 or
|
|
||||||
(k % 4 == 0 and k < n and spiral) then
|
|
||||||
wa.y = wa.y + wa.height
|
|
||||||
end
|
|
||||||
|
|
||||||
local wa2 = {}
|
|
||||||
wa2.x = wa.x + (useless_gap / 2) + global_border
|
|
||||||
wa2.y = wa.y + (useless_gap / 2) + global_border
|
|
||||||
wa2.height = wa.height - (useless_gap / 2)
|
|
||||||
wa2.width = wa.width - (useless_gap / 2)
|
|
||||||
|
|
||||||
-- Useless gap.
|
|
||||||
if useless_gap > 0
|
|
||||||
then
|
|
||||||
-- Top and left clients are shrinked by two steps and
|
|
||||||
-- get moved away from the border. Other clients just
|
|
||||||
-- get shrinked in one direction.
|
|
||||||
|
|
||||||
top = false
|
|
||||||
left = false
|
|
||||||
|
|
||||||
if wa2.y == static_wa.y then
|
|
||||||
top = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if wa2.x == static_wa.x then
|
|
||||||
left = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if top then
|
|
||||||
wa2.height = wa2.height - useless_gap
|
|
||||||
wa2.y = wa2.y - (useless_gap / 2)
|
|
||||||
else
|
|
||||||
wa2.height = wa2.height - (useless_gap / 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
if left then
|
|
||||||
wa2.width = wa2.width - useless_gap
|
|
||||||
wa2.x = wa2.x - (useless_gap / 2)
|
|
||||||
else
|
|
||||||
wa2.width = wa2.width - (useless_gap / 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- End of useless gap.
|
|
||||||
|
|
||||||
c:geometry(wa2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Dwindle layout
|
|
||||||
uselesspiral.dwindle = {}
|
|
||||||
uselesspiral.dwindle.name = "uselessdwindle"
|
|
||||||
function uselesspiral.dwindle.arrange(p)
|
|
||||||
return spiral(p, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Spiral layout
|
|
||||||
uselesspiral.name = "uselesspiral"
|
|
||||||
function uselesspiral.arrange(p)
|
|
||||||
return spiral(p, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
return uselesspiral
|
|
|
@ -1,231 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2014, projektile, worron
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2009, Donald Ephraim Curtis
|
|
||||||
* (c) 2008, Julien Danjolu
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local tag = require("awful.tag")
|
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local ipairs = ipairs
|
|
||||||
local math = { floor = math.floor,
|
|
||||||
ceil = math.ceil,
|
|
||||||
max = math.max,
|
|
||||||
min = math.min }
|
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local uselesstile = {}
|
|
||||||
|
|
||||||
-- Transformation functions
|
|
||||||
local function flip(canvas, geometry)
|
|
||||||
return {
|
|
||||||
-- vertical only
|
|
||||||
x = 2 * canvas.x + canvas.width - geometry.x - geometry.width,
|
|
||||||
y = geometry.y,
|
|
||||||
width = geometry.width,
|
|
||||||
height = geometry.height
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function swap(geometry)
|
|
||||||
return { x = geometry.y, y = geometry.x, width = geometry.height, height = geometry.width }
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Find geometry for secondary windows column
|
|
||||||
local function cut_column(wa, n, index)
|
|
||||||
local width = math.floor(wa.width / n)
|
|
||||||
local area = { x = wa.x + (index - 1) * width, y = wa.y, width = width, height = wa.height }
|
|
||||||
|
|
||||||
return area
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Find geometry for certain window in column
|
|
||||||
local function cut_row(wa, factor, index, used)
|
|
||||||
local height = math.floor(wa.height * factor.window[index] / factor.total)
|
|
||||||
local area = { x = wa.x, y = wa.y + used, width = wa.width, height = height }
|
|
||||||
|
|
||||||
return area
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Client geometry correction depending on useless gap and window border
|
|
||||||
local function size_correction(c, geometry, useless_gap)
|
|
||||||
geometry.width = math.max(geometry.width - 2 * c.border_width - useless_gap, 1)
|
|
||||||
geometry.height = math.max(geometry.height - 2 * c.border_width - useless_gap, 1)
|
|
||||||
geometry.x = geometry.x + useless_gap / 2
|
|
||||||
geometry.y = geometry.y + useless_gap / 2
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check size factor for group of clients and calculate total
|
|
||||||
local function calc_factor(n, winfactors)
|
|
||||||
local factor = { window = winfactors, total = 0, min = 1 }
|
|
||||||
|
|
||||||
for i = 1, n do
|
|
||||||
if not factor.window[i] then
|
|
||||||
factor.window[i] = factor.min
|
|
||||||
else
|
|
||||||
factor.min = math.min(factor.window[i], factor.min)
|
|
||||||
if factor.window[i] < 0.05 then factor.window[i] = 0.05 end
|
|
||||||
end
|
|
||||||
factor.total = factor.total + factor.window[i]
|
|
||||||
end
|
|
||||||
|
|
||||||
return factor
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Tile group of clients in given area
|
|
||||||
-- @canvas need for proper transformation only
|
|
||||||
-- @winfactors table with clients size factors
|
|
||||||
local function tile_column(canvas, area, list, useless_gap, transformation, winfactors)
|
|
||||||
local used = 0
|
|
||||||
local factor = calc_factor(#list, winfactors)
|
|
||||||
|
|
||||||
for i, c in ipairs(list) do
|
|
||||||
local g = cut_row(area, factor, i, used)
|
|
||||||
if i == #list then g.height = area.height - used end
|
|
||||||
used = used + g.height
|
|
||||||
|
|
||||||
-- swap workarea dimensions
|
|
||||||
if transformation.flip then g = flip(canvas, g) end
|
|
||||||
if transformation.swap then g = swap(g) end
|
|
||||||
|
|
||||||
-- useless gap and border correction
|
|
||||||
size_correction(c, g, useless_gap)
|
|
||||||
|
|
||||||
|
|
||||||
c:geometry(g)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--Main tile function
|
|
||||||
local function tile(p, orientation)
|
|
||||||
|
|
||||||
-- Theme vars
|
|
||||||
local useless_gap = beautiful.useless_gap_width or 0
|
|
||||||
local global_border = beautiful.global_border_width or 0
|
|
||||||
|
|
||||||
-- Aliases
|
|
||||||
local wa = p.workarea
|
|
||||||
local cls = p.clients
|
|
||||||
local t = tag.selected(p.screen)
|
|
||||||
|
|
||||||
-- Nothing to tile here
|
|
||||||
if #cls == 0 then return end
|
|
||||||
|
|
||||||
-- Get tag prop
|
|
||||||
local nmaster = math.min(tag.getnmaster(t), #cls)
|
|
||||||
local mwfact = tag.getmwfact(t)
|
|
||||||
|
|
||||||
if nmaster == 0 then
|
|
||||||
mwfact = 0
|
|
||||||
elseif nmaster == #cls then
|
|
||||||
mwfact = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- clients size factor
|
|
||||||
local data = tag.getdata(t).windowfact
|
|
||||||
|
|
||||||
if not data then
|
|
||||||
data = {}
|
|
||||||
tag.getdata(t).windowfact = data
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Workarea size correction depending on useless gap and global border
|
|
||||||
wa.height = wa.height - 2 * global_border - useless_gap
|
|
||||||
wa.width = wa.width - 2 * global_border - useless_gap
|
|
||||||
wa.x = wa.x + useless_gap / 2 + global_border
|
|
||||||
wa.y = wa.y + useless_gap / 2 + global_border
|
|
||||||
|
|
||||||
-- Find which transformation we need for given orientation
|
|
||||||
local transformation = {
|
|
||||||
swap = orientation == 'top' or orientation == 'bottom',
|
|
||||||
flip = orientation == 'left' or orientation == 'top'
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Swap workarea dimensions if orientation vertical
|
|
||||||
if transformation.swap then wa = swap(wa) end
|
|
||||||
|
|
||||||
-- Split master and other windows
|
|
||||||
local cls_master, cls_other = {}, {}
|
|
||||||
|
|
||||||
for i, c in ipairs(cls) do
|
|
||||||
if i <= nmaster then
|
|
||||||
table.insert(cls_master, c)
|
|
||||||
else
|
|
||||||
table.insert(cls_other, c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Tile master windows
|
|
||||||
local master_area = {
|
|
||||||
x = wa.x,
|
|
||||||
y = wa.y,
|
|
||||||
width = nmaster > 0 and math.floor(wa.width * mwfact) or 0,
|
|
||||||
height = wa.height
|
|
||||||
}
|
|
||||||
|
|
||||||
if not data[0] then data[0] = {} end
|
|
||||||
tile_column(wa, master_area, cls_master, useless_gap, transformation, data[0])
|
|
||||||
|
|
||||||
-- Tile other windows
|
|
||||||
local other_area = {
|
|
||||||
x = wa.x + master_area.width,
|
|
||||||
y = wa.y,
|
|
||||||
width = wa.width - master_area.width,
|
|
||||||
height = wa.height
|
|
||||||
}
|
|
||||||
|
|
||||||
-- get column number for other windows
|
|
||||||
local ncol = math.min(tag.getncol(t), #cls_other)
|
|
||||||
|
|
||||||
if ncol == 0 then ncol = 1 end
|
|
||||||
|
|
||||||
-- split other windows to column groups
|
|
||||||
local last_small_column = ncol - #cls_other % ncol
|
|
||||||
local rows_min = math.floor(#cls_other / ncol)
|
|
||||||
|
|
||||||
local client_index = 1
|
|
||||||
local used = 0
|
|
||||||
for i = 1, ncol do
|
|
||||||
local position = transformation.flip and ncol - i + 1 or i
|
|
||||||
local rows = i <= last_small_column and rows_min or rows_min + 1
|
|
||||||
local column = {}
|
|
||||||
|
|
||||||
for j = 1, rows do
|
|
||||||
table.insert(column, cls_other[client_index])
|
|
||||||
client_index = client_index + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- and tile
|
|
||||||
local column_area = cut_column(other_area, ncol, position)
|
|
||||||
if i == ncol then column_area.width = other_area.width - used end
|
|
||||||
used = used + column_area.width
|
|
||||||
|
|
||||||
if not data[i] then data[i] = {} end
|
|
||||||
tile_column(wa, column_area, column, useless_gap, transformation, data[i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Layout constructor
|
|
||||||
local function construct_layout(name, orientation)
|
|
||||||
return {
|
|
||||||
name = name,
|
|
||||||
-- @p screen number to tile
|
|
||||||
arrange = function(p) return tile(p, orientation) end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Build layouts with different tile direction
|
|
||||||
uselesstile.right = construct_layout("uselesstile", "right")
|
|
||||||
uselesstile.left = construct_layout("uselesstileleft", "left")
|
|
||||||
uselesstile.bottom = construct_layout("uselesstilebottom", "bottom")
|
|
||||||
uselesstile.top = construct_layout("uselesstiletop", "top")
|
|
||||||
|
|
||||||
-- Module aliase
|
|
||||||
uselesstile.arrange = uselesstile.right.arrange
|
|
||||||
uselesstile.name = uselesstile.right.name
|
|
||||||
|
|
||||||
return uselesstile
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env sh
|
||||||
#
|
#
|
||||||
# Adapted from Eridan's "fs" (cleanup, enhancements and switch to bash/Linux)
|
# Adapted from Eridan's "fs" (cleanup, enhancements and switch to bash/Linux)
|
||||||
# JM, 10/12/2004
|
# JM, 10/12/2004
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# A simple cover fetcher script for current playing song on mpd.
|
|
||||||
#
|
|
||||||
# Original author: Wolfgang Mueller
|
|
||||||
#
|
|
||||||
# Adapted for Lain internal use.
|
|
||||||
# https://github.com/copycat-killer/lain
|
|
||||||
#
|
|
||||||
# You can use, edit and redistribute this script in any way you like.
|
|
||||||
#
|
|
||||||
# Dependencies: imagemagick.
|
|
||||||
#
|
|
||||||
# Usage: mpdcover <music_directory> <song_file> <cover_resize> <default_art>
|
|
||||||
|
|
||||||
# Configuration-------------------------------------------------------
|
|
||||||
|
|
||||||
# Music directory
|
|
||||||
MUSIC_DIR=$1
|
|
||||||
|
|
||||||
# Song file
|
|
||||||
file=$2
|
|
||||||
|
|
||||||
# Regex expression used for image search
|
|
||||||
IMG_REG="(Front|front|Cover|cover|Art|art|Folder|folder)\.(jpg|jpeg|png|gif)$"
|
|
||||||
|
|
||||||
# Path of temporary resized cover
|
|
||||||
TEMP_PATH="/tmp/mpdcover.png"
|
|
||||||
|
|
||||||
# Resize cover
|
|
||||||
COVER_RESIZE="$3x$3"
|
|
||||||
|
|
||||||
if [ $COVER_RESIZE == "x" ]; then
|
|
||||||
COVER_RESIZE="100x100"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# The default cover to use (optional)
|
|
||||||
DEFAULT_ART=$4
|
|
||||||
|
|
||||||
# Thumbnail background (transparent)
|
|
||||||
COVER_BACKGROUND="none"
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------
|
|
||||||
|
|
||||||
# check if anything is playing at all
|
|
||||||
[[ -z $file ]] && exit 1
|
|
||||||
|
|
||||||
# Art directory
|
|
||||||
art="$MUSIC_DIR/${file%/*}"
|
|
||||||
|
|
||||||
# find every file that matches IMG_REG set the first matching file to be the
|
|
||||||
# cover.
|
|
||||||
cover="$(find "$art/" -maxdepth 1 -type f | egrep -i -m1 "$IMG_REG")"
|
|
||||||
|
|
||||||
# when no cover is found, use DEFAULT_ART as cover
|
|
||||||
cover="${cover:=$DEFAULT_ART}"
|
|
||||||
|
|
||||||
# check if art is available
|
|
||||||
if [[ -n $cover ]]; then
|
|
||||||
if [[ -n $COVER_RESIZE ]]; then
|
|
||||||
convert "$cover" -scale $COVER_RESIZE -gravity "center" -background "$COVER_BACKGROUND" "$TEMP_PATH"
|
|
||||||
cover="$TEMP_PATH"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
rm $TEMP_PATH
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
192
util/init.lua
|
@ -13,15 +13,10 @@
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local beautiful = require("beautiful")
|
local sqrt = math.sqrt
|
||||||
local math = { sqrt = math.sqrt }
|
|
||||||
local mouse = mouse
|
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local string = { gsub = string.gsub }
|
|
||||||
local client = client
|
local client = client
|
||||||
local screen = screen
|
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local wrequire = require("lain.helpers").wrequire
|
local wrequire = require("lain.helpers").wrequire
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
|
@ -29,26 +24,23 @@ local setmetatable = setmetatable
|
||||||
-- lain.util
|
-- lain.util
|
||||||
local util = { _NAME = "lain.util" }
|
local util = { _NAME = "lain.util" }
|
||||||
|
|
||||||
-- Like awful.menu.clients, but only show clients of currently selected
|
-- Like awful.menu.clients, but only show clients of currently selected tags
|
||||||
-- tags.
|
|
||||||
function util.menu_clients_current_tags(menu, args)
|
function util.menu_clients_current_tags(menu, args)
|
||||||
-- List of currently selected tags.
|
-- List of currently selected tags.
|
||||||
local cls_tags = awful.tag.selectedlist(mouse.screen)
|
local cls_tags = awful.screen.focused().selected_tags
|
||||||
|
|
||||||
|
if cls_tags == nil then return nil end
|
||||||
|
|
||||||
-- Final list of menu items.
|
-- Final list of menu items.
|
||||||
local cls_t = {}
|
local cls_t = {}
|
||||||
|
|
||||||
if cls_tags == nil then return nil end
|
|
||||||
|
|
||||||
-- For each selected tag get all clients of that tag and add them to
|
-- For each selected tag get all clients of that tag and add them to
|
||||||
-- the menu. A click on a menu item will raise that client.
|
-- the menu. A click on a menu item will raise that client.
|
||||||
for i = 1,#cls_tags
|
for i = 1,#cls_tags do
|
||||||
do
|
local t = cls_tags[i]
|
||||||
local t = cls_tags[i]
|
|
||||||
local cls = t:clients()
|
local cls = t:clients()
|
||||||
|
|
||||||
for k, c in pairs(cls)
|
for k, c in pairs(cls) do
|
||||||
do
|
|
||||||
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
|
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
|
||||||
function ()
|
function ()
|
||||||
c.minimized = false
|
c.minimized = false
|
||||||
|
@ -68,167 +60,109 @@ function util.menu_clients_current_tags(menu, args)
|
||||||
|
|
||||||
-- Set the list of items and show the menu.
|
-- Set the list of items and show the menu.
|
||||||
menu.items = cls_t
|
menu.items = cls_t
|
||||||
local m = awful.menu.new(menu)
|
local m = awful.menu(menu)
|
||||||
m:show(args)
|
m:show(args)
|
||||||
|
|
||||||
return m
|
return m
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Magnify a client: Set it to "float" and resize it.
|
-- Magnify a client: set it to "float" and resize it.
|
||||||
local magnified_client = nil
|
|
||||||
function util.magnify_client(c)
|
function util.magnify_client(c)
|
||||||
if c and not awful.client.floating.get(c) then
|
if c and not c.floating then
|
||||||
util.mc(c)
|
util.mc(c)
|
||||||
magnified_client = c
|
util.magnified_client = c
|
||||||
else
|
else
|
||||||
awful.client.floating.set(c, false)
|
c.floating = false
|
||||||
magnified_client = nil
|
util.magnified_client = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- https://github.com/copycat-killer/lain/issues/195
|
-- https://github.com/copycat-killer/lain/issues/195
|
||||||
function util.mc(c)
|
function util.mc(c)
|
||||||
c = c or magnified_client
|
c = c or util.magnified_client
|
||||||
if not c then return end
|
if not c then return end
|
||||||
awful.client.floating.set(c, true)
|
|
||||||
local mg = screen[mouse.screen].geometry
|
c.floating = true
|
||||||
local tag = awful.tag.selected(mouse.screen)
|
local s = awful.screen.focused()
|
||||||
local mwfact = awful.tag.getmwfact(tag)
|
local mg = s.geometry
|
||||||
local g = {}
|
local mwfact = s.selected_tag.master_width_factor or 0.5
|
||||||
g.width = math.sqrt(mwfact) * mg.width
|
local g = {}
|
||||||
g.height = math.sqrt(mwfact) * mg.height
|
g.width = sqrt(mwfact) * mg.width
|
||||||
g.x = mg.x + (mg.width - g.width) / 2
|
g.height = sqrt(mwfact) * mg.height
|
||||||
g.y = mg.y + (mg.height - g.height) / 2
|
g.x = mg.x + (mg.width - g.width) / 2
|
||||||
|
g.y = mg.y + (mg.height - g.height) / 2
|
||||||
|
|
||||||
if c then c:geometry(g) end -- if c is still a valid object
|
if c then c:geometry(g) end -- if c is still a valid object
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Read the nice value of pid from /proc.
|
|
||||||
local function get_nice_value(pid)
|
|
||||||
local n = first_line('/proc/' .. pid .. '/stat')
|
|
||||||
if not n then return 0 end
|
|
||||||
|
|
||||||
-- Remove pid and tcomm. This is necessary because tcomm may contain
|
|
||||||
-- nasty stuff such as whitespace or additional parentheses...
|
|
||||||
n = string.gsub(n, '.*%) ', '')
|
|
||||||
|
|
||||||
-- Field number 17 now is the nice value.
|
|
||||||
fields = split(n, ' ')
|
|
||||||
return tonumber(fields[17])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- To be used as a signal handler for "focus"
|
|
||||||
-- This requires beautiful.border_focus{,_highprio,_lowprio}.
|
|
||||||
function util.niceborder_focus(c)
|
|
||||||
local n = get_nice_value(c.pid)
|
|
||||||
if n == 0
|
|
||||||
then
|
|
||||||
c.border_color = beautiful.border_focus
|
|
||||||
elseif n < 0
|
|
||||||
then
|
|
||||||
c.border_color = beautiful.border_focus_highprio
|
|
||||||
else
|
|
||||||
c.border_color = beautiful.border_focus_lowprio
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- To be used as a signal handler for "unfocus"
|
|
||||||
-- This requires beautiful.border_normal{,_highprio,_lowprio}.
|
|
||||||
function util.niceborder_unfocus(c)
|
|
||||||
local n = get_nice_value(c.pid)
|
|
||||||
if n == 0
|
|
||||||
then
|
|
||||||
c.border_color = beautiful.border_normal
|
|
||||||
elseif n < 0
|
|
||||||
then
|
|
||||||
c.border_color = beautiful.border_normal_highprio
|
|
||||||
else
|
|
||||||
c.border_color = beautiful.border_normal_lowprio
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Non-empty tag browsing
|
-- Non-empty tag browsing
|
||||||
-- direction in {-1, 1} <-> {previous, next} non-empty tag
|
-- direction in {-1, 1} <-> {previous, next} non-empty tag
|
||||||
function util.tag_view_nonempty(direction, sc)
|
function util.tag_view_nonempty(direction, sc)
|
||||||
local s = sc or mouse.screen or 1
|
local s = sc or awful.screen.focused()
|
||||||
local scr = screen[s]
|
|
||||||
|
|
||||||
for i = 1, #awful.tag.gettags(s) do
|
for i = 1, #s.tags do
|
||||||
awful.tag.viewidx(direction,s)
|
awful.tag.viewidx(direction, s)
|
||||||
if #awful.client.visible(s) > 0 then
|
if #s.clients > 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- {{{ Dynamic tagging
|
-- {{{ Dynamic tagging
|
||||||
--
|
|
||||||
-- Add a new tag
|
-- Add a new tag
|
||||||
function util.add_tag(mypromptbox)
|
function util.add_tag()
|
||||||
awful.prompt.run({prompt="New tag name: "}, mypromptbox[mouse.screen].widget,
|
awful.prompt.run {
|
||||||
function(text)
|
prompt = "New tag name: ",
|
||||||
if text:len() > 0 then
|
textbox = awful.screen.focused().mypromptbox.widget,
|
||||||
props = { selected = true }
|
exe_callback = function(name)
|
||||||
tag = awful.tag.add(new_name, props)
|
if not name or #name == 0 then return end
|
||||||
tag.name = text
|
awful.tag.add(name, { screen = awful.screen.focused() }):view_only()
|
||||||
tag:emit_signal("property::name")
|
|
||||||
end
|
end
|
||||||
end)
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Rename current tag
|
-- Rename current tag
|
||||||
-- @author: minism
|
function util.rename_tag()
|
||||||
function util.rename_tag(mypromptbox)
|
awful.prompt.run {
|
||||||
local tag = awful.tag.selected(mouse.screen)
|
prompt = "Rename tag: ",
|
||||||
awful.prompt.run({prompt="Rename tag: "}, mypromptbox[mouse.screen].widget,
|
textbox = awful.screen.focused().mypromptbox.widget,
|
||||||
function(text)
|
exe_callback = function(new_name)
|
||||||
if text:len() > 0 then
|
if not new_name or #new_name == 0 then return end
|
||||||
tag.name = text
|
local t = awful.screen.focused().selected_tag
|
||||||
tag:emit_signal("property::name")
|
if t then
|
||||||
|
t.name = new_name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Move current tag
|
-- Move current tag
|
||||||
-- pos in {-1, 1} <-> {previous, next} tag position
|
-- pos in {-1, 1} <-> {previous, next} tag position
|
||||||
function util.move_tag(pos)
|
function util.move_tag(pos)
|
||||||
local tag = awful.tag.selected(mouse.screen)
|
local tag = awful.screen.focused().selected_tag
|
||||||
local idx = awful.tag.getidx(tag)
|
|
||||||
if tonumber(pos) <= -1 then
|
if tonumber(pos) <= -1 then
|
||||||
awful.tag.move(idx - 1, tag)
|
awful.tag.move(tag.index - 1, tag)
|
||||||
else
|
else
|
||||||
awful.tag.move(idx + 1, tag)
|
awful.tag.move(tag.index + 1, tag)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove current tag (if empty)
|
-- Delete current tag
|
||||||
-- Any rule set on the tag shall be broken
|
-- Any rule set on the tag shall be broken
|
||||||
function util.remove_tag()
|
function util.delete_tag()
|
||||||
local tag = awful.tag.selected(mouse.screen)
|
local t = awful.screen.focused().selected_tag
|
||||||
local prevtag = awful.tag.gettags(mouse.screen)[awful.tag.getidx(tag) - 1]
|
if not t then return end
|
||||||
awful.tag.delete(tag, prevtag)
|
t:delete()
|
||||||
end
|
end
|
||||||
--
|
|
||||||
-- }}}
|
-- }}}
|
||||||
|
|
||||||
-- On the fly useless gaps change
|
-- On the fly useless gaps change
|
||||||
function util.useless_gaps_resize(thatmuch)
|
function util.useless_gaps_resize(thatmuch)
|
||||||
beautiful.useless_gap_width = tonumber(beautiful.useless_gap_width) + thatmuch
|
local scr = awful.screen.focused()
|
||||||
awful.layout.arrange(mouse.screen)
|
scr.selected_tag.gap = scr.selected_tag.gap + tonumber(thatmuch)
|
||||||
end
|
awful.layout.arrange(scr)
|
||||||
|
|
||||||
-- On the fly global border change
|
|
||||||
function util.global_border_resize(thatmuch)
|
|
||||||
beautiful.global_border_width = tonumber(beautiful.global_border_width) + thatmuch
|
|
||||||
awful.layout.arrange(mouse.screen)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Check if an element exist on a table
|
|
||||||
function util.element_in_table(element, tbl)
|
|
||||||
for _, i in pairs(tbl) do
|
|
||||||
if i == element then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(util, { __index = wrequire })
|
return setmetatable(util, { __index = wrequire })
|
||||||
|
|
|
@ -8,58 +8,56 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local beautiful = require("beautiful")
|
local string = { format = string.format }
|
||||||
local tostring = tostring
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Lain markup util submodule
|
-- Lain markup util submodule
|
||||||
-- lain.util.markup
|
-- lain.util.markup
|
||||||
local markup = {}
|
local markup = { fg = {}, bg = {} }
|
||||||
|
|
||||||
local fg = {}
|
|
||||||
local bg = {}
|
|
||||||
|
|
||||||
-- Convenience tags.
|
-- Convenience tags.
|
||||||
function markup.bold(text) return '<b>' .. tostring(text) .. '</b>' end
|
function markup.bold(text) return '<b>' .. text .. '</b>' end
|
||||||
function markup.italic(text) return '<i>' .. tostring(text) .. '</i>' end
|
function markup.italic(text) return '<i>' .. text .. '</i>' end
|
||||||
function markup.strike(text) return '<s>' .. tostring(text) .. '</s>' end
|
function markup.strike(text) return '<s>' .. text .. '</s>' end
|
||||||
function markup.underline(text) return '<u>' .. tostring(text) .. '</u>' end
|
function markup.underline(text) return '<u>' .. text .. '</u>' end
|
||||||
function markup.monospace(text) return '<tt>' .. tostring(text) .. '</tt>' end
|
function markup.monospace(text) return '<tt>' .. text .. '</tt>' end
|
||||||
function markup.big(text) return '<big>' .. tostring(text) .. '</big>' end
|
function markup.big(text) return '<big>' .. text .. '</big>' end
|
||||||
function markup.small(text) return '<small>' .. tostring(text) .. '</small>' end
|
function markup.small(text) return '<small>' .. text .. '</small>' end
|
||||||
|
|
||||||
-- Set the font.
|
-- Set the font.
|
||||||
function markup.font(font, text)
|
function markup.font(font, text)
|
||||||
return '<span font="' .. tostring(font) .. '">' .. tostring(text) ..'</span>'
|
return '<span font="' .. font .. '">' .. text ..'</span>'
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set the foreground.
|
-- Set the foreground.
|
||||||
function fg.color(color, text)
|
function markup.fg.color(color, text)
|
||||||
return '<span foreground="' .. tostring(color) .. '">' .. tostring(text) .. '</span>'
|
return '<span foreground="' .. color .. '">' .. text .. '</span>'
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set the background.
|
-- Set the background.
|
||||||
function bg.color(color, text)
|
function markup.bg.color(color, text)
|
||||||
return '<span background="' .. tostring(color) .. '">' .. tostring(text) .. '</span>'
|
return '<span background="' .. color .. '">' .. text .. '</span>'
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Context: focus
|
-- Set foreground and background.
|
||||||
function fg.focus(text) return fg.color(beautiful.fg_focus, text) end
|
function markup.color(fg, bg, text)
|
||||||
function bg.focus(text) return bg.color(beautiful.bg_focus, text) end
|
return string.format('<span foreground="%s" background="%s">%s</span>', fg, bg, text)
|
||||||
function markup.focus(text) return bg.focus(fg.focus(text)) end
|
end
|
||||||
|
|
||||||
-- Context: normal
|
-- Set font and foreground.
|
||||||
function fg.normal(text) return fg.color(beautiful.fg_normal, text) end
|
function markup.fontfg(font, fg, text)
|
||||||
function bg.normal(text) return bg.color(beautiful.bg_normal, text) end
|
return string.format('<span font="%s" foreground="%s">%s</span>', font, fg, text)
|
||||||
function markup.normal(text) return bg.normal(fg.normal(text)) end
|
end
|
||||||
|
|
||||||
-- Context: urgent
|
-- Set font and background.
|
||||||
function fg.urgent(text) return fg.color(beautiful.fg_urgent, text) end
|
function markup.fontbg(font, bg, text)
|
||||||
function bg.urgent(text) return bg.color(beautiful.bg_urgent, text) end
|
return string.format('<span font="%s" background="%s">%s</span>', font, bg, text)
|
||||||
function markup.urgent(text) return bg.urgent(fg.urgent(text)) end
|
end
|
||||||
|
|
||||||
markup.fg = fg
|
-- Set font, foreground and background.
|
||||||
markup.bg = bg
|
function markup.fontcolor(font, fg, bg, text)
|
||||||
|
return string.format('<span font="%s" foreground="%s" background="%s">%s</span>', font, fg, bg, text)
|
||||||
|
end
|
||||||
|
|
||||||
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
|
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
|
||||||
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end })
|
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end })
|
||||||
|
|
249
util/quake.lua
|
@ -3,22 +3,22 @@
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
Licensed under GNU General Public License v2
|
||||||
* (c) 2016, Luke Bonham
|
* (c) 2016, Luke Bonham
|
||||||
|
* (c) 2015, unknown
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local capi = { client = client,
|
local capi = { client = client }
|
||||||
mouse = mouse,
|
|
||||||
screen = screen,
|
local math = { floor = math.floor }
|
||||||
timer = timer }
|
local string = { format = string.format }
|
||||||
local string = string
|
|
||||||
|
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
|
local screen = screen
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
local tostring = tostring
|
|
||||||
|
|
||||||
-- Quake-like Dropdown application spawn
|
-- Quake-like Dropdown application spawn
|
||||||
-- Original version: https://awesomewm.org/wiki/Drop-down_terminal#Another_solution
|
|
||||||
local quake = {}
|
local quake = {}
|
||||||
|
|
||||||
-- If you have a rule like "awful.client.setslave" for your terminals,
|
-- If you have a rule like "awful.client.setslave" for your terminals,
|
||||||
|
@ -26,137 +26,144 @@ local quake = {}
|
||||||
-- run into problems with focus.
|
-- run into problems with focus.
|
||||||
|
|
||||||
function quake:display()
|
function quake:display()
|
||||||
-- First, we locate the client
|
if self.followtag then self.screen = awful.screen.focused() end
|
||||||
local client = nil
|
|
||||||
local i = 0
|
|
||||||
for c in awful.client.iterate(function (c)
|
|
||||||
-- c.name may be changed!
|
|
||||||
return c.instance == self.name
|
|
||||||
end, nil, self.screen)
|
|
||||||
do
|
|
||||||
i = i + 1
|
|
||||||
if i == 1 then
|
|
||||||
client = c
|
|
||||||
else
|
|
||||||
-- Additional matching clients, let's remove the sticky bit
|
|
||||||
-- which may persist between awesome restarts. We don't close
|
|
||||||
-- them as they may be valuable. They will just turn into
|
|
||||||
-- normal clients.
|
|
||||||
c.sticky = false
|
|
||||||
c.ontop = false
|
|
||||||
c.above = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not client and not self.visible then return end
|
-- First, we locate the client
|
||||||
|
local client = nil
|
||||||
|
local i = 0
|
||||||
|
for c in awful.client.iterate(function (c)
|
||||||
|
-- c.name may be changed!
|
||||||
|
return c.instance == self.name
|
||||||
|
end, nil, self.screen)
|
||||||
|
do
|
||||||
|
i = i + 1
|
||||||
|
if i == 1 then
|
||||||
|
client = c
|
||||||
|
else
|
||||||
|
-- Additional matching clients, let's remove the sticky bit
|
||||||
|
-- which may persist between awesome restarts. We don't close
|
||||||
|
-- them as they may be valuable. They will just turn into
|
||||||
|
-- normal clients.
|
||||||
|
c.sticky = false
|
||||||
|
c.ontop = false
|
||||||
|
c.above = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if not client then
|
if not client and not self.visible then return end
|
||||||
-- The client does not exist, we spawn it
|
|
||||||
awful.util.spawn(string.format("%s %s %s", self.app,
|
|
||||||
string.format(self.argname, self.name), self.extra),
|
|
||||||
false, self.screen)
|
|
||||||
self.notexist = true
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Resize
|
if not client then
|
||||||
awful.client.floating.set(client, true)
|
-- The client does not exist, we spawn it
|
||||||
client.border_width = self.border
|
cmd = string.format("%s %s %s", self.app,
|
||||||
client.size_hints_honor = false
|
string.format(self.argname, self.name), self.extra)
|
||||||
if self.notexist then
|
awful.spawn(cmd, { tag = self.screen.selected_tag })
|
||||||
client:geometry(self.geometry)
|
return
|
||||||
self.notexist = false
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- Not sticky and on top
|
-- Set geometry
|
||||||
client.ontop = true
|
client.floating = true
|
||||||
client.above = true
|
client.border_width = self.border
|
||||||
client.skip_taskbar = true
|
client.size_hints_honor = false
|
||||||
client.sticky = false
|
client:geometry(self:compute_size())
|
||||||
|
|
||||||
-- Toggle display
|
-- Set not sticky and on top
|
||||||
if self.visible then
|
client.sticky = false
|
||||||
client.hidden = false
|
client.ontop = true
|
||||||
client:raise()
|
client.above = true
|
||||||
self.last_tag = tostring(awful.tag.selected(self.screen))
|
client.skip_taskbar = true
|
||||||
client:tags({awful.tag.selected(self.screen)})
|
|
||||||
capi.client.focus = client
|
-- Additional user settings
|
||||||
|
if self.settings then self.settings(client) end
|
||||||
|
|
||||||
|
-- Toggle display
|
||||||
|
if self.visible then
|
||||||
|
client.hidden = false
|
||||||
|
client:raise()
|
||||||
|
self.last_tag = self.screen.selected_tag
|
||||||
|
client:tags({self.screen.selected_tag})
|
||||||
|
capi.client.focus = client
|
||||||
else
|
else
|
||||||
client.hidden = true
|
client.hidden = true
|
||||||
local ctags = client:tags()
|
local ctags = client:tags()
|
||||||
for i, t in pairs(ctags) do
|
for i, t in pairs(ctags) do
|
||||||
ctags[i] = nil
|
ctags[i] = nil
|
||||||
end
|
end
|
||||||
client:tags(ctags)
|
client:tags(ctags)
|
||||||
end
|
end
|
||||||
|
|
||||||
return client
|
return client
|
||||||
|
end
|
||||||
|
|
||||||
|
function quake:compute_size()
|
||||||
|
-- skip if we already have a geometry for this screen
|
||||||
|
if not self.geometry[self.screen] then
|
||||||
|
local geom
|
||||||
|
if not self.overlap then
|
||||||
|
geom = screen[self.screen].workarea
|
||||||
|
else
|
||||||
|
geom = screen[self.screen].geometry
|
||||||
|
end
|
||||||
|
local width, height = self.width, self.height
|
||||||
|
if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
|
||||||
|
if height <= 1 then height = math.floor(geom.height * height) end
|
||||||
|
local x, y
|
||||||
|
if self.horiz == "left" then x = geom.x
|
||||||
|
elseif self.horiz == "right" then x = geom.width + geom.x - width
|
||||||
|
else x = geom.x + (geom.width - width)/2 end
|
||||||
|
if self.vert == "top" then y = geom.y
|
||||||
|
elseif self.vert == "bottom" then y = geom.height + geom.y - height
|
||||||
|
else y = geom.y + (geom.height - height)/2 end
|
||||||
|
self.geometry[self.screen] = { x = x, y = y, width = width, height = height }
|
||||||
|
end
|
||||||
|
return self.geometry[self.screen]
|
||||||
end
|
end
|
||||||
|
|
||||||
function quake:new(config)
|
function quake:new(config)
|
||||||
local conf = config or {}
|
local conf = config or {}
|
||||||
|
|
||||||
conf.app = conf.app or "xterm" -- application to spawn
|
conf.app = conf.app or "xterm" -- application to spawn
|
||||||
conf.name = conf.name or "QuakeDD" -- window name
|
conf.name = conf.name or "QuakeDD" -- window name
|
||||||
conf.argname = conf.argname or "-name %s" -- how to specify window name
|
conf.argname = conf.argname or "-name %s" -- how to specify window name
|
||||||
conf.extra = conf.extra or "" -- extra arguments
|
conf.extra = conf.extra or "" -- extra arguments
|
||||||
conf.visible = conf.visible or false -- initially not visible
|
conf.border = conf.border or 1 -- client border width
|
||||||
conf.screen = conf.screen or capi.mouse.screen
|
conf.visible = conf.visible or false -- initially not visible
|
||||||
conf.border = conf.border or 1
|
conf.followtag = conf.followtag or false -- spawn on currently focused screen
|
||||||
|
conf.overlap = conf.overlap or false -- overlap wibox
|
||||||
|
conf.screen = conf.screen or awful.screen.focused()
|
||||||
|
conf.settings = conf.settings
|
||||||
|
|
||||||
-- If width or height <= 1 this is a proportion of the workspace
|
-- If width or height <= 1 this is a proportion of the workspace
|
||||||
wibox_height = conf.wibox_height or 18 -- statusbar weight
|
conf.height = conf.height or 0.25 -- height
|
||||||
height = conf.height or 0.25 -- height
|
conf.width = conf.width or 1 -- width
|
||||||
width = conf.width or 1 -- width
|
conf.vert = conf.vert or "top" -- top, bottom or center
|
||||||
vert = conf.vert or "top" -- top, bottom or center
|
conf.horiz = conf.horiz or "left" -- left, right or center
|
||||||
horiz = conf.horiz or "center" -- left, right or center
|
conf.geometry = {} -- internal use
|
||||||
|
|
||||||
-- Compute size
|
local dropdown = setmetatable(conf, { __index = quake })
|
||||||
local geom = capi.screen[conf.screen].workarea
|
|
||||||
if width <= 1 then width = geom.width * width end
|
|
||||||
if height <= 1 then height = geom.height * height end
|
|
||||||
local x, y
|
|
||||||
if horiz == "left" then x = geom.x
|
|
||||||
elseif horiz == "right" then x = geom.width + geom.x - width
|
|
||||||
else x = geom.x + (geom.width - width)/2 end
|
|
||||||
if vert == "top" then y = geom.y
|
|
||||||
elseif vert == "bottom" then y = geom.height + geom.y - height
|
|
||||||
else y = geom.y + (geom.height - height)/2 end
|
|
||||||
conf.geometry = { x = x, y = y + wibox_height, width = width, height = height }
|
|
||||||
|
|
||||||
local console = setmetatable(conf, { __index = quake })
|
capi.client.connect_signal("manage", function(c)
|
||||||
capi.client.connect_signal("manage", function(c)
|
if c.instance == dropdown.name and c.screen == dropdown.screen then
|
||||||
if c.instance == console.name and c.screen == console.screen then
|
dropdown:display()
|
||||||
console:display()
|
end
|
||||||
end
|
|
||||||
end)
|
|
||||||
capi.client.connect_signal("unmanage", function(c)
|
|
||||||
if c.instance == console.name and c.screen == console.screen then
|
|
||||||
console.visible = false
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
capi.client.connect_signal("unmanage", function(c)
|
||||||
|
if c.instance == dropdown.name and c.screen == dropdown.screen then
|
||||||
|
dropdown.visible = false
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
-- "Reattach" currently running quake application. This is in case awesome is restarted.
|
return dropdown
|
||||||
local reattach = capi.timer { timeout = 0 }
|
|
||||||
reattach:connect_signal("timeout", function()
|
|
||||||
reattach:stop()
|
|
||||||
console:display()
|
|
||||||
end)
|
|
||||||
reattach:start()
|
|
||||||
|
|
||||||
return console
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function quake:toggle()
|
function quake:toggle()
|
||||||
current_tag = awful.tag.selected(self.screen)
|
if self.followtag then self.screen = awful.screen.focused() end
|
||||||
if self.last_tag ~= tostring(current_tag) and self.visible then
|
local current_tag = self.screen.selected_tag
|
||||||
awful.client.movetotag(current_tag, self:display())
|
if current_tag and self.last_tag ~= current_tag and self.visible then
|
||||||
else
|
self:display():move_to_tag(current_tag)
|
||||||
self.visible = not self.visible
|
else
|
||||||
self:display()
|
self.visible = not self.visible
|
||||||
end
|
self:display()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })
|
return setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })
|
||||||
|
|
||||||
return quake
|
|
||||||
|
|
|
@ -8,15 +8,11 @@
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local gears = require("gears")
|
local gears = require("gears")
|
||||||
|
|
||||||
-- Lain Cairo separators util submodule
|
-- Lain Cairo separators util submodule
|
||||||
-- lain.util.separators
|
-- lain.util.separators
|
||||||
local separators = {}
|
local separators = { height = 0, width = 9 }
|
||||||
|
|
||||||
local height = beautiful.awful_widget_height or 0
|
|
||||||
local width = beautiful.separators_width or 9
|
|
||||||
|
|
||||||
-- [[ Arrow
|
-- [[ Arrow
|
||||||
|
|
||||||
|
@ -24,7 +20,9 @@ local width = beautiful.separators_width or 9
|
||||||
function separators.arrow_right(col1, col2)
|
function separators.arrow_right(col1, col2)
|
||||||
local widget = wibox.widget.base.make_widget()
|
local widget = wibox.widget.base.make_widget()
|
||||||
|
|
||||||
widget.fit = function(m, w, h) return width, height end
|
widget.fit = function(m, w, h)
|
||||||
|
return separators.width, separators.height
|
||||||
|
end
|
||||||
|
|
||||||
widget.draw = function(mycross, wibox, cr, width, height)
|
widget.draw = function(mycross, wibox, cr, width, height)
|
||||||
if col2 ~= "alpha" then
|
if col2 ~= "alpha" then
|
||||||
|
@ -62,7 +60,9 @@ end
|
||||||
function separators.arrow_left(col1, col2)
|
function separators.arrow_left(col1, col2)
|
||||||
local widget = wibox.widget.base.make_widget()
|
local widget = wibox.widget.base.make_widget()
|
||||||
|
|
||||||
widget.fit = function(m, w, h) return width, height end
|
widget.fit = function(m, w, h)
|
||||||
|
return separators.width, separators.height
|
||||||
|
end
|
||||||
|
|
||||||
widget.draw = function(mycross, wibox, cr, width, height)
|
widget.draw = function(mycross, wibox, cr, width, height)
|
||||||
if col1 ~= "alpha" then
|
if col1 ~= "alpha" then
|
||||||
|
|
|
@ -6,27 +6,26 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
local async = require("lain.asyncshell")
|
local textbox = require("wibox.widget.textbox")
|
||||||
local wibox = require("wibox")
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Basic template for custom widgets
|
-- Template for custom asynchronous widgets
|
||||||
-- Asynchronous version
|
|
||||||
-- lain.widgets.abase
|
-- lain.widgets.abase
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local abase = {}
|
local abase = {}
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 5
|
local timeout = args.timeout or 5
|
||||||
local cmd = args.cmd or ""
|
local nostart = args.nostart or false
|
||||||
local settings = args.settings or function() end
|
local stoppable = args.stoppable or false
|
||||||
|
local cmd = args.cmd
|
||||||
|
local settings = args.settings or function() widget:set_text(output) end
|
||||||
|
|
||||||
abase.widget = wibox.widget.textbox('')
|
abase.widget = args.widget or textbox()
|
||||||
|
|
||||||
function abase.update()
|
function abase.update()
|
||||||
async.request(cmd, function(f)
|
helpers.async(cmd, function(f)
|
||||||
output = f
|
output = f
|
||||||
if output ~= abase.prev then
|
if output ~= abase.prev then
|
||||||
widget = abase.widget
|
widget = abase.widget
|
||||||
|
@ -36,9 +35,9 @@ local function worker(args)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer(cmd, timeout, abase.update)
|
abase.timer = helpers.newtimer(cmd, timeout, abase.update, nostart, stoppable)
|
||||||
|
|
||||||
return setmetatable(abase, { __index = abase.widget })
|
return abase
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -7,21 +7,18 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
local shell = require("awful.util").shell
|
||||||
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local string = { match = string.match,
|
local string = { match = string.match,
|
||||||
format = string.format }
|
format = string.format }
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- ALSA volume
|
-- ALSA volume
|
||||||
-- lain.widgets.alsa
|
-- lain.widgets.alsa
|
||||||
local alsa = { last_level = "0", last_status = "" }
|
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
|
local alsa = { widget = wibox.widget.textbox() }
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 5
|
local timeout = args.timeout or 5
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
@ -29,31 +26,31 @@ local function worker(args)
|
||||||
alsa.cmd = args.cmd or "amixer"
|
alsa.cmd = args.cmd or "amixer"
|
||||||
alsa.channel = args.channel or "Master"
|
alsa.channel = args.channel or "Master"
|
||||||
alsa.togglechannel = args.togglechannel
|
alsa.togglechannel = args.togglechannel
|
||||||
alsa.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
function alsa.update()
|
local format_cmd = string.format("%s get %s", alsa.cmd, alsa.channel)
|
||||||
mixer = read_pipe(string.format("%s get %s", alsa.cmd, alsa.channel))
|
|
||||||
l,s = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
|
||||||
|
|
||||||
-- HDMIs can have a channel different from Master for toggling mute
|
if alsa.togglechannel then
|
||||||
if alsa.togglechannel then
|
format_cmd = { shell, "-c", string.format("%s get %s; %s get %s",
|
||||||
s = string.match(read_pipe(string.format("%s get %s", alsa.cmd, alsa.togglechannel)), "%[(%a+)%]")
|
alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel) }
|
||||||
end
|
|
||||||
|
|
||||||
if alsa.last_level ~= l or alsa.last_status ~= s then
|
|
||||||
volume_now = { level = l, status = s }
|
|
||||||
alsa.last_level = l
|
|
||||||
alsa.last_status = s
|
|
||||||
|
|
||||||
widget = alsa.widget
|
|
||||||
settings()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
timer_id = string.format("alsa-%s-%s", alsa.cmd, alsa.channel)
|
alsa.last = {}
|
||||||
newtimer(timer_id, timeout, alsa.update)
|
|
||||||
|
|
||||||
return setmetatable(alsa, { __index = alsa.widget })
|
function alsa.update()
|
||||||
|
helpers.async(format_cmd, function(mixer)
|
||||||
|
local l,s = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
||||||
|
if alsa.last.level ~= l or alsa.last.status ~= s then
|
||||||
|
volume_now = { level = l, status = s }
|
||||||
|
widget = alsa.widget
|
||||||
|
settings()
|
||||||
|
alsa.last = volume_now
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
helpers.newtimer(string.format("alsa-%s-%s", alsa.cmd, alsa.channel), timeout, alsa.update)
|
||||||
|
|
||||||
|
return alsa
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(alsa, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -7,179 +7,130 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
|
||||||
|
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
|
local wibox = require("wibox")
|
||||||
local math = { modf = math.modf }
|
local math = { modf = math.modf }
|
||||||
local mouse = mouse
|
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
match = string.match,
|
match = string.match,
|
||||||
rep = string.rep }
|
rep = string.rep }
|
||||||
|
local type = type
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- ALSA volume bar
|
-- ALSA volume bar
|
||||||
-- lain.widgets.alsabar
|
-- lain.widgets.alsabar
|
||||||
local alsabar = {
|
local alsabar = {
|
||||||
channel = "Master",
|
|
||||||
step = "1%",
|
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
background = beautiful.bg_normal,
|
background = "#000000",
|
||||||
mute = "#EB8F8F",
|
mute = "#EB8F8F",
|
||||||
unmute = "#A4CE8A"
|
unmute = "#A4CE8A"
|
||||||
},
|
},
|
||||||
|
|
||||||
terminal = terminal or "xterm",
|
|
||||||
mixer = terminal .. " -e alsamixer",
|
|
||||||
|
|
||||||
notifications = {
|
|
||||||
font = beautiful.font:sub(beautiful.font:find(""), beautiful.font:find(" ")),
|
|
||||||
font_size = "11",
|
|
||||||
color = beautiful.fg_normal,
|
|
||||||
bar_size = 18,
|
|
||||||
screen = 1
|
|
||||||
},
|
|
||||||
|
|
||||||
_current_level = 0,
|
_current_level = 0,
|
||||||
_muted = false
|
_muted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function alsabar.notify()
|
|
||||||
alsabar.update()
|
|
||||||
|
|
||||||
local preset = {
|
|
||||||
title = "",
|
|
||||||
text = "",
|
|
||||||
timeout = 5,
|
|
||||||
screen = alsabar.notifications.screen,
|
|
||||||
font = alsabar.notifications.font .. " " ..
|
|
||||||
alsabar.notifications.font_size,
|
|
||||||
fg = alsabar.notifications.color
|
|
||||||
}
|
|
||||||
|
|
||||||
if alsabar._muted
|
|
||||||
then
|
|
||||||
preset.title = alsabar.channel .. " - Muted"
|
|
||||||
else
|
|
||||||
preset.title = alsabar.channel .. " - " .. alsabar._current_level .. "%"
|
|
||||||
end
|
|
||||||
|
|
||||||
int = math.modf((alsabar._current_level / 100) * alsabar.notifications.bar_size)
|
|
||||||
preset.text = "["
|
|
||||||
.. string.rep("|", int)
|
|
||||||
.. string.rep(" ", alsabar.notifications.bar_size - int)
|
|
||||||
.. "]"
|
|
||||||
|
|
||||||
if alsabar.followmouse then
|
|
||||||
preset.screen = mouse.screen
|
|
||||||
end
|
|
||||||
|
|
||||||
if alsabar._notify ~= nil then
|
|
||||||
alsabar._notify = naughty.notify ({
|
|
||||||
replaces_id = alsabar._notify.id,
|
|
||||||
preset = preset,
|
|
||||||
})
|
|
||||||
else
|
|
||||||
alsabar._notify = naughty.notify ({
|
|
||||||
preset = preset,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 5
|
local timeout = args.timeout or 5
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
local width = args.width or 63
|
local width = args.width or 63
|
||||||
local height = args.heigth or 1
|
local height = args.height or 1
|
||||||
local ticks = args.ticks or false
|
local ticks = args.ticks or false
|
||||||
local ticks_size = args.ticks_size or 7
|
local ticks_size = args.ticks_size or 7
|
||||||
local vertical = args.vertical or false
|
local vertical = args.vertical or false
|
||||||
|
|
||||||
alsabar.cmd = args.cmd or "amixer"
|
alsabar.cmd = args.cmd or "amixer"
|
||||||
alsabar.channel = args.channel or alsabar.channel
|
alsabar.channel = args.channel or "Master"
|
||||||
alsabar.togglechannel = args.togglechannel
|
alsabar.togglechannel = args.togglechannel
|
||||||
alsabar.step = args.step or alsabar.step
|
alsabar.colors = args.colors or alsabar.colors
|
||||||
alsabar.colors = args.colors or alsabar.colors
|
alsabar.followtag = args.followtag or false
|
||||||
alsabar.notifications = args.notifications or alsabar.notifications
|
alsabar.notification_preset = args.notification_preset
|
||||||
alsabar.followmouse = args.followmouse or false
|
|
||||||
|
|
||||||
alsabar.bar = awful.widget.progressbar()
|
if not alsabar.notification_preset then
|
||||||
|
alsabar.notification_preset = {}
|
||||||
alsabar.bar:set_background_color(alsabar.colors.background)
|
alsabar.notification_preset.font = "Monospace 10"
|
||||||
alsabar.bar:set_color(alsabar.colors.unmute)
|
|
||||||
alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
|
|
||||||
alsabar.bar:set_width(width)
|
|
||||||
alsabar.bar:set_height(height)
|
|
||||||
alsabar.bar:set_ticks(ticks)
|
|
||||||
alsabar.bar:set_ticks_size(ticks_size)
|
|
||||||
alsabar.bar:set_vertical(vertical)
|
|
||||||
|
|
||||||
function alsabar.update()
|
|
||||||
-- Get mixer control contents
|
|
||||||
local mixer = read_pipe(string.format("%s get %s", alsabar.cmd, alsabar.channel))
|
|
||||||
|
|
||||||
-- Capture mixer control state: [5%] ... ... [on]
|
|
||||||
local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
|
||||||
|
|
||||||
-- HDMIs can have a channel different from Master for toggling mute
|
|
||||||
if alsabar.togglechannel then
|
|
||||||
mute = string.match(read_pipe(string.format("%s get %s", alsabar.cmd, alsabar.togglechannel)), "%[(%a+)%]")
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
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] ")
|
|
||||||
alsabar.bar:set_color(alsabar.colors.mute)
|
|
||||||
else
|
|
||||||
alsabar._muted = false
|
|
||||||
alsabar.tooltip:set_text(string.format(" %s:%s ", alsabar.channel, volu))
|
|
||||||
alsabar.bar:set_color(alsabar.colors.unmute)
|
|
||||||
end
|
|
||||||
|
|
||||||
volume_now = {}
|
|
||||||
volume_now.level = tonumber(volu)
|
|
||||||
volume_now.status = mute
|
|
||||||
settings()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
alsabar.bar:buttons(awful.util.table.join (
|
local format_cmd = string.format("%s get %s", alsabar.cmd, alsabar.channel)
|
||||||
awful.button({}, 1, function()
|
|
||||||
awful.util.spawn(alsabar.mixer)
|
|
||||||
end),
|
|
||||||
awful.button({}, 2, function()
|
|
||||||
awful.util.spawn(string.format("%s set %s 100%%", alsabar.cmd, alsabar.channel))
|
|
||||||
pulsebar.update()
|
|
||||||
end),
|
|
||||||
awful.button({}, 3, function()
|
|
||||||
awful.util.spawn(string.format("%s set %s toggle", alsabar.cmd, alsabar.channel))
|
|
||||||
alsabar.update()
|
|
||||||
end),
|
|
||||||
awful.button({}, 4, function()
|
|
||||||
awful.util.spawn(string.format("%s set %s %s+", alsabar.cmd, alsabar.channel, alsabar.step))
|
|
||||||
alsabar.update()
|
|
||||||
end),
|
|
||||||
awful.button({}, 5, function()
|
|
||||||
awful.util.spawn(string.format("%s set %s %s-", alsabar.cmd, alsabar.channel, alsabar.step))
|
|
||||||
alsabar.update()
|
|
||||||
end)
|
|
||||||
))
|
|
||||||
|
|
||||||
timer_id = string.format("alsabar-%s-%s", alsabar.cmd, alsabar.channel)
|
if alsabar.togglechannel then
|
||||||
|
format_cmd = { awful.util.shell, "-c", string.format("%s get %s; %s get %s",
|
||||||
|
alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel) }
|
||||||
|
end
|
||||||
|
|
||||||
newtimer(timer_id, timeout, alsabar.update)
|
alsabar.bar = wibox.widget {
|
||||||
|
forced_height = height,
|
||||||
|
forced_width = width,
|
||||||
|
color = alsabar.colors.unmute,
|
||||||
|
background_color = alsabar.colors.background,
|
||||||
|
margins = 1,
|
||||||
|
paddings = 1,
|
||||||
|
ticks = ticks,
|
||||||
|
ticks_size = ticks_size,
|
||||||
|
widget = wibox.widget.progressbar,
|
||||||
|
layout = vertical and wibox.container.rotate
|
||||||
|
}
|
||||||
|
|
||||||
|
alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
|
||||||
|
|
||||||
|
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
|
||||||
|
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]")
|
||||||
|
alsabar.bar.color = alsabar.colors.mute
|
||||||
|
else
|
||||||
|
alsabar._muted = false
|
||||||
|
alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, volu))
|
||||||
|
alsabar.bar.color = alsabar.colors.unmute
|
||||||
|
end
|
||||||
|
|
||||||
|
volume_now = {}
|
||||||
|
volume_now.level = tonumber(volu)
|
||||||
|
volume_now.status = mute
|
||||||
|
|
||||||
|
settings()
|
||||||
|
|
||||||
|
if type(callback) == "function" then callback() end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function alsabar.notify()
|
||||||
|
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)
|
||||||
|
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))
|
||||||
|
|
||||||
|
if alsabar.followtag then preset.screen = awful.screen.focused() end
|
||||||
|
|
||||||
|
if not alsabar.notification then
|
||||||
|
alsabar.notification = naughty.notify {
|
||||||
|
preset = preset,
|
||||||
|
destroy = function() alsabar.notification = nil end
|
||||||
|
}
|
||||||
|
else
|
||||||
|
naughty.replace_text(alsabar.notification, preset.title, preset.text)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
helpers.newtimer(string.format("alsabar-%s-%s", alsabar.cmd, alsabar.channel), timeout, alsabar.update)
|
||||||
|
|
||||||
return alsabar
|
return alsabar
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2014, Luke Bonham
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
|
||||||
|
|
||||||
local wibox = require("wibox")
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
-- Basic template for custom widgets
|
|
||||||
-- lain.widgets.base
|
|
||||||
|
|
||||||
local function worker(args)
|
|
||||||
local base = {}
|
|
||||||
local args = args or {}
|
|
||||||
local timeout = args.timeout or 5
|
|
||||||
local cmd = args.cmd or ""
|
|
||||||
local settings = args.settings or function() end
|
|
||||||
|
|
||||||
base.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
function base.update()
|
|
||||||
output = read_pipe(cmd)
|
|
||||||
if output ~= base.prev then
|
|
||||||
widget = base.widget
|
|
||||||
settings()
|
|
||||||
base.prev = output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
newtimer(cmd, timeout, base.update)
|
|
||||||
|
|
||||||
return setmetatable(base, { __index = base.widget })
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
|
|
@ -7,18 +7,16 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
|
||||||
local first_line = require("lain.helpers").first_line
|
local first_line = require("lain.helpers").first_line
|
||||||
|
local newtimer = require("lain.helpers").newtimer
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local math = { abs = math.abs,
|
local math = { abs = math.abs,
|
||||||
floor = math.floor,
|
floor = math.floor,
|
||||||
log10 = math.log10,
|
log10 = math.log10,
|
||||||
min = math.min }
|
min = math.min }
|
||||||
local string = { format = string.format }
|
local string = { format = string.format }
|
||||||
|
local ipairs = ipairs
|
||||||
local type = type
|
local type = type
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
@ -27,7 +25,7 @@ local setmetatable = setmetatable
|
||||||
-- lain.widgets.bat
|
-- lain.widgets.bat
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local bat = {}
|
local bat = { widget = wibox.widget.textbox() }
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 30
|
local timeout = args.timeout or 30
|
||||||
local batteries = args.batteries or (args.battery and {args.battery}) or {"BAT0"}
|
local batteries = args.batteries or (args.battery and {args.battery}) or {"BAT0"}
|
||||||
|
@ -35,8 +33,6 @@ local function worker(args)
|
||||||
local notify = args.notify or "on"
|
local notify = args.notify or "on"
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
bat.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
bat_notification_low_preset = {
|
bat_notification_low_preset = {
|
||||||
title = "Battery low",
|
title = "Battery low",
|
||||||
text = "Plug the cable!",
|
text = "Plug the cable!",
|
||||||
|
@ -110,35 +106,48 @@ local function worker(args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- When one of the battery is charging, others' status are either
|
||||||
|
-- "Full", "Unknown" or "Charging". When the laptop is not plugged in,
|
||||||
|
-- one or more of the batteries may be full, but only one battery
|
||||||
|
-- discharging suffices to set global status to "Discharging".
|
||||||
bat_now.status = bat_now.n_status[1]
|
bat_now.status = bat_now.n_status[1]
|
||||||
|
for _,status in ipairs(bat_now.n_status) do
|
||||||
|
if status == "Discharging" or status == "Charging" then
|
||||||
|
bat_now.status = status
|
||||||
|
end
|
||||||
|
end
|
||||||
bat_now.ac_status = tonumber(first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
|
bat_now.ac_status = tonumber(first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
|
||||||
|
|
||||||
if bat_now.status ~= "N/A" then
|
if bat_now.status ~= "N/A" then
|
||||||
|
if bat_now.status ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 then
|
||||||
|
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
|
||||||
|
bat_now.time = "00:00"
|
||||||
|
bat_now.watt = 0
|
||||||
|
|
||||||
-- update {perc,time,watt} iff battery not full and rate > 0
|
-- update {perc,time,watt} iff battery not full and rate > 0
|
||||||
if bat_now.status ~= "Full" and (sum_rate_power > 0 or sum_rate_current > 0) then
|
elseif bat_now.status ~= "Full" then
|
||||||
local rate_time = 0
|
local rate_time = 0
|
||||||
local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
|
-- Calculate time and watt if rates are greater then 0
|
||||||
|
if (sum_rate_power > 0 or sum_rate_current > 0) then
|
||||||
|
local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
|
||||||
|
|
||||||
if bat_now.status == "Charging" then
|
if bat_now.status == "Charging" then
|
||||||
rate_time = (sum_energy_full - sum_energy_now) / div
|
rate_time = (sum_energy_full - sum_energy_now) / div
|
||||||
else -- Discharging
|
else -- Discharging
|
||||||
rate_time = sum_energy_now / div
|
rate_time = sum_energy_now / div
|
||||||
end
|
end
|
||||||
|
|
||||||
if 0 < rate_time and rate_time < 0.01 then -- check for magnitude discrepancies (#199)
|
if 0 < rate_time and rate_time < 0.01 then -- check for magnitude discrepancies (#199)
|
||||||
rate_time_magnitude = math.abs(math.floor(math.log10(rate_time)))
|
rate_time_magnitude = math.abs(math.floor(math.log10(rate_time)))
|
||||||
rate_time = rate_time * 10^(rate_time_magnitude - 2)
|
rate_time = rate_time * 10^(rate_time_magnitude - 2)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local hours = math.floor(rate_time)
|
local hours = math.floor(rate_time)
|
||||||
local minutes = math.floor((rate_time - hours) * 60)
|
local minutes = math.floor((rate_time - hours) * 60)
|
||||||
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
|
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
|
||||||
bat_now.time = string.format("%02d:%02d", hours, minutes)
|
bat_now.time = string.format("%02d:%02d", hours, minutes)
|
||||||
bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6))
|
bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6))
|
||||||
elseif bat_now.status ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 then
|
|
||||||
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
|
|
||||||
bat_now.time = "00:00"
|
|
||||||
bat_now.watt = 0
|
|
||||||
elseif bat_now.status == "Full" then
|
elseif bat_now.status == "Full" then
|
||||||
bat_now.perc = 100
|
bat_now.perc = 100
|
||||||
bat_now.time = "00:00"
|
bat_now.time = "00:00"
|
||||||
|
@ -165,9 +174,9 @@ local function worker(args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer(battery, timeout, bat.update)
|
newtimer("batteries", timeout, bat.update)
|
||||||
|
|
||||||
return setmetatable(bat, { __index = bat.widget })
|
return bat
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local wibox = require("awful.wibox")
|
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
-- Creates a thin wibox at a position relative to another wibox
|
|
||||||
-- lain.widgets.borderbox
|
|
||||||
local borderbox = {}
|
|
||||||
|
|
||||||
local function worker(relbox, s, args)
|
|
||||||
local where = args.position or 'top'
|
|
||||||
local color = args.color or '#FFFFFF'
|
|
||||||
local size = args.size or 1
|
|
||||||
local box = nil
|
|
||||||
local wiboxarg = { position = nil, bg = color }
|
|
||||||
|
|
||||||
if where == 'top'
|
|
||||||
then
|
|
||||||
wiboxarg.width = relbox.width
|
|
||||||
wiboxarg.height = size
|
|
||||||
box = wibox(wiboxarg)
|
|
||||||
box.x = relbox.x
|
|
||||||
box.y = relbox.y - size
|
|
||||||
elseif where == 'bottom'
|
|
||||||
then
|
|
||||||
wiboxarg.width = relbox.width
|
|
||||||
wiboxarg.height = size
|
|
||||||
box = wibox(wiboxarg)
|
|
||||||
box.x = relbox.x
|
|
||||||
box.y = relbox.y + relbox.height
|
|
||||||
elseif where == 'left'
|
|
||||||
then
|
|
||||||
wiboxarg.width = size
|
|
||||||
wiboxarg.height = relbox.height
|
|
||||||
box = wibox(wiboxarg)
|
|
||||||
box.x = relbox.x - size
|
|
||||||
box.y = relbox.y
|
|
||||||
elseif where == 'right'
|
|
||||||
then
|
|
||||||
wiboxarg.width = size
|
|
||||||
wiboxarg.height = relbox.height
|
|
||||||
box = wibox(wiboxarg)
|
|
||||||
box.x = relbox.x + relbox.width
|
|
||||||
box.y = relbox.y
|
|
||||||
end
|
|
||||||
|
|
||||||
box.screen = s
|
|
||||||
return box
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable(borderbox, { __call = function(_, ...) return worker(...) end })
|
|
|
@ -6,54 +6,43 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local icons_dir = require("lain.helpers").icons_dir
|
local helpers = require("lain.helpers")
|
||||||
|
local markup = require("lain.util.markup")
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
|
local os = { date = os.date }
|
||||||
local io = { popen = io.popen }
|
|
||||||
local os = { date = os.date }
|
|
||||||
local mouse = mouse
|
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
sub = string.sub,
|
|
||||||
gsub = string.gsub }
|
gsub = string.gsub }
|
||||||
|
local ipairs = ipairs
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Calendar notification
|
-- Calendar notification
|
||||||
-- lain.widgets.calendar
|
-- lain.widgets.calendar
|
||||||
local calendar = {}
|
local calendar = { offset = 0 }
|
||||||
local cal_notification = nil
|
|
||||||
|
|
||||||
function calendar.hide()
|
function calendar.hide()
|
||||||
if cal_notification ~= nil then
|
if not calendar.notification then return end
|
||||||
naughty.destroy(cal_notification)
|
naughty.destroy(calendar.notification)
|
||||||
cal_notification = nil
|
calendar.notification = nil
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function calendar.show(t_out, inc_offset, scr)
|
function calendar.show(t_out, inc_offset, scr)
|
||||||
calendar.hide()
|
local today = os.date("%e")
|
||||||
|
local offs = inc_offset or 0
|
||||||
local f, c_text
|
local f
|
||||||
local offs = inc_offset or 0
|
|
||||||
local tims = t_out or 0
|
|
||||||
local today = tonumber(os.date('%d'))
|
|
||||||
|
|
||||||
calendar.offset = calendar.offset + offs
|
calendar.offset = calendar.offset + offs
|
||||||
|
|
||||||
if offs == 0 or calendar.offset == 0
|
local current_month = (offs == 0 or calendar.offset == 0)
|
||||||
then -- current month showing, today highlighted
|
|
||||||
calendar.offset = 0
|
|
||||||
calendar.notify_icon = calendar.icons .. today .. ".png"
|
|
||||||
|
|
||||||
-- bg and fg inverted to highlight today
|
if current_month then -- today highlighted
|
||||||
f = io.popen(calendar.cal_format(today))
|
calendar.offset = 0
|
||||||
|
calendar.notify_icon = string.format("%s%s.png", calendar.icons, tonumber(today))
|
||||||
|
f = calendar.cal
|
||||||
else -- no current month showing, no day to highlight
|
else -- no current month showing, no day to highlight
|
||||||
local month = tonumber(os.date('%m'))
|
local month = tonumber(os.date("%m"))
|
||||||
local year = tonumber(os.date('%Y'))
|
local year = tonumber(os.date("%Y"))
|
||||||
|
|
||||||
month = month + calendar.offset
|
month = month + calendar.offset
|
||||||
|
|
||||||
|
@ -68,55 +57,30 @@ function calendar.show(t_out, inc_offset, scr)
|
||||||
end
|
end
|
||||||
|
|
||||||
calendar.notify_icon = nil
|
calendar.notify_icon = nil
|
||||||
f = io.popen(string.format('%s %s %s', calendar.cal, month, year))
|
f = string.format("%s %s %s", calendar.cal, month, year)
|
||||||
end
|
end
|
||||||
|
|
||||||
c_text = "<tt><span font='" .. calendar.font .. " "
|
if calendar.followtag then
|
||||||
.. calendar.font_size .. "'><b>"
|
calendar.notification_preset.screen = awful.screen.focused()
|
||||||
.. f:read() .. "</b>\n\n"
|
|
||||||
.. f:read() .. "\n"
|
|
||||||
.. f:read("*all"):gsub("\n*$", "")
|
|
||||||
.. "</span></tt>"
|
|
||||||
f:close()
|
|
||||||
|
|
||||||
if calendar.followmouse then
|
|
||||||
scrp = mouse.screen
|
|
||||||
else
|
else
|
||||||
scrp = scr or calendar.scr_pos
|
calendar.notification_preset.screen = src or 1
|
||||||
end
|
end
|
||||||
|
|
||||||
cal_notification = naughty.notify({
|
helpers.async(f, function(ws)
|
||||||
text = c_text,
|
fg, bg = calendar.notification_preset.fg, calendar.notification_preset.bg
|
||||||
icon = calendar.notify_icon,
|
ws = ws:gsub("%c%[%d+[m]?%s?%d+%c%[%d+[m]?", markup.bold(markup.color(bg, fg, today)))
|
||||||
position = calendar.position,
|
calendar.hide()
|
||||||
fg = calendar.fg,
|
calendar.notification = naughty.notify({
|
||||||
bg = calendar.bg,
|
preset = calendar.notification_preset,
|
||||||
timeout = tims,
|
text = ws:gsub("\n*$", ""),
|
||||||
screen = scrp
|
icon = calendar.notify_icon,
|
||||||
})
|
timeout = t_out or calendar.notification_preset.timeout or 5
|
||||||
|
})
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function calendar.attach(widget, args)
|
function calendar.attach(widget)
|
||||||
local args = args or {}
|
widget:connect_signal("mouse::enter", function () calendar.show(0) end)
|
||||||
|
|
||||||
calendar.cal = args.cal or "/usr/bin/cal"
|
|
||||||
calendar.cal_format = args.cal_format or function(today)
|
|
||||||
return string.format("%s | sed -r -e 's/_\\x08//g' -e '0,/(^| )%d($| )/ s/(^| )%d($| )/\\1<b><span foreground=\"%s\" background=\"%s\">%d<\\/span><\\/b>\\2/'",
|
|
||||||
calendar.cal, today, today, calendar.bg, calendar.fg, today)
|
|
||||||
end
|
|
||||||
calendar.icons = args.icons or icons_dir .. "cal/white/"
|
|
||||||
calendar.font = args.font or beautiful.font:gsub(" %d.*", "")
|
|
||||||
calendar.font_size = tonumber(args.font_size) or 11
|
|
||||||
calendar.fg = args.fg or beautiful.fg_normal or "#FFFFFF"
|
|
||||||
calendar.bg = args.bg or beautiful.bg_normal or "#000000"
|
|
||||||
calendar.position = args.position or "top_right"
|
|
||||||
calendar.scr_pos = args.scr_pos or 1
|
|
||||||
calendar.followmouse = args.followmouse or false
|
|
||||||
|
|
||||||
calendar.offset = 0
|
|
||||||
calendar.notify_icon = nil
|
|
||||||
|
|
||||||
widget:connect_signal("mouse::enter", function () calendar.show(0, 0, calendar.scr_pos) end)
|
|
||||||
widget:connect_signal("mouse::leave", function () calendar.hide() end)
|
widget:connect_signal("mouse::leave", function () calendar.hide() end)
|
||||||
widget:buttons(awful.util.table.join(awful.button({ }, 1, function ()
|
widget:buttons(awful.util.table.join(awful.button({ }, 1, function ()
|
||||||
calendar.show(0, -1, calendar.scr_pos) end),
|
calendar.show(0, -1, calendar.scr_pos) end),
|
||||||
|
@ -128,4 +92,23 @@ function calendar.attach(widget, args)
|
||||||
calendar.show(0, 1, calendar.scr_pos) end)))
|
calendar.show(0, 1, calendar.scr_pos) end)))
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(calendar, { __call = function(_, ...) return create(...) end })
|
local function worker(args)
|
||||||
|
local args = args or {}
|
||||||
|
calendar.cal = args.cal or "/usr/bin/cal"
|
||||||
|
calendar.attach_to = args.attach_to or {}
|
||||||
|
calendar.followtag = args.followtag or false
|
||||||
|
calendar.icons = args.icons or helpers.icons_dir .. "cal/white/"
|
||||||
|
calendar.notification_preset = args.notification_preset
|
||||||
|
|
||||||
|
if not calendar.notification_preset then
|
||||||
|
calendar.notification_preset = {
|
||||||
|
font = "Monospace 10",
|
||||||
|
fg = "#FFFFFF",
|
||||||
|
bg = "#000000"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, widget in ipairs(calendar.attach_to) do calendar.attach(widget) end
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable(calendar, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local helpers = require("lain.helpers")
|
local helpers = require("lain.helpers")
|
||||||
local json = require("lain.util.dkjson")
|
local json = require("lain.util.dkjson")
|
||||||
local pread = require("awful.util").pread
|
local focused = require("awful.screen").focused
|
||||||
local naughty = require("naughty")
|
local pread = require("awful.util").pread
|
||||||
local wibox = require("wibox")
|
local naughty = require("naughty")
|
||||||
local mouse = mouse
|
local wibox = require("wibox")
|
||||||
local os = { getenv = os.getenv }
|
local next = next
|
||||||
|
local os = { getenv = os.getenv }
|
||||||
|
local table = table
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Google Play Music Desktop infos
|
-- Google Play Music Desktop infos
|
||||||
|
@ -24,12 +25,12 @@ local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 2
|
local timeout = args.timeout or 2
|
||||||
local notify = args.notify or "off"
|
local notify = args.notify or "off"
|
||||||
local followmouse = args.followmouse or false
|
local followtag = args.followtag or false
|
||||||
local file_location = args.file_location or
|
local file_location = args.file_location or
|
||||||
os.getenv("HOME") .. "/.config/Google Play Music Desktop Player/json_store/playback.json"
|
os.getenv("HOME") .. "/.config/Google Play Music Desktop Player/json_store/playback.json"
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
gpmdp.widget = wibox.widget.textbox('')
|
gpmdp.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
gpmdp_notification_preset = {
|
gpmdp_notification_preset = {
|
||||||
title = "Now playing",
|
title = "Now playing",
|
||||||
|
@ -39,14 +40,13 @@ local function worker(args)
|
||||||
helpers.set_map("gpmdp_current", nil)
|
helpers.set_map("gpmdp_current", nil)
|
||||||
|
|
||||||
function gpmdp.update()
|
function gpmdp.update()
|
||||||
file, err = io.open(file_location, "r")
|
local filelines = helpers.lines_from(file_location)
|
||||||
if not file
|
|
||||||
then
|
if not next(filelines) then
|
||||||
gpm_now = { running = false, playing = false }
|
local gpm_now = { running = false, playing = false }
|
||||||
else
|
else
|
||||||
dict, pos, err = json.decode(file:read "*a", 1, nil)
|
dict, pos, err = json.decode(table.concat(filelines), 1, nil)
|
||||||
file:close()
|
local gpm_now = {}
|
||||||
gpm_now = {}
|
|
||||||
gpm_now.artist = dict.song.artist
|
gpm_now.artist = dict.song.artist
|
||||||
gpm_now.album = dict.song.album
|
gpm_now.album = dict.song.album
|
||||||
gpm_now.title = dict.song.title
|
gpm_now.title = dict.song.title
|
||||||
|
@ -54,7 +54,7 @@ local function worker(args)
|
||||||
gpm_now.playing = dict.playing
|
gpm_now.playing = dict.playing
|
||||||
end
|
end
|
||||||
|
|
||||||
if (pread("pidof 'Google Play Music Desktop Player'") ~= '') then
|
if pread("pidof 'Google Play Music Desktop Player'") ~= '' then
|
||||||
gpm_now.running = true
|
gpm_now.running = true
|
||||||
else
|
else
|
||||||
gpm_now.running = false
|
gpm_now.running = false
|
||||||
|
@ -64,32 +64,29 @@ local function worker(args)
|
||||||
widget = gpmdp.widget
|
widget = gpmdp.widget
|
||||||
settings()
|
settings()
|
||||||
|
|
||||||
if gpm_now.playing
|
if gpm_now.playing then
|
||||||
then
|
if notify == "on" and gpm_now.title ~= helpers.get_map("gpmdp_current") then
|
||||||
if notify == "on" and gpm_now.title ~= helpers.get_map("gpmdp_current")
|
|
||||||
then
|
|
||||||
helpers.set_map("gpmdp_current", gpm_now.title)
|
helpers.set_map("gpmdp_current", gpm_now.title)
|
||||||
os.execute("curl " .. gpm_now.cover_url .. " -o /tmp/gpmcover.png")
|
|
||||||
|
|
||||||
if followmouse then
|
if followtag then gpmdp_notification_preset.screen = focused() end
|
||||||
gpmdp_notification_preset.screen = mouse.screen
|
|
||||||
end
|
|
||||||
|
|
||||||
gpmdp.id = naughty.notify({
|
helpers.async(string.format("curl %d -o /tmp/gpmcover.png", gpm_now.cover_url),
|
||||||
preset = gpmdp_notification_preset,
|
function(f)
|
||||||
icon = "/tmp/gpmcover.png",
|
gpmdp.id = naughty.notify({
|
||||||
replaces_id = gpmdp.id,
|
preset = gpmdp_notification_preset,
|
||||||
}).id
|
icon = "/tmp/gpmcover.png",
|
||||||
|
replaces_id = gpmdp.id
|
||||||
|
}).id
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
elseif not gpm_now.running
|
elseif not gpm_now.running then
|
||||||
then
|
|
||||||
helpers.set_map("gpmdp_current", nil)
|
helpers.set_map("gpmdp_current", nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.newtimer("gpmdp", timeout, gpmdp.update)
|
gpmdp.timer = helpers.newtimer("gpmdp", timeout, gpmdp.update, true, true)
|
||||||
|
|
||||||
return setmetatable(gpmdp, { __index = gpmdp.widget })
|
return gpmdp
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(gpmdp, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(gpmdp, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,24 +6,21 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
|
||||||
|
|
||||||
local wibox = require("wibox")
|
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
|
local wibox = require("wibox")
|
||||||
local string = { match = string.match }
|
local string = { format = string.format,
|
||||||
|
match = string.match }
|
||||||
|
local execute = os.execute
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Keyboard layout switcher
|
-- Keyboard layout switcher
|
||||||
-- lain.widgets.contrib.kblayout
|
-- lain.widgets.contrib.kblayout
|
||||||
|
local kbdlayout = {}
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local kbdlayout = {}
|
local args = args or {}
|
||||||
kbdlayout.widget = wibox.widget.textbox('')
|
local layouts = args.layouts or {}
|
||||||
|
|
||||||
local layouts = args.layouts
|
|
||||||
local settings = args.settings or function () end
|
local settings = args.settings or function () end
|
||||||
local add_us_secondary = true
|
local add_us_secondary = true
|
||||||
local timeout = args.timeout or 5
|
local timeout = args.timeout or 5
|
||||||
|
@ -31,52 +28,53 @@ local function worker(args)
|
||||||
|
|
||||||
if args.add_us_secondary == false then add_us_secondary = false end
|
if args.add_us_secondary == false then add_us_secondary = false end
|
||||||
|
|
||||||
-- Mouse bindings
|
kbdlayout.widget = wibox.widget.textbox()
|
||||||
kbdlayout.widget:buttons(awful.util.table.join(
|
|
||||||
awful.button({ }, 1, function () kbdlayout.next() end),
|
|
||||||
awful.button({ }, 3, function () kbdlayout.prev() end)))
|
|
||||||
|
|
||||||
local function run_settings(layout, variant)
|
local function kbd_run_settings(layout, variant)
|
||||||
|
kbdlayout_now = {
|
||||||
|
layout = string.match(layout, "[^,]+"), -- Make sure to match the primary layout only.
|
||||||
|
variant = variant
|
||||||
|
}
|
||||||
widget = kbdlayout.widget
|
widget = kbdlayout.widget
|
||||||
kbdlayout_now = { layout=string.match(layout, "[^,]+"), -- Make sure to match the primary layout only.
|
|
||||||
variant=variant }
|
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
function kbdlayout.update()
|
function kbdlayout.update()
|
||||||
local status = read_pipe('setxkbmap -query')
|
helpers.async("setxkbmap -query", function(status)
|
||||||
|
kbd_run_settings(string.match(status, "layout:%s*([^\n]*)"),
|
||||||
run_settings(string.match(status, "layout:%s*([^\n]*)"),
|
string.match(status, "variant:%s*([^\n]*)"))
|
||||||
string.match(status, "variant:%s*([^\n]*)"))
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function kbdlayout.set(i)
|
function kbdlayout.set(i)
|
||||||
|
if #layouts == 0 then return end
|
||||||
idx = ((i - 1) % #layouts) + 1 -- Make sure to wrap around as needed.
|
idx = ((i - 1) % #layouts) + 1 -- Make sure to wrap around as needed.
|
||||||
local to_execute = 'setxkbmap ' .. layouts[idx].layout
|
local to_execute = "setxkbmap " .. layouts[idx].layout
|
||||||
|
|
||||||
if add_us_secondary and not string.match(layouts[idx].layout, ",?us,?") then
|
if add_us_secondary and not string.match(layouts[idx].layout, ",?us,?") then
|
||||||
to_execute = to_execute .. ",us"
|
to_execute = to_execute .. ",us"
|
||||||
end
|
end
|
||||||
|
|
||||||
if layouts[idx].variant then
|
if layouts[idx].variant then
|
||||||
to_execute = to_execute .. ' ' .. layouts[idx].variant
|
to_execute = to_execute .. " " .. layouts[idx].variant
|
||||||
end
|
end
|
||||||
|
|
||||||
if os.execute(to_execute) then
|
if execute(to_execute) then
|
||||||
run_settings(layouts[idx].layout, layouts[idx].variant)
|
kbd_run_settings(layouts[idx].layout, layouts[idx].variant)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function kbdlayout.next()
|
function kbdlayout.next() kbdlayout.set(idx + 1) end
|
||||||
kbdlayout.set(idx + 1)
|
function kbdlayout.prev() kbdlayout.set(idx - 1) end
|
||||||
end
|
|
||||||
|
|
||||||
function kbdlayout.prev()
|
-- Mouse bindings
|
||||||
kbdlayout.set(idx - 1)
|
kbdlayout.widget:buttons(awful.util.table.join(
|
||||||
end
|
awful.button({ }, 1, function () kbdlayout.next() end),
|
||||||
|
awful.button({ }, 3, function () kbdlayout.prev() end)))
|
||||||
|
|
||||||
newtimer("kbdlayout", timeout, kbdlayout.update)
|
helpers.newtimer("kbdlayout", timeout, kbdlayout.update)
|
||||||
return setmetatable(kbdlayout, { __index = kbdlayout.widget })
|
|
||||||
|
return kbdlayout
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function (_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function (_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,19 +6,15 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local helpers = require("lain.helpers")
|
local helpers = require("lain.helpers")
|
||||||
local async = require("lain.asyncshell")
|
local shell = require("awful.util").shell
|
||||||
|
local focused = require("awful.screen").focused
|
||||||
local escape_f = require("awful.util").escape
|
local escape_f = require("awful.util").escape
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
local os = { getenv = os.getenv }
|
||||||
local io = { popen = io.popen }
|
local string = { format = string.format,
|
||||||
local os = { execute = os.execute,
|
gmatch = string.gmatch }
|
||||||
getenv = os.getenv }
|
|
||||||
local string = { format = string.format,
|
|
||||||
gmatch = string.gmatch }
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- MOC audio player
|
-- MOC audio player
|
||||||
|
@ -26,31 +22,23 @@ local setmetatable = setmetatable
|
||||||
local moc = {}
|
local moc = {}
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 2
|
local timeout = args.timeout or 2
|
||||||
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
|
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
|
||||||
local cover_size = args.cover_size or 100
|
local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$"
|
||||||
local default_art = args.default_art or ""
|
local cover_size = args.cover_size or 100
|
||||||
local followmouse = args.followmouse or false
|
local default_art = args.default_art or ""
|
||||||
local settings = args.settings or function() end
|
local followtag = args.followtag or false
|
||||||
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
local mpdcover = helpers.scripts_dir .. "mpdcover"
|
moc.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
moc.widget = wibox.widget.textbox('')
|
moc_notification_preset = { title = "Now playing", timeout = 6 }
|
||||||
|
|
||||||
moc_notification_preset = {
|
|
||||||
title = "Now playing",
|
|
||||||
timeout = 6
|
|
||||||
}
|
|
||||||
|
|
||||||
helpers.set_map("current moc track", nil)
|
helpers.set_map("current moc track", nil)
|
||||||
|
|
||||||
function moc.update()
|
function moc.update()
|
||||||
-- mocp -i will produce output like:
|
helpers.async("mocp -i", function(f)
|
||||||
-- Artist: Travis
|
|
||||||
-- Album: The Man Who
|
|
||||||
-- etc.
|
|
||||||
async.request("mocp -i", function(f)
|
|
||||||
moc_now = {
|
moc_now = {
|
||||||
state = "N/A",
|
state = "N/A",
|
||||||
file = "N/A",
|
file = "N/A",
|
||||||
|
@ -63,13 +51,13 @@ local function worker(args)
|
||||||
|
|
||||||
for line in string.gmatch(f, "[^\n]+") do
|
for line in string.gmatch(f, "[^\n]+") do
|
||||||
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
|
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
|
||||||
if k == "State" then moc_now.state = v
|
if k == "State" then moc_now.state = v
|
||||||
elseif k == "File" then moc_now.file = v
|
elseif k == "File" then moc_now.file = v
|
||||||
elseif k == "Artist" then moc_now.artist = escape_f(v)
|
elseif k == "Artist" then moc_now.artist = escape_f(v)
|
||||||
elseif k == "SongTitle" then moc_now.title = escape_f(v)
|
elseif k == "SongTitle" then moc_now.title = escape_f(v)
|
||||||
elseif k == "Album" then moc_now.album = escape_f(v)
|
elseif k == "Album" then moc_now.album = escape_f(v)
|
||||||
elseif k == "CurrentTime" then moc_now.elapsed = escape_f(v)
|
elseif k == "CurrentTime" then moc_now.elapsed = escape_f(v)
|
||||||
elseif k == "TotalTime" then moc_now.total = escape_f(v)
|
elseif k == "TotalTime" then moc_now.total = escape_f(v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -82,18 +70,22 @@ local function worker(args)
|
||||||
if moc_now.state == "PLAY" then
|
if moc_now.state == "PLAY" then
|
||||||
if moc_now.title ~= helpers.get_map("current moc track") then
|
if moc_now.title ~= helpers.get_map("current moc track") then
|
||||||
helpers.set_map("current moc track", moc_now.title)
|
helpers.set_map("current moc track", moc_now.title)
|
||||||
os.execute(string.format("%s %q %q %d %q", mpdcover, "",
|
|
||||||
moc_now.file, cover_size, default_art))
|
|
||||||
|
|
||||||
if followmouse then
|
if followtag then moc_notification_preset.screen = focused() end
|
||||||
moc_notification_preset.screen = mouse.screen
|
|
||||||
end
|
|
||||||
|
|
||||||
moc.id = naughty.notify({
|
local common = {
|
||||||
preset = moc_notification_preset,
|
preset = moc_notification_preset,
|
||||||
icon = "/tmp/mpdcover.png",
|
icon = default_art,
|
||||||
|
icon_size = cover_size,
|
||||||
replaces_id = moc.id,
|
replaces_id = moc.id,
|
||||||
}).id
|
}
|
||||||
|
|
||||||
|
local path = string.format("%s/%s", music_dir, string.match(moc_now.file, ".*/"))
|
||||||
|
local cover = string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'", path, cover_pattern)
|
||||||
|
helpers.async({ shell, "-c", cover }, function(current_icon)
|
||||||
|
common.icon = current_icon:gsub("\n", "")
|
||||||
|
moc.id = naughty.notify(common).id
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
elseif moc_now.state ~= "PAUSE" then
|
elseif moc_now.state ~= "PAUSE" then
|
||||||
helpers.set_map("current moc track", nil)
|
helpers.set_map("current moc track", nil)
|
||||||
|
@ -101,9 +93,9 @@ local function worker(args)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.newtimer("moc", timeout, moc.update)
|
moc.timer = helpers.newtimer("moc", timeout, moc.update, true, true)
|
||||||
|
|
||||||
return setmetatable(moc, { __index = moc.widget })
|
return moc
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(moc, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(moc, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,73 +6,49 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local awful = require("awful")
|
local async = require("lain.helpers").async
|
||||||
local os = os
|
local awful = require("awful")
|
||||||
local spawn = awful.util.spawn_with_shell
|
local execute = os.execute
|
||||||
|
local type = type
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
-- Redshift
|
-- Redshift
|
||||||
-- lain.widgets.contrib.redshift
|
-- lain.widgets.contrib.redshift
|
||||||
local redshift = {}
|
local redshift = { active = false, pid = nil }
|
||||||
|
|
||||||
local attached = false -- true if attached to a widget
|
function redshift:start()
|
||||||
local active = false -- true if redshift is active
|
execute("pkill redshift")
|
||||||
local running = false -- true if redshift was initialized
|
awful.spawn.with_shell("redshift -x") -- clear adjustments
|
||||||
local update_fnct = function() end -- Function that is run each time redshift is toggled. See redshift:attach().
|
redshift.pid = awful.spawn.with_shell("redshift")
|
||||||
|
redshift.active = true
|
||||||
local function init()
|
if type(redshift.update_fun) == "function" then
|
||||||
-- As there is no way to determine if redshift was previously
|
redshift.update_fun(redshift.active)
|
||||||
-- toggled off (i.e Awesome on-the-fly restart), kill redshift to make sure
|
end
|
||||||
os.execute("pkill redshift")
|
|
||||||
-- Remove existing color adjustment
|
|
||||||
spawn("redshift -x")
|
|
||||||
-- (Re)start redshift
|
|
||||||
spawn("redshift")
|
|
||||||
running = true
|
|
||||||
active = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function redshift:toggle()
|
function redshift:toggle()
|
||||||
if running then
|
async({ awful.util.shell, "-c", string.format("ps -p %d -o pid=", redshift.pid) }, function(f)
|
||||||
-- Sending -USR1 toggles redshift (See project website)
|
if f and #f > 0 then -- redshift is running
|
||||||
os.execute("pkill -USR1 redshift")
|
-- Sending -USR1 toggles redshift (See project website)
|
||||||
active = not active
|
execute("pkill -USR1 redshift")
|
||||||
else
|
redshift.active = not redshift.active
|
||||||
init()
|
else -- not started or killed, (re)start it
|
||||||
end
|
redshift:start()
|
||||||
update_fnct()
|
end
|
||||||
end
|
redshift.update_fun(redshift.active)
|
||||||
|
end)
|
||||||
function redshift:off()
|
|
||||||
if running and active then
|
|
||||||
redshift:toggle()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function redshift:on()
|
|
||||||
if not active then
|
|
||||||
redshift:toggle()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function redshift:is_active()
|
|
||||||
return active
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Attach to a widget
|
-- Attach to a widget
|
||||||
-- Provides a button which toggles redshift on/off on click
|
-- Provides a button which toggles redshift on/off on click
|
||||||
-- @param widget: Widget to attach to.
|
-- @param widget: Widget to attach to.
|
||||||
-- @param fnct: Function to be run each time redshift is toggled (optional).
|
-- @param fun: Function to be run each time redshift is toggled (optional).
|
||||||
-- Use it to update widget text or icons on status change.
|
-- Use it to update widget text or icons on status change.
|
||||||
function redshift:attach(widget, fnct)
|
function redshift:attach(widget, fun)
|
||||||
update_fnct = fnct or function() end
|
redshift.update_fun = fun or function() end
|
||||||
if not attached then
|
if not redshift.pid then redshift:start() end
|
||||||
init()
|
if widget then
|
||||||
attached = true
|
widget:buttons(awful.util.table.join(awful.button({}, 1, function () redshift:toggle() end)))
|
||||||
update_fnct()
|
|
||||||
end
|
end
|
||||||
widget:buttons(awful.util.table.join( awful.button({}, 1, function () redshift:toggle() end) ))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(redshift, { _call = function(_, ...) return create(...) end })
|
return redshift
|
||||||
|
|
|
@ -6,145 +6,77 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local icons_dir = require("lain.helpers").icons_dir
|
local helpers = require("lain.helpers")
|
||||||
|
local markup = require("lain.util").markup
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local beautiful = require("beautiful")
|
local naughty = require("naughty")
|
||||||
local naughty = require("naughty")
|
local string = { format = string.format, gsub = string.gsub }
|
||||||
|
|
||||||
local mouse = mouse
|
|
||||||
local io = io
|
|
||||||
local string = { len = string.len }
|
|
||||||
local tonumber = tonumber
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
-- Taskwarrior notification
|
-- Taskwarrior notification
|
||||||
-- lain.widgets.contrib.task
|
-- lain.widgets.contrib.task
|
||||||
local task = {}
|
local task = {}
|
||||||
|
|
||||||
local task_notification = nil
|
|
||||||
|
|
||||||
function findLast(haystack, needle)
|
|
||||||
local i=haystack:match(".*"..needle.."()")
|
|
||||||
if i==nil then return nil else return i-1 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function task.hide()
|
function task.hide()
|
||||||
if task_notification ~= nil then
|
if not task.notification then return end
|
||||||
naughty.destroy(task_notification)
|
naughty.destroy(task.notification)
|
||||||
task_notification = nil
|
task.notification = nil
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function task.show(scr_pos)
|
function task.show(scr)
|
||||||
task.hide()
|
task.hide()
|
||||||
|
|
||||||
local f, c_text, scrp
|
if task.followtag then
|
||||||
|
task.notification_preset.screen = awful.screen.focused()
|
||||||
if task.followmouse then
|
elseif scr then
|
||||||
scrp = mouse.screen
|
task.notification_preset.screen = scr
|
||||||
else
|
|
||||||
scrp = scr_pos or task.scr_pos
|
|
||||||
end
|
end
|
||||||
|
|
||||||
f = io.popen('task ' .. task.cmdline)
|
helpers.async(task.show_cmd, function(f)
|
||||||
c_text = "<span font='"
|
task.notification = naughty.notify({
|
||||||
.. task.font .. " "
|
preset = task.notification_preset,
|
||||||
.. task.font_size .. "'>"
|
title = task.show_cmd,
|
||||||
.. awful.util.escape(f:read("*all"):gsub("\n*$", ""))
|
text = markup.font(task.notification_preset.font,
|
||||||
.. "</span>"
|
awful.util.escape(f:gsub("\n*$", "")))
|
||||||
f:close()
|
})
|
||||||
|
end)
|
||||||
task_notification = naughty.notify({ title = "[task next]",
|
|
||||||
text = c_text,
|
|
||||||
icon = task.notify_icon,
|
|
||||||
position = task.position,
|
|
||||||
fg = task.fg,
|
|
||||||
bg = task.bg,
|
|
||||||
timeout = task.timeout,
|
|
||||||
screen = scrp
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function task.prompt_add()
|
function task.prompt()
|
||||||
awful.prompt.run({ prompt = "Add task: " },
|
awful.prompt.run {
|
||||||
mypromptbox[mouse.screen].widget,
|
prompt = task.prompt_text,
|
||||||
function (...)
|
textbox = awful.screen.focused().mypromptbox.widget,
|
||||||
local f = io.popen("task add " .. ...)
|
exe_callback = function(t)
|
||||||
c_text = "\n<span font='"
|
helpers.async(t, function(f)
|
||||||
.. task.font .. " "
|
naughty.notify {
|
||||||
.. task.font_size .. "'>"
|
preset = task.notification_preset,
|
||||||
.. awful.util.escape(f:read("*all"))
|
title = t,
|
||||||
.. "</span>"
|
text = markup.font(task.notification_preset.font,
|
||||||
f:close()
|
awful.util.escape(f:gsub("\n*$", "")))
|
||||||
|
}
|
||||||
naughty.notify({
|
end)
|
||||||
text = c_text,
|
end,
|
||||||
icon = task.notify_icon,
|
history_path = awful.util.getdir("cache") .. "/history_task"
|
||||||
position = task.position,
|
}
|
||||||
fg = task.fg,
|
|
||||||
bg = task.bg,
|
|
||||||
timeout = task.timeout,
|
|
||||||
})
|
|
||||||
end,
|
|
||||||
nil,
|
|
||||||
awful.util.getdir("cache") .. "/history_task_add")
|
|
||||||
end
|
|
||||||
|
|
||||||
function task.prompt_search()
|
|
||||||
awful.prompt.run({ prompt = "Search task: " },
|
|
||||||
mypromptbox[mouse.screen].widget,
|
|
||||||
function (...)
|
|
||||||
local f = io.popen("task " .. ...)
|
|
||||||
c_text = f:read("*all"):gsub(" \n*$", "")
|
|
||||||
f:close()
|
|
||||||
|
|
||||||
if string.len(c_text) == 0
|
|
||||||
then
|
|
||||||
c_text = "No results found."
|
|
||||||
else
|
|
||||||
c_text = "<span font='"
|
|
||||||
.. task.font .. " "
|
|
||||||
.. task.font_size .. "'>"
|
|
||||||
.. awful.util.escape(c_text)
|
|
||||||
.. "</span>"
|
|
||||||
end
|
|
||||||
|
|
||||||
naughty.notify({
|
|
||||||
title = "[task next " .. ... .. "]",
|
|
||||||
text = c_text,
|
|
||||||
icon = task.notify_icon,
|
|
||||||
position = task.position,
|
|
||||||
fg = task.fg,
|
|
||||||
bg = task.bg,
|
|
||||||
timeout = task.timeout,
|
|
||||||
screen = mouse.screen
|
|
||||||
})
|
|
||||||
end,
|
|
||||||
nil,
|
|
||||||
awful.util.getdir("cache") .. "/history_task")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function task.attach(widget, args)
|
function task.attach(widget, args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
|
task.show_cmd = args.show_cmd or "task next"
|
||||||
|
task.prompt_text = args.prompt_text or "Enter task command: "
|
||||||
|
task.followtag = args.followtag or false
|
||||||
|
task.notification_preset = args.notification_preset
|
||||||
|
|
||||||
task.font_size = tonumber(args.font_size) or 12
|
if not task.notification_preset then
|
||||||
task.font = args.font or beautiful.font:sub(beautiful.font:find(""),
|
task.notification_preset = {
|
||||||
findLast(beautiful.font, " "))
|
font = "Monospace 10",
|
||||||
task.fg = args.fg or beautiful.fg_normal or "#FFFFFF"
|
icon = helpers.icons_dir .. "/taskwarrior.png"
|
||||||
task.bg = args.bg or beautiful.bg_normal or "#FFFFFF"
|
}
|
||||||
task.position = args.position or "top_right"
|
end
|
||||||
task.timeout = args.timeout or 7
|
|
||||||
task.scr_pos = args.scr_pos or 1
|
|
||||||
task.followmouse = args.followmouse or false
|
|
||||||
task.cmdline = args.cmdline or "next"
|
|
||||||
|
|
||||||
task.notify_icon = icons_dir .. "/taskwarrior/task.png"
|
if widget then
|
||||||
task.notify_icon_small = icons_dir .. "/taskwarrior/tasksmall.png"
|
widget:connect_signal("mouse::enter", function () task.show() end)
|
||||||
|
widget:connect_signal("mouse::leave", function () task.hide() end)
|
||||||
widget:connect_signal("mouse::enter", function () task.show(task.scr_pos) end)
|
end
|
||||||
widget:connect_signal("mouse::leave", function () task.hide() end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(task, { __call = function(_, ...) return create(...) end })
|
return task
|
||||||
|
|
|
@ -17,39 +17,33 @@
|
||||||
local debug = { getinfo = debug.getinfo }
|
local debug = { getinfo = debug.getinfo }
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local newtimer = require("lain.helpers").newtimer
|
||||||
local first_line = require("lain.helpers").first_line
|
local first_line = require("lain.helpers").first_line
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local string = { format = string.format }
|
local string = { format = string.format }
|
||||||
local math = { floor = math.floor }
|
local math = { floor = math.floor }
|
||||||
local tostring = tostring
|
local tostring = tostring
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])[^\/]-$]] .. "?.lua;" .. package.path
|
package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])[^\/]-$]] .. "?.lua;" .. package.path
|
||||||
local smapi = require("smapi")
|
local smapi = require("smapi")
|
||||||
|
|
||||||
-- ThinkPad SMAPI-enabled battery info widget
|
-- ThinkPad SMAPI-enabled battery info widget
|
||||||
-- lain.widgets.contrib.tpbat
|
-- lain.widgets.contrib.tpbat
|
||||||
local tpbat = { }
|
local tpbat = {}
|
||||||
local tpbat_notification = nil
|
|
||||||
|
|
||||||
function tpbat:hide()
|
function tpbat.hide()
|
||||||
if tpbat_notification ~= nil
|
if not tpbat.notification then return end
|
||||||
then
|
naughty.destroy(tpbat.notification)
|
||||||
naughty.destroy(tpbat_notification)
|
tpbat.notification = nil
|
||||||
tpbat_notification = nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function tpbat:show(t_out)
|
function tpbat.show(t_out)
|
||||||
tpbat:hide()
|
tpbat.hide()
|
||||||
|
|
||||||
local bat = self.bat
|
local bat = tpbat.bat
|
||||||
local t_out = t_out or 0
|
|
||||||
|
|
||||||
if bat == nil or not bat:installed() then return end
|
if bat == nil or not bat:installed() then return end
|
||||||
|
|
||||||
|
local t_out = t_out or 0
|
||||||
local mfgr = bat:get('manufacturer') or "no_mfgr"
|
local mfgr = bat:get('manufacturer') or "no_mfgr"
|
||||||
local model = bat:get('model') or "no_model"
|
local model = bat:get('model') or "no_model"
|
||||||
local chem = bat:get('chemistry') or "no_chem"
|
local chem = bat:get('chemistry') or "no_chem"
|
||||||
|
@ -57,10 +51,8 @@ function tpbat:show(t_out)
|
||||||
local time = bat:remaining_time()
|
local time = bat:remaining_time()
|
||||||
local msg = "\t"
|
local msg = "\t"
|
||||||
|
|
||||||
if status ~= "idle" and status ~= "nil"
|
if status ~= "idle" and status ~= "nil" then
|
||||||
then
|
if time == "N/A" then
|
||||||
if time == "N/A"
|
|
||||||
then
|
|
||||||
msg = "...Calculating time remaining..."
|
msg = "...Calculating time remaining..."
|
||||||
else
|
else
|
||||||
msg = time .. (status == "charging" and " until charged" or " remaining")
|
msg = time .. (status == "charging" and " until charged" or " remaining")
|
||||||
|
@ -72,11 +64,10 @@ function tpbat:show(t_out)
|
||||||
local str = string.format("%s : %s %s (%s)\n", bat.name, mfgr, model, chem)
|
local str = string.format("%s : %s %s (%s)\n", bat.name, mfgr, model, chem)
|
||||||
.. string.format("\n%s \t\t\t %s", status:upper(), msg)
|
.. string.format("\n%s \t\t\t %s", status:upper(), msg)
|
||||||
|
|
||||||
tpbat_notification = naughty.notify({
|
tpbat.notification = naughty.notify({
|
||||||
preset = { fg = beautiful.fg_normal },
|
text = str,
|
||||||
text = str,
|
|
||||||
timeout = t_out,
|
timeout = t_out,
|
||||||
screen = client.focus and client.focus.screen or 1
|
screen = client.focus and client.focus.screen or 1
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,7 +80,7 @@ function tpbat.register(args)
|
||||||
tpbat.bat = smapi:battery(battery) -- Create a new battery
|
tpbat.bat = smapi:battery(battery) -- Create a new battery
|
||||||
local bat = tpbat.bat
|
local bat = tpbat.bat
|
||||||
|
|
||||||
tpbat.widget = wibox.widget.textbox('')
|
tpbat.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
bat_notification_low_preset = {
|
bat_notification_low_preset = {
|
||||||
title = "Battery low",
|
title = "Battery low",
|
||||||
|
@ -117,7 +108,7 @@ function tpbat.register(args)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function update()
|
function tpbat.update()
|
||||||
bat_now = {
|
bat_now = {
|
||||||
status = "Not present",
|
status = "Not present",
|
||||||
perc = "N/A",
|
perc = "N/A",
|
||||||
|
@ -156,15 +147,16 @@ function tpbat.register(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
widget = tpbat.widget
|
widget = tpbat.widget
|
||||||
|
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer("tpbat-" .. bat.name, timeout, update)
|
newtimer("tpbat-" .. bat.name, timeout, tpbat.update)
|
||||||
|
|
||||||
widget:connect_signal('mouse::enter', function () tpbat:show() end)
|
widget:connect_signal('mouse::enter', function () tpbat.show() end)
|
||||||
widget:connect_signal('mouse::leave', function () tpbat:hide() end)
|
widget:connect_signal('mouse::leave', function () tpbat.hide() end)
|
||||||
|
|
||||||
return tpbat.widget
|
return tpbat
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(tpbat, { __call = function(_, ...) return tpbat.register(...) end })
|
return setmetatable(tpbat, { __call = function(_, ...) return tpbat.register(...) end })
|
||||||
|
|
|
@ -81,13 +81,11 @@ function smapi:battery(name)
|
||||||
local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time'
|
local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time'
|
||||||
local mins_left = self:get(time_val)
|
local mins_left = self:get(time_val)
|
||||||
|
|
||||||
if mins_left:find("^%d+") == nil
|
if not mins_left:find("^%d+") then return "N/A" end
|
||||||
then
|
|
||||||
return "N/A"
|
|
||||||
end
|
|
||||||
|
|
||||||
local hrs = math.floor(mins_left / 60)
|
local hrs = math.floor(mins_left / 60)
|
||||||
local min = mins_left % 60
|
local min = mins_left % 60
|
||||||
|
|
||||||
return string.format("%02d:%02d", hrs, min)
|
return string.format("%02d:%02d", hrs, min)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,12 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local lines_match = require("lain.helpers").lines_match
|
local helpers = require("lain.helpers")
|
||||||
local newtimer = require("lain.helpers").newtimer
|
|
||||||
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local math = { ceil = math.ceil }
|
local math = { ceil = math.ceil }
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
gmatch = string.gmatch }
|
gmatch = string.gmatch }
|
||||||
local tostring = tostring
|
local tostring = tostring
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- CPU usage
|
-- CPU usage
|
||||||
|
@ -25,28 +21,26 @@ local cpu = { core = {} }
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 2
|
local timeout = args.timeout or 2
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
cpu.widget = wibox.widget.textbox('')
|
cpu.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
function update()
|
function cpu.update()
|
||||||
-- Read the amount of time the CPUs have spent performing
|
-- Read the amount of time the CPUs have spent performing
|
||||||
-- different kinds of work. Read the first line of /proc/stat
|
-- different kinds of work. Read the first line of /proc/stat
|
||||||
-- which is the sum of all CPUs.
|
-- which is the sum of all CPUs.
|
||||||
local times = lines_match("cpu","/proc/stat")
|
local times = helpers.lines_match("cpu","/proc/stat")
|
||||||
|
|
||||||
for index,time in pairs(times)
|
for index,time in pairs(times) do
|
||||||
do
|
|
||||||
local coreid = index - 1
|
local coreid = index - 1
|
||||||
local core = cpu.core[coreid] or
|
local core = cpu.core[coreid] or
|
||||||
{ last_active = 0 , last_total = 0, usage = 0 }
|
{ last_active = 0 , last_total = 0, usage = 0 }
|
||||||
local at = 1
|
local at = 1
|
||||||
local idle = 0
|
local idle = 0
|
||||||
local total = 0
|
local total = 0
|
||||||
|
|
||||||
for field in string.gmatch(time, "[%s]+([^%s]+)")
|
for field in string.gmatch(time, "[%s]+([^%s]+)") do
|
||||||
do
|
|
||||||
-- 4 = idle, 5 = ioWait. Essentially, the CPUs have done
|
-- 4 = idle, 5 = ioWait. Essentially, the CPUs have done
|
||||||
-- nothing during these times.
|
-- nothing during these times.
|
||||||
if at == 4 or at == 5 then
|
if at == 4 or at == 5 then
|
||||||
|
@ -62,27 +56,27 @@ local function worker(args)
|
||||||
-- Read current data and calculate relative values.
|
-- Read current data and calculate relative values.
|
||||||
local dactive = active - core.last_active
|
local dactive = active - core.last_active
|
||||||
local dtotal = total - core.last_total
|
local dtotal = total - core.last_total
|
||||||
|
local usage = math.ceil((dactive / dtotal) * 100)
|
||||||
local usage = math.ceil((dactive / dtotal) * 100)
|
|
||||||
|
|
||||||
core.last_active = active
|
core.last_active = active
|
||||||
core.last_total = total
|
core.last_total = total
|
||||||
core.usage = usage
|
core.usage = usage
|
||||||
|
|
||||||
-- Save current data for the next run.
|
-- Save current data for the next run.
|
||||||
cpu.core[coreid] = core;
|
cpu.core[coreid] = core
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
widget = cpu.widget
|
|
||||||
cpu_now = cpu.core
|
cpu_now = cpu.core
|
||||||
cpu_now.usage = cpu_now[0].usage
|
cpu_now.usage = cpu_now[0].usage
|
||||||
|
widget = cpu.widget
|
||||||
|
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer("cpu", timeout, update)
|
helpers.newtimer("cpu", timeout, cpu.update)
|
||||||
return cpu.widget
|
|
||||||
|
return cpu
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(cpu, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(cpu, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
151
widgets/fs.lua
|
@ -1,62 +1,50 @@
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
Licensed under GNU General Public License v2
|
||||||
* (c) 2013, Luke Bonham
|
* (c) 2013, Luke Bonham
|
||||||
* (c) 2010, Adrian C. <anrxc@sysphere.org>
|
|
||||||
* (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local helpers = require("lain.helpers")
|
local helpers = require("lain.helpers")
|
||||||
|
|
||||||
local beautiful = require("beautiful")
|
local shell = require("awful.util").shell
|
||||||
|
local focused = require("awful.screen").focused
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
|
|
||||||
local io = { popen = io.popen }
|
local string = string
|
||||||
local pairs = pairs
|
|
||||||
local mouse = mouse
|
|
||||||
local string = { match = string.match,
|
|
||||||
format = string.format }
|
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- File system disk space usage
|
-- File system disk space usage
|
||||||
-- lain.widgets.fs
|
-- lain.widgets.fs
|
||||||
local fs = {}
|
local fs = { unit = { ["mb"] = 1024, ["gb"] = 1024^2 } }
|
||||||
local fs_notification = nil
|
|
||||||
|
|
||||||
function fs.hide()
|
function fs.hide()
|
||||||
if fs_notification ~= nil then
|
if not fs.notification then return end
|
||||||
naughty.destroy(fs_notification)
|
naughty.destroy(fs.notification)
|
||||||
fs_notification = nil
|
fs.notification = nil
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.show(seconds, options, scr)
|
function fs.show(seconds, scr)
|
||||||
|
fs.update()
|
||||||
|
|
||||||
fs.hide()
|
fs.hide()
|
||||||
|
|
||||||
local cmd = (options and string.format("dfs %s", options)) or "dfs"
|
if fs.followtag then
|
||||||
local ws = helpers.read_pipe(helpers.scripts_dir .. cmd):gsub("\n*$", "")
|
fs.notification_preset.screen = focused()
|
||||||
|
|
||||||
if fs.followmouse then
|
|
||||||
fs.notification_preset.screen = mouse.screen
|
|
||||||
elseif scr then
|
elseif scr then
|
||||||
fs.notification_preset.screen = scr
|
fs.notification_preset.screen = scr or 1
|
||||||
end
|
end
|
||||||
|
|
||||||
fs_notification = naughty.notify({
|
fs.notification = naughty.notify({
|
||||||
preset = fs.notification_preset,
|
preset = fs.notification_preset,
|
||||||
text = ws,
|
timeout = seconds or 5
|
||||||
timeout = seconds or 5
|
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Unit definitions
|
|
||||||
local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
|
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 600
|
local timeout = args.timeout or 600
|
||||||
|
@ -65,65 +53,78 @@ local function worker(args)
|
||||||
local notify = args.notify or "on"
|
local notify = args.notify or "on"
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
fs.followmouse = args.followmouse or false
|
fs.options = args.options
|
||||||
fs.notification_preset = args.notification_preset or { fg = beautiful.fg_normal }
|
fs.followtag = args.followtag or false
|
||||||
|
fs.notification_preset = args.notification_preset
|
||||||
|
|
||||||
fs.widget = wibox.widget.textbox('')
|
if not fs.notification_preset then
|
||||||
|
fs.notification_preset = {
|
||||||
|
font = "Monospace 10",
|
||||||
|
fg = "#FFFFFF",
|
||||||
|
bg = "#000000"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
fs.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
helpers.set_map(partition, false)
|
helpers.set_map(partition, false)
|
||||||
|
|
||||||
function update()
|
function fs.update()
|
||||||
fs_info = {}
|
fs_info, fs_now = {}, {}
|
||||||
fs_now = {}
|
helpers.async({ shell, "-c", "/usr/bin/env LC_ALL=C df -k --output=target,size,used,avail,pcent" }, function(f)
|
||||||
local f = assert(io.popen("LC_ALL=C df -kP"))
|
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
|
||||||
|
|
||||||
for line in f:lines() do -- Match: (size) (used)(avail)(use%) (mount)
|
fs_info[m .. " size_mb"] = string.format("%.1f", tonumber(s) / fs.unit["mb"])
|
||||||
local s = string.match(line, "^.-[%s]([%d]+)")
|
fs_info[m .. " size_gb"] = string.format("%.1f", tonumber(s) / fs.unit["gb"])
|
||||||
local u,a,p = string.match(line, "([%d]+)[%D]+([%d]+)[%D]+([%d]+)%%")
|
fs_info[m .. " used_mb"] = string.format("%.1f", tonumber(u) / fs.unit["mb"])
|
||||||
local m = string.match(line, "%%[%s]([%p%w]+)")
|
fs_info[m .. " used_gb"] = string.format("%.1f", tonumber(u) / fs.unit["gb"])
|
||||||
|
fs_info[m .. " used_p"] = p
|
||||||
if u and m then -- Handle 1st line and broken regexp
|
fs_info[m .. " avail_mb"] = string.format("%.1f", tonumber(a) / fs.unit["mb"])
|
||||||
fs_info[m .. " size_mb"] = string.format("%.1f", tonumber(s) / unit["mb"])
|
fs_info[m .. " avail_gb"] = string.format("%.1f", tonumber(a) / fs.unit["gb"])
|
||||||
fs_info[m .. " size_gb"] = string.format("%.1f", tonumber(s) / unit["gb"])
|
fs_info[m .. " avail_p"] = string.format("%d", 100 - tonumber(p))
|
||||||
fs_info[m .. " used_p"] = tonumber(p)
|
|
||||||
fs_info[m .. " avail_p"] = 100 - tonumber(p)
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
f:close()
|
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"
|
||||||
|
|
||||||
fs_now.used = tonumber(fs_info[partition .. " used_p"]) or 0
|
notification_preset = fs.notification_preset
|
||||||
fs_now.available = tonumber(fs_info[partition .. " avail_p"]) or 0
|
widget = fs.widget
|
||||||
fs_now.size_mb = tonumber(fs_info[partition .. " size_mb"]) or 0
|
settings()
|
||||||
fs_now.size_gb = tonumber(fs_info[partition .. " size_gb"]) or 0
|
|
||||||
|
|
||||||
notification_preset = fs.notification_preset
|
if notify == "on" and #fs_now.used > 0 and tonumber(fs_now.used) >= 99 and not helpers.get_map(partition) then
|
||||||
widget = fs.widget
|
naughty.notify({
|
||||||
settings()
|
preset = naughty.config.presets.critical,
|
||||||
|
title = "Warning",
|
||||||
|
text = partition .. " is empty",
|
||||||
|
})
|
||||||
|
helpers.set_map(partition, true)
|
||||||
|
else
|
||||||
|
helpers.set_map(partition, false)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
if notify == "on" and fs_now.used >= 99 and not helpers.get_map(partition)
|
local notifycmd = (fs.options and string.format("dfs %s", fs.options)) or "dfs"
|
||||||
then
|
helpers.async(helpers.scripts_dir .. notifycmd, function(ws)
|
||||||
naughty.notify({
|
fs.notification_preset.text = ws:gsub("\n*$", "")
|
||||||
title = "warning",
|
end)
|
||||||
text = partition .. " ran out!\nmake some room",
|
|
||||||
timeout = 8,
|
|
||||||
fg = "#000000",
|
|
||||||
bg = "#FFFFFF",
|
|
||||||
})
|
|
||||||
helpers.set_map(partition, true)
|
|
||||||
else
|
|
||||||
helpers.set_map(partition, false)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if showpopup == "on" then
|
if showpopup == "on" then
|
||||||
fs.widget:connect_signal('mouse::enter', function () fs:show(0) end)
|
fs.widget:connect_signal('mouse::enter', function () fs.show(0) end)
|
||||||
fs.widget:connect_signal('mouse::leave', function () fs:hide() end)
|
fs.widget:connect_signal('mouse::leave', function () fs.hide() end)
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.newtimer(partition, timeout, update)
|
helpers.newtimer(partition, timeout, fs.update)
|
||||||
|
|
||||||
return setmetatable(fs, { __index = fs.widget })
|
return fs
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(fs, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(fs, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -7,77 +7,71 @@
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local helpers = require("lain.helpers")
|
local helpers = require("lain.helpers")
|
||||||
local async = require("lain.asyncshell")
|
|
||||||
|
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local mouse = mouse
|
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
gsub = string.gsub }
|
gsub = string.gsub }
|
||||||
|
local type = type
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Mail IMAP check
|
-- Mail IMAP check
|
||||||
-- lain.widgets.imap
|
-- lain.widgets.imap
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local imap = {}
|
local imap = { widget = wibox.widget.textbox() }
|
||||||
local args = args or {}
|
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 server = args.server
|
local head_command = "curl --connect-timeout 3 -fsm 3"
|
||||||
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 followmouse = args.followmouse or false
|
|
||||||
local settings = args.settings or function() end
|
|
||||||
|
|
||||||
local head_command = "curl --connect-timeout 3 -fsm 3"
|
|
||||||
local request = "-X 'SEARCH (UNSEEN)'"
|
local request = "-X 'SEARCH (UNSEEN)'"
|
||||||
|
|
||||||
|
if not server or not mail or not password then return end
|
||||||
|
|
||||||
helpers.set_map(mail, 0)
|
helpers.set_map(mail, 0)
|
||||||
|
|
||||||
if not is_plain then
|
if not is_plain then
|
||||||
password = helpers.read_pipe(password):gsub("\n", "")
|
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()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
imap.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
function update()
|
function update()
|
||||||
mail_notification_preset = {
|
mail_notification_preset = {
|
||||||
icon = helpers.icons_dir .. "mail.png",
|
icon = helpers.icons_dir .. "mail.png",
|
||||||
position = "top_left"
|
position = "top_left"
|
||||||
}
|
}
|
||||||
|
|
||||||
if followmouse then
|
if followtag then
|
||||||
mail_notification_preset.screen = mouse.screen
|
mail_notification_preset.screen = awful.screen.focused()
|
||||||
end
|
end
|
||||||
|
|
||||||
curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:%q %s -k",
|
curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:%q %s -k",
|
||||||
head_command, server, port, mail, password, request)
|
head_command, server, port, mail, password, request)
|
||||||
|
|
||||||
async.request(curl, function(f)
|
helpers.async(curl, function(f)
|
||||||
_, mailcount = string.gsub(f, "%d+", "")
|
_, mailcount = string.gsub(f, "%d+", "")
|
||||||
_ = nil
|
_ = nil
|
||||||
|
|
||||||
widget = imap.widget
|
widget = imap.widget
|
||||||
settings()
|
settings()
|
||||||
|
|
||||||
if mailcount >= 1 and mailcount > helpers.get_map(mail)
|
if mailcount >= 1 and mailcount > helpers.get_map(mail) then
|
||||||
then
|
|
||||||
if mailcount == 1 then
|
if mailcount == 1 then
|
||||||
nt = mail .. " has one new message"
|
nt = mail .. " has one new message"
|
||||||
else
|
else
|
||||||
nt = mail .. " has <b>" .. mailcount .. "</b> new messages"
|
nt = mail .. " has <b>" .. mailcount .. "</b> new messages"
|
||||||
end
|
end
|
||||||
naughty.notify({
|
naughty.notify({ preset = mail_notification_preset, text = nt })
|
||||||
preset = mail_notification_preset,
|
|
||||||
text = nt
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.set_map(mail, mailcount)
|
helpers.set_map(mail, mailcount)
|
||||||
|
@ -85,9 +79,9 @@ local function worker(args)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.newtimer(mail, timeout, update, true)
|
imap.timer = helpers.newtimer(mail, timeout, update, true, true)
|
||||||
|
|
||||||
return setmetatable(imap, { __index = imap.widget })
|
return imap
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
|
|
||||||
--[[
|
|
||||||
|
|
||||||
Licensed under GNU General Public License v2
|
|
||||||
* (c) 2013, Luke Bonham
|
|
||||||
* (c) 2010-2012, Peter Hofmann
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
|
||||||
local spairs = require("lain.helpers").spairs
|
|
||||||
|
|
||||||
local wibox = require("wibox")
|
|
||||||
|
|
||||||
local awful = require("awful")
|
|
||||||
local util = require("lain.util")
|
|
||||||
|
|
||||||
local io = { popen = io.popen }
|
|
||||||
local os = { getenv = os.getenv }
|
|
||||||
local pairs = pairs
|
|
||||||
local string = { len = string.len,
|
|
||||||
match = string.match }
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
-- Maildir check
|
|
||||||
-- lain.widgets.maildir
|
|
||||||
local maildir = {}
|
|
||||||
|
|
||||||
local function worker(args)
|
|
||||||
local args = args or {}
|
|
||||||
local timeout = args.timeout or 60
|
|
||||||
local mailpath = args.mailpath or os.getenv("HOME") .. "/Mail"
|
|
||||||
local ignore_boxes = args.ignore_boxes or {}
|
|
||||||
local settings = args.settings or function() end
|
|
||||||
local ext_mail_cmd = args.external_mail_cmd
|
|
||||||
|
|
||||||
maildir.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
function update()
|
|
||||||
if ext_mail_cmd then
|
|
||||||
awful.util.spawn(ext_mail_cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Find pathes to mailboxes.
|
|
||||||
local p = io.popen("find " .. mailpath ..
|
|
||||||
" -mindepth 1 -maxdepth 2 -type d" ..
|
|
||||||
" -not -name .git")
|
|
||||||
local boxes = {}
|
|
||||||
repeat
|
|
||||||
line = p:read("*l")
|
|
||||||
if line ~= nil
|
|
||||||
then
|
|
||||||
-- Find all files in the "new" subdirectory. For each
|
|
||||||
-- file, print a single character (no newline). Don't
|
|
||||||
-- match files that begin with a dot.
|
|
||||||
-- Afterwards the length of this string is the number of
|
|
||||||
-- new mails in that box.
|
|
||||||
local mailstring = read_pipe("find " .. line ..
|
|
||||||
"/new -mindepth 1 -type f " ..
|
|
||||||
"-not -name '.*' -printf a")
|
|
||||||
|
|
||||||
-- Strip off leading mailpath.
|
|
||||||
local box = string.match(line, mailpath .. "/(.*)")
|
|
||||||
local nummails = string.len(mailstring)
|
|
||||||
if nummails > 0
|
|
||||||
then
|
|
||||||
boxes[box] = nummails
|
|
||||||
end
|
|
||||||
end
|
|
||||||
until line == nil
|
|
||||||
|
|
||||||
p:close()
|
|
||||||
|
|
||||||
newmail = "no mail"
|
|
||||||
|
|
||||||
-- Count the total number of mails irrespective of where it was found
|
|
||||||
total = 0
|
|
||||||
|
|
||||||
for box, number in spairs(boxes)
|
|
||||||
do
|
|
||||||
-- Add this box only if it's not to be ignored.
|
|
||||||
if not util.element_in_table(box, ignore_boxes)
|
|
||||||
then
|
|
||||||
total = total + number
|
|
||||||
if newmail == "no mail"
|
|
||||||
then
|
|
||||||
newmail = box .. "(" .. number .. ")"
|
|
||||||
else
|
|
||||||
newmail = newmail .. ", " ..
|
|
||||||
box .. "(" .. number .. ")"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
widget = maildir.widget
|
|
||||||
settings()
|
|
||||||
end
|
|
||||||
|
|
||||||
newtimer(mailpath, timeout, update, true)
|
|
||||||
return maildir.widget
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable(maildir, { __call = function(_, ...) return worker(...) end })
|
|
|
@ -7,14 +7,11 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
local gmatch = string.gmatch
|
||||||
local io = { lines = io.lines }
|
local lines = io.lines
|
||||||
local math = { floor = math.floor }
|
local floor = math.floor
|
||||||
local string = { gmatch = string.gmatch }
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Memory usage (ignoring caches)
|
-- Memory usage (ignoring caches)
|
||||||
|
@ -26,25 +23,24 @@ local function worker(args)
|
||||||
local timeout = args.timeout or 2
|
local timeout = args.timeout or 2
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
mem.widget = wibox.widget.textbox('')
|
mem.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
function update()
|
function mem.update()
|
||||||
mem_now = {}
|
mem_now = {}
|
||||||
for line in io.lines("/proc/meminfo")
|
for line in lines("/proc/meminfo") do
|
||||||
do
|
for k, v in gmatch(line, "([%a]+):[%s]+([%d]+).+") do
|
||||||
for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+")
|
if k == "MemTotal" then mem_now.total = floor(v / 1024 + 0.5)
|
||||||
do
|
elseif k == "MemFree" then mem_now.free = floor(v / 1024 + 0.5)
|
||||||
if k == "MemTotal" then mem_now.total = math.floor(v / 1024)
|
elseif k == "Buffers" then mem_now.buf = floor(v / 1024 + 0.5)
|
||||||
elseif k == "MemFree" then mem_now.free = math.floor(v / 1024)
|
elseif k == "Cached" then mem_now.cache = floor(v / 1024 + 0.5)
|
||||||
elseif k == "Buffers" then mem_now.buf = math.floor(v / 1024)
|
elseif k == "SwapTotal" then mem_now.swap = floor(v / 1024 + 0.5)
|
||||||
elseif k == "Cached" then mem_now.cache = math.floor(v / 1024)
|
elseif k == "SwapFree" then mem_now.swapf = floor(v / 1024 + 0.5)
|
||||||
elseif k == "SwapTotal" then mem_now.swap = math.floor(v / 1024)
|
elseif k == "SReclaimable" then mem_now.srec = floor(v / 1024 + 0.5)
|
||||||
elseif k == "SwapFree" then mem_now.swapf = math.floor(v / 1024)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
mem_now.used = mem_now.total - (mem_now.free + mem_now.buf + mem_now.cache)
|
mem_now.used = mem_now.total - mem_now.free - mem_now.buf - mem_now.cache - mem_now.srec
|
||||||
mem_now.swapused = mem_now.swap - mem_now.swapf
|
mem_now.swapused = mem_now.swap - mem_now.swapf
|
||||||
mem_now.perc = math.floor(mem_now.used / mem_now.total * 100)
|
mem_now.perc = math.floor(mem_now.used / mem_now.total * 100)
|
||||||
|
|
||||||
|
@ -52,9 +48,9 @@ local function worker(args)
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer("mem", timeout, update)
|
helpers.newtimer("mem", timeout, mem.update)
|
||||||
|
|
||||||
return mem.widget
|
return mem
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(mem, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(mem, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
108
widgets/mpd.lua
|
@ -8,20 +8,15 @@
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local helpers = require("lain.helpers")
|
local helpers = require("lain.helpers")
|
||||||
local async = require("lain.asyncshell")
|
local shell = require("awful.util").shell
|
||||||
|
|
||||||
local escape_f = require("awful.util").escape
|
local escape_f = require("awful.util").escape
|
||||||
|
local focused = require("awful.screen").focused
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
local os = { getenv = os.getenv }
|
||||||
local os = { execute = os.execute,
|
local string = { format = string.format,
|
||||||
getenv = os.getenv }
|
gmatch = string.gmatch,
|
||||||
local math = { floor = math.floor }
|
match = string.match }
|
||||||
local mouse = mouse
|
|
||||||
local string = { format = string.format,
|
|
||||||
match = string.match,
|
|
||||||
gmatch = string.gmatch }
|
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- MPD infos
|
-- MPD infos
|
||||||
|
@ -29,34 +24,31 @@ local setmetatable = setmetatable
|
||||||
local mpd = {}
|
local mpd = {}
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 2
|
local timeout = args.timeout or 2
|
||||||
local password = args.password or ""
|
local password = (args.password and #args.password > 0 and string.format("password %s\\n", args.password)) or ""
|
||||||
local host = args.host or "127.0.0.1"
|
local host = args.host or "127.0.0.1"
|
||||||
local port = args.port or "6600"
|
local port = args.port or "6600"
|
||||||
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
|
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
|
||||||
local cover_size = args.cover_size or 100
|
local cover_pattern = args.cover_pattern or "*\\.(jpg|jpeg|png|gif)$"
|
||||||
local default_art = args.default_art or ""
|
local cover_size = args.cover_size or 100
|
||||||
local notify = args.notify or "on"
|
local default_art = args.default_art
|
||||||
local followmouse = args.followmouse or false
|
local notify = args.notify or "on"
|
||||||
local echo_cmd = args.echo_cmd or "echo"
|
local followtag = args.followtag or false
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
local mpdcover = helpers.scripts_dir .. "mpdcover"
|
local mpdh = string.format("telnet://%s:%s", host, port)
|
||||||
local mpdh = "telnet://" .. host .. ":" .. port
|
local echo = string.format("printf \"%sstatus\\ncurrentsong\\nclose\\n\"", password)
|
||||||
local echo = echo_cmd .. " 'password " .. password .. "\nstatus\ncurrentsong\nclose'"
|
local cmd = string.format("%s | curl --connect-timeout 1 -fsm 3 %s", echo, mpdh)
|
||||||
|
|
||||||
mpd.widget = wibox.widget.textbox('')
|
mpd.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
mpd_notification_preset = {
|
mpd_notification_preset = { title = "Now playing", timeout = 6 }
|
||||||
title = "Now playing",
|
|
||||||
timeout = 6
|
|
||||||
}
|
|
||||||
|
|
||||||
helpers.set_map("current mpd track", nil)
|
helpers.set_map("current mpd track", nil)
|
||||||
|
|
||||||
function mpd.update()
|
function mpd.update()
|
||||||
async.request(echo .. " | curl --connect-timeout 1 -fsm 3 " .. mpdh, function (f)
|
helpers.async({ shell, "-c", cmd }, function(f)
|
||||||
mpd_now = {
|
mpd_now = {
|
||||||
random_mode = false,
|
random_mode = false,
|
||||||
single_mode = false,
|
single_mode = false,
|
||||||
|
@ -70,6 +62,8 @@ local function worker(args)
|
||||||
artist = "N/A",
|
artist = "N/A",
|
||||||
title = "N/A",
|
title = "N/A",
|
||||||
album = "N/A",
|
album = "N/A",
|
||||||
|
genre = "N/A",
|
||||||
|
track = "N/A",
|
||||||
date = "N/A",
|
date = "N/A",
|
||||||
time = "N/A",
|
time = "N/A",
|
||||||
elapsed = "N/A"
|
elapsed = "N/A"
|
||||||
|
@ -83,6 +77,8 @@ local function worker(args)
|
||||||
elseif k == "Artist" then mpd_now.artist = escape_f(v)
|
elseif k == "Artist" then mpd_now.artist = escape_f(v)
|
||||||
elseif k == "Title" then mpd_now.title = escape_f(v)
|
elseif k == "Title" then mpd_now.title = escape_f(v)
|
||||||
elseif k == "Album" then mpd_now.album = escape_f(v)
|
elseif k == "Album" then mpd_now.album = escape_f(v)
|
||||||
|
elseif k == "Genre" then mpd_now.genre = escape_f(v)
|
||||||
|
elseif k == "Track" then mpd_now.track = escape_f(v)
|
||||||
elseif k == "Date" then mpd_now.date = escape_f(v)
|
elseif k == "Date" then mpd_now.date = escape_f(v)
|
||||||
elseif k == "Time" then mpd_now.time = v
|
elseif k == "Time" then mpd_now.time = v
|
||||||
elseif k == "elapsed" then mpd_now.elapsed = string.match(v, "%d+")
|
elseif k == "elapsed" then mpd_now.elapsed = string.match(v, "%d+")
|
||||||
|
@ -101,41 +97,41 @@ local function worker(args)
|
||||||
widget = mpd.widget
|
widget = mpd.widget
|
||||||
settings()
|
settings()
|
||||||
|
|
||||||
if mpd_now.state == "play"
|
if mpd_now.state == "play" then
|
||||||
then
|
if notify == "on" and mpd_now.title ~= helpers.get_map("current mpd track") then
|
||||||
if notify == "on" and mpd_now.title ~= helpers.get_map("current mpd track")
|
|
||||||
then
|
|
||||||
helpers.set_map("current mpd track", mpd_now.title)
|
helpers.set_map("current mpd track", mpd_now.title)
|
||||||
|
|
||||||
if string.match(mpd_now.file, "http.*://") == nil
|
if followtag then mpd_notification_preset.screen = focused() end
|
||||||
then -- local file
|
|
||||||
os.execute(string.format("%s %q %q %d %q", mpdcover, music_dir,
|
local common = {
|
||||||
mpd_now.file, cover_size, default_art))
|
preset = mpd_notification_preset,
|
||||||
current_icon = "/tmp/mpdcover.png"
|
icon = default_art,
|
||||||
else -- http stream
|
icon_size = cover_size,
|
||||||
current_icon = default_art
|
replaces_id = mpd.id
|
||||||
|
}
|
||||||
|
|
||||||
|
if not string.match(mpd_now.file, "http.*://") then -- local file instead of http stream
|
||||||
|
local path = string.format("%s/%s", music_dir, string.match(mpd_now.file, ".*/"))
|
||||||
|
local cover = string.format("find '%s' -maxdepth 1 -type f | egrep -i -m1 '%s'", path:gsub("'", "'\\''"), cover_pattern)
|
||||||
|
helpers.async({ shell, "-c", cover }, function(current_icon)
|
||||||
|
common.icon = current_icon:gsub("\n", "")
|
||||||
|
if #common.icon == 0 then common.icon = nil end
|
||||||
|
mpd.id = naughty.notify(common).id
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
mpd.id = naughty.notify(common).id
|
||||||
end
|
end
|
||||||
|
|
||||||
if followmouse then
|
|
||||||
mpd_notification_preset.screen = mouse.screen
|
|
||||||
end
|
|
||||||
|
|
||||||
mpd.id = naughty.notify({
|
|
||||||
preset = mpd_notification_preset,
|
|
||||||
icon = current_icon,
|
|
||||||
replaces_id = mpd.id,
|
|
||||||
}).id
|
|
||||||
end
|
end
|
||||||
elseif mpd_now.state ~= "pause"
|
elseif mpd_now.state ~= "pause" then
|
||||||
then
|
|
||||||
helpers.set_map("current mpd track", nil)
|
helpers.set_map("current mpd track", nil)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.newtimer("mpd", timeout, mpd.update)
|
mpd.timer = helpers.newtimer("mpd", timeout, mpd.update, true, true)
|
||||||
|
|
||||||
return setmetatable(mpd, { __index = mpd.widget })
|
return mpd
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(mpd, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(mpd, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -10,55 +10,40 @@
|
||||||
local helpers = require("lain.helpers")
|
local helpers = require("lain.helpers")
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
gsub = string.gsub,
|
|
||||||
match = string.match }
|
match = string.match }
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- Network infos
|
-- Network infos
|
||||||
-- lain.widgets.net
|
-- lain.widgets.net
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local net = { last_t = 0, last_r = 0, devices = {} }
|
local net = { widget = wibox.widget.textbox() }
|
||||||
|
net.last_t = 0
|
||||||
|
net.last_r = 0
|
||||||
|
net.devices = {}
|
||||||
|
|
||||||
function net.get_first_device()
|
local args = args or {}
|
||||||
local ws = helpers.read_pipe("ip link show | cut -d' ' -f2,9")
|
local timeout = args.timeout or 2
|
||||||
ws = ws:match("%w+: UP") or ws:match("ppp%w+: UNKNOWN")
|
local units = args.units or 1024 --kb
|
||||||
if ws then return { ws:match("(%w+):") }
|
local notify = args.notify or "on"
|
||||||
else return {} end
|
local screen = args.screen or 1
|
||||||
end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
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 iface = args.iface or net.get_first_device()
|
|
||||||
|
|
||||||
net.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
-- Compatibility with old API where iface was a string corresponding to 1 interface
|
-- Compatibility with old API where iface was a string corresponding to 1 interface
|
||||||
if type(iface) == "string" then
|
net.iface = (args.iface and (type(args.iface) == "string" and {args.iface}) or
|
||||||
iftable = {iface}
|
(type(args.iface) == "table" and args.iface)) or {}
|
||||||
else
|
|
||||||
iftable = iface
|
function net.get_device()
|
||||||
|
helpers.async(string.format("ip link show", device_cmd), function(ws)
|
||||||
|
ws = ws:match("(%w+): <BROADCAST,MULTICAST,.-UP,LOWER_UP>")
|
||||||
|
net.iface = ws and { ws } or {}
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Mark all devices as initially online/active
|
if #net.iface == 0 then net.get_device() end
|
||||||
for i, dev in ipairs(iftable) do
|
|
||||||
helpers.set_map(dev, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
function update()
|
function update()
|
||||||
-- This check is required to ensure we keep looking for one device if
|
|
||||||
-- none is found by net.get_first_device() at startup (i.e. iftable = {})
|
|
||||||
if next(iftable) == nil then
|
|
||||||
iftable = net.get_first_device()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- These are the totals over all specified interfaces
|
-- These are the totals over all specified interfaces
|
||||||
net_now = {
|
net_now = {
|
||||||
-- New api - Current state of requested devices
|
-- New api - Current state of requested devices
|
||||||
|
@ -72,15 +57,14 @@ local function worker(args)
|
||||||
local total_t = 0
|
local total_t = 0
|
||||||
local total_r = 0
|
local total_r = 0
|
||||||
|
|
||||||
for i, dev in ipairs(iftable) do
|
for i, dev in ipairs(net.iface) do
|
||||||
local dev_now = {}
|
local dev_now = {}
|
||||||
local dev_before = net.devices[dev] or { last_t = 0, last_r = 0 }
|
local dev_before = net.devices[dev] or { last_t = 0, last_r = 0 }
|
||||||
|
local now_t = tonumber(helpers.first_line(string.format("/sys/class/net/%s/statistics/tx_bytes", dev)) or 0)
|
||||||
|
local now_r = tonumber(helpers.first_line(string.format("/sys/class/net/%s/statistics/rx_bytes", dev)) or 0)
|
||||||
|
|
||||||
dev_now.carrier = helpers.first_line(string.format('/sys/class/net/%s/carrier', dev)) or '0'
|
dev_now.carrier = helpers.first_line(string.format("/sys/class/net/%s/carrier", dev)) or "0"
|
||||||
dev_now.state = helpers.first_line(string.format('/sys/class/net/%s/operstate', dev)) or 'down'
|
dev_now.state = helpers.first_line(string.format("/sys/class/net/%s/operstate", dev)) or "down"
|
||||||
|
|
||||||
local now_t = tonumber(helpers.first_line(string.format('/sys/class/net/%s/statistics/tx_bytes', dev)) or 0)
|
|
||||||
local now_r = tonumber(helpers.first_line(string.format('/sys/class/net/%s/statistics/rx_bytes', dev)) or 0)
|
|
||||||
|
|
||||||
dev_now.sent = (now_t - dev_before.last_t) / timeout / units
|
dev_now.sent = (now_t - dev_before.last_t) / timeout / units
|
||||||
dev_now.received = (now_r - dev_before.last_r) / timeout / units
|
dev_now.received = (now_r - dev_before.last_r) / timeout / units
|
||||||
|
@ -88,8 +72,8 @@ local function worker(args)
|
||||||
net_now.sent = net_now.sent + dev_now.sent
|
net_now.sent = net_now.sent + dev_now.sent
|
||||||
net_now.received = net_now.received + dev_now.received
|
net_now.received = net_now.received + dev_now.received
|
||||||
|
|
||||||
dev_now.sent = string.gsub(string.format('%.1f', dev_now.sent), ',', '.')
|
dev_now.sent = string.format('%.1f', dev_now.sent)
|
||||||
dev_now.received = string.gsub(string.format('%.1f', dev_now.received), ',', '.')
|
dev_now.received = string.format('%.1f', dev_now.received)
|
||||||
|
|
||||||
dev_now.last_t = now_t
|
dev_now.last_t = now_t
|
||||||
dev_now.last_r = now_r
|
dev_now.last_r = now_r
|
||||||
|
@ -113,32 +97,27 @@ local function worker(args)
|
||||||
helpers.set_map(dev, true)
|
helpers.set_map(dev, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Old api compatibility
|
|
||||||
net_now.carrier = dev_now.carrier
|
net_now.carrier = dev_now.carrier
|
||||||
net_now.state = dev_now.state
|
net_now.state = dev_now.state
|
||||||
-- And new api
|
|
||||||
net_now.devices[dev] = dev_now
|
net_now.devices[dev] = dev_now
|
||||||
-- With the new api new_now.sent and net_now.received will be the
|
-- new_now.sent and net_now.received will be the
|
||||||
-- totals across all specified devices
|
-- totals across all specified devices
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if total_t ~= net.last_t or total_r ~= net.last_r then
|
if total_t ~= net.last_t or total_r ~= net.last_r then
|
||||||
-- Convert to a string to round the digits after the float point
|
net_now.sent = string.format('%.1f', net_now.sent)
|
||||||
net_now.sent = string.gsub(string.format('%.1f', net_now.sent), ',', '.')
|
net_now.received = string.format('%.1f', net_now.received)
|
||||||
net_now.received = string.gsub(string.format('%.1f', net_now.received), ',', '.')
|
net.last_t = total_t
|
||||||
|
net.last_r = total_r
|
||||||
net.last_t = total_t
|
|
||||||
net.last_r = total_r
|
|
||||||
end
|
end
|
||||||
|
|
||||||
widget = net.widget
|
widget = net.widget
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers.newtimer(iface, timeout, update)
|
helpers.newtimer("network", timeout, update)
|
||||||
|
|
||||||
return setmetatable(net, { __index = net.widget })
|
return net
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,55 +6,57 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
local helpers = require("lain.helpers")
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local shell = require("awful.util").shell
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local string = { gmatch = string.gmatch,
|
local string = { gmatch = string.gmatch,
|
||||||
match = string.match,
|
match = string.match,
|
||||||
format = string.format }
|
format = string.format }
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- PulseAudio volume
|
-- PulseAudio volume
|
||||||
-- lain.widgets.pulseaudio
|
-- lain.widgets.pulseaudio
|
||||||
local pulseaudio = {}
|
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local pulseaudio = { wibox.widget.textbox() }
|
||||||
local timeout = args.timeout or 5
|
local args = args or {}
|
||||||
local settings = args.settings or function() end
|
local devicetype = args.devicetype or "sink"
|
||||||
local scallback = args.scallback
|
local timeout = args.timeout or 5
|
||||||
|
local settings = args.settings or function() end
|
||||||
|
local scallback = args.scallback
|
||||||
|
|
||||||
pulseaudio.cmd = args.cmd or string.format("pacmd list-sinks | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'")
|
pulseaudio.cmd = args.cmd or "pacmd list-" .. devicetype .. "s | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p' -e '/device\\.string/p'"
|
||||||
pulseaudio.widget = wibox.widget.textbox('')
|
|
||||||
|
|
||||||
function pulseaudio.update()
|
function pulseaudio.update()
|
||||||
if scallback then pulseaudio.cmd = scallback() end
|
if scallback then pulseaudio.cmd = scallback() end
|
||||||
local s = read_pipe(pulseaudio.cmd)
|
|
||||||
|
|
||||||
volume_now = {}
|
helpers.async({ shell, "-c", pulseaudio.cmd }, function(s)
|
||||||
volume_now.index = string.match(s, "index: (%S+)") or "N/A"
|
volume_now = {
|
||||||
volume_now.sink = string.match(s, "device.string = \"(%S+)\"") or "N/A"
|
index = string.match(s, "index: (%S+)") or "N/A",
|
||||||
volume_now.muted = string.match(s, "muted: (%S+)") or "N/A"
|
device = string.match(s, "device.string = \"(%S+)\"") or "N/A",
|
||||||
|
sink = device, -- legacy API
|
||||||
|
muted = string.match(s, "muted: (%S+)") or "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
local ch = 1
|
local ch = 1
|
||||||
volume_now.channel = {}
|
volume_now.channel = {}
|
||||||
for v in string.gmatch(s, ":.-(%d+)%%") do
|
for v in string.gmatch(s, ":.-(%d+)%%") do
|
||||||
volume_now.channel[ch] = v
|
volume_now.channel[ch] = v
|
||||||
ch = ch + 1
|
ch = ch + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
volume_now.left = volume_now.channel[1] or "N/A"
|
volume_now.left = volume_now.channel[1] or "N/A"
|
||||||
volume_now.right = volume_now.channel[2] or "N/A"
|
volume_now.right = volume_now.channel[2] or "N/A"
|
||||||
|
|
||||||
widget = pulseaudio.widget
|
widget = pulseaudio.widget
|
||||||
settings()
|
|
||||||
end
|
|
||||||
|
|
||||||
newtimer(string.format("pulseaudio-%s", timeout), timeout, pulseaudio.update)
|
settings()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
return setmetatable(pulseaudio, { __index = pulseaudio.widget })
|
helpers.newtimer("pulseaudio", timeout, pulseaudio.update)
|
||||||
|
|
||||||
|
return pulseaudio
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(pulseaudio, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -7,90 +7,32 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
|
||||||
|
|
||||||
local awful = require("awful")
|
local awful = require("awful")
|
||||||
local beautiful = require("beautiful")
|
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
|
local wibox = require("wibox")
|
||||||
local math = { modf = math.modf }
|
local math = { modf = math.modf }
|
||||||
local mouse = mouse
|
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
|
gmatch = string.gmatch,
|
||||||
match = string.match,
|
match = string.match,
|
||||||
rep = string.rep }
|
rep = string.rep }
|
||||||
|
local type = type
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- ALSA volume bar
|
-- Pulseaudio volume bar
|
||||||
-- lain.widgets.pulsebar
|
-- lain.widgets.pulsebar
|
||||||
local pulsebar = {
|
local pulsebar = {
|
||||||
sink = 0,
|
|
||||||
step = "1%",
|
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
background = beautiful.bg_normal,
|
background = "#000000",
|
||||||
mute = "#EB8F8F",
|
mute = "#EB8F8F",
|
||||||
unmute = "#A4CE8A"
|
unmute = "#A4CE8A"
|
||||||
},
|
},
|
||||||
|
|
||||||
mixer = "pavucontrol",
|
|
||||||
|
|
||||||
notifications = {
|
|
||||||
font = beautiful.font:sub(beautiful.font:find(""), beautiful.font:find(" ")),
|
|
||||||
font_size = "11",
|
|
||||||
color = beautiful.fg_normal,
|
|
||||||
bar_size = 18,
|
|
||||||
screen = 1
|
|
||||||
},
|
|
||||||
|
|
||||||
_current_level = 0,
|
_current_level = 0,
|
||||||
_muted = false
|
_muted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function pulsebar.notify()
|
|
||||||
pulsebar.update()
|
|
||||||
|
|
||||||
local preset = {
|
|
||||||
title = "",
|
|
||||||
text = "",
|
|
||||||
timeout = 5,
|
|
||||||
screen = pulsebar.notifications.screen,
|
|
||||||
font = pulsebar.notifications.font .. " " ..
|
|
||||||
pulsebar.notifications.font_size,
|
|
||||||
fg = pulsebar.notifications.color
|
|
||||||
}
|
|
||||||
|
|
||||||
if pulsebar._muted
|
|
||||||
then
|
|
||||||
preset.title = "Sink " .. pulsebar.sink .. " - Muted"
|
|
||||||
else
|
|
||||||
preset.title = "Sink " .. pulsebar.sink .. " - " .. pulsebar._current_level .. "%"
|
|
||||||
end
|
|
||||||
|
|
||||||
int = math.modf((pulsebar._current_level / 100) * pulsebar.notifications.bar_size)
|
|
||||||
preset.text = "["
|
|
||||||
.. string.rep("|", int)
|
|
||||||
.. string.rep(" ", pulsebar.notifications.bar_size - int)
|
|
||||||
.. "]"
|
|
||||||
|
|
||||||
if pulsebar.followmouse then
|
|
||||||
preset.screen = mouse.screen
|
|
||||||
end
|
|
||||||
|
|
||||||
if pulsebar._notify ~= nil then
|
|
||||||
pulsebar._notify = naughty.notify ({
|
|
||||||
replaces_id = pulsebar._notify.id,
|
|
||||||
preset = preset,
|
|
||||||
})
|
|
||||||
else
|
|
||||||
pulsebar._notify = naughty.notify ({
|
|
||||||
preset = preset,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 5
|
local timeout = args.timeout or 5
|
||||||
|
@ -102,79 +44,103 @@ local function worker(args)
|
||||||
local vertical = args.vertical or false
|
local vertical = args.vertical or false
|
||||||
local scallback = args.scallback
|
local scallback = args.scallback
|
||||||
|
|
||||||
pulsebar.cmd = args.cmd or string.format("pacmd list-sinks | sed -n -e '0,/*/d' -e '/base volume/d' -e '/volume:/p' -e '/muted:/p'")
|
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.colors = args.colors or pulsebar.colors
|
|
||||||
pulsebar.notifications = args.notifications or pulsebar.notifications
|
|
||||||
pulsebar.sink = args.sink or 0
|
pulsebar.sink = args.sink or 0
|
||||||
pulsebar.step = args.step or pulsebar.step
|
pulsebar.colors = args.colors or pulsebar.colors
|
||||||
pulsebar.followmouse = args.followmouse or false
|
pulsebar.followtag = args.followtag or false
|
||||||
|
pulsebar.notifications = args.notification_preset
|
||||||
|
|
||||||
pulsebar.bar = awful.widget.progressbar()
|
if not pulsebar.notification_preset then
|
||||||
|
pulsebar.notification_preset = {}
|
||||||
pulsebar.bar:set_background_color(pulsebar.colors.background)
|
pulsebar.notification_preset.font = "Monospace 10"
|
||||||
pulsebar.bar:set_color(pulsebar.colors.unmute)
|
|
||||||
pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
|
|
||||||
pulsebar.bar:set_width(width)
|
|
||||||
pulsebar.bar:set_height(height)
|
|
||||||
pulsebar.bar:set_ticks(ticks)
|
|
||||||
pulsebar.bar:set_ticks_size(ticks_size)
|
|
||||||
pulsebar.bar:set_vertical(vertical)
|
|
||||||
|
|
||||||
function pulsebar.update()
|
|
||||||
if scallback then pulseaudio.cmd = scallback() end
|
|
||||||
local s = read_pipe(pulsebar.cmd)
|
|
||||||
|
|
||||||
volume_now = {}
|
|
||||||
volume_now.left = tonumber(string.match(s, ":.-(%d+)%%"))
|
|
||||||
volume_now.right = tonumber(string.match(s, ":.-(%d+)%%"))
|
|
||||||
volume_now.muted = string.match(s, "muted: (%S+)")
|
|
||||||
|
|
||||||
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
|
|
||||||
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] ")
|
|
||||||
pulsebar.bar:set_color(pulsebar.colors.mute)
|
|
||||||
else
|
|
||||||
pulsebar._muted = false
|
|
||||||
pulsebar.tooltip:set_text(string.format(" %s:%s ", pulsebar.sink, volu))
|
|
||||||
pulsebar.bar:set_color(pulsebar.colors.unmute)
|
|
||||||
end
|
|
||||||
settings()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pulsebar.bar:buttons(awful.util.table.join (
|
pulsebar.bar = wibox.widget {
|
||||||
awful.button({}, 1, function()
|
forced_height = height,
|
||||||
awful.util.spawn(pulsebar.mixer)
|
forced_width = width,
|
||||||
end),
|
color = pulsebar.colors.unmute,
|
||||||
awful.button({}, 2, function()
|
background_color = pulsebar.colors.background,
|
||||||
awful.util.spawn(string.format("pactl set-sink-volume %d 100%%", pulsebar.sink))
|
margins = 1,
|
||||||
pulsebar.update()
|
paddings = 1,
|
||||||
end),
|
ticks = ticks,
|
||||||
awful.button({}, 3, function()
|
ticks_size = ticks_size,
|
||||||
awful.util.spawn(string.format("pactl set-sink-mute %d toggle", pulsebar.sink))
|
widget = wibox.widget.progressbar,
|
||||||
pulsebar.update()
|
layout = vertical and wibox.container.rotate
|
||||||
end),
|
}
|
||||||
awful.button({}, 4, function()
|
|
||||||
awful.util.spawn(string.format("pactl set-sink-volume %d +%s", pulsebar.sink, pulsebar.step))
|
|
||||||
pulsebar.update()
|
|
||||||
end),
|
|
||||||
awful.button({}, 5, function()
|
|
||||||
awful.util.spawn(string.format("pactl set-sink-volume %d -%s", pulsebar.sink, pulsebar.step))
|
|
||||||
pulsebar.update()
|
|
||||||
end)
|
|
||||||
))
|
|
||||||
|
|
||||||
timer_id = string.format("pulsebar-%s", pulsebar.sink)
|
pulsebar.tooltip = awful.tooltip({ objects = { pulsebar.bar } })
|
||||||
|
|
||||||
newtimer(timer_id, timeout, pulsebar.update)
|
function pulsebar.update(callback)
|
||||||
|
if scallback then pulseaudio.cmd = scallback() end
|
||||||
|
|
||||||
|
helpers.async({ awful.util.shell, "-c", 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
local ch = 1
|
||||||
|
volume_now.channel = {}
|
||||||
|
for v in string.gmatch(s, ":.-(%d+)%%") do
|
||||||
|
volume_now.channel[ch] = v
|
||||||
|
ch = ch + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
volume_now.left = volume_now.channel[1] or "N/A"
|
||||||
|
volume_now.right = volume_now.channel[2] or "N/A"
|
||||||
|
|
||||||
|
local volu = volume_now.left
|
||||||
|
local mute = volume_now.muted
|
||||||
|
|
||||||
|
if (volu and volu ~= pulsebar._current_level) or (mute and mute ~= pulsebar._muted) then
|
||||||
|
pulsebar._current_level = 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]")
|
||||||
|
pulsebar.bar.color = pulsebar.colors.mute
|
||||||
|
else
|
||||||
|
pulsebar._muted = false
|
||||||
|
pulsebar.tooltip:set_text(string.format("%s: %s", pulsebar.sink, volu))
|
||||||
|
pulsebar.bar.color = pulsebar.colors.unmute
|
||||||
|
end
|
||||||
|
|
||||||
|
settings()
|
||||||
|
|
||||||
|
if type(callback) == "function" then callback() end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pulsebar.notify()
|
||||||
|
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)
|
||||||
|
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))
|
||||||
|
|
||||||
|
if pulsebar.followtag then preset.screen = awful.screen.focused() end
|
||||||
|
|
||||||
|
if not pulsebar.notification then
|
||||||
|
pulsebar.notification = naughty.notify {
|
||||||
|
preset = preset,
|
||||||
|
destroy = function() pulsebar.notification = nil end
|
||||||
|
}
|
||||||
|
else
|
||||||
|
naughty.replace_text(pulsebar.notification, preset.title, preset.text)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
helpers.newtimer(string.format("pulsebar-%s", pulsebar.sink), timeout, pulsebar.update)
|
||||||
|
|
||||||
return pulsebar
|
return pulsebar
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,13 +7,10 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local io = { open = io.open }
|
local io = { open = io.open }
|
||||||
local string = { match = string.match }
|
local string = { match = string.match }
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- System load
|
-- System load
|
||||||
|
@ -21,13 +18,13 @@ local setmetatable = setmetatable
|
||||||
local sysload = {}
|
local sysload = {}
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local timeout = args.timeout or 2
|
local timeout = args.timeout or 2
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
sysload.widget = wibox.widget.textbox('')
|
sysload.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
function update()
|
function sysload.update()
|
||||||
local f = io.open("/proc/loadavg")
|
local f = io.open("/proc/loadavg")
|
||||||
local ret = f:read("*all")
|
local ret = f:read("*all")
|
||||||
f:close()
|
f:close()
|
||||||
|
@ -38,8 +35,9 @@ local function worker(args)
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer("sysload", timeout, update)
|
helpers.newtimer("sysload", timeout, sysload.update)
|
||||||
return sysload.widget
|
|
||||||
|
return sysload
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(sysload, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(sysload, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,13 +6,10 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
|
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local io = { open = io.open }
|
local io = { open = io.open }
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
|
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
-- coretemp
|
-- coretemp
|
||||||
|
@ -25,9 +22,9 @@ local function worker(args)
|
||||||
local tempfile = args.tempfile or "/sys/class/thermal/thermal_zone0/temp"
|
local tempfile = args.tempfile or "/sys/class/thermal/thermal_zone0/temp"
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
temp.widget = wibox.widget.textbox('')
|
temp.widget = wibox.widget.textbox()
|
||||||
|
|
||||||
function update()
|
function temp.update()
|
||||||
local f = io.open(tempfile)
|
local f = io.open(tempfile)
|
||||||
if f then
|
if f then
|
||||||
coretemp_now = tonumber(f:read("*all")) / 1000
|
coretemp_now = tonumber(f:read("*all")) / 1000
|
||||||
|
@ -40,9 +37,9 @@ local function worker(args)
|
||||||
settings()
|
settings()
|
||||||
end
|
end
|
||||||
|
|
||||||
newtimer("coretemp", timeout, update)
|
helpers.newtimer("coretemp", timeout, temp.update)
|
||||||
|
|
||||||
return temp.widget
|
return temp
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable(temp, { __call = function(_, ...) return worker(...) end })
|
return setmetatable(temp, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
|
@ -6,24 +6,17 @@
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
local newtimer = require("lain.helpers").newtimer
|
local helpers = require("lain.helpers")
|
||||||
local read_pipe = require("lain.helpers").read_pipe
|
|
||||||
|
|
||||||
local async = require("lain.asyncshell")
|
|
||||||
local json = require("lain.util").dkjson
|
local json = require("lain.util").dkjson
|
||||||
local lain_icons = require("lain.helpers").icons_dir
|
local focused = require("awful.screen").focused
|
||||||
|
|
||||||
local naughty = require("naughty")
|
local naughty = require("naughty")
|
||||||
local wibox = require("wibox")
|
local wibox = require("wibox")
|
||||||
|
|
||||||
local math = { floor = math.floor }
|
local math = { floor = math.floor }
|
||||||
local os = { time = os.time,
|
local os = { time = os.time,
|
||||||
date = os.date,
|
date = os.date,
|
||||||
difftime = os.difftime }
|
difftime = os.difftime }
|
||||||
local string = { format = string.format,
|
local string = { format = string.format,
|
||||||
gsub = string.gsub }
|
gsub = string.gsub }
|
||||||
|
|
||||||
local mouse = mouse
|
|
||||||
local tonumber = tonumber
|
local tonumber = tonumber
|
||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
|
@ -32,7 +25,7 @@ local setmetatable = setmetatable
|
||||||
-- lain.widgets.weather
|
-- lain.widgets.weather
|
||||||
|
|
||||||
local function worker(args)
|
local function worker(args)
|
||||||
local weather = {}
|
local weather = { widget = wibox.widget.textbox() }
|
||||||
local args = args or {}
|
local args = args or {}
|
||||||
local APPID = args.APPID or "3e321f9414eaedbfab34983bda77a66e" -- lain default
|
local APPID = args.APPID or "3e321f9414eaedbfab34983bda77a66e" -- lain default
|
||||||
local timeout = args.timeout or 900 -- 15 min
|
local timeout = args.timeout or 900 -- 15 min
|
||||||
|
@ -49,32 +42,33 @@ local function worker(args)
|
||||||
local lang = args.lang or "en"
|
local lang = args.lang or "en"
|
||||||
local cnt = args.cnt or 5
|
local cnt = args.cnt or 5
|
||||||
local date_cmd = args.date_cmd or "date -u -d @%d +'%%a %%d'"
|
local date_cmd = args.date_cmd or "date -u -d @%d +'%%a %%d'"
|
||||||
local icons_path = args.icons_path or lain_icons .. "openweathermap/"
|
local icons_path = args.icons_path or helpers.icons_dir .. "openweathermap/"
|
||||||
local notification_preset = args.notification_preset or {}
|
local notification_preset = args.notification_preset or {}
|
||||||
local notification_text_fun = args.notification_text_fun or
|
local notification_text_fun = args.notification_text_fun or
|
||||||
function (wn)
|
function (wn)
|
||||||
local day = string.gsub(read_pipe(string.format(date_cmd, wn["dt"])), "\n", "")
|
local day = os.date("%a %d", wn["dt"])
|
||||||
local tmin = math.floor(wn["temp"]["min"])
|
local tmin = math.floor(wn["temp"]["min"])
|
||||||
local tmax = math.floor(wn["temp"]["max"])
|
local tmax = math.floor(wn["temp"]["max"])
|
||||||
local desc = wn["weather"][1]["description"]
|
local desc = wn["weather"][1]["description"]
|
||||||
return string.format("<b>%s</b>: %s, %d - %d ", day, desc, tmin, tmax)
|
return string.format("<b>%s</b>: %s, %d - %d ", day, desc, tmin, tmax)
|
||||||
end
|
end
|
||||||
local weather_na_markup = args.weather_na_markup or " N/A "
|
local weather_na_markup = args.weather_na_markup or " N/A "
|
||||||
local followmouse = args.followmouse or false
|
local followtag = args.followtag or false
|
||||||
local settings = args.settings or function() end
|
local settings = args.settings or function() end
|
||||||
|
|
||||||
weather.widget = wibox.widget.textbox(weather_na_markup)
|
weather.widget:set_markup(weather_na_markup)
|
||||||
weather.icon_path = icons_path .. "na.png"
|
weather.icon_path = icons_path .. "na.png"
|
||||||
weather.icon = wibox.widget.imagebox(weather.icon_path)
|
weather.icon = wibox.widget.imagebox(weather.icon_path)
|
||||||
|
|
||||||
function weather.show(t_out)
|
function weather.show(t_out)
|
||||||
weather.hide()
|
weather.hide()
|
||||||
|
|
||||||
if followmouse then
|
if followtag then
|
||||||
notification_preset.screen = mouse.screen
|
notification_preset.screen = focused()
|
||||||
end
|
end
|
||||||
|
|
||||||
if not weather.notification_text then
|
if not weather.notification_text then
|
||||||
|
weather.update()
|
||||||
weather.forecast_update()
|
weather.forecast_update()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,7 +98,7 @@ local function worker(args)
|
||||||
|
|
||||||
function weather.forecast_update()
|
function weather.forecast_update()
|
||||||
local cmd = string.format(forecast_call, city_id, units, lang, cnt, APPID)
|
local cmd = string.format(forecast_call, city_id, units, lang, cnt, APPID)
|
||||||
async.request(cmd, function(f)
|
helpers.async(cmd, function(f)
|
||||||
local pos, err
|
local pos, err
|
||||||
weather_now, pos, err = json.decode(f, 1, nil)
|
weather_now, pos, err = json.decode(f, 1, nil)
|
||||||
|
|
||||||
|
@ -124,7 +118,7 @@ local function worker(args)
|
||||||
|
|
||||||
function weather.update()
|
function weather.update()
|
||||||
local cmd = string.format(current_call, city_id, units, lang, APPID)
|
local cmd = string.format(current_call, city_id, units, lang, APPID)
|
||||||
async.request(cmd, function(f)
|
helpers.async(cmd, function(f)
|
||||||
local pos, err, icon
|
local pos, err, icon
|
||||||
weather_now, pos, err = json.decode(f, 1, nil)
|
weather_now, pos, err = json.decode(f, 1, nil)
|
||||||
|
|
||||||
|
@ -134,12 +128,9 @@ local function worker(args)
|
||||||
local sunrise = tonumber(weather_now["sys"]["sunrise"])
|
local sunrise = tonumber(weather_now["sys"]["sunrise"])
|
||||||
local sunset = tonumber(weather_now["sys"]["sunset"])
|
local sunset = tonumber(weather_now["sys"]["sunset"])
|
||||||
local icon = weather_now["weather"][1]["icon"]
|
local icon = weather_now["weather"][1]["icon"]
|
||||||
local utc_m = string.gsub(read_pipe(string.format("date -u -d 'today 00:00:00' +'%%s'")), "\n", "")
|
local loc_m = os.time { year = os.date("%Y"), month = os.date("%m"), day = os.date("%d"), hour = 0 }
|
||||||
local loc_m = string.gsub(read_pipe(string.format("date -d 'today 00:00:00' +'%%s'")), "\n", "")
|
local offset = utc_offset()
|
||||||
|
local utc_m = loc_m + offset
|
||||||
loc_m = tonumber(loc_m)
|
|
||||||
utc_m = tonumber(utc_m)
|
|
||||||
offset = utc_offset()
|
|
||||||
|
|
||||||
-- if we are 1 day after the GMT, return 1 day back, and viceversa
|
-- if we are 1 day after the GMT, return 1 day back, and viceversa
|
||||||
if offset > 0 and loc_m >= utc_m then
|
if offset > 0 and loc_m >= utc_m then
|
||||||
|
@ -168,10 +159,10 @@ local function worker(args)
|
||||||
|
|
||||||
weather.attach(weather.widget)
|
weather.attach(weather.widget)
|
||||||
|
|
||||||
newtimer("weather-" .. city_id, timeout, weather.update)
|
weather.timer = helpers.newtimer("weather-" .. city_id, timeout, weather.update, false, true)
|
||||||
newtimer("weather_forecast-" .. city_id, timeout, weather.forecast_update)
|
weather.timer_forecast = helpers.newtimer("weather_forecast-" .. city_id, timeout, weather.forecast_update, false, true)
|
||||||
|
|
||||||
return setmetatable(weather, { __index = weather.widget })
|
return weather
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
return setmetatable({}, { __call = function(_, ...) return worker(...) end })
|
||||||
|
|
2
wiki
|
@ -1 +1 @@
|
||||||
Subproject commit d0df450d05655c5d8f724c42dc6b5d18b3676a60
|
Subproject commit af671ad9bb1ce9c7bb74a75f489a3b5d0a934558
|