inital commit of clone of old repo

This commit is contained in:
Contegix Support
2015-04-12 18:06:28 -05:00
parent 5529249e29
commit 77e1a1340d
3071 changed files with 157540 additions and 4 deletions

View File

@ -0,0 +1,81 @@
!terminal colors ------------------------------------------------------------
! tangoesque scheme
*background: #323232
*foreground: #FFFFFF
! Black
*color0: #2E3436
*color8: #555753
! Red
*color1: #CC0000
*color9: #EF2929
! Green
*color2: #4E9A06
*color10: #8AE234
! Yellow
*color3: #C4A000
*color11: #FCE94F
! Blue
*color4: #3465A4
*color12: #729FCF
! Mangenta
*color5: #75507B
*color13: #AD7FA8
! Cyan
*color6: #06989A
*color14: #34E2E2
! White
*color7: #D3D7CF
*color15: #EEEEEC
! rxvt-unicode ---------------------------------------------------------------
urxvt*font: xft:Ohsnap:pixelsize=14
urxvt*boldFont: xft:Ohsnap:pixelsize=14
urxvt*geometry: 160x50
urxvt*internalBorder: 0
urxvt*fading: 0
urxvt*inheritPixmap: true
!urxvt*depth: 24
urxvt*depth: 32
urxvt*saveLines: 32767
urxvt*visualBell: false
urxvt*scrollTtyKeypress: true
urxvt*scrollWithBuffer: false
urxvt*scrollTtyOutput: false
urxvt*scrollBar: false
!urxvt*scrollstyle: plain
!urxvt*scrollBar_right: true
urxvt*cursorColor: #00FF00
urxvt*loginShell: true
urxvt*termName: rxvt
urxvt*cutchars: "()*,<>[]{}|'
urxvt*print-pipe: cat > $(echo urxvt.dump.`date +'%Y%M%d%H%m%S'`)
urxvt*secondaryScroll: true
urxvt*mapAlert: true
urxvt*utmpInhibit: true
urxvt*perl-lib: /usr/lib/urxvt/perl/
urxvt*perl-ext-common: default,matcher
urxvt*urlLauncher: /usr/bin/opera
urxvt*matcher.button: 1
urxvt*background: #323232
urxvt*shading: 100
! xterm ----------------------------------------------------------------------
xterm*geometry: 80x25
xterm*faceName: terminus:pixelsize=10
xterm*dynamicColors: true
xterm*utf8: 2
xterm*eightBitInput: true
xterm*saveLines: 32767
xterm*scrollTtyKeypress: true
xterm*scrollTtyOutput: false
xterm*scrollBar: true
xterm*loginShell: true
xterm*jumpScroll: false
xterm*multiScroll: true
xterm*toolBar:

View File

@ -0,0 +1,45 @@
[Configuration]
FontName=Terminus 9
MiscAlwaysShowTabs=FALSE
MiscBell=FALSE
MiscBordersDefault=TRUE
MiscCursorBlinks=FALSE
MiscCursorShape=TERMINAL_CURSOR_SHAPE_BLOCK
MiscDefaultGeometry=80x24
MiscInheritGeometry=FALSE
MiscMenubarDefault=TRUE
MiscMouseAutohide=FALSE
MiscToolbarsDefault=FALSE
MiscConfirmClose=TRUE
MiscCycleTabs=TRUE
MiscTabCloseButtons=TRUE
MiscTabCloseMiddleClick=TRUE
MiscTabPosition=GTK_POS_TOP
MiscHighlightUrls=TRUE
BackgroundImageFile=/home/burchettm/Pictures/Wallpaper/newarchback.jpg
BackgroundImageStyle=TERMINAL_BACKGROUND_STYLE_STRETCHED
ScrollingBar=TERMINAL_SCROLLBAR_NONE
TitleInitial=
TitleMode=TERMINAL_TITLE_REPLACE
BackgroundDarkness=0.800000
BackgroundMode=TERMINAL_BACKGROUND_TRANSPARENT
AccelContents=
ColorForeground=White
ColorBackground=#323232323232
ColorPalette1=#2e2e34343636
ColorPalette2=#cccc00000000
ColorPalette3=#4e4e9a9a0606
ColorPalette4=#c4c4a0a00000
ColorPalette5=#34346565a4a4
ColorPalette6=#757550507b7b
ColorPalette7=#060698989a9a
ColorPalette8=#d3d3d7d7cfcf
ColorPalette9=#555557575353
ColorPalette10=#efef29292929
ColorPalette11=#8a8ae2e23434
ColorPalette12=#fcfce9e94f4f
ColorPalette13=#72729f9fcfcf
ColorPalette14=#adad7f7fa8a8
ColorPalette15=#3434e2e2e2e2
ColorPalette16=#eeeeeeeeecec

View File

@ -0,0 +1 @@
NOVA AwesomeWM configuration directory

View File

@ -0,0 +1,46 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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 when clients appear/disappear.
-- @param obj An object that should have a .screen property.
local function check_focus(obj)
-- When no visible client has the focus...
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
end
end
-- Give focus on tag selection change.
-- @param obj An object that should have a .screen property.
local function check_focus_screen(obj)
check_focus(obj)
if client.focus and client.focus.screen ~= obj.screen then
local c = nil
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_screen)
client.add_signal("unmanage", check_focus)
client.add_signal("new", function(c)
c:add_signal("tagged", check_focus)
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

View File

@ -0,0 +1,52 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,876 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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.
-- @param merge If true then merge tags when clients are not visible.
function urgent.jumpto(merge)
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
-- Try to make client visible, this also covers e.g. sticky
local t = c:tags()[1]
if t and not c:isvisible() then
if merge then
t.selected = true
else
tag.viewonly(t)
end
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 floating.get(c) then
floating.set(c, false)
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
--- Restore (=unminimize) a random client.
-- @param s The screen to use.
-- @return True if some client was restored.
function restore(s)
local s = s or (capi.client.focus and capi.client.focus.screen) or capi.mouse.screen
local cls = capi.client.get(s)
local tags = tag.selectedlist(s)
local mcls = {}
for k, c in pairs(cls) do
local ctags = c:tags()
if c.minimized then
for k, t in ipairs(tags) do
if util.table.hasitem(ctags, t) then
c.minimized = false
return true
end
end
end
end
return false
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

View File

@ -0,0 +1,191 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @author Sébastien Gross &lt;seb-awesome@chezwam.org&gt;
-- @copyright 2008 Julien Danjou, Sébastien Gross
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,19 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,160 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,30 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,78 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,156 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,74 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,13 @@
---------------------------------------------------------------------------
-- @author Gregor Best
-- @copyright 2008 Gregor Best
-- @release v3.4.10
---------------------------------------------------------------------------
--- Dummy function for floating layout
module("awful.layout.suit.floating")
function arrange()
end
name = "floating"

View File

@ -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")

View File

@ -0,0 +1,92 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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"

View File

@ -0,0 +1,41 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,58 @@
---------------------------------------------------------------------------
-- @author Uli Schlachter &lt;psychon@znc.in&gt;
-- @copyright 2009 Uli Schlachter
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,180 @@
---------------------------------------------------------------------------
-- @author Donald Ephraim Curtis &lt;dcurtis@cs.uiowa.edu&gt;
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Donald Ephraim Curtis
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,455 @@
---------------------------------------------------------------------------
-- @author Damien Leone &lt;damien.leone@gmail.com&gt;
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Damien Leone, Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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]), "&amp;(%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.<br/>
-- <ul>
-- <li> Key items: Table containing the displayed items. Each element is a table containing: item name, triggered action, submenu table or function, item icon (optional). </li>
-- <li> 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. </li>
-- <li> Key auto_expand controls the submenu auto expand behaviour by setting it to true (default) or false. </li>
-- </ul>
-- @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.
-- @usage The following function builds, and shows a menu of clients that match
-- a particular rule. Bound to a key, it can for example be used to select from
-- dozens of terminals open on several tags. With the use of
-- <code>match_any</code> instead of <code>match</code>, menu of clients with
-- different classes can also be build.
--
-- <p><code>
-- function terminal_menu () <br/>
-- &nbsp; terms = {} <br/>
-- &nbsp; for i, c in pairs(client.get()) do <br/>
-- &nbsp;&nbsp; if awful.rules.match(c, {class = "URxvt"}) then <br/>
-- &nbsp;&nbsp;&nbsp; terms[i] = <br/>
-- &nbsp;&nbsp;&nbsp; {c.name, <br/>
-- &nbsp;&nbsp;&nbsp; function() <br/>
-- &nbsp;&nbsp;&nbsp;&nbsp; awful.tag.viewonly(c:tags()[1]) <br/>
-- &nbsp;&nbsp;&nbsp;&nbsp; client.focus = c <br/>
-- &nbsp;&nbsp;&nbsp; end, <br/>
-- &nbsp;&nbsp;&nbsp; c.icon <br/>
-- &nbsp;&nbsp;&nbsp; } <br/>
-- &nbsp;&nbsp; end <br/>
-- &nbsp; end <br/>
-- &nbsp; m = awful.menu({items = terms}) <br/>
-- &nbsp; m:show({keygrabber=true}) <br/>
-- &nbsp; return m <br/>
-- end <br/>
--</code></p>
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

View File

@ -0,0 +1,150 @@
-------------------------------------------------------------------------
-- @author Sébastien Gross &lt;seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org&gt
-- @copyright 2009 Sébastien Gross
-- @release v3.4.10
-------------------------------------------------------------------------
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

View File

@ -0,0 +1,591 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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()
geom.width = geom.width + (2 * c.border_width)
geom.height = geom.height + (2 * c.border_width)
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
geom.x = geom.x - (2 * c.border_width)
geom.y = geom.y - (2 * c.border_width)
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
geom.width = geom.width - (2 * c.border_width)
geom.height = geom.height - (2 * c.border_width)
geom.x = geom.x + (2 * c.border_width)
geom.y = geom.y + (2 * c.border_width)
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

View File

@ -0,0 +1,238 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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
-- Check if the client's current position is available
-- and prefer that one (why move it around pointlessly?)
if geometry.x >= r.x
and geometry.y >= r.y
and geometry.x + geometry.width <= r.x + r.width
and geometry.y + geometry.height <= r.y + r.height then
new.x = geometry.x
new.y = geometry.y
end
end
end
-- We did not find 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

View File

@ -0,0 +1,381 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,48 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,203 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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>
--
-- <p> To match multiple clients with an exception one can couple 'except' or
-- 'except_any' with the rules:
-- <br/>
-- <code>
-- { rule = { class = "Firefox" },
-- except = { instance = "Navigator" },
-- properties = {floating = true},
-- },
-- </code>
-- <br/>
-- <code>
-- { rule_any = { class = { "Pidgin", "Xchat" } },
-- except_any = { role = { "conversation" } },
-- properties = { tag = tags[1][1] }
-- }
-- <br/>
-- <code>
-- { rule = {},
-- except_any = { class = { "Firefox", "Vim" } },
-- 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)
if not rule then return false end
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)
if not rule then return false end
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 (match(c, entry.rule) or match_any(c, entry.rule_any)) and
(not match(c, entry.except) and not match_any(c, entry.except_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

View File

@ -0,0 +1,53 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,54 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,527 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,421 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,233 @@
-------------------------------------------------------------------------
-- @author Sébastien Gross &lt;seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org&gt
-- @copyright 2009 Sébastien Gross
-- @release v3.4.10
-------------------------------------------------------------------------
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

View File

@ -0,0 +1,347 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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 = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
--- 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

View File

@ -0,0 +1,345 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,45 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008-2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,98 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008-2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,301 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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 graph 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

View File

@ -0,0 +1,21 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008-2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,35 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008-2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,58 @@
-------------------------------------------------
-- @author Gregor Best <farhaven@googlemail.com>
-- @copyright 2009 Gregor Best
-- @release v3.4.10
-------------------------------------------------
-- 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 })

View File

@ -0,0 +1,188 @@
-------------------------------------------------
-- @author Gregor Best <farhaven@googlemail.com>
-- @copyright 2009 Gregor Best
-- @release v3.4.10
-------------------------------------------------
-- 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

View File

@ -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

View File

@ -0,0 +1,101 @@
-------------------------------------------------
-- @author Gregor Best <farhaven@googlemail.com>
-- @copyright 2009 Gregor Best
-- @release v3.4.10
-------------------------------------------------
-- 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

View File

@ -0,0 +1,53 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,243 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,51 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,196 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008-2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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

View File

@ -0,0 +1,213 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2008-2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
-- 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::minimized", 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

View File

@ -0,0 +1,35 @@
---------------------------------------------------------------------------
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @copyright 2009 Julien Danjou
-- @release v3.4.10
---------------------------------------------------------------------------
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

View File

@ -0,0 +1,76 @@
----------------------------------------------------------------------------
-- @author Damien Leone &lt;damien.leone@gmail.com&gt;
-- @author Julien Danjou &lt;julien@danjou.info&gt;
-- @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

View 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

View File

@ -0,0 +1,594 @@
----------------------------------------------------------------------------
-- @author koniu &lt;gkusnierz@gmail.com&gt;
-- @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, "[<>&]", { ['<'] = "&lt;", ['>'] = "&gt;", ['&'] = "&amp;" }) then
textbox.text = "<i>&lt;Invalid markup, cannot display message&gt;</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

View File

@ -0,0 +1,129 @@
-------------------------------------------------------------------
-- Drop-down applications manager for the awesome window manager
-------------------------------------------------------------------
-- Coded by: * Lucas de Vries <lucas@glacicle.com>
-- Hacked by: * Adrian C. (anrxc) <anrxc@sysphere.org>
-- Licensed under the WTFPL version 2
-- * http://sam.zoy.org/wtfpl/COPYING
-------------------------------------------------------------------
-- To use this module add:
-- require("scratch")
-- to the top of your rc.lua, and call it from a keybinding:
-- scratch.drop(prog, vert, horiz, width, height, sticky, screen)
--
-- Parameters:
-- prog - Program to run; "urxvt", "gmrun", "thunderbird"
-- vert - Vertical; "bottom", "center" or "top" (default)
-- horiz - Horizontal; "left", "right" or "center" (default)
-- width - Width in absolute pixels, or width percentage
-- when <= 1 (1 (100% of the screen) by default)
-- height - Height in absolute pixels, or height percentage
-- when <= 1 (0.25 (25% of the screen) by default)
-- sticky - Visible on all tags, false by default
-- screen - Screen (optional), mouse.screen by default
-------------------------------------------------------------------
-- Grab environment
local pairs = pairs
local awful = require("awful")
local setmetatable = setmetatable
local capi = {
mouse = mouse,
client = client,
screen = screen
}
-- Scratchdrop: drop-down applications manager for the awesome window manager
module("scratch.drop")
local dropdown = {}
-- Create a new window for the drop-down application when it doesn't
-- exist, or toggle between hidden and visible states when it does
function toggle(prog, vert, horiz, width, height, sticky, screen)
vert = vert or "top"
horiz = horiz or "center"
width = width or 1
height = height or 0.25
sticky = sticky or false
screen = screen or capi.mouse.screen
if not dropdown[prog] then
dropdown[prog] = {}
-- Add unmanage signal for scratchdrop programs
capi.client.add_signal("unmanage", function (c)
for scr, cl in pairs(dropdown[prog]) do
if cl == c then
dropdown[prog][scr] = nil
end
end
end)
end
if not dropdown[prog][screen] then
spawnw = function (c)
dropdown[prog][screen] = c
-- Scratchdrop clients are floaters
awful.client.floating.set(c, true)
-- Client geometry and placement
local screengeom = capi.screen[screen].workarea
if width <= 1 then width = screengeom.width * width end
if height <= 1 then height = screengeom.height * height end
if horiz == "left" then x = screengeom.x
elseif horiz == "right" then x = screengeom.width - width
else x = screengeom.x+(screengeom.width-width)/2 end
if vert == "bottom" then y = screengeom.height + screengeom.y - height
elseif vert == "center" then y = screengeom.y+(screengeom.height-height)/2
else y = screengeom.y - screengeom.y end
-- Client properties
c:geometry({ x = x, y = y, width = width, height = height })
c.ontop = true
c.above = true
c.skip_taskbar = true
if sticky then c.sticky = true end
if c.titlebar then awful.titlebar.remove(c) end
c:raise()
capi.client.focus = c
capi.client.remove_signal("manage", spawnw)
end
-- Add manage signal and spawn the program
capi.client.add_signal("manage", spawnw)
awful.util.spawn(prog, false)
else
-- Get a running client
c = dropdown[prog][screen]
-- Switch the client to the current workspace
if c:isvisible() == false then c.hidden = true
awful.client.movetotag(awful.tag.selected(screen), c)
end
-- Focus and raise if hidden
if c.hidden then
-- Make sure it is centered
if vert == "center" then awful.placement.center_vertical(c) end
if horiz == "center" then awful.placement.center_horizontal(c) end
c.hidden = false
c:raise()
capi.client.focus = c
else -- Hide and detach tags if not
c.hidden = true
local ctags = c:tags()
for i, t in pairs(ctags) do
ctags[i] = nil
end
c:tags(ctags)
end
end
end
setmetatable(_M, { __call = function(_, ...) return toggle(...) end })

View File

@ -0,0 +1,12 @@
---------------------------------------------------------------
-- Drop-down applications and scratchpad manager for awesome wm
---------------------------------------------------------------
-- Coded by: * Adrian C. (anrxc) <anrxc@sysphere.org>
-- Licensed under the WTFPL version 2
-- * http://sam.zoy.org/wtfpl/COPYING
---------------------------------------------------------------
require("scratch.pad")
require("scratch.drop")
module("scratch")

View File

@ -0,0 +1,130 @@
---------------------------------------------------------------
-- Basic scratchpad manager for the awesome window manager
---------------------------------------------------------------
-- Coded by: * Adrian C. (anrxc) <anrxc@sysphere.org>
-- Licensed under the WTFPL version 2
-- * http://sam.zoy.org/wtfpl/COPYING
---------------------------------------------------------------
-- To use this module add:
-- require("scratch")
-- to the top of your rc.lua, and call:
-- scratch.pad.set(c, width, height, sticky, screen)
-- from a clientkeys binding, and:
-- scratch.pad.toggle(screen)
-- from a globalkeys binding.
--
-- Parameters:
-- c - Client to scratch or un-scratch
-- width - Width in absolute pixels, or width percentage
-- when <= 1 (0.50 (50% of the screen) by default)
-- height - Height in absolute pixels, or height percentage
-- when <= 1 (0.50 (50% of the screen) by default)
-- sticky - Visible on all tags, false by default
-- screen - Screen (optional), mouse.screen by default
---------------------------------------------------------------
-- Grab environment
local pairs = pairs
local awful = require("awful")
local capi = {
mouse = mouse,
client = client,
screen = screen
}
-- Scratchpad: basic scratchpad manager for the awesome window manager
module("scratch.pad")
local scratchpad = {}
-- Toggle a set of properties on a client.
local function toggleprop(c, prop)
c.ontop = prop.ontop or false
c.above = prop.above or false
c.hidden = prop.hidden or false
c.sticky = prop.stick or false
c.skip_taskbar = prop.task or false
end
-- Scratch the focused client, or un-scratch and tile it. If another
-- client is already scratched, replace it with the focused client.
function set(c, width, height, sticky, screen)
width = width or 0.50
height = height or 0.50
sticky = sticky or false
screen = screen or capi.mouse.screen
local function setscratch(c)
-- Scratchpad is floating and has no titlebar
awful.client.floating.set(c, true); awful.titlebar.remove(c)
-- Scratchpad client properties
toggleprop(c, {ontop=true, above=true, task=true, stick=sticky})
-- Scratchpad geometry and placement
local screengeom = capi.screen[screen].workarea
if width <= 1 then width = screengeom.width * width end
if height <= 1 then height = screengeom.height * height end
c:geometry({ -- Scratchpad is always centered on screen
x = screengeom.x + (screengeom.width - width) / 2,
y = screengeom.y + (screengeom.height - height) / 2,
width = width, height = height
})
-- Scratchpad should not loose focus
c:raise(); capi.client.focus = c
end
-- Prepare a table for storing clients,
if not scratchpad.pad then scratchpad.pad = {}
-- add unmanage signal for scratchpad clients
capi.client.add_signal("unmanage", function (c)
for scr, cl in pairs(scratchpad.pad) do
if cl == c then scratchpad.pad[scr] = nil end
end
end)
end
-- If the scratcphad is emtpy, store the client,
if not scratchpad.pad[screen] then
scratchpad.pad[screen] = c
-- then apply geometry and properties
setscratch(c)
else -- If a client is already scratched,
local oc = scratchpad.pad[screen]
-- unscratch, and compare it with the focused client
awful.client.floating.toggle(oc); toggleprop(oc, {})
-- If it matches clear the table, if not replace it
if oc == c then scratchpad.pad[screen] = nil
else scratchpad.pad[screen] = c; setscratch(c) end
end
end
-- Move the scratchpad to the current workspace, focus and raise it
-- when it's hidden, or hide it when it's visible.
function toggle(screen)
screen = screen or capi.mouse.screen
-- Check if we have a client on storage,
if scratchpad.pad and
scratchpad.pad[screen] ~= nil
then -- and get it out, to play
local c = scratchpad.pad[screen]
-- If it's visible on another tag hide it,
if c:isvisible() == false then c.hidden = true
-- and move it to the current worskpace
awful.client.movetotag(awful.tag.selected(screen), c)
end
-- Focus and raise if it's hidden,
if c.hidden then
awful.placement.centered(c)
c.hidden = false
c:raise(); capi.client.focus = c
else -- hide it if it's not
c.hidden = true
end
end
end

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View 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 = {
["\""] = "&quot;",
["&"] = "&amp;",
["'"] = "&apos;",
["<"] = "&lt;",
[">"] = "&gt;"
}
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
-- }}}
-- }}}

View 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
-- }}}
-- }}}

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -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 })

View File

@ -0,0 +1,154 @@
menu98edb85b00d9527ad5acebe451b3fae6 = { {"7-Zip FM", "7zFM"},
{"Android Notifier Desktop", "/usr/share/android-notifier-desktop/run.sh"},
{"Archive Manager", "file-roller "},
{"AutoKey (GTK)", "autokey-gtk"},
{"Avant Window Navigator", "avant-window-navigator"},
{"ClamTk", "clamtk "},
{"Disk Utility", "palimpsest"},
{"File Manager", "pcmanfm "},
{"HP Device Manager", "hp-toolbox"},
{"Image Viewer", "gpicview "},
{"KeePassX", "keepassx "},
{"LXTerminal", "lxterminal"},
{"Leafpad", "leafpad "},
{"NFO Viewer", "nfoview "},
{"Root Terminal", "gksu -l gnome-terminal"},
{"Terminator", "terminator"},
{"Vi IMproved", "gvim -f "},
}
menu78059f1898ed518c6ccd6a6392fa82c1 = { {"AUR", "xdg-open https://aur.archlinux.org"},
{"Bugs", "xdg-open https://bugs.archlinux.org"},
{"Developers", "xdg-open http://www.archlinux.org/developers/"},
{"Documentation", "xdg-open https://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide"},
{"Donate", "xdg-open http://www.archlinux.org/donate/"},
{"Forum", "xdg-open https://bbs.archlinux.org"},
{"Homepage", "xdg-open http://www.archlinux.org"},
{"SVN", "xdg-open http://projects.archlinux.org/svntogit/"},
{"Schwag", "xdg-open http://www.zazzle.com/archlinux/"},
{"Wiki", "xdg-open https://wiki.archlinux.org"},
}
menu251bd8143891238ecedc306508e29017 = { {"Imprudence Second Life viewer", "/usr/bin/imprudence-secondlife"},
{"Lincity-NG", "lincity-ng"},
{"Minecraft", "minecraft"},
{"PlayOnLinux", "playonlinux"},
{"Savage 2", "/usr/bin/savage2"},
{"Savage 2 Map Editor", "/usr/bin/savage2 \"PushMod editor; Set host_autoExec StartClient\""},
{"Savage 2 Model Viewer", "/usr/bin/savage2 \"PushMod modelviewer; Set host_autoExec StartClient\""},
{"Supertuxkart", "/usr/bin/supertuxkart --log=file"},
{"The Lord of the Rings Online", "pylotro"},
{"World of Padman", "worldofpadman"},
{"fretsonfire", "fretsonfire"},
}
menud334dfcea59127bedfcdbe0a3ee7f494 = { {"E-book Viewer", "ebook-viewer "},
{"GNU Image Manipulation Program", "gimp-2.7 "},
{"Image Viewer", "gpicview "},
{"LRF Viewer", "lrfviewer "},
{"XSane - Scanning", "xsane"},
}
menuc8205c7636e728d448c2774e6a4a944b = { {"Avahi SSH Server Browser", "/usr/bin/bssh"},
{"Avahi VNC Server Browser", "/usr/bin/bvnc"},
{"Chromium", "chromium "},
{"Dropbox", "/opt/dropbox/dropboxd"},
{"FileZilla", "filezilla"},
{"Firefox", "firefox "},
{"Links", "xlinks -g"},
{"Mangler", "mangler"},
{"Midori", "midori "},
{"Opera", "/usr/bin/opera "},
{"Pidgin Internet Messenger", "pidgin"},
{"QuickSynergy", "quicksynergy"},
{"SeaMonkey internet suite", "seamonkey "},
{"Skype", "skype"},
{"TeamSpeak 3", "/usr/bin/teamspeak3"},
{"TeamViewer", "/opt/teamviewer/teamviewer/6/bin/teamviewer"},
{"Thunderbird", "thunderbird "},
{"Turpial", "turpial"},
{"Wicd", "/usr/bin/wicd-client"},
{"X11VNC Server", "x11vnc -gui tray=setpass -rfbport PROMPT -bg -o %HOME/.x11vnc.log.%VNCDISPLAY"},
}
menudf814135652a5a308fea15bff37ea284 = { {"Calibre", "calibre"},
{"LibreOffice ", "libreoffice "},
{"ePDFViewer", "epdfview "},
}
menu6311ae17c1ee52b36e68aaf4ad066387 = { {"ROX Filer", "rox"},
{"dosbox Emulator", "dosbox"},
}
menue6f43c40ab1c07cd29e4e83e4ef6bf85 = { {"Android SDK", "android"},
{"BlueJ", "/usr/bin/bluej"},
{"Bluefish Editor", "bluefish "},
{"Eclipse", "eclipse"},
{"Google Gadget Designer", "/usr/bin/ggl-gtk -sa -nd -gp /usr/share/google-gadgets/designer.gg"},
{"Java Monitoring and Management Console", "jconsole"},
{"Java VisualVM", "jvisualvm"},
{"MonoDevelop", "monodevelop "},
{"NetBeans IDE", "/usr/share/netbeans/bin/netbeans"},
{"Qt Assistant", "/usr/bin/assistant"},
{"Qt Designer", "/usr/bin/designer"},
{"Qt Linguist", "/usr/bin/linguist"},
}
menu52dd1c847264a75f400961bfb4d1c849 = { {"AcetoneISO", "acetoneiso "},
{"Audacious", "audacious "},
{"Audacity", "audacity"},
{"EasyTAG", "easytag "},
{"Ex Falso", "exfalso"},
{"GNOME MPlayer", "gnome-mplayer "},
{"Gnome Music Player Client", "gmpc"},
{"HandBrake", "ghb"},
{"Last.fm", "lastfm"},
{"Nero Linux", "nero "},
{"Nero Linux Express", "neroexpress "},
{"Pithos", "pithos"},
{"QT V4L2 test Utility", "qv4l2"},
{"Quod Libet", "quodlibet"},
{"Sonata", "sonata"},
{"Sound Converter", "soundconverter "},
{"VLC media player", "vlc "},
{"VolWheel", "volwheel"},
{"Webcam Application", "wxcam"},
{"XBMC Media Center", "xbmc"},
{"dvd::rip", "/usr/bin/vendor_perl/dvdrip"},
{"gtk-recordMyDesktop", "gtk-recordMyDesktop"},
}
menuee69799670a33f75d45c57d1d1cd0ab3 = { {"Avahi Zeroconf Browser", "/usr/bin/avahi-discover"},
{"Bulk Rename", "/usr/lib/Thunar/ThunarBulkRename "},
{"Cairo Composite Manager", "cairo-compmgr"},
{"Cairo-Dock (no OpenGL)", "cairo-dock -c"},
{"Compiz Fusion Icon", "fusion-icon"},
{"GLX-Dock (Cairo-Dock with OpenGL)", "cairo-dock -o"},
{"GParted", "gksu /usr/sbin/gparted "},
{"Htop", "xterm -e htop"},
{"Manage Printing", "/usr/bin/xdg-open http://localhost:631/"},
{"Oracle VM VirtualBox", "VirtualBox "},
{"PkgBrowser", "pkgbrowser"},
{"Sakura", "sakura"},
{"Terminal", "Terminal"},
{"Thunar File Manager", "Thunar "},
{"UNetbootin", "/usr/bin/unetbootin"},
{"VMware Player", "/usr/bin/vmplayer"},
{"VMware Workstation", "/usr/bin/vmware"},
{"Virtual Network Editor", "/usr/bin/vmware-netcfg"},
{"Wireshark", "wireshark"},
{"rxvt-unicode", "urxvt"},
}
xdgmenu = { {"Accessories", menu98edb85b00d9527ad5acebe451b3fae6},
{"Archlinux", menu78059f1898ed518c6ccd6a6392fa82c1},
{"Games", menu251bd8143891238ecedc306508e29017},
{"Graphics", menud334dfcea59127bedfcdbe0a3ee7f494},
{"Internet", menuc8205c7636e728d448c2774e6a4a944b},
{"Office", menudf814135652a5a308fea15bff37ea284},
{"Other", menu6311ae17c1ee52b36e68aaf4ad066387},
{"Programming", menue6f43c40ab1c07cd29e4e83e4ef6bf85},
{"Sound & Video", menu52dd1c847264a75f400961bfb4d1c849},
{"System Tools", menuee69799670a33f75d45c57d1d1cd0ab3},
}

View File

@ -0,0 +1,693 @@
-- -- NOVA Awesome Setup -- --
-- -- Created by Matt Burchett -- --
-- -- Fri, 2010/06/10 -- --
-- -- LIBRARY REQUIREMENTS -- --
-- -- THERE MAY BE LIBRARIES COMMENTED OUT THAT ARE CURRENTLY OUT OF USE -- --
require("awful") -- Standard Awesome Library
require("awful.autofocus") -- Standard Awesome Library
require("awful.rules") -- Standard Awesome Library
require("beautiful") -- Theme Handling Library
require("naughty") -- Notification Library
require("vicious") -- Dynamic Widget Library
require("lib/cal") -- Calendar Library / Widget
require("scratch") -- ScratchPad Library / Widget
-- -- APP AUTOSTART -- --
awful.util.spawn_with_shell("dropboxd")
awful.util.spawn_with_shell("mpd")
awful.util.spawn_with_shell("/home/burchettm/.config/awesome/scripts/x11vnc")
--awful.util.spawn_with_shell("/home/burchettm/.config/awesome/scripts/synergys")
awful.util.spawn_with_shell("/usr/bin/numlockx")
awful.util.spawn_with_shell("xscreensaver -nosplash")
awful.util.spawn_with_shell("wmname LG3D")
-- DISABLE BUSY CURSOR WITH AWFUL.UTIL.SPAWN --
-- disable startup-notification globally
local oldspawn = awful.util.spawn
awful.util.spawn = function (s)
oldspawn(s, false)
end
-- -- VARIABLE DEFINITIONS -- --
-- -- SPECIFY THEME LOCATION (CONSISTS OF COLOURS, ICONS, AND WALLPAPERS) -- --
beautiful.init("/home/burchettm/.config/awesome/themes/awesomeo/theme.lua")
-- CHANGE NAUGHTY FONT TO DIFFER FROM BANKGOTHIC LT BT --
naughty.config.default_preset.font = "Sans 8"
-- -- SPECIFY DEFAULT APPLICATIONS -- --
terminal = "/usr/bin/terminal --hide-menubar" -- Specify Default Terminal
--terminal = "urxvt" -- Specify Default Terminal
editor = os.getenv("EDITOR") or "vim"
editor_cmd = terminal .. " -e " .. editor
modkey = "Mod4" -- Set ModKey to Windows Key, use xmodmap to change
-- -- LAYOUTS -- --
layouts =
{
awful.layout.suit.floating,
awful.layout.suit.tile,
awful.layout.suit.tile.left,
awful.layout.suit.tile.bottom,
awful.layout.suit.tile.top,
awful.layout.suit.fair,
awful.layout.suit.fair.horizontal,
awful.layout.suit.spiral,
awful.layout.suit.spiral.dwindle,
awful.layout.suit.max,
awful.layout.suit.max.fullscreen,
awful.layout.suit.magnifier
}
-- -- TAGS -- --
-- Define a tag table which hold all screen tags.
tags = {}
for s = 1, screen.count() do
-- Each screen has its own tag table.
tags[s] = awful.tag({ "WORK", "TERM", "WWW", "CHAT", "MEDIA", "SOCIAL" }, s,
{ layouts[1], layouts[2], layouts[2], -- Tags: 1, 2, 3
layouts[1], layouts[2], layouts[2], -- 4, 5 ,6
layouts[1], layouts[1], layouts[1] -- 7, 8, 9
})
end
-- -- MENU -- --
myawesomemenu = {
{ "Manual", terminal .. " -e man awesome" },
{ "Edit Config", editor_cmd .. " " .. awful.util.getdir("config") .. "/rc.lua" },
{ "Restart", awesome.restart },
{ "Quit", awesome.quit }
}
myaccessoriesmenu = {
{ "Android Notifier Desktop", "/usr/share/android-notifier-desktop/run.sh" },
{ "Archive Manager", "file-roller" },
{ "AutoKey (GTK)", "autokey-gtk"},
{ "Avant Window Navigator", "avant-window-navigator" },
{ "ClamTK", "clamtk" },
{ "Disk Utility", "palimpsest" },
{ "DOSBOX Emulator", "dosbox" },
{ "gVim", "gvim" },
{ "LXDE Image Viewer", "gpicview" },
{ "KeePassX", "keepassx" },
{ "LXTerminal", "lxtermnal" },
{ "PCManFM File Manager", "pcmanfm" },
{ "Root Terminal", "gksu -l gnome-terminal" },
{ "Terminator", "terminator" },
}
myarchmenu = {
{ "AUR", "xdg-open http://aur.archlinux.org" },
{ "Bugs", "xdg-open http://bugs.archlinux.org" },
{ "Developers", "xdg-open http://www.archlinux.org/developers/" },
{ "Documentation", "xdg-open http://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide" },
{ "Donate", "xdg-open http://www.archlinux.org/donate/" },
{ "Forum", "xdg-open http://bbs.archlinux.org" },
{ "Homepage", "xdg-open http://repos.archlinux.org" },
{ "SVN", "xdg-open http://repos.archlinux.org" },
{ "Schwag", "xdg-open http://www.zazzle.com/archlinux/" },
{ "Wiki", "xdg-open http://wiki.archlinux.org" }
}
mygamesmenu = {
{ "Alien Arena", "alienarena" },
{ "America's Army 3", "env WINEPREFIX='/home/burchettm/.wineprefix/Steam' wine winebrowser steam://rungameid/13140" },
{ "Ceiling Fan Man", "env WINEPREFIX='/home/burchettm/.wineprefix/SFGames' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/SFGames/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Skyfall/Ceiling\\ Fan\\ Man/Play\\ Ceiling\\ Fan\\ Man.lnk" },
{ "Ceiling Fan Man II", "env WINEPREFIX='/home/burchettm/.wineprefix/SFGames' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/SFGames/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Skyfall/Ceiling\\ Fan\\ Man\\ II\\ Demo/Play\\ Ceiling\\ Fan\\ Man\\ II.lnk" },
{ "CS:S Beta", "env WINEPREFIX='/home/burchettm/.wineprefix/Steam' wine winebrowser steam://rungameid/260" },
{ "Curse Client", "env WINEPREFIX='/home/burchettm/.wineprefix/Curse' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Curse/dosdevices/c:/users/Public/Start\\ Menu/Programs/Curse/Curse\\ Client.lnk" },
{ "Fallout 3", "env WINEPREFIX='/home/burchettm/.wineprefix/Fallout3' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Fallout3/dosdevices/c:/users/Public/Start\\ Menu/Programs/Bethesda\\ Softworks/Fallout\\ 3/Fallout\\ 3.lnk" },
{ "Frets on Fire", "fretsonfire" },
{ "Garry's Mod", "env WINEPREFIX='/home/burchettm/.wineprefix/Steam' wine winebrowser steam://rungameid/4000" },
{ "GCFScape", "env WINEPREFIX='/home/burchettm/.wine' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wine/dosdevices/c:/users/Public/Start\\ Menu/Programs/GCFScape/GCFScape.lnk" },
{ "GTA San Andreas", "env WINEPREFIX='/home/burchettm/.wineprefix/GTASA' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/GTASA/dosdevices/c:/users/Public/Start\\ Menu/Programs/Rockstar\\ Games/GTA\\ San\\ Andreas/Play\\ GTA\\ San\\ Andreas.lnk" },
{ "GTA Vice City", "env WINEPREFIX='/home/burchettm/.wineprefix/GTAVC' wine '/home/burchettm/.wineprefix/GTAVC/drive_c/Program Files/Rockstar Games/Grand Theft Auto Vice City/gta-vc.exe'" },
{ "Imprudence", "/usr/bin/imprudence-secondlife" },
{ "Infiltration", "env WINEPREFIX='/home/burchettm/.wineprefix/UT' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/UT/dosdevices/c:/users/Public/Start\\ Menu/Programs/SentryStudios/Infiltration/Play\\ Infiltration.lnk" },
{ "LinCity-NG", "lincity-ng" },
{ "MaNGOLin", "/home/burchettm/Apps/MaNGOLin/MaNGOLin" },
{ "MCEdit", "python26 -O '/home/burchettm/Apps/MCEdit-linux/MCEditData/mcedit.pyo'" },
{ "Minecraft", "minecraft" },
{ "Monopoly: HN", "env WINEPREFIX='/home/burchettm/.wineprefix/MonoHN' wine '/home/burchettm/.wineprefix/MonoHN/drive_c/Program Files/Hasbro/Monopoly Here & Now Edition/Monopoly.exe'" },
{ "Oblivion", "env WINEPREFIX='/home/burchettm/.wineprefix/Oblivion' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Oblivion/dosdevices/c:/users/Public/Start\\ Menu/Programs/Bethesda\\ Softworks/Oblivion/Oblivion.lnk" },
{ "PlayOnLinux", "playonlinux" },
{ "PyLoTRO", "pylotro" },
{ "Savage 2", "/usr/bin/savage2" },
{ "Savage 2 Map Editor", "/usr/bin/savage2 \"PushMod editor; Set host_autoExec StartClient\"" },
{ "Savage 2 Model Viewer", "/usr/bin/savage2 \"PushMod modelviewer; Set host_autoExec StartClient\"" },
{ "Second Life", "/usr/bin/secondlife" },
{ "SimCity 4 Deluxe", "env WINEPREFIX='/home/burchettm/.wineprefix/SimCity4' wine '/home/burchettm/.wineprefix/SimCity4/drive_c/Program Files/Maxis/SimCity 4 Deluxe/Apps/SimCity 4.exe' -intro:off -customresolution:enabled -r1920x1080x32" },
{ "Sims 3", "/home/burchettm/bin/sims3" },
{ "SLiteChat", "env WINEPREFIX='/home/burchettm/.wine' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wine/dosdevices/c:/users/Public/Start\\ Menu/Programs/SLiteChat\\ for\\ Windows/SLiteChat\\ -\\ Text-based\\ IM\\ client\\ for\\ Second\\ Life.lnk" },
{ "Soldier of Fortune", "env WINEPREFIX='/home/burchettm/.wineprefix/SOF' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/SOF/dosdevices/c:/users/Public/Start\\ Menu/Programs/Raven\\ Software/Soldier\\ of\\ Fortune\\ Platinum/Soldier\\ of\\ Fortune\\ Platinum.lnk" },
{ "Snowglobe 1.3", "snowglobe" },
{ "Steam", "env WINEPREFIX='/home/burchettm/.wineprefix/Steam' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Steam/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Steam/Steam.lnk" },
{ "Strike Force 181", "env WINEPREFIX='/home/burchettm/.wineprefix/UT' wine C:\\\\unrealtournament\\\\System\\\\Strike\\ Force.exe" },
{ "SuperTuxKart", "/usr/bin/supertuxkart --log=file" },
{ "Team Fortress 2", "env WINEPREFIX='/home/burchettm/.wineprefix/Steam' wine winebrowser steam://rungameid/440" },
{ "UT2004", "env WINEPREFIX='/home/burchettm/.wineprefix/UT' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/UT/dosdevices/c:/users/Public/Start\\ Menu/Programs/Unreal\\ Tournament\\ 2004/Play\\ UT2004.lnk" },
{ "UTGOTY", "env WINEPREFIX='/home/burchettm/.wineprefix/UT' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/UT/dosdevices/c:/users/Public/Start\\ Menu/Programs/Unreal\\ Tournament\\ G.O.T.Y.\\ Edition/Play\\ Unreal\\ Tournament.lnk" },
{ "World of Padman", "worldofpadman" },
{ "WoW-Cataclysm", "env WINEPREFIX='/home/burchettm/.wineprefix/WoW-Cataclysm' wine '/media/Terabyte/WoW-Cataclysm/Wow.exe'" },
{ "WoW-PTR", "env WINEPREFIX='/home/burchettm/.wine' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wine/dosdevices/c:/users/Public/Start\\ Menu/Programs/World\\ of\\ Warcraft\\ Public\\ Test/World\\ of\\ Warcraft.lnk" },
{ "WoW-WotLK", "wine '/media/Terabyte/WoW-WoTLK/Wow.exe'" }
}
mygraphicsmenu = {
{ "Adobe ImageReady 7.0", "env WINEPREFIX='/home/burchettm/.wineprefix/Adobe' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Adobe/dosdevices/c:/users/Public/Start\\ Menu/Programs/Adobe\\ ImageReady\\ 7.0.lnk" },
{ "Adobe PhotoShop 7.0", "env WINEPREFIX='/home/burchettm/.wineprefix/Adobe' wine '/home/burchettm/.wineprefix/Adobe/drive_c/Program Files/Adobe/Photoshop 7.0/Photoshop.exe'" },
{ "Dreamweaver 8", "env WINEPREFIX='/home/burchettm/.wineprefix/Adobe' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Adobe/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Macromedia/Macromedia\\ Dreamweaver\\ 8.lnk" },
{ "IconsExtract", "env WINEPREFIX='/home/burchettm/.wine' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wine/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/NirSoft\\ IconsExtract/IconsExtract.lnk" },
{ "GIMP", "gimp-2.6" },
{ "LXDE Image Viewer", "gpicview" },
{ "MCEdit", "python26 -O '/home/burchettm/Apps/MCEdit-linux/MCEditData/mcedit.pyo'" },
{ "MS Paint", "env WINEPREFIX='/home/burchettm/.wine' wine '/home/burchettm/.wine/drive_c/windows/mspaint.exe'" },
{ "XSane - Scanning", "xsane" },
}
myinternetmenu = {
{ "Avahi SSH", "/usr/bin/bssh" },
{ "Avahi VNC", "/usr/bin/bvnc" },
{ "Chromium", "chromium" },
{ "Curse Client", "env WINEPREFIX='/home/burchettm/.wineprefix/Curse' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Curse/dosdevices/c:/users/Public/Start\\ Menu/Programs/Curse/Curse\\ Client.lnk" },
{ "Dropbox", "/opt/dropbox/dropboxd" },
{ "FileZilla", "filezilla" },
{ "Firefox", "firefox" },
{ "Links", "xlinks -g" },
{ "Mangler", "mangler" },
{ "Midori", "midori" },
{ "MS RDP", "env WINEPREFIX='/home/burchettm/.wine' wine '/home/burchettm/.wine/drive_c/Program Files/RDP/mstsc.exe'" },
{ "Opera", "/usr/bin/opera" },
{ "Pidgin", "pidgin" },
{ "QuickSynergy", "quicksynergy" },
{ "SeaMonkey", "seamonkey" },
{ "Skype", "skype" },
{ "TeamSpeak 3", "/usr/bin/teamspeak3" },
{ "TeamViewer", "/opt/teamviewer/teamviewer/6/bin/teamviewer" },
{ "Thunderbird", "thunderbird" },
{ "Turpial", "turpial" },
{ "WhizNet", "env WINEPREFIX='/home/burchettm/.wineprefix/Whizkid' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Whizkid/dosdevices/c:/users/Public/Start\\ Menu/Programs/Whizkid\\ Online/WhizNet/WhizNet.lnk" },
{ "Wicd", "/usr/bin/wicd-client" }
}
myofficemenu = {
{ "LibreOffice", "libreoffice" },
{ "LibreOffice Base", "libreoffice --base" },
{ "LibreOffice Calc", "libreoffice --calc" },
{ "LibreOffice Draw", "libreoffice --draw" },
{ "LibreOffice Impress", "libreoffice --impress"},
{ "LibreOffice Math", "libreoffice --math" },
{ "LibreOffice Writer", "libreoffice --writer" },
{ "PDF Viewer", "epdfview" }
}
myprogrammingmenu = {
{ "Android SDK", "android" },
{ "BlueJ", "/usr/bin/bluej" },
{ "Bluefish Editor", "bluefish " },
{ "Dreamweaver 8", "env WINEPREFIX='/home/burchettm/.wineprefix/Adobe' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/Adobe/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Macromedia/Macromedia\\ Dreamweaver\\ 8.lnk" },
{"Eclipse", "eclipse"},
{ "Google Gadget Designer", "/usr/bin/ggl-gtk -sa -nd -gp /usr/share/google-gadgets/designer.gg" },
{ "Java Monitoring/Management Console", "jconsole" },
{ "Java VisualVM", "jvisualvm" },
{ "MonoDevelop", "monodevelop " },
{ "NetBeans IDE", "/usr/share/netbeans/bin/netbeans"},
{ "Qt Assistant", "/usr/bin/assistant" },
{ "Qt Designer", "/usr/bin/designer" },
{ "Qt Linguist", "/usr/bin/linguist" }
}
mysoundmenu = {
{ "AcetoneISO", "acetoneiso" },
{ "Audacious", "audacious" },
{ "Audacity", "audacity" },
{ "dvd::rip", "/usr/bin/vendor_perl/dvdrip" },
{ "EasyTAG", "easytag" },
{ "Ex Falso", "exfalso" },
{ "GNOME MPlayer", "gnome-mplayer" },
{ "GNOME MPC", "gmpc" },
{ "GTK-RecordMyDesktop", "gtk-recordmydesktop" },
{ "HandBrake", "ghb" },
{ "Last.FM", "lastfm" },
{ "Nero Linux", "nero" },
{ "Nero Linux Express", "neroexpress" },
{ "Pithos", "pithos" },
{ "QT V4L2 Tester", "qv4l2" },
{ "Quod Libet", "quodlibet" },
{ "Sonata", "sonata" },
{ "VLC", "vlc" },
{ "VolWheel", "volwheel" },
{ "Webcam Application", "wxcam" },
{ "XBMC", "xbmc" },
}
mysystemtoolsmenu = {
{ "Avahi Zeroconf", "/usr/bin/avahi-discover" },
{ "Bulk Rename", "/usr/lib/Thunar/ThunarBulkRename" },
{ "Cairo-Dock", "cairo-dock -c" },
{ "GLX-Dock", "cairo-dock -o" },
{ "GParted", "gksu /usr/sbin/gparted" },
{ "Htop", terminal .. " -e htop" },
{ "Manage Printing", "/usr/bin/xdg-open http://localhost:631/" },
{ ".NET 1.1 Configuration", "env WINEPREFIX='/home/burchettm/.wineprefix/SOF' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/SOF/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Administrative\\ Tools/Microsoft\\ .NET\\ Framework\\ 1.1\\ Configuration.lnk" },
{ ".NET 1.1 Wizards", "env WINEPREFIX='/home/burchettm/.wineprefix/SOF' wine C:\\\\windows\\\\command\\\\start.exe /Unix /home/burchettm/.wineprefix/SOF/dosdevices/c:/users/burchettm/Start\\ Menu/Programs/Administrative\\ Tools/Microsoft\\ .NET\\ Framework\\ 1.1\\ Wizards.lnk" },
{ "PkgBrowser", "pkgbrowser" },
{ "RXVT-Unicode", "urxvt" },
{ "Terminal", "terminal" },
{ "Thunar", "Thunar" },
{ "UNetBootIn", "/usr/bin/unetbootin" },
{ "VMware Player", "/usr/bin/vmplayer" },
{ "VMware Workstation", "/usr/bin/vmware" },
{ "VirtualBox", "VirtualBox" },
{ "Virtual Network Editor", "/usr/bin/vmware-netcfg" },
{ "Wireshark", "Wireshark" },
}
mymainmenu = awful.menu({ items = { { " ", " " },
{ "Opera", "opera" },
{ "Pidgin", "pidgin" },
{ "Skype", "skype" },
{ "Minecraft", "minecraft" },
{ "NCMPC++", "terminal --geometry 200x60 --hide-menubar -e ncmpcpp" },
{ "TeamSpeak3", "teamspeak3" },
{ "Terminal", terminal },
{ "Thunderbird", "thunderbird" },
{ "Turpial", "turpial" },
{ "VirtualBox", "VirtualBox" },
{ "WoW-Cataclysm", "env WINEPREFIX='/home/burchettm/.wineprefix/WoW-Cataclysm' wine '/media/Terabyte/WoW-Cataclysm/Wow.exe'" },
{ " ", " " },
{ "Accessories", myaccessoriesmenu, beautiful.menu_accessories },
{ "Arch Linux" , myarchmenu, beautiful.arch_icon },
{ "Games", mygamesmenu, beautiful.menu_games },
{ "Graphics", mygraphicsmenu, beautiful.menu_graphics },
{ "Internet", myinternetmenu, beautiful.menu_internet },
{ "Office", myofficemenu, beautiful.menu_office },
{ "Programming", myprogrammingmenu, beautiful.menu_programming },
{ "Sound & Video", mysoundmenu, beautiful.menu_sound },
{ "System Tools", mysystemtoolsmenu, beautiful.menu_system },
{ " ", " " },
{ "Awesome", myawesomemenu, beautiful.awesome_icon }
}
})
mylauncher = awful.widget.launcher({ image = image(beautiful.arch_icon),
menu = mymainmenu })
-- -- WIBOXES -- --
mywibox = {}
mypromptbox = {}
mylayoutbox = {}
mytaglist = {}
mytaglist.buttons = awful.util.table.join(
awful.button({ }, 1, awful.tag.viewonly),
awful.button({ modkey }, 1, awful.client.movetotag),
-- awful.button({ }, 3, awful.tag.viewtoggle), -- toggle viewing of other workspaces
awful.button({ modkey }, 3, awful.client.toggletag),
awful.button({ }, 4, awful.tag.viewnext),
awful.button({ }, 5, awful.tag.viewprev)
)
mytasklist = {}
mytasklist.buttons = awful.util.table.join(
awful.button({ }, 1, function (c)
if not c:isvisible() then
awful.tag.viewonly(c:tags()[1])
end
client.focus = c
c:raise()
end),
awful.button({ }, 3, function ()
if instance then
instance:hide()
instance = nil
else
instance = awful.menu.clients({ width=250 })
end
end),
awful.button({ }, 4, function ()
awful.client.focus.byidx(1)
if client.focus then client.focus:raise() end
end),
awful.button({ }, 5, function ()
awful.client.focus.byidx(-1)
if client.focus then client.focus:raise() end
end))
for s = 1, screen.count() do
-- Create a promptbox for each screen
mypromptbox[s] = awful.widget.prompt({ layout = awful.widget.layout.horizontal.leftright })
-- Create an imagebox widget which will contains an icon indicating which layout we're using.
-- We need one layoutbox per screen.
mylayoutbox[s] = awful.widget.layoutbox(s)
mylayoutbox[s]:buttons(awful.util.table.join(
awful.button({ }, 1, function () awful.layout.inc(layouts, 1) end),
awful.button({ }, 3, function () awful.layout.inc(layouts, -1) end),
awful.button({ }, 4, function () awful.layout.inc(layouts, 1) end),
awful.button({ }, 5, function () awful.layout.inc(layouts, -1) end)))
-- WIDGETS --
-- TEXT CLOCK --
mytextclock = awful.widget.textclock({ align = "right" }, "%H:%M:%S ", 1)
-- DATE --
mytextdate = awful.widget.textclock({ align = "right"}, "%a, %Y/%m/%d", 1)
-- CALENDAR --
cal.register(mytextdate, "<b><u>%s</u></b>") -- Added Calendar tooltip to date, bolded day & underlined day
-- SYSTRAY --
mysystray = widget({ type = "systray" })
-- SPACER --
myspacer = widget({ type = "textbox" })
myspacer.text = " | "
-- TAG LIST --
mytaglist[s] = awful.widget.taglist(s, awful.widget.taglist.label.all, mytaglist.buttons)
-- TASKLIST --
mytasklist[s] = awful.widget.tasklist(function(c)
return awful.widget.tasklist.label.currenttags(c, s)
end, mytasklist.buttons)
-- VOLUME --
volumewidget = widget ({ type = "textbox" })
vicious.register( volumewidget, vicious.widgets.volume, "$2 $1%", 2, "Master")
volumewidget:buttons(awful.util.table.join(
awful.button({ }, 1, function () awful.util.spawn("amixer -q sset Master toggle", false) end),
awful.button({ }, 3, function () awful.util.spawn("urxvt -e alsamixer", true) end),
awful.button({ }, 4, function () awful.util.spawn("amixer -q sset Master 5%+", false) end),
awful.button({ }, 5, function () awful.util.spawn("amixer -q sset Master 5%-", false) end)
))
-- WEATHER --
weatherwidget = widget ({ type = "textbox" })
vicious.register( weatherwidget, vicious.widgets.weather, '${tempf}°F',300, 'KSTL')
-- TOP BOX --
mywibox[s] = awful.wibox({ position = "top", screen = s, bg = "#22222200" })
-- Add widgets to the wibox - order matters
mywibox[s].widgets = {
{
mylauncher,
mytaglist[s],
mypromptbox[s],
layout = awful.widget.layout.horizontal.leftright
},
mylayoutbox[s],
mytextclock,
myspacer,
mytextdate,
myspacer,
weatherwidget,
myspacer,
volumewidget,
myspacer,
s == 1 and mysystray or nil,
mytasklist[s],
layout = awful.widget.layout.horizontal.rightleft
}
-- BOTTOM BOX --
-- BLANK SPACER --
blankspacer = widget({ type = "textbox" })
blankspacer.text = " "
-- OS --
sysinfo = widget({ type = "textbox" })
vicious.register(sysinfo, vicious.widgets.os, 'OS: Arch<span color = "'..beautiful.archblue..'">Linux</span> $2')
-- UPTIME --
uptime = widget({ type = "textbox" })
vicious.register(uptime, vicious.widgets.uptime, 'UP:<span color = "'..beautiful.dgreen..'"> $1D $2H $3M</span>')
-- CPU USAGE --
cpu = widget({ type = "textbox" })
vicious.register(cpu, vicious.widgets.cpu, 'CPU: <span color = "orange">$1%</span>')
-- MEMORY --
memory = widget({ type = "textbox" })
vicious.register(memory, vicious.widgets.mem, 'RAM:<span color = "cyan"> $1%</span> | SWAP:<span color = "green"> $5%</span>')
-- FILESYSTEM --
fileroot = widget({ type = "textbox" })
vicious.register(fileroot, vicious.widgets.fs, 'Root:<span color = "'..beautiful.orange..'"> ${/ used_gb} GB</span> / <span color = "green">${/ size_gb} GB</span>', 30)
filehome = widget({ type = "textbox" })
vicious.register(filehome, vicious.widgets.fs, 'Home:<span color = "'..beautiful.orange..'"> ${/home used_gb} GB</span> / <span color = "green">${/home size_gb} GB</span>', 30)
filetera = widget({ type = "textbox" })
vicious.register(filetera, vicious.widgets.fs, 'Terabyte: <span color = "'..beautiful.orange..'">${/media/Terabyte used_gb} GB</span> / <span color = "green">${/media/Terabyte size_gb} GB</span>', 30)
-- NET --
net = widget({ type = "textbox" })
vicious.register(net, vicious.widgets.net, 'D: <span color = "cyan">${eth0 down_kb} KB</span> / U: <span color = "#01A40D">${eth0 up_kb} KB</span>')
-- MPD --
mpd = widget({ type = "textbox" })
mpd.width, mpd.align = 750, "right"
vicious.register(mpd, vicious.widgets.mpd,
function (widget, args)
if args ["{state}"] == "Stop" then return 'MPD: <span color = "'..beautiful.orange..'">Stopped</span>'
else return 'MPD: <span color = "cyan"> '..
args ["{Artist}"]..' - '.. args["{Title}"]..'</span>'
end
end)
-- WIBOX --
infobox = {}
infobox[s] = awful.wibox({ position = "bottom", screen = s, bg = "#22222200" })
infobox[s].widgets = { { blankspacer,
sysinfo,
myspacer,
uptime,
myspacer,
cpu,
myspacer,
memory,
myspacer,
fileroot,
myspacer,
filehome,
myspacer,
filetera,
myspacer,
net,
layout = awful.widget.layout.horizontal.leftright },
blankspacer,
mpd,
layout = awful.widget.layout.horizontal.rightleft }
end
-- -- BINDINGS -- --
-- MOUSE --
root.buttons(awful.util.table.join(
awful.button({ }, 3, function () mymainmenu:toggle() end),
awful.button({ }, 4, awful.tag.viewnext),
awful.button({ }, 5, awful.tag.viewprev)
))
-- KEYBOARD --
globalkeys = awful.util.table.join(
awful.key({ modkey, }, "Left", awful.tag.viewprev ),
awful.key({ modkey, }, "Right", awful.tag.viewnext ),
awful.key({ modkey, }, "Escape", awful.tag.history.restore),
awful.key({ modkey, }, "j",
function ()
awful.client.focus.byidx( 1)
if client.focus then client.focus:raise() end
end),
awful.key({ modkey, }, "k",
function ()
awful.client.focus.byidx(-1)
if client.focus then client.focus:raise() end
end),
awful.key({ modkey, }, "w", function () mymainmenu:show({keygrabber=true}) end),
-- User Added Keybindings
awful.key({}, "XF86AudioRaiseVolume", function () awful.util.spawn("amixer set Master 5%+") end),
awful.key({}, "XF86AudioLowerVolume", function () awful.util.spawn("amixer set Master 5%-") end),
awful.key({}, "XF86AudioMute", function () awful.util.spawn("amixer set Master toggle") end),
awful.key({}, "XF86AudioNext", function () awful.util.spawn("mpc next") end),
awful.key({}, "XF86AudioPrev", function () awful.util.spawn("mpc prev") end),
awful.key({}, "XF86AudioStop", function () awful.util.spawn("mpc stop") end),
awful.key({}, "XF86AudioPlay", function () awful.util.spawn("mpc toggle") end),
awful.key({}, "Print", function () awful.util.spawn("scrotshooter") end),
awful.key({}, "Sys_Req", function () awful.util.spawn("scrotshooter-aprint") end),
awful.key({modkey }, "p", function() awful.util.spawn( "dmenu_run" ) end),
awful.key({modkey }, "e", function() awful.util.spawn( "pcmanfm" ) end),
awful.key({ modkey }, "F12", function () scratch.drop( terminal, "top") end),
-- Layout manipulation
awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end),
awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end),
awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end),
awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end),
awful.key({ modkey, }, "u", awful.client.urgent.jumpto),
awful.key({ modkey, }, "Tab",
function ()
awful.client.focus.history.previous()
if client.focus then
client.focus:raise()
end
end),
-- Standard program
awful.key({ modkey, }, "Return", function () awful.util.spawn(terminal) end),
awful.key({ modkey, "Control" }, "r", awesome.restart),
awful.key({ modkey, "Shift" }, "q", awesome.quit),
awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end),
awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end),
awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1) end),
awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1) end),
awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1) end),
awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1) end),
awful.key({ modkey, }, "space", function () awful.layout.inc(layouts, 1) end),
awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(layouts, -1) end),
-- Prompt
awful.key({ modkey }, "r", function () mypromptbox[mouse.screen]:run() end),
awful.key({ modkey }, "x",
function ()
awful.prompt.run({ prompt = "Run Lua code: " },
mypromptbox[mouse.screen].widget,
awful.util.eval, nil,
awful.util.getdir("cache") .. "/history_eval")
end)
)
clientkeys = awful.util.table.join(
awful.key({ modkey, }, "f", function (c) c.fullscreen = not c.fullscreen end),
awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end),
awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ),
awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end),
awful.key({ modkey, }, "o", awful.client.movetoscreen ),
awful.key({ modkey, "Shift" }, "r", function (c) c:redraw() end),
awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end),
awful.key({ modkey, }, "n", function (c) c.minimized = not c.minimized end),
awful.key({ modkey, }, "m",
function (c)
c.maximized_horizontal = not c.maximized_horizontal
c.maximized_vertical = not c.maximized_vertical
end)
)
-- Compute the maximum number of digit we need, limited to 9
keynumber = 0
for s = 1, screen.count() do
keynumber = math.min(9, math.max(#tags[s], keynumber));
end
-- Bind all key numbers to tags.
-- Be careful: we use keycodes to make it works on any keyboard layout.
-- This should map on the top row of your keyboard, usually 1 to 9.
for i = 1, keynumber do
globalkeys = awful.util.table.join(globalkeys,
awful.key({ modkey }, "#" .. i + 9,
function ()
local screen = mouse.screen
if tags[screen][i] then
awful.tag.viewonly(tags[screen][i])
end
end),
awful.key({ modkey, "Control" }, "#" .. i + 9,
function ()
local screen = mouse.screen
if tags[screen][i] then
awful.tag.viewtoggle(tags[screen][i])
end
end),
awful.key({ modkey, "Shift" }, "#" .. i + 9,
function ()
if client.focus and tags[client.focus.screen][i] then
awful.client.movetotag(tags[client.focus.screen][i])
end
end),
awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
function ()
if client.focus and tags[client.focus.screen][i] then
awful.client.toggletag(tags[client.focus.screen][i])
end
end))
end
clientbuttons = awful.util.table.join(
awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
awful.button({ modkey }, 1, awful.mouse.client.move),
awful.button({ modkey }, 3, awful.mouse.client.resize))
-- Set keys
root.keys(globalkeys)
-- -- RULES -- --
awful.rules.rules = {
-- All clients will match this rule.
{ rule = { },
properties = { border_width = beautiful.border_width,
border_color = beautiful.border_normal,
focus = true,
keys = clientkeys,
buttons = clientbuttons } },
{ rule = { class = "MPlayer" },
properties = { floating = true } },
{ rule = { class = "pinentry" },
properties = { floating = true } },
{ rule = { class = "gimp" },
properties = { maximized_vertical = true, maximized_horizontal = true } },
{ rule = { class = "Opera" }, properties = { tag = tags[1][3] } },
{ rule = { class = "Pidgin" }, properties = { tag = tags[1][4] } },
{ rule = { class = "Skype" }, properties = { tag = tags[1][4] } },
{ rule = { class = "Sonata" }, properties = { tag = tags[1][5] } },
{ rule = { class = "Turpial" }, properties = { tag = tags[1][6] } },
{ rule = { class = "NCMPC++" }, properties = { tag = tags[1][5] } },
{ rule = { class = "ts3client_linux_amd64" }, properties = { tag = tags[1][4] } },
-- Set Firefox to always map on tags number 2 of screen 1.
-- { rule = { class = "Firefox" },
-- properties = { tag = tags[1][2] } },
}
-- -- SIGNALS -- --
-- Signal function to execute when a new client appears.
client.add_signal("manage", function (c, startup)
-- Add a titlebar
-- awful.titlebar.add(c, { modkey = modkey })
-- Enable sloppy focus
c:add_signal("mouse::enter", function(c)
if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
and awful.client.focus.filter(c) then
client.focus = c
end
end)
if not startup then
-- Set the windows at the slave,
-- i.e. put it at the end of others instead of setting it master.
-- awful.client.setslave(c)
-- Put windows in a smart way, only if they does not set an initial position.
if not c.size_hints.user_position and not c.size_hints.program_position then
awful.placement.no_overlap(c)
awful.placement.no_offscreen(c)
end
end
end)
client.add_signal("focus", function(c) c.border_color = beautiful.border_focus end)
client.add_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)

View File

@ -0,0 +1,29 @@
#!/bin/zsh
SERVICE=conky
if pidof $SERVICE > /dev/null
then
echo "$SERVICE is running."
#echo "Starting $SERVICE ..."
#synergys -c /home/burchettm/.quicksynergy/synergy.conf
# if pgrep $SERVICE > /dev/null
# then
# echo "$SERVICE started ..."
# else
# echo "$SERVICE failed to start ..."
# fi
else
echo "$SERVICE is NOT running."
echo "Starting $SERVICE ..."
conky --config /home/burchettm/.conky/conkyrc1
if pidof $SERVICE > /dev/null
then
echo "$SERVICE started ..."
else
echo "$SERVICE failed to start ..."
fi
fi

View File

@ -0,0 +1,29 @@
#!/bin/zsh
SERVICE=synergys
if pidof $SERVICE > /dev/null
then
echo "$SERVICE is running."
#echo "Starting $SERVICE ..."
#synergys -c /home/burchettm/.quicksynergy/synergy.conf
# if pgrep $SERVICE > /dev/null
# then
# echo "$SERVICE started ..."
# else
# echo "$SERVICE failed to start ..."
# fi
else
echo "$SERVICE is NOT running."
echo "Starting $SERVICE ..."
synergys -c /home/burchettm/.quicksynergy/synergy.conf
if pidof $SERVICE > /dev/null
then
echo "$SERVICE started ..."
else
echo "$SERVICE failed to start ..."
fi
fi

View File

@ -0,0 +1,29 @@
#!/bin/zsh
SERVICE=x11vnc
if pidof $SERVICE > /dev/null
then
echo "$SERVICE is running."
#echo "Starting $SERVICE ..."
#synergys -c /home/burchettm/.quicksynergy/synergy.conf
# if pgrep $SERVICE > /dev/null
# then
# echo "$SERVICE started ..."
# else
# echo "$SERVICE failed to start ..."
# fi
else
echo "$SERVICE is NOT running."
echo "Starting $SERVICE ..."
x11vnc -rfbauth -bg -q ~/.vnc/passwd >> /home/burchettm/.log/x11vnc.log
if pidof $SERVICE > /dev/null
then
echo "$SERVICE started ..."
else
echo "$SERVICE failed to start ..."
fi
fi

View File

@ -0,0 +1,3 @@
Background images:
Mikael Eriksson <mikael_eriksson@miffe.org>
Licensed under CC-BY-SA-3.0

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