2013-07-17 06:53:30 +02:00
|
|
|
local capi = { client = client , mouse = mouse ,
|
|
|
|
screen = screen , keygrabber = keygrabber,}
|
2013-06-03 23:22:41 +02:00
|
|
|
|
|
|
|
local setmetatable = setmetatable
|
2013-07-17 06:53:30 +02:00
|
|
|
local ipairs = ipairs
|
2016-02-09 06:10:11 +01:00
|
|
|
local surface = require( "gears.surface" )
|
|
|
|
local shape = require( "gears.shape" )
|
2014-10-16 07:20:41 +02:00
|
|
|
local util = require( "awful.util" )
|
|
|
|
local client = require( "awful.client" )
|
|
|
|
local tag = require( "awful.tag" )
|
|
|
|
local alayout = require( "awful.layout" )
|
|
|
|
local wibox = require( "wibox" )
|
|
|
|
local cairo = require( "lgi" ).cairo
|
|
|
|
local beautiful = require( "beautiful" )
|
|
|
|
local color = require( "gears.color" )
|
|
|
|
local col_utils = require( "collision.util" )
|
2013-06-03 23:22:41 +02:00
|
|
|
|
|
|
|
local module = {}
|
2014-05-08 07:53:57 +02:00
|
|
|
local wiboxes,delta = nil,100
|
2015-03-15 06:16:31 +01:00
|
|
|
local edge = nil
|
2013-06-03 23:22:41 +02:00
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
---------------- Visual -----------------------
|
2013-07-17 06:53:30 +02:00
|
|
|
local function init()
|
2014-05-13 05:35:45 +02:00
|
|
|
wiboxes = {}
|
|
|
|
for k,v in ipairs({"up","right","down","left","center"}) do
|
|
|
|
wiboxes[v] = wibox({})
|
|
|
|
wiboxes[v].height = 75
|
|
|
|
wiboxes[v].width = 75
|
|
|
|
wiboxes[v].ontop = true
|
|
|
|
if v ~= "center" then
|
|
|
|
local ib,m = wibox.widget.imagebox(),wibox.layout.margin()
|
2016-02-09 06:10:11 +01:00
|
|
|
|
|
|
|
ib:set_image(surface.load_from_shape(55, 55,
|
|
|
|
shape.transform(col_utils.arrow_path2)
|
|
|
|
: rotate_at(55/2, 55/2, (k-1)*(2*math.pi)/4),
|
|
|
|
beautiful.collision_fg_focus or beautiful.fg_normal or "#0000ff",
|
|
|
|
nil , 55, 55-20
|
|
|
|
))
|
|
|
|
|
2014-05-13 05:35:45 +02:00
|
|
|
m:set_margins(10)
|
|
|
|
m:set_widget(ib)
|
|
|
|
wiboxes[v]:set_widget(m)
|
2016-02-09 06:10:11 +01:00
|
|
|
surface.apply_shape_bounding(wiboxes[v], shape.rounded_rect, 10)
|
2013-06-03 23:22:41 +02:00
|
|
|
end
|
2014-05-13 05:35:45 +02:00
|
|
|
end
|
2016-01-08 07:51:37 +01:00
|
|
|
wiboxes["center"]:set_bg(beautiful.collision_bg_center or beautiful.bg_urgent or "#ff0000")
|
2016-02-09 06:10:11 +01:00
|
|
|
|
|
|
|
surface.apply_shape_bounding(wiboxes["center"], shape.rounded_rect, 37.5)
|
|
|
|
|
2013-06-03 23:22:41 +02:00
|
|
|
end
|
|
|
|
|
2015-03-15 04:17:18 +01:00
|
|
|
local function emulate_client(screen)
|
|
|
|
return {is_screen = true, screen=screen, geometry=function() return capi.screen[screen].workarea end}
|
|
|
|
end
|
|
|
|
|
2014-05-10 06:42:59 +02:00
|
|
|
local function display_wiboxes(cltbl,geomtbl,float,swap,c)
|
2014-05-13 05:35:45 +02:00
|
|
|
if not wiboxes then
|
|
|
|
init()
|
|
|
|
end
|
2015-03-15 04:17:18 +01:00
|
|
|
local fc = capi.client.focus or emulate_client(capi.mouse.screen)
|
2014-05-13 05:35:45 +02:00
|
|
|
for k,v in ipairs({"left","right","up","down","center"}) do
|
2015-03-15 04:17:18 +01:00
|
|
|
local next_clients = (float and swap) and c or cltbl[util.get_rectangle_in_direction(v , geomtbl, fc:geometry())]
|
2014-05-13 05:35:45 +02:00
|
|
|
if next_clients or k==5 then
|
2015-03-15 04:17:18 +01:00
|
|
|
local same, center = fc == next_clients,k==5
|
|
|
|
local geo = center and fc:geometry() or next_clients:geometry()
|
2014-05-13 05:35:45 +02:00
|
|
|
wiboxes[v].visible = true
|
2015-12-26 12:53:12 +01:00
|
|
|
wiboxes[v].x = math.floor((swap and float and (not center)) and (geo.x + (k>2 and (geo.width/2) or 0) + (k==2 and geo.width or 0) - 75/2) or (geo.x + geo.width/2 - 75/2))
|
|
|
|
wiboxes[v].y = math.floor((swap and float and (not center)) and (geo.y + (k<=2 and geo.height/2 or 0) + (k==4 and geo.height or 0) - 75/2) or (geo.y + geo.height/2 - 75/2))
|
2014-05-13 05:35:45 +02:00
|
|
|
else
|
|
|
|
wiboxes[v].visible = false
|
2014-05-08 07:53:57 +02:00
|
|
|
end
|
2014-05-13 05:35:45 +02:00
|
|
|
end
|
2014-05-08 07:53:57 +02:00
|
|
|
end
|
2013-06-03 23:22:41 +02:00
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
---------------- Position -----------------------
|
|
|
|
local function float_move(dir,c)
|
2014-05-13 05:35:45 +02:00
|
|
|
return ({left={x=c:geometry().x-delta},right={x=c:geometry().x+delta},up={y=c:geometry().y-delta},down={y=c:geometry().y+delta}})[dir]
|
2014-05-08 07:53:57 +02:00
|
|
|
end
|
2013-06-03 23:22:41 +02:00
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
local function float_move_max(dir,c)
|
2014-05-13 05:35:45 +02:00
|
|
|
return ({left={x=capi.screen[c.screen].workarea.x},right={x=capi.screen[c.screen].workarea.width+capi.screen[c.screen].workarea.x-c:geometry().width}
|
|
|
|
,up={y=capi.screen[c.screen].workarea.y},down={y=capi.screen[c.screen].workarea.y+capi.screen[c.screen].workarea.height-c:geometry().height}})[dir]
|
2014-05-08 07:53:57 +02:00
|
|
|
end
|
2013-06-03 23:22:41 +02:00
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
local function floating_clients()
|
2014-05-13 05:35:45 +02:00
|
|
|
local ret = {}
|
|
|
|
for v in util.table.iterate(client.visible(),function(c) return client.floating.get(c) end) do
|
|
|
|
ret[#ret+1] = v
|
|
|
|
end
|
|
|
|
return ret
|
2013-06-03 23:22:41 +02:00
|
|
|
end
|
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
local function bydirection(dir, c, swap,max)
|
2015-03-15 04:17:18 +01:00
|
|
|
if not c then
|
|
|
|
c = emulate_client(capi.mouse.screen)
|
|
|
|
end
|
|
|
|
|
|
|
|
local float = nil
|
|
|
|
|
|
|
|
if c.is_screen then
|
|
|
|
float = false
|
|
|
|
else
|
|
|
|
float = (client.floating.get(c) or alayout.get(c.screen) == alayout.suit.floating)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Move the client if floating, swaping wont work anyway
|
|
|
|
if swap and float then
|
|
|
|
c:geometry((max and float_move_max or float_move)(dir,c))
|
|
|
|
display_wiboxes(nil,nil,float,swap,c)
|
|
|
|
else
|
2015-03-15 06:16:31 +01:00
|
|
|
|
|
|
|
if not edge then
|
|
|
|
local scrs =col_utils.get_ordered_screens()
|
|
|
|
local last_geo =capi.screen[scrs[#scrs]].geometry
|
|
|
|
edge = last_geo.x + last_geo.width
|
|
|
|
end
|
|
|
|
|
2015-03-15 04:17:18 +01:00
|
|
|
-- Get all clients rectangle
|
2015-03-15 06:16:31 +01:00
|
|
|
local cltbl,geomtbl,scrs,roundr,roundl = max and floating_clients() or client.tiled(),{},{},{},{}
|
2015-03-15 04:17:18 +01:00
|
|
|
for i,cl in ipairs(cltbl) do
|
2015-03-15 06:16:31 +01:00
|
|
|
local geo = cl:geometry()
|
|
|
|
geomtbl[i] = geo
|
2015-03-15 04:17:18 +01:00
|
|
|
scrs[cl.screen or 1] = true
|
2015-03-15 06:16:31 +01:00
|
|
|
if geo.x == 0 then
|
|
|
|
roundr[#roundr+1] = cl
|
|
|
|
elseif geo.x + geo.width >= edge -2 then
|
|
|
|
roundl[#roundl+1] = cl
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--Add first client at the end to be able to rotate selection
|
|
|
|
for k,c in ipairs(roundr) do
|
|
|
|
local geo = c:geometry()
|
|
|
|
geomtbl[#geomtbl+1] = {x=edge,width=geo.width,y=geo.y,height=geo.height}
|
|
|
|
cltbl[#geomtbl] = c
|
|
|
|
end
|
|
|
|
for k,c in ipairs(roundl) do
|
|
|
|
local geo = c:geometry()
|
|
|
|
geomtbl[#geomtbl+1] = {x=-geo.width,width=geo.width,y=geo.y,height=geo.height}
|
|
|
|
cltbl[#geomtbl] = c
|
2015-03-15 04:17:18 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Add rectangles for empty screens too
|
|
|
|
for i = 1, capi.screen.count() do
|
|
|
|
if not scrs[i] then
|
|
|
|
geomtbl[#geomtbl+1] = capi.screen[i].workarea
|
|
|
|
cltbl[#geomtbl] = emulate_client(i)
|
2014-05-13 05:35:45 +02:00
|
|
|
end
|
2015-03-15 04:17:18 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
local target = util.get_rectangle_in_direction(dir, geomtbl, c:geometry())
|
|
|
|
if swap ~= true then
|
|
|
|
-- If we found a client to focus, then do it.
|
|
|
|
if target then
|
|
|
|
local cl = cltbl[target]
|
|
|
|
if cl and cl.is_screen then
|
|
|
|
capi.client.focus = nil --TODO Fix upstream fix
|
|
|
|
capi.mouse.screen = capi.screen[cl.screen]
|
|
|
|
else
|
2015-03-30 02:54:56 +02:00
|
|
|
local old_src = capi.client.focus and capi.client.focus.screen
|
2015-03-15 04:17:18 +01:00
|
|
|
capi.client.focus = cltbl[((not cl and #cltbl == 1) and 1 or target)]
|
2014-05-13 05:35:45 +02:00
|
|
|
capi.client.focus:raise()
|
2015-03-30 02:54:56 +02:00
|
|
|
if old_src and capi.client.focus.screen ~= old_src then
|
|
|
|
capi.mouse.coords(capi.client.focus:geometry())
|
|
|
|
end
|
2015-02-24 16:27:57 +01:00
|
|
|
end
|
2015-03-15 04:17:18 +01:00
|
|
|
end
|
|
|
|
else
|
|
|
|
if target then
|
|
|
|
-- We found a client to swap
|
|
|
|
local other = cltbl[((not cltbl[target] and #cltbl == 1) and 1 or target)]
|
|
|
|
if other.screen == c.screen or col_utils.settings.swap_across_screen then
|
|
|
|
--BUG swap doesn't work if the screen is not the same
|
|
|
|
c:swap(other)
|
2015-02-24 16:27:57 +01:00
|
|
|
else
|
2015-03-15 04:17:18 +01:00
|
|
|
local t = tag.selected(other.screen) --TODO get index
|
|
|
|
c.screen = other.screen
|
|
|
|
c:tags({t})
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- No client to swap, try to find a screen.
|
|
|
|
local screen_geom = {}
|
|
|
|
for i = 1, capi.screen.count() do
|
|
|
|
screen_geom[i] = capi.screen[i].workarea
|
2013-06-03 23:22:41 +02:00
|
|
|
end
|
2015-03-15 04:17:18 +01:00
|
|
|
target = util.get_rectangle_in_direction(dir, screen_geom, c:geometry())
|
|
|
|
if target and target ~= c.screen then
|
|
|
|
local t = tag.selected(target)
|
|
|
|
c.screen = target
|
|
|
|
c:tags({t})
|
|
|
|
c:raise()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if target then
|
|
|
|
-- Geometries have changed by swapping, so refresh.
|
|
|
|
cltbl,geomtbl = max and floating_clients() or client.tiled(),{}
|
|
|
|
for i,cl in ipairs(cltbl) do
|
|
|
|
geomtbl[i] = cl:geometry()
|
2015-02-24 16:28:20 +01:00
|
|
|
end
|
2014-05-13 05:35:45 +02:00
|
|
|
end
|
2013-06-03 23:22:41 +02:00
|
|
|
end
|
2015-03-15 04:17:18 +01:00
|
|
|
display_wiboxes(cltbl,geomtbl,float,swap,c)
|
2014-05-13 05:35:45 +02:00
|
|
|
end
|
2013-06-03 23:22:41 +02:00
|
|
|
end
|
2013-06-04 05:00:09 +02:00
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
function module.global_bydirection(dir, c,swap,max)
|
2014-05-13 05:35:45 +02:00
|
|
|
bydirection(dir, c or capi.client.focus, swap,max)
|
2014-05-08 05:51:28 +02:00
|
|
|
end
|
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
function module._global_bydirection_key(mod,key,event,direction,is_swap,is_max)
|
2014-05-13 05:35:45 +02:00
|
|
|
bydirection(direction,capi.client.focus,is_swap,is_max)
|
|
|
|
return true
|
2014-05-08 07:53:57 +02:00
|
|
|
end
|
2014-05-08 05:51:28 +02:00
|
|
|
|
2014-05-10 06:42:59 +02:00
|
|
|
function module.display(mod,key,event,direction,is_swap,is_max)
|
2014-05-13 05:35:45 +02:00
|
|
|
local c = capi.client.focus
|
|
|
|
local cltbl,geomtbl = max and floating_clients() or client.tiled(),{}
|
|
|
|
for i,cl in ipairs(cltbl) do
|
|
|
|
geomtbl[i] = cl:geometry()
|
|
|
|
end
|
2014-10-04 08:53:01 +02:00
|
|
|
|
|
|
|
-- Sometime, there is no focussed clients
|
|
|
|
if not c then
|
|
|
|
c = geomtbl[1] or cltbl[1]
|
|
|
|
end
|
|
|
|
|
|
|
|
-- If there is still no accessible clients, there is nothing to display
|
|
|
|
if not c then return end
|
|
|
|
|
2014-05-13 05:35:45 +02:00
|
|
|
display_wiboxes(cltbl,geomtbl,client.floating.get(c) or alayout.get(c.screen) == alayout.suit.floating,is_swap,c)
|
2014-05-10 06:42:59 +02:00
|
|
|
end
|
|
|
|
|
2014-05-08 07:53:57 +02:00
|
|
|
function module._quit()
|
2014-10-04 08:53:01 +02:00
|
|
|
if not wiboxes then return end
|
2014-05-13 05:35:45 +02:00
|
|
|
for k,v in ipairs({"left","right","up","down","center"}) do
|
|
|
|
wiboxes[v].visible = false
|
|
|
|
end
|
2013-06-04 05:00:09 +02:00
|
|
|
end
|
|
|
|
|
2014-05-13 05:35:45 +02:00
|
|
|
return setmetatable(module, { __call = function(_, ...) return new(...) end })
|
2016-03-28 11:03:55 +02:00
|
|
|
-- kate: space-indent on; indent-width 2; replace-tabs on;
|