initial commit

This commit is contained in:
sqozz 2015-01-14 19:51:01 +01:00
commit f25e579fed
416 changed files with 6475 additions and 0 deletions

57
awesome/eminent/init.lua Normal file
View file

@ -0,0 +1,57 @@
------------------------------------------
-- Effortless wmii-style dynamic tagging.
------------------------------------------
-- Lucas de Vries <lucas@glacicle.org>
-- Licensed under the WTFPL version 2
-- * http://sam.zoy.org/wtfpl/COPYING
-----------------------------------------
-- Cut version
-----------------------------------------
-- Grab environment
local ipairs = ipairs
local awful = require("awful")
local table = table
local capi = {
screen = screen,
}
-- Eminent: Effortless wmii-style dynamic tagging
module("eminent")
-- Grab the original functions we're replacing
local deflayout = nil
local orig = {
new = awful.tag.new,
taglist = awful.widget.taglist.new,
filter = awful.widget.taglist.filter.all,
}
-- Return tags with stuff on them, mark others hidden
function gettags(screen)
local tags = {}
for k, t in ipairs(capi.screen[screen]:tags()) do
if t.selected or #t:clients() > 0 then
awful.tag.setproperty(t, "hide", false)
table.insert(tags, t)
else
awful.tag.setproperty(t, "hide", true)
end
end
return tags
end
-- Pre-create tags
awful.tag.new = function (names, screen, layout)
deflayout = layout and layout[1] or layout
return orig.new(names, screen, layout)
end
-- Taglist label functions
awful.widget.taglist.filter.all = function (t, args)
if t.selected or #t:clients() > 0 then
return orig.filter(t, args)
end
end

3
awesome/lain/.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "wiki"]
path = wiki
url = https://github.com/copycat-killer/lain.wiki.git

47
awesome/lain/README.rst Normal file
View file

@ -0,0 +1,47 @@
Lain
====
--------------------------------------------------
Layouts, widgets and utilities for Awesome WM 3.5+
--------------------------------------------------
:Author: Luke Bonham <dada [at] archlinux [dot] info>
:Version: git
:License: GNU-GPLv2_
:Source: https://github.com/copycat-killer/lain
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.
Read the wiki_ for all the info.
Contributions
-------------
Any contribution is welcome! Feel free to make a pull request.
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 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 eventually update ``wiki`` submodule with a thorough section.
Contributed widgets have to be put in ``lain/widgets/contrib``.
Screenshots
-----------
.. image:: http://i.imgur.com/8D9A7lW.png
.. image:: http://i.imgur.com/9Iv3OR3.png
.. image:: http://i.imgur.com/STCPcaJ.png
.. _GNU-GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
.. _awesome-vain: https://github.com/vain/awesome-vain
.. _Awesome: http://awesome.naquadah.org/
.. _wiki: https://github.com/copycat-killer/lain/wiki

View file

@ -0,0 +1,82 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Alexander Yakushev
--]]
-- Asynchronous io.popen for Awesome WM.
-- How to use...
-- ...asynchronously:
-- asyncshell.request('wscript -Kiev', function(f) wwidget.text = f:read("*l") end)
-- ...synchronously
-- widget:set_text(asyncshell.demand('wscript -Kiev', 5):read("*l") or "Error")
-- This is more cpu demanding, but makes things faster.
local spawn = require('awful.util').spawn
asyncshell = {}
asyncshell.request_table = {}
asyncshell.id_counter = 0
asyncshell.folder = "/tmp/asyncshell"
asyncshell.file_template = asyncshell.folder .. '/req'
-- Create a directory for asynchell response files
os.execute("mkdir -p " .. asyncshell.folder)
-- Returns next tag - unique identifier of the request
local function next_id()
asyncshell.id_counter = (asyncshell.id_counter + 1) % 100000
return asyncshell.id_counter
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
-- @return Request ID
function asyncshell.request(command, callback)
local id = next_id()
local tmpfname = asyncshell.file_template .. id
asyncshell.request_table[id] = { callback = callback }
local req =
string.format("sh -c '%s > %s; " ..
'echo "asyncshell.deliver(%s)" | ' ..
"awesome-client' 2> /dev/null",
string.gsub(command, "'", "'\\''"), tmpfname,
id, tmpfname)
spawn(req, false)
return id
end
-- Calls the remembered callback function on the output of the shell
-- command.
-- @param id Request ID
-- @param output The output file of the shell command to be delievered
function asyncshell.deliver(id)
if asyncshell.request_table[id] and
asyncshell.request_table[id].callback then
local output = io.open(asyncshell.file_template .. id, 'r')
asyncshell.request_table[id].callback(output)
end
end
-- Sends a synchronous request for an output of the command. Waits for
-- the output, but if the given timeout expires returns nil.
-- @param command Command to be executed and taken output from
-- @param timeout Maximum amount of time to wait for the result
-- @return File handler on success, nil otherwise
function asyncshell.demand(command, timeout)
local id = next_id()
local tmpfname = asyncshell.file_template .. id
local f = io.popen(string.format("(%s > %s; echo asyncshell_done) & " ..
"(sleep %s; echo asynchell_timeout)",
command, tmpfname, timeout))
local result = f:read("*line")
if result == "asyncshell_done" then
return io.open(tmpfname)
end
end
return asyncshell

103
awesome/lain/helpers.lua Normal file
View file

@ -0,0 +1,103 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local debug = require("debug")
local capi = { timer = timer }
local io = { open = io.open,
lines = io.lines }
local rawget = rawget
-- Lain helper functions for internal use
-- lain.helpers
local helpers = {}
helpers.lain_dir = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]]
helpers.icons_dir = helpers.lain_dir .. 'icons/'
helpers.scripts_dir = helpers.lain_dir .. 'scripts/'
-- {{{ Modules loader
function helpers.wrequire(table, key)
local module = rawget(table, key)
return module or require(table._NAME .. '.' .. key)
end
-- }}}
-- {{{ File operations
-- see if the file exists and is readable
function helpers.file_exists(file)
local f = io.open(file)
if f then
local s = f:read()
f:close()
f = s
end
return f ~= nil
end
-- get all lines from a file, returns an empty
-- list/table if the file does not exist
function helpers.lines_from(file)
if not helpers.file_exists(file) then return {} end
lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
-- get first line of a file, return nil if
-- the file does not exist
function helpers.first_line(file)
return helpers.lines_from(file)[1]
end
-- get first non empty line from a file,
-- returns nil otherwise
function helpers.first_nonempty_line(file)
for k,v in pairs(helpers.lines_from(file)) do
if #v then return v end
end
return nil
end
-- }}}
-- {{{ Timer maker
helpers.timer_table = {}
function helpers.newtimer(name, timeout, fun, nostart)
helpers.timer_table[name] = capi.timer({ timeout = timeout })
helpers.timer_table[name]:connect_signal("timeout", fun)
helpers.timer_table[name]:start()
if not nostart then
helpers.timer_table[name]:emit_signal("timeout")
end
end
-- }}}
-- {{{ A map utility
helpers.map_table = {}
function helpers.set_map(element, value)
helpers.map_table[element] = value
end
function helpers.get_map(element)
return helpers.map_table[element]
end
-- }}}
return helpers

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

BIN
awesome/lain/icons/mail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

BIN
awesome/lain/icons/no_net.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

21
awesome/lain/init.lua Normal file
View file

@ -0,0 +1,21 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
package.loaded.lain = nil
local lain =
{
layout = require("lain.layout"),
util = require("lain.util"),
widgets = require("lain.widgets")
}
return lain

View file

@ -0,0 +1,80 @@
--[[
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 cascade =
{
name = "cascade",
nmaster = 0,
offset_x = 32,
offset_y = 8
}
function cascade.arrange(p)
-- 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
-- Themes border width requires an offset.
local bw = tonumber(beautiful.border_width) or 0
-- Screen.
local wa = p.workarea
local cls = p.clients
wa.height = wa.height - ((global_border * 2) + (bw * 2))
wa.width = wa.width - ((global_border * 2) + (bw * 2))
wa.x = wa.x + global_border
wa.y = wa.y + global_border
-- 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 t = tag.selected(p.screen)
local num_c
if cascade.nmaster > 0
then
num_c = cascade.nmaster
else
num_c = tag.getnmaster(t)
end
local how_many = #cls
if how_many < num_c
then
how_many = num_c
end
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
c:geometry(g)
end
end
return cascade

View file

@ -0,0 +1,167 @@
--[[
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
-- Themes border width requires an offset
local bw = tonumber(beautiful.border_width) or 0
-- Screen.
local wa = p.workarea
local cls = p.clients
-- Borders are factored in.
wa.height = wa.height - ((global_border * 2) + (bw * 2))
wa.width = wa.width - ((global_border * 2) + (bw * 2))
-- 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[#cls]
local g = {}
local mainwid = wa.width * mwfact
local slavewid = wa.width - mainwid
if overlap_main == 1
then
g.width = wa.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
end
g.height = wa.height
g.x = wa.x + global_border
g.y = wa.y + global_border
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
c:geometry(g)
-- Remaining clients stacked in slave column, new ones on top.
if #cls > 1
then
for i = (#cls - 1),1,-1
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) * cascadetile.offset_x
g.y = wa.y + (i - 1) * cascadetile.offset_y + global_border
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
c:geometry(g)
end
end
end
end
return cascadetile

View file

@ -0,0 +1,163 @@
--[[
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
-- Themes border width requires an offset
local bw = tonumber(beautiful.border_width) or 0
-- Screen.
local wa = p.workarea
local cls = p.clients
-- Borders are factored in.
wa.height = wa.height - ((global_border * 2) + (bw * 2))
wa.width = wa.width - ((global_border * 2) + (bw * 2))
-- 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)
local offset_y = wa.y + useless_gap
if #cls < num_x
then
-- Less clients than the number of columns, let's center it!
local offset_x = wa.x + useless_gap + (wa.width - #cls*width - (#cls+1)*useless_gap) / 2
local g = {}
g.width = width
g.height = wa.height - 2*useless_gap - 2
g.y = offset_y + global_border
for i = 1, #cls do
g.x = offset_x + (#cls - i) * (width + useless_gap + 2) + global_border
cls[i]:geometry(g)
end
else
-- More clients than the number of columns, let's arrange it!
local offset_x = wa.x
if useless_gap > 0 then
offset_x = offset_x
end
-- Master client deserves a special treatement
local g = {}
g.width = wa.width - (num_x - 1) * width - num_x * 2*useless_gap - 2
g.height = wa.height - 2*useless_gap - 2
g.x = offset_x + useless_gap + global_border
g.y = offset_y + global_border
cls[#cls]: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 = #cls-1 -- we start with the 2nd client
g.x = g.x + g.width+useless_gap + 2
g.width = width
if useless_gap > 0 then
g.width = g.width + useless_gap - 2
end
for i = 1, (num_x-1) do
to_remove = 2
g.height = math.floor((wa.height - (num_y[i] * useless_gap)) / num_y[i])
g.y = offset_y + global_border
for j = 0, (num_y[i]-2) do
cls[nclient]:geometry(g)
nclient = nclient - 1
g.y = g.y + g.height+useless_gap + 2
to_remove = to_remove + 2
end
g.height = wa.height - num_y[i]*useless_gap - (num_y[i]-1)*g.height - useless_gap - to_remove
cls[nclient]:geometry(g)
nclient = nclient - 1
g.x = g.x+g.width+useless_gap + 2
end
end
end
return centerfair

View file

@ -0,0 +1,131 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, projektile
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local awful = require("awful")
local beautiful = require("beautiful")
local tonumber = tonumber
local math = { floor = math.floor }
local centerwork =
{
name = "centerwork",
top_left = 0,
top_right = 1,
bottom_left = 2,
bottom_right = 3
}
function centerwork.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
-- Themes border width requires an offset
local bw = tonumber(beautiful.border_width) or 0
-- Screen.
local wa = p.workarea
local cls = p.clients
-- Borders are factored in.
wa.height = wa.height - ((global_border * 2) + (bw * 2))
wa.width = wa.width - ((global_border * 2) + (bw * 2))
-- 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[#cls]
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 slaveThei = math.floor(wa.height / 2)
local slaveBhei = wa.height - slaveThei
g.height = wa.height - 2 * useless_gap
g.width = mainwid
g.x = wa.x + slaveLwid + global_border
g.y = wa.y + useless_gap + global_border
c:geometry(g)
-- Auxiliary windows.
if #cls > 1
then
local at = 0
for i = (#cls - 1),1,-1
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 at == centerwork.top_left
then
-- top left
g.x = wa.x + useless_gap + global_border
g.y = wa.y + useless_gap + global_border
g.width = slaveLwid - 2 * useless_gap
g.height = slaveThei - useless_gap
elseif at == centerwork.top_right
then
-- top right
g.x = wa.x + slaveLwid + mainwid + useless_gap + global_border
g.y = wa.y + useless_gap + global_border
g.width = slaveRwid - 2 * useless_gap
g.height = slaveThei - useless_gap
elseif at == centerwork.bottom_left
then
-- bottom left
g.x = wa.x + useless_gap + global_border
g.y = wa.y + slaveThei + useless_gap + global_border
g.width = slaveLwid - 2 * useless_gap
g.height = slaveBhei - 2 * useless_gap
elseif at == centerwork.bottom_right
then
-- bottom right
g.x = wa.x + slaveLwid + mainwid + useless_gap + global_border
g.y = wa.y + slaveThei + useless_gap + global_border
g.width = slaveRwid - 2 * useless_gap
g.height = slaveBhei - 2 * useless_gap
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 centerwork

View file

@ -0,0 +1,20 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Layouts section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
local layout = { _NAME = "lain.layout" }
return setmetatable(layout, { __index = wrequire })

View file

@ -0,0 +1,138 @@
--[[
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 math = { ceil = math.ceil,
floor = math.floor,
max = math.max }
local tonumber = tonumber
local termfair = { name = "termfair" }
function termfair.arrange(p)
-- Layout with fixed number of vertical columns (read from nmaster).
-- 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
-- Themes border width requires an offset
local bw = tonumber(beautiful.border_width) or 0
-- Screen.
local wa = p.workarea
local cls = p.clients
-- Borders are factored in.
wa.height = wa.height - ((global_border * 2) + (bw * 2))
wa.width = wa.width - ((global_border * 2) + (bw * 2))
-- How many vertical columns?
local t = tag.selected(p.screen)
local num_x = termfair.nmaster or tag.getnmaster(t)
-- Do at least "desired_y" rows.
local desired_y = termfair.ncol or tag.getncol(t)
if #cls > 0
then
local num_y = math.max(math.ceil(#cls / num_x), desired_y)
local cur_num_x = num_x
local at_x = 0
local at_y = 0
local remaining_clients = #cls
local width = math.floor(wa.width / num_x)
local height = math.floor(wa.height / num_y)
-- We start the first row. Left-align by limiting the number of
-- available slots.
if remaining_clients < num_x
then
cur_num_x = remaining_clients
end
-- Iterate in reversed order.
for i = #cls,1,-1
do
-- Get x and y position.
local c = cls[i]
local this_x = cur_num_x - at_x - 1
local this_y = num_y - at_y - 1
-- Calc geometry.
local g = {}
if this_x == (num_x - 1)
then
g.width = wa.width - (num_x - 1) * width - useless_gap
else
g.width = width - useless_gap
end
if this_y == (num_y - 1)
then
g.height = wa.height - (num_y - 1) * height - useless_gap
else
g.height = height - useless_gap
end
g.x = wa.x + this_x * width + global_border
g.y = wa.y + this_y * height + global_border
if useless_gap > 0
then
-- All clients tile evenly.
g.x = g.x + (useless_gap / 2)
g.y = g.y + (useless_gap / 2)
end
c:geometry(g)
remaining_clients = remaining_clients - 1
-- Next grid position.
at_x = at_x + 1
if at_x == num_x
then
-- Row full, create a new one above it.
at_x = 0
at_y = at_y + 1
-- We start a new row. Left-align.
if remaining_clients < num_x
then
cur_num_x = remaining_clients
end
end
end
end
end
return termfair

View file

@ -0,0 +1,121 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, projektile
* (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 }
local tonumber = tonumber
local uselessfair = {}
local function fair(p, orientation)
-- 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
wa.height = wa.height - ((global_border * 2) + (bw * 2))
wa.width = wa.width - ((global_border * 2) + (bw * 2))
if #cls > 0 then
local cells = math.ceil(math.sqrt(#cls))
local strips = math.ceil(#cls / cells)
local cell = 0
local strip = 0
for k, c in ipairs(cls) do
local g = {}
-- Save actual grid index for use in the useless_gap
-- routine.
local this_x = 0
local this_y = 0
if ( orientation == "east" and #cls > 2 )
or ( orientation == "south" and #cls <= 2 ) then
if #cls < (strips * cells) and strip == strips - 1 then
g.width = wa.width / (cells - ((strips * cells) - #cls))
else
g.width = wa.width / cells
end
g.height = wa.height / strips
this_x = cell
this_y = strip
g.x = wa.x + cell * g.width + global_border
g.y = wa.y + strip * g.height + global_border
else
if #cls < (strips * cells) and strip == strips - 1 then
g.height = wa.height / (cells - ((strips * cells) - #cls))
else
g.height = wa.height / cells
end
g.width = wa.width / strips
this_x = strip
this_y = cell
g.x = wa.x + strip * g.width + global_border
g.y = wa.y + cell * g.height + global_border
end
-- Useless gap.
if useless_gap > 0
then
-- All clients tile evenly.
g.width = g.width - useless_gap
g.x = g.x + (useless_gap / 2)
g.height = g.height - useless_gap
g.y = g.y + (useless_gap / 2)
end
-- End of useless gap.
c:geometry(g)
cell = cell + 1
if cell == cells then
cell = 0
strip = strip + 1
end
end
end
end
--- Horizontal fair layout.
-- @param screen The screen to arrange.
uselessfair.horizontal = {}
uselessfair.horizontal.name = "uselessfairh"
function uselessfair.horizontal.arrange(p)
return fair(p, "east")
end
-- Vertical fair layout.
-- @param screen The screen to arrange.
uselessfair.name = "uselessfair"
function uselessfair.arrange(p)
return fair(p, "south")
end
return uselessfair

View file

@ -0,0 +1,123 @@
--[[
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

View file

@ -0,0 +1,239 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014 projektile
* (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,
max = math.max,
min = math.min }
local tonumber = tonumber
local uselesstile = {}
local function tile_group(cls, wa, orientation, fact, group)
-- 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 height = "height"
local width = "width"
local x = "x"
local y = "y"
if orientation == "top" or orientation == "bottom" then
height = "width"
width = "height"
x = "y"
y = "x"
end
-- make this more generic (not just width)
--if for top
available = wa[width] - (group.coord - wa[x]) -- it's truly not here
-- find our total values
local total_fact = 0
local min_fact = 1
local size = group.size
for c = group.first,group.last do
-- determine the width/height based on the size_hint
local i = c - group.first +1
local size_hints = cls[c].size_hints
local size_hint = size_hints["min_"..width] or size_hints["base_"..width] or 0
size_hint = size_hint + cls[c].border_width*2
size = math.max(size_hint, size)
-- calculate the height
if not fact[i] then
fact[i] = min_fact
else
min_fact = math.min(fact[i],min_fact)
end
total_fact = total_fact + fact[i]
end
size = math.min(size, (available - global_border))
local coord = wa[y]
local geom = {}
local used_size = 0
local unused = wa[height] - (global_border * 2)
local stat_coord = wa[x]
--stat_coord = size
for c = group.first,group.last do
local i = c - group.first +1
geom[width] = size - global_border - (bw * 2)
geom[height] = math.floor(unused * fact[i] / total_fact) - (bw * 2)
geom[x] = group.coord + global_border + (useless_gap / 2)
geom[y] = coord + global_border + (useless_gap / 2)
coord = coord + geom[height]
unused = unused - geom[height]
total_fact = total_fact - fact[i]
used_size = math.max(used_size, geom[width])
-- 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 geom[y] == wa[y] then
top = true
end
if geom[x] == 0 or geom[x] == wa[x] then
left = true
end
if top then
geom[height] = geom[height] - (2 * useless_gap)
geom[y] = geom[y] + useless_gap
else
geom[height] = geom[height] - useless_gap
end
if left then
geom[width] = geom[width] - (2 * useless_gap)
geom[x] = geom[x] + useless_gap
else
geom[width] = geom[width] - useless_gap
end
end
-- End of useless gap.
geom = cls[c]:geometry(geom)
end
return used_size
end
local function tile(param, orientation)
local t = tag.selected(param.screen)
orientation = orientation or "right"
-- this handles are different orientations
local height = "height"
local width = "width"
local x = "x"
local y = "y"
if orientation == "top" or orientation == "bottom" then
height = "width"
width = "height"
x = "y"
y = "x"
end
local cls = param.clients
local nmaster = math.min(tag.getnmaster(t), #cls)
local nother = math.max(#cls - nmaster,0)
local mwfact = tag.getmwfact(t)
local wa = param.workarea
local ncol = tag.getncol(t)
local data = tag.getdata(t).windowfact
if not data then
data = {}
tag.getdata(t).windowfact = data
end
local coord = wa[x]
local place_master = true
if orientation == "left" or orientation == "top" then
-- if we are on the left or top we need to render the other windows first
place_master = false
end
-- this was easier than writing functions because there is a lot of data we need
for d = 1,2 do
if place_master and nmaster > 0 then
local size = wa[width]
if nother > 0 then
size = math.min(wa[width] * mwfact, wa[width] - (coord - wa[x]))
end
if not data[0] then
data[0] = {}
end
coord = coord + tile_group(cls, wa, orientation, data[0], {first=1, last=nmaster, coord = coord, size = size})
end
if not place_master and nother > 0 then
local last = nmaster
-- we have to modify the work area size to consider left and top views
local wasize = wa[width]
if nmaster > 0 and (orientation == "left" or orientation == "top") then
wasize = wa[width] - wa[width]*mwfact
end
for i = 1,ncol do
-- Try to get equal width among remaining columns
local size = math.min((wasize - (coord - wa[x])) / (ncol - i + 1)) --+ (global_border/(ncol))/(ncol+i^2)
local first = last + 1
last = last + math.floor((#cls - last)/(ncol - i + 1))
-- tile the column and update our current x coordinate
if not data[i] then
data[i] = {}
end
coord = coord + tile_group(cls, wa, orientation, data[i], { first = first, last = last, coord = coord, size = size })
end
end
place_master = not place_master
end
end
uselesstile.right = {}
uselesstile.right.name = "uselesstile"
uselesstile.right.arrange = tile
--- The main tile algo, on left.
-- @param screen The screen number to tile.
uselesstile.left = {}
uselesstile.left.name = "uselesstileleft"
function uselesstile.left.arrange(p)
return tile(p, "left")
end
--- The main tile algo, on bottom.
-- @param screen The screen number to tile.
uselesstile.bottom = {}
uselesstile.bottom.name = "uselesstilebottom"
function uselesstile.bottom.arrange(p)
return tile(p, "bottom")
end
--- The main tile algo, on top.
-- @param screen The screen number to tile.
uselesstile.top = {}
uselesstile.top.name = "uselesstiletop"
function uselesstile.top.arrange(p)
return tile(p, "top")
end
uselesstile.arrange = uselesstile.right.arrange
uselesstile.name = uselesstile.right.name
return uselesstile

387
awesome/lain/scripts/dfs Executable file
View file

@ -0,0 +1,387 @@
#!/bin/bash
#
# Adapted from Eridan's "fs" (cleanup, enhancements and switch to bash/Linux)
# JM, 10/12/2004
#
# Integrated into Lain in september 2013
# https://github.com/copycat-killer/lain
# Requires gawk
# -------------------------------------------------------------------------
# Decoding options
# -------------------------------------------------------------------------
USAGE="Usage: $0 [-h(elp)] | [-n(arrow mode)] | [-w(eb output)]"
NARROW_MODE=0
WEB_OUTPUT=0
while [ $# -gt 0 ]; do
case "$1" in
"-h" )
echo $USAGE
exit
;;
"-d" )
DEBUG=1
;;
"-n" )
NARROW_MODE=1
;;
"-w" )
WEB_OUTPUT=1
;;
* )
echo $USAGE
exit
;;
esac
shift
done
# -------------------------------------------------------------------------
# Preparations
# -------------------------------------------------------------------------
SYSTEM=`uname -s`
PATTERN="/"
case "$SYSTEM" in
"Linux" )
DF_COMMAND="/usr/bin/env df -k"
SORT_COMMAND="/usr/bin/env sort -k6"
AWK_COMMAND="/usr/bin/env awk"
;;
* )
DF_COMMAND="/bin/df -k"
SORT_COMMAND="/usr/bin/sort -k6"
AWK_COMMAND="/usr/bin/env gawk"
;;
esac
# -------------------------------------------------------------------------
# Grabbing "df" result
# -------------------------------------------------------------------------
DF_RESULT=`$DF_COMMAND`
if [ ! -z $DEBUG ]; then
echo "--> DF_RESULT:"
echo "$DF_RESULT"
echo ""
fi
# -------------------------------------------------------------------------
# Preprocessing "df" result, to join split logical lines
# -------------------------------------------------------------------------
PREPROCESSING_RESULT=` \
echo "$DF_RESULT" | $AWK_COMMAND -v PATTERN=$PATTERN \
'
NF == 1 {
printf ("%s", $0)
}
NF == 5 {
printf ("%s\n", $0)
}
NF > 6 {
}
NF == 6 {
printf ("%s\n", $0)
}'
`
if [ ! -z $DEBUG ]; then
echo "--> PREPROCESSING_RESULT:"
echo "$PREPROCESSING_RESULT"
echo ""
fi
SORTED_FILE_SYSTEMS_INFO=`echo "$PREPROCESSING_RESULT" | $SORT_COMMAND`
if [ ! -z $DEBUG ]; then
echo "--> SORTED_FILE_SYSTEMS_INFO:"
echo "$SORTED_FILE_SYSTEMS_INFO"
echo ""
fi
# -------------------------------------------------------------------------
# Computing mount point max length
# -------------------------------------------------------------------------
MOUNT_POINT_MAX_LENGTH=` \
echo $SORTED_FILE_SYSTEMS_INFO | $AWK_COMMAND -v PATTERN=$PATTERN \
'
BEGIN {
mount_point_length_max = 15;
}
END {
printf ("%d", mount_point_length_max);
}
$0 ~ PATTERN {
# printf ("$6 = %s\n", $6);
mount_point = $6;
# printf ("mount_point = %s\n", mount_point);
mount_point_length = length (mount_point);
# printf ("mount_point_length = %d\n", mount_point_length);
if (mount_point_length > mount_point_length_max)
mount_point_length_max = mount_point_length;
}'
`
if [ ! -z $DEBUG ]; then
echo "MOUNT_POINT_MAX_LENGTH: $MOUNT_POINT_MAX_LENGTH"
fi
# -------------------------------------------------------------------------
# Computing mount point data max size
# -------------------------------------------------------------------------
MOUNT_POINT_MAX_SIZE=` \
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v PATTERN=$PATTERN \
'
BEGIN {
mount_point_size_max = 0;
}
END {
printf ("%d", mount_point_size_max);
}
$0 ~ PATTERN {
# df -k shows k_bytes!
# printf ("$2 = %s\n", $2);
mount_point_size = $2 * 1024;
# printf ("mount_point_size = %d\n", mount_point_size);
if (mount_point_size > mount_point_size_max)
mount_point_size_max = mount_point_size;
}'
`
if [ ! -z $DEBUG ]; then
echo "MOUNT_POINT_MAX_SIZE: $MOUNT_POINT_MAX_SIZE"
fi
# -------------------------------------------------------------------------
# Let's go!
# -------------------------------------------------------------------------
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v DEBUG=$DEBUG -v PATTERN=$PATTERN -v NARROW_MODE=$NARROW_MODE -v LEFT_COLUMN=$MOUNT_POINT_MAX_LENGTH -v MAX_SIZE=$MOUNT_POINT_MAX_SIZE -v SCALE=$SCALE -v WEB_OUTPUT=$WEB_OUTPUT \
'
# {printf ("$0 = %s\n", $0);}
# {printf ("$1 = %s\n", $1);}
# {printf ("PATTERN = %s\n", PATTERN);}
# {printf ("LEFT_COLUMN = %s\n", LEFT_COLUMN);}
BEGIN {
k_bytes = 1024.0;
m_bytes = 1024.0 * k_bytes;
g_bytes = 1024.0 * m_bytes;
t_bytes = 1024.0 * g_bytes;
if (WEB_OUTPUT)
{
all_stars = "**************************************************";
current_date = strftime ("%d-%m-%Y @ %H:%M:%S", localtime (systime ()));
free_threshold = 10; # %
printf ("<!-- DEBUT CONTENU -->\n");
printf ( \
"<A NAME=\"top\"></A>\n" \
"<P ALIGN=CENTER><SPAN CLASS=\"titleblue\">%s</SPAN><SPAN CLASS=\"textbold\"> -- STATUS OF <SPAN CLASS=\"titlered\">ALCOR</SPAN> FILE SYSTEMS</SPAN></P><BR>\n",
current_date )
printf ("<TABLE WIDTH=\"100%%\" BORDER=1>\n");
printf ( \
"<TR>\n" \
"<TD ALIGN=LEFT><STRONG>Mount point</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>%% Usato&nbsp;(<SPAN CLASS=\"titleblue\">*</SPAN>)" \
"&nbsp;-&nbsp;%% Free&nbsp;(<SPAN CLASS=\"titlegreen\">*</SPAN>)</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>%% Used</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>Free</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>Total</STRONG></TD>\n" \
"</TR>\n" );
}
else
{
narrow_margin = " ";
# printf ("%-*s", LEFT_COLUMN + 2, "Mount point");
if (NARROW_MODE)
printf ("\n%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
print " Used Free Total ";
if (! NARROW_MODE)
print "";
}
}
END {
if (WEB_OUTPUT)
{
printf ("</TABLE>\n");
printf ("<!-- FIN CONTENU -->\n");
}
else
{
if (NARROW_MODE)
printf ("%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
print "|----|----|----|----|----|----|----|----|----|----|"
if (NARROW_MODE)
printf ("\n%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
print "0 10 20 30 40 50 60 70 80 90 100";
print "";
}
}
$0 ~ PATTERN {
if (index ($0, "members") == 0 && index ($0, "Download") == 0 && index ($0, "admin") == 0)
{
# df -k shows k_bytes!
total_size = $2 * k_bytes;
free_size = $4 * k_bytes;
percentage_occupied = substr($5, 0, 3);
mount_point = $6;
percentage_free = int (100 - percentage_occupied);
# reduction_factor: 2
stars_number = int (percentage_occupied / 2);
if (WEB_OUTPUT)
{
posGroup = index (mount_point, "scratch");
if (posGroup == 0)
posGroup = index (mount_point, "u1");
if (posGroup == 0)
posGroup = index (mount_point, "u2");
if (posGroup == 0)
posGroup = index (mount_point, "u4");
if (posGroup == 0)
posGroup = index (mount_point, "u5");
printf ("<TR>\n");
if (posGroup > 0 || percentage_free < free_threshold)
{
if (percentage_free < free_threshold)
{
class = "titlered";
if (posGroup == 0)
posGroup = 1; # to display the whole mount_point in this color anyway
}
else if ((index (mount_point, "scratch") != 0) || (index (mount_point, "u1") != 0) || (index (mount_point, "u2") != 0))
{
class = "titleorange";
posGroup = 1; # to display the whole mount_point in this color
}
else if ((index (mount_point, "u4") != 0) || (index (mount_point, "u5") != 0))
{
class = "titlebrown";
posGroup = 1; # to display the whole mount_point in this color
}
printf ( \
"<TD ALIGN=LEFT>%s<SPAN CLASS=\"%s\">%s</SPAN></TD>\n",
substr (mount_point, 1, posGroup - 1),
class,
substr (mount_point, posGroup) );
}
else
{
printf ("<TD ALIGN=LEFT>%s</TD>\n", mount_point);
}
printf ( \
"<TD ALIGN=CENTER><SPAN CLASS=\"titleblue\">%s</SPAN><SPAN CLASS=\"titlegreen\">%s</SPAN></TD>\n",
substr (all_stars, 1, stars_number), substr (all_stars, stars_number + 1, 49) );
if (percentage_free < free_threshold)
{
color_beginning = "<SPAN CLASS=\"titlered\">";
color_end = "</SPAN>"
}
else
{
color_beginning = "";
color_end = ""
}
if (total_size > 1 * t_bytes)
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Tb</TD><TD ALIGN=RIGHT>%5.1f Tb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / t_bytes, total_size / t_bytes \
);
else if (total_size > 1 * g_bytes)
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Gb</TD><TD ALIGN=RIGHT>%5.1f Gb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / g_bytes, total_size / g_bytes \
);
else if (total_size > 1 * m_byptes)
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Mb</TD><TD ALIGN=RIGHT>%5.1f Mb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / m_bytes, total_size / m_bytes \
);
else
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Kb</TD><TD ALIGN=RIGHT>%5.1f Kb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / k_bytes, total_size / k_bytes \
);
printf ("</TR>\n");
}
else
{
# printf ("percentage_occupied = %d\n", percentage_occupied);
# printf ("percentage_free = %d\n", percentage_free);
printf ("%-*s", LEFT_COLUMN + 2, mount_point);
if (NARROW_MODE)
printf ("\n%s", narrow_margin);
# printf ("stars_number = %d\n", stars_number);
printf ("|");
for (i = 1; i <= stars_number; i++)
{
printf ("%s", "*");
}
for (i = stars_number + 1; i <= 49; i++)
{
printf ("%s", "-");
}
if (total_size > 1 * t_bytes)
printf ( \
"| %3d%% %5.1f %5.1f Tb\n", \
percentage_occupied, free_size / t_bytes, total_size / t_bytes \
);
else if (total_size > 1 * g_bytes)
printf ( \
"| %3d%% %5.1f %5.1f Gb\n", \
percentage_occupied, free_size / g_bytes, total_size / g_bytes \
);
else if (total_size > 1 * m_byptes)
printf ( \
"| %3d%% %5.1f %5.1f Mb\n", \
percentage_occupied, free_size / m_bytes, total_size / m_bytes \
);
else
printf ( \
"| %3d%% %5.1f %5.1f Kb\n", \
percentage_occupied, free_size / k_bytes, total_size / k_bytes \
);
}
} # if
}'

68
awesome/lain/scripts/mpdcover Executable file
View file

@ -0,0 +1,68 @@
#!/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

229
awesome/lain/util/init.lua Normal file
View file

@ -0,0 +1,229 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Utilities section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local awful = require("awful")
local beautiful = require("beautiful")
local math = { sqrt = math.sqrt }
local mouse = mouse
local pairs = pairs
local string = { gsub = string.gsub }
local client = client
local screen = screen
local tonumber = tonumber
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
-- Lain utilities submodule
-- lain.util
local util = { _NAME = "lain.util" }
-- Like awful.menu.clients, but only show clients of currently selected
-- tags.
function util.menu_clients_current_tags(menu, args)
-- List of currently selected tags.
local cls_tags = awful.tag.selectedlist(mouse.screen)
-- Final list of menu items.
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
-- the menu. A click on a menu item will raise that client.
for i = 1,#cls_tags
do
local t = cls_tags[i]
local cls = t:clients()
for k, c in pairs(cls)
do
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
function ()
c.minimized = false
client.focus = c
c:raise()
end,
c.icon }
end
end
-- No clients? Then quit.
if #cls_t <= 0 then return nil end
-- menu may contain some predefined values, otherwise start with a
-- fresh menu.
if not menu then menu = {} end
-- Set the list of items and show the menu.
menu.items = cls_t
local m = awful.menu.new(menu)
m:show(args)
return m
end
-- Magnify a client: Set it to "float" and resize it.
function util.magnify_client(c)
if not awful.client.floating.get(c) then
awful.client.floating.set(c, true)
local mg = screen[mouse.screen].geometry
local tag = awful.tag.selected(mouse.screen)
local mwfact = awful.tag.getmwfact(tag)
local g = {}
g.width = math.sqrt(mwfact) * mg.width
g.height = math.sqrt(mwfact) * mg.height
g.x = mg.x + (mg.width - g.width) / 2
g.y = mg.y + (mg.height - g.height) / 2
c:geometry(g)
else
awful.client.floating.set(c, false)
end
end
-- Read the nice value of pid from /proc.
local function get_nice_value(pid)
local n = first_line('/proc/' .. pid .. '/stat')
if n == nil
then
-- This should not happen. But I don't want to crash, either.
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
-- direction in {-1, 1} <-> {previous, next} non-empty tag
function util.tag_view_nonempty(direction, sc)
local s = sc or mouse.screen or 1
local scr = screen[s]
for i = 1, #awful.tag.gettags(s) do
awful.tag.viewidx(direction,s)
if #awful.client.visible(s) > 0 then
return
end
end
end
-- {{{ Dynamic tagging
--
-- Add a new tag
function util.add_tag(mypromptbox)
awful.prompt.run({prompt="New tag name: "}, mypromptbox[mouse.screen].widget,
function(text)
if text:len() > 0 then
props = { selected = true }
tag = awful.tag.add(new_name, props)
tag.name = text
tag:emit_signal("property::name")
end
end)
end
-- Rename current tag
-- @author: minism
function util.rename_tag(mypromptbox)
local tag = awful.tag.selected(mouse.screen)
awful.prompt.run({prompt="Rename tag: "}, mypromptbox[mouse.screen].widget,
function(text)
if text:len() > 0 then
tag.name = text
tag:emit_signal("property::name")
end
end)
end
-- Move current tag
-- pos in {-1, 1} <-> {previous, next} tag position
function util.move_tag(pos)
local tag = awful.tag.selected(mouse.screen)
local idx = awful.tag.getidx(tag)
if tonumber(pos) <= -1 then
awful.tag.move(idx - 1, tag)
else
awful.tag.move(idx + 1, tag)
end
end
-- Remove current tag (if empty)
-- Any rule set on the tag shall be broken
function util.remove_tag()
local tag = awful.tag.selected(mouse.screen)
local prevtag = awful.tag.gettags(mouse.screen)[awful.tag.getidx(tag) - 1]
awful.tag.delete(tag, prevtag)
end
--
-- }}}
-- On the fly useless gaps change
function util.useless_gaps_resize(thatmuch)
beautiful.useless_gap_width = tonumber(beautiful.useless_gap_width) + thatmuch
awful.layout.arrange(mouse.screen)
end
-- 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
return setmetatable(util, { __index = wrequire })

View file

@ -0,0 +1,69 @@
--[[
Licensed under MIT License
* (c) 2013, Luke Bonham
* (c) 2009, Uli Schlachter
* (c) 2009, Majic
--]]
local beautiful = require("beautiful")
local tostring = tostring
local setmetatable = setmetatable
-- Lain markup util submodule
-- lain.util.markup
local markup = {}
local fg = {}
local bg = {}
-- Convenience tags.
function markup.bold(text) return '<b>' .. tostring(text) .. '</b>' end
function markup.italic(text) return '<i>' .. tostring(text) .. '</i>' end
function markup.strike(text) return '<s>' .. tostring(text) .. '</s>' end
function markup.underline(text) return '<u>' .. tostring(text) .. '</u>' end
function markup.monospace(text) return '<tt>' .. tostring(text) .. '</tt>' end
function markup.big(text) return '<big>' .. tostring(text) .. '</big>' end
function markup.small(text) return '<small>' .. tostring(text) .. '</small>' end
-- Set the font.
function markup.font(font, text)
return '<span font="' .. tostring(font) .. '">' .. tostring(text) ..'</span>'
end
-- Set the foreground.
function fg.color(color, text)
return '<span foreground="' .. tostring(color) .. '">' .. tostring(text) .. '</span>'
end
-- Set the background.
function bg.color(color, text)
return '<span background="' .. tostring(color) .. '">' .. tostring(text) .. '</span>'
end
-- Context: focus
function fg.focus(text) return fg.color(beautiful.fg_focus, text) end
function bg.focus(text) return bg.color(beautiful.bg_focus, text) end
function markup.focus(text) return bg.focus(fg.focus(text)) end
-- Context: normal
function fg.normal(text) return fg.color(beautiful.fg_normal, text) end
function bg.normal(text) return bg.color(beautiful.bg_normal, text) end
function markup.normal(text) return bg.normal(fg.normal(text)) end
-- Context: urgent
function fg.urgent(text) return fg.color(beautiful.fg_urgent, text) end
function bg.urgent(text) return bg.color(beautiful.bg_urgent, text) end
function markup.urgent(text) return bg.urgent(fg.urgent(text)) end
markup.fg = fg
markup.bg = bg
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end })
setmetatable(markup.bg, { __call = function(_, ...) return markup.bg.color(...) end })
-- link markup(...) calls to markup.fg.color(...)
return setmetatable(markup, { __call = function(_, ...) return markup.fg.color(...) end })

View file

@ -0,0 +1,42 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, Luke Bonham
--]]
local newtimer = require("lain.helpers").newtimer
local async = require("lain.asyncshell")
local wibox = require("wibox")
local setmetatable = setmetatable
-- Basic template for custom widgets
-- Asynchronous version
-- lain.widgets.abase
local function worker(args)
local abase = {}
local args = args or {}
local timeout = args.timeout or 5
local cmd = args.cmd or ""
local settings = args.settings or function() end
abase.widget = wibox.widget.textbox('')
function abase.update()
async.request(cmd, function(f)
output = f:read("*a")
f:close()
widget = abase.widget
settings()
end)
end
newtimer(cmd, timeout, abase.update)
return setmetatable(abase, { __index = abase.widget })
end
return setmetatable({}, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,65 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010, Adrian C. <anrxc@sysphere.org>
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local io = { popen = io.popen }
local string = { match = string.match }
local setmetatable = setmetatable
-- ALSA volume
-- lain.widgets.alsa
local alsa = {}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 5
local channel = args.channel or "Master"
local settings = args.settings or function() end
alsa.widget = wibox.widget.textbox('')
function alsa.update()
local f = assert(io.popen('amixer -M get ' .. channel))
local mixer = f:read("*a")
f:close()
volume_now = {}
volume_now.level, volume_now.status = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
if volume_now.level == nil
then
volume_now.level = "0"
volume_now.status = "off"
end
if volume_now.status == ""
then
if volume_now.level == "0"
then
volume_now.status = "off"
else
volume_now.status = "on"
end
end
widget = alsa.widget
settings()
end
newtimer("alsa", timeout, alsa.update)
return setmetatable(alsa, { __index = alsa.widget })
end
return setmetatable(alsa, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,173 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2013, Rman
--]]
local newtimer = require("lain.helpers").newtimer
local awful = require("awful")
local beautiful = require("beautiful")
local naughty = require("naughty")
local io = { popen = io.popen }
local math = { modf = math.modf }
local string = { format = string.format,
match = string.match,
rep = string.rep }
local tonumber = tonumber
local setmetatable = setmetatable
-- ALSA volume bar
-- lain.widgets.alsabar
local alsabar = {
channel = "Master",
step = "5%",
colors = {
background = beautiful.bg_normal,
mute = "#EB8F8F",
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,
_muted = false
}
function alsabar.notify()
alsabar.update()
local preset = {
title = "",
text = "",
timeout = 4,
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._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 args = args or {}
local timeout = args.timeout or 4
local settings = args.settings or function() end
local width = args.width or 63
local height = args.heigth or 1
local ticks = args.ticks or false
local ticks_size = args.ticks_size or 7
local vertical = args.vertical or false
alsabar.channel = args.channel or alsabar.channel
alsabar.step = args.step or alsabar.step
alsabar.colors = args.colors or alsabar.colors
alsabar.notifications = args.notifications or alsabar.notifications
alsabar.bar = awful.widget.progressbar()
alsabar.bar:set_background_color(alsabar.colors.background)
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 f = io.popen("amixer -M get " .. alsabar.channel)
local mixer = f:read("*a")
f:close()
-- Capture mixer control state: [5%] ... ... [on]
local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
if volu == nil then
volu = 0
mute = "off"
end
alsabar._current_level = tonumber(volu)
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
newtimer("alsabar", timeout, alsabar.update)
alsabar.bar:buttons (awful.util.table.join (
awful.button ({}, 1, function()
awful.util.spawn(alsabar.mixer)
end),
awful.button ({}, 3, function()
awful.util.spawn(string.format("amixer set %s toggle", alsabar.channel))
alsabar.update()
end),
awful.button ({}, 4, function()
awful.util.spawn(string.format("amixer set %s %s+", alsabar.channel, alsabar.step))
alsabar.update()
end),
awful.button ({}, 5, function()
awful.util.spawn(string.format("amixer set %s %s-", alsabar.channel, alsabar.step))
alsabar.update()
end)
))
return alsabar
end
return setmetatable(alsabar, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,40 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, Luke Bonham
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local io = { popen = io.popen }
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()
local f = assert(io.popen(cmd))
output = f:read("*a")
f:close()
widget = base.widget
settings()
end
newtimer(cmd, timeout, base.update)
return setmetatable(base, { __index = base.widget })
end
return setmetatable({}, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,149 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local newtimer = require("lain.helpers").newtimer
local first_line = require("lain.helpers").first_line
local naughty = require("naughty")
local wibox = require("wibox")
local math = { floor = math.floor }
local string = { format = string.format }
local tonumber = tonumber
local setmetatable = setmetatable
-- Battery infos
-- lain.widgets.bat
local bat = {}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 30
local battery = args.battery or "BAT0"
local notify = args.notify or "on"
local settings = args.settings or function() end
bat.widget = wibox.widget.textbox('')
bat_notification_low_preset = {
title = "Battery low",
text = "Plug the cable!",
timeout = 15,
fg = "#202020",
bg = "#CDCDCD"
}
bat_notification_critical_preset = {
title = "Battery exhausted",
text = "Shutdown imminent",
timeout = 15,
fg = "#000000",
bg = "#FFFFFF"
}
function update()
bat_now = {
status = "Not present",
perc = "N/A",
time = "N/A",
watt = "N/A"
}
local bstr = "/sys/class/power_supply/" .. battery
local present = first_line(bstr .. "/present")
if present == "1"
then
local rate = first_line(bstr .. "/power_now") or
first_line(bstr .. "/current_now")
local ratev = first_line(bstr .. "/voltage_now")
local rem = first_line(bstr .. "/energy_now") or
first_line(bstr .. "/charge_now")
local tot = first_line(bstr .. "/energy_full") or
first_line(bstr .. "/charge_full")
bat_now.status = first_line(bstr .. "/status") or "N/A"
rate = tonumber(rate) or 1
ratev = tonumber(ratev)
rem = tonumber(rem)
tot = tonumber(tot)
local time_rat = 0
if bat_now.status == "Charging"
then
time_rat = (tot - rem) / rate
elseif bat_now.status == "Discharging"
then
time_rat = rem / rate
end
local hrs = math.floor(time_rat)
if hrs < 0 then hrs = 0 elseif hrs > 23 then hrs = 23 end
local min = math.floor((time_rat - hrs) * 60)
if min < 0 then min = 0 elseif min > 59 then min = 59 end
bat_now.time = string.format("%02d:%02d", hrs, min)
bat_now.perc = first_line(bstr .. "/capacity")
if not bat_now.perc then
local perc = (rem / tot) * 100
if perc <= 100 then
bat_now.perc = string.format("%d", perc)
elseif perc > 100 then
bat_now.perc = "100"
elseif perc < 0 then
bat_now.perc = "0"
end
end
if rate ~= nil and ratev ~= nil then
bat_now.watt = string.format("%.2fW", (rate * ratev) / 1e12)
else
bat_now.watt = "N/A"
end
end
widget = bat.widget
settings()
-- notifications for low and critical states
if bat_now.status == "Discharging" and notify == "on" and bat_now.perc ~= nil
then
local nperc = tonumber(bat_now.perc) or 100
if nperc <= 5
then
bat.id = naughty.notify({
preset = bat_notification_critical_preset,
replaces_id = bat.id,
}).id
elseif nperc <= 15
then
bat.id = naughty.notify({
preset = bat_notification_low_preset,
replaces_id = bat.id,
}).id
end
end
end
newtimer("bat", timeout, update)
return bat.widget
end
return setmetatable(bat, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,62 @@
--[[
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 })

View file

@ -0,0 +1,133 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local icons_dir = require("lain.helpers").icons_dir
local awful = require("awful")
local beautiful = require("beautiful")
local naughty = require("naughty")
local io = { popen = io.popen }
local os = { date = os.date }
local tonumber = tonumber
local setmetatable = setmetatable
-- Calendar notification
-- lain.widgets.calendar
local calendar = {}
local cal_notification = nil
function calendar:hide()
if cal_notification ~= nil then
naughty.destroy(cal_notification)
cal_notification = nil
end
end
function calendar:show(t_out, inc_offset, scr)
calendar:hide()
local offs = inc_offset or 0
local tims = t_out or 0
local f, c_text
local today = tonumber(os.date('%d'))
local init_t = calendar.cal .. ' | sed -r -e "s/(^| )( '
calendar.offset = calendar.offset + offs
if offs == 0 or calendar.offset == 0
then -- current month showing, today highlighted
if today >= 10
then
init_t = calendar.cal .. ' | sed -r -e "s/_\\x08//g" | sed -r -e "s/(^| )('
end
calendar.offset = 0
calendar.notify_icon = calendar.icons .. today .. ".png"
-- bg and fg inverted to highlight today
f = io.popen( init_t .. today ..
')($| )/\\1<b><span foreground=\\"'
.. calendar.bg ..
'\\" background=\\"'
.. calendar.fg ..
'\\">\\2<\\/span><\\/b>\\3/"' )
else -- no current month showing, no day to highlight
local month = tonumber(os.date('%m'))
local year = tonumber(os.date('%Y'))
month = month + calendar.offset
if month > 12 then
month = month % 12
year = year + 1
if month <= 0 then
month = 12
end
elseif month < 1 then
month = month + 12
year = year - 1
if month <= 0 then
month = 1
end
end
calendar.notify_icon = nil
f = io.popen(calendar.cal .. ' ' .. month .. ' ' .. year)
end
c_text = "<tt><span font='" .. calendar.font .. " "
.. calendar.font_size .. "'><b>"
.. f:read() .. "</b>\n\n"
.. f:read() .. "\n"
.. f:read("*a"):gsub("\n*$", "")
.. "</span></tt>"
f:close()
cal_notification = naughty.notify({
text = c_text,
icon = calendar.notify_icon,
position = calendar.position,
fg = calendar.fg,
bg = calendar.bg,
timeout = tims,
screen = scr or 1
})
end
function calendar:attach(widget, args)
local args = args or {}
calendar.cal = args.cal or "/usr/bin/cal"
calendar.icons = args.icons or icons_dir .. "cal/white/"
calendar.font = args.font or beautiful.font:sub(beautiful.font:find(""),
beautiful.font:find(" "))
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 "#FFFFFF"
calendar.position = args.position or "top_right"
calendar.scr_pos = args.scr_pos or 1
calendar.offset = 0
calendar.notify_icon = nil
widget:connect_signal("mouse::enter", function () calendar:show(0, 0, scr_pos) end)
widget:connect_signal("mouse::leave", function () calendar:hide() end)
widget:buttons(awful.util.table.join( awful.button({ }, 1, function ()
calendar:show(0, -1, scr_pos) end),
awful.button({ }, 3, function ()
calendar:show(0, 1, scr_pos) end),
awful.button({ }, 4, function ()
calendar:show(0, -1, scr_pos) end),
awful.button({ }, 5, function ()
calendar:show(0, 1, scr_pos) end)))
end
return setmetatable(calendar, { __call = function(_, ...) return create(...) end })

View file

@ -0,0 +1,82 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, Aaron Lebo
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local json = require("dkjson")
local string = { format = string.format }
local tonumber = tonumber
-- Crypto currencies widget
-- lain.widgets.contrib.ccurr
local ccurr = {}
-- Currently gets
-- * BTC/USD
-- * DOGE/USD
-- using Coinbase and Cryptsy APIs.
-- requires http://dkolf.de/src/dkjson-lua.fsl/home
-- based upon http://awesome.naquadah.org/wiki/Bitcoin_Price_Widget
local function get(url)
local f = io.popen('curl -m 5 -s "' .. url .. '"')
if not f then
return 0
else
local s = f:read("*all")
f:close()
return s
end
end
local function parse(j)
local obj, pos, err = json.decode(j, 1, nil)
if err then
return nil
else
return obj
end
end
local function worker(args)
local args = args or {}
local timeout = args.timeout or 600
local btc_url = args.btc_url or "https://coinbase.com/api/v1/prices/buy"
local doge_url = args.doge_url or "http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=132"
local settings = args.settings or function() end
ccurr.widget = wibox.widget.textbox('')
local function update()
price_now = {
btc = "N/A",
doge = "N/A"
}
btc = parse(get(btc_url))
doge = parse(get(doge_url))
if btc and doge then
price_now.btc = tonumber(btc["subtotal"]["amount"])
price_now.doge = tonumber(doge["return"]["markets"]["DOGE"]["lasttradeprice"])
price_now.doge = string.format("%.4f", price_now.btc * price_now.doge)
end
widget = ccurr.widget
settings()
end
newtimer("ccurr", timeout, update)
return ccurr.widget
end
return setmetatable(ccurr, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,19 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Users contributed widgets section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
local widgets = { _NAME = "lain.widgets.contrib" }
return setmetatable(widgets, { __index = wrequire })

View file

@ -0,0 +1,79 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, blueluke <http://github.com/blueluke>
--]]
local os = os
local awful = require("awful")
local spawn = awful.util.spawn_with_shell
local setmetatable = setmetatable
-- redshift
-- lain.widgets.contrib.redshift
local redshift = {}
local attached = false -- true if attached to a widget
local active = false -- true if redshift is active
local running = false -- true if redshift was initialized
local update_fnct = function() end -- function that is run each time redshift is toggled. See redshift:attach().
local function init()
-- As there is no way to determine if redshift was previously
-- toggled off (i.e Awesome on-the-fly restart), kill redshift to make sure
os.execute("pkill redshift")
-- Remove existing color adjustment
spawn("redshift -x")
-- (Re)start redshift
spawn("redshift")
running = true
active = true
end
function redshift:toggle()
if running then
-- Sending -USR1 toggles redshift (See project website)
os.execute("pkill -USR1 redshift")
active = not active
else
init()
end
update_fnct()
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
-- Attach to a widget
-- Provides a button which toggles redshift on/off on click
-- @ param widget: widget to attach to
-- @ param fnct: function to be run each time redshift is toggled (optional).
-- Use it to update widget text or icons on status change.
function redshift:attach(widget, fnct)
update_fnct = fnct or function() end
if not attached then
init()
attached = true
update_fnct()
end
widget:buttons(awful.util.table.join( awful.button({}, 1, function () redshift:toggle() end) ))
end
return setmetatable(redshift, { _call = function(_, ...) return create(...) end })

View file

@ -0,0 +1,133 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Jan Xie
--]]
local icons_dir = require("lain.helpers").icons_dir
local awful = require("awful")
local beautiful = require("beautiful")
local naughty = require("naughty")
local io = io
local string = { len = string.len }
local tonumber = tonumber
local setmetatable = setmetatable
-- Taskwarrior notification
-- lain.widgets.contrib.task
local task = {}
local task_notification = nil
function task:hide()
if task_notification ~= nil then
naughty.destroy(task_notification)
task_notification = nil
end
end
function task:show()
task:hide()
local f, c_text
f = io.popen('task')
c_text = "<span font='"
.. task.font .. " "
.. task.font_size .. "'>"
.. f:read("*all"):gsub("\n*$", "")
.. "</span>"
f:close()
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,
})
end
function task:prompt_add()
awful.prompt.run({ prompt = "Add task: " },
mypromptbox[mouse.screen].widget,
function (...)
local f = io.popen("task add " .. ...)
c_text = "\n<span font='"
.. task.font .. " "
.. task.font_size .. "'>"
.. f:read("*all")
.. "</span>"
f:close()
naughty.notify({
text = c_text,
icon = task.notify_icon,
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 .. "'>"
.. 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,
})
end,
nil,
awful.util.getdir("cache") .. "/history_task")
end
function task:attach(widget, args)
local args = args or {}
task.font_size = tonumber(args.font_size) or 12
task.font = beautiful.font:sub(beautiful.font:find(""),
beautiful.font:find(" "))
task.fg = args.fg or beautiful.fg_normal or "#FFFFFF"
task.bg = args.bg or beautiful.bg_normal or "#FFFFFF"
task.position = args.position or "top_right"
task.timeout = args.timeout or 7
task.notify_icon = icons_dir .. "/taskwarrior/task.png"
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)
end
return setmetatable(task, { __call = function(_, ...) return create(...) end })

View file

@ -0,0 +1,170 @@
--[[
tpbat.lua
Battery status widget for ThinkPad laptops that use SMAPI
lain.widgets.contrib.tpbat
More on tp_smapi: http://www.thinkwiki.org/wiki/Tp_smapi
Licensed under GNU General Public License v2
* (c) 2013, Conor Heine
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local debug = { getinfo = debug.getinfo }
local newtimer = require("lain.helpers").newtimer
local first_line = require("lain.helpers").first_line
local beautiful = require("beautiful")
local naughty = require("naughty")
local wibox = require("wibox")
local string = { format = string.format }
local math = { floor = math.floor }
local tostring = tostring
local setmetatable = setmetatable
package.path = debug.getinfo(1,"S").source:match[[^@?(.*[\/])[^\/]-$]] .. "?.lua;" .. package.path
local smapi = require("smapi")
-- ThinkPad SMAPI-enabled battery info widget
-- lain.widgets.contrib.tpbat
local tpbat = { }
local tpbat_notification = nil
function tpbat:hide()
if tpbat_notification ~= nil
then
naughty.destroy(tpbat_notification)
tpbat_notification = nil
end
end
function tpbat:show(t_out)
tpbat:hide()
local bat = self.bat
local t_out = t_out or 0
if bat == nil or not bat:installed() then return end
local mfgr = bat:get('manufacturer') or "no_mfgr"
local model = bat:get('model') or "no_model"
local chem = bat:get('chemistry') or "no_chem"
local status = bat:get('state') or "nil"
local time = bat:remaining_time()
local msg = "\t"
if status ~= "idle" and status ~= "nil"
then
if time == "N/A"
then
msg = "...Calculating time remaining..."
else
msg = time .. (status == "charging" and " until charged" or " remaining")
end
else
msg = "On AC Power"
end
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)
tpbat_notification = naughty.notify({
preset = { fg = beautiful.fg_normal },
text = str,
timeout = t_out,
screen = client.focus and client.focus.screen or 1
})
end
function tpbat.register(args)
local args = args or {}
local timeout = args.timeout or 30
local battery = args.battery or "BAT0"
local settings = args.settings or function() end
tpbat.bat = smapi:battery(battery) -- Create a new battery
local bat = tpbat.bat
tpbat.widget = wibox.widget.textbox('')
bat_notification_low_preset = {
title = "Battery low",
text = "Plug the cable!",
timeout = 15,
fg = "#202020",
bg = "#CDCDCD"
}
bat_notification_critical_preset = {
title = "Battery exhausted",
text = "Shutdown imminent",
timeout = 15,
fg = "#000000",
bg = "#FFFFFF"
}
if bat:get('state') == nil
then
local n = naughty.notify({
preset = bat_notification_low_preset,
title = "SMAPI Battery Warning: Unable to read battery state!",
text = "This widget is intended for ThinkPads. Is tp_smapi installed? Check your configs & paths.",
screen = client.focus and client.focus.screen or 1
})
end
function update()
bat_now = {
status = "Not present",
perc = "N/A",
time = "N/A",
watt = "N/A"
}
if bat:installed()
then
bat_now.status = bat:status() or "N/A"
bat_now.perc = bat:percent()
bat_now.time = bat:remaining_time()
-- bat_now.watt = string.format("%.2fW", (VOLTS * AMPS) / 1e12)
-- notifications for low and critical states (when discharging)
if bat_now.status == "discharging"
then
if bat_now.perc <= 5
then
tpbat.id = naughty.notify({
preset = bat_notification_critical_preset,
replaces_id = tpbat.id,
screen = client.focus and client.focus.screen or 1
}).id
elseif bat_now.perc <= 15
then
tpbat.id = naughty.notify({
preset = bat_notification_low_preset,
replaces_id = tpbat.id,
screen = client.focus and client.focus.screen or 1
}).id
end
end
bat_now.perc = tostring(bat_now.perc)
end
widget = tpbat.widget
settings()
end
newtimer("tpbat", timeout, update)
widget:connect_signal('mouse::enter', function () tpbat:show() end)
widget:connect_signal('mouse::leave', function () tpbat:hide() end)
return tpbat.widget
end
return setmetatable(tpbat, { __call = function(_, ...) return tpbat.register(...) end })

View file

@ -0,0 +1,102 @@
--[[
smapi.lua
Interface with thinkpad battery information
Licensed under GNU General Public License v2
* (c) 2013, Conor Heine
--]]
local first_line = require("lain.helpers").first_line
local string = { format = string.format }
local tonumber = tonumber
local setmetatable = setmetatable
local smapi = {}
local apipath = "/sys/devices/platform/smapi"
-- Most are readable values, but some can be written to (not implemented, yet?)
local readable = {
barcoding = true,
charging_max_current = true,
charging_max_voltage = true,
chemistry = true,
current_avg = true,
current_now = true,
cycle_count = true,
design_capacity = true,
design_voltage = true,
dump = true,
first_use_date = true,
force_discharge = false,
group0_voltage = true,
group1_voltage = true,
group2_voltage = true,
group3_voltage = true,
inhibit_charge_minutes = false,
installed = true,
last_full_capacity = true,
manufacture_date = true,
manufacturer = true,
model = true,
power_avg = true,
power_now = true,
remaining_capacity = true,
remaining_charging_time = true,
remaining_percent = true,
remaining_percent_error = true,
remaining_running_time = true,
remaining_running_time_now = true,
serial = true,
start_charge_thresh = false,
state = true,
stop_charge_thresh = false,
temperature = true,
voltage = true,
}
function smapi:battery(name)
local bat = {}
bat.name = name
bat.path = apipath .. "/" .. name
function bat:get(item)
return self.path ~= nil and readable[item] and first_line(self.path .. "/" .. item) or nil
end
function bat:installed()
return self:get("installed") == "1"
end
function bat:status()
return self:get('state')
end
-- Remaining time can either be time until battery dies or time until charging completes
function bat:remaining_time()
local time_val = bat_now.status == 'discharging' and 'remaining_running_time' or 'remaining_charging_time'
local mins_left = self:get(time_val)
if mins_left:find("^%d+") == nil
then
return "N/A"
end
local hrs = mins_left / 60
local min = mins_left % 60
return string.format("%02d:%02d", hrs, min)
end
function bat:percent()
return tonumber(self:get("remaining_percent"))
end
return setmetatable(bat, {__metatable = false, __newindex = false})
end
return smapi

View file

@ -0,0 +1,77 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local first_line = require("lain.helpers").first_line
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local math = { ceil = math.ceil }
local string = { format = string.format,
gmatch = string.gmatch }
local tostring = tostring
local setmetatable = setmetatable
-- CPU usage
-- lain.widgets.cpu
local cpu = {
last_total = 0,
last_active = 0
}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 5
local settings = args.settings or function() end
cpu.widget = wibox.widget.textbox('')
function update()
-- Read the amount of time the CPUs have spent performing
-- different kinds of work. Read the first line of /proc/stat
-- which is the sum of all CPUs.
local times = first_line("/proc/stat")
local at = 1
local idle = 0
local total = 0
for field in string.gmatch(times, "[%s]+([^%s]+)")
do
-- 4 = idle, 5 = ioWait. Essentially, the CPUs have done
-- nothing during these times.
if at == 4 or at == 5
then
idle = idle + field
end
total = total + field
at = at + 1
end
local active = total - idle
-- Read current data and calculate relative values.
local dactive = active - cpu.last_active
local dtotal = total - cpu.last_total
cpu_now = {}
cpu_now.usage = tostring(math.ceil((dactive / dtotal) * 100))
widget = cpu.widget
settings()
-- Save current data for the next run.
cpu.last_active = active
cpu.last_total = total
end
newtimer("cpu", timeout, update)
return cpu.widget
end
return setmetatable(cpu, { __call = function(_, ...) return worker(...) end })

117
awesome/lain/widgets/fs.lua Normal file
View file

@ -0,0 +1,117 @@
--[[
Licensed under GNU General Public License v2
* (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 beautiful = require("beautiful")
local wibox = require("wibox")
local naughty = require("naughty")
local io = { popen = io.popen }
local pairs = pairs
local string = { match = string.match,
format = string.format }
local tonumber = tonumber
local setmetatable = setmetatable
-- File system disk space usage
-- lain.widgets.fs
local fs = {}
local notification = nil
fs_notification_preset = { fg = beautiful.fg_normal }
function fs:hide()
if notification ~= nil then
naughty.destroy(notification)
notification = nil
end
end
function fs:show(t_out)
fs:hide()
local f = io.popen(helpers.scripts_dir .. "dfs")
ws = f:read("*a"):gsub("\n*$", "")
f:close()
notification = naughty.notify({
preset = fs_notification_preset,
text = ws,
timeout = t_out,
})
end
-- Unit definitions
local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
local function worker(args)
local args = args or {}
local timeout = args.timeout or 600
local partition = args.partition or "/"
local settings = args.settings or function() end
fs.widget = wibox.widget.textbox('')
helpers.set_map("fs", false)
function update()
fs_info = {}
fs_now = {}
local f = io.popen("LC_ALL=C df -kP " .. partition)
for line in f:lines() do -- Match: (size) (used)(avail)(use%) (mount)
local s = string.match(line, "^.-[%s]([%d]+)")
local u,a,p = string.match(line, "([%d]+)[%D]+([%d]+)[%D]+([%d]+)%%")
local m = string.match(line, "%%[%s]([%p%w]+)")
if u and m then -- Handle 1st line and broken regexp
fs_info[m .. " size_mb"] = string.format("%.1f", tonumber(s) / unit["mb"])
fs_info[m .. " size_gb"] = string.format("%.1f", tonumber(s) / unit["gb"])
fs_info[m .. " used_p"] = tonumber(p)
fs_info[m .. " avail_p"] = 100 - tonumber(p)
end
end
f:close()
fs_now.used = tonumber(fs_info[partition .. " used_p"]) or 0
fs_now.available = tonumber(fs_info[partition .. " avail_p"]) or 0
fs_now.size_mb = tonumber(fs_info[partition .. " size_mb"]) or 0
fs_now.size_gb = tonumber(fs_info[partition .. " size_gb"]) or 0
widget = fs.widget
settings()
if fs_now.used >= 99 and not helpers.get_map("fs")
then
naughty.notify({
title = "warning",
text = partition .. " ran out!\nmake some room",
timeout = 8,
fg = "#000000",
bg = "#FFFFFF",
})
helpers.set_map("fs", true)
else
helpers.set_map("fs", false)
end
end
helpers.newtimer(partition, timeout, update)
widget:connect_signal('mouse::enter', function () fs:show(0) end)
widget:connect_signal('mouse::leave', function () fs:hide() end)
return setmetatable(fs, { __index = fs.widget })
end
return setmetatable(fs, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,93 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local helpers = require("lain.helpers")
local async = require("lain.asyncshell")
local naughty = require("naughty")
local wibox = require("wibox")
local string = { format = string.format,
gsub = string.gsub }
local tonumber = tonumber
local setmetatable = setmetatable
-- Mail IMAP check
-- lain.widgets.imap
local function worker(args)
local imap = {}
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 settings = args.settings or function() end
local head_command = "curl --connect-timeout 3 -fsm 3"
local request = "-X 'SEARCH (UNSEEN)'"
helpers.set_map(mail, 0)
if not is_plain
then
local f = io.popen(password)
password = f:read("*a"):gsub("\n", "")
f:close()
end
imap.widget = wibox.widget.textbox('')
function update()
mail_notification_preset = {
icon = helpers.icons_dir .. "mail.png",
position = "top_left"
}
curl = string.format("%s --url imaps://%s:%s/INBOX -u %s:%q %s -k",
head_command, server, port, mail, password, request)
async.request(curl, function(f)
ws = f:read("*a")
f:close()
_, mailcount = string.gsub(ws, "%d+", "")
_ = nil
widget = imap.widget
settings()
if mailcount >= 1 and mailcount > helpers.get_map(mail)
then
if mailcount == 1 then
nt = mail .. " has one new message"
else
nt = mail .. " has <b>" .. mailcount .. "</b> new messages"
end
naughty.notify({
preset = mail_notification_preset,
text = nt,
})
end
helpers.set_map(mail, mailcount)
end)
end
helpers.newtimer(mail, timeout, update, true)
return setmetatable(imap, { __index = imap.widget })
end
return setmetatable({}, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,20 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Widgets section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
local widgets = { _NAME = "lain.widgets" }
return setmetatable(widgets, { __index = wrequire })

View file

@ -0,0 +1,98 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
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 table = { sort = table.sort }
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
maildir.widget = wibox.widget.textbox('')
function update()
-- Find pathes to mailboxes.
local p = io.popen("find " .. mailpath ..
" -mindepth 1 -maxdepth 1 -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 np = io.popen("find " .. line ..
"/new -mindepth 1 -type f " ..
"-not -name '.*' -printf a")
local mailstring = np:read("*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
table.sort(boxes)
newmail = "no mail"
--Count the total number of mails irrespective of where it was found
total = 0
for box, number in pairs(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 })

View file

@ -0,0 +1,61 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local io = { lines = io.lines }
local math = { floor = math.floor }
local string = { format = string.format,
gmatch = string.gmatch,
len = string.len }
local setmetatable = setmetatable
-- Memory usage (ignoring caches)
-- lain.widgets.mem
local mem = {}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 3
local settings = args.settings or function() end
mem.widget = wibox.widget.textbox('')
function update()
mem_now = {}
for line in io.lines("/proc/meminfo")
do
for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+")
do
if k == "MemTotal" then mem_now.total = math.floor(v / 1024)
elseif k == "MemFree" then mem_now.free = math.floor(v / 1024)
elseif k == "Buffers" then mem_now.buf = math.floor(v / 1024)
elseif k == "Cached" then mem_now.cache = math.floor(v / 1024)
elseif k == "SwapTotal" then mem_now.swap = math.floor(v / 1024)
elseif k == "SwapFree" then mem_now.swapf = math.floor(v / 1024)
end
end
end
mem_now.used = mem_now.total - (mem_now.free + mem_now.buf + mem_now.cache)
mem_now.swapused = mem_now.swap - mem_now.swapf
widget = mem.widget
settings()
end
newtimer("mem", timeout, update)
return mem.widget
end
return setmetatable(mem, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,108 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010, Adrian C. <anrxc@sysphere.org>
--]]
local helpers = require("lain.helpers")
local async = require("lain.asyncshell")
local escape_f = require("awful.util").escape
local naughty = require("naughty")
local wibox = require("wibox")
local io = { popen = io.popen }
local os = { execute = os.execute,
getenv = os.getenv }
local string = { format = string.format,
gmatch = string.gmatch }
local setmetatable = setmetatable
-- MPD infos
-- lain.widgets.mpd
local mpd = {}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 2
local password = args.password or ""
local host = args.host or "127.0.0.1"
local port = args.port or "6600"
local music_dir = args.music_dir or os.getenv("HOME") .. "/Music"
local cover_size = args.cover_size or 100
local default_art = args.default_art or ""
local settings = args.settings or function() end
local mpdcover = helpers.scripts_dir .. "mpdcover"
local mpdh = "telnet://" .. host .. ":" .. port
local echo = "echo 'password " .. password .. "\nstatus\ncurrentsong\nclose'"
mpd.widget = wibox.widget.textbox('')
mpd_notification_preset = {
title = "Now playing",
timeout = 6
}
helpers.set_map("current mpd track", nil)
function mpd.update()
async.request(echo .. " | curl --connect-timeout 1 -fsm 3 " .. mpdh, function (f)
mpd_now = {
state = "N/A",
file = "N/A",
artist = "N/A",
title = "N/A",
album = "N/A",
date = "N/A"
}
for line in f:lines() do
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
if k == "state" then mpd_now.state = v
elseif k == "file" then mpd_now.file = v
elseif k == "Artist" then mpd_now.artist = escape_f(v)
elseif k == "Title" then mpd_now.title = escape_f(v)
elseif k == "Album" then mpd_now.album = escape_f(v)
elseif k == "Date" then mpd_now.date = escape_f(v)
end
end
end
mpd_notification_preset.text = string.format("%s (%s) - %s\n%s", mpd_now.artist,
mpd_now.album, mpd_now.date, mpd_now.title)
widget = mpd.widget
settings()
if mpd_now.state == "play"
then
if mpd_now.title ~= helpers.get_map("current mpd track")
then
helpers.set_map("current mpd track", mpd_now.title)
os.execute(string.format("%s %q %q %d %q", mpdcover, music_dir,
mpd_now.file, cover_size, default_art))
mpd.id = naughty.notify({
preset = mpd_notification_preset,
icon = "/tmp/mpdcover.png",
replaces_id = mpd.id,
}).id
end
elseif mpd_now.state ~= "pause"
then
helpers.set_map("current mpd track", nil)
end
end)
end
helpers.newtimer("mpd", timeout, mpd.update)
return setmetatable(mpd, { __index = mpd.widget })
end
return setmetatable(mpd, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,110 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local helpers = require("lain.helpers")
local notify_fg = require("beautiful").fg_focus
local naughty = require("naughty")
local wibox = require("wibox")
local io = { popen = io.popen }
local tostring = tostring
local string = { format = string.format,
gsub = string.gsub,
match = string.match }
local setmetatable = setmetatable
-- Network infos
-- lain.widgets.net
local net = {
last_t = 0,
last_r = 0
}
function net.get_device()
f = io.popen("ip link show | cut -d' ' -f2,9")
ws = f:read("*a")
f:close()
ws = ws:match("%w+: UP") or ws:match("ppp%w+: UNKNOWN")
if ws ~= nil then
return ws:match("(%w+):")
else
return "network off"
end
end
local function worker(args)
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
iface = args.iface or net.get_device()
net.widget = wibox.widget.textbox('')
helpers.set_map(iface, true)
function update()
net_now = {}
if iface == "" or string.match(iface, "network off")
then
iface = net.get_device()
end
net_now.carrier = helpers.first_line('/sys/class/net/' .. iface ..
'/carrier') or "0"
net_now.state = helpers.first_line('/sys/class/net/' .. iface ..
'/operstate') or "down"
local now_t = helpers.first_line('/sys/class/net/' .. iface ..
'/statistics/tx_bytes') or 0
local now_r = helpers.first_line('/sys/class/net/' .. iface ..
'/statistics/rx_bytes') or 0
net_now.sent = tostring((now_t - net.last_t) / timeout / units)
net_now.sent = string.gsub(string.format('%.1f', net_now.sent), ",", ".")
net_now.received = tostring((now_r - net.last_r) / timeout / units)
net_now.received = string.gsub(string.format('%.1f', net_now.received), ",", ".")
widget = net.widget
settings()
net.last_t = now_t
net.last_r = now_r
if net_now.carrier ~= "1" and notify == "on"
then
if helpers.get_map(iface)
then
naughty.notify({
title = iface,
text = "no carrier",
timeout = 7,
position = "top_left",
icon = helpers.icons_dir .. "no_net.png",
fg = notify_fg or "#FFFFFF",
screen = screen
})
helpers.set_map(iface, false)
end
else
helpers.set_map(iface, true)
end
end
helpers.newtimer(iface, timeout, update)
return net.widget
end
return setmetatable(net, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,46 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local io = { open = io.open }
local string = { format = string.format,
match = string.match }
local setmetatable = setmetatable
-- System load
-- lain.widgets.sysload
local sysload = {}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 5
local settings = args.settings or function() end
sysload.widget = wibox.widget.textbox('')
function update()
local f = io.open("/proc/loadavg")
local ret = f:read("*a")
f:close()
load_1, load_5, load_15 = string.match(ret, "([^%s]+) ([^%s]+) ([^%s]+)")
widget = sysload.widget
settings()
end
newtimer("sysload", timeout, update)
return sysload.widget
end
return setmetatable(sysload, { __call = function(_, ...) return worker(...) end })

View file

@ -0,0 +1,48 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local newtimer = require("lain.helpers").newtimer
local wibox = require("wibox")
local io = { open = io.open }
local tonumber = tonumber
local setmetatable = setmetatable
-- coretemp
-- lain.widgets.temp
local temp = {}
local function worker(args)
local args = args or {}
local timeout = args.timeout or 5
local tempfile = args.tempfile or "/sys/class/thermal/thermal_zone0/temp"
local settings = args.settings or function() end
temp.widget = wibox.widget.textbox('')
function update()
local f = io.open(tempfile)
if f ~= nil
then
coretemp_now = tonumber(f:read("*a")) / 1000
f:close()
else
coretemp_now = "N/A"
end
widget = temp.widget
settings()
end
newtimer("coretemp", timeout, update)
return temp.widget
end
return setmetatable(temp, { __call = function(_, ...) return worker(...) end })

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

View file

@ -0,0 +1 @@
DayClear.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Some files were not shown because too many files have changed in this diff Show more