awesome-revelation/init.lua

490 lines
15 KiB
Lua
Raw Normal View History

2013-08-31 23:54:57 +02:00
-- revelation .lua
2011-08-23 23:37:11 +02:00
--
-- Library that implements Expose like behavior.
--
-- @author Perry Hargrave resixian@gmail.com
-- @author Espen Wiborg espenhw@grumblesmurf.org
-- @author Julien Danjou julien@danjou.info
2013-08-31 23:54:57 +02:00
-- @auther Quan Guo guotsuan@gmail.com
2011-08-23 23:37:11 +02:00
--
-- @copyright 2008 Espen Wiborg, Julien Danjou
--
2013-08-31 23:54:57 +02:00
local beautiful = require("beautiful")
local wibox = require("wibox")
local awful = require('awful')
local aw_rules = require('awful.rules')
local pairs = pairs
2011-08-23 23:37:11 +02:00
local setmetatable = setmetatable
2013-08-31 23:54:57 +02:00
local naughty = require("naughty")
local table = table
local clock = os.clock
2013-08-31 23:54:57 +02:00
local tostring = tostring
local capi = {
awesome = awesome,
2013-08-31 23:54:57 +02:00
tag = tag,
client = client,
keygrabber = keygrabber,
mousegrabber = mousegrabber,
mouse = mouse,
screen = screen
2011-08-23 23:37:11 +02:00
}
-- disable for now.
-- It seems there is not way to pass err handling function into the delayed_call()
local delayed_call = (type(timer) ~= 'table' and require("gears.timer").delayed_call)
2011-08-23 23:37:11 +02:00
local clientData = {} -- table that holds the positions and sizes of floating clients
2015-08-21 02:24:01 +02:00
local charorder = "jkluiopyhnmfdsatgvcewqzx1234567890"
local hintbox = {} -- Table of letter wiboxes with characters as the keys
2015-09-26 03:38:54 +02:00
local hintindex = {} -- Table of visible clients with the hint letter as the keys
2011-08-23 23:37:11 +02:00
2015-08-21 02:24:01 +02:00
local revelation = {
-- Name of expose tag.
tag_name = "Revelation",
-- Match function can be defined by user.
-- Must accept a `rule` and `client` and return `boolean`.
-- The rule forms follow `awful.rules` syntax except we also check the
-- special `rule.any` key. If its true, then we use the `match.any` function
-- for comparison.
match = {
exact = aw_rules.match,
any = aw_rules.match_any
},
property_to_watch={
minimized = false,
fullscreen = false,
maximized_horizontal = false,
maximized_vertical = false,
sticky = false,
ontop = false,
above = false,
below = false,
},
tags_status = {},
is_excluded = false,
curr_tag_only = false,
font = "monospace 20",
2015-08-21 02:24:01 +02:00
fg = beautiful.fg_normal,
hintsize = (type(beautiful.xresources) == 'table' and beautiful.xresources.apply_dpi(50) or 60)
}
2011-08-23 23:37:11 +02:00
2013-08-31 23:54:57 +02:00
2011-08-23 23:37:11 +02:00
-- Executed when user selects a client from expose view.
--
-- @param restore Function to reset the current tags view.
2015-09-26 03:38:54 +02:00
local function selectfn(restore, t, zt)
2011-08-23 23:37:11 +02:00
return function(c)
2015-09-26 03:38:54 +02:00
revelation.restore(t, zt)
2011-08-23 23:37:11 +02:00
-- Focus and raise
if c.minimized then
c.minimized = false
end
awful.client.jumpto(c)
2011-08-23 23:37:11 +02:00
end
end
-- Tags all matching clients with tag t
-- @param rule The rule. Conforms to awful.rules syntax.
-- @param clients A table of clients to check.
-- @param t The tag to give matching clients.
local function match_clients(rule, clients, t, is_excluded)
local mfc = rule.any and revelation.match.any or revelation.match.exact
2015-08-21 02:24:01 +02:00
local mf = is_excluded and function(c,_rule) return not mfc(c,_rule) end or mfc
local flt
for _, c in pairs(clients) do
if mf(c, rule) then
-- Store geometry before setting their tags
clientData[c] = {}
2015-02-24 21:48:06 +01:00
if awful.client.floating.get(c) then
clientData[c]["geometry"] = c:geometry()
2015-02-24 21:48:06 +01:00
flt = awful.client.property.get(c, "floating")
if flt ~= nil then
clientData[c]["floating"] = flt
2015-02-24 21:48:06 +01:00
awful.client.property.set(c, "floating", false)
end
end
for k,v in pairs(revelation.property_to_watch) do
clientData[c][k] = c[k]
c[k] = v
2015-02-24 21:48:06 +01:00
end
awful.client.toggletag(t, c)
end
end
return clients
end
2011-08-23 23:37:11 +02:00
-- Implement Exposé (ala Mac OS X).
--
-- @param rule A table with key and value to match. [{class=""}]
2013-08-31 23:54:57 +02:00
function revelation.expose(args)
2015-08-21 02:24:01 +02:00
args = args or {}
local rule = args.rule or {}
local is_excluded = args.is_excluded or false
local curr_tag_only = args.curr_tag_only or false
revelation.is_excluded = is_excluded
revelation.curr_tag_only = curr_tag_only
2013-08-31 23:54:57 +02:00
local t={}
local zt={}
2013-08-31 23:54:57 +02:00
for scr=1,capi.screen.count() do
t[scr] = awful.tag.new({revelation.tag_name},
2013-08-31 23:54:57 +02:00
scr,
awful.layout.suit.fair)[1]
zt[scr] = awful.tag.new({revelation.tag_name.."_zoom"},
2013-08-31 23:54:57 +02:00
scr,
awful.layout.suit.fair)[1]
2015-02-24 21:48:06 +01:00
if curr_tag_only then
match_clients(rule, awful.client.visible(scr), t[scr], is_excluded)
else
match_clients(rule, capi.client.get(scr), t[scr], is_excluded)
end
2013-08-31 23:54:57 +02:00
awful.tag.viewonly(t[scr], t.screen)
2015-02-24 21:48:06 +01:00
end
if type(delayed_call) == 'function' then
capi.awesome.emit_signal("refresh")
end
-- No need for awesome WM 3.5.6: capi.awesome.emit_signal("refresh")
--
local status, err=pcall(revelation.expose_callback, t, zt)
--revelation.expose_callback(t, zt)
if not status then
debuginfo('Oops!, something is wrong in revelation.expose_callback!')
if err.msg then
debuginfo(err.msg)
end
if err.code then
debuginfo('error code is '.. tostring(err.code))
end
2015-09-26 03:38:54 +02:00
revelation.restore(t, zt)
end
end
2013-08-31 23:54:57 +02:00
---- descrepted
---- this timer is used to want the the geometry of clients are recalcuated.
---- if timeout = 0.0, it consumes cpu, timeout = 0.001 is good enough.
----
--local block_timer = timer({ timeout = 0.001 })
--local hintindex = {} -- Table of visible clients with the hint letter as the keys
--local clientlist = awful.client.visible()
--block_timer:connect_signal("timeout", function ()
--for i,thisclient in pairs(clientlist) do
---- Move wiboxes to center of visible windows and populate hintindex
--local char = charorder:sub(i,i)
--hintindex[char] = thisclient
--hintbox[char].visible = true
--local geom = thisclient.geometry(thisclient)
--hintbox[char].x = geom.x + geom.width/2 - hintsize/2
--hintbox[char].y = geom.y + geom.height/2 - hintsize/2
--hintbox[char].screen = thisclient.screen
--end
--end)
--block_timer:start()
2015-09-26 03:38:54 +02:00
function revelation.restore(t, zt)
for scr=1, capi.screen.count() do
awful.tag.history.restore(scr)
t[scr].screen = nil
end
capi.keygrabber.stop()
capi.mousegrabber.stop()
for scr=1, capi.screen.count() do
t[scr].activated = false
zt[scr].activated = false
end
local clients
for scr=1, capi.screen.count() do
if revelation.curr_tag_only then
clients = awful.client.visible(scr)
else
clients = capi.client.get(scr)
end
for _, c in pairs(clients) do
if clientData[c] then
for k,v in pairs(clientData[c]) do
if v ~= nil then
if k== "geometry" then
c:geometry(v)
elseif k == "floating" then
awful.client.property.set(c, "floating", v)
else
c[k]=v
end
end
end
end
end
end
for i,j in pairs(hintindex) do
hintbox[i].visible = false
end
end
local function hintbox_display_toggle(c, show)
for char, thisclient in pairs(hintindex) do
if char and char ~= c then
hintindex[char] = thisclient
if show then
hintbox[char].visible = true
else
hintbox[char].visible = false
end
end
end
end
local function hintbox_pos(char)
local client = hintindex[char]
local geom = client:geometry()
hintbox[char].x = math.floor(geom.x + geom.width/2 - revelation.hintsize/2)
hintbox[char].y = math.floor(geom.y + geom.height/2 - revelation.hintsize/2)
end
2015-09-26 03:38:54 +02:00
2015-08-21 02:24:01 +02:00
function revelation.expose_callback(t, zt)
2013-08-31 23:54:57 +02:00
local clientlist = awful.client.visible()
2015-02-24 21:48:06 +01:00
for i,thisclient in pairs(clientlist) do
2013-08-31 23:54:57 +02:00
-- Move wiboxes to center of visible windows and populate hintindex
local char = charorder:sub(i,i)
if char and char ~= '' then
hintindex[char] = thisclient
hintbox_pos(char)
hintbox[char].visible = true
hintbox[char].screen = thisclient.screen
end
2013-08-31 23:54:57 +02:00
end
2011-08-23 23:37:11 +02:00
local zoomed = false
local zoomedClient = nil
local key_char_zoomed = nil
capi.keygrabber.run(function (mod, key, event)
local c
if event == "release" then return true end
if awful.util.table.hasitem(mod, "Shift") then
key_char = string.lower(key)
c = hintindex[key_char]
if not zoomed and c ~= nil then
awful.tag.viewonly(zt[capi.mouse.screen], capi.mouse.screen)
awful.client.toggletag(zt[capi.mouse.screen], c)
zoomedClient = c
key_char_zoomed = key_char
zoomed = true
-- update the position of this hintbox, since it is zoomed
if type(delayed_call) == 'function' then
capi.awesome.emit_signal("refresh")
end
hintbox_pos(key_char)
hintbox_display_toggle(key_char, false)
elseif zoomedClient ~= nil then
awful.tag.history.restore(capi.mouse.screen)
awful.client.toggletag(zt[capi.mouse.screen], zoomedClient)
hintbox_display_toggle(key_char, true)
if type(delayed_call) == 'function' then
capi.awesome.emit_signal("refresh")
end
hintbox_pos(key_char_zoomed)
zoomedClient = nil
zoomed = false
end
end
if hintindex[key] then
--client.focus = hintindex[key]
--hintindex[key]:raise()
selectfn(restore,t, zt)(hintindex[key])
for i,j in pairs(hintindex) do
hintbox[i].visible = false
end
return false
end
if key == "Escape" then
if zoomedClient ~= nil then
awful.tag.history.restore(capi.mouse.screen)
awful.client.toggletag(zt[capi.mouse.screen], zoomedClient)
hintbox_display_toggle(string.lower(key), true)
if type(delayed_call) == 'function' then
capi.awesome.emit_signal("refresh")
end
hintbox_pos(key_char_zoomed)
zoomedClient = nil
zoomed = false
else
for i,j in pairs(hintindex) do
hintbox[i].visible = false
end
revelation.restore(t, zt)
return false
end
end
2015-09-26 03:38:54 +02:00
return true
end)
local pressedMiddle = false
2013-08-31 23:54:57 +02:00
capi.mousegrabber.run(function(mouse)
local c = awful.mouse.client_under_pointer()
local key_char = awful.util.table.hasitem(hintindex, c)
if mouse.buttons[1] == true then
2015-09-26 03:38:54 +02:00
selectfn(restore, t, zt)(c)
2013-08-31 23:54:57 +02:00
for i,j in pairs(hintindex) do
hintbox[i].visible = false
end
return false
2015-02-24 21:48:06 +01:00
elseif mouse.buttons[2] == true and pressedMiddle == false and c ~= nil then
-- is true whenever the button is down.
pressedMiddle = true
2013-08-31 23:54:57 +02:00
-- extra variable needed to prevent script from spam-closing windows
--
if zoomed == true and zoomedClient ~=nil then
awful.tag.history.restore(capi.mouse.screen)
awful.client.toggletag(zt[capi.mouse.screen], zoomedClient)
end
c:kill()
hintbox[key_char].visible = false
hintindex[key_char] = nil
if zoomed == true and zoomedClient ~=nil then
hintbox_display_toggle(key_char_zoomed, true)
zoomedClient = nil
zoomed = false
key_char_zoomed = nil
end
return true
elseif mouse.buttons[2] == false and pressedMiddle == true then
pressedMiddle = false
for key, _ in pairs(hintindex) do
hintbox_pos(key)
end
elseif mouse.buttons[3] == true then
2013-08-31 23:54:57 +02:00
if not zoomed and c ~= nil then
awful.tag.viewonly(zt[capi.mouse.screen], capi.mouse.screen)
awful.client.toggletag(zt[capi.mouse.screen], c)
if key_char ~= nil then
hintbox_display_toggle(key_char, false)
if type(delayed_call) == 'function' then
capi.awesome.emit_signal("refresh")
end
hintbox_pos(key_char)
end
2013-08-31 23:54:57 +02:00
zoomedClient = c
zoomed = true
key_char_zoomed = key_char
2013-08-31 23:54:57 +02:00
elseif zoomedClient ~= nil then
awful.tag.history.restore(capi.mouse.screen)
awful.client.toggletag(zt[capi.mouse.screen], zoomedClient)
hintbox_display_toggle(key_char_zoomed, true)
if type(delayed_call) == 'function' then
capi.awesome.emit_signal("refresh")
end
hintbox_pos(key_char_zoomed)
2013-08-31 23:54:57 +02:00
zoomedClient = nil
2015-02-24 21:48:06 +01:00
zoomed = false
2013-08-31 23:54:57 +02:00
end
end
return true
--Strange but on my machine only fleur worked as a string.
--stole it from
--https://github.com/Elv13/awesome-configs/blob/master/widgets/layout/desktopLayout.lua#L175
end,"fleur")
2011-08-23 23:37:11 +02:00
end
2013-08-31 23:54:57 +02:00
-- Create the wiboxes, but don't show them
--
function revelation.init(args)
2013-08-31 23:54:57 +02:00
local letterbox = {}
2015-08-21 02:24:01 +02:00
args = args or {}
revelation.tag_name = args.tag_name or revelation.tag_name
2015-02-24 21:48:06 +01:00
if args.match then
revelation.match.exact = args.match.exact or revelation.match.exact
revelation.match.any = args.match.any or revelation.match.any
end
2013-08-31 23:54:57 +02:00
for i = 1, #charorder do
local char = charorder:sub(i,i)
hintbox[char] = wibox({fg=beautiful.fg_normal, bg=beautiful.bg_focus, border_color=beautiful.border_focus, border_width=beautiful.border_width})
hintbox[char].ontop = true
2015-08-21 02:24:01 +02:00
hintbox[char].width = revelation.hintsize
hintbox[char].height = revelation.hintsize
2013-08-31 23:54:57 +02:00
letterbox[char] = wibox.widget.textbox()
letterbox[char]:set_markup(
"<span color=\"" .. revelation.fg .. "\"" .. ">" ..
char.upper(char) ..
"</span>"
)
letterbox[char]:set_font(revelation.font)
2013-08-31 23:54:57 +02:00
letterbox[char]:set_align("center")
hintbox[char]:set_widget(letterbox[char])
end
end
local function debuginfo( message )
mm = message
if not message then
mm = "false"
end
nid = naughty.notify({ text = tostring(mm), timeout = 10 })
end
2013-08-31 23:54:57 +02:00
setmetatable(revelation, { __call = function(_, ...) return revelation.expose(...) end })
return revelation