2008-09-29 16:49:18 +02:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
-- @author Julien Danjou <julien@danjou.info>
|
|
|
|
-- @copyright 2008 Julien Danjou
|
|
|
|
-- @release @AWESOME_VERSION@
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- Grab environment we need
|
|
|
|
local os = os
|
|
|
|
local io = io
|
|
|
|
local assert = assert
|
2012-06-16 14:22:35 +02:00
|
|
|
local load = loadstring or load -- v5.1 - loadstring, v5.2 - load
|
2008-09-30 17:00:19 +02:00
|
|
|
local loadfile = loadfile
|
2008-09-29 16:49:18 +02:00
|
|
|
local debug = debug
|
2009-07-02 02:04:59 +02:00
|
|
|
local pairs = pairs
|
|
|
|
local ipairs = ipairs
|
2008-09-30 15:50:41 +02:00
|
|
|
local type = type
|
2009-04-15 10:31:41 +02:00
|
|
|
local rtable = table
|
2009-04-18 22:44:36 +02:00
|
|
|
local pairs = pairs
|
2009-05-27 17:49:20 +02:00
|
|
|
local string = string
|
2008-09-29 16:49:18 +02:00
|
|
|
local capi =
|
|
|
|
{
|
|
|
|
awesome = awesome,
|
|
|
|
mouse = mouse
|
|
|
|
}
|
|
|
|
|
|
|
|
--- Utility module for awful
|
2012-06-12 20:13:09 +02:00
|
|
|
-- awful.util
|
|
|
|
local util = {}
|
|
|
|
util.table = {}
|
2009-04-15 10:46:34 +02:00
|
|
|
|
2009-05-09 13:28:57 +02:00
|
|
|
shell = os.getenv("SHELL") or "/bin/sh"
|
|
|
|
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.deprecate(see)
|
2008-11-12 11:37:34 +01:00
|
|
|
io.stderr:write("W: awful: function is deprecated")
|
2008-11-14 12:09:35 +01:00
|
|
|
if see then
|
|
|
|
io.stderr:write(", see " .. see)
|
|
|
|
end
|
|
|
|
io.stderr:write("\n")
|
2008-11-12 11:37:34 +01:00
|
|
|
io.stderr:write(debug.traceback())
|
2008-09-29 16:49:18 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Strip alpha part of color.
|
|
|
|
-- @param color The color.
|
|
|
|
-- @return The color without alpha channel.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.color_strip_alpha(color)
|
2008-09-29 16:49:18 +02:00
|
|
|
if color:len() == 9 then
|
|
|
|
color = color:sub(1, 7)
|
|
|
|
end
|
|
|
|
return color
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Make i cycle.
|
2011-11-09 21:34:30 +01:00
|
|
|
-- @param t A length. Must be greater than zero.
|
2008-09-29 16:49:18 +02:00
|
|
|
-- @param i An absolute index to fit into #t.
|
2011-11-09 21:34:30 +01:00
|
|
|
-- @return An integer in (1, t) or nil if t is less than or equal to zero.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.cycle(t, i)
|
2011-11-09 21:34:30 +01:00
|
|
|
if t < 1 then return end
|
2008-09-29 16:49:18 +02:00
|
|
|
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
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.mkdir(dir)
|
2008-09-29 16:49:18 +02:00
|
|
|
return os.execute("mkdir -p " .. dir)
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Spawn a program.
|
|
|
|
-- @param cmd The command.
|
2009-06-22 17:45:20 +02:00
|
|
|
-- @param sn Enable startup-notification.
|
2008-09-29 16:49:18 +02:00
|
|
|
-- @param screen The screen where to spawn window.
|
|
|
|
-- @return The awesome.spawn return value.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.spawn(cmd, sn, screen)
|
2008-09-29 16:49:18 +02:00
|
|
|
if cmd and cmd ~= "" then
|
2009-04-03 16:30:18 +02:00
|
|
|
if sn == nil then sn = true end
|
|
|
|
return capi.awesome.spawn(cmd, sn, screen or capi.mouse.screen)
|
2008-09-29 16:49:18 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-04-30 00:39:51 +02:00
|
|
|
--- Spawn a program using the shell.
|
|
|
|
-- @param cmd The command.
|
|
|
|
-- @param screen The screen where to run the command.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.spawn_with_shell(cmd, screen)
|
2009-04-30 00:39:51 +02:00
|
|
|
if cmd and cmd ~= "" then
|
|
|
|
cmd = shell .. " -c \"" .. cmd .. "\""
|
|
|
|
return capi.awesome.spawn(cmd, false, screen or capi.mouse.screen)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-04-23 10:12:53 +02:00
|
|
|
--- Read a program output and returns its output as a string.
|
2008-09-29 16:49:18 +02:00
|
|
|
-- @param cmd The command to run.
|
2009-08-25 20:16:35 +02:00
|
|
|
-- @return A string with the program output, or the error if one occured.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.pread(cmd)
|
2008-09-29 16:49:18 +02:00
|
|
|
if cmd and cmd ~= "" then
|
2008-12-11 22:14:07 +01:00
|
|
|
local f, err = io.popen(cmd, 'r')
|
|
|
|
if f then
|
|
|
|
local s = f:read("*all")
|
|
|
|
f:close()
|
|
|
|
return s
|
|
|
|
else
|
2009-08-25 20:16:35 +02:00
|
|
|
return err
|
2008-12-11 22:14:07 +01:00
|
|
|
end
|
2008-09-29 16:49:18 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Eval Lua code.
|
|
|
|
-- @return The return value of Lua code.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.eval(s)
|
2012-06-16 14:22:35 +02:00
|
|
|
return assert(load(s))()
|
2008-09-29 16:49:18 +02:00
|
|
|
end
|
|
|
|
|
2009-02-15 20:12:44 +01:00
|
|
|
local xml_entity_names = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
|
2008-09-29 16:49:18 +02:00
|
|
|
--- Escape a string from XML char.
|
|
|
|
-- Useful to set raw text in textbox.
|
|
|
|
-- @param text Text to escape.
|
|
|
|
-- @return Escape text.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.escape(text)
|
2009-01-28 10:05:26 +01:00
|
|
|
return text and text:gsub("['&<>\"]", xml_entity_names) or nil
|
2008-09-29 16:49:18 +02:00
|
|
|
end
|
|
|
|
|
2009-02-15 20:12:44 +01:00
|
|
|
local xml_entity_chars = { lt = "<", gt = ">", nbsp = " ", quot = "\"", apos = "'", ndash = "-", mdash = "-", amp = "&" };
|
2008-09-29 16:49:18 +02:00
|
|
|
--- Unescape a string from entities.
|
|
|
|
-- @param text Text to unescape.
|
|
|
|
-- @return Unescaped text.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.unescape(text)
|
2009-01-28 10:05:26 +01:00
|
|
|
return text and text:gsub("&(%a+);", xml_entity_chars) or nil
|
2008-09-29 16:49:18 +02:00
|
|
|
end
|
|
|
|
|
2008-09-30 15:50:41 +02:00
|
|
|
--- Check if a file is a Lua valid file.
|
2008-09-30 17:00:19 +02:00
|
|
|
-- This is done by loading the content and compiling it with loadfile().
|
2008-09-30 15:50:41 +02:00
|
|
|
-- @param path The file path.
|
|
|
|
-- @return A function if everything is alright, a string with the error
|
|
|
|
-- otherwise.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.checkfile(path)
|
2008-09-30 17:07:25 +02:00
|
|
|
local f, e = loadfile(path)
|
2008-09-30 15:50:41 +02:00
|
|
|
-- 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.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.restart()
|
|
|
|
local c = util.checkfile(capi.awesome.conffile)
|
2008-09-30 15:50:41 +02:00
|
|
|
|
|
|
|
if type(c) ~= "function" then
|
|
|
|
return c
|
|
|
|
end
|
|
|
|
|
|
|
|
capi.awesome.restart()
|
|
|
|
end
|
|
|
|
|
2009-02-15 20:12:44 +01:00
|
|
|
--- 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.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.getdir(d)
|
2008-10-22 17:56:51 +02:00
|
|
|
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"
|
Various changes to awful.util and invaders
This commit changes various aspects of awful.util and invaders:
awful.util:
- added awful.util.getdir(d)
This function takes one argument and returns a matching directory,
as of now, only "cache" is supported. The return value is either
$XDG_CACHE_HOME/awesome/ or $HOME/.cache/awesome/, XDG_CACHE_HOME
takes precedence
invaders:
- renamed invaders to awesome invaders
at two places in the sourcecode, invaders is referred to as
"Space Invaders for Awesome". As Taiko holds the trademark for
the term "Space Invaders", I changed both of its occurences to
"Awesome Invaders" to avoid conflicts with the law of Japan and
the United States of America (and possibly others)
- added support for XDG_CACHE_HOME
this change adds support for XDG_CACHE_HOME as the cache directory
for highscores and screenshots
- added some parameters to invaders.run()
this change adds three parameters to invaders.run, supplied as a
table. They are "x", "y" and "solidbg".
"x" sets the X coordinate of the playfield
"y" sets the Y coordinate of the playfield
"solidbg" sets the color of the playfield background for people who
have problems with transparency. This still looks rather hackish and
needs to be polished
- changed startup position
up until now, invaders always started at (100,100) on the first
screen, now it starts centered to the screen on which the mouse cursor
is.
2008-10-17 19:05:57 +02:00
|
|
|
end
|
|
|
|
return os.getenv("HOME").."/.cache/awesome"
|
|
|
|
end
|
|
|
|
end
|
2008-11-22 17:23:03 +01:00
|
|
|
|
2011-11-02 02:42:37 +01:00
|
|
|
--- Search for an icon and return the full path.
|
|
|
|
-- It searches for the icon path under the directories given w/the right ext
|
|
|
|
-- @param iconname The name of the icon to search for.
|
|
|
|
-- @param exts Table of image extensions allowed, otherwise { 'png', gif' }
|
|
|
|
-- @param dirs Table of dirs to search, otherwise { '/usr/share/pixmaps/' }
|
2012-05-28 19:16:11 +02:00
|
|
|
-- @param size Optional size. If this is specified, subdirectories <size>x<size>
|
|
|
|
-- of the dirs are searched first
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.geticonpath(iconname, exts, dirs, size)
|
2011-11-02 02:42:37 +01:00
|
|
|
exts = exts or { 'png', 'gif' }
|
|
|
|
dirs = dirs or { '/usr/share/pixmaps/' }
|
|
|
|
for _, d in pairs(dirs) do
|
|
|
|
for _, e in pairs(exts) do
|
2012-05-28 19:16:11 +02:00
|
|
|
local icon
|
|
|
|
if size then
|
|
|
|
icon = string.format("%s%ux%u/%s.%s",
|
|
|
|
d, size, size, iconname, e)
|
2012-06-12 20:13:09 +02:00
|
|
|
if util.file_readable(icon) then
|
2012-05-28 19:16:11 +02:00
|
|
|
return icon
|
|
|
|
end
|
|
|
|
end
|
|
|
|
icon = d .. iconname .. '.' .. e
|
2012-06-12 20:13:09 +02:00
|
|
|
if util.file_readable(icon) then
|
2011-11-02 02:42:37 +01:00
|
|
|
return icon
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2008-11-22 17:23:03 +01:00
|
|
|
--- Check if file exists and is readable.
|
|
|
|
-- @param filename The file path
|
|
|
|
-- @return True if file exists and readable.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.file_readable(filename)
|
2008-11-22 17:23:03 +01:00
|
|
|
local file = io.open(filename)
|
|
|
|
if file then
|
|
|
|
io.close(file)
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2009-04-15 10:31:41 +02:00
|
|
|
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.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.subsets(set)
|
2009-04-15 10:31:41 +02:00
|
|
|
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
|
|
|
|
|
2009-04-15 21:33:21 +02:00
|
|
|
--- Join all tables given as parameters.
|
2009-04-18 22:44:36 +02:00
|
|
|
-- This will iterate all tables and insert all their keys into a new table.
|
2009-04-15 21:33:21 +02:00
|
|
|
-- @param args A list of tables to join
|
2009-04-18 22:44:36 +02:00
|
|
|
-- @return A new table containing all keys from the arguments.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.join(...)
|
2009-04-15 10:46:34 +02:00
|
|
|
local ret = {}
|
2010-10-11 16:55:56 +02:00
|
|
|
for i, t in ipairs({...}) do
|
|
|
|
if t then
|
|
|
|
for k, v in pairs(t) do
|
2009-04-18 23:22:15 +02:00
|
|
|
if type(k) == "number" then
|
|
|
|
rtable.insert(ret, v)
|
|
|
|
else
|
|
|
|
ret[k] = v
|
|
|
|
end
|
2009-04-18 22:44:36 +02:00
|
|
|
end
|
|
|
|
end
|
2009-04-15 10:46:34 +02:00
|
|
|
end
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
|
2009-04-27 18:33:15 +02:00
|
|
|
--- 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.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.hasitem(t, item)
|
2009-04-27 18:33:15 +02:00
|
|
|
for k, v in pairs(t) do
|
|
|
|
if v == item then
|
|
|
|
return k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-05-27 17:49:20 +02:00
|
|
|
--- 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.
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.linewrap(text, width, indent)
|
2009-05-27 17:49:20 +02:00
|
|
|
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
|
|
|
|
|
2009-07-02 02:04:59 +02:00
|
|
|
--- 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
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.keys(t)
|
2009-07-02 02:04:59 +02:00
|
|
|
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
|
|
|
|
|
2009-07-02 02:05:29 +02:00
|
|
|
--- 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
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.keys_filter(t, ...)
|
|
|
|
local keys = util.table.keys(t)
|
2009-07-02 02:05:29 +02:00
|
|
|
local keys_filtered = { }
|
|
|
|
for _, k in pairs(keys) do
|
2010-10-12 18:16:39 +02:00
|
|
|
for _, et in pairs({...}) do
|
2009-07-02 02:05:29 +02:00
|
|
|
if type(t[k]) == et then
|
|
|
|
rtable.insert(keys_filtered, k)
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return keys_filtered
|
|
|
|
end
|
|
|
|
|
2009-07-02 02:05:42 +02:00
|
|
|
--- Reverse a table
|
|
|
|
-- @param t the table to reverse
|
|
|
|
-- @return the reversed table
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.reverse(t)
|
2009-07-02 02:05:42 +02:00
|
|
|
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
|
2009-11-17 07:53:07 +01:00
|
|
|
if type(k) ~= "number" then
|
2009-07-02 02:05:42 +02:00
|
|
|
tr[k] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return tr
|
|
|
|
end
|
|
|
|
|
2009-06-25 01:15:07 +02:00
|
|
|
--- Clone a table
|
|
|
|
-- @param t the table to clone
|
|
|
|
-- @return a clone of t
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.clone(t)
|
2009-06-25 01:15:07 +02:00
|
|
|
local c = { }
|
|
|
|
for k, v in pairs(t) do
|
2009-10-24 14:51:47 +02:00
|
|
|
if type(v) == "table" then
|
2012-06-12 20:13:09 +02:00
|
|
|
c[k] = util.table.clone(v)
|
2009-10-24 14:51:47 +02:00
|
|
|
else
|
|
|
|
c[k] = v
|
|
|
|
end
|
2009-06-25 01:15:07 +02:00
|
|
|
end
|
|
|
|
return c
|
|
|
|
end
|
|
|
|
|
2012-02-16 22:00:41 +01:00
|
|
|
---
|
|
|
|
-- Returns an iterator to cycle through, starting from the first element or the
|
|
|
|
-- given index, all elments of a table that match a given criteria.
|
2012-04-02 13:36:12 +02:00
|
|
|
--
|
2012-02-16 22:00:41 +01:00
|
|
|
-- @param t the table to iterate
|
|
|
|
-- @param filter a function that returns true to indicate a positive match
|
|
|
|
-- @param start what index to start iterating from. Default is 1 (=> start of
|
|
|
|
-- the table)
|
2012-06-12 20:13:09 +02:00
|
|
|
function util.table.iterate(t, filter, start)
|
2012-02-16 22:00:41 +01:00
|
|
|
local count = 0
|
|
|
|
local index = start or 1
|
|
|
|
local length = #t
|
|
|
|
|
|
|
|
return function ()
|
|
|
|
while count < length do
|
|
|
|
local item = t[index]
|
2012-06-12 20:13:09 +02:00
|
|
|
index = util.cycle(#t, index + 1)
|
2012-02-16 22:00:41 +01:00
|
|
|
count = count + 1
|
|
|
|
if filter(item) then return item end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-06-12 20:13:09 +02:00
|
|
|
|
|
|
|
return util
|
|
|
|
|
2011-09-11 16:50:01 +02:00
|
|
|
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
|