inital commit of clone of old repo
This commit is contained in:
@ -0,0 +1,36 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local client = client
|
||||
local screen = screen
|
||||
local aclient = require("awful.client")
|
||||
local atag = require("awful.tag")
|
||||
|
||||
--- When loaded, this module makes sure that there's always a client that will have focus
|
||||
-- on event such as tag switching, client unmanaging, etc.
|
||||
module("awful.autofocus")
|
||||
|
||||
-- Give focus on tag selection change.
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus(obj)
|
||||
if not client.focus or not client.focus:isvisible() then
|
||||
local c = aclient.focus.history.get(obj.screen, 0)
|
||||
if c then client.focus = c end
|
||||
elseif client.focus and client.focus.screen ~= obj.screen then
|
||||
local c = aclient.focus.history.get(obj.screen, 0)
|
||||
if c then client.focus = c end
|
||||
end
|
||||
end
|
||||
|
||||
atag.attached_add_signal(nil, "property::selected", check_focus)
|
||||
client.add_signal("unmanage", check_focus)
|
||||
client.add_signal("new", function(c)
|
||||
c:add_signal("untagged", check_focus)
|
||||
c:add_signal("property::hidden", check_focus)
|
||||
c:add_signal("property::minimized", check_focus)
|
||||
end)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,52 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local capi = { button = button }
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Create easily new buttons objects ignoring certain modifiers.
|
||||
module("awful.button")
|
||||
|
||||
--- Modifiers to ignore.
|
||||
-- By default this is initialized as { "Lock", "Mod2" }
|
||||
-- so the Caps Lock or Num Lock modifier are not taking into account by awesome
|
||||
-- when pressing keys.
|
||||
-- @name ignore_modifiers
|
||||
-- @class table
|
||||
ignore_modifiers = { "Lock", "Mod2" }
|
||||
|
||||
--- Create a new button to use as binding.
|
||||
-- This function is useful to create several buttons from one, because it will use
|
||||
-- the ignore_modifier variable to create more button with or without the ignored
|
||||
-- modifiers activated.
|
||||
-- For example if you want to ignore CapsLock in your buttonbinding (which is
|
||||
-- ignored by default by this function), creating button binding with this function
|
||||
-- will return 2 button objects: one with CapsLock on, and the other one with
|
||||
-- CapsLock off.
|
||||
-- @see button
|
||||
-- @return A table with one or several button objects.
|
||||
function new(mod, button, press, release)
|
||||
local ret = {}
|
||||
local subsets = util.subsets(ignore_modifiers)
|
||||
for _, set in ipairs(subsets) do
|
||||
ret[#ret + 1] = capi.button({ modifiers = util.table.join(mod, set),
|
||||
button = button })
|
||||
if press then
|
||||
ret[#ret]:add_signal("press", function(bobj, ...) press(...) end)
|
||||
end
|
||||
if release then
|
||||
ret[#ret]:add_signal("release", function (bobj, ...) release(...) end)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
846
Old/ATARI/home/burchettm/.config/awesome/lib/awful/client.lua
Normal file
846
Old/ATARI/home/burchettm/.config/awesome/lib/awful/client.lua
Normal file
@ -0,0 +1,846 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local util = require("awful.util")
|
||||
local tag = require("awful.tag")
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local math = math
|
||||
local setmetatable = setmetatable
|
||||
local capi =
|
||||
{
|
||||
client = client,
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
}
|
||||
|
||||
--- Useful client manipulation functions.
|
||||
module("awful.client")
|
||||
|
||||
-- Private data
|
||||
data = {}
|
||||
data.focus = {}
|
||||
data.urgent = {}
|
||||
data.marked = {}
|
||||
data.properties = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- Functions
|
||||
urgent = {}
|
||||
focus = {}
|
||||
focus.history = {}
|
||||
swap = {}
|
||||
floating = {}
|
||||
dockable = {}
|
||||
property = {}
|
||||
|
||||
--- Get the first client that got the urgent hint.
|
||||
-- @return The first urgent client.
|
||||
function urgent.get()
|
||||
if #data.urgent > 0 then
|
||||
return data.urgent[1]
|
||||
else
|
||||
-- fallback behaviour: iterate through clients and get the first urgent
|
||||
local clients = capi.client.get()
|
||||
for k, cl in pairs(clients) do
|
||||
if cl.urgent then
|
||||
return cl
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Jump to the client that received the urgent hint first.
|
||||
function urgent.jumpto()
|
||||
local c = urgent.get()
|
||||
if c then
|
||||
local s = capi.client.focus and capi.client.focus.screen or capi.mouse.screen
|
||||
-- focus the screen
|
||||
if s ~= c.screen then
|
||||
capi.mouse.screen = c.screen
|
||||
end
|
||||
-- focus the tag only if the client is not sticky
|
||||
if not c.sticky then
|
||||
tag.viewonly(c:tags()[1])
|
||||
end
|
||||
-- focus the client
|
||||
capi.client.focus = c
|
||||
c:raise()
|
||||
end
|
||||
end
|
||||
|
||||
--- Adds client to urgent stack.
|
||||
-- @param c The client object.
|
||||
-- @param prop The property which is updated.
|
||||
function urgent.add(c, prop)
|
||||
if type(c) == "client" and prop == "urgent" and c.urgent then
|
||||
table.insert(data.urgent, c)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove client from urgent stack.
|
||||
-- @param c The client object.
|
||||
function urgent.delete(c)
|
||||
for k, cl in ipairs(data.urgent) do
|
||||
if c == cl then
|
||||
table.remove(data.urgent, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove a client from the focus history
|
||||
-- @param c The client that must be removed.
|
||||
function focus.history.delete(c)
|
||||
for k, v in ipairs(data.focus) do
|
||||
if v == c then
|
||||
table.remove(data.focus, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Filter out window that we do not want handled by focus.
|
||||
-- This usually means that desktop, dock and splash windows are
|
||||
-- not registered and cannot get focus.
|
||||
-- @param c A client.
|
||||
-- @return The same client if it's ok, nil otherwise.
|
||||
function focus.filter(c)
|
||||
if c.type == "desktop"
|
||||
or c.type == "dock"
|
||||
or c.type == "splash"
|
||||
or not c.focusable then
|
||||
return nil
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
--- Update client focus history.
|
||||
-- @param c The client that has been focused.
|
||||
function focus.history.add(c)
|
||||
if focus.filter(c) then
|
||||
-- Remove the client if its in stack
|
||||
focus.history.delete(c)
|
||||
-- Record the client has latest focused
|
||||
table.insert(data.focus, 1, c)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the latest focused client for a screen in history.
|
||||
-- @param screen The screen number to look for.
|
||||
-- @param idx The index: 0 will return first candidate,
|
||||
-- 1 will return second, etc.
|
||||
-- @return A client.
|
||||
function focus.history.get(screen, idx)
|
||||
-- When this counter is equal to idx, we return the client
|
||||
local counter = 0
|
||||
local vc = visible(screen)
|
||||
for k, c in ipairs(data.focus) do
|
||||
if c.screen == screen then
|
||||
for j, vcc in ipairs(vc) do
|
||||
if vcc == c then
|
||||
if counter == idx then
|
||||
return c
|
||||
end
|
||||
-- We found one, increment the counter only.
|
||||
counter = counter + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Argh nobody found in history, give the first one visible if there is one
|
||||
-- that passes the filter.
|
||||
if counter == 0 then
|
||||
for k, v in ipairs(vc) do
|
||||
if focus.filter(v) then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Focus the previous client in history.
|
||||
function focus.history.previous()
|
||||
local sel = capi.client.focus
|
||||
local s
|
||||
if sel then
|
||||
s = sel.screen
|
||||
else
|
||||
s = capi.mouse.screen
|
||||
end
|
||||
local c = focus.history.get(s, 1)
|
||||
if c then capi.client.focus = c end
|
||||
end
|
||||
|
||||
--- Get visible clients from a screen.
|
||||
-- @param screen The screen number, or nil for all screens.
|
||||
-- @return A table with all visible clients.
|
||||
function visible(screen)
|
||||
local cls = capi.client.get(screen)
|
||||
local vcls = {}
|
||||
for k, c in pairs(cls) do
|
||||
if c:isvisible() then
|
||||
table.insert(vcls, c)
|
||||
end
|
||||
end
|
||||
return vcls
|
||||
end
|
||||
|
||||
--- Get visible and tiled clients
|
||||
-- @param screen The screen number, or nil for all screens.
|
||||
-- @return A tabl with all visible and tiled clients.
|
||||
function tiled(screen)
|
||||
local clients = visible(screen)
|
||||
local tclients = {}
|
||||
-- Remove floating clients
|
||||
for k, c in pairs(clients) do
|
||||
if not floating.get(c) then
|
||||
table.insert(tclients, c)
|
||||
end
|
||||
end
|
||||
return tclients
|
||||
end
|
||||
|
||||
--- Get a client by its relative index to the focused window.
|
||||
-- @usage Set i to 1 to get next, -1 to get previous.
|
||||
-- @param i The index.
|
||||
-- @param c Optional client.
|
||||
-- @return A client, or nil if no client is available.
|
||||
function next(i, c)
|
||||
-- Get currently focused client
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
-- Get all visible clients
|
||||
local cls = visible(sel.screen)
|
||||
local fcls = {}
|
||||
-- Remove all non-normal clients
|
||||
for idx, c in ipairs(cls) do
|
||||
if focus.filter(c) or c == sel then
|
||||
table.insert(fcls, c)
|
||||
end
|
||||
end
|
||||
cls = fcls
|
||||
-- Loop upon each client
|
||||
for idx, c in ipairs(cls) do
|
||||
if c == sel then
|
||||
-- Cycle
|
||||
return cls[util.cycle(#cls, idx + i)]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Return true whether client B is in the right direction
|
||||
-- compared to client A.
|
||||
-- @param dir The direction.
|
||||
-- @param cA The first client.
|
||||
-- @param cB The second client.
|
||||
-- @return True if B is in the direction of A.
|
||||
local function is_in_direction(dir, cA, cB)
|
||||
local gA = cA:geometry()
|
||||
local gB = cB:geometry()
|
||||
if dir == "up" then
|
||||
return gA.y > gB.y
|
||||
elseif dir == "down" then
|
||||
return gA.y < gB.y
|
||||
elseif dir == "left" then
|
||||
return gA.x > gB.x
|
||||
elseif dir == "right" then
|
||||
return gA.x < gB.x
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Calculate distance between two points.
|
||||
-- i.e: if we want to move to the right, we will take the right border
|
||||
-- of the currently focused client and the left side of the checked client.
|
||||
-- This avoid the focus of an upper client when you move to the right in a
|
||||
-- tilebottom layout with nmaster=2 and 5 clients open, for instance.
|
||||
-- @param dir The direction.
|
||||
-- @param cA The first client.
|
||||
-- @param cB The second client.
|
||||
-- @return The distance between the clients.
|
||||
local function calculate_distance(dir, cA, cB)
|
||||
local gA = cA:geometry()
|
||||
local gB = cB:geometry()
|
||||
|
||||
if dir == "up" then
|
||||
gB.y = gB.y + gB.height
|
||||
elseif dir == "down" then
|
||||
gA.y = gA.y + gA.height
|
||||
elseif dir == "left" then
|
||||
gB.x = gB.x + gB.width
|
||||
elseif dir == "right" then
|
||||
gA.x = gA.x + gA.width
|
||||
end
|
||||
|
||||
return math.sqrt(math.pow(gB.x - gA.x, 2) + math.pow(gB.y - gA.y, 2))
|
||||
end
|
||||
|
||||
-- Get the nearest client in the given direction.
|
||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||
-- @param c Optional client to get a client relative to. Else focussed is used.
|
||||
local function get_client_in_direction(dir, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local geometry = sel:geometry()
|
||||
local dist, dist_min
|
||||
local target = nil
|
||||
local cls = visible(sel.screen)
|
||||
|
||||
-- We check each client.
|
||||
for i, c in ipairs(cls) do
|
||||
-- Check geometry to see if client is located in the right direction.
|
||||
if is_in_direction(dir, sel, c) then
|
||||
|
||||
-- Calculate distance between focused client and checked client.
|
||||
dist = calculate_distance(dir, sel, c)
|
||||
|
||||
-- If distance is shorter then keep the client.
|
||||
if not target or dist < dist_min then
|
||||
target = c
|
||||
dist_min = dist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return target
|
||||
end
|
||||
end
|
||||
|
||||
--- Focus a client by the given direction.
|
||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||
-- @param c Optional client.
|
||||
function focus.bydirection(dir, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local target = get_client_in_direction(dir, sel)
|
||||
|
||||
-- If we found a client to focus, then do it.
|
||||
if target then
|
||||
capi.client.focus = target
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Focus a client by its relative index.
|
||||
-- @param i The index.
|
||||
-- @param c Optional client.
|
||||
function focus.byidx(i, c)
|
||||
local target = next(i, c)
|
||||
if target then
|
||||
capi.client.focus = target
|
||||
end
|
||||
end
|
||||
|
||||
--- Swap a client with another client in the given direction
|
||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||
-- @param c Optional client.
|
||||
function swap.bydirection(dir, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local target = get_client_in_direction(dir, sel)
|
||||
|
||||
-- If we found a client to swap with, then go for it
|
||||
if target then
|
||||
target:swap(sel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Swap a client by its relative index.
|
||||
-- @param i The index.
|
||||
-- @param c Optional client, otherwise focused one is used.
|
||||
function swap.byidx(i, c)
|
||||
local sel = c or capi.client.focus
|
||||
local target = next(i, sel)
|
||||
if target then
|
||||
target:swap(sel)
|
||||
end
|
||||
end
|
||||
|
||||
--- Cycle clients.
|
||||
-- @param clockwise True to cycle clients clockwise.
|
||||
-- @param screen Optional screen where to cycle clients.
|
||||
function cycle(clockwise, screen)
|
||||
local screen = screen or capi.mouse.screen
|
||||
local cls = visible(screen)
|
||||
-- We can't rotate without at least 2 clients, buddy.
|
||||
if #cls >= 2 then
|
||||
local c = table.remove(cls, 1)
|
||||
if clockwise then
|
||||
for i = #cls, 1, -1 do
|
||||
c:swap(cls[i])
|
||||
end
|
||||
else
|
||||
for _, rc in pairs(cls) do
|
||||
c:swap(rc)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the master window.
|
||||
-- @param screen Optional screen number, otherwise screen mouse is used.
|
||||
-- @return The master window.
|
||||
function getmaster(screen)
|
||||
local s = screen or capi.mouse.screen
|
||||
return visible(s)[1]
|
||||
end
|
||||
|
||||
--- Set the client as slave: put it at the end of other windows.
|
||||
-- @param c The window to set as slave.
|
||||
function setslave(c)
|
||||
local cls = visible(c.screen)
|
||||
for k, v in pairs(cls) do
|
||||
c:swap(v)
|
||||
end
|
||||
end
|
||||
|
||||
--- Move/resize a client relative to current coordinates.
|
||||
-- @param x The relative x coordinate.
|
||||
-- @param y The relative y coordinate.
|
||||
-- @param w The relative width.
|
||||
-- @param h The relative height.
|
||||
-- @param c The optional client, otherwise focused one is used.
|
||||
function moveresize(x, y, w, h, c)
|
||||
local sel = c or capi.client.focus
|
||||
local geometry = sel:geometry()
|
||||
geometry['x'] = geometry['x'] + x
|
||||
geometry['y'] = geometry['y'] + y
|
||||
geometry['width'] = geometry['width'] + w
|
||||
geometry['height'] = geometry['height'] + h
|
||||
sel:geometry(geometry)
|
||||
end
|
||||
|
||||
--- Move a client to a tag.
|
||||
-- @param target The tag to move the client to.
|
||||
-- @param c Optional client to move, otherwise the focused one is used.
|
||||
function movetotag(target, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel and target.screen then
|
||||
-- Set client on the same screen as the tag.
|
||||
sel.screen = target.screen
|
||||
sel:tags({ target })
|
||||
end
|
||||
end
|
||||
|
||||
--- Toggle a tag on a client.
|
||||
-- @param target The tag to toggle.
|
||||
-- @param c Optional client to toggle, otherwise the focused one is used.
|
||||
function toggletag(target, c)
|
||||
local sel = c or capi.client.focus
|
||||
-- Check that tag and client screen are identical
|
||||
if sel and sel.screen == target.screen then
|
||||
local tags = sel:tags()
|
||||
local index = nil;
|
||||
for i, v in ipairs(tags) do
|
||||
if v == target then
|
||||
index = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if index then
|
||||
-- If it's the only tag for the window, stop.
|
||||
if #tags == 1 then return end
|
||||
tags[index] = nil
|
||||
else
|
||||
tags[#tags + 1] = target
|
||||
end
|
||||
sel:tags(tags)
|
||||
end
|
||||
end
|
||||
|
||||
--- Move a client to a screen. Default is next screen, cycling.
|
||||
-- @param c The client to move.
|
||||
-- @param s The screen number, default to current + 1.
|
||||
function movetoscreen(c, s)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local sc = capi.screen.count()
|
||||
if not s then
|
||||
s = sel.screen + 1
|
||||
end
|
||||
if s > sc then s = 1 elseif s < 1 then s = sc end
|
||||
sel.screen = s
|
||||
capi.mouse.coords(capi.screen[s].geometry)
|
||||
capi.client.focus = sel
|
||||
end
|
||||
end
|
||||
|
||||
--- Mark a client, and then call 'marked' hook.
|
||||
-- @param c The client to mark, the focused one if not specified.
|
||||
-- @return True if the client has been marked. False if the client was already marked.
|
||||
function mark(c)
|
||||
local cl = c or capi.client.focus
|
||||
if cl then
|
||||
for k, v in pairs(data.marked) do
|
||||
if cl == v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(data.marked, cl)
|
||||
|
||||
-- Call callback
|
||||
cl:emit_signal("marked")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Unmark a client and then call 'unmarked' hook.
|
||||
-- @param c The client to unmark, or the focused one if not specified.
|
||||
-- @return True if the client has been unmarked. False if the client was not marked.
|
||||
function unmark(c)
|
||||
local cl = c or capi.client.focus
|
||||
|
||||
for k, v in pairs(data.marked) do
|
||||
if cl == v then
|
||||
table.remove(data.marked, k)
|
||||
cl:emit_signal("unmarked")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if a client is marked.
|
||||
-- @param c The client to check, or the focused one otherwise.
|
||||
function ismarked(c)
|
||||
local cl = c or capi.client.focus
|
||||
if cl then
|
||||
for k, v in pairs(data.marked) do
|
||||
if cl == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Toggle a client as marked.
|
||||
-- @param c The client to toggle mark.
|
||||
function togglemarked(c)
|
||||
local cl = c or capi.client.focus
|
||||
|
||||
if not mark(c) then
|
||||
unmark(c)
|
||||
end
|
||||
end
|
||||
|
||||
--- Return the marked clients and empty the marked table.
|
||||
-- @return A table with all marked clients.
|
||||
function getmarked()
|
||||
for k, v in pairs(data.marked) do
|
||||
v:emit_signal("unmarked")
|
||||
end
|
||||
|
||||
t = data.marked
|
||||
data.marked = {}
|
||||
return t
|
||||
end
|
||||
|
||||
--- Set a client floating state, overriding auto-detection.
|
||||
-- Floating client are not handled by tiling layouts.
|
||||
-- @param c A client.
|
||||
-- @param s True or false.
|
||||
function floating.set(c, s)
|
||||
local c = c or capi.client.focus
|
||||
if c and property.get(c, "floating") ~= s then
|
||||
property.set(c, "floating", s)
|
||||
local screen = c.screen
|
||||
if s == true then
|
||||
c:geometry(property.get(c, "floating_geometry"))
|
||||
end
|
||||
c.screen = screen
|
||||
end
|
||||
end
|
||||
|
||||
local function store_floating_geometry(c)
|
||||
if floating.get(c) then
|
||||
property.set(c, "floating_geometry", c:geometry())
|
||||
end
|
||||
end
|
||||
|
||||
-- Store the initial client geometry.
|
||||
capi.client.add_signal("new", function(c)
|
||||
local function store_init_geometry(c)
|
||||
property.set(c, "floating_geometry", c:geometry())
|
||||
c:remove_signal("property::geometry", store_init_geometry)
|
||||
end
|
||||
c:add_signal("property::geometry", store_init_geometry)
|
||||
end)
|
||||
|
||||
capi.client.add_signal("manage", function(c)
|
||||
c:add_signal("property::geometry", store_floating_geometry)
|
||||
end)
|
||||
|
||||
--- Return if a client has a fixe size or not.
|
||||
-- @param c The client.
|
||||
function isfixed(c)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
local h = c.size_hints
|
||||
if h.min_width and h.max_width
|
||||
and h.max_height and h.min_height
|
||||
and h.min_width > 0 and h.max_width > 0
|
||||
and h.max_height > 0 and h.min_height > 0
|
||||
and h.min_width == h.max_width
|
||||
and h.min_height == h.max_height then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Get a client floating state.
|
||||
-- @param c A client.
|
||||
-- @return True or false. Note that some windows might be floating even if you
|
||||
-- did not set them manually. For example, windows with a type different than
|
||||
-- normal.
|
||||
function floating.get(c)
|
||||
local c = c or capi.client.focus
|
||||
if c then
|
||||
local value = property.get(c, "floating")
|
||||
if value ~= nil then
|
||||
return value
|
||||
end
|
||||
if c.type ~= "normal"
|
||||
or c.fullscreen
|
||||
or c.maximized_vertical
|
||||
or c.maximized_horizontal
|
||||
or isfixed(c) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Toggle the floating state of a client between 'auto' and 'true'.
|
||||
-- @param c A client.
|
||||
function floating.toggle(c)
|
||||
local c = c or capi.client.focus
|
||||
-- If it has been set to floating
|
||||
if property.get(c, "floating") then
|
||||
floating.set(c, nil)
|
||||
else
|
||||
floating.set(c, true)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove the floating information on a client.
|
||||
-- @param c The client.
|
||||
function floating.delete(c)
|
||||
floating.set(c, nil)
|
||||
end
|
||||
|
||||
-- Normalize a set of numbers to 1
|
||||
-- @param set the set of numbers to normalize
|
||||
-- @param num the number of numbers to normalize
|
||||
local function normalize(set, num)
|
||||
local num = num or #set
|
||||
local total = 0
|
||||
if num then
|
||||
for i = 1,num do
|
||||
total = total + set[i]
|
||||
end
|
||||
for i = 1,num do
|
||||
set[i] = set[i] / total
|
||||
end
|
||||
else
|
||||
for i,v in ipairs(set) do
|
||||
total = total + v
|
||||
end
|
||||
|
||||
for i,v in ipairs(set) do
|
||||
set[i] = v / total
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Calculate a client's column number, index in that column, and
|
||||
-- number of visible clients in this column.
|
||||
-- @param c the client
|
||||
-- @return col the column number
|
||||
-- @return idx index of the client in the column
|
||||
-- @return num the number of visible clients in the column
|
||||
function idx(c)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
|
||||
local clients = tiled(c.screen)
|
||||
local idx = nil
|
||||
for k, cl in ipairs(clients) do
|
||||
if cl == c then
|
||||
idx = k
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local t = tag.selected(c.screen)
|
||||
local nmaster = tag.getnmaster(t)
|
||||
if idx <= nmaster then
|
||||
return {idx = idx, col=0, num=nmaster}
|
||||
end
|
||||
local nother = #clients - nmaster
|
||||
idx = idx - nmaster
|
||||
|
||||
-- rather than regenerate the column number we can calculate it
|
||||
-- based on the how the tiling algorithm places clients we calculate
|
||||
-- the column, we could easily use the for loop in the program but we can
|
||||
-- calculate it.
|
||||
local ncol = tag.getncol(t)
|
||||
-- minimum number of clients per column
|
||||
local percol = math.floor(nother / ncol)
|
||||
-- number of columns with an extra client
|
||||
local overcol = math.mod(nother, ncol)
|
||||
-- number of columns filled with [percol] clients
|
||||
local regcol = ncol - overcol
|
||||
|
||||
local col = math.floor( (idx - 1) / percol) + 1
|
||||
if col > regcol then
|
||||
-- col = math.floor( (idx - (percol*regcol) - 1) / (percol + 1) ) + regcol + 1
|
||||
-- simplified
|
||||
col = math.floor( (idx + regcol + percol) / (percol+1) )
|
||||
-- calculate the index in the column
|
||||
idx = idx - percol*regcol - (col - regcol - 1) * (percol+1)
|
||||
percol = percol+1
|
||||
else
|
||||
idx = idx - percol*(col-1)
|
||||
end
|
||||
|
||||
return {idx = idx, col=col, num=percol}
|
||||
end
|
||||
|
||||
|
||||
--- Set the window factor of a client
|
||||
-- @param wfact the window factor value
|
||||
-- @param c the client
|
||||
function setwfact(wfact, c)
|
||||
-- get the currently selected window
|
||||
local c = c or capi.client.focus
|
||||
if not c or not c:isvisible() then return end
|
||||
|
||||
local t = tag.selected(c.screen)
|
||||
local w = idx(c)
|
||||
|
||||
local cls = tiled(t.screen)
|
||||
local nmaster = tag.getnmaster(t)
|
||||
|
||||
-- n is the number of windows currently visible for which we have to be concerned with the properties
|
||||
local data = tag.getproperty(t, "windowfact") or {}
|
||||
local colfact = data[w.col]
|
||||
|
||||
colfact[w.idx] = wfact
|
||||
rest = 1-wfact
|
||||
|
||||
-- calculate the current denominator
|
||||
local total = 0
|
||||
for i = 1,w.num do
|
||||
if i ~= w.idx then
|
||||
total = total + colfact[i]
|
||||
end
|
||||
end
|
||||
|
||||
-- normalize the windows
|
||||
for i = 1,w.num do
|
||||
if i ~= w.idx then
|
||||
colfact[i] = (colfact[i] * rest) / total
|
||||
end
|
||||
end
|
||||
|
||||
t:emit_signal("property::windowfact")
|
||||
end
|
||||
|
||||
--- Increment a client's window factor
|
||||
-- @param add amount to increase the client's window
|
||||
-- @param c the client
|
||||
function incwfact(add, c)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
|
||||
local t = tag.selected(c.screen)
|
||||
|
||||
local w = idx(c)
|
||||
|
||||
local nmaster = tag.getnmaster(t)
|
||||
local data = tag.getproperty(t, "windowfact") or {}
|
||||
local colfact = data[w.col]
|
||||
curr = colfact[w.idx] or 1
|
||||
colfact[w.idx] = curr + add
|
||||
|
||||
-- keep our ratios normalized
|
||||
normalize(colfact, w.num)
|
||||
|
||||
t:emit_signal("property::windowfact")
|
||||
end
|
||||
|
||||
--- Get a client dockable state.
|
||||
-- @param c A client.
|
||||
-- @return True or false. Note that some windows might be dockable even if you
|
||||
-- did not set them manually. For example, windows with a type "utility", "toolbar"
|
||||
-- or "dock"
|
||||
function dockable.get(c)
|
||||
local value = property.get(c, "dockable")
|
||||
|
||||
-- Some sane defaults
|
||||
if value == nil then
|
||||
if (c.type == "utility" or c.type == "toolbar" or c.type == "dock") then
|
||||
value = true
|
||||
else
|
||||
value = false
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
--- Set a client dockable state, overriding auto-detection.
|
||||
-- With this enabled you can dock windows by moving them from the center
|
||||
-- to the edge of the workarea.
|
||||
-- @param c A client.
|
||||
-- @param value True or false.
|
||||
function dockable.set(c, value)
|
||||
property.set(c, "dockable", value)
|
||||
end
|
||||
|
||||
--- Get a client property.
|
||||
-- @param c The client.
|
||||
-- @param prop The property name.
|
||||
-- @return The property.
|
||||
function property.get(c, prop)
|
||||
if data.properties[c] then
|
||||
return data.properties[c][prop]
|
||||
end
|
||||
end
|
||||
|
||||
--- Set a client property.
|
||||
-- This properties are internal to awful. Some are used to move clients, etc.
|
||||
-- @param c The client.
|
||||
-- @param prop The property name.
|
||||
-- @param value The value.
|
||||
function property.set(c, prop, value)
|
||||
if not data.properties[c] then
|
||||
data.properties[c] = {}
|
||||
end
|
||||
data.properties[c][prop] = value
|
||||
c:emit_signal("property::" .. prop)
|
||||
end
|
||||
|
||||
-- Register standards signals
|
||||
capi.client.add_signal("focus", focus.history.add)
|
||||
capi.client.add_signal("unmanage", focus.history.delete)
|
||||
|
||||
capi.client.add_signal("manage", function(c) c:add_signal("property::urgent", urgent.add) end)
|
||||
capi.client.add_signal("focus", urgent.delete)
|
||||
capi.client.add_signal("unmanage", urgent.delete)
|
||||
|
||||
capi.client.add_signal("unmanage", floating.delete)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,191 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @author Sébastien Gross <seb-awesome@chezwam.org>
|
||||
-- @copyright 2008 Julien Danjou, Sébastien Gross
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local io = io
|
||||
local os = os
|
||||
local table = table
|
||||
local math = math
|
||||
local print = print
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Completion module.
|
||||
-- This module store a set of function using shell to complete commands name.
|
||||
module("awful.completion")
|
||||
|
||||
-- mapping of command/completion function
|
||||
local bashcomp_funcs = {}
|
||||
local bashcomp_src = "/etc/bash_completion"
|
||||
|
||||
--- Enable programmable bash completion in awful.completion.bash at the price of
|
||||
-- a slight overhead.
|
||||
-- @param src The bash completion source file, /etc/bash_completion by default.
|
||||
function bashcomp_load(src)
|
||||
if src then bashcomp_src = src end
|
||||
local c, err = io.popen("/usr/bin/env bash -c 'source " .. bashcomp_src .. "; complete -p'")
|
||||
if c then
|
||||
while true do
|
||||
local line = c:read("*line")
|
||||
if not line then break end
|
||||
-- if a bash function is used for completion, register it
|
||||
if line:match(".* -F .*") then
|
||||
bashcomp_funcs[line:gsub(".* (%S+)$","%1")] = line:gsub(".*-F +(%S+) .*$", "%1")
|
||||
end
|
||||
end
|
||||
c:close()
|
||||
else
|
||||
print(err)
|
||||
end
|
||||
end
|
||||
|
||||
local function bash_escape(str)
|
||||
str = str:gsub(" ", "\\ ")
|
||||
str = str:gsub("%[", "\\[")
|
||||
str = str:gsub("%]", "\\]")
|
||||
str = str:gsub("%(", "\\(")
|
||||
str = str:gsub("%)", "\\)")
|
||||
return str
|
||||
end
|
||||
|
||||
--- Use shell completion system to complete command and filename.
|
||||
-- @param command The command line.
|
||||
-- @param cur_pos The cursor position.
|
||||
-- @param ncomp The element number to complete.
|
||||
-- @param shell The shell to use for completion (bash (default) or zsh).
|
||||
-- @return The new command, the new cursor position, the table of all matches.
|
||||
function shell(command, cur_pos, ncomp, shell)
|
||||
local wstart = 1
|
||||
local wend = 1
|
||||
local words = {}
|
||||
local cword_index = 0
|
||||
local cword_start = 0
|
||||
local cword_end = 0
|
||||
local i = 1
|
||||
local comptype = "file"
|
||||
|
||||
-- do nothing if we are on a letter, i.e. not at len + 1 or on a space
|
||||
if cur_pos ~= #command + 1 and command:sub(cur_pos, cur_pos) ~= " " then
|
||||
return command, cur_pos
|
||||
elseif #command == 0 then
|
||||
return command, cur_pos
|
||||
end
|
||||
|
||||
while wend <= #command do
|
||||
wend = command:find(" ", wstart)
|
||||
if not wend then wend = #command + 1 end
|
||||
table.insert(words, command:sub(wstart, wend - 1))
|
||||
if cur_pos >= wstart and cur_pos <= wend + 1 then
|
||||
cword_start = wstart
|
||||
cword_end = wend
|
||||
cword_index = i
|
||||
end
|
||||
wstart = wend + 1
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if cword_index == 1 then
|
||||
comptype = "command"
|
||||
end
|
||||
|
||||
local shell_cmd
|
||||
if shell == "zsh" or (not shell and os.getenv("SHELL"):match("zsh$")) then
|
||||
if comptype == "file" then
|
||||
shell_cmd = "/usr/bin/env zsh -c 'local -a res; res=( " .. words[cword_index] .. "* ); print -l -- ${res[@]}'"
|
||||
else
|
||||
-- check commands, aliases, builtins, functions and reswords
|
||||
shell_cmd = "/usr/bin/env zsh -c 'local -a res; "..
|
||||
"res=( "..
|
||||
"\"${(k)commands[@]}\" \"${(k)aliases[@]}\" \"${(k)builtins[@]}\" \"${(k)functions[@]}\" \"${(k)reswords[@]}\" "..
|
||||
"); "..
|
||||
"print -l -- ${(M)res[@]:#"..words[cword_index].."*}'"
|
||||
end
|
||||
else
|
||||
if bashcomp_funcs[words[1]] then
|
||||
-- fairly complex command with inline bash script to get the possible completions
|
||||
shell_cmd = "/usr/bin/env bash -c 'source " .. bashcomp_src .. "; " ..
|
||||
"__print_completions() { for ((i=0;i<${#COMPREPLY[*]};i++)); do echo ${COMPREPLY[i]}; done }; " ..
|
||||
"COMP_WORDS=(" .. command .."); COMP_LINE=\"" .. command .. "\"; " ..
|
||||
"COMP_COUNT=" .. cur_pos .. "; COMP_CWORD=" .. cword_index-1 .. "; " ..
|
||||
bashcomp_funcs[words[1]] .. "; __print_completions'"
|
||||
else
|
||||
shell_cmd = "/usr/bin/env bash -c 'compgen -A " .. comptype .. " " .. words[cword_index] .. "'"
|
||||
end
|
||||
end
|
||||
local c, err = io.popen(shell_cmd .. " | sort -u")
|
||||
local output = {}
|
||||
i = 0
|
||||
if c then
|
||||
while true do
|
||||
local line = c:read("*line")
|
||||
if not line then break end
|
||||
if os.execute("test -d " .. line) == 0 then
|
||||
line = line .. "/"
|
||||
end
|
||||
table.insert(output, bash_escape(line))
|
||||
end
|
||||
|
||||
c:close()
|
||||
else
|
||||
print(err)
|
||||
end
|
||||
|
||||
-- no completion, return
|
||||
if #output == 0 then
|
||||
return command, cur_pos
|
||||
end
|
||||
|
||||
-- cycle
|
||||
while ncomp > #output do
|
||||
ncomp = ncomp - #output
|
||||
end
|
||||
|
||||
local str = command:sub(1, cword_start - 1) .. output[ncomp] .. command:sub(cword_end)
|
||||
cur_pos = cword_end + #output[ncomp] + 1
|
||||
|
||||
return str, cur_pos, output
|
||||
end
|
||||
|
||||
--- Run a generic completion.
|
||||
-- For this function to run properly the awful.completion.keyword table should
|
||||
-- be fed up with all keywords. The completion is run against these keywords.
|
||||
-- @param text The current text the user had typed yet.
|
||||
-- @param cur_pos The current cursor position.
|
||||
-- @param ncomp The number of yet requested completion using current text.
|
||||
-- @param keywords The keywords table uised for completion.
|
||||
-- @return The new match, the new cursor position, the table of all matches.
|
||||
function generic(text, cur_pos, ncomp, keywords)
|
||||
-- The keywords table may be empty
|
||||
if #keywords == 0 then
|
||||
return text, #text + 1
|
||||
end
|
||||
|
||||
-- if no text had been typed yet, then we could start cycling around all
|
||||
-- keywords with out filtering and move the cursor at the end of keyword
|
||||
if text == nil or #text == 0 then
|
||||
ncomp = math.mod(ncomp - 1, #keywords) + 1
|
||||
return keywords[ncomp], #keywords[ncomp] + 2
|
||||
end
|
||||
|
||||
-- Filter out only keywords starting with text
|
||||
local matches = {}
|
||||
table.foreach(keywords, function(_, x)
|
||||
if x:sub(1 , #text) == text then
|
||||
table.insert(matches, x)
|
||||
end
|
||||
end)
|
||||
|
||||
-- if there are no matches just leave out with the current text and position
|
||||
if #matches == 0 then
|
||||
return text, #text + 1, matches
|
||||
end
|
||||
|
||||
-- cycle around all matches
|
||||
ncomp = math.mod(ncomp - 1, #matches) + 1
|
||||
return matches[ncomp], #matches[ncomp] + 1, matches
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
19
Old/ATARI/home/burchettm/.config/awesome/lib/awful/dbus.lua
Normal file
19
Old/ATARI/home/burchettm/.config/awesome/lib/awful/dbus.lua
Normal file
@ -0,0 +1,19 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local dbus = dbus
|
||||
|
||||
--- D-Bus module for awful.
|
||||
-- This module simply request the org.naquadah.awesome.awful name on the D-Bus
|
||||
-- for futur usage by other awful modules.
|
||||
module("awful.dbus")
|
||||
|
||||
if dbus then
|
||||
dbus.request_name("session", "org.naquadah.awesome.awful")
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
160
Old/ATARI/home/burchettm/.config/awesome/lib/awful/hooks.lua
Normal file
160
Old/ATARI/home/burchettm/.config/awesome/lib/awful/hooks.lua
Normal file
@ -0,0 +1,160 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local math = math
|
||||
local capi =
|
||||
{
|
||||
hooks = hooks
|
||||
}
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Hooks module for awful.
|
||||
-- This module is deprecated and should not be used anymore. You are encouraged
|
||||
-- to use signals.
|
||||
module("awful.hooks")
|
||||
|
||||
-- User hook functions
|
||||
user = {}
|
||||
|
||||
--- Create a new userhook (for external libs).
|
||||
-- @param name Hook name.
|
||||
function user.create(name)
|
||||
_M[name] = {}
|
||||
_M[name].callbacks = {}
|
||||
_M[name].register = function (f)
|
||||
table.insert(_M[name].callbacks, f)
|
||||
end
|
||||
_M[name].unregister = function (f)
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
if h == f then
|
||||
table.remove(_M[name].callbacks, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Call a created userhook (for external libs).
|
||||
-- @param name Hook name.
|
||||
function user.call(name, ...)
|
||||
for name, callback in pairs(_M[name].callbacks) do
|
||||
callback(...)
|
||||
end
|
||||
end
|
||||
|
||||
-- Autodeclare awful.hooks.* functions
|
||||
-- mapped to awesome hooks.* functions
|
||||
for name, hook in pairs(capi.hooks) do
|
||||
_M[name] = {}
|
||||
if name == 'timer' then
|
||||
_M[name].register = function (time, f, runnow)
|
||||
util.deprecate("timer object")
|
||||
if type(time) ~= 'number' or type(f) ~= 'function' or time <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if not _M[name].callbacks then
|
||||
_M[name].callbacks = {}
|
||||
end
|
||||
|
||||
for k, v in pairs(_M[name].callbacks) do
|
||||
if v.callback == f then
|
||||
_M[name].unregister(f)
|
||||
_M[name].register(time, f, runnow)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local new_timer
|
||||
if _M[name].timer then
|
||||
-- Take the smallest between current and new
|
||||
new_timer = math.min(time, _M[name].timer)
|
||||
else
|
||||
new_timer = time
|
||||
end
|
||||
|
||||
if _M[name].timer ~= new_timer then
|
||||
_M[name].timer = new_timer
|
||||
end
|
||||
|
||||
hook(_M[name].timer, function (...)
|
||||
for i, callback in ipairs(_M[name].callbacks) do
|
||||
callback['counter'] = callback['counter'] + _M[name].timer
|
||||
if callback['counter'] >= callback['timer'] then
|
||||
callback['callback'](...)
|
||||
callback['counter'] = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if runnow then
|
||||
table.insert(_M[name].callbacks, { callback = f, timer = time, counter = time })
|
||||
else
|
||||
table.insert(_M[name].callbacks, { callback = f, timer = time, counter = 0 })
|
||||
end
|
||||
end
|
||||
_M[name].unregister = function (f)
|
||||
if _M[name].callbacks then
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
if h.callback == f then
|
||||
table.remove(_M[name].callbacks, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
local delays = { }
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
table.insert(delays, h.timer)
|
||||
end
|
||||
table.sort(delays)
|
||||
_M[name].timer = delays[1]
|
||||
if not delays[1] then delays[1] = 0 end
|
||||
hook(delays[1], function (...)
|
||||
for i, callback in ipairs(_M[name].callbacks) do
|
||||
callback['counter'] = callback['counter'] + _M[name].timer
|
||||
if callback['counter'] >= callback['timer'] then
|
||||
callback['callback'](...)
|
||||
callback['counter'] = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
else
|
||||
_M[name].register = function (f)
|
||||
util.deprecate("signals")
|
||||
if not _M[name].callbacks then
|
||||
_M[name].callbacks = {}
|
||||
hook(function (...)
|
||||
for i, callback in ipairs(_M[name].callbacks) do
|
||||
callback(...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
table.insert(_M[name].callbacks, f)
|
||||
end
|
||||
end
|
||||
|
||||
if name ~= "timer" then
|
||||
_M[name].unregister = function (f)
|
||||
if _M[name].callbacks then
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
if h == f then
|
||||
table.remove(_M[name].callbacks, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
30
Old/ATARI/home/burchettm/.config/awesome/lib/awful/init.lua
Normal file
30
Old/ATARI/home/burchettm/.config/awesome/lib/awful/init.lua
Normal file
@ -0,0 +1,30 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
require("awful.client")
|
||||
require("awful.completion")
|
||||
require("awful.hooks")
|
||||
require("awful.layout")
|
||||
require("awful.placement")
|
||||
require("awful.prompt")
|
||||
require("awful.screen")
|
||||
require("awful.tag")
|
||||
require("awful.titlebar")
|
||||
require("awful.util")
|
||||
require("awful.widget")
|
||||
require("awful.menu")
|
||||
require("awful.mouse")
|
||||
require("awful.remote")
|
||||
require("awful.key")
|
||||
require("awful.button")
|
||||
require("awful.wibox")
|
||||
require("awful.startup_notification")
|
||||
require("awful.tooltip")
|
||||
|
||||
--- AWesome Functions very UsefuL
|
||||
module("awful")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
78
Old/ATARI/home/burchettm/.config/awesome/lib/awful/key.lua
Normal file
78
Old/ATARI/home/burchettm/.config/awesome/lib/awful/key.lua
Normal file
@ -0,0 +1,78 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local capi = { key = key }
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Create easily new key objects ignoring certain modifiers.
|
||||
module("awful.key")
|
||||
|
||||
--- Modifiers to ignore.
|
||||
-- By default this is initialized as { "Lock", "Mod2" }
|
||||
-- so the Caps Lock or Num Lock modifier are not taking into account by awesome
|
||||
-- when pressing keys.
|
||||
-- @name ignore_modifiers
|
||||
-- @class table
|
||||
ignore_modifiers = { "Lock", "Mod2" }
|
||||
|
||||
--- Create a new key to use as binding.
|
||||
-- This function is useful to create several keys from one, because it will use
|
||||
-- the ignore_modifier variable to create more key with or without the ignored
|
||||
-- modifiers activated.
|
||||
-- For example if you want to ignore CapsLock in your keybinding (which is
|
||||
-- ignored by default by this function), creating key binding with this function
|
||||
-- will return 2 key objects: one with CapsLock on, and the other one with
|
||||
-- CapsLock off.
|
||||
-- @see capi.key
|
||||
-- @return A table with one or several key objects.
|
||||
function new(mod, key, press, release)
|
||||
local ret = {}
|
||||
local subsets = util.subsets(ignore_modifiers)
|
||||
for _, set in ipairs(subsets) do
|
||||
ret[#ret + 1] = capi.key({ modifiers = util.table.join(mod, set),
|
||||
key = key })
|
||||
if press then
|
||||
ret[#ret]:add_signal("press", function(kobj, ...) press(...) end)
|
||||
end
|
||||
if release then
|
||||
ret[#ret]:add_signal("release", function(kobj, ...) release(...) end)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Compare a key object with modifiers and key.
|
||||
-- @param key The key object.
|
||||
-- @param pressed_mod The modifiers to compare with.
|
||||
-- @param pressed_key The key to compare with.
|
||||
function match(key, pressed_mod, pressed_key)
|
||||
-- First, compare key.
|
||||
if pressed_key ~= key.key then return false end
|
||||
-- Then, compare mod
|
||||
local mod = key.modifiers
|
||||
-- For each modifier of the key object, check that the modifier has been
|
||||
-- pressed.
|
||||
for _, m in ipairs(mod) do
|
||||
-- Has it been pressed?
|
||||
if not util.table.hasitem(pressed_mod, m) then
|
||||
-- No, so this is failure!
|
||||
return false
|
||||
end
|
||||
end
|
||||
-- If the number of pressed modifier is ~=, it is probably >, so this is not
|
||||
-- the same, return false.
|
||||
if #pressed_mod ~= #mod then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,156 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local capi = { screen = screen, client = client }
|
||||
local tag = require("awful.tag")
|
||||
local util = require("awful.util")
|
||||
local suit = require("awful.layout.suit")
|
||||
local ascreen = require("awful.screen")
|
||||
local capi = {
|
||||
screen = screen,
|
||||
awesome = awesome,
|
||||
client = client
|
||||
}
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Layout module for awful
|
||||
module("awful.layout")
|
||||
|
||||
-- This is a special lock used by the arrange function.
|
||||
-- This avoids recurring call by emitted signals.
|
||||
local arrange_lock = false
|
||||
|
||||
--- Get the current layout.
|
||||
-- @param screen The screen number.
|
||||
-- @return The layout function.
|
||||
function get(screen)
|
||||
local t = tag.selected(screen)
|
||||
return tag.getproperty(t, "layout") or suit.floating
|
||||
end
|
||||
|
||||
--- Change the layout of the current tag.
|
||||
-- @param layouts A table of layouts.
|
||||
-- @param i Relative index.
|
||||
function inc(layouts, i)
|
||||
local t = tag.selected()
|
||||
if t then
|
||||
local curlayout = get()
|
||||
local curindex
|
||||
local rev_layouts = {}
|
||||
for k, v in ipairs(layouts) do
|
||||
if v == curlayout then
|
||||
curindex = k
|
||||
break
|
||||
end
|
||||
end
|
||||
if curindex then
|
||||
local newindex = util.cycle(#layouts, curindex + i)
|
||||
set(layouts[newindex])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the layout function of the current tag.
|
||||
-- @param layout Layout name.
|
||||
function set(layout, t)
|
||||
t = t or tag.selected()
|
||||
tag.setproperty(t, "layout", layout)
|
||||
end
|
||||
|
||||
--- Arrange a screen using its current layout.
|
||||
-- @param screen The screen to arrange.
|
||||
function arrange(screen)
|
||||
if arrange_lock then return end
|
||||
arrange_lock = true
|
||||
local p = {}
|
||||
p.workarea = capi.screen[screen].workarea
|
||||
-- Handle padding
|
||||
local padding = ascreen.padding(capi.screen[screen])
|
||||
if padding then
|
||||
p.workarea.x = p.workarea.x + (padding.left or 0)
|
||||
p.workarea.y = p.workarea.y + (padding.top or 0)
|
||||
p.workarea.width = p.workarea.width - ((padding.left or 0 ) + (padding.right or 0))
|
||||
p.workarea.height = p.workarea.height - ((padding.top or 0) + (padding.bottom or 0))
|
||||
end
|
||||
p.geometry = capi.screen[screen].geometry
|
||||
p.clients = client.tiled(screen)
|
||||
p.screen = screen
|
||||
get(screen).arrange(p)
|
||||
capi.screen[screen]:emit_signal("arrange")
|
||||
arrange_lock = false
|
||||
end
|
||||
|
||||
--- Get the current layout name.
|
||||
-- @param layout The layout.
|
||||
-- @return The layout name.
|
||||
function getname(layout)
|
||||
local layout = layout or get()
|
||||
return layout.name
|
||||
end
|
||||
|
||||
local function arrange_prop(obj) arrange(obj.screen) end
|
||||
|
||||
capi.client.add_signal("new", function(c)
|
||||
c:add_signal("property::size_hints_honor", arrange_prop)
|
||||
c:add_signal("property::struts", arrange_prop)
|
||||
c:add_signal("property::minimized", arrange_prop)
|
||||
c:add_signal("property::sticky", arrange_prop)
|
||||
c:add_signal("property::fullscreen", arrange_prop)
|
||||
c:add_signal("property::maximized_horizontal", arrange_prop)
|
||||
c:add_signal("property::maximized_vertical", arrange_prop)
|
||||
c:add_signal("property::border_width", arrange_prop)
|
||||
c:add_signal("property::hidden", arrange_prop)
|
||||
c:add_signal("property::titlebar", arrange_prop)
|
||||
c:add_signal("property::floating", arrange_prop)
|
||||
c:add_signal("property::geometry", arrange_prop)
|
||||
-- If prop is screen, we do not know what was the previous screen, so
|
||||
-- let's arrange all screens :-(
|
||||
c:add_signal("property::screen", function(c)
|
||||
for screen = 1, capi.screen.count() do arrange(screen) end end)
|
||||
end)
|
||||
|
||||
local function arrange_on_tagged(c, tag)
|
||||
if not tag.screen then return end
|
||||
arrange(tag.screen)
|
||||
if not capi.client.focus or not capi.client.focus:isvisible() then
|
||||
local c = client.focus.history.get(tag.screen, 0)
|
||||
if c then capi.client.focus = c end
|
||||
end
|
||||
end
|
||||
|
||||
for s = 1, capi.screen.count() do
|
||||
tag.attached_add_signal(s, "property::mwfact", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::nmaster", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::ncol", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::layout", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::windowfact", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::selected", arrange_prop)
|
||||
tag.attached_add_signal(s, "tagged", arrange_prop)
|
||||
capi.screen[s]:add_signal("property::workarea", function(screen)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
capi.screen[s]:add_signal("tag::attach", function (screen, tag)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
capi.screen[s]:add_signal("tag::detach", function (screen, tag)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
capi.screen[s]:add_signal("padding", function (screen)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
end
|
||||
|
||||
capi.client.add_signal("focus", function(c) arrange(c.screen) end)
|
||||
capi.client.add_signal("list", function()
|
||||
for screen = 1, capi.screen.count() do
|
||||
arrange(screen)
|
||||
end
|
||||
end)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,74 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
|
||||
--- Fair layouts module for awful
|
||||
module("awful.layout.suit.fair")
|
||||
|
||||
local function fair(p, orientation)
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
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 = {}
|
||||
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
|
||||
|
||||
g.x = wa.x + cell * g.width
|
||||
g.y = wa.y + strip * g.height
|
||||
|
||||
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
|
||||
|
||||
g.x = wa.x + strip * g.width
|
||||
g.y = wa.y + cell * g.height
|
||||
end
|
||||
|
||||
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.
|
||||
horizontal = {}
|
||||
horizontal.name = "fairh"
|
||||
function horizontal.arrange(p)
|
||||
return fair(p, "east")
|
||||
end
|
||||
|
||||
-- Vertical fair layout.
|
||||
-- @param screen The screen to arrange.
|
||||
name = "fairv"
|
||||
function arrange(p)
|
||||
return fair(p, "south")
|
||||
end
|
@ -0,0 +1,13 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Gregor Best
|
||||
-- @copyright 2008 Gregor Best
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
--- Dummy function for floating layout
|
||||
module("awful.layout.suit.floating")
|
||||
|
||||
function arrange()
|
||||
end
|
||||
|
||||
name = "floating"
|
@ -0,0 +1,9 @@
|
||||
require("awful.layout.suit.max")
|
||||
require("awful.layout.suit.tile")
|
||||
require("awful.layout.suit.fair")
|
||||
require("awful.layout.suit.floating")
|
||||
require("awful.layout.suit.magnifier")
|
||||
require("awful.layout.suit.spiral")
|
||||
|
||||
--- Suits for awful
|
||||
module("awful.layout.suit")
|
@ -0,0 +1,92 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local tag = require("awful.tag")
|
||||
local capi =
|
||||
{
|
||||
client = client,
|
||||
screen = screen
|
||||
}
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Magnifier layout module for awful
|
||||
module("awful.layout.suit.magnifier")
|
||||
|
||||
function arrange(p)
|
||||
-- Fullscreen?
|
||||
local area = p.workarea
|
||||
local cls = p.clients
|
||||
local focus = capi.client.focus
|
||||
local mwfact = tag.getmwfact(tag.selected(p.screen))
|
||||
local fidx
|
||||
|
||||
-- Check that the focused window is on the right screen
|
||||
if focus and focus.screen ~= p.screen then focus = nil end
|
||||
|
||||
if not focus and #cls > 0 then
|
||||
focus = cls[1]
|
||||
fidx = 1
|
||||
end
|
||||
|
||||
-- If focused window is not tiled, take the first one which is tiled.
|
||||
if client.floating.get(focus) then
|
||||
focus = cls[1]
|
||||
fidx = 1
|
||||
end
|
||||
|
||||
-- Abort if no clients are present
|
||||
if not focus then return end
|
||||
|
||||
local geometry = {}
|
||||
if #cls > 1 then
|
||||
geometry.width = area.width * math.sqrt(mwfact)
|
||||
geometry.height = area.height * math.sqrt(mwfact)
|
||||
geometry.x = area.x + (area.width - geometry.width) / 2
|
||||
geometry.y = area.y + (area.height - geometry.height) /2
|
||||
else
|
||||
geometry.x = area.x
|
||||
geometry.y = area.y
|
||||
geometry.width = area.width
|
||||
geometry.height = area.height
|
||||
end
|
||||
focus:geometry(geometry)
|
||||
focus:raise()
|
||||
|
||||
if #cls > 1 then
|
||||
geometry.x = area.x
|
||||
geometry.y = area.y
|
||||
geometry.height = area.height / (#cls - 1)
|
||||
geometry.width = area.width
|
||||
|
||||
-- We don't know what the focus window index. Try to find it.
|
||||
if not fidx then
|
||||
for k, c in ipairs(cls) do
|
||||
if c == focus then
|
||||
fidx = k
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- First move clients that are before focused client.
|
||||
for k = fidx + 1, #cls do
|
||||
cls[k]:geometry(geometry)
|
||||
geometry.y = geometry.y + geometry.height
|
||||
end
|
||||
|
||||
-- Then move clients that are after focused client.
|
||||
-- So the next focused window will be the one at the top of the screen.
|
||||
for k = 1, fidx - 1 do
|
||||
cls[k]:geometry(geometry)
|
||||
geometry.y = geometry.y + geometry.height
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
name = "magnifier"
|
@ -0,0 +1,41 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local pairs = pairs
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Maximized and fullscreen layouts module for awful
|
||||
module("awful.layout.suit.max")
|
||||
|
||||
local function fmax(p, fs)
|
||||
-- Fullscreen?
|
||||
local area
|
||||
if fs then
|
||||
area = p.geometry
|
||||
else
|
||||
area = p.workarea
|
||||
end
|
||||
|
||||
for k, c in pairs(p.clients) do
|
||||
c:geometry(area)
|
||||
end
|
||||
end
|
||||
|
||||
--- Maximized layout.
|
||||
-- @param screen The screen to arrange.
|
||||
name = "max"
|
||||
function arrange(p)
|
||||
return fmax(p, false)
|
||||
end
|
||||
|
||||
--- Fullscreen layout.
|
||||
-- @param screen The screen to arrange.
|
||||
fullscreen = {}
|
||||
fullscreen.name = "fullscreen"
|
||||
function fullscreen.arrange(p)
|
||||
return fmax(p, true)
|
||||
end
|
@ -0,0 +1,58 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Uli Schlachter <psychon@znc.in>
|
||||
-- @copyright 2009 Uli Schlachter
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
|
||||
module("awful.layout.suit.spiral")
|
||||
|
||||
local function spiral(p, spiral)
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
local n = #cls
|
||||
|
||||
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
|
||||
|
||||
c:geometry(wa)
|
||||
end
|
||||
end
|
||||
|
||||
--- Dwindle layout
|
||||
dwindle = {}
|
||||
dwindle.name = "dwindle"
|
||||
function dwindle.arrange(p)
|
||||
return spiral(p, false)
|
||||
end
|
||||
|
||||
--- Spiral layout
|
||||
name = "spiral"
|
||||
function arrange(p)
|
||||
return spiral(p, true)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,180 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Donald Ephraim Curtis <dcurtis@cs.uiowa.edu>
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Donald Ephraim Curtis
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local tag = require("awful.tag")
|
||||
|
||||
--- Tiled layouts module for awful
|
||||
module("awful.layout.suit.tile")
|
||||
|
||||
local function tile_group(cls, wa, orientation, fact, group)
|
||||
-- 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)
|
||||
available = wa[width] - (group.coord - wa[x])
|
||||
|
||||
-- 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)
|
||||
|
||||
local coord = wa[y]
|
||||
local geom = {}
|
||||
local used_size = 0
|
||||
local unused = wa[height]
|
||||
for c = group.first,group.last do
|
||||
local i = c - group.first +1
|
||||
geom[width] = size
|
||||
geom[height] = math.floor(unused * fact[i] / total_fact)
|
||||
geom[x] = group.coord
|
||||
geom[y] = coord
|
||||
geom = cls[c]:geometry(geom)
|
||||
coord = coord + geom[height]
|
||||
unused = unused - geom[height]
|
||||
total_fact = total_fact - fact[i]
|
||||
used_size = math.max(used_size, geom[width])
|
||||
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) )
|
||||
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
|
||||
|
||||
right = {}
|
||||
right.name = "tile"
|
||||
right.arrange = tile
|
||||
|
||||
--- The main tile algo, on left.
|
||||
-- @param screen The screen number to tile.
|
||||
left = {}
|
||||
left.name = "tileleft"
|
||||
function left.arrange(p)
|
||||
return tile(p, "left")
|
||||
end
|
||||
|
||||
--- The main tile algo, on bottom.
|
||||
-- @param screen The screen number to tile.
|
||||
bottom = {}
|
||||
bottom.name = "tilebottom"
|
||||
function bottom.arrange(p)
|
||||
return tile(p, "bottom")
|
||||
end
|
||||
|
||||
--- The main tile algo, on top.
|
||||
-- @param screen The screen number to tile.
|
||||
top = {}
|
||||
top.name = "tiletop"
|
||||
function top.arrange(p)
|
||||
return tile(p, "top")
|
||||
end
|
||||
|
||||
arrange = right.arrange
|
||||
name = right.name
|
424
Old/ATARI/home/burchettm/.config/awesome/lib/awful/menu.lua
Normal file
424
Old/ATARI/home/burchettm/.config/awesome/lib/awful/menu.lua
Normal file
@ -0,0 +1,424 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Damien Leone <damien.leone@gmail.com>
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Damien Leone, Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local string = string
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local wibox = wibox
|
||||
local image = image
|
||||
local widget = widget
|
||||
local button = require("awful.button")
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
mouse = mouse,
|
||||
client = client,
|
||||
keygrabber = keygrabber
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local tags = require("awful.tag")
|
||||
local layout = require("awful.widget.layout")
|
||||
local awbeautiful = require("beautiful")
|
||||
local tonumber = tonumber
|
||||
|
||||
--- Creation of menus.
|
||||
module("awful.menu")
|
||||
|
||||
local cur_menu
|
||||
|
||||
--- Key bindings for menu navigation.
|
||||
-- Keys are: up, down, exec, back, close. Value are table with a list of valid
|
||||
-- keys for the action, i.e. menu_keys.up = { "j", "k" } will bind 'j' and 'k'
|
||||
-- key to up action. This is common to all created menu.
|
||||
-- @class table
|
||||
-- @name menu_keys
|
||||
menu_keys = { up = { "Up" },
|
||||
down = { "Down" },
|
||||
exec = { "Return", "Right" },
|
||||
back = { "Left" },
|
||||
close = { "Escape" } }
|
||||
|
||||
local function load_theme(custom)
|
||||
local theme = {}
|
||||
local beautiful
|
||||
|
||||
beautiful = awbeautiful.get()
|
||||
|
||||
theme.fg_focus = custom.fg_focus or beautiful.menu_fg_focus or beautiful.fg_focus
|
||||
theme.bg_focus = custom.bg_focus or beautiful.menu_bg_focus or beautiful.bg_focus
|
||||
theme.fg_normal = custom.fg_normal or beautiful.menu_fg_normal or beautiful.fg_normal
|
||||
theme.bg_normal = custom.bg_normal or beautiful.menu_bg_normal or beautiful.bg_normal
|
||||
|
||||
theme.submenu_icon = custom.submenu_icon or beautiful.menu_submenu_icon
|
||||
|
||||
theme.menu_height = custom.height or beautiful.menu_height or 16
|
||||
theme.menu_width = custom.width or beautiful.menu_width or 100
|
||||
|
||||
theme.border = custom.border_color or beautiful.menu_border_color or beautiful.border_normal
|
||||
theme.border_width = custom.border_width or beautiful.menu_border_width or beautiful.border_width
|
||||
|
||||
return theme
|
||||
end
|
||||
|
||||
local function item_leave(menu, num)
|
||||
if num > 0 then
|
||||
menu.items[num].wibox.fg = menu.theme.fg_normal
|
||||
menu.items[num].wibox.bg = menu.theme.bg_normal
|
||||
end
|
||||
end
|
||||
|
||||
--- Hide a menu popup.
|
||||
-- @param menu The menu to hide.
|
||||
function hide(menu)
|
||||
-- Remove items from screen
|
||||
for i = 1, #menu.items do
|
||||
item_leave(menu, i)
|
||||
menu.items[i].wibox.screen = nil
|
||||
end
|
||||
if menu.active_child then
|
||||
menu.active_child:hide()
|
||||
menu.active_child = nil
|
||||
end
|
||||
menu.sel = nil
|
||||
|
||||
if cur_menu == menu then
|
||||
cur_menu = cur_menu.parent
|
||||
end
|
||||
if not cur_menu and menu.keygrabber then
|
||||
capi.keygrabber.stop()
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the elder parent so for example when you kill
|
||||
-- it, it will destroy the whole family.
|
||||
local function get_parents(menu)
|
||||
if menu.parent then
|
||||
return get_parents(menu.parent)
|
||||
end
|
||||
return menu
|
||||
end
|
||||
|
||||
local function exec(menu, num, mouse_event)
|
||||
local cmd = menu.items[num].cmd
|
||||
if type(cmd) == "table" then
|
||||
if #cmd == 0 then
|
||||
return
|
||||
end
|
||||
if not menu.child[num] then
|
||||
menu.child[num] = new({ items = cmd }, menu, num)
|
||||
end
|
||||
|
||||
if menu.active_child then
|
||||
menu.active_child:hide()
|
||||
menu.active_child = nil
|
||||
end
|
||||
menu.active_child = menu.child[num]
|
||||
menu.active_child:show()
|
||||
elseif type(cmd) == "string" then
|
||||
get_parents(menu):hide()
|
||||
util.spawn(cmd)
|
||||
elseif type(cmd) == "function" then
|
||||
get_parents(menu):hide()
|
||||
cmd(menu.items[num].returned_value)
|
||||
end
|
||||
end
|
||||
|
||||
local function item_enter(menu, num, mouse_event)
|
||||
if menu.sel == num then
|
||||
return
|
||||
elseif menu.sel then
|
||||
item_leave(menu, menu.sel)
|
||||
end
|
||||
|
||||
menu.items[num].wibox.fg = menu.theme.fg_focus
|
||||
menu.items[num].wibox.bg = menu.theme.bg_focus
|
||||
menu.sel = num
|
||||
cur_menu = menu
|
||||
|
||||
if menu.auto_expand and mouse_event then
|
||||
if menu.active_child then
|
||||
menu.active_child:hide()
|
||||
menu.active_child = nil
|
||||
end
|
||||
|
||||
if type(menu.items[num].cmd) == "table" then
|
||||
exec(menu, num)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function check_access_key(menu, key)
|
||||
for i, item in pairs(menu.items) do
|
||||
if item.akey == key then
|
||||
item_enter(menu, i)
|
||||
exec(menu, i)
|
||||
return
|
||||
end
|
||||
end
|
||||
if menu.parent then
|
||||
check_access_key(menu.parent, key)
|
||||
end
|
||||
end
|
||||
|
||||
local function grabber(mod, key, event)
|
||||
if event == "release" then
|
||||
return true
|
||||
end
|
||||
|
||||
local sel = cur_menu.sel or 0
|
||||
if util.table.hasitem(menu_keys.up, key) then
|
||||
local sel_new = sel-1 < 1 and #cur_menu.items or sel-1
|
||||
item_enter(cur_menu, sel_new)
|
||||
elseif util.table.hasitem(menu_keys.down, key) then
|
||||
local sel_new = sel+1 > #cur_menu.items and 1 or sel+1
|
||||
item_enter(cur_menu, sel_new)
|
||||
elseif sel > 0 and util.table.hasitem(menu_keys.exec, key) then
|
||||
exec(cur_menu, sel)
|
||||
elseif util.table.hasitem(menu_keys.back, key) then
|
||||
cur_menu:hide()
|
||||
elseif util.table.hasitem(menu_keys.close, key) then
|
||||
get_parents(cur_menu):hide()
|
||||
else
|
||||
check_access_key(cur_menu, key)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function add_item(data, num, item_info)
|
||||
local item = wibox({
|
||||
fg = data.theme.fg_normal,
|
||||
bg = data.theme.bg_normal,
|
||||
border_color = data.theme.border,
|
||||
border_width = data.theme.border_width
|
||||
})
|
||||
|
||||
-- Create bindings
|
||||
local bindings = util.table.join(
|
||||
button({}, 1, function () item_enter(data, num); exec(data, num) end),
|
||||
button({}, 3, function () data:hide() end)
|
||||
)
|
||||
|
||||
-- Create the item label widget
|
||||
local label = widget({ type = "textbox" })
|
||||
local key = ''
|
||||
label.text = string.gsub(util.escape(item_info[1]), "&(%w)",
|
||||
function (l)
|
||||
key = string.lower(l)
|
||||
return "<u>"..l.."</u>"
|
||||
end, 1)
|
||||
-- Set icon if needed
|
||||
local iconbox
|
||||
if item_info[3] then
|
||||
local icon = type(item_info[3]) == "string" and image(item_info[3]) or item_info[3]
|
||||
if icon.width > data.h or icon.height > data.h then
|
||||
local width, height
|
||||
if ((data.h/icon.height) * icon.width) > data.h then
|
||||
width, height = data.h, (data.h / icon.width) * icon.height
|
||||
else
|
||||
width, height = (data.h / icon.height) * icon.width, data.h
|
||||
end
|
||||
icon = icon:crop_and_scale(0, 0, icon.width, icon.height, width, height)
|
||||
end
|
||||
iconbox = widget { type = "imagebox" }
|
||||
iconbox.image = icon
|
||||
layout.margins[label] = { left = 2 }
|
||||
else
|
||||
layout.margins[label] = { left = data.h + 2 }
|
||||
end
|
||||
|
||||
item:buttons(bindings)
|
||||
|
||||
local mouse_enter_func = function () item_enter(data, num, true) end
|
||||
item:add_signal("mouse::enter", mouse_enter_func)
|
||||
|
||||
-- Create the submenu icon widget
|
||||
local submenu
|
||||
if type(item_info[2]) == "table" then
|
||||
submenu = widget({ type = "imagebox" })
|
||||
submenu.image = data.theme.submenu_icon and image(data.theme.submenu_icon)
|
||||
submenu:buttons(bindings)
|
||||
end
|
||||
|
||||
-- Add widgets to the wibox
|
||||
if iconbox then
|
||||
item.widgets = {
|
||||
iconbox,
|
||||
label,
|
||||
{ submenu, layout = layout.horizontal.rightleft },
|
||||
layout = layout.horizontal.leftright
|
||||
}
|
||||
else
|
||||
item.widgets = {
|
||||
label,
|
||||
{ submenu, layout = layout.horizontal.rightleft },
|
||||
layout = layout.horizontal.leftright
|
||||
}
|
||||
end
|
||||
|
||||
item.height = label:extents().height + 2
|
||||
item.ontop = true
|
||||
|
||||
return { wibox = item, akey= key, cmd = item_info[2], returned_value=item_info[1] }
|
||||
end
|
||||
|
||||
--- Build a popup menu with running clients and shows it.
|
||||
-- @param menu Menu table, see new() function for more informations
|
||||
-- @param args.keygrabber A boolean enabling or not the keyboard navigation.
|
||||
-- @return The menu.
|
||||
function clients(menu, args)
|
||||
local cls = capi.client.get()
|
||||
local cls_t = {}
|
||||
for k, c in pairs(cls) do
|
||||
cls_t[#cls_t + 1] = { util.escape(c.name) or "",
|
||||
function ()
|
||||
if not c:isvisible() then
|
||||
tags.viewmore(c:tags(), c.screen)
|
||||
end
|
||||
capi.client.focus = c
|
||||
c:raise()
|
||||
end,
|
||||
c.icon }
|
||||
end
|
||||
|
||||
if not menu then
|
||||
menu = {}
|
||||
end
|
||||
|
||||
menu.items = cls_t
|
||||
|
||||
local m = new(menu)
|
||||
m:show(args)
|
||||
return m
|
||||
end
|
||||
|
||||
local function set_coords(menu, screen_idx, m_coords)
|
||||
local s_geometry = capi.screen[screen_idx].workarea
|
||||
local screen_w = s_geometry.x + s_geometry.width
|
||||
local screen_h = s_geometry.y + s_geometry.height
|
||||
|
||||
local i_h = menu.h + menu.theme.border_width
|
||||
local m_h = (i_h * #menu.items) + menu.theme.border_width
|
||||
|
||||
if menu.parent then
|
||||
menu.w = menu.parent.w
|
||||
menu.h = menu.parent.h
|
||||
|
||||
local p_w = i_h * (menu.num - 1)
|
||||
local m_w = menu.w - menu.theme.border_width
|
||||
|
||||
menu.y = menu.parent.y + p_w + m_h > screen_h and screen_h - m_h or menu.parent.y + p_w
|
||||
menu.x = menu.parent.x + m_w*2 > screen_w and menu.parent.x - m_w or menu.parent.x + m_w
|
||||
else
|
||||
local m_w = menu.w
|
||||
if m_coords == nil then
|
||||
m_coords = capi.mouse.coords()
|
||||
m_coords.x = m_coords.x + 1
|
||||
m_coords.y = m_coords.y + 1
|
||||
end
|
||||
|
||||
menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y
|
||||
menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x
|
||||
|
||||
menu.y = menu.y + m_h > screen_h and screen_h - m_h or menu.y
|
||||
menu.x = menu.x + m_w > screen_w and screen_w - m_w or menu.x
|
||||
end
|
||||
end
|
||||
|
||||
--- Show a menu.
|
||||
-- @param menu The menu to show.
|
||||
-- @param args.keygrabber A boolean enabling or not the keyboard navigation.
|
||||
-- @param args.coords Menu position defaulting to mouse.coords()
|
||||
function show(menu, args)
|
||||
args = args or {}
|
||||
local screen_index = capi.mouse.screen
|
||||
local keygrabber = args.keygrabber or false
|
||||
local coords = args.coords or nil
|
||||
set_coords(menu, screen_index, coords)
|
||||
for num, item in pairs(menu.items) do
|
||||
local wibox = item.wibox
|
||||
wibox.width = menu.w
|
||||
wibox.height = menu.h
|
||||
wibox.x = menu.x
|
||||
wibox.y = menu.y + (num - 1) * (menu.h + wibox.border_width)
|
||||
wibox.screen = screen_index
|
||||
end
|
||||
|
||||
if menu.parent then
|
||||
menu.keygrabber = menu.parent.keygrabber
|
||||
elseif keygrabber ~= nil then
|
||||
menu.keygrabber = keygrabber
|
||||
else
|
||||
menu.keygrabber = false
|
||||
end
|
||||
|
||||
if not cur_menu and menu.keygrabber then
|
||||
capi.keygrabber.run(grabber)
|
||||
end
|
||||
cur_menu = menu
|
||||
end
|
||||
|
||||
--- Toggle menu visibility.
|
||||
-- @param menu The menu to show if it's hidden, or to hide if it's shown.
|
||||
-- @param args.keygrabber A boolean enabling or not the keyboard navigation.
|
||||
-- @param args.coords Menu position {x,y}
|
||||
function toggle(menu, args)
|
||||
if menu.items[1] and menu.items[1].wibox.screen then
|
||||
menu:hide()
|
||||
else
|
||||
menu:show(args)
|
||||
end
|
||||
end
|
||||
|
||||
--- Open a menu popup.
|
||||
-- @param menu Table containing the menu informations. Key items: Table containing the displayed items, each element is a tab containing: item name, triggered action, submenu table or function, item icon (optional). Keys [fg|bg]_[focus|normal], border, border_width, submenu_icon, height and width override the default display for your menu, each of them are optional. Key auto_expand controls the submenu auto expand behaviour by setting it to true (default) or false.
|
||||
-- @param parent Specify the parent menu if we want to open a submenu, this value should never be set by the user.
|
||||
-- @param num Specify the parent's clicked item number if we want to open a submenu, this value should never be set by the user.
|
||||
function new(menu, parent, num)
|
||||
-- Create a table to store our menu informations
|
||||
local data = {}
|
||||
|
||||
data.items = {}
|
||||
data.num = num or 1
|
||||
data.theme = parent and parent.theme or load_theme(menu)
|
||||
data.parent = parent
|
||||
data.child = {}
|
||||
if parent then
|
||||
data.auto_expand = parent.auto_expand
|
||||
elseif menu.auto_expand ~= nil then
|
||||
data.auto_expand = menu.auto_expand
|
||||
else
|
||||
data.auto_expand = true
|
||||
end
|
||||
data.h = parent and parent.h or data.theme.menu_height
|
||||
if type(data.h) ~= 'number' then data.h = tonumber(data.h) end
|
||||
data.w = parent and parent.w or data.theme.menu_width
|
||||
if type(data.w) ~= 'number' then data.w = tonumber(data.w) end
|
||||
|
||||
-- Create items
|
||||
for k, v in pairs(menu.items) do
|
||||
table.insert(data.items, add_item(data, k, v))
|
||||
end
|
||||
|
||||
if #data.items > 0 and data.h < data.items[1].wibox.height then
|
||||
data.h = data.items[1].wibox.height
|
||||
end
|
||||
|
||||
-- Set methods
|
||||
data.hide = hide
|
||||
data.show = show
|
||||
data.toggle = toggle
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,150 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- @author Sébastien Gross <seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org>
|
||||
-- @copyright 2009 Sébastien Gross
|
||||
-- @release v3.4.9
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
local mouse = mouse
|
||||
local wibox = wibox
|
||||
local screen = screen
|
||||
local timer = timer
|
||||
local a_placement = require("awful.placement")
|
||||
local a_wibox = require("awful.wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local setmetatable = setmetatable
|
||||
|
||||
--- Find the mouse pointer on the screen.
|
||||
-- Mouse finder highlights the mouse cursor on the screen
|
||||
-- <p>To enable this feature, a <code>awful.mouse.finder</code> object needs to
|
||||
-- be bound to a key:<br/>
|
||||
-- <code>mymousefinder = awful.mouse.finder()</code><br/>
|
||||
-- Then bind the <code>find</code> function a key binding.
|
||||
-- <p>Some configuration variable can be set in the theme:<br/>
|
||||
-- The mouse_finder display duration<br/>
|
||||
-- <code>theme.mouse_finder_timeout = 3</code><br/>
|
||||
-- The animation speed<br/>
|
||||
-- <code>theme.mouse_finder_animate_timeout = 0.05</code><br/>
|
||||
-- The mouse_finder radius<br/>
|
||||
-- <code>theme.mouse_finder_radius = 20</code><br/>
|
||||
-- The growth factor<br/>
|
||||
-- <code>theme.mouse_finder_factor = 2</code><br/>
|
||||
-- The mouse_finder color<br/>
|
||||
-- <code>theme.mouse_finder_color = "#ff0000"</code><br/>
|
||||
-- </p>
|
||||
module("awful.mouse.finder")
|
||||
|
||||
-- Mouse finder private data.
|
||||
-- @name data
|
||||
-- @field color Background color.
|
||||
-- @field hide The hide() function.
|
||||
-- @field show The show() function.
|
||||
-- @field timer Timer to hide the mouse finder.
|
||||
-- @field animate_timer Timer to animate the mouse finder.
|
||||
-- @field wibox The mouse finder wibox show on the screen.
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- Place a mouse finder on the screen.
|
||||
-- @param self A mouse finder object.
|
||||
local function place(self)
|
||||
a_placement.under_mouse(data[self].wibox)
|
||||
a_placement.no_offscreen(data[self].wibox)
|
||||
end
|
||||
|
||||
-- Animate a mouse finder.
|
||||
-- @param self A mouse finder object.
|
||||
local function animate(self)
|
||||
local r = data[self].wibox:geometry().width
|
||||
-- Check if the object should be grown or shrinked
|
||||
-- the minimum radius is -data[self].factor because:
|
||||
-- 1. factor is alway negative when shrinking
|
||||
-- 2. geometry() does not hande negative values
|
||||
if data[self].factor > 0 and r >= data[self].radius
|
||||
or data[self].factor < 0 and r <= -data[self].factor then
|
||||
data[self].factor = -data[self].factor
|
||||
end
|
||||
data[self].wibox:geometry({width = r + data[self].factor,
|
||||
height = r + data[self].factor })
|
||||
-- need -1 to the radius to draw a full circle
|
||||
a_wibox.rounded_corners(data[self].wibox, (r + data[self].factor)/2 -1)
|
||||
-- make sure the mouse finder follows the pointer. Uh!
|
||||
place(self)
|
||||
end
|
||||
|
||||
|
||||
-- Show a mouse finder.
|
||||
-- @param self The mouse finder to show.
|
||||
local function show(self)
|
||||
-- do nothing if the mouse finder is already shown
|
||||
if data[self].wibox.visible then return end
|
||||
if not data[self].timer.started then
|
||||
-- make sure the mouse finder is on the same screen as the mouse
|
||||
data[self].wibox.screen = mouse.screen
|
||||
data[self].wibox:geometry({width = data[self].radius, height = data[self].radius })
|
||||
a_wibox.rounded_corners(data[self].wibox, data[self].radius/2 -1)
|
||||
data[self].timer:start()
|
||||
data[self].animate_timer:start()
|
||||
end
|
||||
place(self)
|
||||
data[self].wibox.visible = true
|
||||
end
|
||||
|
||||
-- Hide a mouse finder.
|
||||
-- @param self The mouse finder to hide.
|
||||
local function hide(self)
|
||||
-- do nothing if the mouse finder is already hidden
|
||||
if not data[self].wibox.visible then return end
|
||||
if data[self].timer.started then
|
||||
data[self].timer:stop()
|
||||
data[self].animate_timer:stop()
|
||||
end
|
||||
data[self].wibox.visible = false
|
||||
end
|
||||
|
||||
-- Load Default values.
|
||||
-- @param self A mouse finder object.
|
||||
local function set_defaults(self)
|
||||
data[self].wibox.border_width = 0
|
||||
data[self].wibox.opacity = beautiful.mouse_finder_opacity or 1
|
||||
data[self].wibox.bg = beautiful.mouse_finder_color or beautiful.bg_focus or "#ff0000"
|
||||
data[self].timeout = beautiful.mouse_finder_timeout or 3
|
||||
data[self].animate_timeout = beautiful.mouse_finder_animate_timeout or 0.05
|
||||
data[self].radius = beautiful.mouse_finder_radius or 20
|
||||
data[self].factor = beautiful.mouse_finder_factor or 2
|
||||
end
|
||||
|
||||
--- Find the mouse on the screen
|
||||
-- @param self A mouse finder object.
|
||||
function find(self)
|
||||
show(self)
|
||||
end
|
||||
|
||||
--- Create a new mouse finder.
|
||||
local function new()
|
||||
local self = { }
|
||||
-- private data
|
||||
data[self] = {
|
||||
wibox = wibox({ }),
|
||||
show = function() show(self) end,
|
||||
hide = function() hide(self) end,
|
||||
animate = function() animate(self) end,
|
||||
}
|
||||
|
||||
-- export functions
|
||||
self.find = find
|
||||
|
||||
set_defaults(self)
|
||||
|
||||
-- setup the timer action only if needed
|
||||
data[self].timer = timer { timeout = data[self].timeout }
|
||||
data[self].animate_timer = timer { timeout = data[self].animate_timeout }
|
||||
data[self].timer:add_signal("timeout", data[self].hide)
|
||||
data[self].animate_timer:add_signal("timeout", data[self].animate)
|
||||
data[self].wibox.ontop = true
|
||||
data[self].wibox.visible = false
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: ft=lua:et:sw=4:ts=4:sts=4:enc=utf-8:tw=78
|
@ -0,0 +1,581 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local layout = require("awful.layout")
|
||||
local tag = require("awful.tag")
|
||||
local aclient = require("awful.client")
|
||||
local widget = require("awful.widget")
|
||||
local awibox = require("awful.wibox")
|
||||
local util = require("awful.util")
|
||||
local type = type
|
||||
local math = math
|
||||
local ipairs = ipairs
|
||||
local capi =
|
||||
{
|
||||
root = root,
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
client = client,
|
||||
mousegrabber = mousegrabber,
|
||||
}
|
||||
|
||||
require("awful.mouse.finder")
|
||||
|
||||
--- Mouse module for awful
|
||||
module("awful.mouse")
|
||||
|
||||
client = {}
|
||||
wibox = {}
|
||||
|
||||
--- Get the client object under the pointer.
|
||||
-- @return The client object under the pointer, if one can be found.
|
||||
function client_under_pointer()
|
||||
local obj = capi.mouse.object_under_pointer()
|
||||
if type(obj) == "client" then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the wibox object under the pointer.
|
||||
-- @return The wibox object under the pointer, if one can be found.
|
||||
function wibox_under_pointer()
|
||||
local obj = capi.mouse.object_under_pointer()
|
||||
if type(obj) == "wibox" then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the widget under the pointer.
|
||||
-- @return The widget object under the pointer, if it can be found.
|
||||
function widget_under_pointer()
|
||||
local obj, obj2 = capi.mouse.object_under_pointer()
|
||||
if type(obj2) == "widget" then
|
||||
return obj2
|
||||
end
|
||||
end
|
||||
|
||||
local function snap_outside(g, sg, snap)
|
||||
if g.x < snap + sg.x + sg.width and g.x > sg.x + sg.width then
|
||||
g.x = sg.x + sg.width
|
||||
elseif g.x + g.width < sg.x and g.x + g.width > sg.x - snap then
|
||||
g.x = sg.x - g.width
|
||||
end
|
||||
if g.y < snap + sg.y + sg.height and g.y > sg.y + sg.height then
|
||||
g.y = sg.y + sg.height
|
||||
elseif g.y + g.height < sg.y and g.y + g.height > sg.y - snap then
|
||||
g.y = sg.y - g.height
|
||||
end
|
||||
return g
|
||||
end
|
||||
|
||||
local function snap_inside(g, sg, snap)
|
||||
local edgev = 'none'
|
||||
local edgeh = 'none'
|
||||
if math.abs(g.x) < snap + sg.x and g.x > sg.x then
|
||||
edgev = 'left'
|
||||
g.x = sg.x
|
||||
elseif math.abs((sg.x + sg.width) - (g.x + g.width)) < snap then
|
||||
edgev = 'right'
|
||||
g.x = sg.x + sg.width - g.width
|
||||
end
|
||||
if math.abs(g.y) < snap + sg.y and g.y > sg.y then
|
||||
edgeh = 'top'
|
||||
g.y = sg.y
|
||||
elseif math.abs((sg.y + sg.height) - (g.y + g.height)) < snap then
|
||||
edgeh = 'bottom'
|
||||
g.y = sg.y + sg.height - g.height
|
||||
end
|
||||
|
||||
-- What is the dominant dimension?
|
||||
if g.width > g.height then
|
||||
return g, edgeh
|
||||
else
|
||||
return g, edgev
|
||||
end
|
||||
end
|
||||
|
||||
--- Snap a client to the closest client or screen edge.
|
||||
-- @param c The client to snap.
|
||||
-- @param snap The pixel to snap clients.
|
||||
-- @param x The client x coordinate.
|
||||
-- @param y The client y coordinate.
|
||||
-- @param fixed_x True if the client isn't allowed to move in the x direction.
|
||||
-- @param fixed_y True if the client isn't allowed to move in the y direction.
|
||||
function client.snap(c, snap, x, y, fixed_x, fixed_y)
|
||||
local snap = snap or 8
|
||||
local c = c or client.focus
|
||||
local cur_geom = c:geometry()
|
||||
local geom = c:geometry()
|
||||
local edge = "none"
|
||||
local edge2 = "none"
|
||||
geom.x = x or geom.x
|
||||
geom.y = y or geom.y
|
||||
|
||||
geom, edge = snap_inside(geom, capi.screen[c.screen].geometry, snap)
|
||||
geom = snap_inside(geom, capi.screen[c.screen].workarea, snap)
|
||||
|
||||
-- Allow certain windows to snap to the edge of the workarea.
|
||||
-- Only allow docking to workarea for consistency/to avoid problems.
|
||||
if aclient.dockable.get(c) then
|
||||
local struts = c:struts()
|
||||
struts['left'] = 0
|
||||
struts['right'] = 0
|
||||
struts['top'] = 0
|
||||
struts['bottom'] = 0
|
||||
if edge ~= "none" and aclient.floating.get(c) then
|
||||
if edge == "left" or edge == "right" then
|
||||
struts[edge] = cur_geom.width
|
||||
elseif edge == "top" or edge == "bottom" then
|
||||
struts[edge] = cur_geom.height
|
||||
end
|
||||
end
|
||||
c:struts(struts)
|
||||
end
|
||||
|
||||
for k, snapper in ipairs(aclient.visible(c.screen)) do
|
||||
if snapper ~= c then
|
||||
geom = snap_outside(geom, snapper:geometry(), snap)
|
||||
end
|
||||
end
|
||||
|
||||
-- It's easiest to undo changes afterwards if they're not allowed
|
||||
if fixed_x then geom.x = cur_geom.x end
|
||||
if fixed_y then geom.y = cur_geom.y end
|
||||
|
||||
return geom
|
||||
end
|
||||
|
||||
--- Move a client.
|
||||
-- @param c The client to move, or the focused one if nil.
|
||||
-- @param snap The pixel to snap clients.
|
||||
function client.move(c, snap)
|
||||
local c = c or capi.client.focus
|
||||
|
||||
if not c
|
||||
or c.fullscreen
|
||||
or c.type == "desktop"
|
||||
or c.type == "splash"
|
||||
or c.type == "dock" then
|
||||
return
|
||||
end
|
||||
|
||||
c:raise()
|
||||
|
||||
local orig = c:geometry()
|
||||
local m_c = capi.mouse.coords()
|
||||
local dist_x = m_c.x - orig.x
|
||||
local dist_y = m_c.y - orig.y
|
||||
-- Only allow moving in the non-maximized directions
|
||||
local fixed_x = c.maximized_horizontal
|
||||
local fixed_y = c.maximized_vertical
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
local lay = layout.get(c.screen)
|
||||
if lay == layout.suit.floating or aclient.floating.get(c) then
|
||||
local x = mouse.x - dist_x
|
||||
local y = mouse.y - dist_y
|
||||
c:geometry(client.snap(c, snap, x, y, fixed_x, fixed_y))
|
||||
elseif lay ~= layout.suit.magnifier then
|
||||
-- Only move the client to the mouse
|
||||
-- screen if the target screen is not
|
||||
-- floating.
|
||||
-- Otherwise, we move if via geometry.
|
||||
if layout.get(capi.mouse.screen) == layout.suit.floating then
|
||||
local x = mouse.x - dist_x
|
||||
local y = mouse.y - dist_y
|
||||
c:geometry(client.snap(c, snap, x, y, fixed_x, fixed_y))
|
||||
else
|
||||
c.screen = capi.mouse.screen
|
||||
end
|
||||
if layout.get(c.screen) ~= layout.suit.floating then
|
||||
local c_u_m = client_under_pointer()
|
||||
if c_u_m and not aclient.floating.get(c_u_m) then
|
||||
if c_u_m ~= c then
|
||||
c:swap(c_u_m)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
client.dragtotag = { }
|
||||
|
||||
--- Move a client to a tag by drag'n'dropping it over a taglist widget
|
||||
-- @param c The client to move
|
||||
function client.dragtotag.widget(c)
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
local button_down = false
|
||||
for _, v in ipairs(mouse.buttons) do
|
||||
if v then button_down = true end
|
||||
end
|
||||
if not button_down then
|
||||
local w = widget_under_pointer()
|
||||
if w and widget.taglist.gettag(w) then
|
||||
local t = widget.taglist.gettag(w)
|
||||
if t.screen ~= c.screen then
|
||||
aclient.movetoscreen(c, t.screen)
|
||||
end
|
||||
aclient.movetotag(t, c)
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
--- Move a client to a tag by dragging it onto the left / right side of the screen
|
||||
-- @param c The client to move
|
||||
function client.dragtotag.border(c)
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
local button_down = false
|
||||
for _, v in ipairs(mouse.buttons) do
|
||||
if v then button_down = true end
|
||||
end
|
||||
local wa = capi.screen[c.screen].workarea
|
||||
if mouse.x >= wa.x + wa.width then
|
||||
capi.mouse.coords({ x = wa.x + wa.width - 1 })
|
||||
elseif mouse.x <= wa.x then
|
||||
capi.mouse.coords({ x = wa.x + 1 })
|
||||
end
|
||||
if not button_down then
|
||||
local tags = capi.screen[c.screen]:tags()
|
||||
local t = tag.selected()
|
||||
local idx
|
||||
for i, v in ipairs(tags) do
|
||||
if v == t then
|
||||
idx = i
|
||||
end
|
||||
end
|
||||
if mouse.x > wa.x + wa.width - 10 then
|
||||
local newtag = tags[util.cycle(#tags, idx + 1)]
|
||||
aclient.movetotag(newtag, c)
|
||||
tag.viewnext()
|
||||
elseif mouse.x < wa.x + 10 then
|
||||
local newtag = tags[util.cycle(#tags, idx - 1)]
|
||||
aclient.movetotag(newtag, c)
|
||||
tag.viewprev()
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
--- Move the wibox under the cursor
|
||||
--@param w The wibox to move, or none to use that under the pointer
|
||||
function wibox.move(w)
|
||||
local w = w or wibox_under_pointer()
|
||||
if not w then return end
|
||||
|
||||
local offset = {
|
||||
x = w.x - capi.mouse.coords().x,
|
||||
y = w.y - capi.mouse.coords().y
|
||||
}
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
local button_down = false
|
||||
if awibox.get_position(w) == "floating" then
|
||||
w.x = capi.mouse.coords().x + offset.x
|
||||
w.y = capi.mouse.coords().y + offset.y
|
||||
else
|
||||
local wa = capi.screen[capi.mouse.screen].workarea
|
||||
|
||||
if capi.mouse.coords()["y"] > wa.y + wa.height - 10 then
|
||||
awibox.set_position(w, "bottom", w.screen)
|
||||
elseif capi.mouse.coords()["y"] < wa.y + 10 then
|
||||
awibox.set_position(w, "top", w.screen)
|
||||
elseif capi.mouse.coords()["x"] > wa.x + wa.width - 10 then
|
||||
awibox.set_position(w, "right", w.screen)
|
||||
elseif capi.mouse.coords()["x"] < wa.x + 10 then
|
||||
awibox.set_position(w, "left", w.screen)
|
||||
end
|
||||
w.screen = capi.mouse.screen
|
||||
end
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then button_down = true end
|
||||
end
|
||||
if not button_down then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
--- Get a client corner coordinates.
|
||||
-- @param c The client to get corner from, focused one by default.
|
||||
-- @param corner The corner to use: auto, top_left, top_right, bottom_left,
|
||||
-- bottom_right. Default is auto, and auto find the nearest corner.
|
||||
-- @return Actual used corner and x and y coordinates.
|
||||
function client.corner(c, corner)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
|
||||
local g = c:geometry()
|
||||
|
||||
if not corner or corner == "auto" then
|
||||
local m_c = capi.mouse.coords()
|
||||
if math.abs(g.y - m_c.y) < math.abs(g.y + g.height - m_c.y) then
|
||||
if math.abs(g.x - m_c.x) < math.abs(g.x + g.width - m_c.x) then
|
||||
corner = "top_left"
|
||||
else
|
||||
corner = "top_right"
|
||||
end
|
||||
else
|
||||
if math.abs(g.x - m_c.x) < math.abs(g.x + g.width - m_c.x) then
|
||||
corner = "bottom_left"
|
||||
else
|
||||
corner = "bottom_right"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local x, y
|
||||
if corner == "top_right" then
|
||||
x = g.x + g.width
|
||||
y = g.y
|
||||
elseif corner == "top_left" then
|
||||
x = g.x
|
||||
y = g.y
|
||||
elseif corner == "bottom_left" then
|
||||
x = g.x
|
||||
y = g.y + g.height
|
||||
else
|
||||
x = g.x + g.width
|
||||
y = g.y + g.height
|
||||
end
|
||||
|
||||
return corner, x, y
|
||||
end
|
||||
|
||||
local function client_resize_magnifier(c, corner)
|
||||
local corner, x, y = client.corner(c, corner)
|
||||
capi.mouse.coords({ x = x, y = y })
|
||||
|
||||
local wa = capi.screen[c.screen].workarea
|
||||
local center_x = wa.x + wa.width / 2
|
||||
local center_y = wa.y + wa.height / 2
|
||||
local maxdist_pow = (wa.width^2 + wa.height^2) / 4
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
local dx = center_x - mouse.x
|
||||
local dy = center_y - mouse.y
|
||||
local dist = dx^2 + dy^2
|
||||
|
||||
-- New master width factor
|
||||
local mwfact = dist / maxdist_pow
|
||||
tag.setmwfact(math.min(math.max(0.01, mwfact), 0.99), tag.selected(c.screen))
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, corner .. "_corner")
|
||||
end
|
||||
|
||||
local function client_resize_tiled(c, lay)
|
||||
local wa = capi.screen[c.screen].workarea
|
||||
local mwfact = tag.getmwfact()
|
||||
local cursor
|
||||
local g = c:geometry()
|
||||
local offset = 0
|
||||
local x,y
|
||||
if lay == layout.suit.tile then
|
||||
cursor = "cross"
|
||||
if g.height+15 > wa.height then
|
||||
offset = g.height * .5
|
||||
cursor = "sb_h_double_arrow"
|
||||
elseif not (g.y+g.height+15 > wa.y+wa.height) then
|
||||
offset = g.height
|
||||
end
|
||||
capi.mouse.coords({ x = wa.x + wa.width * mwfact, y = g.y + offset })
|
||||
elseif lay == layout.suit.tile.left then
|
||||
cursor = "cross"
|
||||
if g.height+15 >= wa.height then
|
||||
offset = g.height * .5
|
||||
cursor = "sb_h_double_arrow"
|
||||
elseif not (g.y+g.height+15 > wa.y+wa.height) then
|
||||
offset = g.height
|
||||
end
|
||||
capi.mouse.coords({ x = wa.x + wa.width * (1 - mwfact), y = g.y + offset })
|
||||
elseif lay == layout.suit.tile.bottom then
|
||||
cursor = "cross"
|
||||
if g.width+15 >= wa.width then
|
||||
offset = g.width * .5
|
||||
cursor = "sb_v_double_arrow"
|
||||
elseif not (g.x+g.width+15 > wa.x+wa.width) then
|
||||
offset = g.width
|
||||
end
|
||||
capi.mouse.coords({ y = wa.y + wa.height * mwfact, x = g.x + offset})
|
||||
else
|
||||
cursor = "cross"
|
||||
if g.width+15 >= wa.width then
|
||||
offset = g.width * .5
|
||||
cursor = "sb_v_double_arrow"
|
||||
elseif not (g.x+g.width+15 > wa.x+wa.width) then
|
||||
offset = g.width
|
||||
end
|
||||
capi.mouse.coords({ y = wa.y + wa.height * (1 - mwfact), x= g.x + offset })
|
||||
end
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
local fact_x = (mouse.x - wa.x) / wa.width
|
||||
local fact_y = (mouse.y - wa.y) / wa.height
|
||||
local mwfact
|
||||
|
||||
local g = c:geometry()
|
||||
|
||||
|
||||
-- we have to make sure we're not on the last visible client where we have to use different settings.
|
||||
local wfact
|
||||
local wfact_x, wfact_y
|
||||
if (g.y+g.height+15) > (wa.y+wa.height) then
|
||||
wfact_y = (g.y + g.height - mouse.y) / wa.height
|
||||
else
|
||||
wfact_y = (mouse.y - g.y) / wa.height
|
||||
end
|
||||
|
||||
if (g.x+g.width+15) > (wa.x+wa.width) then
|
||||
wfact_x = (g.x + g.width - mouse.x) / wa.width
|
||||
else
|
||||
wfact_x = (mouse.x - g.x) / wa.width
|
||||
end
|
||||
|
||||
|
||||
if lay == layout.suit.tile then
|
||||
mwfact = fact_x
|
||||
wfact = wfact_y
|
||||
elseif lay == layout.suit.tile.left then
|
||||
mwfact = 1 - fact_x
|
||||
wfact = wfact_y
|
||||
elseif lay == layout.suit.tile.bottom then
|
||||
mwfact = fact_y
|
||||
wfact = wfact_x
|
||||
else
|
||||
mwfact = 1 - fact_y
|
||||
wfact = wfact_x
|
||||
end
|
||||
|
||||
tag.setmwfact(math.min(math.max(mwfact, 0.01), 0.99), tag.selected(c.screen))
|
||||
aclient.setwfact(math.min(math.max(wfact,0.01), 0.99), c)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, cursor)
|
||||
end
|
||||
|
||||
local function client_resize_floating(c, corner, fixed_x, fixed_y)
|
||||
local corner, x, y = client.corner(c, corner)
|
||||
local g = c:geometry()
|
||||
|
||||
-- Warp mouse pointer
|
||||
capi.mouse.coords({ x = x, y = y })
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
-- Ignore screen changes
|
||||
if not aclient.floating.get(c)
|
||||
and capi.mouse.screen ~= c.screen then
|
||||
return true
|
||||
end
|
||||
|
||||
local ng
|
||||
if corner == "bottom_right" then
|
||||
ng = { width = mouse.x - g.x,
|
||||
height = mouse.y - g.y }
|
||||
elseif corner == "bottom_left" then
|
||||
ng = { x = mouse.x,
|
||||
width = (g.x + g.width) - mouse.x,
|
||||
height = mouse.y - g.y }
|
||||
elseif corner == "top_left" then
|
||||
ng = { x = mouse.x,
|
||||
width = (g.x + g.width) - mouse.x,
|
||||
y = mouse.y,
|
||||
height = (g.y + g.height) - mouse.y }
|
||||
else
|
||||
ng = { width = mouse.x - g.x,
|
||||
y = mouse.y,
|
||||
height = (g.y + g.height) - mouse.y }
|
||||
end
|
||||
if ng.width <= 0 then ng.width = nil end
|
||||
if ng.height <= 0 then ng.height = nil end
|
||||
if fixed_x then ng.width = g.width ng.x = g.x end
|
||||
if fixed_y then ng.height = g.height ng.y = g.y end
|
||||
c:geometry(ng)
|
||||
-- Get real geometry that has been applied
|
||||
-- in case we honor size hints
|
||||
-- XXX: This should be rewritten when size
|
||||
-- hints are available from Lua.
|
||||
local rg = c:geometry()
|
||||
|
||||
if corner == "bottom_right" then
|
||||
ng = {}
|
||||
elseif corner == "bottom_left" then
|
||||
ng = { x = (g.x + g.width) - rg.width }
|
||||
elseif corner == "top_left" then
|
||||
ng = { x = (g.x + g.width) - rg.width,
|
||||
y = (g.y + g.height) - rg.height }
|
||||
else
|
||||
ng = { y = (g.y + g.height) - rg.height }
|
||||
end
|
||||
c:geometry({ x = ng.x, y = ng.y })
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, corner .. "_corner")
|
||||
end
|
||||
|
||||
--- Resize a client.
|
||||
-- @param c The client to resize, or the focused one by default.
|
||||
-- @param corner The corner to grab on resize. Auto detected by default.
|
||||
function client.resize(c, corner)
|
||||
local c = c or capi.client.focus
|
||||
|
||||
if not c then return end
|
||||
|
||||
if c.fullscreen
|
||||
or c.type == "desktop"
|
||||
or c.type == "splash"
|
||||
or c.type == "dock" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Do not allow maximized clients to be resized by mouse
|
||||
local fixed_x = c.maximized_horizontal
|
||||
local fixed_y = c.maximized_vertical
|
||||
|
||||
local lay = layout.get(c.screen)
|
||||
|
||||
if lay == layout.suit.floating or aclient.floating.get(c) then
|
||||
return client_resize_floating(c, corner, fixed_x, fixed_y)
|
||||
elseif lay == layout.suit.tile
|
||||
or lay == layout.suit.tile.left
|
||||
or lay == layout.suit.tile.top
|
||||
or lay == layout.suit.tile.bottom
|
||||
then
|
||||
return client_resize_tiled(c, lay)
|
||||
elseif lay == layout.suit.magnifier then
|
||||
return client_resize_magnifier(c, corner)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the cursor at startup
|
||||
capi.root.cursor("left_ptr")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
229
Old/ATARI/home/burchettm/.config/awesome/lib/awful/placement.lua
Normal file
229
Old/ATARI/home/burchettm/.config/awesome/lib/awful/placement.lua
Normal file
@ -0,0 +1,229 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local math = math
|
||||
local table = table
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
mouse = mouse,
|
||||
client = client
|
||||
}
|
||||
local client = require("awful.client")
|
||||
local layout = require("awful.layout")
|
||||
|
||||
--- Places client according to special criteria.
|
||||
module("awful.placement")
|
||||
|
||||
-- Check if an area intersect another area.
|
||||
-- @param a The area.
|
||||
-- @param b The other area.
|
||||
-- @return True if they intersect, false otherwise.
|
||||
local function area_intersect_area(a, b)
|
||||
return (b.x < a.x + a.width
|
||||
and b.x + b.width > a.x
|
||||
and b.y < a.y + a.height
|
||||
and b.y + b.height > a.y)
|
||||
end
|
||||
|
||||
-- Get the intersect area between a and b.
|
||||
-- @param a The area.
|
||||
-- @param b The other area.
|
||||
-- @return The intersect area.
|
||||
local function area_intersect_area_get(a, b)
|
||||
local g = {}
|
||||
g.x = math.max(a.x, b.x)
|
||||
g.y = math.max(a.y, b.y)
|
||||
g.width = math.min(a.x + a.width, b.x + b.width) - g.x
|
||||
g.height = math.min(a.y + a.height, b.y + b.height) - g.y
|
||||
return g
|
||||
end
|
||||
|
||||
-- Remove an area from a list, splitting the space between several area that
|
||||
-- can overlap.
|
||||
-- @param areas Table of areas.
|
||||
-- @param elem Area to remove.
|
||||
-- @return The new area list.
|
||||
local function area_remove(areas, elem)
|
||||
for i = #areas, 1, -1 do
|
||||
-- Check if the 'elem' intersect
|
||||
if area_intersect_area(areas[i], elem) then
|
||||
-- It does? remove it
|
||||
local r = table.remove(areas, i)
|
||||
local inter = area_intersect_area_get(r, elem)
|
||||
|
||||
if inter.x > r.x then
|
||||
table.insert(areas, {
|
||||
x = r.x,
|
||||
y = r.y,
|
||||
width = inter.x - r.x,
|
||||
height = r.height
|
||||
})
|
||||
end
|
||||
|
||||
if inter.y > r.y then
|
||||
table.insert(areas, {
|
||||
x = r.x,
|
||||
y = r.y,
|
||||
width = r.width,
|
||||
height = inter.y - r.y
|
||||
})
|
||||
end
|
||||
|
||||
if inter.x + inter.width < r.x + r.width then
|
||||
table.insert(areas, {
|
||||
x = inter.x + inter.width,
|
||||
y = r.y,
|
||||
width = (r.x + r.width) - (inter.x + inter.width),
|
||||
height = r.height
|
||||
})
|
||||
end
|
||||
|
||||
if inter.y + inter.height < r.y + r.height then
|
||||
table.insert(areas, {
|
||||
x = r.x,
|
||||
y = inter.y + inter.height,
|
||||
width = r.width,
|
||||
height = (r.y + r.height) - (inter.y + inter.height)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return areas
|
||||
end
|
||||
|
||||
--- Place the client so no part of it will be outside the screen.
|
||||
-- @param c The client.
|
||||
-- @return The new client geometry.
|
||||
function no_offscreen(c)
|
||||
local c = c or capi.client.focus
|
||||
local geometry = c:geometry()
|
||||
local border = c.border_width
|
||||
local screen_geometry = capi.screen[c.screen].workarea
|
||||
|
||||
if geometry.x + geometry.width + 2*border > screen_geometry.x + screen_geometry.width then
|
||||
geometry.x = screen_geometry.x + screen_geometry.width - geometry.width
|
||||
elseif geometry.x < screen_geometry.x then
|
||||
geometry.x = screen_geometry.x
|
||||
end
|
||||
|
||||
if geometry.y + geometry.height + border > screen_geometry.y + screen_geometry.height then
|
||||
geometry.y = screen_geometry.y + screen_geometry.height - geometry.height
|
||||
elseif geometry.y < screen_geometry.y then
|
||||
geometry.y = screen_geometry.y
|
||||
end
|
||||
|
||||
c:geometry(geometry)
|
||||
end
|
||||
|
||||
--- Place the client where there's place available with minimum overlap.
|
||||
-- @param c The client.
|
||||
function no_overlap(c)
|
||||
local cls = client.visible(c.screen)
|
||||
local curlay = layout.get()
|
||||
local areas = { capi.screen[c.screen].workarea }
|
||||
local geometry = c:geometry()
|
||||
for i, cl in pairs(cls) do
|
||||
if cl ~= c and cl.type ~= "desktop" and (client.floating.get(cl) or curlay == layout.suit.floating) then
|
||||
areas = area_remove(areas, cl:geometry())
|
||||
end
|
||||
end
|
||||
|
||||
-- Look for available space
|
||||
local found = false
|
||||
local new = { x = geometry.x, y = geometry.y, width = 0, height = 0 }
|
||||
for i, r in ipairs(areas) do
|
||||
if r.width >= geometry.width
|
||||
and r.height >= geometry.height
|
||||
and r.width * r.height > new.width * new.height then
|
||||
found = true
|
||||
new = r
|
||||
end
|
||||
end
|
||||
|
||||
-- We did not foudn an area with enough space for our size:
|
||||
-- just take the biggest available one and go in
|
||||
if not found then
|
||||
for i, r in ipairs(areas) do
|
||||
if r.width * r.height > new.width * new.height then
|
||||
new = r
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Restore height and width
|
||||
new.width = geometry.width
|
||||
new.height = geometry.height
|
||||
|
||||
return c:geometry(new)
|
||||
end
|
||||
|
||||
--- Place the client under the mouse.
|
||||
-- @param c The client.
|
||||
-- @return The new client geometry.
|
||||
function under_mouse(c)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local m_coords = capi.mouse.coords()
|
||||
return c:geometry({ x = m_coords.x - c_geometry.width / 2,
|
||||
y = m_coords.y - c_geometry.height / 2 })
|
||||
end
|
||||
|
||||
--- Place the client centered with respect to a parent or the clients screen.
|
||||
-- @param c The client.
|
||||
-- @param p The parent (optional, nil for screen centering).
|
||||
-- @return The new client geometry.
|
||||
function centered(c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[c.screen].geometry
|
||||
end
|
||||
return c:geometry({ x = s_geometry.x + (s_geometry.width - c_geometry.width) / 2,
|
||||
y = s_geometry.y + (s_geometry.height - c_geometry.height) / 2 })
|
||||
end
|
||||
|
||||
--- Place the client centered on the horizontal axis with respect to a parent or the clients screen.
|
||||
-- @param c The client.
|
||||
-- @param p The parent (optional, nil for screen centering).
|
||||
-- @return The new client geometry.
|
||||
function center_horizontal(c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[c.screen].geometry
|
||||
end
|
||||
return c:geometry({ x = s_geometry.x + (s_geometry.width - c_geometry.width) / 2 })
|
||||
end
|
||||
|
||||
--- Place the client centered on the vertical axis with respect to a parent or the clients screen.
|
||||
-- @param c The client.
|
||||
-- @param p The parent (optional, nil for screen centering).
|
||||
-- @return The new client geometry.
|
||||
function center_vertical(c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[c.screen].geometry
|
||||
end
|
||||
return c:geometry({ y = s_geometry.y + (s_geometry.height - c_geometry.height) / 2 })
|
||||
end
|
||||
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
381
Old/ATARI/home/burchettm/.config/awesome/lib/awful/prompt.lua
Normal file
381
Old/ATARI/home/burchettm/.config/awesome/lib/awful/prompt.lua
Normal file
@ -0,0 +1,381 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local assert = assert
|
||||
local io = io
|
||||
local table = table
|
||||
local math = math
|
||||
local ipairs = ipairs
|
||||
local pcall = pcall
|
||||
local capi =
|
||||
{
|
||||
keygrabber = keygrabber,
|
||||
selection = selection
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local beautiful = require("beautiful")
|
||||
|
||||
--- Prompt module for awful
|
||||
module("awful.prompt")
|
||||
|
||||
--- Private data
|
||||
local data = {}
|
||||
data.history = {}
|
||||
|
||||
-- Load history file in history table
|
||||
-- @param id The data.history identifier which is the path to the filename
|
||||
-- @param max Optional parameter, the maximum number of entries in file
|
||||
local function history_check_load(id, max)
|
||||
if id and id ~= ""
|
||||
and not data.history[id] then
|
||||
data.history[id] = { max = 50, table = {} }
|
||||
|
||||
if max then
|
||||
data.history[id].max = max
|
||||
end
|
||||
|
||||
local f = io.open(id, "r")
|
||||
|
||||
-- Read history file
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(data.history[id].table, line)
|
||||
if #data.history[id].table >= data.history[id].max then
|
||||
break
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save history table in history file
|
||||
-- @param id The data.history identifier
|
||||
local function history_save(id)
|
||||
if data.history[id] then
|
||||
local f = io.open(id, "w")
|
||||
if not f then
|
||||
local i = 0
|
||||
for d in id:gmatch(".-/") do
|
||||
i = i + #d
|
||||
end
|
||||
util.mkdir(id:sub(1, i - 1))
|
||||
f = assert(io.open(id, "w"))
|
||||
end
|
||||
for i = 1, math.min(#data.history[id].table, data.history[id].max) do
|
||||
f:write(data.history[id].table[i] .. "\n")
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- Return the number of items in history table regarding the id
|
||||
-- @param id The data.history identifier
|
||||
-- @return the number of items in history table, -1 if history is disabled
|
||||
local function history_items(id)
|
||||
if data.history[id] then
|
||||
return #data.history[id].table
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
-- Add an entry to the history file
|
||||
-- @param id The data.history identifier
|
||||
-- @param command The command to add
|
||||
local function history_add(id, command)
|
||||
if data.history[id] then
|
||||
if command ~= ""
|
||||
and command ~= data.history[id].table[#data.history[id].table] then
|
||||
table.insert(data.history[id].table, command)
|
||||
|
||||
-- Do not exceed our max_cmd
|
||||
if #data.history[id].table > data.history[id].max then
|
||||
table.remove(data.history[id].table, 1)
|
||||
end
|
||||
|
||||
history_save(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Draw the prompt text with a cursor.
|
||||
-- @param args The table of arguments.
|
||||
-- @param text The text.
|
||||
-- @param font The font.
|
||||
-- @param prompt The text prefix.
|
||||
-- @param text_color The text color.
|
||||
-- @param cursor_color The cursor color.
|
||||
-- @param cursor_pos The cursor position.
|
||||
-- @param cursor_ul The cursor underline style.
|
||||
-- @param selectall If true cursor is rendered on the entire text.
|
||||
local function prompt_text_with_cursor(args)
|
||||
local char, spacer, text_start, text_end, ret
|
||||
local text = args.text or ""
|
||||
local prompt = args.prompt or ""
|
||||
local underline = args.cursor_ul or "none"
|
||||
|
||||
if args.selectall then
|
||||
if #text == 0 then char = " " else char = util.escape(text) end
|
||||
spacer = " "
|
||||
text_start = ""
|
||||
text_end = ""
|
||||
elseif #text < args.cursor_pos then
|
||||
char = " "
|
||||
spacer = ""
|
||||
text_start = util.escape(text)
|
||||
text_end = ""
|
||||
else
|
||||
char = util.escape(text:sub(args.cursor_pos, args.cursor_pos))
|
||||
spacer = " "
|
||||
text_start = util.escape(text:sub(1, args.cursor_pos - 1))
|
||||
text_end = util.escape(text:sub(args.cursor_pos + 1))
|
||||
end
|
||||
|
||||
ret = prompt .. text_start .. "<span background=\"" .. util.color_strip_alpha(args.cursor_color) .. "\" foreground=\"" .. util.color_strip_alpha(args.text_color) .. "\" underline=\"" .. underline .. "\">" .. char .. "</span>" .. text_end .. spacer
|
||||
if args.font then ret = "<span font_desc='" .. args.font .. "'>" .. ret .. "</span>" end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Run a prompt in a box.
|
||||
-- @param args A table with optional arguments: fg_cursor, bg_cursor, ul_cursor, prompt, text, selectall, font, autoexec.
|
||||
-- @param textbox The textbox to use for the prompt.
|
||||
-- @param exe_callback The callback function to call with command as argument when finished.
|
||||
-- @param completion_callback The callback function to call to get completion.
|
||||
-- @param history_path Optional parameter: file path where the history should be saved, set nil to disable history
|
||||
-- @param history_max Optional parameter: set the maximum entries in history file, 50 by default
|
||||
-- @param done_callback Optional parameter: the callback function to always call without arguments, regardless of whether the prompt was cancelled.
|
||||
function run(args, textbox, exe_callback, completion_callback, history_path, history_max, done_callback)
|
||||
local theme = beautiful.get()
|
||||
if not args then args = {} end
|
||||
local command = args.text or ""
|
||||
local command_before_comp
|
||||
local cur_pos_before_comp
|
||||
local prettyprompt = args.prompt or ""
|
||||
local inv_col = args.fg_cursor or theme.fg_focus or "black"
|
||||
local cur_col = args.bg_cursor or theme.bg_focus or "white"
|
||||
local cur_ul = args.ul_cursor
|
||||
local text = args.text or ""
|
||||
local font = args.font or theme.font
|
||||
local selectall = args.selectall
|
||||
|
||||
history_check_load(history_path, history_max)
|
||||
local history_index = history_items(history_path) + 1
|
||||
-- The cursor position
|
||||
local cur_pos = (selectall and 1) or text:wlen() + 1
|
||||
-- The completion element to use on completion request.
|
||||
local ncomp = 1
|
||||
if not textbox or not exe_callback then
|
||||
return
|
||||
end
|
||||
textbox.text = prompt_text_with_cursor{
|
||||
text = text, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
font = font, prompt = prettyprompt }
|
||||
|
||||
local exec = function()
|
||||
textbox.text = ""
|
||||
history_add(history_path, command)
|
||||
capi.keygrabber.stop()
|
||||
exe_callback(command)
|
||||
if done_callback then done_callback() end
|
||||
end
|
||||
|
||||
capi.keygrabber.run(
|
||||
function (modifiers, key, event)
|
||||
if event ~= "press" then return true end
|
||||
-- Convert index array to hash table
|
||||
local mod = {}
|
||||
for k, v in ipairs(modifiers) do mod[v] = true end
|
||||
-- Get out cases
|
||||
if (mod.Control and (key == "c" or key == "g"))
|
||||
or (not mod.Control and key == "Escape") then
|
||||
textbox.text = ""
|
||||
if done_callback then done_callback() end
|
||||
return false
|
||||
elseif (mod.Control and (key == "j" or key == "m"))
|
||||
or (not mod.Control and key == "Return")
|
||||
or (not mod.Control and key == "KP_Enter") then
|
||||
exec()
|
||||
-- We already unregistered ourselves so we don't want to return
|
||||
-- true, otherwise we may unregister someone else.
|
||||
return true
|
||||
end
|
||||
|
||||
-- Control cases
|
||||
if mod.Control then
|
||||
selectall = nil
|
||||
if key == "a" then
|
||||
cur_pos = 1
|
||||
elseif key == "b" then
|
||||
if cur_pos > 1 then
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
elseif key == "d" then
|
||||
if cur_pos <= #command then
|
||||
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
||||
end
|
||||
elseif key == "e" then
|
||||
cur_pos = #command + 1
|
||||
elseif key == "f" then
|
||||
if cur_pos <= #command then
|
||||
cur_pos = cur_pos + 1
|
||||
end
|
||||
elseif key == "h" then
|
||||
if cur_pos > 1 then
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
elseif key == "k" then
|
||||
command = command:sub(1, cur_pos - 1)
|
||||
elseif key == "u" then
|
||||
command = command:sub(cur_pos, #command)
|
||||
cur_pos = 1
|
||||
elseif key == "w" or key == "BackSpace" then
|
||||
local wstart = 1
|
||||
local wend = 1
|
||||
local cword_start = 1
|
||||
local cword_end = 1
|
||||
while wend < cur_pos do
|
||||
wend = command:find("[{[(,.:;_-+=@/ ]", wstart)
|
||||
if not wend then wend = #command + 1 end
|
||||
if cur_pos >= wstart and cur_pos <= wend + 1 then
|
||||
cword_start = wstart
|
||||
cword_end = cur_pos - 1
|
||||
break
|
||||
end
|
||||
wstart = wend + 1
|
||||
end
|
||||
command = command:sub(1, cword_start - 1) .. command:sub(cword_end + 1)
|
||||
cur_pos = cword_start
|
||||
end
|
||||
else
|
||||
if completion_callback then
|
||||
if key == "Tab" or key == "ISO_Left_Tab" then
|
||||
if key == "ISO_Left_Tab" then
|
||||
if ncomp == 1 then return true end
|
||||
if ncomp == 2 then
|
||||
command = command_before_comp
|
||||
textbox.text = prompt_text_with_cursor{
|
||||
text = command_before_comp, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
font = font, prompt = prettyprompt }
|
||||
return true
|
||||
end
|
||||
|
||||
ncomp = ncomp - 2
|
||||
elseif ncomp == 1 then
|
||||
command_before_comp = command
|
||||
cur_pos_before_comp = cur_pos
|
||||
end
|
||||
local matches
|
||||
command, cur_pos, matches = completion_callback(command_before_comp, cur_pos_before_comp, ncomp)
|
||||
ncomp = ncomp + 1
|
||||
key = ""
|
||||
-- execute if only one match found and autoexec flag set
|
||||
if matches and #matches == 1 and args.autoexec then
|
||||
exec()
|
||||
return true
|
||||
end
|
||||
else
|
||||
ncomp = 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Typin cases
|
||||
if mod.Shift and key == "Insert" then
|
||||
local selection = capi.selection()
|
||||
if selection then
|
||||
-- Remove \n
|
||||
local n = selection:find("\n")
|
||||
if n then
|
||||
selection = selection:sub(1, n - 1)
|
||||
end
|
||||
command = command:sub(1, cur_pos - 1) .. selection .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos + #selection
|
||||
end
|
||||
elseif key == "Home" then
|
||||
cur_pos = 1
|
||||
elseif key == "End" then
|
||||
cur_pos = #command + 1
|
||||
elseif key == "BackSpace" then
|
||||
if cur_pos > 1 then
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
elseif key == "Delete" then
|
||||
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
||||
elseif key == "Left" then
|
||||
cur_pos = cur_pos - 1
|
||||
elseif key == "Right" then
|
||||
cur_pos = cur_pos + 1
|
||||
elseif key == "Up" then
|
||||
if history_index > 1 then
|
||||
history_index = history_index - 1
|
||||
|
||||
command = data.history[history_path].table[history_index]
|
||||
cur_pos = #command + 2
|
||||
end
|
||||
elseif key == "Down" then
|
||||
if history_index < history_items(history_path) then
|
||||
history_index = history_index + 1
|
||||
|
||||
command = data.history[history_path].table[history_index]
|
||||
cur_pos = #command + 2
|
||||
elseif history_index == history_items(history_path) then
|
||||
history_index = history_index + 1
|
||||
|
||||
command = ""
|
||||
cur_pos = 1
|
||||
end
|
||||
else
|
||||
-- wlen() is UTF-8 aware but #key is not,
|
||||
-- so check that we have one UTF-8 char but advance the cursor of # position
|
||||
if key:wlen() == 1 then
|
||||
if selectall then command = "" end
|
||||
command = command:sub(1, cur_pos - 1) .. key .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos + #key
|
||||
end
|
||||
end
|
||||
if cur_pos < 1 then
|
||||
cur_pos = 1
|
||||
elseif cur_pos > #command + 1 then
|
||||
cur_pos = #command + 1
|
||||
end
|
||||
selectall = nil
|
||||
end
|
||||
|
||||
-- Update textbox
|
||||
local function update()
|
||||
textbox.text = prompt_text_with_cursor{
|
||||
text = command, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
font = font, prompt = prettyprompt }
|
||||
end
|
||||
|
||||
local success = pcall(update)
|
||||
while not success do
|
||||
-- TODO UGLY HACK TODO
|
||||
-- Setting the text failed. Most likely reason is that the user
|
||||
-- entered a multibyte character and pressed backspace which only
|
||||
-- removed the last byte. Let's remove another byte.
|
||||
if cur_pos <= 1 then
|
||||
-- No text left?!
|
||||
break
|
||||
end
|
||||
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
success = pcall(update)
|
||||
end
|
||||
|
||||
return true
|
||||
end)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,48 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
require("awful.dbus")
|
||||
local loadstring = loadstring
|
||||
local tostring = tostring
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local dbus = dbus
|
||||
local unpack = unpack
|
||||
local type = type
|
||||
|
||||
--- Remote control module allowing usage of awesome-client.
|
||||
module("awful.remote")
|
||||
|
||||
if dbus then
|
||||
dbus.add_signal("org.naquadah.awesome.awful.Remote", function(data, code)
|
||||
if data.member == "Eval" then
|
||||
local f, e = loadstring(code)
|
||||
if f then
|
||||
results = { f() }
|
||||
retvals = {}
|
||||
for _, v in ipairs(results) do
|
||||
local t = type(v)
|
||||
if t == "boolean" then
|
||||
table.insert(retvals, "b")
|
||||
table.insert(retvals, v)
|
||||
elseif t == "number" then
|
||||
table.insert(retvals, "d")
|
||||
table.insert(retvals, v)
|
||||
else
|
||||
table.insert(retvals, "s")
|
||||
table.insert(retvals, tostring(v))
|
||||
end
|
||||
end
|
||||
return unpack(retvals)
|
||||
elseif e then
|
||||
return "s", e
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
177
Old/ATARI/home/burchettm/.config/awesome/lib/awful/rules.lua
Normal file
177
Old/ATARI/home/burchettm/.config/awesome/lib/awful/rules.lua
Normal file
@ -0,0 +1,177 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local client = client
|
||||
local table = table
|
||||
local type = type
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local aclient = require("awful.client")
|
||||
local atag = require("awful.tag")
|
||||
|
||||
--- Apply rules to clients at startup.
|
||||
module("awful.rules")
|
||||
|
||||
--- This is the global rules table.
|
||||
-- <p>You should fill this table with your rule and properties to apply.
|
||||
-- For example, if you want to set xterm maximized at startup, you can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "xterm" },
|
||||
-- properties = { maximized_vertical = true, maximized_horizontal = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to set mplayer floating at startup, you can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { name = "MPlayer" },
|
||||
-- properties = { floating = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to put Firefox on a specific tag at startup, you
|
||||
-- can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { instance = "firefox" }
|
||||
-- properties = { tag = mytagobject } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to put Emacs on a specific tag at startup, and
|
||||
-- immediately switch to that tag you can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "Emacs" }
|
||||
-- properties = { tag = mytagobject, switchtotag = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to apply a custom callback to execute when a rule matched, you
|
||||
-- can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "dosbox" },
|
||||
-- callback = awful.placement.centered }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>Note that all "rule" entries need to match. If any of the entry does not
|
||||
-- match, the rule won't be applied.</p>
|
||||
-- <p>If a client matches multiple rules, their applied in the order they are
|
||||
-- put in this global rules table. If the value of a rule is a string, then the
|
||||
-- match function is used to determine if the client matches the rule.</p>
|
||||
--
|
||||
-- <p> To match multiple clients to a rule one need to use slightly different
|
||||
-- syntax:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule_any = { class = { "MPlayer", "Nitrogen" }, instance = { "xterm" } },
|
||||
-- properties = { floating = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
--
|
||||
-- @class table
|
||||
-- @name rules
|
||||
rules = {}
|
||||
|
||||
--- Check if a client match a rule.
|
||||
-- @param c The client.
|
||||
-- @param rule The rule to check.
|
||||
-- @return True if it matches, false otherwise.
|
||||
function match(c, rule)
|
||||
for field, value in pairs(rule) do
|
||||
if c[field] then
|
||||
if type(c[field]) == "string" then
|
||||
if not c[field]:match(value) and c[field] ~= value then
|
||||
return false
|
||||
end
|
||||
elseif c[field] ~= value then
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Check if a client match a rule. Multiple clients can be matched
|
||||
-- @param c The client.
|
||||
-- @param rules The rule to check.
|
||||
-- @return True if at least one rule is matched, false otherwise.
|
||||
function match_any(c, rule)
|
||||
for field, values in pairs(rule) do
|
||||
if c[field] then
|
||||
for _, value in ipairs(values) do
|
||||
if c[field] == value then
|
||||
return true
|
||||
elseif type(c[field]) == "string" and c[field]:match(value) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Apply rules to a client.
|
||||
-- @param c The client.
|
||||
function apply(c)
|
||||
local props = {}
|
||||
local callbacks = {}
|
||||
for _, entry in ipairs(rules) do
|
||||
if (entry.rule and match(c, entry.rule)) or
|
||||
(entry.rule_any and match_any(c, entry.rule_any)) then
|
||||
if entry.properties then
|
||||
for property, value in pairs(entry.properties) do
|
||||
props[property] = value
|
||||
end
|
||||
end
|
||||
if entry.callback then
|
||||
table.insert(callbacks, entry.callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for property, value in pairs(props) do
|
||||
if property == "floating" then
|
||||
aclient.floating.set(c, value)
|
||||
elseif property == "tag" then
|
||||
c:tags({ value })
|
||||
c.screen = value.screen
|
||||
elseif property == "switchtotag" and value and props.tag then
|
||||
atag.viewonly(props.tag)
|
||||
elseif property == "height" or property == "width" or
|
||||
property == "x" or property == "y" then
|
||||
local geo = c:geometry();
|
||||
geo[property] = value
|
||||
c:geometry(geo);
|
||||
elseif type(c[property]) == "function" then
|
||||
c[property](c, value)
|
||||
else
|
||||
c[property] = value
|
||||
end
|
||||
end
|
||||
|
||||
-- If untagged, stick the client on the current one.
|
||||
if #c:tags() == 0 then
|
||||
atag.withcurrent(c)
|
||||
end
|
||||
|
||||
-- Apply all callbacks from matched rules.
|
||||
for i, callback in pairs(callbacks) do
|
||||
callback(c)
|
||||
end
|
||||
|
||||
-- Do this at last so we do not erase things done by the focus
|
||||
-- signal.
|
||||
if props.focus then
|
||||
client.focus = c
|
||||
end
|
||||
end
|
||||
|
||||
client.add_signal("manage", apply)
|
||||
client.remove_signal("manage", atag.withcurrent)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,53 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi =
|
||||
{
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
client = client
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Screen module for awful
|
||||
module("awful.screen")
|
||||
|
||||
local data = {}
|
||||
data.padding = {}
|
||||
|
||||
--- Give the focus to a screen, and move pointer.
|
||||
-- @param screen Screen number.
|
||||
function focus(screen)
|
||||
if screen > capi.screen.count() then screen = capi.mouse.screen end
|
||||
local c = client.focus.history.get(screen, 0)
|
||||
if c then capi.client.focus = c end
|
||||
-- Move the mouse on the screen
|
||||
capi.mouse.screen = screen
|
||||
end
|
||||
|
||||
--- Give the focus to a screen, and move pointer, but relative to the current
|
||||
-- focused screen.
|
||||
-- @param i Value to add to the current focused screen index. 1 will focus next
|
||||
-- screen, -1 would focus the previous one.
|
||||
function focus_relative(i)
|
||||
return focus(util.cycle(capi.screen.count(), capi.mouse.screen + i))
|
||||
end
|
||||
|
||||
--- Get or set the screen padding.
|
||||
-- @param screen The screen object to change the padding on
|
||||
-- @param padding The padding, an table with 'top', 'left', 'right' and/or
|
||||
-- 'bottom'. Can be nil if you only want to retrieve padding
|
||||
function padding(screen, padding)
|
||||
if padding then
|
||||
data.padding[screen] = padding
|
||||
screen:emit_signal("padding")
|
||||
end
|
||||
return data.padding[screen]
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,54 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
root = root
|
||||
}
|
||||
|
||||
--- Startup notification module for awful
|
||||
module("awful.startup_notification")
|
||||
|
||||
local app_starting = {}
|
||||
|
||||
cursor_waiting = "watch"
|
||||
|
||||
local function update_cursor()
|
||||
if #app_starting > 0 then
|
||||
capi.root.cursor(cursor_waiting)
|
||||
else
|
||||
capi.root.cursor("left_ptr")
|
||||
end
|
||||
end
|
||||
|
||||
local function unregister_event(event_id)
|
||||
for k, v in ipairs(app_starting) do
|
||||
if v == event_id then
|
||||
table.remove(app_starting, k)
|
||||
update_cursor()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function register_event(event_id)
|
||||
table.insert(app_starting, event_id)
|
||||
update_cursor()
|
||||
end
|
||||
|
||||
local function unregister_hook(event) unregister_event(event.id) end
|
||||
local function register_hook(event) register_event(event.id) end
|
||||
|
||||
capi.awesome.add_signal("spawn::initiated", register_hook)
|
||||
capi.awesome.add_signal("spawn::canceled", unregister_hook)
|
||||
capi.awesome.add_signal("spawn::completed", unregister_hook)
|
||||
capi.awesome.add_signal("spawn::timeout", unregister_hook)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
527
Old/ATARI/home/burchettm/.config/awesome/lib/awful/tag.lua
Normal file
527
Old/ATARI/home/burchettm/.config/awesome/lib/awful/tag.lua
Normal file
@ -0,0 +1,527 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local util = require("awful.util")
|
||||
local tostring = tostring
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local setmetatable = setmetatable
|
||||
local capi =
|
||||
{
|
||||
tag = tag,
|
||||
screen = screen,
|
||||
mouse = mouse,
|
||||
client = client
|
||||
}
|
||||
|
||||
--- Useful functions for tag manipulation.
|
||||
module("awful.tag")
|
||||
|
||||
-- Private data
|
||||
local data = {}
|
||||
data.history = {}
|
||||
data.tags = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- History functions
|
||||
history = {}
|
||||
history.limit = 20
|
||||
|
||||
--- Move a tag to an absolute position in the screen[]:tags() table.
|
||||
-- @param new_index Integer absolute position in the table to insert.
|
||||
function move(new_index, target_tag)
|
||||
local target_tag = target_tag or selected()
|
||||
local scr = target_tag.screen
|
||||
local tmp_tags = capi.screen[scr]:tags()
|
||||
|
||||
if (not new_index) or (new_index < 1) or (new_index > #tmp_tags) then
|
||||
return
|
||||
end
|
||||
|
||||
for i, t in ipairs(tmp_tags) do
|
||||
if t == target_tag then
|
||||
table.remove(tmp_tags, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(tmp_tags, new_index, target_tag)
|
||||
capi.screen[scr]:tags(tmp_tags)
|
||||
end
|
||||
|
||||
--- Add a tag.
|
||||
-- @param name The tag name, a string
|
||||
-- @param props The tags properties, a table
|
||||
-- @return The created tag
|
||||
function add(name, props)
|
||||
local properties = props or {}
|
||||
local newtag = capi.tag{name = name}
|
||||
newtag.screen = properties.screen or capi.mouse.screen
|
||||
|
||||
for k, v in pairs(properties) do
|
||||
setproperty(newtag, k, v)
|
||||
end
|
||||
|
||||
return newtag
|
||||
end
|
||||
|
||||
--- Create a set of tags and attach it to a screen.
|
||||
-- @param names The tag name, in a table
|
||||
-- @param screen The tag screen, or 1 if not set.
|
||||
-- @param layout The layout or layout table to set for this tags by default.
|
||||
-- @return A table with all created tags.
|
||||
function new(names, screen, layout)
|
||||
local screen = screen or 1
|
||||
local tags = {}
|
||||
for id, name in ipairs(names) do
|
||||
table.insert(tags, id, add(name, {screen = screen,
|
||||
layout = (layout and layout[id]) or
|
||||
layout}))
|
||||
-- Select the first tag.
|
||||
if id == 1 then
|
||||
tags[id].selected = true
|
||||
end
|
||||
end
|
||||
|
||||
return tags
|
||||
end
|
||||
|
||||
--- Find a suitable fallback tag.
|
||||
-- @param screen The screen number to look for a tag on. [mouse.screen]
|
||||
-- @param target A table of tags we consider unacceptable. [selectedlist(scr)]
|
||||
function find_fallback(screen, invalids)
|
||||
local scr = screen or capi.mouse.screen
|
||||
local t = invalids or selectedlist(scr)
|
||||
|
||||
for _, v in pairs(capi.screen[scr]:tags()) do
|
||||
if not util.table.hasitem(t, v) then return v end
|
||||
end
|
||||
end
|
||||
|
||||
--- Delete a tag.
|
||||
-- @param target_tag Optional tag object to delete. [selected()]
|
||||
-- @param fallback_tag Tag to assign stickied tags to. [~selected()]
|
||||
-- @return Returns true if the tag is successfully deleted, nil otherwise.
|
||||
-- If there are no clients exclusively on this tag then delete it. Any
|
||||
-- stickied clients are assigned to the optional 'fallback_tag'.
|
||||
-- If after deleting the tag there is no selected tag, try and restore from
|
||||
-- history or select the first tag on the screen.
|
||||
function delete(target_tag, fallback_tag)
|
||||
-- abort if no tag is passed or currently selected
|
||||
local target_tag = target_tag or selected()
|
||||
if target_tag == nil then return end
|
||||
|
||||
local ntags = #capi.screen[target_tag.screen]:tags()
|
||||
local target_scr = target_tag.screen
|
||||
|
||||
-- We can't use the target tag as a fallback.
|
||||
local fallback_tag = fallback_tag
|
||||
if fallback_tag == target_tag then return end
|
||||
|
||||
-- No fallback_tag provided, try and get one.
|
||||
if fallback_tag == nil then
|
||||
fallback_tag = find_fallback(target_scr, {target_tag})
|
||||
end
|
||||
|
||||
-- Abort if we would have un-tagged clients.
|
||||
local clients = target_tag:clients()
|
||||
if ( #clients > 0 and ntags <= 1 ) or fallback_tag == nil then return end
|
||||
|
||||
-- Move the clients we can off of this tag.
|
||||
for _, c in pairs(clients) do
|
||||
|
||||
-- If a client has only this tag, or stickied clients with
|
||||
-- nowhere to go, abort.
|
||||
if (not c.sticky and #c:tags() == 1) or
|
||||
(c.sticky and fallback_tag == nil) then
|
||||
return
|
||||
else
|
||||
c:tags({fallback_tag})
|
||||
end
|
||||
end
|
||||
|
||||
-- delete the tag
|
||||
target_tag.screen = nil
|
||||
|
||||
-- If no tags are visible, try and view one.
|
||||
if selected(target_scr) == nil and ntags > 0 then
|
||||
history.restore()
|
||||
if selected(target_scr) == nil then
|
||||
capi.screen[target_scr]:tags()[1].selected = true
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Update the tag history.
|
||||
-- @param obj Screen object.
|
||||
function history.update(obj)
|
||||
local s = obj.index
|
||||
local curtags = selectedlist(s)
|
||||
-- create history table
|
||||
if not data.history[s] then
|
||||
data.history[s] = {}
|
||||
else
|
||||
if data.history[s].current then
|
||||
-- Check that the list is not identical
|
||||
local identical = true
|
||||
for idx, tag in ipairs(data.history[s].current) do
|
||||
if curtags[idx] ~= tag then
|
||||
identical = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Do not update history the table are identical
|
||||
if identical then return end
|
||||
end
|
||||
|
||||
-- Limit history
|
||||
if #data.history[s] >= history.limit then
|
||||
for i = history.limit, #data.history[s] do
|
||||
data.history[s][i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- store previously selected tags in the history table
|
||||
table.insert(data.history[s], 1, data.history[s].current)
|
||||
data.history[s].previous = data.history[s][1]
|
||||
-- store currently selected tags
|
||||
data.history[s].current = setmetatable(curtags, { __mode = 'v' })
|
||||
end
|
||||
|
||||
--- Revert tag history.
|
||||
-- @param screen The screen number.
|
||||
-- @param idx Index in history. Defaults to "previous" which is a special index
|
||||
-- toggling between last two selected sets of tags. Number (eg 1) will go back
|
||||
-- to the given index in history.
|
||||
function history.restore(screen, idx)
|
||||
local s = screen or capi.mouse.screen
|
||||
local i = idx or "previous"
|
||||
local sel = selectedlist(s)
|
||||
-- do nothing if history empty
|
||||
if not data.history[s] or not data.history[s][i] then return end
|
||||
-- if all tags been deleted, try next entry
|
||||
if #data.history[s][i] == 0 then
|
||||
if i == "previous" then i = 0 end
|
||||
history.restore(s, i + 1)
|
||||
return
|
||||
end
|
||||
-- deselect all tags
|
||||
viewnone(s)
|
||||
-- select tags from the history entry
|
||||
for _, t in ipairs(data.history[s][i]) do
|
||||
t.selected = true
|
||||
end
|
||||
-- update currently selected tags table
|
||||
data.history[s].current = data.history[s][i]
|
||||
-- store previously selected tags
|
||||
data.history[s].previous = setmetatable(sel, { __mode = 'v' })
|
||||
-- remove the reverted history entry
|
||||
if i ~= "previous" then table.remove(data.history[s], i) end
|
||||
end
|
||||
|
||||
--- Return a table with all visible tags
|
||||
-- @param s Screen number.
|
||||
-- @return A table with all selected tags.
|
||||
function selectedlist(s)
|
||||
local screen = s or capi.mouse.screen
|
||||
local tags = capi.screen[screen]:tags()
|
||||
local vtags = {}
|
||||
for i, t in pairs(tags) do
|
||||
if t.selected then
|
||||
vtags[#vtags + 1] = t
|
||||
end
|
||||
end
|
||||
return vtags
|
||||
end
|
||||
|
||||
--- Return only the first visible tag.
|
||||
-- @param s Screen number.
|
||||
function selected(s)
|
||||
return selectedlist(s)[1]
|
||||
end
|
||||
|
||||
--- Set master width factor.
|
||||
-- @param mwfact Master width factor.
|
||||
function setmwfact(mwfact, t)
|
||||
local t = t or selected()
|
||||
if mwfact >= 0 and mwfact <= 1 then
|
||||
setproperty(t, "mwfact", mwfact)
|
||||
end
|
||||
end
|
||||
|
||||
--- Increase master width factor.
|
||||
-- @param add Value to add to master width factor.
|
||||
function incmwfact(add, t)
|
||||
setmwfact(getmwfact(t) + add)
|
||||
end
|
||||
|
||||
--- Get master width factor.
|
||||
-- @param t Optional tag.
|
||||
function getmwfact(t)
|
||||
local t = t or selected()
|
||||
return getproperty(t, "mwfact") or 0.5
|
||||
end
|
||||
|
||||
--- Set the number of master windows.
|
||||
-- @param nmaster The number of master windows.
|
||||
-- @param t Optional tag.
|
||||
function setnmaster(nmaster, t)
|
||||
local t = t or selected()
|
||||
if nmaster >= 0 then
|
||||
setproperty(t, "nmaster", nmaster)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the number of master windows.
|
||||
-- @param t Optional tag.
|
||||
function getnmaster(t)
|
||||
local t = t or selected()
|
||||
return getproperty(t, "nmaster") or 1
|
||||
end
|
||||
|
||||
--- Increase the number of master windows.
|
||||
-- @param add Value to add to number of master windows.
|
||||
function incnmaster(add, t)
|
||||
setnmaster(getnmaster(t) + add)
|
||||
end
|
||||
|
||||
|
||||
--- Set the tag icon
|
||||
-- @param icon the icon to set, either path or image object
|
||||
-- @param tag the tag
|
||||
function seticon(icon, tag)
|
||||
local tag = tag or selected()
|
||||
setproperty(tag, "icon", icon)
|
||||
end
|
||||
|
||||
--- Get the tag icon
|
||||
-- @param t the tag
|
||||
function geticon(tag)
|
||||
local tag = tag or selected()
|
||||
return getproperty(tag, "icon")
|
||||
end
|
||||
|
||||
--- Set number of column windows.
|
||||
-- @param ncol The number of column.
|
||||
function setncol(ncol, t)
|
||||
local t = t or selected()
|
||||
if ncol >= 1 then
|
||||
setproperty(t, "ncol", ncol)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get number of column windows.
|
||||
-- @param t Optional tag.
|
||||
function getncol(t)
|
||||
local t = t or selected()
|
||||
return getproperty(t, "ncol") or 1
|
||||
end
|
||||
|
||||
--- Increase number of column windows.
|
||||
-- @param add Value to add to number of column windows.
|
||||
function incncol(add, t)
|
||||
setncol(getncol(t) + add)
|
||||
end
|
||||
|
||||
--- View no tag.
|
||||
-- @param Optional screen number.
|
||||
function viewnone(screen)
|
||||
local tags = capi.screen[screen or capi.mouse.screen]:tags()
|
||||
for i, t in pairs(tags) do
|
||||
t.selected = false
|
||||
end
|
||||
end
|
||||
|
||||
--- View a tag by its taglist index.
|
||||
-- @param i The relative index to see.
|
||||
-- @param screen Optional screen number.
|
||||
function viewidx(i, screen)
|
||||
local screen = screen and screen.index or capi.mouse.screen
|
||||
local tags = capi.screen[screen]:tags()
|
||||
local showntags = {}
|
||||
for k, t in ipairs(tags) do
|
||||
if not getproperty(t, "hide") then
|
||||
table.insert(showntags, t)
|
||||
end
|
||||
end
|
||||
local sel = selected(screen)
|
||||
viewnone(screen)
|
||||
for k, t in ipairs(showntags) do
|
||||
if t == sel then
|
||||
showntags[util.cycle(#showntags, k + i)].selected = true
|
||||
end
|
||||
end
|
||||
capi.screen[screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- Get a tag's index in the screen[]:tags() table.
|
||||
-- @param query_tag The tag object to find. [selected()]
|
||||
-- @return The index of the tag, nil if the tag is not found.
|
||||
function getidx(query_tag)
|
||||
local query_tag = query_tag or selected()
|
||||
if query_tag == nil then return end
|
||||
|
||||
for i, t in ipairs(capi.screen[query_tag.screen]:tags()) do
|
||||
if t == query_tag then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- View next tag. This is the same as tag.viewidx(1).
|
||||
-- @param screen The screen number.
|
||||
function viewnext(screen)
|
||||
return viewidx(1, screen)
|
||||
end
|
||||
|
||||
--- View previous tag. This is the same a tag.viewidx(-1).
|
||||
-- @param screen The screen number.
|
||||
function viewprev(screen)
|
||||
return viewidx(-1, screen)
|
||||
end
|
||||
|
||||
--- View only a tag.
|
||||
-- @param t The tag object.
|
||||
function viewonly(t)
|
||||
local tags = capi.screen[t.screen]:tags()
|
||||
-- First, untag everyone except the viewed tag.
|
||||
for _, tag in pairs(tags) do
|
||||
if tag ~= t then
|
||||
tag.selected = false
|
||||
end
|
||||
end
|
||||
-- Then, set this one to selected.
|
||||
-- We need to do that in 2 operations so we avoid flickering and several tag
|
||||
-- selected at the same time.
|
||||
t.selected = true
|
||||
capi.screen[t.screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- View only a set of tags.
|
||||
-- @param tags A table with tags to view only.
|
||||
-- @param screen Optional screen number of the tags.
|
||||
function viewmore(tags, screen)
|
||||
local screen_tags = capi.screen[screen or capi.mouse.screen]:tags()
|
||||
for _, tag in ipairs(screen_tags) do
|
||||
if not util.table.hasitem(tags, tag) then
|
||||
tag.selected = false
|
||||
end
|
||||
end
|
||||
for _, tag in ipairs(tags) do
|
||||
tag.selected = true
|
||||
end
|
||||
capi.screen[screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- Toggle selection of a tag
|
||||
-- @param tag Tag to be toggled
|
||||
function viewtoggle(t)
|
||||
t.selected = not t.selected
|
||||
capi.screen[t.screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- Get tag data table.
|
||||
-- @param tag The Tag.
|
||||
-- @return The data table.
|
||||
function getdata(tag)
|
||||
return data.tags[tag]
|
||||
end
|
||||
|
||||
--- Get a tag property.
|
||||
-- @param tag The tag.
|
||||
-- @param prop The property name.
|
||||
-- @return The property.
|
||||
function getproperty(tag, prop)
|
||||
if data.tags[tag] then
|
||||
return data.tags[tag][prop]
|
||||
end
|
||||
end
|
||||
|
||||
--- Set a tag property.
|
||||
-- This properties are internal to awful. Some are used to draw taglist, or to
|
||||
-- handle layout, etc.
|
||||
-- @param tag The tag.
|
||||
-- @param prop The property name.
|
||||
-- @param value The value.
|
||||
function setproperty(tag, prop, value)
|
||||
if not data.tags[tag] then
|
||||
data.tags[tag] = {}
|
||||
end
|
||||
data.tags[tag][prop] = value
|
||||
tag:emit_signal("property::" .. prop)
|
||||
end
|
||||
|
||||
--- Tag a client with the set of current tags.
|
||||
-- @param c The client to tag.
|
||||
-- @param startup Optional: don't do anything if true.
|
||||
function withcurrent(c, startup)
|
||||
if startup ~= true and c.sticky == false then
|
||||
if #c:tags() == 0 then
|
||||
c:tags(selectedlist(c.screen))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function attached_add_signal_screen(screen, sig, func)
|
||||
capi.screen[screen]:add_signal("tag::attach", function (s, tag)
|
||||
tag:add_signal(sig, func)
|
||||
end)
|
||||
capi.screen[screen]:add_signal("tag::detach", function (s, tag)
|
||||
tag:remove_signal(sig, func)
|
||||
end)
|
||||
for _, tag in ipairs(capi.screen[screen]:tags()) do
|
||||
tag:add_signal(sig, func)
|
||||
end
|
||||
end
|
||||
|
||||
--- Add a signal to all attached tag and all tag that will be attached in the
|
||||
-- future. When a tag is detach from the screen, its signal is removed.
|
||||
-- @param screen The screen concerned, or all if nil.
|
||||
function attached_add_signal(screen, ...)
|
||||
if screen then
|
||||
attached_add_signal_screen(screen, ...)
|
||||
else
|
||||
for screen = 1, capi.screen.count() do
|
||||
attached_add_signal_screen(screen, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Register standards signals
|
||||
capi.client.add_signal("manage", function(c, startup)
|
||||
-- If we are not managing this application at startup,
|
||||
-- move it to the screen where the mouse is.
|
||||
-- We only do it for "normal" windows (i.e. no dock, etc).
|
||||
if not startup
|
||||
and c.type ~= "desktop"
|
||||
and c.type ~= "dock"
|
||||
and c.type ~= "splash" then
|
||||
if c.transient_for then
|
||||
c.screen = c.transient_for.screen
|
||||
if not c.sticky then
|
||||
c:tags(c.transient_for:tags())
|
||||
end
|
||||
else
|
||||
c.screen = capi.mouse.screen
|
||||
end
|
||||
end
|
||||
c:add_signal("property::screen", withcurrent)
|
||||
end)
|
||||
|
||||
capi.client.add_signal("manage", withcurrent)
|
||||
|
||||
for s = 1, capi.screen.count() do
|
||||
capi.screen[s]:add_signal("tag::history::update", history.update)
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function (_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
421
Old/ATARI/home/burchettm/.config/awesome/lib/awful/titlebar.lua
Normal file
421
Old/ATARI/home/burchettm/.config/awesome/lib/awful/titlebar.lua
Normal file
@ -0,0 +1,421 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local math = math
|
||||
local image = image
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
wibox = wibox,
|
||||
widget = widget,
|
||||
client = client,
|
||||
}
|
||||
local abutton = require("awful.button")
|
||||
local beautiful = require("beautiful")
|
||||
local util = require("awful.util")
|
||||
local widget = require("awful.widget")
|
||||
local mouse = require("awful.mouse")
|
||||
local client = require("awful.client")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Titlebar module for awful
|
||||
module("awful.titlebar")
|
||||
|
||||
-- Privata data
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- Predeclaration for buttons
|
||||
local button_groups
|
||||
|
||||
local function button_callback_focus_raise_move(w, t)
|
||||
capi.client.focus = t.client
|
||||
t.client:raise()
|
||||
mouse.client.move(t.client)
|
||||
end
|
||||
|
||||
local function button_callback_move(w, t)
|
||||
return mouse.client.move(t.client)
|
||||
end
|
||||
|
||||
local function button_callback_resize(w, t)
|
||||
return mouse.client.resize(t.client)
|
||||
end
|
||||
|
||||
--- Create a standard titlebar.
|
||||
-- @param c The client.
|
||||
-- @param args Arguments.
|
||||
-- modkey: the modkey used for the bindings.
|
||||
-- fg: the foreground color.
|
||||
-- bg: the background color.
|
||||
-- fg_focus: the foreground color for focused window.
|
||||
-- fg_focus: the background color for focused window.
|
||||
-- width: the titlebar width
|
||||
function add(c, args)
|
||||
if not c or (c.type ~= "normal" and c.type ~= "dialog") then return end
|
||||
if not args then args = {} end
|
||||
if not args.height then args.height = capi.awesome.font_height * 1.5 end
|
||||
local theme = beautiful.get()
|
||||
if not args.widget then customwidget = {} else customwidget = args.widget end
|
||||
-- Store colors
|
||||
data[c] = {}
|
||||
data[c].fg = args.fg or theme.titlebar_fg_normal or theme.fg_normal
|
||||
data[c].bg = args.bg or theme.titlebar_bg_normal or theme.bg_normal
|
||||
data[c].fg_focus = args.fg_focus or theme.titlebar_fg_focus or theme.fg_focus
|
||||
data[c].bg_focus = args.bg_focus or theme.titlebar_bg_focus or theme.bg_focus
|
||||
data[c].width = args.width
|
||||
data[c].font = args.font or theme.titlebar_font or theme.font
|
||||
|
||||
local tb = capi.wibox(args)
|
||||
|
||||
local title = capi.widget({ type = "textbox" })
|
||||
if c.name then
|
||||
title.text = "<span font_desc='" .. data[c].font .. "'> " ..
|
||||
util.escape(c.name) .. " </span>"
|
||||
end
|
||||
|
||||
-- Redirect relevant events to the client the titlebar belongs to
|
||||
local bts = util.table.join(
|
||||
abutton({ }, 1, button_callback_focus_raise_move),
|
||||
abutton({ args.modkey }, 1, button_callback_move),
|
||||
abutton({ args.modkey }, 3, button_callback_resize))
|
||||
title:buttons(bts)
|
||||
|
||||
local appicon = capi.widget({ type = "imagebox" })
|
||||
appicon.image = c.icon
|
||||
|
||||
-- for each button group, call create for the client.
|
||||
-- if a button set is created add the set to the
|
||||
-- data[c].button_sets for late updates and add the
|
||||
-- individual buttons to the array part of the widget
|
||||
-- list
|
||||
local widget_list = {
|
||||
layout = layout.horizontal.rightleft
|
||||
}
|
||||
local iw = 1
|
||||
local is = 1
|
||||
data[c].button_sets = {}
|
||||
for i = 1, #button_groups do
|
||||
local set = button_groups[i].create(c, args.modkey, theme)
|
||||
if (set) then
|
||||
data[c].button_sets[is] = set
|
||||
is = is + 1
|
||||
for n,b in pairs(set) do
|
||||
widget_list[iw] = b
|
||||
iw = iw + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tb.widgets = {
|
||||
widget_list,
|
||||
customwidget,
|
||||
{
|
||||
appicon = appicon,
|
||||
title = title,
|
||||
layout = layout.horizontal.flex
|
||||
},
|
||||
layout = layout.horizontal.rightleft
|
||||
}
|
||||
|
||||
c.titlebar = tb
|
||||
|
||||
c:add_signal("property::icon", update)
|
||||
c:add_signal("property::name", update)
|
||||
c:add_signal("property::sticky", update)
|
||||
c:add_signal("property::floating", update)
|
||||
c:add_signal("property::ontop", update)
|
||||
c:add_signal("property::maximized_vertical", update)
|
||||
c:add_signal("property::maximized_horizontal", update)
|
||||
update(c)
|
||||
end
|
||||
|
||||
--- Update a titlebar. This should be called in some hooks.
|
||||
-- @param c The client to update.
|
||||
-- @param prop The property name which has changed.
|
||||
function update(c)
|
||||
if c.titlebar and data[c] then
|
||||
local widgets = c.titlebar.widgets
|
||||
if widgets[3].title then
|
||||
widgets[3].title.text = "<span font_desc='" .. data[c].font ..
|
||||
"'> ".. util.escape(c.name or "<unknown>") .. " </span>"
|
||||
end
|
||||
if widgets[3].appicon then
|
||||
widgets[3].appicon.image = c.icon
|
||||
end
|
||||
if capi.client.focus == c then
|
||||
c.titlebar.fg = data[c].fg_focus
|
||||
c.titlebar.bg = data[c].bg_focus
|
||||
else
|
||||
c.titlebar.fg = data[c].fg
|
||||
c.titlebar.bg = data[c].bg
|
||||
end
|
||||
|
||||
-- iterated of all registered button_sets and update
|
||||
local sets = data[c].button_sets
|
||||
for i = 1, #sets do
|
||||
sets[i].update(c,prop)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove a titlebar from a client.
|
||||
-- @param c The client.
|
||||
function remove(c)
|
||||
c.titlebar = nil
|
||||
data[c] = nil
|
||||
end
|
||||
|
||||
-- Create a new button for the toolbar
|
||||
-- @param c The client of the titlebar
|
||||
-- @param name The base name of the button (i.e. close)
|
||||
-- @param modkey ... you know that one, don't you?
|
||||
-- @param theme The theme from beautifull. Used to get the image paths
|
||||
-- @param state The state the button is associated to. Containse path the action and info about the image
|
||||
local function button_new(c, name, modkey, theme, state)
|
||||
local bts = abutton({ }, 1, nil, state.action)
|
||||
|
||||
-- get the image path from the theme. Only return a button if we find an image
|
||||
local img
|
||||
img = "titlebar_" .. name .. "_button_" .. state.img
|
||||
img = theme[img]
|
||||
if not img then return end
|
||||
img = image(img)
|
||||
if not img then return end
|
||||
|
||||
-- now create the button
|
||||
local bname = name .. "_" .. state.idx
|
||||
local button = widget.button({ image = img })
|
||||
if not button then return end
|
||||
local rbts = button:buttons()
|
||||
|
||||
for k, v in pairs(rbts) do
|
||||
bts[#bts + 1] = v
|
||||
end
|
||||
|
||||
button:buttons(bts)
|
||||
button.visible = false
|
||||
return button
|
||||
end
|
||||
|
||||
-- Update the buttons in a button group
|
||||
-- @param s The button group to update
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function button_group_update(s,c,p)
|
||||
-- hide the currently active button, get the new state and show the new button
|
||||
local n = s.select_state(c,p)
|
||||
if n == nil then return end
|
||||
if (s.active ~= nil) then s.active.visible = false end
|
||||
s.active = s.buttons[n]
|
||||
s.active.visible = true
|
||||
end
|
||||
|
||||
-- Create all buttons in a group
|
||||
-- @param c The client of the titlebar
|
||||
-- @param group The button group to create the buttons for
|
||||
-- @param modkey ...
|
||||
-- @param theme Theme for the image paths
|
||||
local function button_group_create(c, group, modkey, theme )
|
||||
local s = {}
|
||||
s.name = group.name
|
||||
s.select_state = group.select_state
|
||||
s.buttons = {
|
||||
layout = layout.horizontal.rightleft
|
||||
}
|
||||
for n,state in pairs(group.states) do
|
||||
s.buttons[n] = button_new(c, s.name, modkey, theme, state)
|
||||
if (s.buttons[n] == nil) then return end
|
||||
for a,v in pairs(group.attributes) do
|
||||
s.buttons[n][a] = v
|
||||
end
|
||||
end
|
||||
function s.update(c,p) button_group_update(s,c,p) end
|
||||
return s
|
||||
end
|
||||
|
||||
-- Builds a new button group
|
||||
-- @param name The base name for the buttons in the group (i.e. "close")
|
||||
-- @param attrs Common attributes for the buttons (i.e. {align = "right")
|
||||
-- @param sfn State select function.
|
||||
-- @param args The states of the button
|
||||
local function button_group(name, attrs, sfn, ...)
|
||||
local s = {}
|
||||
s.name = name
|
||||
s.select_state = sfn
|
||||
s.attributes = attrs
|
||||
s.states = {}
|
||||
|
||||
for i, state in pairs({...}) do
|
||||
s.states[state.idx] = state
|
||||
end
|
||||
|
||||
function s.create(c,modkey, theme) return button_group_create(c,s,modkey, theme) end
|
||||
return s
|
||||
end
|
||||
|
||||
-- Select a state for a client based on an attribute of the client and whether it has focus
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
-- @param a The property to check
|
||||
local function select_state(c,p,a)
|
||||
if (c == nil) then return "n/i" end
|
||||
if capi.client.focus == c then
|
||||
if c[a] then
|
||||
return "f/a"
|
||||
else
|
||||
return "f/i"
|
||||
end
|
||||
else
|
||||
if c[a] then
|
||||
return "n/a"
|
||||
else
|
||||
return "n/i"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Select a state for a client based on whether it's floating or not
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function select_state_floating(c,p)
|
||||
if not c then return end
|
||||
if capi.client.focus == c then
|
||||
if client.floating.get(c) then
|
||||
return "f/a"
|
||||
end
|
||||
return "f/i"
|
||||
end
|
||||
if client.floating.get(c) then
|
||||
return "n/a"
|
||||
end
|
||||
return "n/i"
|
||||
end
|
||||
|
||||
-- Select a state for a client based on whether it's maximized or not
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function select_state_maximized(c,p)
|
||||
if (c == nil) then return "n/i" end
|
||||
if capi.client.focus == c then
|
||||
if c.maximized_horizontal or c.maximized_vertical then
|
||||
return "f/a"
|
||||
else
|
||||
return "f/i"
|
||||
end
|
||||
else
|
||||
if c.maximized_horizontal or c.maximized_vertical then
|
||||
return "n/a"
|
||||
else
|
||||
return "n/i"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Select a state for a client based on whether it has focus or not
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function select_state_focus(c,p)
|
||||
if c and capi.client.focus == c then
|
||||
return "f"
|
||||
end
|
||||
return "n"
|
||||
end
|
||||
|
||||
-- These are the predefined button groups
|
||||
-- A short explanation using 'close_buttons' as an example:
|
||||
-- "close" : name of the button, the images for this button are taken from the
|
||||
-- theme variables titlebar_close_button_...
|
||||
-- { align ... : attributes of all the buttons
|
||||
-- select_state_focus : This function returns a short string used to describe
|
||||
-- the state. In this case either "n" or "f" depending on
|
||||
-- the focus state of the client. These strings can be
|
||||
-- choosen freely but the< must match one of the idx fuekds
|
||||
-- of the states below
|
||||
-- { idx = "n" ... : This is the state of the button for the 'unfocussed'
|
||||
-- (normal) state. The idx = "n" parameter connects this
|
||||
-- button to the return value of the 'select_state_focus'
|
||||
-- function. The img = "normal" parameter is used to
|
||||
-- determine its image. In this case the iamge is taken from
|
||||
-- the theme variable "titlebar_close_button_normal".
|
||||
-- Finally the last parameter is the action for mouse
|
||||
-- button 1
|
||||
|
||||
local ontop_buttons = button_group("ontop",
|
||||
{ align = "right" },
|
||||
function(c,p) return select_state(c, p, "ontop") end,
|
||||
{ idx = "n/i", img = "normal_inactive",
|
||||
action = function(w, t) t.client.ontop = true end },
|
||||
{ idx = "f/i", img = "focus_inactive",
|
||||
action = function(w, t) t.client.ontop = true end },
|
||||
{ idx = "n/a", img = "normal_active",
|
||||
action = function(w, t) t.client.ontop = false end },
|
||||
{ idx = "f/a", img = "focus_active",
|
||||
action = function(w, t) t.client.ontop = false end })
|
||||
|
||||
local sticky_buttons = button_group("sticky",
|
||||
{ align = "right" },
|
||||
function(c,p) return select_state(c,p,"sticky") end,
|
||||
{ idx = "n/i", img = "normal_inactive",
|
||||
action = function(w, t) t.client.sticky = true end },
|
||||
{ idx = "f/i", img = "focus_inactive",
|
||||
action = function(w, t) t.client.sticky = true end },
|
||||
{ idx = "n/a", img = "normal_active",
|
||||
action = function(w, t) t.client.sticky = false end },
|
||||
{ idx = "f/a", img = "focus_active",
|
||||
action = function(w, t) t.client.sticky = false end })
|
||||
|
||||
local maximized_buttons = button_group("maximized",
|
||||
{ align = "right" },
|
||||
select_state_maximized,
|
||||
{ idx = "n/i", img = "normal_inactive",
|
||||
action = function(w, t) t.client.maximized_horizontal = true
|
||||
t.client.maximized_vertical = true end },
|
||||
{ idx = "f/i", img = "focus_inactive",
|
||||
action = function(w, t) t.client.maximized_horizontal = true
|
||||
t.client.maximized_vertical = true end },
|
||||
{ idx = "n/a", img = "normal_active",
|
||||
action = function(w, t) t.client.maximized_horizontal = false
|
||||
t.client.maximized_vertical = false end },
|
||||
{ idx = "f/a", img = "focus_active",
|
||||
action = function(w, t) t.client.maximized_horizontal = false
|
||||
t.client.maximized_vertical = false end })
|
||||
|
||||
local close_buttons = button_group("close",
|
||||
{ align = "left" },
|
||||
select_state_focus,
|
||||
{ idx = "n", img = "normal",
|
||||
action = function (w, t) t.client:kill() end },
|
||||
{ idx = "f", img = "focus",
|
||||
action = function (w, t) t.client:kill() end })
|
||||
|
||||
local function floating_update(w, t)
|
||||
client.floating.toggle(t.client)
|
||||
end
|
||||
|
||||
local floating_buttons = button_group("floating",
|
||||
{ align = "right"},
|
||||
select_state_floating,
|
||||
{ idx = "n/i", img = "normal_inactive", action = floating_update },
|
||||
{ idx = "f/i", img = "focus_inactive", action = floating_update },
|
||||
{ idx = "n/a", img = "normal_active", action = floating_update },
|
||||
{ idx = "f/a", img = "focus_active", action = floating_update })
|
||||
|
||||
button_groups = { close_buttons,
|
||||
ontop_buttons,
|
||||
sticky_buttons,
|
||||
maximized_buttons,
|
||||
floating_buttons }
|
||||
|
||||
-- Register standards hooks
|
||||
capi.client.add_signal("focus", update)
|
||||
capi.client.add_signal("unfocus", update)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
233
Old/ATARI/home/burchettm/.config/awesome/lib/awful/tooltip.lua
Normal file
233
Old/ATARI/home/burchettm/.config/awesome/lib/awful/tooltip.lua
Normal file
@ -0,0 +1,233 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- @author Sébastien Gross <seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org>
|
||||
-- @copyright 2009 Sébastien Gross
|
||||
-- @release v3.4.9
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
local mouse = mouse
|
||||
local widget = widget
|
||||
local wibox = wibox
|
||||
local screen = screen
|
||||
local timer = timer
|
||||
local a_placement = require("awful.placement")
|
||||
local beautiful = require("beautiful")
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
|
||||
--- Tooltip module for awesome objects.
|
||||
-- A tooltip is a small hint displayed when the mouse cursor
|
||||
-- hovers a specific item.
|
||||
-- In awesome, a tooltip can be linked with almost any
|
||||
-- object having a <code>add_signal()</code> method and receiving
|
||||
-- <code>mouse::enter</code> and <code>mouse::leave</code> signals.
|
||||
-- <p>How to create a tooltip?<br/>
|
||||
-- <code>
|
||||
-- myclock = awful.widget.textclock({}, "%T", 1)<br/>
|
||||
-- myclock_t = awful.tooltip({<br/>
|
||||
-- objects = { K },<br/>
|
||||
-- timer_function = function()<br/>
|
||||
-- return os.date("Today is %A %B %d %Y\nThe time is %T")<br/>
|
||||
-- end,<br/>
|
||||
-- })<br/>
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>How to add the same tooltip to several objects?<br/>
|
||||
-- <code>
|
||||
-- myclock_t:add_to_object(obj1)<br/>
|
||||
-- myclock_t:add_to_object(obj2)<br/>
|
||||
-- </code>
|
||||
-- Now the same tooltip is attached to <code>K</code>, <code>obj1</code>,
|
||||
-- <code>obj2</code>.<br/>
|
||||
-- </p>
|
||||
-- <p>How to remove tooltip from many objects?<br/>
|
||||
-- <code>
|
||||
-- myclock_t:remove_from_object(obj1)<br/>
|
||||
-- myclock_t:remove_from_object(obj2)<br/>
|
||||
-- </code>
|
||||
-- Now the same tooltip is only attached to <code>K</code>.<br/>
|
||||
-- </p>
|
||||
module("awful.tooltip")
|
||||
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
--- Tooltip object definition.
|
||||
-- @name tooltip
|
||||
-- @field wibox The wibox displaying the tooltip.
|
||||
-- @field visible True if tooltip is visible.
|
||||
-- @class table
|
||||
|
||||
-- Tooltip private data.
|
||||
-- @name awful.tooltip.data
|
||||
-- @field fg tooltip foreground color.
|
||||
-- @field font Tooltip font.
|
||||
-- @field hide The hide() function.
|
||||
-- @field show The show() function.
|
||||
-- @field timer The text update timer.
|
||||
-- @field timer_function The text update timer function.
|
||||
|
||||
-- Place to tooltip on th screen.
|
||||
-- @param self A tooltip object.
|
||||
local function place(self)
|
||||
a_placement.under_mouse(self.wibox)
|
||||
a_placement.no_offscreen(self.wibox)
|
||||
end
|
||||
|
||||
-- Place the tooltip under the mouse.
|
||||
-- @param self A tooltip object.
|
||||
local function set_geometry(self)
|
||||
local my_geo = self.wibox:geometry()
|
||||
-- calculate width / height
|
||||
n_s = self.wibox.widgets[1]:extents()
|
||||
if my_geo.width ~= n_s.width or my_geo.height ~= n_s.height then
|
||||
self.wibox:geometry(n_s)
|
||||
place(self)
|
||||
end
|
||||
if not self.wibox.visible then
|
||||
place(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- Show a tooltip.
|
||||
-- @param self The tooltip to show.
|
||||
local function show(self)
|
||||
-- do nothing if the tooltip is already shown
|
||||
if self.visible then return end
|
||||
-- make sure the tooltip is on the same screen as the mouse
|
||||
self.wibox.screen = mouse.screen
|
||||
if data[self].timer then
|
||||
if not data[self].timer.started then
|
||||
data[self].timer_function()
|
||||
data[self].timer:start()
|
||||
end
|
||||
end
|
||||
set_geometry(self)
|
||||
self.wibox.visible = true
|
||||
self.visible = true
|
||||
end
|
||||
|
||||
-- Hide a tooltip.
|
||||
-- @param self The tooltip to hide.
|
||||
local function hide(self)
|
||||
-- do nothing if the tooltip is already hidden
|
||||
if not self.visible then return end
|
||||
if data[self].timer then
|
||||
if data[self].timer.started then
|
||||
data[self].timer:stop()
|
||||
end
|
||||
end
|
||||
self.visible = false
|
||||
self.wibox.visible = false
|
||||
end
|
||||
|
||||
--- Change displayed text.
|
||||
-- @param self The tooltip object.
|
||||
-- @param text New tooltip text.
|
||||
local function set_text(self, text)
|
||||
self.wibox.widgets[1].text = '<span color="' .. data[self].fg
|
||||
.. '" font_desc="' .. data[self].font .. '">' .. text .. "</span>"
|
||||
end
|
||||
|
||||
--- Change the tooltip's update interval.
|
||||
-- @param self A tooltip object.
|
||||
-- @param timeout The timeout value.
|
||||
local function set_timeout(self, timeout)
|
||||
if data[self].timer then
|
||||
data[self].timer.timeout = timeout
|
||||
end
|
||||
end
|
||||
|
||||
-- Load Default values.
|
||||
-- @param self A tooltip object.
|
||||
local function set_defaults(self)
|
||||
self.wibox.border_width = beautiful.tooltip_border_width or beautiful.border_width or 1
|
||||
self.wibox.border_color = beautiful.tooltip_border_color or beautiful.border_normal or "#ffcb60"
|
||||
self.wibox.opacity = beautiful.tooltip_opacity or 1
|
||||
self.wibox.bg = beautiful.tooltip_bg_color or beautiful.bg_focus or "#ffcb60"
|
||||
data[self].fg = beautiful.tooltip_fg_color or beautiful.fg_focus or "#000000"
|
||||
data[self].font = beautiful.tooltip_font or beautiful.font or "terminus 6"
|
||||
end
|
||||
|
||||
--- Add tooltip to an object.
|
||||
-- @param self The tooltip.
|
||||
-- @param object An object.
|
||||
local function add_to_object(self, object)
|
||||
object:add_signal("mouse::enter", data[self].show)
|
||||
object:add_signal("mouse::leave", data[self].hide)
|
||||
end
|
||||
|
||||
--- Remove tooltip from an object.
|
||||
-- @param self The tooltip.
|
||||
-- @param object An object.
|
||||
local function remove_from_object(self, object)
|
||||
object:remove_signal("mouse::enter", data[self].show)
|
||||
object:remove_signal("mouse::leave", data[self].hide)
|
||||
end
|
||||
|
||||
|
||||
--- Create a new tooltip and link it to a widget.
|
||||
-- @param args Arguments for tooltip creation may containt:<br/>
|
||||
-- <code>timeout</code>: The timeout value for update_func.<br/>
|
||||
-- <code>timer_function</code>: A function to dynamicaly change the tooltip
|
||||
-- text.<br/>
|
||||
-- <code>objects</code>: A list of objects linked to the tooltip.<br/>
|
||||
-- @return The created tooltip.
|
||||
-- @see add_to_object
|
||||
-- @see set_timeout
|
||||
-- @see set_text
|
||||
local function new(args)
|
||||
local self = {
|
||||
wibox = wibox({ }),
|
||||
visible = false,
|
||||
}
|
||||
|
||||
local my_textbox = widget({
|
||||
type = "textbox",
|
||||
name = "tooltip_textbox",
|
||||
align="right"})
|
||||
|
||||
-- private data
|
||||
data[self] = {
|
||||
show = function() show(self) end,
|
||||
hide = function() hide(self) end
|
||||
}
|
||||
|
||||
-- export functions
|
||||
self.set_text = set_text
|
||||
self.set_timeout = set_timeout
|
||||
self.add_to_object = add_to_object
|
||||
self.remove_from_object = remove_from_object
|
||||
|
||||
set_defaults(self)
|
||||
|
||||
-- setup the timer action only if needed
|
||||
if args.timer_function then
|
||||
data[self].timer = timer { timeout = args.timeout and args.timeout or 1 }
|
||||
data[self].timer_function = function()
|
||||
self:set_text(args.timer_function())
|
||||
set_geometry(self)
|
||||
end
|
||||
data[self].timer:add_signal("timeout", data[self].timer_function)
|
||||
end
|
||||
|
||||
-- set tooltip properties
|
||||
self.wibox.visible = false
|
||||
-- Who want a non ontop tooltip ?
|
||||
self.wibox.ontop = true
|
||||
self.wibox.widgets = { my_textbox }
|
||||
|
||||
-- add some signals on both the tooltip and widget
|
||||
self.wibox:add_signal("mouse::enter", data[self].hide)
|
||||
|
||||
-- Add tooltip to objects
|
||||
if args.objects then
|
||||
for _, object in ipairs(args.objects) do
|
||||
self:add_to_object(object)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: ft=lua:et:sw=4:ts=4:sts=4:enc=utf-8:tw=78
|
347
Old/ATARI/home/burchettm/.config/awesome/lib/awful/util.lua
Normal file
347
Old/ATARI/home/burchettm/.config/awesome/lib/awful/util.lua
Normal file
@ -0,0 +1,347 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local os = os
|
||||
local io = io
|
||||
local assert = assert
|
||||
local loadstring = loadstring
|
||||
local loadfile = loadfile
|
||||
local debug = debug
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local rtable = table
|
||||
local pairs = pairs
|
||||
local string = string
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
mouse = mouse
|
||||
}
|
||||
|
||||
--- Utility module for awful
|
||||
module("awful.util")
|
||||
|
||||
table = {}
|
||||
|
||||
shell = os.getenv("SHELL") or "/bin/sh"
|
||||
|
||||
function deprecate(see)
|
||||
io.stderr:write("W: awful: function is deprecated")
|
||||
if see then
|
||||
io.stderr:write(", see " .. see)
|
||||
end
|
||||
io.stderr:write("\n")
|
||||
io.stderr:write(debug.traceback())
|
||||
end
|
||||
|
||||
--- Strip alpha part of color.
|
||||
-- @param color The color.
|
||||
-- @return The color without alpha channel.
|
||||
function color_strip_alpha(color)
|
||||
if color:len() == 9 then
|
||||
color = color:sub(1, 7)
|
||||
end
|
||||
return color
|
||||
end
|
||||
|
||||
--- Make i cycle.
|
||||
-- @param t A length.
|
||||
-- @param i An absolute index to fit into #t.
|
||||
-- @return The object at new index.
|
||||
function cycle(t, i)
|
||||
while i > t do i = i - t end
|
||||
while i < 1 do i = i + t end
|
||||
return i
|
||||
end
|
||||
|
||||
--- Create a directory
|
||||
-- @param dir The directory.
|
||||
-- @return mkdir return code
|
||||
function mkdir(dir)
|
||||
return os.execute("mkdir -p " .. dir)
|
||||
end
|
||||
|
||||
--- Spawn a program.
|
||||
-- @param cmd The command.
|
||||
-- @param sn Enable startup-notification.
|
||||
-- @param screen The screen where to spawn window.
|
||||
-- @return The awesome.spawn return value.
|
||||
function spawn(cmd, sn, screen)
|
||||
if cmd and cmd ~= "" then
|
||||
if sn == nil then sn = true end
|
||||
return capi.awesome.spawn(cmd, sn, screen or capi.mouse.screen)
|
||||
end
|
||||
end
|
||||
|
||||
--- Spawn a program using the shell.
|
||||
-- @param cmd The command.
|
||||
-- @param screen The screen where to run the command.
|
||||
function spawn_with_shell(cmd, screen)
|
||||
if cmd and cmd ~= "" then
|
||||
cmd = shell .. " -c \"" .. cmd .. "\""
|
||||
return capi.awesome.spawn(cmd, false, screen or capi.mouse.screen)
|
||||
end
|
||||
end
|
||||
|
||||
--- Read a program output and returns its output as a string.
|
||||
-- @param cmd The command to run.
|
||||
-- @return A string with the program output, or the error if one occured.
|
||||
function pread(cmd)
|
||||
if cmd and cmd ~= "" then
|
||||
local f, err = io.popen(cmd, 'r')
|
||||
if f then
|
||||
local s = f:read("*all")
|
||||
f:close()
|
||||
return s
|
||||
else
|
||||
return err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Eval Lua code.
|
||||
-- @return The return value of Lua code.
|
||||
function eval(s)
|
||||
return assert(loadstring(s))()
|
||||
end
|
||||
|
||||
local xml_entity_names = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
|
||||
--- Escape a string from XML char.
|
||||
-- Useful to set raw text in textbox.
|
||||
-- @param text Text to escape.
|
||||
-- @return Escape text.
|
||||
function escape(text)
|
||||
return text and text:gsub("['&<>\"]", xml_entity_names) or nil
|
||||
end
|
||||
|
||||
local xml_entity_chars = { lt = "<", gt = ">", nbsp = " ", quot = "\"", apos = "'", ndash = "-", mdash = "-", amp = "&" };
|
||||
--- Unescape a string from entities.
|
||||
-- @param text Text to unescape.
|
||||
-- @return Unescaped text.
|
||||
function unescape(text)
|
||||
return text and text:gsub("&(%a+);", xml_entity_chars) or nil
|
||||
end
|
||||
|
||||
--- Check if a file is a Lua valid file.
|
||||
-- This is done by loading the content and compiling it with loadfile().
|
||||
-- @param path The file path.
|
||||
-- @return A function if everything is alright, a string with the error
|
||||
-- otherwise.
|
||||
function checkfile(path)
|
||||
local f, e = loadfile(path)
|
||||
-- Return function if function, otherwise return error.
|
||||
if f then return f end
|
||||
return e
|
||||
end
|
||||
|
||||
--- Try to restart awesome.
|
||||
-- It checks if the configuration file is valid, and then restart if it's ok.
|
||||
-- If it's not ok, the error will be returned.
|
||||
-- @return Never return if awesome restart, or return a string error.
|
||||
function restart()
|
||||
local c = checkfile(capi.awesome.conffile)
|
||||
|
||||
if type(c) ~= "function" then
|
||||
return c
|
||||
end
|
||||
|
||||
capi.awesome.restart()
|
||||
end
|
||||
|
||||
--- Get the user's config or cache dir.
|
||||
-- It first checks XDG_CONFIG_HOME / XDG_CACHE_HOME, but then goes with the
|
||||
-- default paths.
|
||||
-- @param d The directory to get (either "config" or "cache").
|
||||
-- @return A string containing the requested path.
|
||||
function getdir(d)
|
||||
if d == "config" then
|
||||
local dir = os.getenv("XDG_CONFIG_HOME")
|
||||
if dir then
|
||||
return dir .. "/awesome"
|
||||
end
|
||||
return os.getenv("HOME") .. "/.config/awesome"
|
||||
elseif d == "cache" then
|
||||
local dir = os.getenv("XDG_CACHE_HOME")
|
||||
if dir then
|
||||
return dir .. "/awesome"
|
||||
end
|
||||
return os.getenv("HOME").."/.cache/awesome"
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if file exists and is readable.
|
||||
-- @param filename The file path
|
||||
-- @return True if file exists and readable.
|
||||
function file_readable(filename)
|
||||
local file = io.open(filename)
|
||||
if file then
|
||||
io.close(file)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function subset_mask_apply(mask, set)
|
||||
local ret = {}
|
||||
for i = 1, #set do
|
||||
if mask[i] then
|
||||
rtable.insert(ret, set[i])
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function subset_next(mask)
|
||||
local i = 1
|
||||
while i <= #mask and mask[i] do
|
||||
mask[i] = false
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if i <= #mask then
|
||||
mask[i] = 1
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Return all subsets of a specific set.
|
||||
-- This function, giving a set, will return all subset it.
|
||||
-- For example, if we consider a set with value { 10, 15, 34 },
|
||||
-- it will return a table containing 2^n set:
|
||||
-- { }, { 10 }, { 15 }, { 34 }, { 10, 15 }, { 10, 34 }, etc.
|
||||
-- @param set A set.
|
||||
-- @return A table with all subset.
|
||||
function subsets(set)
|
||||
local mask = {}
|
||||
local ret = {}
|
||||
for i = 1, #set do mask[i] = false end
|
||||
|
||||
-- Insert the empty one
|
||||
rtable.insert(ret, {})
|
||||
|
||||
while subset_next(mask) do
|
||||
rtable.insert(ret, subset_mask_apply(mask, set))
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Join all tables given as parameters.
|
||||
-- This will iterate all tables and insert all their keys into a new table.
|
||||
-- @param args A list of tables to join
|
||||
-- @return A new table containing all keys from the arguments.
|
||||
function table.join(...)
|
||||
local ret = {}
|
||||
for i, t in ipairs({...}) do
|
||||
if t then
|
||||
for k, v in pairs(t) do
|
||||
if type(k) == "number" then
|
||||
rtable.insert(ret, v)
|
||||
else
|
||||
ret[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Check if a table has an item and return its key.
|
||||
-- @param t The table.
|
||||
-- @param item The item to look for in values of the table.
|
||||
-- @return The key were the item is found, or nil if not found.
|
||||
function table.hasitem(t, item)
|
||||
for k, v in pairs(t) do
|
||||
if v == item then
|
||||
return k
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Split a string into multiple lines
|
||||
-- @param text String to wrap.
|
||||
-- @param width Maximum length of each line. Default: 72.
|
||||
-- @param indent Number of spaces added before each wrapped line. Default: 0.
|
||||
-- @return The string with lines wrapped to width.
|
||||
function linewrap(text, width, indent)
|
||||
local text = text or ""
|
||||
local width = width or 72
|
||||
local indent = indent or 0
|
||||
|
||||
local pos = 1
|
||||
return text:gsub("(%s+)()(%S+)()",
|
||||
function(sp, st, word, fi)
|
||||
if fi - pos > width then
|
||||
pos = st
|
||||
return "\n" .. string.rep(" ", indent) .. word
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Get a sorted table with all integer keys from a table
|
||||
-- @param t the table for which the keys to get
|
||||
-- @return A table with keys
|
||||
function table.keys(t)
|
||||
local keys = { }
|
||||
for k, _ in pairs(t) do
|
||||
rtable.insert(keys, k)
|
||||
end
|
||||
rtable.sort(keys, function (a, b)
|
||||
return type(a) == type(b) and a < b or false
|
||||
end)
|
||||
return keys
|
||||
end
|
||||
|
||||
--- Filter a tables keys for certain content types
|
||||
-- @param t The table to retrieve the keys for
|
||||
-- @param ... the types to look for
|
||||
-- @return A filtered table with keys
|
||||
function table.keys_filter(t, ...)
|
||||
local keys = table.keys(t)
|
||||
local keys_filtered = { }
|
||||
for _, k in pairs(keys) do
|
||||
for _, et in pairs({...}) do
|
||||
if type(t[k]) == et then
|
||||
rtable.insert(keys_filtered, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return keys_filtered
|
||||
end
|
||||
|
||||
--- Reverse a table
|
||||
-- @param t the table to reverse
|
||||
-- @return the reversed table
|
||||
function table.reverse(t)
|
||||
local tr = { }
|
||||
-- reverse all elements with integer keys
|
||||
for _, v in ipairs(t) do
|
||||
rtable.insert(tr, 1, v)
|
||||
end
|
||||
-- add the remaining elements
|
||||
for k, v in pairs(t) do
|
||||
if type(k) ~= "number" then
|
||||
tr[k] = v
|
||||
end
|
||||
end
|
||||
return tr
|
||||
end
|
||||
|
||||
--- Clone a table
|
||||
-- @param t the table to clone
|
||||
-- @return a clone of t
|
||||
function table.clone(t)
|
||||
local c = { }
|
||||
for k, v in pairs(t) do
|
||||
c[k] = v
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
345
Old/ATARI/home/burchettm/.config/awesome/lib/awful/wibox.lua
Normal file
345
Old/ATARI/home/burchettm/.config/awesome/lib/awful/wibox.lua
Normal file
@ -0,0 +1,345 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
screen = screen,
|
||||
wibox = wibox,
|
||||
client = client
|
||||
}
|
||||
local setmetatable = setmetatable
|
||||
local tostring = tostring
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local type = type
|
||||
local image = image
|
||||
local error = error
|
||||
|
||||
--- Wibox module for awful.
|
||||
-- This module allows you to easily create wibox and attach them to the edge of
|
||||
-- a screen.
|
||||
module("awful.wibox")
|
||||
|
||||
-- Array of table with wiboxes inside.
|
||||
-- It's an array so it is ordered.
|
||||
local wiboxes = {}
|
||||
|
||||
--- Get a wibox position if it has been set, or return top.
|
||||
-- @param wibox The wibox
|
||||
-- @return The wibox position.
|
||||
function get_position(wibox)
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
if wprop.wibox == wibox then
|
||||
return wprop.position
|
||||
end
|
||||
end
|
||||
return "top"
|
||||
end
|
||||
|
||||
--- Put a wibox on a screen at this position.
|
||||
-- @param wibox The wibox to attach.
|
||||
-- @param position The position: top, bottom left or right.
|
||||
-- @param screen If the wibox it not attached to a screen, specified on which
|
||||
-- screen the position should be set.
|
||||
function set_position(wibox, position, screen)
|
||||
local screen = screen or wibox.screen or 1
|
||||
local area = capi.screen[screen].geometry
|
||||
|
||||
-- The "length" of a wibox is always chosen to be the optimal size
|
||||
-- (non-floating).
|
||||
-- The "width" of a wibox is kept if it exists.
|
||||
if position == "right" then
|
||||
wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
|
||||
elseif position == "left" then
|
||||
wibox.x = area.x
|
||||
elseif position == "bottom" then
|
||||
wibox.y = (area.y + area.height) - (wibox.height + 2 * wibox.border_width)
|
||||
elseif position == "top" then
|
||||
wibox.y = area.y
|
||||
end
|
||||
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
if wprop.wibox == wibox then
|
||||
wprop.position = position
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset all wiboxes positions.
|
||||
local function update_all_wiboxes_position()
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
set_position(wprop.wibox, wprop.position)
|
||||
end
|
||||
end
|
||||
|
||||
local function call_wibox_position_hook_on_prop_update(w)
|
||||
update_all_wiboxes_position()
|
||||
end
|
||||
|
||||
local function wibox_update_strut(wibox)
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
if wprop.wibox == wibox then
|
||||
if not wibox.visible then
|
||||
wibox:struts { left = 0, right = 0, bottom = 0, top = 0 }
|
||||
elseif wprop.position == "top" then
|
||||
wibox:struts { left = 0, right = 0, bottom = 0, top = wibox.height + 2 * wibox.border_width }
|
||||
elseif wprop.position == "bottom" then
|
||||
wibox:struts { left = 0, right = 0, bottom = wibox.height + 2 * wibox.border_width, top = 0 }
|
||||
elseif wprop.position == "left" then
|
||||
wibox:struts { left = wibox.width + 2 * wibox.border_width, right = 0, bottom = 0, top = 0 }
|
||||
elseif wprop.position == "right" then
|
||||
wibox:struts { left = 0, right = wibox.width + 2 * wibox.border_width, bottom = 0, top = 0 }
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Attach a wibox to a screen.
|
||||
-- If a wibox is attached, it will be automatically be moved when other wiboxes
|
||||
-- will be attached.
|
||||
-- @param wibox The wibox to attach.
|
||||
-- @param position The position of the wibox: top, bottom, left or right.
|
||||
function attach(wibox, position)
|
||||
-- Store wibox as attached in a weak-valued table
|
||||
local wibox_prop_table
|
||||
-- Start from end since we sometimes remove items
|
||||
for i = #wiboxes, 1, -1 do
|
||||
-- Since wiboxes are stored as weak value, they can disappear.
|
||||
-- If they did, remove their entries
|
||||
if wiboxes[i].wibox == nil then
|
||||
table.remove(wiboxes, i)
|
||||
elseif wiboxes[i].wibox == wibox then
|
||||
wibox_prop_table = wiboxes[i]
|
||||
-- We could break here, but well, let's check if there is no other
|
||||
-- table with their wiboxes been garbage collected.
|
||||
end
|
||||
end
|
||||
|
||||
if not wibox_prop_table then
|
||||
table.insert(wiboxes, setmetatable({ wibox = wibox, position = position }, { __mode = 'v' }))
|
||||
else
|
||||
wibox_prop_table.position = position
|
||||
end
|
||||
|
||||
wibox:add_signal("property::width", wibox_update_strut)
|
||||
wibox:add_signal("property::height", wibox_update_strut)
|
||||
wibox:add_signal("property::visible", wibox_update_strut)
|
||||
|
||||
wibox:add_signal("property::screen", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::width", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::height", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::visible", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::border_width", call_wibox_position_hook_on_prop_update)
|
||||
end
|
||||
|
||||
--- Align a wibox.
|
||||
-- @param wibox The wibox.
|
||||
-- @param align The alignment: left, right or center.
|
||||
-- @param screen If the wibox is not attached to any screen, you can specify the
|
||||
-- screen where to align. Otherwise 1 is assumed.
|
||||
function align(wibox, align, screen)
|
||||
local position = get_position(wibox)
|
||||
local screen = screen or wibox.screen or 1
|
||||
local area = capi.screen[screen].workarea
|
||||
|
||||
if position == "right" then
|
||||
if align == "right" then
|
||||
wibox.y = area.y
|
||||
elseif align == "left" then
|
||||
wibox.y = area.y + area.height - (wibox.height + 2 * wibox.border_width)
|
||||
elseif align == "center" then
|
||||
wibox.y = area.y + (area.height - wibox.height) / 2
|
||||
end
|
||||
elseif position == "left" then
|
||||
if align == "right" then
|
||||
wibox.y = (area.y + area.height) - (wibox.height + 2 * wibox.border_width)
|
||||
elseif align == "left" then
|
||||
wibox.y = area.y
|
||||
elseif align == "center" then
|
||||
wibox.y = area.y + (area.height - wibox.height) / 2
|
||||
end
|
||||
elseif position == "bottom" then
|
||||
if align == "right" then
|
||||
wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
|
||||
elseif align == "left" then
|
||||
wibox.x = area.x
|
||||
elseif align == "center" then
|
||||
wibox.x = area.x + (area.width - wibox.width) / 2
|
||||
end
|
||||
elseif position == "top" then
|
||||
if align == "right" then
|
||||
wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
|
||||
elseif align == "left" then
|
||||
wibox.x = area.x
|
||||
elseif align == "center" then
|
||||
wibox.x = area.x + (area.width - wibox.width) / 2
|
||||
end
|
||||
end
|
||||
|
||||
-- Update struts regardless of changes
|
||||
wibox_update_strut(wibox)
|
||||
end
|
||||
|
||||
--- Stretch a wibox so it takes all screen width or height.
|
||||
-- @param wibox The wibox.
|
||||
-- @param screen The screen to stretch on, or the wibox screen.
|
||||
function stretch(wibox, screen)
|
||||
local screen = screen or wibox.screen
|
||||
if screen then
|
||||
local position = get_position(wibox)
|
||||
local area = capi.screen[screen].workarea
|
||||
if position == "right" or position == "left" then
|
||||
wibox.height = area.height - (2 * wibox.border_width)
|
||||
wibox.y = area.y
|
||||
else
|
||||
wibox.width = area.width - (2 * wibox.border_width)
|
||||
wibox.x = area.x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a new wibox and attach it to a screen edge.
|
||||
-- @see capi.wibox
|
||||
-- @param args A table with standard arguments to wibox() creator.
|
||||
-- You can add also position key with value top, bottom, left or right.
|
||||
-- You can also use width or height in % and set align to center, right or left.
|
||||
-- You can also set the screen key with a screen number to attach the wibox.
|
||||
-- If not specified, 1 is assumed.
|
||||
-- @return The wibox created.
|
||||
function new(arg)
|
||||
local arg = arg or {}
|
||||
local position = arg.position or "top"
|
||||
local has_to_stretch = true
|
||||
-- Empty position and align in arg so we are passing deprecation warning
|
||||
arg.position = nil
|
||||
|
||||
if position ~= "top" and position ~="bottom"
|
||||
and position ~= "left" and position ~= "right" then
|
||||
error("Invalid position in awful.wibox(), you may only use"
|
||||
.. " 'top', 'bottom', 'left' and 'right'")
|
||||
end
|
||||
|
||||
-- Set default size
|
||||
if position == "left" or position == "right" then
|
||||
arg.width = arg.width or capi.awesome.font_height * 1.5
|
||||
if arg.height then
|
||||
has_to_stretch = false
|
||||
if arg.screen then
|
||||
local hp = tostring(arg.height):match("(%d+)%%")
|
||||
if hp then
|
||||
arg.height = capi.screen[arg.screen].geometry.height * hp / 100
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
arg.height = arg.height or capi.awesome.font_height * 1.5
|
||||
if arg.width then
|
||||
has_to_stretch = false
|
||||
if arg.screen then
|
||||
local wp = tostring(arg.width):match("(%d+)%%")
|
||||
if wp then
|
||||
arg.width = capi.screen[arg.screen].geometry.width * wp / 100
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local w = capi.wibox(arg)
|
||||
|
||||
if position == "left" then
|
||||
w.orientation = "north"
|
||||
elseif position == "right" then
|
||||
w.orientation = "south"
|
||||
end
|
||||
|
||||
w.screen = arg.screen or 1
|
||||
|
||||
attach(w, position)
|
||||
if has_to_stretch then
|
||||
stretch(w)
|
||||
else
|
||||
align(w, arg.align)
|
||||
end
|
||||
|
||||
set_position(w, position)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
local function do_rounded_corners(width, height, corner)
|
||||
local img = image.argb32(width, height, nil)
|
||||
|
||||
-- The image starts completely black which is fully opaque for our use
|
||||
|
||||
local function transp_rect(x, y)
|
||||
img:draw_rectangle(x, y, corner, corner, true, "#ffffff")
|
||||
end
|
||||
local function opaque_circle(x, y)
|
||||
-- x, y are the center of the circle
|
||||
img:draw_circle(x, y, corner, corner, true, "#000000")
|
||||
end
|
||||
|
||||
-- Upper left corner
|
||||
-- First make a 'corner times corner' rectangle transparent
|
||||
transp_rect(0, 0)
|
||||
-- Then add the rounded corner
|
||||
opaque_circle(corner, corner)
|
||||
|
||||
-- Upper right corner
|
||||
transp_rect(width - corner, 0)
|
||||
opaque_circle(width - corner - 1, corner)
|
||||
|
||||
-- Bottom left corner
|
||||
transp_rect(0, height - corner)
|
||||
opaque_circle(corner, height - corner - 1)
|
||||
|
||||
-- Bottom right corner
|
||||
transp_rect(width - corner, height - corner)
|
||||
opaque_circle(width - corner - 1, height - corner - 1)
|
||||
|
||||
return img
|
||||
end
|
||||
|
||||
--- Add rounded corners to a wibox
|
||||
-- @param wibox The wibox.
|
||||
-- @param corner_size The size in pixel of the rounded corners.
|
||||
function rounded_corners(wibox, corner_size)
|
||||
local border = wibox.border_width
|
||||
|
||||
-- Corners can't be larger than half the wibox' space
|
||||
if wibox.width / 2 < corner_size then
|
||||
corner_size = wibox.width / 2
|
||||
end
|
||||
if wibox.height / 2 < corner_size then
|
||||
corner_size = wibox.height / 2
|
||||
end
|
||||
|
||||
wibox.shape_clip = do_rounded_corners(wibox.width, wibox.height, corner_size)
|
||||
wibox.shape_bounding = do_rounded_corners(wibox.width + border * 2, wibox.height + border * 2, corner_size + border)
|
||||
end
|
||||
|
||||
local function update_wiboxes_on_struts(c)
|
||||
local struts = c:struts()
|
||||
if struts.left ~= 0 or struts.right ~= 0
|
||||
or struts.top ~= 0 or struts.bottom ~= 0 then
|
||||
update_all_wiboxes_position()
|
||||
end
|
||||
end
|
||||
|
||||
-- Hook registered to reset all wiboxes position.
|
||||
capi.client.add_signal("manage", function(c)
|
||||
update_wiboxes_on_struts(c)
|
||||
c:add_signal("property::struts", update_wiboxes_on_struts)
|
||||
end)
|
||||
capi.client.add_signal("unmanage", update_wiboxes_on_struts)
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,45 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
local button = require("awful.button")
|
||||
local capi = { image = image,
|
||||
widget = widget,
|
||||
mouse = mouse }
|
||||
|
||||
module("awful.widget.button")
|
||||
|
||||
--- Create a button widget. When clicked, the image is deplaced to make it like
|
||||
-- a real button.
|
||||
-- @param args Standard widget table arguments, plus image for the image path or
|
||||
-- the image object.
|
||||
-- @return A textbox widget configured as a button.
|
||||
function new(args)
|
||||
if not args or not args.image then return end
|
||||
local img_release
|
||||
if type(args.image) == "string" then
|
||||
img_release = capi.image(args.image)
|
||||
elseif type(args.image) == "image" then
|
||||
img_release = args.image
|
||||
else
|
||||
return
|
||||
end
|
||||
local img_press = img_release:crop(-2, -2, img_release.width, img_release.height)
|
||||
args.type = "imagebox"
|
||||
local w = capi.widget(args)
|
||||
w.image = img_release
|
||||
w:buttons(button({}, 1, function () w.image = img_press end, function () w.image = img_release end))
|
||||
w:add_signal("mouse::leave", function () w.image = img_release end)
|
||||
w:add_signal("mouse::enter", function ()
|
||||
if capi.mouse.coords().buttons[1] then w.image = img_press end
|
||||
end)
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,98 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local math = math
|
||||
local type = type
|
||||
local pcall = pcall
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local capi = { widget = widget, button = button }
|
||||
|
||||
--- Common widget code
|
||||
module("awful.widget.common")
|
||||
|
||||
-- Private structures
|
||||
tagwidgets = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
function list_update(w, buttons, label, data, widgets, objects)
|
||||
-- Hack: if it has been registered as a widget in a wibox,
|
||||
-- it's w.len since __len meta does not work on table until Lua 5.2.
|
||||
-- Otherwise it's standard #w.
|
||||
local len = (w.len or #w) / 2
|
||||
-- Add more widgets
|
||||
if len < #objects then
|
||||
for i = len * 2 + 1, #objects * 2, 2 do
|
||||
local ib = capi.widget({ type = "imagebox", align = widgets.imagebox.align })
|
||||
local tb = capi.widget({ type = "textbox", align = widgets.textbox.align })
|
||||
|
||||
w[i] = ib
|
||||
w[i + 1] = tb
|
||||
w[i + 1]:margin({ left = widgets.textbox.margin.left, right = widgets.textbox.margin.right })
|
||||
w[i + 1].bg_resize = widgets.textbox.bg_resize or false
|
||||
w[i + 1].bg_align = widgets.textbox.bg_align or ""
|
||||
|
||||
if type(objects[math.floor(i / 2) + 1]) == "tag" then
|
||||
tagwidgets[ib] = objects[math.floor(i / 2) + 1]
|
||||
tagwidgets[tb] = objects[math.floor(i / 2) + 1]
|
||||
end
|
||||
end
|
||||
-- Remove widgets
|
||||
elseif len > #objects then
|
||||
for i = #objects * 2 + 1, len * 2, 2 do
|
||||
w[i] = nil
|
||||
w[i + 1] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- update widgets text
|
||||
for k = 1, #objects * 2, 2 do
|
||||
local o = objects[(k + 1) / 2]
|
||||
if buttons then
|
||||
-- Use a local variable so that the garbage collector doesn't strike
|
||||
-- between now and the :buttons() call.
|
||||
local btns = data[o]
|
||||
if not btns then
|
||||
btns = {}
|
||||
data[o] = btns
|
||||
for kb, b in ipairs(buttons) do
|
||||
-- Create a proxy button object: it will receive the real
|
||||
-- press and release events, and will propagate them the the
|
||||
-- button object the user provided, but with the object as
|
||||
-- argument.
|
||||
local btn = capi.button { modifiers = b.modifiers, button = b.button }
|
||||
btn:add_signal("press", function () b:emit_signal("press", o) end)
|
||||
btn:add_signal("release", function () b:emit_signal("release", o) end)
|
||||
btns[#btns + 1] = btn
|
||||
end
|
||||
end
|
||||
w[k]:buttons(btns)
|
||||
w[k + 1]:buttons(btns)
|
||||
end
|
||||
|
||||
local text, bg, bg_image, icon = label(o)
|
||||
|
||||
-- Check if we got a valid text here, it might contain e.g. broken utf8.
|
||||
if not pcall(function() w[k + 1].text = text end) then
|
||||
w[k + 1].text = "<i>Invalid</i>"
|
||||
end
|
||||
|
||||
w[k + 1].bg, w[k + 1].bg_image = bg, bg_image
|
||||
w[k].bg, w[k].image = bg, icon
|
||||
if not w[k + 1].text then
|
||||
w[k+1].visible = false
|
||||
else
|
||||
w[k+1].visible = true
|
||||
end
|
||||
if not w[k].image then
|
||||
w[k].visible = false
|
||||
else
|
||||
w[k].visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,301 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local table = table
|
||||
local type = type
|
||||
local capi = { image = image,
|
||||
widget = widget }
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- A graph widget.
|
||||
module("awful.widget.graph")
|
||||
|
||||
local data = setmetatable({}, { __mode = "k" })
|
||||
|
||||
--- Set the graph border color.
|
||||
-- If the value is nil, no border will be drawn.
|
||||
-- @name set_border_color
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param color The border color to set.
|
||||
|
||||
--- Set the graph foreground color as a gradient.
|
||||
-- @name set_gradient_colors
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param gradient_colors A table with gradients colors. The distance between each color
|
||||
-- can also be specified. Example: { "red", "blue" } or { "red", "green",
|
||||
-- "blue", blue = 10 } to specify blue distance from other colors.
|
||||
|
||||
--- Set the graph foreground colors gradient angle. Default is 270 degrees
|
||||
-- (horizontal).
|
||||
-- @name set_gradient_angle
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param gradient_angle Angle of gradient in degrees.
|
||||
|
||||
--- Set the graph foreground color.
|
||||
-- @name set_color
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param color The graph color.
|
||||
|
||||
--- Set the graph background color.
|
||||
-- @name set_background_color
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param color The graph background color.
|
||||
|
||||
--- Set the maximum value the graph should handle.
|
||||
-- If "scale" is also set, the graph never scales up below this value, but it
|
||||
-- automatically scales down to make all data fit.
|
||||
-- @name set_max_value
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param value The value.
|
||||
|
||||
--- Set the graph to automatically scale its values. Default is false.
|
||||
-- @name set_scale
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param scale A boolean value
|
||||
|
||||
--- Set the graph to draw stacks. Default is false.
|
||||
-- @name set_stack
|
||||
-- @class function
|
||||
-- @param progressbar The graph.
|
||||
-- @param stack A boolean value.
|
||||
|
||||
--- Set the graph stacking colors. Order matters.
|
||||
-- @name set_stack_colors
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param stack_colors A table with stacking colors.
|
||||
|
||||
local properties = { "width", "height", "border_color", "stack",
|
||||
"stack_colors", "gradient_colors", "gradient_angle",
|
||||
"color", "background_color", "max_value", "scale" }
|
||||
|
||||
local function update(graph)
|
||||
-- Create new empty image
|
||||
local img = capi.image.argb32(data[graph].width, data[graph].height, nil)
|
||||
local max_value = data[graph].max_value
|
||||
local values = data[graph].values
|
||||
|
||||
local border_width = 0
|
||||
if data[graph].border_color then
|
||||
border_width = 1
|
||||
end
|
||||
|
||||
-- Draw a stacked graph
|
||||
if data[graph].stack then
|
||||
|
||||
if data[graph].scale then
|
||||
for _, v in ipairs(values) do
|
||||
for __, sv in ipairs(v) do
|
||||
if sv > max_value then
|
||||
max_value = sv
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw the background first
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
data[graph].width - (2 * border_width),
|
||||
data[graph].height,
|
||||
true, data[graph].background_color or "#000000aa")
|
||||
|
||||
for i = 0, data[graph].width - (2 * border_width) do
|
||||
local rel_i = 0
|
||||
local rel_x = data[graph].width - border_width - i - 1
|
||||
|
||||
if data[graph].stack_colors then
|
||||
for idx, color in ipairs(data[graph].stack_colors) do
|
||||
local stack_values = values[idx]
|
||||
if stack_values and i < #stack_values then
|
||||
local value = stack_values[#stack_values - i] + rel_i
|
||||
|
||||
img:draw_line(rel_x, border_width - 1 +
|
||||
math.ceil((data[graph].height - 2 * border_width) * (1 - (rel_i / max_value))),
|
||||
rel_x, border_width - 1 +
|
||||
math.ceil((data[graph].height - 2 * border_width) * (1 - (value / max_value))),
|
||||
color or "red")
|
||||
rel_i = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
if data[graph].scale then
|
||||
for _, v in ipairs(values) do
|
||||
if v > max_value then
|
||||
max_value = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw full gradient
|
||||
if data[graph].gradient_colors then
|
||||
img:draw_rectangle_gradient(border_width, border_width,
|
||||
data[graph].width - (2 * border_width),
|
||||
data[graph].height - (2 * border_width),
|
||||
data[graph].gradient_colors,
|
||||
data[graph].gradient_angle or 270)
|
||||
else
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
data[graph].width - (2 * border_width),
|
||||
data[graph].height - (2 * border_width),
|
||||
true, data[graph].color or "red")
|
||||
end
|
||||
|
||||
-- Draw the background on no value
|
||||
if #values ~= 0 then
|
||||
-- Draw reverse
|
||||
for i = 0, #values - 1 do
|
||||
local value = values[#values - i]
|
||||
if value >= 0 then
|
||||
value = value / max_value
|
||||
img:draw_line(data[graph].width - border_width - i - 1,
|
||||
border_width - 1 +
|
||||
math.ceil((data[graph].height - 2 * border_width) * (1 - value)),
|
||||
data[graph].width - border_width - i - 1,
|
||||
border_width - 1,
|
||||
data[graph].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- If we didn't draw values in full length, draw a square
|
||||
-- over the last, left, part to reset everything to 0
|
||||
if #values < data[graph].width - (2 * border_width) then
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
data[graph].width - (2 * border_width) - #values,
|
||||
data[graph].height - (2 * border_width),
|
||||
true, data[graph].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw the border last so that it overlaps already drawn values
|
||||
if data[graph].border_color then
|
||||
-- Draw the border
|
||||
img:draw_rectangle(0, 0, data[graph].width, data[graph].height,
|
||||
false, data[graph].border_color or "white")
|
||||
end
|
||||
|
||||
-- Update the image
|
||||
graph.widget.image = img
|
||||
end
|
||||
|
||||
--- Add a value to the graph
|
||||
-- @param graph The graph.
|
||||
-- @param value The value between 0 and 1.
|
||||
-- @param group The stack color group index.
|
||||
local function add_value(graph, value, group)
|
||||
if not graph then return end
|
||||
|
||||
local value = value or 0
|
||||
local values = data[graph].values
|
||||
local max_value = data[graph].max_value
|
||||
value = math.max(0, value)
|
||||
if not data[graph].scale then
|
||||
value = math.min(max_value, value)
|
||||
end
|
||||
|
||||
if data[graph].stack and group then
|
||||
if not data[graph].values[group]
|
||||
or type(data[graph].values[group]) ~= "table"
|
||||
then
|
||||
data[graph].values[group] = {}
|
||||
end
|
||||
values = data[graph].values[group]
|
||||
end
|
||||
table.insert(values, value)
|
||||
|
||||
local border_width = 0
|
||||
if data[graph].border then border_width = 2 end
|
||||
|
||||
-- Ensure we never have more data than we can draw
|
||||
while #values > data[graph].width - border_width do
|
||||
table.remove(values, 1)
|
||||
end
|
||||
|
||||
update(graph)
|
||||
return graph
|
||||
end
|
||||
|
||||
|
||||
--- Set the graph height.
|
||||
-- @param graph The graph.
|
||||
-- @param height The height to set.
|
||||
function set_height(graph, height)
|
||||
if height >= 5 then
|
||||
data[graph].height = height
|
||||
update(graph)
|
||||
end
|
||||
return graph
|
||||
end
|
||||
|
||||
--- Set the graph width.
|
||||
-- @param graph The graph.
|
||||
-- @param width The width to set.
|
||||
function set_width(graph, width)
|
||||
if width >= 5 then
|
||||
data[graph].width = width
|
||||
update(graph)
|
||||
end
|
||||
return graph
|
||||
end
|
||||
|
||||
-- Build properties function
|
||||
for _, prop in ipairs(properties) do
|
||||
if not _M["set_" .. prop] then
|
||||
_M["set_" .. prop] = function(graph, value)
|
||||
data[graph][prop] = value
|
||||
update(graph)
|
||||
return graph
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a graph widget.
|
||||
-- @param args Standard widget() arguments. You should add width and height
|
||||
-- key to set graph geometry.
|
||||
-- @return A graph widget.
|
||||
function new(args)
|
||||
local args = args or {}
|
||||
args.type = "imagebox"
|
||||
|
||||
local width = args.width or 100
|
||||
local height = args.height or 20
|
||||
|
||||
if width < 5 or height < 5 then return end
|
||||
|
||||
local graph = {}
|
||||
graph.widget = capi.widget(args)
|
||||
graph.widget.resize = false
|
||||
|
||||
data[graph] = { width = width, height = height, values = {}, max_value = 1 }
|
||||
|
||||
-- Set methods
|
||||
graph.add_value = add_value
|
||||
|
||||
for _, prop in ipairs(properties) do
|
||||
graph["set_" .. prop] = _M["set_" .. prop]
|
||||
end
|
||||
|
||||
graph.layout = args.layout or layout.horizontal.leftright
|
||||
|
||||
return graph
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,21 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
require("awful.widget.taglist")
|
||||
require("awful.widget.tasklist")
|
||||
require("awful.widget.button")
|
||||
require("awful.widget.launcher")
|
||||
require("awful.widget.prompt")
|
||||
require("awful.widget.progressbar")
|
||||
require("awful.widget.graph")
|
||||
require("awful.widget.layoutbox")
|
||||
require("awful.widget.textclock")
|
||||
require("awful.widget.layout")
|
||||
|
||||
--- Widget module for awful
|
||||
module("awful.widget")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,35 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local util = require("awful.util")
|
||||
local wbutton = require("awful.widget.button")
|
||||
local button = require("awful.button")
|
||||
|
||||
module("awful.widget.launcher")
|
||||
|
||||
--- Create a button widget which will launch a command.
|
||||
-- @param args Standard widget table arguments, plus image for the image path
|
||||
-- and command for the command to run on click, or either menu to create menu.
|
||||
-- @return A launcher widget.
|
||||
function new(args)
|
||||
if not args.command and not args.menu then return end
|
||||
local w = wbutton(args)
|
||||
if not w then return end
|
||||
|
||||
if args.command then
|
||||
b = util.table.join(w:buttons(), button({}, 1, nil, function () util.spawn(args.command) end))
|
||||
elseif args.menu then
|
||||
b = util.table.join(w:buttons(), button({}, 1, nil, function () args.menu:toggle() end))
|
||||
end
|
||||
|
||||
w:buttons(b)
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function (_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,58 @@
|
||||
-------------------------------------------------
|
||||
-- @author Gregor Best <farhaven@googlemail.com>
|
||||
-- @copyright 2009 Gregor Best
|
||||
-- @release v3.4.9
|
||||
-------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local table = table
|
||||
local math = math
|
||||
local setmetatable = setmetatable
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Simple default layout, emulating the fallback C layout
|
||||
module("awful.widget.layout.default")
|
||||
|
||||
local function default(bounds, widgets, screen)
|
||||
local geometries = {
|
||||
free = { x = 0, y = 0, width = 0, height = bounds.height }
|
||||
}
|
||||
|
||||
local width = 0
|
||||
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
local nbounds = util.table.clone(bounds)
|
||||
local g = layout(nbounds, v, screen)
|
||||
for _, w in ipairs(g) do
|
||||
table.insert(geometries, w)
|
||||
end
|
||||
else
|
||||
if v.visible then
|
||||
local e = v:extents(screen)
|
||||
e.x = 0
|
||||
e.y = 0
|
||||
e.width = math.min(e.width, bounds.width)
|
||||
e.height = bounds.height
|
||||
width = math.max(e.width, width)
|
||||
|
||||
table.insert(geometries, e)
|
||||
else
|
||||
table.insert(geometries, { x = 0, y = 0, width = 0, height = 0 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
geometries.free.width = bounds.width - width
|
||||
geometries.free.x = width
|
||||
|
||||
return geometries
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return default(...) end })
|
@ -0,0 +1,188 @@
|
||||
-------------------------------------------------
|
||||
-- @author Gregor Best <farhaven@googlemail.com>
|
||||
-- @copyright 2009 Gregor Best
|
||||
-- @release v3.4.9
|
||||
-------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local table = table
|
||||
local math = math
|
||||
local util = require("awful.util")
|
||||
local default = require("awful.widget.layout.default")
|
||||
local margins = awful.widget.layout.margins
|
||||
|
||||
--- Horizontal widget layout
|
||||
module("awful.widget.layout.horizontal")
|
||||
|
||||
local function horizontal(direction, bounds, widgets, screen)
|
||||
local geometries = { }
|
||||
local x = 0
|
||||
|
||||
-- we are only interested in tables and widgets
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
if margins[v] then
|
||||
bounds.width = bounds.width - (margins[v].left or 0) - (margins[v].right or 0)
|
||||
bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
|
||||
end
|
||||
local g = layout(bounds, v, screen)
|
||||
if margins[v] then
|
||||
x = x + (margins[v].left or 0)
|
||||
end
|
||||
for _, v in ipairs(g) do
|
||||
v.x = v.x + x
|
||||
v.y = v.y + (margins[v] and (margins[v].top and margins[v].top or 0) or 0)
|
||||
table.insert(geometries, v)
|
||||
end
|
||||
bounds = g.free
|
||||
if margins[v] then
|
||||
x = x + g.free.x + (margins[v].right or 0)
|
||||
bounds.width = bounds.width - (margins[v].right or 0) - (margins[v].left or 0)
|
||||
else
|
||||
x = x + g.free.x
|
||||
end
|
||||
elseif type(v) == "widget" then
|
||||
local g
|
||||
if v.visible then
|
||||
g = v:extents(screen)
|
||||
if margins[v] then
|
||||
g.width = g.width + (margins[v].left or 0) + (margins[v].right or 0)
|
||||
g.height = g.height + (margins[v].top or 0) + (margins[v].bottom or 0)
|
||||
end
|
||||
else
|
||||
g = {
|
||||
width = 0,
|
||||
height = 0,
|
||||
}
|
||||
end
|
||||
|
||||
if v.resize and g.width > 0 and g.height > 0 then
|
||||
local ratio = g.width / g.height
|
||||
g.width = math.floor(bounds.height * ratio)
|
||||
g.height = bounds.height
|
||||
end
|
||||
|
||||
if g.width > bounds.width then
|
||||
g.width = bounds.width
|
||||
end
|
||||
g.height = bounds.height
|
||||
|
||||
if margins[v] then
|
||||
g.y = (margins[v].top or 0)
|
||||
else
|
||||
g.y = 0
|
||||
end
|
||||
|
||||
if direction == "leftright" then
|
||||
if margins[v] then
|
||||
g.x = x + (margins[v].left or 0)
|
||||
else
|
||||
g.x = x
|
||||
end
|
||||
x = x + g.width
|
||||
else
|
||||
if margins[v] then
|
||||
g.x = x + bounds.width - g.width + (margins[v].left or 0)
|
||||
else
|
||||
g.x = x + bounds.width - g.width
|
||||
end
|
||||
end
|
||||
bounds.width = bounds.width - g.width
|
||||
|
||||
table.insert(geometries, g)
|
||||
end
|
||||
end
|
||||
|
||||
geometries.free = util.table.clone(bounds)
|
||||
geometries.free.x = x
|
||||
geometries.free.y = 0
|
||||
|
||||
return geometries
|
||||
end
|
||||
|
||||
function flex(bounds, widgets, screen)
|
||||
local geometries = {
|
||||
free = util.table.clone(bounds)
|
||||
}
|
||||
-- the flex layout always uses the complete available place, thus we return
|
||||
-- no usable free area
|
||||
geometries.free.width = 0
|
||||
|
||||
-- we are only interested in tables and widgets
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
local nelements = 0
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
nelements = nelements + 1
|
||||
elseif type(v) == "widget" then
|
||||
local g = v:extents()
|
||||
if v.resize and g.width > 0 and g.height > 0 then
|
||||
bounds.width = bounds.width - bounds.height
|
||||
elseif g.width > 0 and g.height > 0 then
|
||||
nelements = nelements + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
nelements = (nelements == 0) and 1 or nelements
|
||||
|
||||
local x = 0
|
||||
local width = bounds.width / nelements
|
||||
|
||||
for _, k in ipairs(util.table.keys(widgets)) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
local g = layout(bounds, v, screen)
|
||||
for _, v in ipairs(g) do
|
||||
v.x = v.x + x
|
||||
table.insert(geometries, v)
|
||||
end
|
||||
bounds = g.free
|
||||
elseif type(v) == "widget" then
|
||||
local g = v:extents(screen)
|
||||
g.resize = v.resize
|
||||
|
||||
if v.resize and g.width > 0 and g.height > 0 then
|
||||
g.width = bounds.height
|
||||
g.height = bounds.height
|
||||
g.x = x
|
||||
g.y = bounds.y
|
||||
x = x + g.width
|
||||
elseif g.width > 0 and g.height > 0 then
|
||||
g.x = x
|
||||
g.y = bounds.y
|
||||
g.width = math.floor(width + 0.5)
|
||||
g.height = bounds.height
|
||||
x = x + width
|
||||
else
|
||||
g.x = 0
|
||||
g.y = 0
|
||||
g.width = 0
|
||||
g.height = 0
|
||||
end
|
||||
|
||||
table.insert(geometries, g)
|
||||
end
|
||||
end
|
||||
|
||||
return geometries
|
||||
end
|
||||
|
||||
function leftright(...)
|
||||
return horizontal("leftright", ...)
|
||||
end
|
||||
|
||||
function rightleft(...)
|
||||
return horizontal("rightleft", ...)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,23 @@
|
||||
local setmetatable = setmetatable
|
||||
local require = require
|
||||
|
||||
-- Widget layouts
|
||||
module("awful.widget.layout")
|
||||
|
||||
--- Widgets margins.
|
||||
-- <p>In this table you can set the margin you want the layout to use when
|
||||
-- positionning your widgets.
|
||||
-- For example, if you want to put 10 pixel free on left on a widget, add this:
|
||||
-- <code>
|
||||
-- awful.widget.layout.margins[mywidget] = { left = 10 }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- @name margins
|
||||
-- @class table
|
||||
margins = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
require("awful.widget.layout.horizontal")
|
||||
require("awful.widget.layout.vertical")
|
||||
require("awful.widget.layout.default")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,101 @@
|
||||
-------------------------------------------------
|
||||
-- @author Gregor Best <farhaven@googlemail.com>
|
||||
-- @copyright 2009 Gregor Best
|
||||
-- @release v3.4.9
|
||||
-------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local table = table
|
||||
local math = math
|
||||
local util = require("awful.util")
|
||||
local default = require("awful.widget.layout.default")
|
||||
|
||||
--- Vertical widget layout
|
||||
module("awful.widget.layout.vertical")
|
||||
|
||||
function flex(bounds, widgets, screen)
|
||||
local geometries = {
|
||||
free = util.table.clone(bounds)
|
||||
}
|
||||
|
||||
local y = 0
|
||||
|
||||
-- we are only interested in tables and widgets
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
local nelements = 0
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
nelements = nelements + 1
|
||||
else
|
||||
local e = v:extents()
|
||||
if v.visible and e.width > 0 and e.height > 0 then
|
||||
nelements = nelements + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if nelements == 0 then return geometries end
|
||||
local height = math.floor(bounds.height / nelements)
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
-- we need to modify the height a bit because vertical layouts always span the
|
||||
-- whole height
|
||||
nbounds = util.table.clone(bounds)
|
||||
nbounds.height = height
|
||||
local g = layout(nbounds, v, screen)
|
||||
for _, w in ipairs(g) do
|
||||
w.y = w.y + y
|
||||
table.insert(geometries, w)
|
||||
end
|
||||
y = y + height
|
||||
elseif type(v) == "widget" then
|
||||
local g
|
||||
if v.visible then
|
||||
g = v:extents(screen)
|
||||
else
|
||||
g = {
|
||||
["width"] = 0,
|
||||
["height"] = 0
|
||||
}
|
||||
end
|
||||
|
||||
g.ratio = 1
|
||||
if g.height > 0 and g.width > 0 then
|
||||
g.ratio = g.width / g.height
|
||||
end
|
||||
g.height = height
|
||||
if v.resize then
|
||||
g.width = g.height * g.ratio
|
||||
end
|
||||
g.width = math.min(g.width, bounds.width)
|
||||
geometries.free.x = math.max(geometries.free.x, g.width)
|
||||
|
||||
g.x = 0
|
||||
g.y = y
|
||||
y = y + g.height
|
||||
bounds.height = bounds.height - g.height
|
||||
|
||||
table.insert(geometries, g)
|
||||
end
|
||||
end
|
||||
|
||||
local maxw = 0
|
||||
local maxx = 0
|
||||
for _, v in ipairs(geometries) do
|
||||
if v.width > maxw then maxw = v.width end
|
||||
if v.x > maxx then maxx = v.x end
|
||||
end
|
||||
|
||||
geometries.free.width = geometries.free.width - maxw
|
||||
geometries.free.x = geometries.free.x + maxw
|
||||
|
||||
geometries.free.height = nelements * height
|
||||
geometries.free.y = 0
|
||||
|
||||
return geometries
|
||||
end
|
@ -0,0 +1,53 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local button = require("awful.button")
|
||||
local layout = require("awful.layout")
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local capi = { image = image,
|
||||
screen = screen,
|
||||
widget = widget }
|
||||
|
||||
--- Layoutbox widget.
|
||||
module("awful.widget.layoutbox")
|
||||
|
||||
local function update(w, screen)
|
||||
local layout = layout.getname(layout.get(screen))
|
||||
if layout and beautiful["layout_" ..layout] then
|
||||
w.image = capi.image(beautiful["layout_" ..layout])
|
||||
else
|
||||
w.image = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a layoutbox widget. It draws a picture with the current layout
|
||||
-- symbol of the current tag.
|
||||
-- @param screen The screen number that the layout will be represented for.
|
||||
-- @param args Standard arguments for an imagebox widget.
|
||||
-- @return An imagebox widget configured as a layoutbox.
|
||||
function new(screen, args)
|
||||
local screen = screen or 1
|
||||
local args = args or {}
|
||||
args.type = "imagebox"
|
||||
local w = capi.widget(args)
|
||||
update(w, screen)
|
||||
|
||||
local function update_on_tag_selection(tag)
|
||||
return update(w, tag.screen)
|
||||
end
|
||||
|
||||
tag.attached_add_signal(screen, "property::selected", update_on_tag_selection)
|
||||
tag.attached_add_signal(screen, "property::layout", update_on_tag_selection)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,243 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local capi = { image = image,
|
||||
widget = widget }
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- A progressbar widget.
|
||||
module("awful.widget.progressbar")
|
||||
|
||||
local data = setmetatable({}, { __mode = "k" })
|
||||
|
||||
--- Set the progressbar border color.
|
||||
-- If the value is nil, no border will be drawn.
|
||||
-- @name set_border_color
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param color The border color to set.
|
||||
|
||||
--- Set the progressbar foreground color as a gradient.
|
||||
-- @name set_gradient_colors
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param gradient_colors A table with gradients colors. The distance between each color
|
||||
-- can also be specified. Example: { "red", "blue" } or { "red", "green",
|
||||
-- "blue", blue = 10 } to specify blue distance from other colors.
|
||||
|
||||
--- Set the progressbar foreground color.
|
||||
-- @name set_color
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param color The progressbar color.
|
||||
|
||||
--- Set the progressbar background color.
|
||||
-- @name set_background_color
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param color The progressbar background color.
|
||||
|
||||
--- Set the progressbar to draw vertically. Default is false.
|
||||
-- @name set_vertical
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param vertical A boolean value.
|
||||
|
||||
--- Set the progressbar to draw ticks. Default is false.
|
||||
-- @name set_ticks
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param ticks A boolean value.
|
||||
|
||||
--- Set the progressbar ticks gap.
|
||||
-- @name set_ticks_gap
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param value The value.
|
||||
|
||||
--- Set the progressbar ticks size.
|
||||
-- @name set_ticks_size
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param value The value.
|
||||
|
||||
--- Set the maximum value the progressbar should handle.
|
||||
-- @name set_max_value
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param value The value.
|
||||
|
||||
local properties = { "width", "height", "border_color",
|
||||
"gradient_colors", "color", "background_color",
|
||||
"vertical", "value", "max_value",
|
||||
"ticks", "ticks_gap", "ticks_size" }
|
||||
|
||||
local function update(pbar)
|
||||
local width = data[pbar].width or 100
|
||||
local height = data[pbar].height or 20
|
||||
local ticks_gap = data[pbar].ticks_gap or 1
|
||||
local ticks_size = data[pbar].ticks_size or 4
|
||||
|
||||
-- Create new empty image
|
||||
local img = capi.image.argb32(width, height, nil)
|
||||
|
||||
local value = data[pbar].value
|
||||
local max_value = data[pbar].max_value
|
||||
if value >= 0 then
|
||||
value = value / max_value
|
||||
end
|
||||
|
||||
local over_drawn_width = width
|
||||
local over_drawn_height = height
|
||||
local border_width = 0
|
||||
if data[pbar].border_color then
|
||||
-- Draw border
|
||||
img:draw_rectangle(0, 0, width, height, false, data[pbar].border_color)
|
||||
over_drawn_width = width - 2 -- remove 2 for borders
|
||||
over_drawn_height = height - 2 -- remove 2 for borders
|
||||
border_width = 1
|
||||
end
|
||||
|
||||
local angle = 270
|
||||
if data[pbar].vertical then
|
||||
angle = 180
|
||||
end
|
||||
|
||||
-- Draw full gradient
|
||||
if data[pbar].gradient_colors then
|
||||
img:draw_rectangle_gradient(border_width, border_width,
|
||||
over_drawn_width, over_drawn_height,
|
||||
data[pbar].gradient_colors, angle)
|
||||
else
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
over_drawn_width, over_drawn_height,
|
||||
true, data[pbar].color or "red")
|
||||
end
|
||||
|
||||
-- Cover the part that is not set with a rectangle
|
||||
if data[pbar].vertical then
|
||||
local rel_height = math.floor(over_drawn_height * (1 - value))
|
||||
img:draw_rectangle(border_width,
|
||||
border_width,
|
||||
over_drawn_width,
|
||||
rel_height,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
|
||||
-- Place smaller pieces over the gradient if ticks are enabled
|
||||
if data[pbar].ticks then
|
||||
for i=0, height / (ticks_size+ticks_gap)-border_width do
|
||||
local rel_offset = over_drawn_height / 1 - (ticks_size+ticks_gap) * i
|
||||
|
||||
if rel_offset >= rel_height then
|
||||
img:draw_rectangle(border_width,
|
||||
rel_offset,
|
||||
over_drawn_width,
|
||||
ticks_gap,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local rel_x = math.ceil(over_drawn_width * value)
|
||||
img:draw_rectangle(border_width + rel_x,
|
||||
border_width,
|
||||
over_drawn_width - rel_x,
|
||||
over_drawn_height,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
|
||||
if data[pbar].ticks then
|
||||
for i=0, width / (ticks_size+ticks_gap)-border_width do
|
||||
local rel_offset = over_drawn_width / 1 - (ticks_size+ticks_gap) * i
|
||||
|
||||
if rel_offset <= rel_x then
|
||||
img:draw_rectangle(rel_offset,
|
||||
border_width,
|
||||
ticks_gap,
|
||||
over_drawn_height,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the image
|
||||
pbar.widget.image = img
|
||||
end
|
||||
|
||||
--- Set the progressbar value.
|
||||
-- @param pbar The progress bar.
|
||||
-- @param value The progress bar value between 0 and 1.
|
||||
function set_value(pbar, value)
|
||||
local value = value or 0
|
||||
local max_value = data[pbar].max_value
|
||||
data[pbar].value = math.min(max_value, math.max(0, value))
|
||||
update(pbar)
|
||||
return pbar
|
||||
end
|
||||
|
||||
--- Set the progressbar height.
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param height The height to set.
|
||||
function set_height(progressbar, height)
|
||||
data[progressbar].height = height
|
||||
update(progressbar)
|
||||
return progressbar
|
||||
end
|
||||
|
||||
--- Set the progressbar width.
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param width The width to set.
|
||||
function set_width(progressbar, width)
|
||||
data[progressbar].width = width
|
||||
update(progressbar)
|
||||
return progressbar
|
||||
end
|
||||
|
||||
-- Build properties function
|
||||
for _, prop in ipairs(properties) do
|
||||
if not _M["set_" .. prop] then
|
||||
_M["set_" .. prop] = function(pbar, value)
|
||||
data[pbar][prop] = value
|
||||
update(pbar)
|
||||
return pbar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a progressbar widget.
|
||||
-- @param args Standard widget() arguments. You should add width and height
|
||||
-- key to set progressbar geometry.
|
||||
-- @return A progressbar widget.
|
||||
function new(args)
|
||||
local args = args or {}
|
||||
local width = args.width or 100
|
||||
local height = args.height or 20
|
||||
|
||||
args.type = "imagebox"
|
||||
|
||||
local pbar = {}
|
||||
|
||||
pbar.widget = capi.widget(args)
|
||||
pbar.widget.resize = false
|
||||
|
||||
data[pbar] = { width = width, height = height, value = 0, max_value = 1 }
|
||||
|
||||
-- Set methods
|
||||
for _, prop in ipairs(properties) do
|
||||
pbar["set_" .. prop] = _M["set_" .. prop]
|
||||
end
|
||||
|
||||
pbar.layout = args.layout or layout.horizontal.leftright
|
||||
|
||||
return pbar
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,51 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local capi = { widget = widget }
|
||||
local completion = require("awful.completion")
|
||||
local util = require("awful.util")
|
||||
local prompt = require("awful.prompt")
|
||||
local layout = require("awful.widget.layout")
|
||||
local type = type
|
||||
|
||||
module("awful.widget.prompt")
|
||||
|
||||
--- Run method for promptbox.
|
||||
-- @param promptbox The promptbox to run.
|
||||
local function run(promptbox)
|
||||
return prompt.run({ prompt = promptbox.prompt },
|
||||
promptbox.widget,
|
||||
function (...)
|
||||
local result = util.spawn(...)
|
||||
if type(result) == "string" then
|
||||
promptbox.widget.text = result
|
||||
end
|
||||
end,
|
||||
completion.shell,
|
||||
util.getdir("cache") .. "/history")
|
||||
end
|
||||
|
||||
--- Create a prompt widget which will launch a command.
|
||||
-- @param args Standard widget table arguments, with prompt to change the
|
||||
-- default prompt.
|
||||
-- @return A launcher widget.
|
||||
function new(args)
|
||||
local args = args or {}
|
||||
local promptbox = {}
|
||||
args.type = "textbox"
|
||||
promptbox.widget = capi.widget(args)
|
||||
promptbox.widget.ellipsize = "start"
|
||||
promptbox.run = run
|
||||
promptbox.prompt = args.prompt or "Run: "
|
||||
promptbox.layout = args.layout or layout.horizontal.leftright
|
||||
return promptbox
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function (_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,196 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi = { widget = widget,
|
||||
screen = screen,
|
||||
image = image,
|
||||
client = client }
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local common = require("awful.widget.common")
|
||||
local util = require("awful.util")
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Taglist widget module for awful
|
||||
module("awful.widget.taglist")
|
||||
|
||||
label = {}
|
||||
|
||||
local function taglist_update (screen, w, label, buttons, data, widgets)
|
||||
local tags = capi.screen[screen]:tags()
|
||||
local showntags = {}
|
||||
for k, t in ipairs(tags) do
|
||||
if not tag.getproperty(t, "hide") then
|
||||
table.insert(showntags, t)
|
||||
end
|
||||
end
|
||||
common.list_update(w, buttons, label, data, widgets, showntags)
|
||||
end
|
||||
|
||||
--- Get the tag object the given widget appears on.
|
||||
-- @param widget The widget the look for.
|
||||
-- @return The tag object.
|
||||
function gettag(widget)
|
||||
return common.tagwidgets[widget]
|
||||
end
|
||||
|
||||
--- Create a new taglist widget.
|
||||
-- @param screen The screen to draw tag list for.
|
||||
-- @param label Label function to use.
|
||||
-- @param buttons A table with buttons binding to set.
|
||||
function new(screen, label, buttons)
|
||||
local w = {
|
||||
layout = layout.horizontal.leftright
|
||||
}
|
||||
local widgets = { }
|
||||
widgets.imagebox = { }
|
||||
widgets.textbox = { ["margin"] = { ["left"] = 0,
|
||||
["right"] = 0},
|
||||
["bg_resize"] = true
|
||||
}
|
||||
local data = setmetatable({}, { __mode = 'kv' })
|
||||
local u = function (s)
|
||||
if s == screen then
|
||||
taglist_update(s, w, label, buttons, data, widgets)
|
||||
end
|
||||
end
|
||||
local uc = function (c) return u(c.screen) end
|
||||
capi.client.add_signal("focus", uc)
|
||||
capi.client.add_signal("unfocus", uc)
|
||||
tag.attached_add_signal(screen, "property::selected", uc)
|
||||
tag.attached_add_signal(screen, "property::icon", uc)
|
||||
tag.attached_add_signal(screen, "property::hide", uc)
|
||||
tag.attached_add_signal(screen, "property::name", uc)
|
||||
capi.screen[screen]:add_signal("tag::attach", function(screen, tag)
|
||||
u(screen.index)
|
||||
end)
|
||||
capi.screen[screen]:add_signal("tag::detach", function(screen, tag)
|
||||
u(screen.index)
|
||||
end)
|
||||
capi.client.add_signal("new", function(c)
|
||||
c:add_signal("property::urgent", uc)
|
||||
c:add_signal("property::screen", function(c)
|
||||
-- If client change screen, refresh it anyway since we don't from
|
||||
-- which screen it was coming :-)
|
||||
u(screen)
|
||||
end)
|
||||
c:add_signal("tagged", uc)
|
||||
c:add_signal("untagged", uc)
|
||||
end)
|
||||
capi.client.add_signal("unmanage", uc)
|
||||
u(screen)
|
||||
return w
|
||||
end
|
||||
|
||||
--- Return labels for a taglist widget with all tag from screen.
|
||||
-- It returns the tag name and set a special
|
||||
-- foreground and background color for selected tags.
|
||||
-- @param t The tag.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for selected tag.
|
||||
-- fg_focus The foreground color for selected tag.
|
||||
-- bg_urgent The background color for urgent tags.
|
||||
-- fg_urgent The foreground color for urgent tags.
|
||||
-- squares_sel Optional: a user provided image for selected squares.
|
||||
-- squares_unsel Optional: a user provided image for unselected squares.
|
||||
-- squares_resize Optional: true or false to resize squares.
|
||||
-- @return A string to print, a background color, a background image and a
|
||||
-- background resize value.
|
||||
function label.all(t, args)
|
||||
if not args then args = {} end
|
||||
local theme = beautiful.get()
|
||||
local fg_focus = args.fg_focus or theme.taglist_fg_focus or theme.fg_focus
|
||||
local bg_focus = args.bg_focus or theme.taglist_bg_focus or theme.bg_focus
|
||||
local fg_urgent = args.fg_urgent or theme.taglist_fg_urgent or theme.fg_urgent
|
||||
local bg_urgent = args.bg_urgent or theme.taglist_bg_urgent or theme.bg_urgent
|
||||
local taglist_squares_sel = args.squares_sel or theme.taglist_squares_sel
|
||||
local taglist_squares_unsel = args.squares_unsel or theme.taglist_squares_unsel
|
||||
local taglist_squares_resize = theme.taglist_squares_resize or args.squares_resize or "true"
|
||||
local font = args.font or theme.taglist_font or theme.font or ""
|
||||
local text = "<span font_desc='"..font.."'>"
|
||||
local sel = capi.client.focus
|
||||
local bg_color = nil
|
||||
local fg_color = nil
|
||||
local bg_image
|
||||
local icon
|
||||
local bg_resize = false
|
||||
local is_selected = false
|
||||
if t.selected then
|
||||
bg_color = bg_focus
|
||||
fg_color = fg_focus
|
||||
end
|
||||
if sel then
|
||||
if taglist_squares_sel then
|
||||
-- Check that the selected clients is tagged with 't'.
|
||||
local seltags = sel:tags()
|
||||
for _, v in ipairs(seltags) do
|
||||
if v == t then
|
||||
bg_image = capi.image(taglist_squares_sel)
|
||||
bg_resize = taglist_squares_resize == "true"
|
||||
is_selected = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not is_selected then
|
||||
local cls = t:clients()
|
||||
if #cls > 0 and taglist_squares_unsel then
|
||||
bg_image = capi.image(taglist_squares_unsel)
|
||||
bg_resize = taglist_squares_resize == "true"
|
||||
end
|
||||
for k, c in pairs(cls) do
|
||||
if c.urgent then
|
||||
if bg_urgent then bg_color = bg_urgent end
|
||||
if fg_urgent then fg_color = fg_urgent end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not tag.getproperty(t, "icon_only") then
|
||||
if fg_color then
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_color).."'>"
|
||||
text = " " .. text.. (util.escape(t.name) or "") .." </span>"
|
||||
else
|
||||
text = text .. " " .. (util.escape(t.name) or "") .. " "
|
||||
end
|
||||
end
|
||||
text = text .. "</span>"
|
||||
if tag.geticon(t) and type(tag.geticon(t)) == "image" then
|
||||
icon = tag.geticon(t)
|
||||
elseif tag.geticon(t) then
|
||||
icon = capi.image(tag.geticon(t))
|
||||
end
|
||||
|
||||
return text, bg_color, bg_image, icon
|
||||
end
|
||||
|
||||
--- Return labels for a taglist widget with all *non empty* tags from screen.
|
||||
-- It returns the tag name and set a special
|
||||
-- foreground and background color for selected tags.
|
||||
-- @param t The tag.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for selected tag.
|
||||
-- fg_focus The foreground color for selected tag.
|
||||
-- bg_urgent The background color for urgent tags.
|
||||
-- fg_urgent The foreground color for urgent tags.
|
||||
-- @return A string to print, a background color, a background image and a
|
||||
-- background resize value.
|
||||
function label.noempty(t, args)
|
||||
if #t:clients() > 0 or t.selected then
|
||||
return label.all(t, args)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,212 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi = { screen = screen,
|
||||
image = image,
|
||||
client = client }
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local table = table
|
||||
local common = require("awful.widget.common")
|
||||
local beautiful = require("beautiful")
|
||||
local client = require("awful.client")
|
||||
local util = require("awful.util")
|
||||
local tag = require("awful.tag")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Tasklist widget module for awful
|
||||
module("awful.widget.tasklist")
|
||||
|
||||
-- Public structures
|
||||
label = {}
|
||||
|
||||
local function tasklist_update(w, buttons, label, data, widgets)
|
||||
local clients = capi.client.get()
|
||||
local shownclients = {}
|
||||
for k, c in ipairs(clients) do
|
||||
if not (c.skip_taskbar or c.hidden
|
||||
or c.type == "splash" or c.type == "dock" or c.type == "desktop") then
|
||||
table.insert(shownclients, c)
|
||||
end
|
||||
end
|
||||
clients = shownclients
|
||||
|
||||
common.list_update(w, buttons, label, data, widgets, clients)
|
||||
end
|
||||
|
||||
--- Create a new tasklist widget.
|
||||
-- @param label Label function to use.
|
||||
-- @param buttons A table with buttons binding to set.
|
||||
function new(label, buttons)
|
||||
local w = {
|
||||
layout = layout.horizontal.flex
|
||||
}
|
||||
local widgets = { }
|
||||
widgets.imagebox = { }
|
||||
widgets.textbox = { margin = { left = 2,
|
||||
right = 2 },
|
||||
bg_resize = true,
|
||||
bg_align = "right"
|
||||
}
|
||||
local data = setmetatable({}, { __mode = 'kv' })
|
||||
local u = function () tasklist_update(w, buttons, label, data, widgets) end
|
||||
for s = 1, capi.screen.count() do
|
||||
tag.attached_add_signal(s, "property::selected", u)
|
||||
capi.screen[s]:add_signal("tag::attach", u)
|
||||
capi.screen[s]:add_signal("tag::detach", u)
|
||||
end
|
||||
capi.client.add_signal("new", function (c)
|
||||
c:add_signal("property::urgent", u)
|
||||
c:add_signal("property::floating", u)
|
||||
c:add_signal("property::maximized_horizontal", u)
|
||||
c:add_signal("property::maximized_vertical", u)
|
||||
c:add_signal("property::name", u)
|
||||
c:add_signal("property::icon_name", u)
|
||||
c:add_signal("property::icon", u)
|
||||
c:add_signal("property::skip_taskbar", u)
|
||||
c:add_signal("property::hidden", u)
|
||||
c:add_signal("tagged", u)
|
||||
c:add_signal("untagged", u)
|
||||
end)
|
||||
capi.client.add_signal("unmanage", u)
|
||||
capi.client.add_signal("list", u)
|
||||
capi.client.add_signal("focus", u)
|
||||
capi.client.add_signal("unfocus", u)
|
||||
u()
|
||||
return w
|
||||
end
|
||||
|
||||
local function widget_tasklist_label_common(c, args)
|
||||
if not args then args = {} end
|
||||
local theme = beautiful.get()
|
||||
local fg_focus = args.fg_focus or theme.tasklist_fg_focus or theme.fg_focus
|
||||
local bg_focus = args.bg_focus or theme.tasklist_bg_focus or theme.bg_focus
|
||||
local fg_urgent = args.fg_urgent or theme.tasklist_fg_urgent or theme.fg_urgent
|
||||
local bg_urgent = args.bg_urgent or theme.tasklist_bg_urgent or theme.bg_urgent
|
||||
local fg_minimize = args.fg_minimize or theme.tasklist_fg_minimize or theme.fg_minimize
|
||||
local bg_minimize = args.bg_minimize or theme.tasklist_bg_minimize or theme.bg_minimize
|
||||
local floating_icon = args.floating_icon or theme.tasklist_floating_icon
|
||||
local font = args.font or theme.tasklist_font or theme.font or ""
|
||||
local bg = nil
|
||||
local text = "<span font_desc='"..font.."'>"
|
||||
local name
|
||||
local status_image
|
||||
if client.floating.get(c) and floating_icon then
|
||||
status_image = capi.image(floating_icon)
|
||||
end
|
||||
if c.minimized then
|
||||
name = util.escape(c.icon_name) or util.escape(c.name) or util.escape("<untitled>")
|
||||
else
|
||||
name = util.escape(c.name) or util.escape("<untitled>")
|
||||
end
|
||||
if capi.client.focus == c then
|
||||
bg = bg_focus
|
||||
if fg_focus then
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_focus).."'>"..name.."</span>"
|
||||
else
|
||||
text = text .. name
|
||||
end
|
||||
elseif c.urgent and fg_urgent then
|
||||
bg = bg_urgent
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_urgent).."'>"..name.."</span>"
|
||||
elseif c.minimized and fg_minimize and bg_minimize then
|
||||
bg = bg_minimize
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_minimize).."'>"..name.."</span>"
|
||||
else
|
||||
text = text .. name
|
||||
end
|
||||
text = text .. "</span>"
|
||||
return text, bg, status_image, c.icon
|
||||
-- return text, bg, status_image, nil
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from all tags and screen.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.allscreen(c, screen, args)
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from all tags.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.alltags(c, screen, args)
|
||||
-- Only print client on the same screen as this widget
|
||||
if c.screen ~= screen then return end
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from currently selected tags.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.currenttags(c, screen, args)
|
||||
-- Only print client on the same screen as this widget
|
||||
if c.screen ~= screen then return end
|
||||
-- Include sticky client too
|
||||
if c.sticky then return widget_tasklist_label_common(c, args) end
|
||||
for k, t in ipairs(capi.screen[screen]:tags()) do
|
||||
if t.selected then
|
||||
local ctags = c:tags()
|
||||
for _, v in ipairs(ctags) do
|
||||
if v == t then
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Return label for only the currently focused client.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.focused(c, screen, args)
|
||||
-- Only print client on the same screen as this widget
|
||||
if c.screen == screen and capi.client.focus == c then
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,35 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.9
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local os = os
|
||||
local capi = { widget = widget,
|
||||
timer = timer }
|
||||
|
||||
--- Text clock widget.
|
||||
module("awful.widget.textclock")
|
||||
|
||||
--- Create a textclock widget. It draws the time it is in a textbox.
|
||||
-- @param args Standard arguments for textbox widget.
|
||||
-- @param format The time format. Default is " %a %b %d, %H:%M ".
|
||||
-- @param timeout How often update the time. Default is 60.
|
||||
-- @return A textbox widget.
|
||||
function new(args, format, timeout)
|
||||
local args = args or {}
|
||||
local format = format or " %a %b %d, %H:%M "
|
||||
local timeout = timeout or 60
|
||||
args.type = "textbox"
|
||||
local w = capi.widget(args)
|
||||
local timer = capi.timer { timeout = timeout }
|
||||
w.text = os.date(format)
|
||||
timer:add_signal("timeout", function() w.text = os.date(format) end)
|
||||
timer:start()
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
76
Old/ATARI/home/burchettm/.config/awesome/lib/beautiful.lua
Normal file
76
Old/ATARI/home/burchettm/.config/awesome/lib/beautiful.lua
Normal file
@ -0,0 +1,76 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- @author Damien Leone <damien.leone@gmail.com>
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Damien Leone, Julien Danjou
|
||||
-- @release v3.4.9
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local io = io
|
||||
local os = os
|
||||
local print = print
|
||||
local pcall = pcall
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
local dofile = dofile
|
||||
local setmetatable = setmetatable
|
||||
local util = require("awful.util")
|
||||
local package = package
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
awesome = awesome,
|
||||
image = image
|
||||
}
|
||||
|
||||
--- Theme library.
|
||||
module("beautiful")
|
||||
|
||||
-- Local data
|
||||
local theme
|
||||
|
||||
--- Init function, should be runned at the beginning of configuration file.
|
||||
-- @param path The theme file path.
|
||||
function init(path)
|
||||
if path then
|
||||
local success
|
||||
success, theme = pcall(function() return dofile(path) end)
|
||||
|
||||
if not success then
|
||||
return print("E: beautiful: error loading theme file " .. theme)
|
||||
elseif theme then
|
||||
-- try and grab user's $HOME directory
|
||||
local homedir = os.getenv("HOME")
|
||||
-- expand '~'
|
||||
if homedir then
|
||||
for k, v in pairs(theme) do
|
||||
if type(v) == "string" then theme[k] = v:gsub("~", homedir) end
|
||||
end
|
||||
end
|
||||
|
||||
-- setup wallpaper
|
||||
if theme.wallpaper_cmd then
|
||||
for s = 1, capi.screen.count() do
|
||||
util.spawn(theme.wallpaper_cmd[util.cycle(#theme.wallpaper_cmd, s)], false, s)
|
||||
end
|
||||
end
|
||||
if theme.font then capi.awesome.font = theme.font end
|
||||
if theme.fg_normal then capi.awesome.fg = theme.fg_normal end
|
||||
if theme.bg_normal then capi.awesome.bg = theme.bg_normal end
|
||||
else
|
||||
return print("E: beautiful: error loading theme file " .. path)
|
||||
end
|
||||
else
|
||||
return print("E: beautiful: error loading theme: no path specified")
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the current theme.
|
||||
-- @return The current theme table.
|
||||
function get()
|
||||
return theme
|
||||
end
|
||||
|
||||
setmetatable(_M, { __index = function(t, k) return theme[k] end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
121
Old/ATARI/home/burchettm/.config/awesome/lib/cal.lua
Normal file
121
Old/ATARI/home/burchettm/.config/awesome/lib/cal.lua
Normal file
@ -0,0 +1,121 @@
|
||||
-- original code made by Bzed and published on http://awesome.naquadah.org/wiki/Calendar_widget
|
||||
-- modified by Marc Dequènes (Duck) <Duck@DuckCorp.org> (2009-12-29), under the same licence,
|
||||
-- and with the following changes:
|
||||
-- + transformed to module
|
||||
-- + the current day formating is customizable
|
||||
-- modified by Jörg Thalheim (Mic92) <jthalheim@gmail.com> (2011), under the same licence,
|
||||
-- and with the following changes:
|
||||
-- + use tooltip instead of naughty.notify
|
||||
-- + rename it to cal
|
||||
--
|
||||
-- # How to Install #
|
||||
-- 1. Download the code and move it into your config directory
|
||||
-- wget --no-check-certificate https://github.com/Mic92/awesome-dotfiles/raw/master/cal.lua -O $XDG_CONFIG_HOME/awesome/cal.lua
|
||||
-- 2. require it in your rc.lua
|
||||
-- require("cal")
|
||||
-- 3. attach the calendar to a widget of your choice (ex mytextclock)
|
||||
-- cal.register(mytextclock)
|
||||
-- If you don't like the default current day formating you can change it as following
|
||||
-- cal.register(mytextclock, "<b>%s</b>") -- now the current day is bold instead of underlined
|
||||
--
|
||||
-- # How to Use #
|
||||
-- Just hover with your mouse over the widget, you register and the calendar popup.
|
||||
-- On clicking or by using the mouse wheel the displayed month changes.
|
||||
-- Pressing Shift + Mouse click change the year.
|
||||
|
||||
local string = {format = string.format}
|
||||
local os = {date = os.date, time = os.time}
|
||||
local awful = require("awful")
|
||||
|
||||
module("cal")
|
||||
|
||||
local tooltip
|
||||
local state = {}
|
||||
local current_day_format = "<u>%s</u>"
|
||||
|
||||
function displayMonth(month,year,weekStart)
|
||||
local t,wkSt=os.time{year=year, month=month+1, day=0},weekStart or 1
|
||||
local d=os.date("*t",t)
|
||||
local mthDays,stDay=d.day,(d.wday-d.day-wkSt+1)%7
|
||||
|
||||
local lines = " "
|
||||
|
||||
for x=0,6 do
|
||||
lines = lines .. os.date("%a ",os.time{year=2006,month=1,day=x+wkSt})
|
||||
end
|
||||
|
||||
lines = lines .. "\n" .. os.date(" %V",os.time{year=year,month=month,day=1})
|
||||
|
||||
local writeLine = 1
|
||||
while writeLine < (stDay + 1) do
|
||||
lines = lines .. " "
|
||||
writeLine = writeLine + 1
|
||||
end
|
||||
|
||||
for d=1,mthDays do
|
||||
local x = d
|
||||
local t = os.time{year=year,month=month,day=d}
|
||||
if writeLine == 8 then
|
||||
writeLine = 1
|
||||
lines = lines .. "\n" .. os.date(" %V",t)
|
||||
end
|
||||
if os.date("%Y-%m-%d") == os.date("%Y-%m-%d", t) then
|
||||
x = string.format(current_day_format, d)
|
||||
end
|
||||
if d < 10 then
|
||||
x = " " .. x
|
||||
end
|
||||
lines = lines .. " " .. x
|
||||
writeLine = writeLine + 1
|
||||
end
|
||||
local header = os.date("%B %Y\n",os.time{year=year,month=month,day=1})
|
||||
|
||||
return header .. "\n" .. lines
|
||||
end
|
||||
|
||||
function register(mywidget, custom_current_day_format)
|
||||
if custom_current_day_format then current_day_format = custom_current_day_format end
|
||||
|
||||
if not tooltip then
|
||||
tooltip = awful.tooltip({})
|
||||
end
|
||||
tooltip:add_to_object(mywidget)
|
||||
|
||||
mywidget:add_signal("mouse::enter", function()
|
||||
local month, year = os.date('%m'), os.date('%Y')
|
||||
state = {month, year}
|
||||
tooltip:set_text(string.format('<span font_desc="monospace">%s</span>', displayMonth(month, year, 2)))
|
||||
end)
|
||||
|
||||
mywidget:buttons(awful.util.table.join(
|
||||
awful.button({ }, 1, function()
|
||||
switchMonth(-1)
|
||||
end),
|
||||
awful.button({ }, 3, function()
|
||||
switchMonth(1)
|
||||
end),
|
||||
awful.button({ }, 4, function()
|
||||
switchMonth(-1)
|
||||
end),
|
||||
awful.button({ }, 5, function()
|
||||
switchMonth(1)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 1, function()
|
||||
switchMonth(-12)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 3, function()
|
||||
switchMonth(12)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 4, function()
|
||||
switchMonth(-12)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 5, function()
|
||||
switchMonth(12)
|
||||
end)))
|
||||
end
|
||||
|
||||
function switchMonth(delta)
|
||||
state[1] = state[1] + (delta or 1)
|
||||
local text = string.format('<span font_desc="monospace">%s</span>', displayMonth(state[1], state[2], 2))
|
||||
tooltip:set_text(text)
|
||||
end
|
594
Old/ATARI/home/burchettm/.config/awesome/lib/naughty.lua
Normal file
594
Old/ATARI/home/burchettm/.config/awesome/lib/naughty.lua
Normal file
@ -0,0 +1,594 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- @author koniu <gkusnierz@gmail.com>
|
||||
-- @copyright 2008 koniu
|
||||
-- @release v3.4.9
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Package environment
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local type = type
|
||||
local string = string
|
||||
local pcall = pcall
|
||||
local capi = { screen = screen,
|
||||
awesome = awesome,
|
||||
dbus = dbus,
|
||||
widget = widget,
|
||||
wibox = wibox,
|
||||
image = image,
|
||||
timer = timer }
|
||||
local button = require("awful.button")
|
||||
local util = require("awful.util")
|
||||
local bt = require("beautiful")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Notification library
|
||||
module("naughty")
|
||||
|
||||
--- Naughty configuration - a table containing common popup settings.
|
||||
-- @name config
|
||||
-- @field padding Space between popups and edge of the workarea. Default: 4
|
||||
-- @field spacing Spacing between popups. Default: 1
|
||||
-- @field icon_dirs List of directories that will be checked by getIcon()
|
||||
-- Default: { "/usr/share/pixmaps/", }
|
||||
-- @field icon_formats List of formats that will be checked by getIcon()
|
||||
-- Default: { "png", "gif" }
|
||||
-- @field default_preset Preset to be used by default.
|
||||
-- Default: config.presets.normal
|
||||
-- @class table
|
||||
|
||||
config = {}
|
||||
config.padding = 4
|
||||
config.spacing = 1
|
||||
config.icon_dirs = { "/usr/share/pixmaps/", }
|
||||
config.icon_formats = { "png", "gif" }
|
||||
|
||||
|
||||
--- Notification Presets - a table containing presets for different purposes
|
||||
-- Preset is a table of any parameters available to notify()
|
||||
-- You have to pass a reference of a preset in your notify() call to use the preset
|
||||
-- At least the default preset named "normal" has to be defined
|
||||
-- The presets "low", "normal" and "critical" are used for notifications over DBUS
|
||||
-- @name config.presets
|
||||
-- @field low The preset for notifications with low urgency level
|
||||
-- @field normal The default preset for every notification without a preset that will also be used for normal urgency level
|
||||
-- @field critical The preset for notifications with a critical urgency level
|
||||
-- @class table
|
||||
|
||||
config.presets = {
|
||||
normal = {},
|
||||
low = {
|
||||
timeout = 5
|
||||
},
|
||||
critical = {
|
||||
bg = "#ff0000",
|
||||
fg = "#ffffff",
|
||||
timeout = 0,
|
||||
}
|
||||
}
|
||||
|
||||
config.default_preset = config.presets.normal
|
||||
|
||||
-- DBUS Notification constants
|
||||
urgency = {
|
||||
low = "\0",
|
||||
normal = "\1",
|
||||
critical = "\2"
|
||||
}
|
||||
|
||||
--- DBUS notification to preset mapping
|
||||
-- @name config.mapping
|
||||
-- The first element is an object containing the filter
|
||||
-- If the rules in the filter matches the associated preset will be applied
|
||||
-- The rules object can contain: urgency, category, appname
|
||||
-- The second element is the preset
|
||||
|
||||
config.mapping = {
|
||||
{{urgency = urgency.low}, config.presets.low},
|
||||
{{urgency = urgency.normal}, config.presets.normal},
|
||||
{{urgency = urgency.critical}, config.presets.critical}
|
||||
}
|
||||
|
||||
-- Counter for the notifications
|
||||
-- Required for later access via DBUS
|
||||
local counter = 1
|
||||
|
||||
-- True if notifying is suspended
|
||||
local suspended = false
|
||||
|
||||
--- Index of notifications. See config table for valid 'position' values.
|
||||
-- Each element is a table consisting of:
|
||||
-- @field box Wibox object containing the popup
|
||||
-- @field height Popup height
|
||||
-- @field width Popup width
|
||||
-- @field die Function to be executed on timeout
|
||||
-- @field id Unique notification id based on a counter
|
||||
-- @name notifications[screen][position]
|
||||
-- @class table
|
||||
|
||||
notifications = { suspended = { } }
|
||||
for s = 1, capi.screen.count() do
|
||||
notifications[s] = {
|
||||
top_left = {},
|
||||
top_right = {},
|
||||
bottom_left = {},
|
||||
bottom_right = {},
|
||||
}
|
||||
end
|
||||
|
||||
--- Suspend notifications
|
||||
function suspend()
|
||||
suspended = true
|
||||
end
|
||||
|
||||
--- Resume notifications
|
||||
function resume()
|
||||
suspended = false
|
||||
for i, v in pairs(notifications.suspended) do
|
||||
v.box.visible = true
|
||||
if v.timer then v.timer:start() end
|
||||
end
|
||||
notifications.suspended = { }
|
||||
end
|
||||
|
||||
-- Evaluate desired position of the notification by index - internal
|
||||
-- @param idx Index of the notification
|
||||
-- @param position top_right | top_left | bottom_right | bottom_left
|
||||
-- @param height Popup height
|
||||
-- @param width Popup width (optional)
|
||||
-- @return Absolute position and index in { x = X, y = Y, idx = I } table
|
||||
local function get_offset(screen, position, idx, width, height)
|
||||
local ws = capi.screen[screen].workarea
|
||||
local v = {}
|
||||
local idx = idx or #notifications[screen][position] + 1
|
||||
local width = width or notifications[screen][position][idx].width
|
||||
|
||||
-- calculate x
|
||||
if position:match("left") then
|
||||
v.x = ws.x + config.padding
|
||||
else
|
||||
v.x = ws.x + ws.width - (width + config.padding)
|
||||
end
|
||||
|
||||
-- calculate existing popups' height
|
||||
local existing = 0
|
||||
for i = 1, idx-1, 1 do
|
||||
existing = existing + notifications[screen][position][i].height + config.spacing
|
||||
end
|
||||
|
||||
-- calculate y
|
||||
if position:match("top") then
|
||||
v.y = ws.y + config.padding + existing
|
||||
else
|
||||
v.y = ws.y + ws.height - (config.padding + height + existing)
|
||||
end
|
||||
|
||||
-- if positioned outside workarea, destroy oldest popup and recalculate
|
||||
if v.y + height > ws.y + ws.height or v.y < ws.y then
|
||||
idx = idx - 1
|
||||
destroy(notifications[screen][position][1])
|
||||
v = get_offset(screen, position, idx, width, height)
|
||||
end
|
||||
if not v.idx then v.idx = idx end
|
||||
|
||||
return v
|
||||
end
|
||||
|
||||
-- Re-arrange notifications according to their position and index - internal
|
||||
-- @return None
|
||||
local function arrange(screen)
|
||||
for p,pos in pairs(notifications[screen]) do
|
||||
for i,notification in pairs(notifications[screen][p]) do
|
||||
local offset = get_offset(screen, p, i, notification.width, notification.height)
|
||||
notification.box:geometry({ x = offset.x, y = offset.y })
|
||||
notification.idx = offset.idx
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Destroy notification by notification object
|
||||
-- @param notification Notification object to be destroyed
|
||||
-- @return True if the popup was successfully destroyed, nil otherwise
|
||||
function destroy(notification)
|
||||
if notification and notification.box.screen then
|
||||
if suspended then
|
||||
for k, v in pairs(notifications.suspended) do
|
||||
if v.box == notification.box then
|
||||
table.remove(notifications.suspended, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local scr = notification.box.screen
|
||||
table.remove(notifications[notification.box.screen][notification.position], notification.idx)
|
||||
if notification.timer then
|
||||
notification.timer:stop()
|
||||
end
|
||||
notification.box.screen = nil
|
||||
arrange(scr)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Get notification by ID
|
||||
-- @param id ID of the notification
|
||||
-- @return notification object if it was found, nil otherwise
|
||||
local function getById(id)
|
||||
-- iterate the notifications to get the notfications with the correct ID
|
||||
for s = 1, capi.screen.count() do
|
||||
for p,pos in pairs(notifications[s]) do
|
||||
for i,notification in pairs(notifications[s][p]) do
|
||||
if notification.id == id then
|
||||
return notification
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Search for an icon in specified directories with a specified format
|
||||
-- @param icon Name of the icon
|
||||
-- @return full path of the icon, or nil of no icon was found
|
||||
local function getIcon(name)
|
||||
for d, dir in pairs(config.icon_dirs) do
|
||||
for f, format in pairs(config.icon_formats) do
|
||||
local icon = dir .. name .. "." .. format
|
||||
if util.file_readable(icon) then
|
||||
return icon
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create notification. args is a dictionary of (optional) arguments.
|
||||
-- @param text Text of the notification. Default: ''
|
||||
-- @param title Title of the notification. Default: nil
|
||||
-- @param timeout Time in seconds after which popup expires.
|
||||
-- Set 0 for no timeout. Default: 5
|
||||
-- @param hover_timeout Delay in seconds after which hovered popup disappears.
|
||||
-- Default: nil
|
||||
-- @param screen Target screen for the notification. Default: 1
|
||||
-- @param position Corner of the workarea displaying the popups.
|
||||
-- Values: "top_right" (default), "top_left", "bottom_left", "bottom_right".
|
||||
-- @param ontop Boolean forcing popups to display on top. Default: true
|
||||
-- @param height Popup height. Default: nil (auto)
|
||||
-- @param width Popup width. Default: nil (auto)
|
||||
-- @param font Notification font. Default: beautiful.font or awesome.font
|
||||
-- @param icon Path to icon. Default: nil
|
||||
-- @param icon_size Desired icon size in px. Default: nil
|
||||
-- @param fg Foreground color. Default: beautiful.fg_focus or '#ffffff'
|
||||
-- @param bg Background color. Default: beautiful.bg_focus or '#535d6c'
|
||||
-- @param border_width Border width. Default: 1
|
||||
-- @param border_color Border color.
|
||||
-- Default: beautiful.border_focus or '#535d6c'
|
||||
-- @param run Function to run on left click. Default: nil
|
||||
-- @param preset Table with any of the above parameters. Note: Any parameters
|
||||
-- specified directly in args will override ones defined in the preset.
|
||||
-- @param replaces_id Replace the notification with the given ID
|
||||
-- @param callback function that will be called with all arguments
|
||||
-- the notification will only be displayed if the function returns true
|
||||
-- note: this function is only relevant to notifications sent via dbus
|
||||
-- @usage naughty.notify({ title = "Achtung!", text = "You're idling", timeout = 0 })
|
||||
-- @return The notification object
|
||||
function notify(args)
|
||||
-- gather variables together
|
||||
local preset = args.preset or config.default_preset or {}
|
||||
local timeout = args.timeout or preset.timeout or 5
|
||||
local icon = args.icon or preset.icon
|
||||
local icon_size = args.icon_size or preset.icon_size
|
||||
local text = args.text or preset.text or ""
|
||||
local title = args.title or preset.title
|
||||
local screen = args.screen or preset.screen or 1
|
||||
local ontop = args.ontop or preset.ontop or true
|
||||
local width = args.width or preset.width
|
||||
local height = args.height or preset.height
|
||||
local hover_timeout = args.hover_timeout or preset.hover_timeout
|
||||
local opacity = args.opacity or preset.opacity
|
||||
local margin = args.margin or preset.margin or "5"
|
||||
local border_width = args.border_width or preset.border_width or "1"
|
||||
local position = args.position or preset.position or "top_right"
|
||||
|
||||
-- beautiful
|
||||
local beautiful = bt.get()
|
||||
local font = args.font or preset.font or beautiful.font or capi.awesome.font
|
||||
local fg = args.fg or preset.fg or beautiful.fg_normal or '#ffffff'
|
||||
local bg = args.bg or preset.bg or beautiful.bg_normal or '#535d6c'
|
||||
local border_color = args.border_color or preset.border_color or beautiful.bg_focus or '#535d6c'
|
||||
local notification = {}
|
||||
|
||||
-- replace notification if needed
|
||||
if args.replaces_id then
|
||||
local obj = getById(args.replaces_id)
|
||||
if obj then
|
||||
-- destroy this and ...
|
||||
destroy(obj)
|
||||
end
|
||||
-- ... may use its ID
|
||||
if args.replaces_id < counter then
|
||||
notification.id = args.replaces_id
|
||||
else
|
||||
counter = counter + 1
|
||||
notification.id = counter
|
||||
end
|
||||
else
|
||||
-- get a brand new ID
|
||||
counter = counter + 1
|
||||
notification.id = counter
|
||||
end
|
||||
|
||||
notification.position = position
|
||||
|
||||
if title then title = title .. "\n" else title = "" end
|
||||
|
||||
-- hook destroy
|
||||
local die = function () destroy(notification) end
|
||||
if timeout > 0 then
|
||||
local timer_die = capi.timer { timeout = timeout }
|
||||
timer_die:add_signal("timeout", die)
|
||||
if not suspended then
|
||||
timer_die:start()
|
||||
end
|
||||
notification.timer = timer_die
|
||||
end
|
||||
notification.die = die
|
||||
|
||||
local run = function ()
|
||||
if args.run then
|
||||
args.run(notification)
|
||||
else
|
||||
die()
|
||||
end
|
||||
end
|
||||
|
||||
local hover_destroy = function ()
|
||||
if hover_timeout == 0 then
|
||||
die()
|
||||
else
|
||||
if notification.timer then notification.timer:stop() end
|
||||
notification.timer = capi.timer { timeout = hover_timeout }
|
||||
notification.timer:add_signal("timeout", die)
|
||||
notification.timer:start()
|
||||
end
|
||||
end
|
||||
|
||||
-- create textbox
|
||||
local textbox = capi.widget({ type = "textbox", align = "flex" })
|
||||
textbox:buttons(util.table.join(button({ }, 1, run), button({ }, 3, die)))
|
||||
layout.margins[textbox] = { right = margin, left = margin, bottom = margin, top = margin }
|
||||
textbox.valign = "middle"
|
||||
|
||||
local function setText(pattern, replacements)
|
||||
textbox.text = string.format('<span font_desc="%s"><b>%s</b>%s</span>', font, title, text:gsub(pattern, replacements))
|
||||
end
|
||||
|
||||
-- First try to set the text while only interpreting <br>.
|
||||
-- (Setting a textbox' .text to an invalid pattern throws a lua error)
|
||||
if not pcall(setText, "<br.->", "\n") then
|
||||
-- That failed, escape everything which might cause an error from pango
|
||||
if not pcall(setText, "[<>&]", { ['<'] = "<", ['>'] = ">", ['&'] = "&" }) then
|
||||
textbox.text = "<i><Invalid markup, cannot display message></i>"
|
||||
end
|
||||
end
|
||||
|
||||
-- create iconbox
|
||||
local iconbox = nil
|
||||
if icon then
|
||||
-- try to guess icon if the provided one is non-existent/readable
|
||||
if type(icon) == "string" and not util.file_readable(icon) then
|
||||
icon = getIcon(icon)
|
||||
end
|
||||
|
||||
-- if we have an icon, use it
|
||||
if icon then
|
||||
iconbox = capi.widget({ type = "imagebox", align = "left" })
|
||||
layout.margins[iconbox] = { right = margin, left = margin, bottom = margin, top = margin }
|
||||
iconbox:buttons(util.table.join(button({ }, 1, run), button({ }, 3, die)))
|
||||
local img
|
||||
if type(icon) == "string" then
|
||||
img = capi.image(icon)
|
||||
else
|
||||
img = icon
|
||||
end
|
||||
if icon_size then
|
||||
img = img:crop_and_scale(0,0,img.height,img.width,icon_size,icon_size)
|
||||
end
|
||||
iconbox.resize = false
|
||||
iconbox.image = img
|
||||
end
|
||||
end
|
||||
|
||||
-- create container wibox
|
||||
notification.box = capi.wibox({ fg = fg,
|
||||
bg = bg,
|
||||
border_color = border_color,
|
||||
border_width = border_width })
|
||||
|
||||
if hover_timeout then notification.box:add_signal("mouse::enter", hover_destroy) end
|
||||
|
||||
-- calculate the height
|
||||
if not height then
|
||||
if iconbox and iconbox:extents().height + 2 * margin > textbox:extents().height + 2 * margin then
|
||||
height = iconbox:extents().height + 2 * margin
|
||||
else
|
||||
height = textbox:extents().height + 2 * margin
|
||||
end
|
||||
end
|
||||
|
||||
-- calculate the width
|
||||
if not width then
|
||||
width = textbox:extents().width + (iconbox and iconbox:extents().width + 2 * margin or 0) + 2 * margin
|
||||
end
|
||||
|
||||
-- crop to workarea size if too big
|
||||
local workarea = capi.screen[screen].workarea
|
||||
if width > workarea.width - 2 * (border_width or 0) - 2 * (config.padding or 0) then
|
||||
width = workarea.width - 2 * (border_width or 0) - 2 * (config.padding or 0)
|
||||
end
|
||||
if height > workarea.height - 2 * (border_width or 0) - 2 * (config.padding or 0) then
|
||||
height = workarea.height - 2 * (border_width or 0) - 2 * (config.padding or 0)
|
||||
end
|
||||
|
||||
-- set size in notification object
|
||||
notification.height = height + 2 * (border_width or 0)
|
||||
notification.width = width + 2 * (border_width or 0)
|
||||
|
||||
-- position the wibox
|
||||
local offset = get_offset(screen, notification.position, nil, notification.width, notification.height)
|
||||
notification.box.ontop = ontop
|
||||
notification.box:geometry({ width = width,
|
||||
height = height,
|
||||
x = offset.x,
|
||||
y = offset.y })
|
||||
notification.box.opacity = opacity
|
||||
notification.box.screen = screen
|
||||
notification.idx = offset.idx
|
||||
|
||||
-- populate widgets
|
||||
notification.box.widgets = { iconbox, textbox, ["layout"] = layout.horizontal.leftright }
|
||||
|
||||
-- insert the notification to the table
|
||||
table.insert(notifications[screen][notification.position], notification)
|
||||
|
||||
if suspended then
|
||||
notification.box.visible = false
|
||||
table.insert(notifications.suspended, notification)
|
||||
end
|
||||
|
||||
-- return the notification
|
||||
return notification
|
||||
end
|
||||
|
||||
-- DBUS/Notification support
|
||||
-- Notify
|
||||
if capi.dbus then
|
||||
capi.dbus.add_signal("org.freedesktop.Notifications", function (data, appname, replaces_id, icon, title, text, actions, hints, expire)
|
||||
args = { preset = { } }
|
||||
if data.member == "Notify" then
|
||||
if text ~= "" then
|
||||
args.text = text
|
||||
if title ~= "" then
|
||||
args.title = title
|
||||
end
|
||||
else
|
||||
if title ~= "" then
|
||||
args.text = title
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
local score = 0
|
||||
for i, obj in pairs(config.mapping) do
|
||||
local filter, preset, s = obj[1], obj[2], 0
|
||||
if (not filter.urgency or filter.urgency == hints.urgency) and
|
||||
(not filter.category or filter.category == hints.category) and
|
||||
(not filter.appname or filter.appname == appname) then
|
||||
for j, el in pairs(filter) do s = s + 1 end
|
||||
if s > score then
|
||||
score = s
|
||||
args.preset = preset
|
||||
end
|
||||
end
|
||||
end
|
||||
if not args.preset.callback or (type(args.preset.callback) == "function" and
|
||||
args.preset.callback(data, appname, replaces_id, icon, title, text, actions, hints, expire)) then
|
||||
if icon ~= "" then
|
||||
args.icon = icon
|
||||
elseif hints.icon_data or hints.image_data then
|
||||
if hints.icon_data == nil then hints.icon_data = hints.image_data end
|
||||
-- icon_data is an array:
|
||||
-- 1 -> width, 2 -> height, 3 -> rowstride, 4 -> has alpha
|
||||
-- 5 -> bits per sample, 6 -> channels, 7 -> data
|
||||
|
||||
local imgdata
|
||||
-- If has alpha (ARGB32)
|
||||
if hints.icon_data[6] == 4 then
|
||||
imgdata = hints.icon_data[7]
|
||||
-- If has not alpha (RGB24)
|
||||
elseif hints.icon_data[6] == 3 then
|
||||
imgdata = ""
|
||||
for i = 1, #hints.icon_data[7], 3 do
|
||||
imgdata = imgdata .. hints.icon_data[7]:sub(i , i + 2):reverse()
|
||||
imgdata = imgdata .. string.format("%c", 255) -- alpha is 255
|
||||
end
|
||||
end
|
||||
if imgdata then
|
||||
args.icon = capi.image.argb32(hints.icon_data[1], hints.icon_data[2], imgdata)
|
||||
end
|
||||
end
|
||||
if replaces_id and replaces_id ~= "" and replaces_id ~= 0 then
|
||||
args.replaces_id = replaces_id
|
||||
end
|
||||
if expire and expire > -1 then
|
||||
args.timeout = expire / 1000
|
||||
end
|
||||
local id = notify(args).id
|
||||
return "u", id
|
||||
end
|
||||
return "u", "0"
|
||||
elseif data.member == "CloseNotification" then
|
||||
local obj = getById(appname)
|
||||
if obj then
|
||||
destroy(obj)
|
||||
end
|
||||
elseif data.member == "GetServerInfo" or data.member == "GetServerInformation" then
|
||||
-- name of notification app, name of vender, version
|
||||
return "s", "naughty", "s", "awesome", "s", capi.awesome.version:match("%d.%d"), "s", "1.0"
|
||||
elseif data.member == "GetCapabilities" then
|
||||
-- We actually do display the body of the message, we support <b>, <i>
|
||||
-- and <u> in the body and we handle static (non-animated) icons.
|
||||
return "as", { "s", "body", "s", "body-markup", "s", "icon-static" }
|
||||
end
|
||||
end)
|
||||
|
||||
capi.dbus.add_signal("org.freedesktop.DBus.Introspectable",
|
||||
function (data, text)
|
||||
if data.member == "Introspect" then
|
||||
local xml = [=[<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object
|
||||
Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="data" direction="out" type="s"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.Notifications">
|
||||
<method name="GetCapabilities">
|
||||
<arg name="caps" type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="CloseNotification">
|
||||
<arg name="id" type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="Notify">
|
||||
<arg name="app_name" type="s" direction="in"/>
|
||||
<arg name="id" type="u" direction="in"/>
|
||||
<arg name="icon" type="s" direction="in"/>
|
||||
<arg name="summary" type="s" direction="in"/>
|
||||
<arg name="body" type="s" direction="in"/>
|
||||
<arg name="actions" type="as" direction="in"/>
|
||||
<arg name="hints" type="a{sv}" direction="in"/>
|
||||
<arg name="timeout" type="i" direction="in"/>
|
||||
<arg name="return_id" type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="GetServerInformation">
|
||||
<arg name="return_name" type="s" direction="out"/>
|
||||
<arg name="return_vendor" type="s" direction="out"/>
|
||||
<arg name="return_version" type="s" direction="out"/>
|
||||
<arg name="return_spec_version" type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="GetServerInfo">
|
||||
<arg name="return_name" type="s" direction="out"/>
|
||||
<arg name="return_vendor" type="s" direction="out"/>
|
||||
<arg name="return_version" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>]=]
|
||||
return "s", xml
|
||||
end
|
||||
end)
|
||||
|
||||
-- listen for dbus notification requests
|
||||
capi.dbus.request_name("session", "org.freedesktop.Notifications")
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,51 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
local string = { match = string.match }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Batacpi: provides state, charge, and remaining time for all batteries using acpitool
|
||||
module("vicious.contrib.batacpi")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format)
|
||||
local battery_info = {}
|
||||
local battery_state = {
|
||||
["full"] = "↯",
|
||||
["unknown"] = "⌁",
|
||||
["charged"] = "↯",
|
||||
["charging"] = "+",
|
||||
["discharging"] = "-"
|
||||
}
|
||||
|
||||
-- Get data from acpitool
|
||||
local f = io.popen("acpitool -b")
|
||||
|
||||
for line in f:lines() do
|
||||
-- Check if the battery is present
|
||||
if string.match(line, "^[%s]+Battery.*") then
|
||||
-- Store state and charge information
|
||||
table.insert(battery_info, (battery_state[string.match(line, "([%a]*),") or "unknown"]))
|
||||
table.insert(battery_info, (tonumber(string.match(line, "([%d]?[%d]?[%d])%.")) or 0))
|
||||
-- Store remaining time information
|
||||
table.insert(battery_info, (string.match(line, "%%,%s(.*)") or "N/A"))
|
||||
else
|
||||
return {battery_state["unknown"], 0, "N/A"}
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return battery_info
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,78 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local math = {
|
||||
min = math.min,
|
||||
floor = math.floor
|
||||
}
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match,
|
||||
format = string.format
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Batpmu: provides state, charge and remaining time for a requested battery using PMU
|
||||
module("vicious.contrib.batpmu")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format, batid)
|
||||
local battery_state = {
|
||||
["full"] = "↯",
|
||||
["unknown"] = "⌁",
|
||||
["00000013"] = "+",
|
||||
["00000011"] = "-"
|
||||
}
|
||||
|
||||
-- Get /proc/pmu/battery* state
|
||||
local f = io.open("/proc/pmu/" .. batid)
|
||||
-- Handler for incompetent users
|
||||
if not f then return {battery_state["unknown"], 0, "N/A"} end
|
||||
local statefile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Get /proc/pmu/info data
|
||||
local f = io.open("/proc/pmu/info")
|
||||
local infofile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Check if the battery is present
|
||||
if infofile == nil or string.find(infofile, "Battery count[%s]+:[%s]0") then
|
||||
return {battery_state["unknown"], 0, "N/A"}
|
||||
end
|
||||
|
||||
|
||||
-- Get capacity and charge information
|
||||
local capacity = string.match(statefile, "max_charge[%s]+:[%s]([%d]+).*")
|
||||
local remaining = string.match(statefile, "charge[%s]+:[%s]([%d]+).*")
|
||||
|
||||
-- Calculate percentage
|
||||
local percent = math.min(math.floor(remaining / capacity * 100), 100)
|
||||
|
||||
|
||||
-- Get timer information
|
||||
local timer = string.match(statefile, "time rem%.[%s]+:[%s]([%d]+).*")
|
||||
if timer == "0" then return {battery_state["full"], percent, "N/A"} end
|
||||
|
||||
-- Get state information
|
||||
local state = string.match(statefile, "flags[%s]+:[%s]([%d]+).*")
|
||||
local state = battery_state[state] or battery_state["unknown"]
|
||||
|
||||
-- Calculate remaining (charging or discharging) time
|
||||
local hoursleft = math.floor(tonumber(timer) / 3600)
|
||||
local minutesleft = math.floor((tonumber(timer) / 60) % 60)
|
||||
local time = string.format("%02d:%02d", hoursleft, minutesleft)
|
||||
|
||||
return {state, percent, time}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,85 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local math = {
|
||||
min = math.min,
|
||||
floor = math.floor
|
||||
}
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match,
|
||||
format = string.format
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Batproc: provides state, charge, and remaining time for a requested battery using procfs
|
||||
module("vicious.contrib.batproc")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format, batid)
|
||||
local battery_state = {
|
||||
["full"] = "↯",
|
||||
["unknown"] = "⌁",
|
||||
["charged"] = "↯",
|
||||
["charging"] = "+",
|
||||
["discharging"] = "-"
|
||||
}
|
||||
|
||||
-- Get /proc/acpi/battery info
|
||||
local f = io.open("/proc/acpi/battery/"..batid.."/info")
|
||||
-- Handler for incompetent users
|
||||
if not f then return {battery_state["unknown"], 0, "N/A"} end
|
||||
local infofile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Check if the battery is present
|
||||
if infofile == nil or string.find(infofile, "present:[%s]+no") then
|
||||
return {battery_state["unknown"], 0, "N/A"}
|
||||
end
|
||||
|
||||
-- Get capacity information
|
||||
local capacity = string.match(infofile, "last full capacity:[%s]+([%d]+).*")
|
||||
|
||||
|
||||
-- Get /proc/acpi/battery state
|
||||
local f = io.open("/proc/acpi/battery/"..batid.."/state")
|
||||
local statefile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Get state information
|
||||
local state = string.match(statefile, "charging state:[%s]+([%a]+).*")
|
||||
local state = battery_state[state] or battery_state["unknown"]
|
||||
|
||||
-- Get charge information
|
||||
local rate = string.match(statefile, "present rate:[%s]+([%d]+).*")
|
||||
local remaining = string.match(statefile, "remaining capacity:[%s]+([%d]+).*")
|
||||
|
||||
|
||||
-- Calculate percentage (but work around broken BAT/ACPI implementations)
|
||||
local percent = math.min(math.floor(remaining / capacity * 100), 100)
|
||||
|
||||
-- Calculate remaining (charging or discharging) time
|
||||
if state == "+" then
|
||||
timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate)
|
||||
elseif state == "-" then
|
||||
timeleft = tonumber(remaining) / tonumber(rate)
|
||||
else
|
||||
return {state, percent, "N/A"}
|
||||
end
|
||||
local hoursleft = math.floor(timeleft)
|
||||
local minutesleft = math.floor((timeleft - hoursleft) * 60 )
|
||||
local time = string.format("%02d:%02d", hoursleft, minutesleft)
|
||||
|
||||
return {state, percent, time}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,72 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
local string = { gmatch = string.gmatch }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Disk I/O: provides I/O statistics for requested storage devices
|
||||
module("vicious.contrib.dio")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local disk_usage = {}
|
||||
local disk_total = {}
|
||||
-- Variable definitions
|
||||
local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 }
|
||||
|
||||
-- {{{ Disk I/O widget type
|
||||
local function worker(format, disk)
|
||||
if not disk then return end
|
||||
|
||||
local disk_lines = { [disk] = {} }
|
||||
local disk_stats = helpers.pathtotable("/sys/block/" .. disk)
|
||||
|
||||
if disk_stats.stat then
|
||||
local match = string.gmatch(disk_stats.stat, "[%s]+([%d]+)")
|
||||
for i = 1, 11 do -- Store disk stats
|
||||
table.insert(disk_lines[disk], match())
|
||||
end
|
||||
end
|
||||
|
||||
-- Ensure tables are initialized correctly
|
||||
local diff_total = { [disk] = {} }
|
||||
if not disk_total[disk] then
|
||||
disk_usage[disk] = {}
|
||||
disk_total[disk] = {}
|
||||
|
||||
while #disk_total[disk] < #disk_lines[disk] do
|
||||
table.insert(disk_total[disk], 0)
|
||||
end
|
||||
end
|
||||
|
||||
for i, v in ipairs(disk_lines[disk]) do
|
||||
-- Diskstats are absolute, substract our last reading
|
||||
diff_total[disk][i] = v - disk_total[disk][i]
|
||||
|
||||
-- Store totals
|
||||
disk_total[disk][i] = v
|
||||
end
|
||||
|
||||
-- Calculate and store I/O
|
||||
helpers.uformat(disk_usage[disk], "read", diff_total[disk][3], unit)
|
||||
helpers.uformat(disk_usage[disk], "write", diff_total[disk][7], unit)
|
||||
helpers.uformat(disk_usage[disk], "total", diff_total[disk][7] + diff_total[disk][3], unit)
|
||||
|
||||
-- Store I/O scheduler
|
||||
if disk_stats.queue and disk_stats.queue.scheduler then
|
||||
disk_usage[disk]["{sched}"] = string.gmatch(disk_stats.queue.scheduler, "%[([%a]+)%]")
|
||||
end
|
||||
|
||||
return disk_usage[disk]
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,17 @@
|
||||
---------------------------------------------------
|
||||
-- Vicious widgets for the awesome window manager
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Setup environment
|
||||
local setmetatable = setmetatable
|
||||
local wrequire = require("vicious.helpers").wrequire
|
||||
|
||||
-- Vicious: widgets for the awesome window manager
|
||||
module("vicious.contrib")
|
||||
-- }}}
|
||||
|
||||
-- Load modules at runtime as needed
|
||||
setmetatable(_M, { __index = wrequire })
|
@ -0,0 +1,47 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { find = string.find }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mpc: provides the currently playing song in MPD
|
||||
module("vicious.contrib.mpc")
|
||||
|
||||
|
||||
-- {{{ MPC widget type
|
||||
local function worker(format, warg)
|
||||
-- Get data from mpd
|
||||
local f = io.popen("mpc")
|
||||
local np = f:read("*line")
|
||||
f:close()
|
||||
|
||||
-- Not installed,
|
||||
if np == nil or -- off or stoppped.
|
||||
(string.find(np, "MPD_HOST") or string.find(np, "volume:"))
|
||||
then
|
||||
return {"Stopped"}
|
||||
end
|
||||
|
||||
-- Check if we should scroll, or maybe truncate
|
||||
if warg then
|
||||
if type(warg) == "table" then
|
||||
np = helpers.scroll(np, warg[1], warg[2])
|
||||
else
|
||||
np = helpers.truncate(np, warg)
|
||||
end
|
||||
end
|
||||
|
||||
return {helpers.escape(np)}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,138 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Henning Glawe <glaweh@debian.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local tonumber = tonumber
|
||||
local os = { time = os.time }
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Net: provides usage statistics for all network interfaces
|
||||
module("vicious.contrib.net")
|
||||
|
||||
|
||||
-- Initialise function tables
|
||||
local nets = {}
|
||||
-- Variable definitions
|
||||
local unit = { ["b"] = 1, ["kb"] = 1024,
|
||||
["mb"] = 1024^2, ["gb"] = 1024^3
|
||||
}
|
||||
|
||||
-- {{{ Net widget type
|
||||
local function worker(format, tignorelist)
|
||||
local args = {}
|
||||
local tignore = {}
|
||||
local total_rx = 0
|
||||
local total_tx = 0
|
||||
local any_up = 0
|
||||
|
||||
if not tignorelist then
|
||||
tignorelist = {"lo", "wmaster0"}
|
||||
end
|
||||
for k, i in pairs(tignorelist) do
|
||||
tignore[i] = true
|
||||
end
|
||||
|
||||
-- Get NET stats
|
||||
for line in io.lines("/proc/net/dev") do
|
||||
-- Match wmaster0 as well as rt0 (multiple leading spaces)
|
||||
local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):")
|
||||
if name ~= nil then
|
||||
-- Received bytes, first value after the name
|
||||
local recv = tonumber(string.match(line, ":[%s]*([%d]+)"))
|
||||
-- Transmited bytes, 7 fields from end of the line
|
||||
local send = tonumber(string.match(line,
|
||||
"([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$"))
|
||||
|
||||
if not tignore[name] then
|
||||
total_rx = total_rx + recv
|
||||
total_tx = total_tx + send
|
||||
end
|
||||
|
||||
helpers.uformat(args, name .. " rx", recv, unit)
|
||||
helpers.uformat(args, name .. " tx", send, unit)
|
||||
|
||||
if nets[name] == nil then
|
||||
-- Default values on the first run
|
||||
nets[name] = {}
|
||||
|
||||
helpers.uformat(args, name .. " down", 0, unit)
|
||||
helpers.uformat(args, name .. " up", 0, unit)
|
||||
args["{"..name.." carrier}"] = 0
|
||||
|
||||
nets[name].time = os.time()
|
||||
else -- Net stats are absolute, substract our last reading
|
||||
local interval = os.time() - nets[name].time > 0 and
|
||||
os.time() - nets[name].time or 1
|
||||
nets[name].time = os.time()
|
||||
|
||||
local down = (recv - nets[name][1]) / interval
|
||||
local up = (send - nets[name][2]) / interval
|
||||
|
||||
helpers.uformat(args, name .. " down", down, unit)
|
||||
helpers.uformat(args, name .. " up", up, unit)
|
||||
|
||||
-- Carrier detection
|
||||
sysnet = helpers.pathtotable("/sys/class/net/" .. name)
|
||||
|
||||
if sysnet.carrier then
|
||||
ccarrier = tonumber(sysnet.carrier)
|
||||
|
||||
args["{"..name.." carrier}"] = ccarrier
|
||||
if ccarrier ~= 0 and not tignore[name] then
|
||||
any_up = 1
|
||||
end
|
||||
else
|
||||
args["{"..name.." carrier}"] = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- Store totals
|
||||
nets[name][1] = recv
|
||||
nets[name][2] = send
|
||||
end
|
||||
end
|
||||
|
||||
helpers.uformat(args, "total rx", total_rx, unit)
|
||||
helpers.uformat(args, "total tx", total_tx, unit)
|
||||
|
||||
if nets["total"] == nil then
|
||||
-- Default values on the first run
|
||||
nets["total"] = {}
|
||||
|
||||
helpers.uformat(args, "total down", 0, unit)
|
||||
helpers.uformat(args, "total up", 0, unit)
|
||||
args["{total carrier}"] = 0
|
||||
|
||||
nets["total"].time = os.time()
|
||||
else -- Net stats are absolute, substract our last reading
|
||||
local interval = os.time() - nets["total"].time > 0 and
|
||||
os.time() - nets["total"].time or 1
|
||||
nets["total"].time = os.time()
|
||||
|
||||
local down = (total_rx - nets["total"][1]) / interval
|
||||
local up = (total_tx - nets["total"][2]) / interval
|
||||
|
||||
helpers.uformat(args, "total down", down, unit)
|
||||
helpers.uformat(args, "total up", up, unit)
|
||||
args["{total carrier}"] = any_up
|
||||
end
|
||||
|
||||
-- Store totals
|
||||
nets["total"][1] = total_rx
|
||||
nets["total"][2] = total_tx
|
||||
|
||||
return args
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,34 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Radu A. <admiral0@tuxfamily.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Netcfg: provides active netcfg network profiles
|
||||
module("vicious.contrib.netcfg")
|
||||
|
||||
|
||||
-- {{{ Netcfg widget type
|
||||
local function worker(format)
|
||||
-- Initialize counters
|
||||
local profiles = {}
|
||||
|
||||
local f = io.popen("ls -1 /var/run/network/profiles")
|
||||
for line in f:lines() do
|
||||
if line ~= nil then
|
||||
table.insert(profiles, line)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return profiles
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,53 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Ossvol: provides volume levels of requested OSS mixers
|
||||
module("vicious.contrib.ossvol")
|
||||
|
||||
|
||||
-- {{{ Volume widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local mixer_state = {
|
||||
["on"] = "♫", -- "",
|
||||
["off"] = "♩" -- "M"
|
||||
}
|
||||
|
||||
-- Get mixer control contents
|
||||
local f = io.popen("ossmix -c")
|
||||
local mixer = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Capture mixer control state
|
||||
local volu = tonumber(string.match(mixer, warg .. "[%s]([%d%.]+)"))/0.25
|
||||
local mute = string.match(mixer, "vol%.mute[%s]([%a]+)")
|
||||
-- Handle mixers without data
|
||||
if volu == nil then
|
||||
return {0, mixer_state["off"]}
|
||||
end
|
||||
|
||||
-- Handle mixers without mute
|
||||
if mute == "OFF" and volu == "0"
|
||||
-- Handle mixers that are muted
|
||||
or mute == "ON" then
|
||||
mute = mixer_state["off"]
|
||||
else
|
||||
mute = mixer_state["on"]
|
||||
end
|
||||
|
||||
return {volu, mute}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,54 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Boris Bolgradov <>
|
||||
--
|
||||
-- This widget type depends on luasocket.
|
||||
--
|
||||
-- Widget arguments are host, port, username and
|
||||
-- password, i.e.:
|
||||
-- {"mail.myhost.com", 110, "John", "132435"}
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local sock_avail, socket = pcall(function()
|
||||
return require("socket")
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
|
||||
-- POP: provides the count of new messages in a POP3 mailbox
|
||||
module("vicious.contrib.pop")
|
||||
|
||||
|
||||
-- {{{ POP3 count widget type
|
||||
local function worker(format, warg)
|
||||
if not sock_avail or (not warg or #warg ~= 4) then
|
||||
return {"N/A"}
|
||||
end
|
||||
|
||||
local host, port = warg[1], tonumber(warg[2])
|
||||
local user, pass = warg[3], warg[4]
|
||||
|
||||
local client = socket.tcp()
|
||||
client:settimeout(3)
|
||||
client:connect(host, port)
|
||||
client:receive("*l")
|
||||
client:send("USER " .. user .. "\r\n")
|
||||
client:receive("*l")
|
||||
client:send("PASS " .. pass .. "\r\n")
|
||||
client:receive("*l")
|
||||
client:send("STAT" .. "\r\n")
|
||||
local response = client:receive("*l")
|
||||
client:close()
|
||||
|
||||
if response:find("%+OK") then
|
||||
response = response:match("%+OK (%d+)")
|
||||
end
|
||||
|
||||
return {response}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,111 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, MrMagne <mr.magne@yahoo.fr>
|
||||
-- * (c) 2010, Mic92 <jthalheim@gmail.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local os = { execute = os.execute }
|
||||
local table = { insert = table.insert }
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match,
|
||||
format = string.format,
|
||||
gmatch = string.gmatch
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Pulse: provides volume levels of requested pulseaudio sinks and methods to change them
|
||||
module("vicious.contrib.pulse")
|
||||
|
||||
-- {{{ Helper function
|
||||
local function pacmd(args)
|
||||
local f = io.popen("pacmd "..args)
|
||||
local line = f:read("*all")
|
||||
f:close()
|
||||
return line
|
||||
end
|
||||
|
||||
local function escape(text)
|
||||
local special_chars = { ["."] = "%.", ["-"] = "%-" }
|
||||
return text:gsub("[%.%-]", special_chars)
|
||||
end
|
||||
|
||||
local cached_sinks = {}
|
||||
local function get_sink_name(sink)
|
||||
if type(sink) == "string" then return sink end
|
||||
-- avoid nil keys
|
||||
local key = sink or 1
|
||||
-- Cache requests
|
||||
if not cached_sinks[key] then
|
||||
local line = pacmd("list-sinks")
|
||||
for s in string.gmatch(line, "name: <(.-)>") do
|
||||
table.insert(cached_sinks, s)
|
||||
end
|
||||
end
|
||||
|
||||
return cached_sinks[key]
|
||||
end
|
||||
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Pulseaudio widget type
|
||||
local function worker(format, sink)
|
||||
sink = get_sink_name(sink)
|
||||
if sink == nil then return {0, "unknown"} end
|
||||
|
||||
-- Get sink data
|
||||
local data = pacmd("dump")
|
||||
|
||||
-- If mute return 0 (not "Mute") so we don't break progressbars
|
||||
if string.find(data,"set%-sink%-mute "..escape(sink).." yes") then
|
||||
return {0, "off"}
|
||||
end
|
||||
|
||||
local vol = tonumber(string.match(data, "set%-sink%-volume "..escape(sink).." (0x[%x]+)"))
|
||||
if vol == nil then vol = 0 end
|
||||
|
||||
return { vol/0x10000*100, "on"}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Volume control helper
|
||||
function add(percent, sink)
|
||||
sink = get_sink_name(sink)
|
||||
if sink == nil then return end
|
||||
|
||||
local data = pacmd("dump")
|
||||
|
||||
local pattern = "set%-sink%-volume "..escape(sink).." (0x[%x]+)"
|
||||
local initial_vol = tonumber(string.match(data, pattern))
|
||||
|
||||
local vol = initial_vol + percent/100*0x10000
|
||||
if vol > 0x10000 then vol = 0x10000 end
|
||||
if vol < 0 then vol = 0 end
|
||||
|
||||
local cmd = string.format("pacmd set-sink-volume %s 0x%x >/dev/null", sink, vol)
|
||||
return os.execute(cmd)
|
||||
end
|
||||
|
||||
function toggle(sink)
|
||||
sink = get_sink_name(sink)
|
||||
if sink == nil then return end
|
||||
|
||||
local data = pacmd("dump")
|
||||
local pattern = "set%-sink%-mute "..escape(sink).." (%a%a%a?)"
|
||||
local mute = string.match(data, pattern)
|
||||
|
||||
-- 0 to enable a sink or 1 to mute it.
|
||||
local state = { yes = 0, no = 1}
|
||||
local cmd = string.format("pacmd set-sink-mute %s %d", sink, state[mute])
|
||||
return os.execute(cmd)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,67 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2009, olcc
|
||||
--
|
||||
-- This is now a standalone RSS reader for awesome:
|
||||
-- * http://github.com/olcc/aware
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
-- }}}
|
||||
|
||||
|
||||
-- RSS: provides latest world news
|
||||
module("vicious.contrib.rss")
|
||||
|
||||
|
||||
-- {{{ RSS widget type
|
||||
local function worker(format, input)
|
||||
-- input: * feed - feed url
|
||||
-- * object - entity to look for (typically: 'item')
|
||||
-- * fields - fields to read (example: 'link', 'title', 'description')
|
||||
-- output: * count - number of entities found
|
||||
-- * one table for each field, containing wanted values
|
||||
local feed = input.feed
|
||||
local object = input.object
|
||||
local fields = input.fields
|
||||
|
||||
-- Initialise tables
|
||||
local out = {}
|
||||
|
||||
for _, v in pairs(fields) do
|
||||
out[v] = {}
|
||||
end
|
||||
|
||||
-- Initialise variables
|
||||
local ob = nil
|
||||
local i,j,k = 1, 1, 0
|
||||
local curl = "curl -A 'Mozilla/4.0' -fsm 5 --connect-timeout 3 "
|
||||
|
||||
-- Get the feed
|
||||
local f = io.popen(curl .. '"' .. feed .. '"')
|
||||
local feed = f:read("*all")
|
||||
f:close()
|
||||
|
||||
while true do
|
||||
i, j, ob = feed.find(feed, "<" .. object .. ">(.-)</" .. object .. ">", i)
|
||||
if not ob then break end
|
||||
|
||||
for _, v in pairs(fields) do
|
||||
out[v][k] = ob:match("<" .. v .. ">(.*)</" .. v .. ">")
|
||||
end
|
||||
|
||||
k = k+1
|
||||
i = j+1
|
||||
end
|
||||
|
||||
-- Update the entity count
|
||||
out.count = k
|
||||
|
||||
return out
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,68 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Greg D. <jabbas@jabbas.pl>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
local string = {
|
||||
gsub = string.gsub,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Sensors: provides access to lm_sensors data
|
||||
module("vicious.contrib.sensors")
|
||||
|
||||
|
||||
-- {{{ Split helper function
|
||||
local function datasplit(str)
|
||||
-- Splitting strings into associative array
|
||||
-- with some magic to get the values right.
|
||||
str = string.gsub(str, "\n", ":")
|
||||
|
||||
local tbl = {}
|
||||
string.gsub(str, "([^:]*)", function (v)
|
||||
if string.match(v, ".") then
|
||||
table.insert(tbl, v)
|
||||
end
|
||||
end)
|
||||
|
||||
local assoc = {}
|
||||
for c = 1, #tbl, 2 do
|
||||
local k = string.gsub(tbl[c], ".*_", "")
|
||||
local v = tonumber(string.match(tbl[c+1], "[%d]+"))
|
||||
assoc[k] = v
|
||||
end
|
||||
|
||||
return assoc
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Sensors widget type
|
||||
local function worker(format, warg)
|
||||
-- Get data from all sensors
|
||||
local f = io.popen("LANG=C sensors -uA")
|
||||
local lm_sensors = f:read("*all")
|
||||
f:close()
|
||||
|
||||
local sensor_data = string.gsub(
|
||||
string.match(lm_sensors, warg..":\n(%s%s.-)\n[^ ]"), " ", "")
|
||||
|
||||
-- One of: crit, max
|
||||
local divisor = "crit"
|
||||
local s_data = datasplit(sensor_data)
|
||||
|
||||
if s_data[divisor] and s_data[divisor] > 0 then
|
||||
s_data.percent = s_data.input / s_data[divisor] * 100
|
||||
end
|
||||
|
||||
return {s_data.input, tonumber(s_data.percent)}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
149
Old/ATARI/home/burchettm/.config/awesome/lib/vicious/helpers.lua
Normal file
149
Old/ATARI/home/burchettm/.config/awesome/lib/vicious/helpers.lua
Normal file
@ -0,0 +1,149 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Rémy C. <shikamaru@mandriva.org>
|
||||
-- * (c) 2009, Benedikt Sauer <filmor@gmail.com>
|
||||
-- * (c) 2009, Henning Glawe <glaweh@debian.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local rawget = rawget
|
||||
local require = require
|
||||
local tonumber = tonumber
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local getmetatable = getmetatable
|
||||
local string = {
|
||||
upper = string.upper,
|
||||
format = string.format
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Helpers: provides helper functions for vicious widgets
|
||||
module("vicious.helpers")
|
||||
|
||||
|
||||
-- {{{ Variable definitions
|
||||
local scroller = {}
|
||||
-- }}}
|
||||
|
||||
-- {{{ Helper functions
|
||||
-- {{{ Loader of vicious modules
|
||||
function wrequire(table, key)
|
||||
local module = rawget(table, key)
|
||||
return module or require(table._NAME .. "." .. key)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Expose path as a Lua table
|
||||
function pathtotable(dir)
|
||||
return setmetatable({ _path = dir },
|
||||
{ __index = function(table, index)
|
||||
local path = table._path .. '/' .. index
|
||||
local f = io.open(path)
|
||||
if f then
|
||||
local s = f:read("*all")
|
||||
f:close()
|
||||
if s then
|
||||
return s
|
||||
else
|
||||
local o = { _path = path }
|
||||
setmetatable(o, getmetatable(table))
|
||||
return o
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Format a string with args
|
||||
function format(format, args)
|
||||
for var, val in pairs(args) do
|
||||
format = format:gsub("$" .. (tonumber(var) and var or
|
||||
var:gsub("[-+?*]", function(i) return "%"..i end)),
|
||||
val)
|
||||
end
|
||||
|
||||
return format
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Format units to one decimal point
|
||||
function uformat(array, key, value, unit)
|
||||
for u, v in pairs(unit) do
|
||||
array["{"..key.."_"..u.."}"] = string.format("%.1f", value/v)
|
||||
end
|
||||
|
||||
return array
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Escape a string
|
||||
function escape(text)
|
||||
local xml_entities = {
|
||||
["\""] = """,
|
||||
["&"] = "&",
|
||||
["'"] = "'",
|
||||
["<"] = "<",
|
||||
[">"] = ">"
|
||||
}
|
||||
|
||||
return text and text:gsub("[\"&'<>]", xml_entities)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Capitalize a string
|
||||
function capitalize(text)
|
||||
return text and text:gsub("([%w])([%w]*)", function(c, s)
|
||||
return string.upper(c) .. s
|
||||
end)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Truncate a string
|
||||
function truncate(text, maxlen)
|
||||
local txtlen = text:len()
|
||||
|
||||
if txtlen > maxlen then
|
||||
text = text:sub(1, maxlen - 3) .. "..."
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Scroll through a string
|
||||
function scroll(text, maxlen, widget)
|
||||
if not scroller[widget] then
|
||||
scroller[widget] = { i = 1, d = true }
|
||||
end
|
||||
|
||||
local txtlen = text:len()
|
||||
local state = scroller[widget]
|
||||
|
||||
if txtlen > maxlen then
|
||||
if state.d then
|
||||
text = text:sub(state.i, state.i + maxlen) .. "..."
|
||||
state.i = state.i + 3
|
||||
|
||||
if maxlen + state.i >= txtlen then
|
||||
state.d = false
|
||||
end
|
||||
else
|
||||
text = "..." .. text:sub(state.i, state.i + maxlen)
|
||||
state.i = state.i - 3
|
||||
|
||||
if state.i <= 1 then
|
||||
state.d = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
-- }}}
|
||||
-- }}}
|
249
Old/ATARI/home/burchettm/.config/awesome/lib/vicious/init.lua
Normal file
249
Old/ATARI/home/burchettm/.config/awesome/lib/vicious/init.lua
Normal file
@ -0,0 +1,249 @@
|
||||
---------------------------------------------------
|
||||
-- Vicious widgets for the awesome window manager
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Setup environment
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local tonumber = tonumber
|
||||
local capi = { timer = timer }
|
||||
local os = { time = os.time }
|
||||
local table = {
|
||||
insert = table.insert,
|
||||
remove = table.remove
|
||||
}
|
||||
require("vicious.helpers")
|
||||
require("vicious.widgets")
|
||||
--require("vicious.contrib")
|
||||
|
||||
-- Vicious: widgets for the awesome window manager
|
||||
module("vicious")
|
||||
|
||||
|
||||
-- Initialize tables
|
||||
local timers = {}
|
||||
local registered = {}
|
||||
local widget_cache = {}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- {{{ Local functions
|
||||
-- {{{ Update a widget
|
||||
local function update(widget, reg, disablecache)
|
||||
-- Check if there are any equal widgets
|
||||
if reg == nil then
|
||||
for w, i in pairs(registered) do
|
||||
if w == widget then
|
||||
for _, r in pairs(i) do
|
||||
update(w, r, disablecache)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local t = os.time()
|
||||
local data = {}
|
||||
|
||||
-- Check for chached output newer than the last update
|
||||
if widget_cache[reg.wtype] ~= nil then
|
||||
local c = widget_cache[reg.wtype]
|
||||
|
||||
if (c.time == nil or c.time <= t-reg.timer) or disablecache then
|
||||
c.time, c.data = t, reg.wtype(reg.format, reg.warg)
|
||||
end
|
||||
|
||||
data = c.data
|
||||
else
|
||||
data = reg.wtype and reg.wtype(reg.format, reg.warg)
|
||||
end
|
||||
|
||||
if type(data) == "table" then
|
||||
if type(reg.format) == "string" then
|
||||
data = helpers.format(reg.format, data)
|
||||
elseif type(reg.format) == "function" then
|
||||
data = reg.format(widget, data)
|
||||
end
|
||||
end
|
||||
|
||||
if widget.add_value ~= nil then
|
||||
widget:add_value(tonumber(data) and tonumber(data)/100)
|
||||
elseif widget.set_value ~= nil then
|
||||
widget:set_value(tonumber(data) and tonumber(data)/100)
|
||||
elseif widget.set_markup ~= nil then
|
||||
widget:set_markup(data)
|
||||
else
|
||||
widget.text = data
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Register from reg object
|
||||
local function regregister(reg)
|
||||
if not reg.running then
|
||||
if registered[reg.widget] == nil then
|
||||
registered[reg.widget] = {}
|
||||
table.insert(registered[reg.widget], reg)
|
||||
else
|
||||
local already = false
|
||||
|
||||
for w, i in pairs(registered) do
|
||||
if w == reg.widget then
|
||||
for _, v in pairs(i) do
|
||||
if v == reg then
|
||||
already = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if already then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not already then
|
||||
table.insert(registered[reg.widget], reg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Start the timer
|
||||
if reg.timer > 0 then
|
||||
timers[reg.update] = {
|
||||
timer = capi.timer({ timeout = reg.timer })
|
||||
}
|
||||
|
||||
local tm = timers[reg.update].timer
|
||||
if tm.connect_signal then
|
||||
tm:connect_signal("timeout", reg.update)
|
||||
else
|
||||
tm:add_signal("timeout", reg.update)
|
||||
end
|
||||
tm:start()
|
||||
|
||||
-- Initial update
|
||||
tm:emit_signal("timeout")
|
||||
end
|
||||
reg.running = true
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- {{{ Global functions
|
||||
-- {{{ Register a widget
|
||||
function register(widget, wtype, format, timer, warg)
|
||||
local reg = {}
|
||||
local widget = widget
|
||||
|
||||
-- Set properties
|
||||
reg.wtype = wtype
|
||||
reg.format = format
|
||||
reg.timer = timer
|
||||
reg.warg = warg
|
||||
reg.widget = widget
|
||||
|
||||
-- Update function
|
||||
reg.update = function ()
|
||||
update(widget, reg)
|
||||
end
|
||||
|
||||
-- Default to 2s timer
|
||||
if reg.timer == nil then
|
||||
reg.timer = 2
|
||||
end
|
||||
|
||||
-- Register a reg object
|
||||
regregister(reg)
|
||||
|
||||
-- Return a reg object for reuse
|
||||
return reg
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Unregister a widget
|
||||
function unregister(widget, keep, reg)
|
||||
if reg == nil then
|
||||
for w, i in pairs(registered) do
|
||||
if w == widget then
|
||||
for _, v in pairs(i) do
|
||||
reg = unregister(w, keep, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return reg
|
||||
end
|
||||
|
||||
if not keep then
|
||||
for w, i in pairs(registered) do
|
||||
if w == widget then
|
||||
for k, v in pairs(i) do
|
||||
if v == reg then
|
||||
table.remove(registered[w], k)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop the timer
|
||||
if timers[reg.update].timer.started then
|
||||
timers[reg.update].timer:stop()
|
||||
end
|
||||
reg.running = false
|
||||
|
||||
return reg
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Enable caching of a widget type
|
||||
function cache(wtype)
|
||||
if wtype ~= nil then
|
||||
if widget_cache[wtype] == nil then
|
||||
widget_cache[wtype] = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Force update of widgets
|
||||
function force(wtable)
|
||||
if type(wtable) == "table" then
|
||||
for _, w in pairs(wtable) do
|
||||
update(w, nil, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Suspend all widgets
|
||||
function suspend()
|
||||
for w, i in pairs(registered) do
|
||||
for _, v in pairs(i) do
|
||||
unregister(w, true, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Activate a widget
|
||||
function activate(widget)
|
||||
for w, i in pairs(registered) do
|
||||
if widget == nil or w == widget then
|
||||
for _, v in pairs(i) do
|
||||
regregister(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
-- }}}
|
@ -0,0 +1,85 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local string = { format = string.format }
|
||||
local helpers = require("vicious.helpers")
|
||||
local math = {
|
||||
min = math.min,
|
||||
floor = math.floor
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Bat: provides state, charge, and remaining time for a requested battery
|
||||
module("vicious.widgets.bat")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local battery = helpers.pathtotable("/sys/class/power_supply/"..warg)
|
||||
local battery_state = {
|
||||
["Full\n"] = "↯",
|
||||
["Unknown\n"] = "⌁",
|
||||
["Charged\n"] = "↯",
|
||||
["Charging\n"] = "+",
|
||||
["Discharging\n"] = "-"
|
||||
}
|
||||
|
||||
-- Check if the battery is present
|
||||
if battery.present ~= "1\n" then
|
||||
return {battery_state["Unknown\n"], 0, "N/A"}
|
||||
end
|
||||
|
||||
|
||||
-- Get state information
|
||||
local state = battery_state[battery.status] or battery_state["Unknown\n"]
|
||||
|
||||
-- Get capacity information
|
||||
if battery.charge_now then
|
||||
remaining, capacity = battery.charge_now, battery.charge_full
|
||||
elseif battery.energy_now then
|
||||
remaining, capacity = battery.energy_now, battery.energy_full
|
||||
else
|
||||
return {battery_state["Unknown\n"], 0, "N/A"}
|
||||
end
|
||||
|
||||
-- Calculate percentage (but work around broken BAT/ACPI implementations)
|
||||
local percent = math.min(math.floor(remaining / capacity * 100), 100)
|
||||
|
||||
|
||||
-- Get charge information
|
||||
if battery.current_now then
|
||||
rate = battery.current_now
|
||||
elseif battery.power_now then
|
||||
rate = battery.power_now
|
||||
else
|
||||
return {state, percent, "N/A"}
|
||||
end
|
||||
|
||||
-- Calculate remaining (charging or discharging) time
|
||||
local time = "N/A"
|
||||
if rate ~= nil then
|
||||
if state == "+" then
|
||||
timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate)
|
||||
elseif state == "-" then
|
||||
timeleft = tonumber(remaining) / tonumber(rate)
|
||||
else
|
||||
return {state, percent, time}
|
||||
end
|
||||
local hoursleft = math.floor(timeleft)
|
||||
local minutesleft = math.floor((timeleft - hoursleft) * 60 )
|
||||
time = string.format("%02d:%02d", hoursleft, minutesleft)
|
||||
end
|
||||
|
||||
return {state, percent, time}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,75 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2011, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
-- * (c) 2011, Jörg Thalheim <jthalheim@gmail.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local ipairs = ipairs
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local math = { floor = math.floor }
|
||||
local table = { insert = table.insert }
|
||||
local string = {
|
||||
sub = string.sub,
|
||||
gmatch = string.gmatch
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Cpu: provides CPU usage for all available CPUs/cores
|
||||
module("vicious.widgets.cpu")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local cpu_usage = {}
|
||||
local cpu_total = {}
|
||||
local cpu_active = {}
|
||||
|
||||
-- {{{ CPU widget type
|
||||
local function worker(format)
|
||||
local cpu_lines = {}
|
||||
|
||||
-- Get CPU stats
|
||||
for line in io.lines("/proc/stat") do
|
||||
if string.sub(line, 1, 3) ~= "cpu" then break end
|
||||
|
||||
cpu_lines[#cpu_lines+1] = {}
|
||||
|
||||
for i in string.gmatch(line, "[%s]+([^%s]+)") do
|
||||
table.insert(cpu_lines[#cpu_lines], i)
|
||||
end
|
||||
end
|
||||
|
||||
-- Ensure tables are initialized correctly
|
||||
for i = #cpu_total + 1, #cpu_lines do
|
||||
cpu_total[i] = 0
|
||||
cpu_usage[i] = 0
|
||||
cpu_active[i] = 0
|
||||
end
|
||||
|
||||
|
||||
for i, v in ipairs(cpu_lines) do
|
||||
-- Calculate totals
|
||||
local total_new = 0
|
||||
for j = 1, #v do
|
||||
total_new = total_new + v[j]
|
||||
end
|
||||
local active_new = total_new - (v[4] + v[5])
|
||||
|
||||
-- Calculate percentage
|
||||
local diff_total = total_new - cpu_total[i]
|
||||
local diff_active = active_new - cpu_active[i]
|
||||
cpu_usage[i] = math.floor((diff_active / diff_total) * 100)
|
||||
|
||||
-- Store totals
|
||||
cpu_total[i] = total_new
|
||||
cpu_active[i] = active_new
|
||||
end
|
||||
|
||||
return cpu_usage
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,56 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Cpufreq: provides freq, voltage and governor info for a requested CPU
|
||||
module("vicious.widgets.cpufreq")
|
||||
|
||||
|
||||
-- {{{ CPU frequency widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local cpufreq = helpers.pathtotable("/sys/devices/system/cpu/"..warg.."/cpufreq")
|
||||
local governor_state = {
|
||||
["ondemand\n"] = "↯",
|
||||
["powersave\n"] = "⌁",
|
||||
["userspace\n"] = "¤",
|
||||
["performance\n"] = "⚡",
|
||||
["conservative\n"] = "↯"
|
||||
}
|
||||
-- Default voltage values
|
||||
local voltage = { v = "N/A", mv = "N/A" }
|
||||
|
||||
|
||||
-- Get the current frequency
|
||||
local freq = tonumber(cpufreq.scaling_cur_freq)
|
||||
-- Calculate MHz and GHz
|
||||
local freqmhz = freq / 1000
|
||||
local freqghz = freqmhz / 1000
|
||||
|
||||
-- Get the current voltage
|
||||
if cpufreq.scaling_voltages then
|
||||
voltage.mv = tonumber(string.match(cpufreq.scaling_voltages, freq.."[%s]([%d]+)"))
|
||||
-- Calculate voltage from mV
|
||||
voltage.v = voltage.mv / 1000
|
||||
end
|
||||
|
||||
-- Get the current governor
|
||||
local governor = cpufreq.scaling_governor
|
||||
-- Represent the governor as a symbol
|
||||
governor = governor_state[governor] or governor
|
||||
|
||||
return {freqmhz, freqghz, voltage.mv, voltage.v, governor}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,43 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gmatch = string.gmatch }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Cpuinf: provides speed and cache information for all available CPUs/cores
|
||||
module("vicious.widgets.cpuinf")
|
||||
|
||||
|
||||
-- {{{ CPU Information widget type
|
||||
local function worker(format)
|
||||
local id = nil
|
||||
|
||||
local cpu_info = {} -- Get CPU info
|
||||
for line in io.lines("/proc/cpuinfo") do
|
||||
for k, v in string.gmatch(line, "([%a%s]+)[%s]+:[%s]([%d]+).-$") do
|
||||
if k == "processor" then
|
||||
id = v
|
||||
elseif k == "cpu MHz\t" or k == "cpu MHz" then
|
||||
local speed = tonumber(v)
|
||||
cpu_info["{cpu"..id.." mhz}"] = speed
|
||||
cpu_info["{cpu"..id.." ghz}"] = speed / 1000
|
||||
elseif k == "cache size" then
|
||||
local cache = tonumber(v)
|
||||
cpu_info["{cpu"..id.." kb}"] = cache
|
||||
cpu_info["{cpu"..id.." mb}"] = cache / 1024
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return cpu_info
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,26 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local setmetatable = setmetatable
|
||||
local os = {
|
||||
date = os.date,
|
||||
time = os.time
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Date: provides access to os.date with optional time formatting
|
||||
module("vicious.widgets.date")
|
||||
|
||||
|
||||
-- {{{ Date widget type
|
||||
local function worker(format, warg)
|
||||
return os.date(format or nil, warg and os.time()+warg or nil)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,72 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2011, Jörg T. <jthalheim@gmail.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
local os = {
|
||||
time = os.time,
|
||||
difftime = os.difftime
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Disk I/O: provides I/O statistics for requested storage devices
|
||||
module("vicious.widgets.dio")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local disk_usage = {}
|
||||
local disk_stats = {}
|
||||
local disk_time = 0
|
||||
-- Constant definitions
|
||||
local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 }
|
||||
|
||||
-- {{{ Disk I/O widget type
|
||||
local function worker(format)
|
||||
local disk_lines = {}
|
||||
|
||||
for line in io.lines("/proc/diskstats") do
|
||||
local device, read, write =
|
||||
-- Linux kernel documentation: Documentation/iostats.txt
|
||||
string.match(line, "([^%s]+) %d+ %d+ (%d+) %d+ %d+ %d+ (%d+)")
|
||||
disk_lines[device] = { read, write }
|
||||
end
|
||||
|
||||
local time = os.time()
|
||||
local interval = os.difftime(time, disk_time)
|
||||
if interval == 0 then interval = 1 end
|
||||
|
||||
for device, stats in pairs(disk_lines) do
|
||||
-- Avoid insane values on startup
|
||||
local last_stats = disk_stats[device] or stats
|
||||
|
||||
-- Check for overflows and counter resets (> 2^32)
|
||||
if stats[1] < last_stats[1] or stats[2] < last_stats[2] then
|
||||
last_stats[1], last_stats[2] = stats[1], stats[2]
|
||||
end
|
||||
|
||||
-- Diskstats are absolute, substract our last reading
|
||||
-- * divide by timediff because we don't know the timer value
|
||||
local read = (stats[1] - last_stats[1]) / interval
|
||||
local write = (stats[2] - last_stats[2]) / interval
|
||||
|
||||
-- Calculate and store I/O
|
||||
helpers.uformat(disk_usage, device.." read", read, unit)
|
||||
helpers.uformat(disk_usage, device.." write", write, unit)
|
||||
helpers.uformat(disk_usage, device.." total", read + write, unit)
|
||||
end
|
||||
|
||||
disk_time = time
|
||||
disk_stats = disk_lines
|
||||
|
||||
return disk_usage
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,51 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- FS: provides file system disk space usage
|
||||
module("vicious.widgets.fs")
|
||||
|
||||
|
||||
-- Variable definitions
|
||||
local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
|
||||
|
||||
-- {{{ Filesystem widget type
|
||||
local function worker(format, warg)
|
||||
-- Fallback to listing local filesystems
|
||||
if warg then warg = "" else warg = "-l" end
|
||||
|
||||
local fs_info = {} -- Get data from df
|
||||
local f = io.popen("LC_ALL=C df -kP " .. warg)
|
||||
|
||||
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
|
||||
helpers.uformat(fs_info, m .. " size", s, unit)
|
||||
helpers.uformat(fs_info, m .. " used", u, unit)
|
||||
helpers.uformat(fs_info, m .. " avail", a, unit)
|
||||
|
||||
fs_info["{" .. m .. " used_p}"] = tonumber(p)
|
||||
fs_info["{" .. m .. " avail_p}"] = 100 - tonumber(p)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return fs_info
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,82 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local helpers = require("vicious.helpers")
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Gmail: provides count of new and subject of last e-mail on Gmail
|
||||
module("vicious.widgets.gmail")
|
||||
|
||||
|
||||
-- {{{ Variable definitions
|
||||
local rss = {
|
||||
inbox = {
|
||||
"https://mail.google.com/mail/feed/atom",
|
||||
"Gmail %- Inbox"
|
||||
},
|
||||
unread = {
|
||||
"https://mail.google.com/mail/feed/atom/unread",
|
||||
"Gmail %- Label"
|
||||
},
|
||||
--labelname = {
|
||||
-- "https://mail.google.com/mail/feed/atom/labelname",
|
||||
-- "Gmail %- Label"
|
||||
--},
|
||||
}
|
||||
|
||||
-- Default is just Inbox
|
||||
local feed = rss.inbox
|
||||
local mail = {
|
||||
["{count}"] = 0,
|
||||
["{subject}"] = "N/A"
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- {{{ Gmail widget type
|
||||
local function worker(format, warg)
|
||||
-- Get info from the Gmail atom feed
|
||||
local f = io.popen("curl --connect-timeout 1 -m 3 -fsn " .. feed[1])
|
||||
|
||||
-- Could be huge don't read it all at once, info we are after is at the top
|
||||
for line in f:lines() do
|
||||
mail["{count}"] = -- Count comes before messages and matches at least 0
|
||||
tonumber(string.match(line, "<fullcount>([%d]+)</fullcount>")) or mail["{count}"]
|
||||
|
||||
-- Find subject tags
|
||||
local title = string.match(line, "<title>(.*)</title>")
|
||||
-- If the subject changed then break out of the loop
|
||||
if title ~= nil and not string.find(title, feed[2]) then
|
||||
-- Check if we should scroll, or maybe truncate
|
||||
if warg then
|
||||
if type(warg) == "table" then
|
||||
title = helpers.scroll(title, warg[1], warg[2])
|
||||
else
|
||||
title = helpers.truncate(title, warg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Spam sanitize the subject and store
|
||||
mail["{subject}"] = helpers.escape(title)
|
||||
break
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return mail
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,37 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gmatch = string.gmatch }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Hddtemp: provides hard drive temperatures using the hddtemp daemon
|
||||
module("vicious.widgets.hddtemp")
|
||||
|
||||
|
||||
-- {{{ HDD Temperature widget type
|
||||
local function worker(format, warg)
|
||||
-- Fallback to default hddtemp port
|
||||
if warg == nil then warg = 7634 end
|
||||
|
||||
local hdd_temp = {} -- Get info from the hddtemp daemon
|
||||
local f = io.popen("curl --connect-timeout 1 -fsm 3 telnet://127.0.0.1:"..warg)
|
||||
|
||||
for line in f:lines() do
|
||||
for d, t in string.gmatch(line, "|([%/%a%d]+)|.-|([%d]+)|[CF]+|") do
|
||||
hdd_temp["{"..d.."}"] = tonumber(t)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return hdd_temp
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,17 @@
|
||||
---------------------------------------------------
|
||||
-- Vicious widgets for the awesome window manager
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Setup environment
|
||||
local setmetatable = setmetatable
|
||||
local wrequire = require("vicious.helpers").wrequire
|
||||
|
||||
-- Vicious: widgets for the awesome window manager
|
||||
module("vicious.widgets")
|
||||
-- }}}
|
||||
|
||||
-- Load modules at runtime as needed
|
||||
setmetatable(_M, { __index = wrequire })
|
@ -0,0 +1,52 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gfind = string.gfind }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mbox: provides the subject of last e-mail in a mbox file
|
||||
module("vicious.widgets.mbox")
|
||||
|
||||
|
||||
-- Initialize variables
|
||||
local subject = "N/A"
|
||||
|
||||
-- {{{ Mailbox widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- mbox could be huge, get a 30kb chunk from EOF
|
||||
if type(warg) ~= "table" then mbox = warg end
|
||||
-- * attachment could be much bigger than 30kb
|
||||
local f = io.open(mbox or warg[1])
|
||||
f:seek("end", -30720)
|
||||
local txt = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Find all Subject lines
|
||||
for i in string.gfind(txt, "Subject: ([^\n]*)") do
|
||||
subject = i
|
||||
end
|
||||
|
||||
-- Check if we should scroll, or maybe truncate
|
||||
if type(warg) == "table" then
|
||||
if warg[3] ~= nil then
|
||||
subject = helpers.scroll(subject, warg[2], warg[3])
|
||||
else
|
||||
subject = helpers.truncate(subject, warg[2])
|
||||
end
|
||||
end
|
||||
|
||||
return {helpers.escape(subject)}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,57 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local string = { find = string.find }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mboxc: provides the count of total, old and new messages in mbox files
|
||||
module("vicious.widgets.mboxc")
|
||||
|
||||
|
||||
-- {{{ Mbox count widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Initialize counters
|
||||
local count = { old = 0, total = 0, new = 0 }
|
||||
|
||||
-- Get data from mbox files
|
||||
for i=1, #warg do
|
||||
local f = io.open(warg[i])
|
||||
|
||||
while true do
|
||||
-- Read the mbox line by line, if we are going to read
|
||||
-- some *HUGE* folders then switch to reading chunks
|
||||
local lines = f:read("*line")
|
||||
if not lines then break end
|
||||
|
||||
-- Find all messages
|
||||
-- * http://www.jwz.org/doc/content-length.html
|
||||
local _, from = string.find(lines, "^From[%s]")
|
||||
if from ~= nil then count.total = count.total + 1 end
|
||||
|
||||
-- Read messages have the Status header
|
||||
local _, status = string.find(lines, "^Status:[%s]RO$")
|
||||
if status ~= nil then count.old = count.old + 1 end
|
||||
|
||||
-- Skip the folder internal data
|
||||
local _, int = string.find(lines, "^Subject:[%s].*FOLDER[%s]INTERNAL[%s]DATA")
|
||||
if int ~= nil then count.total = count.total - 1 end
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- Substract total from old to get the new count
|
||||
count.new = count.total - count.old
|
||||
|
||||
return {count.total, count.old, count.new}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,40 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) Maildir Biff Widget, Fredrik Ax
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mdir: provides the number of new and unread messages in Maildir structures/dirs
|
||||
module("vicious.widgets.mdir")
|
||||
|
||||
|
||||
-- {{{ Maildir widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Initialize counters
|
||||
local count = { new = 0, cur = 0 }
|
||||
|
||||
for i=1, #warg do
|
||||
-- Recursively find new messages
|
||||
local f = io.popen("find "..warg[i].." -type f -wholename '*/new/*'")
|
||||
for line in f:lines() do count.new = count.new + 1 end
|
||||
f:close()
|
||||
|
||||
-- Recursively find "old" messages lacking the Seen flag
|
||||
local f = io.popen("find "..warg[i].." -type f -regex '.*/cur/.*2,[^S]*$'")
|
||||
for line in f:lines() do count.cur = count.cur + 1 end
|
||||
f:close()
|
||||
end
|
||||
|
||||
return {count.new, count.cur}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,49 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local math = { floor = math.floor }
|
||||
local string = { gmatch = string.gmatch }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mem: provides RAM and Swap usage statistics
|
||||
module("vicious.widgets.mem")
|
||||
|
||||
|
||||
-- {{{ Memory widget type
|
||||
local function worker(format)
|
||||
local mem = { buf = {}, swp = {} }
|
||||
|
||||
-- Get MEM info
|
||||
for line in io.lines("/proc/meminfo") do
|
||||
for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+") do
|
||||
if k == "MemTotal" then mem.total = math.floor(v/1024)
|
||||
elseif k == "MemFree" then mem.buf.f = math.floor(v/1024)
|
||||
elseif k == "Buffers" then mem.buf.b = math.floor(v/1024)
|
||||
elseif k == "Cached" then mem.buf.c = math.floor(v/1024)
|
||||
elseif k == "SwapTotal" then mem.swp.t = math.floor(v/1024)
|
||||
elseif k == "SwapFree" then mem.swp.f = math.floor(v/1024)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate memory percentage
|
||||
mem.free = mem.buf.f + mem.buf.b + mem.buf.c
|
||||
mem.inuse = mem.total - mem.free
|
||||
mem.usep = math.floor(mem.inuse / mem.total * 100)
|
||||
-- Calculate swap percentage
|
||||
mem.swp.inuse = mem.swp.t - mem.swp.f
|
||||
mem.swp.usep = math.floor(mem.swp.inuse / mem.swp.t * 100)
|
||||
|
||||
return {mem.usep, mem.inuse, mem.total, mem.free,
|
||||
mem.swp.usep, mem.swp.inuse, mem.swp.t, mem.swp.f}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,63 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gmatch = string.gmatch }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mpd: provides Music Player Daemon information
|
||||
module("vicious.widgets.mpd")
|
||||
|
||||
|
||||
-- {{{ MPD widget type
|
||||
local function worker(format, warg)
|
||||
local mpd_state = {
|
||||
["{volume}"] = 0,
|
||||
["{state}"] = "N/A",
|
||||
["{Artist}"] = "N/A",
|
||||
["{Title}"] = "N/A",
|
||||
["{Album}"] = "N/A",
|
||||
["{Genre}"] = "N/A",
|
||||
--["{Name}"] = "N/A",
|
||||
--["{file}"] = "N/A",
|
||||
}
|
||||
|
||||
-- Fallback to MPD defaults
|
||||
local pass = warg and (warg.password or warg[1]) or "\"\""
|
||||
local host = warg and (warg.host or warg[2]) or "127.0.0.1"
|
||||
local port = warg and (warg.port or warg[3]) or "6600"
|
||||
|
||||
-- Construct MPD client options
|
||||
local mpdh = "telnet://"..host..":"..port
|
||||
local echo = "echo 'password "..pass.."\nstatus\ncurrentsong\nclose'"
|
||||
|
||||
-- Get data from MPD server
|
||||
local f = io.popen(echo.." | curl --connect-timeout 1 -fsm 3 "..mpdh)
|
||||
|
||||
for line in f:lines() do
|
||||
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
|
||||
if k == "volume" then mpd_state["{"..k.."}"] = v and tonumber(v)
|
||||
elseif k == "state" then mpd_state["{"..k.."}"] = helpers.capitalize(v)
|
||||
elseif k == "Artist" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
elseif k == "Title" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
elseif k == "Album" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
elseif k == "Genre" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
--elseif k == "Name" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
--elseif k == "file" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return mpd_state
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,79 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local os = { time = os.time }
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Net: provides state and usage statistics of all network interfaces
|
||||
module("vicious.widgets.net")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local nets = {}
|
||||
-- Variable definitions
|
||||
local unit = { ["b"] = 1, ["kb"] = 1024,
|
||||
["mb"] = 1024^2, ["gb"] = 1024^3
|
||||
}
|
||||
|
||||
-- {{{ Net widget type
|
||||
local function worker(format)
|
||||
local args = {}
|
||||
|
||||
-- Get NET stats
|
||||
for line in io.lines("/proc/net/dev") do
|
||||
-- Match wmaster0 as well as rt0 (multiple leading spaces)
|
||||
local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):")
|
||||
if name ~= nil then
|
||||
-- Received bytes, first value after the name
|
||||
local recv = tonumber(string.match(line, ":[%s]*([%d]+)"))
|
||||
-- Transmited bytes, 7 fields from end of the line
|
||||
local send = tonumber(string.match(line,
|
||||
"([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$"))
|
||||
|
||||
helpers.uformat(args, name .. " rx", recv, unit)
|
||||
helpers.uformat(args, name .. " tx", send, unit)
|
||||
|
||||
-- Operational state and carrier detection
|
||||
local sysnet = helpers.pathtotable("/sys/class/net/" .. name)
|
||||
args["{"..name.." carrier}"] = tonumber(sysnet.carrier) or 0
|
||||
|
||||
if nets[name] == nil then
|
||||
-- Default values on the first run
|
||||
nets[name] = {}
|
||||
helpers.uformat(args, name .. " down", 0, unit)
|
||||
helpers.uformat(args, name .. " up", 0, unit)
|
||||
|
||||
nets[name].time = os.time()
|
||||
else -- Net stats are absolute, substract our last reading
|
||||
local interval = os.time() - nets[name].time > 0 and
|
||||
os.time() - nets[name].time or 1
|
||||
nets[name].time = os.time()
|
||||
|
||||
local down = (recv - nets[name][1]) / interval
|
||||
local up = (send - nets[name][2]) / interval
|
||||
|
||||
helpers.uformat(args, name .. " down", down, unit)
|
||||
helpers.uformat(args, name .. " up", up, unit)
|
||||
end
|
||||
|
||||
-- Store totals
|
||||
nets[name][1] = recv
|
||||
nets[name][2] = send
|
||||
end
|
||||
end
|
||||
|
||||
return args
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,61 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) org-awesome, Damien Leone
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { find = string.find }
|
||||
local os = {
|
||||
time = os.time,
|
||||
date = os.date
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Org: provides agenda statistics for Emacs org-mode
|
||||
module("vicious.widgets.org")
|
||||
|
||||
|
||||
-- {{{ OrgMode widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Compute delays
|
||||
local today = os.time{ year=os.date("%Y"), month=os.date("%m"), day=os.date("%d") }
|
||||
local soon = today + 24 * 3600 * 3 -- 3 days ahead is close
|
||||
local future = today + 24 * 3600 * 7 -- 7 days ahead is maximum
|
||||
|
||||
-- Initialize counters
|
||||
local count = { past = 0, today = 0, soon = 0, future = 0 }
|
||||
|
||||
-- Get data from agenda files
|
||||
for i=1, #warg do
|
||||
for line in io.lines(warg[i]) do
|
||||
local scheduled = string.find(line, "SCHEDULED:")
|
||||
local closed = string.find(line, "CLOSED:")
|
||||
local deadline = string.find(line, "DEADLINE:")
|
||||
|
||||
if (scheduled and not closed) or (deadline and not closed) then
|
||||
local b, e, y, m, d = string.find(line, "(%d%d%d%d)-(%d%d)-(%d%d)")
|
||||
|
||||
if b then
|
||||
local t = os.time{ year = y, month = m, day = d }
|
||||
|
||||
if t < today then count.past = count.past + 1
|
||||
elseif t == today then count.today = count.today + 1
|
||||
elseif t <= soon then count.soon = count.soon + 1
|
||||
elseif t <= future then count.future = count.future + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {count.past, count.today, count.soon, count.future}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,72 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local os = { getenv = os.getenv }
|
||||
local math = { ceil = math.ceil }
|
||||
local setmetatable = setmetatable
|
||||
local helpers = require("vicious.helpers")
|
||||
local string = {
|
||||
gsub = string.gsub,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- OS: provides operating system information
|
||||
module("vicious.widgets.os")
|
||||
|
||||
|
||||
-- {{{ Operating system widget type
|
||||
local function worker(format)
|
||||
local system = {
|
||||
["ostype"] = "N/A",
|
||||
["hostname"] = "N/A",
|
||||
["osrelease"] = "N/A",
|
||||
["username"] = "N/A",
|
||||
["entropy"] = "N/A",
|
||||
["entropy_p"] = "N/A"
|
||||
}
|
||||
|
||||
-- Linux manual page: uname(2)
|
||||
local kernel = helpers.pathtotable("/proc/sys/kernel")
|
||||
for k, v in pairs(system) do
|
||||
if kernel[k] then
|
||||
system[k] = string.gsub(kernel[k], "[%s]*$", "")
|
||||
end
|
||||
end
|
||||
|
||||
-- BSD manual page: uname(1)
|
||||
if system["ostype"] == "N/A" then
|
||||
local f = io.popen("uname -snr")
|
||||
local uname = f:read("*line")
|
||||
f:close()
|
||||
|
||||
system["ostype"], system["hostname"], system["osrelease"] =
|
||||
string.match(uname, "([%w]+)[%s]([%w%p]+)[%s]([%w%p]+)")
|
||||
end
|
||||
|
||||
-- Linux manual page: random(4)
|
||||
if kernel.random then
|
||||
-- Linux 2.6 default entropy pool is 4096-bits
|
||||
local poolsize = tonumber(kernel.random.poolsize)
|
||||
|
||||
-- Get available entropy and calculate percentage
|
||||
system["entropy"] = tonumber(kernel.random.entropy_avail)
|
||||
system["entropy_p"] = math.ceil(system["entropy"] * 100 / poolsize)
|
||||
end
|
||||
|
||||
-- Get user from the environment
|
||||
system["username"] = os.getenv("USER")
|
||||
|
||||
return {system["ostype"], system["osrelease"], system["username"],
|
||||
system["hostname"], system["entropy"], system["entropy_p"]}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,46 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { popen = io.popen }
|
||||
local math = { max = math.max }
|
||||
local setmetatable = setmetatable
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Pkg: provides number of pending updates on UNIX systems
|
||||
module("vicious.widgets.pkg")
|
||||
|
||||
|
||||
-- {{{ Packages widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Initialize counters
|
||||
local updates = 0
|
||||
local manager = {
|
||||
["Arch"] = { cmd = "pacman -Qu" },
|
||||
["Arch S"] = { cmd = "yes | pacman -Sup", sub = 2 },
|
||||
["Debian"] = { cmd = "apt-show-versions -u -b" },
|
||||
["Ubuntu"] = { cmd = "aptitude search '~U'" },
|
||||
["Fedora"] = { cmd = "yum list updates", sub = 3 },
|
||||
["FreeBSD"] ={ cmd = "pkg_version -I -l '<'" },
|
||||
["Mandriva"]={ cmd = "urpmq --auto-select" }
|
||||
}
|
||||
|
||||
-- Check if updates are available
|
||||
local pkg = manager[warg]
|
||||
local f = io.popen(pkg.cmd)
|
||||
|
||||
for line in f:lines() do
|
||||
updates = updates + 1
|
||||
end
|
||||
f:close()
|
||||
|
||||
return {pkg.sub and math.max(updates-pkg.sub, 0) or updates}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,57 @@
|
||||
-----------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Hagen Schink <troja84@googlemail.com>
|
||||
-----------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = {
|
||||
len = string.len,
|
||||
sub = string.sub,
|
||||
match = string.match,
|
||||
gmatch = string.gmatch
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Raid: provides state information for a requested RAID array
|
||||
module("vicious.widgets.raid")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local mddev = {}
|
||||
|
||||
-- {{{ RAID widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
mddev[warg] = {
|
||||
["found"] = false,
|
||||
["active"] = 0,
|
||||
["assigned"] = 0
|
||||
}
|
||||
|
||||
-- Linux manual page: md(4)
|
||||
for line in io.lines("/proc/mdstat") do
|
||||
if mddev[warg]["found"] then
|
||||
local updev = string.match(line, "%[[_U]+%]")
|
||||
|
||||
for i in string.gmatch(updev, "U") do
|
||||
mddev[warg]["active"] = mddev[warg]["active"] + 1
|
||||
end
|
||||
|
||||
break
|
||||
elseif string.sub(line, 1, string.len(warg)) == warg then
|
||||
mddev[warg]["found"] = true
|
||||
|
||||
for i in string.gmatch(line, "%[[%d]%]") do
|
||||
mddev[warg]["assigned"] = mddev[warg]["assigned"] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {mddev[warg]["assigned"], mddev[warg]["active"]}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,45 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Thermal: provides temperature levels of ACPI and coretemp thermal zones
|
||||
module("vicious.widgets.thermal")
|
||||
|
||||
|
||||
-- {{{ Thermal widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local zone = { -- Known temperature data sources
|
||||
["sys"] = {"/sys/class/thermal/", file = "temp", div = 1000},
|
||||
["core"] = {"/sys/devices/platform/", file = "temp1_input",div = 1000},
|
||||
["proc"] = {"/proc/acpi/thermal_zone/",file = "temperature"}
|
||||
} -- Default to /sys/class/thermal
|
||||
warg = type(warg) == "table" and warg or { warg, "sys" }
|
||||
|
||||
-- Get temperature from thermal zone
|
||||
local thermal = helpers.pathtotable(zone[warg[2]][1] .. warg[1])
|
||||
|
||||
if thermal[zone[warg[2]].file] then
|
||||
if zone[warg[2]].div then
|
||||
return {thermal[zone[warg[2]].file] / zone[warg[2]].div}
|
||||
else -- /proc/acpi "temperature: N C"
|
||||
return {tonumber(string.match(thermal[zone[warg[2]].file], "[%d]+"))}
|
||||
end
|
||||
end
|
||||
|
||||
return {0}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,35 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local setmetatable = setmetatable
|
||||
local math = { floor = math.floor }
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Uptime: provides system uptime and load information
|
||||
module("vicious.widgets.uptime")
|
||||
|
||||
|
||||
-- {{{ Uptime widget type
|
||||
local function worker(format)
|
||||
local proc = helpers.pathtotable("/proc")
|
||||
|
||||
-- Get system uptime
|
||||
local up_t = math.floor(string.match(proc.uptime, "[%d]+"))
|
||||
local up_d = math.floor(up_t / (3600 * 24))
|
||||
local up_h = math.floor((up_t % (3600 * 24)) / 3600)
|
||||
local up_m = math.floor(((up_t % (3600 * 24)) % 3600) / 60)
|
||||
|
||||
local l1, l5, l15 = -- Get load averages for past 1, 5 and 15 minutes
|
||||
string.match(proc.loadavg, "([%d%.]+)[%s]([%d%.]+)[%s]([%d%.]+)")
|
||||
return {up_d, up_h, up_m, l1, l5, l15}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,52 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Volume: provides volume levels and state of requested ALSA mixers
|
||||
module("vicious.widgets.volume")
|
||||
|
||||
|
||||
-- {{{ Volume widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local mixer_state = {
|
||||
["on"] = "♫", -- "",
|
||||
["off"] = "♩" -- "M"
|
||||
}
|
||||
|
||||
-- Get mixer control contents
|
||||
local f = io.popen("amixer get " .. warg)
|
||||
local mixer = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Capture mixer control state: [5%] ... ... [on]
|
||||
local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
||||
-- Handle mixers without data
|
||||
if volu == nil then
|
||||
return {0, mixer_state["off"]}
|
||||
end
|
||||
|
||||
-- Handle mixers without mute
|
||||
if mute == "" and volu == "0"
|
||||
-- Handle mixers that are muted
|
||||
or mute == "off" then
|
||||
mute = mixer_state["off"]
|
||||
else
|
||||
mute = mixer_state["on"]
|
||||
end
|
||||
|
||||
return {tonumber(volu), mute}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,85 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local math = { ceil = math.ceil }
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Weather: provides weather information for a requested station
|
||||
module("vicious.widgets.weather")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local weather = {
|
||||
["{city}"] = "N/A",
|
||||
["{wind}"] = "N/A",
|
||||
["{windmph}"] = "N/A",
|
||||
["{windkmh}"] = "N/A",
|
||||
["{sky}"] = "N/A",
|
||||
["{weather}"] = "N/A",
|
||||
["{tempf}"] = "N/A",
|
||||
["{tempc}"] = "N/A",
|
||||
["{humid}"] = "N/A",
|
||||
["{press}"] = "N/A"
|
||||
}
|
||||
|
||||
-- {{{ Weather widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Get weather forceast by the station ICAO code, from:
|
||||
-- * US National Oceanic and Atmospheric Administration
|
||||
local noaa = "http://weather.noaa.gov/pub/data/observations/metar/decoded/"
|
||||
local f = io.popen("curl --connect-timeout 1 -fsm 3 "..noaa..warg..".TXT")
|
||||
local ws = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Check if there was a timeout or a problem with the station
|
||||
if ws == nil then return weather end
|
||||
|
||||
weather["{city}"] = -- City and/or area
|
||||
string.match(ws, "^(.+)%,.*%([%u]+%)") or weather["{city}"]
|
||||
weather["{wind}"] = -- Wind direction and degrees if available
|
||||
string.match(ws, "Wind:[%s][%a]+[%s][%a]+[%s](.+)[%s]at.+$") or weather["{wind}"]
|
||||
weather["{windmph}"] = -- Wind speed in MPH if available
|
||||
string.match(ws, "Wind:[%s].+[%s]at[%s]([%d]+)[%s]MPH") or weather["{windmph}"]
|
||||
weather["{sky}"] = -- Sky conditions if available
|
||||
string.match(ws, "Sky[%s]conditions:[%s](.-)[%c]") or weather["{sky}"]
|
||||
weather["{weather}"] = -- Weather conditions if available
|
||||
string.match(ws, "Weather:[%s](.-)[%c]") or weather["{weather}"]
|
||||
weather["{tempf}"] = -- Temperature in fahrenheit
|
||||
string.match(ws, "Temperature:[%s]([%-]?[%d%.]+).*[%c]") or weather["{tempf}"]
|
||||
weather["{humid}"] = -- Relative humidity in percent
|
||||
string.match(ws, "Relative[%s]Humidity:[%s]([%d]+)%%") or weather["{humid}"]
|
||||
weather["{press}"] = -- Pressure in hPa
|
||||
string.match(ws, "Pressure[%s].+%((.+)[%s]hPa%)") or weather["{press}"]
|
||||
|
||||
-- Wind speed in km/h if MPH was available
|
||||
if weather["{windmph}"] ~= "N/A" then
|
||||
weather["{windmph}"] = tonumber(weather["{windmph}"])
|
||||
weather["{windkmh}"] = math.ceil(weather["{windmph}"] * 1.6)
|
||||
end -- Temperature in °C if °F was available
|
||||
if weather["{tempf}"] ~= "N/A" then
|
||||
weather["{tempf}"] = tonumber(weather["{tempf}"])
|
||||
weather["{tempc}"] = math.ceil((weather["{tempf}"] - 32) * 5/9)
|
||||
end -- Capitalize some stats so they don't look so out of place
|
||||
if weather["{sky}"] ~= "N/A" then
|
||||
weather["{sky}"] = helpers.capitalize(weather["{sky}"])
|
||||
end
|
||||
if weather["{weather}"] ~= "N/A" then
|
||||
weather["{weather}"] = helpers.capitalize(weather["{weather}"])
|
||||
end
|
||||
|
||||
return weather
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,80 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local math = { ceil = math.ceil }
|
||||
local setmetatable = setmetatable
|
||||
local helpers = require("vicious.helpers")
|
||||
local io = {
|
||||
open = io.open,
|
||||
popen = io.popen
|
||||
}
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Wifi: provides wireless information for a requested interface
|
||||
module("vicious.widgets.wifi")
|
||||
|
||||
|
||||
-- {{{ Wireless widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Default values
|
||||
local winfo = {
|
||||
["{ssid}"] = "N/A",
|
||||
["{mode}"] = "N/A",
|
||||
["{chan}"] = 0,
|
||||
["{rate}"] = 0,
|
||||
["{link}"] = 0,
|
||||
["{linp}"] = 0,
|
||||
["{sign}"] = 0
|
||||
}
|
||||
|
||||
-- Get data from iwconfig where available
|
||||
local iwconfig = "/sbin/iwconfig"
|
||||
local f = io.open(iwconfig, "rb")
|
||||
if not f then
|
||||
iwconfig = "/usr/sbin/iwconfig"
|
||||
else
|
||||
f:close()
|
||||
end
|
||||
local f = io.popen(iwconfig .." ".. warg .. " 2>&1")
|
||||
local iw = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- iwconfig wasn't found, isn't executable, or non-wireless interface
|
||||
if iw == nil or string.find(iw, "No such device") then
|
||||
return winfo
|
||||
end
|
||||
|
||||
-- Output differs from system to system, some stats can be
|
||||
-- separated by =, and not all drivers report all stats
|
||||
winfo["{ssid}"] = -- SSID can have almost anything in it
|
||||
helpers.escape(string.match(iw, 'ESSID[=:]"(.-)"') or winfo["{ssid}"])
|
||||
winfo["{mode}"] = -- Modes are simple, but also match the "-" in Ad-Hoc
|
||||
string.match(iw, "Mode[=:]([%w%-]*)") or winfo["{mode}"]
|
||||
winfo["{chan}"] = -- Channels are plain digits
|
||||
tonumber(string.match(iw, "Channel[=:]([%d]+)") or winfo["{chan}"])
|
||||
winfo["{rate}"] = -- Bitrate can start with a space, we don't want to display Mb/s
|
||||
tonumber(string.match(iw, "Bit Rate[=:]([%s]?[%d%.]*)") or winfo["{rate}"])
|
||||
winfo["{link}"] = -- Link quality can contain a slash (32/70), match only the first number
|
||||
tonumber(string.match(iw, "Link Quality[=:]([%d]+)") or winfo["{link}"])
|
||||
winfo["{sign}"] = -- Signal level can be a negative value, don't display decibel notation
|
||||
tonumber(string.match(iw, "Signal level[=:]([%-]?[%d]+)") or winfo["{sign}"])
|
||||
|
||||
-- Link quality percentage if quality was available
|
||||
if winfo["{link}"] ~= 0 then winfo["{linp}"] = math.ceil(winfo["{link}"] / 0.7) end
|
||||
|
||||
return winfo
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
Reference in New Issue
Block a user