Functions to change client focus by direction across screens
Added functions awful.client.focus.global_bydirection and awful.client.swap.global_bydirection, that change focus and swap clients, crossing screen boundaries. Also modified awful.client.movetoscreen. Now calls awful.screen.focus. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
d799ac76aa
commit
0e2960ebf3
|
@ -252,95 +252,54 @@ function client.next(i, c)
|
||||||
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 = client.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.
|
--- Focus a client by the given direction.
|
||||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||||
-- @param c Optional client.
|
-- @param c Optional client.
|
||||||
function client.focus.bydirection(dir, c)
|
function client.focus.bydirection(dir, c)
|
||||||
local sel = c or capi.client.focus
|
local sel = c or capi.client.focus
|
||||||
if sel then
|
if sel then
|
||||||
local target = get_client_in_direction(dir, sel)
|
local cltbl = client.visible(sel.screen)
|
||||||
|
local geomtbl = {}
|
||||||
|
for i,cl in ipairs(cltbl) do
|
||||||
|
geomtbl[i] = cl:geometry()
|
||||||
|
end
|
||||||
|
|
||||||
|
local target = util.get_rectangle_in_direction(dir, geomtbl, sel:geometry())
|
||||||
|
|
||||||
-- If we found a client to focus, then do it.
|
-- If we found a client to focus, then do it.
|
||||||
if target then
|
if target then
|
||||||
capi.client.focus = target
|
capi.client.focus = cltbl[target]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Focus a client by the given direction. Moves across screens.
|
||||||
|
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||||
|
-- @param c Optional client.
|
||||||
|
function client.focus.global_bydirection(dir, c)
|
||||||
|
local sel = c or capi.client.focus
|
||||||
|
local scr = capi.mouse.screen
|
||||||
|
if sel then
|
||||||
|
scr = sel.screen
|
||||||
|
end
|
||||||
|
|
||||||
|
-- change focus inside the screen
|
||||||
|
client.focus.bydirection(dir, sel)
|
||||||
|
|
||||||
|
-- if focus not changed, we must change screen
|
||||||
|
if sel == capi.client.focus then
|
||||||
|
awful.screen.focus_bydirection(dir, scr)
|
||||||
|
if scr ~= capi.mouse.screen then
|
||||||
|
local cltbl = client.visible(capi.mouse.screen)
|
||||||
|
local geomtbl = {}
|
||||||
|
for i,cl in ipairs(cltbl) do
|
||||||
|
geomtbl[i] = cl:geometry()
|
||||||
|
end
|
||||||
|
local target = util.get_rectangle_in_direction(dir, geomtbl, capi.screen[scr].geometry)
|
||||||
|
|
||||||
|
if target then
|
||||||
|
capi.client.focus = cltbl[target]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -361,15 +320,54 @@ end
|
||||||
function client.swap.bydirection(dir, c)
|
function client.swap.bydirection(dir, c)
|
||||||
local sel = c or capi.client.focus
|
local sel = c or capi.client.focus
|
||||||
if sel then
|
if sel then
|
||||||
local target = get_client_in_direction(dir, sel)
|
local cltbl = client.visible(sel.screen)
|
||||||
|
local geomtbl = {}
|
||||||
|
for i,cl in ipairs(cltbl) do
|
||||||
|
geomtbl[i] = cl:geometry()
|
||||||
|
end
|
||||||
|
local target = util.get_rectangle_in_direction(dir, geomtbl, sel:geometry())
|
||||||
|
|
||||||
-- If we found a client to swap with, then go for it
|
-- If we found a client to swap with, then go for it
|
||||||
if target then
|
if target then
|
||||||
target:swap(sel)
|
cltbl[target]:swap(sel)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Swap a client with another client in the given direction. Swaps across screens.
|
||||||
|
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||||
|
-- @param c Optional client.
|
||||||
|
function client.swap.global_bydirection(dir, c)
|
||||||
|
local sel = c or capi.client.focus
|
||||||
|
local screen = capi.mouse.screen
|
||||||
|
if sel then
|
||||||
|
screen = sel.screen
|
||||||
|
end
|
||||||
|
|
||||||
|
if sel then
|
||||||
|
-- move focus
|
||||||
|
client.focus.global_bydirection(dir, sel)
|
||||||
|
local c = capi.client.focus
|
||||||
|
|
||||||
|
-- swapping inside a screen
|
||||||
|
if sel.screen == c.screen and sel ~= c then
|
||||||
|
c:swap(sel)
|
||||||
|
|
||||||
|
-- swapping to an empty screen
|
||||||
|
elseif sel.screen ~= c.screen and sel == c then
|
||||||
|
awful.client.movetoscreen(sel, capi.mouse.screen)
|
||||||
|
|
||||||
|
--swapping to a nonempty screen
|
||||||
|
elseif sel.screen ~= c.screen and sel ~= c then
|
||||||
|
awful.client.movetoscreen(sel, c.screen)
|
||||||
|
awful.client.movetoscreen(c, screen)
|
||||||
|
end
|
||||||
|
|
||||||
|
awful.screen.focus(sel.screen)
|
||||||
|
capi.client.focus = sel
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Swap a client by its relative index.
|
--- Swap a client by its relative index.
|
||||||
-- @param i The index.
|
-- @param i The index.
|
||||||
-- @param c Optional client, otherwise focused one is used.
|
-- @param c Optional client, otherwise focused one is used.
|
||||||
|
@ -494,7 +492,7 @@ function client.movetoscreen(c, s)
|
||||||
end
|
end
|
||||||
if s > sc then s = 1 elseif s < 1 then s = sc end
|
if s > sc then s = 1 elseif s < 1 then s = sc end
|
||||||
sel.screen = s
|
sel.screen = s
|
||||||
capi.mouse.coords(capi.screen[s].geometry)
|
awful.screen.focus(s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue