1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
18 local client
= require("awful.client")
19 local layout
= require("awful.layout")
21 --- Places client according to special criteria.
22 module("awful.placement")
24 -- Check if an area intersect another area.
26 -- @param b The other area.
27 -- @return True if they intersect, false otherwise.
28 local function area_intersect_area(a
, b
)
29 return (b
.x
< a
.x
+ a
.width
30 and b
.x
+ b
.width
> a
.x
31 and b
.y
< a
.y
+ a
.height
32 and b
.y
+ b
.height
> a
.y
)
35 -- Get the intersect area between a and b.
37 -- @param b The other area.
38 -- @return The intersect area.
39 local function area_intersect_area_get(a
, b
)
41 g
.x
= math
.max(a
.x
, b
.x
)
42 g
.y
= math
.max(a
.y
, b
.y
)
43 g
.width
= math
.min(a
.x
+ a
.width
, b
.x
+ b
.width
) - g
.x
44 g
.height
= math
.min(a
.y
+ a
.height
, b
.y
+ b
.height
) - g
.y
48 -- Remove an area from a list, splitting the space between several area that
50 -- @param areas Table of areas.
51 -- @param elem Area to remove.
52 -- @return The new area list.
53 local function area_remove(areas
, elem
)
54 for i
= #areas
, 1, -1 do
55 -- Check if the 'elem' intersect
56 if area_intersect_area(areas
[i
], elem
) then
58 local r
= table.remove(areas
, i
)
59 local inter
= area_intersect_area_get(r
, elem
)
65 width
= inter
.x
- r
.x
,
75 height
= inter
.y
- r
.y
79 if inter
.x
+ inter
.width
< r
.x
+ r
.width
then
81 x
= inter
.x
+ inter
.width
,
83 width
= (r
.x
+ r
.width
) - (inter
.x
+ inter
.width
),
88 if inter
.y
+ inter
.height
< r
.y
+ r
.height
then
91 y
= inter
.y
+ inter
.height
,
93 height
= (r
.y
+ r
.height
) - (inter
.y
+ inter
.height
)
102 --- Place the client so no part of it will be outside the screen.
103 -- @param c The client.
104 -- @return The new client geometry.
105 function no_offscreen(c
)
106 local c
= c
or capi
.client
.focus
107 local geometry
= c
:geometry()
108 local border
= c
.border_width
109 local screen_geometry
= capi
.screen
[c
.screen
].workarea
111 if geometry
.x
+ geometry
.width
+ 2*border
> screen_geometry
.x
+ screen_geometry
.width
then
112 geometry
.x
= screen_geometry
.x
+ screen_geometry
.width
- geometry
.width
113 elseif geometry
.x
< screen_geometry
.x
then
114 geometry
.x
= screen_geometry
.x
117 if geometry
.y
+ geometry
.height
+ border
> screen_geometry
.y
+ screen_geometry
.height
then
118 geometry
.y
= screen_geometry
.y
+ screen_geometry
.height
- geometry
.height
119 elseif geometry
.y
< screen_geometry
.y
then
120 geometry
.y
= screen_geometry
.y
126 --- Place the client where there's place available with minimum overlap.
127 -- @param c The client.
128 function no_overlap(c
)
129 local cls
= client
.visible(c
.screen
)
130 local curlay
= layout
.get()
131 local areas
= { capi
.screen
[c
.screen
].workarea
}
132 local geometry
= c
:geometry()
133 for i
, cl
in pairs(cls
) do
134 if cl
~= c
and cl
.type ~= "desktop" and (client
.floating
.get(cl
) or curlay
== layout
.suit
.floating
) then
135 areas
= area_remove(areas
, cl
:geometry())
139 -- Look for available space
141 local new
= { x
= geometry
.x
, y
= geometry
.y
, width
= 0, height
= 0 }
142 for i
, r
in ipairs(areas
) do
143 if r
.width
>= geometry
.width
144 and r
.height
>= geometry
.height
145 and r
.width
* r
.height
> new
.width
* new
.height
then
151 -- We did not foudn an area with enough space for our size:
152 -- just take the biggest available one and go in
154 for i
, r
in ipairs(areas
) do
155 if r
.width
* r
.height
> new
.width
* new
.height
then
161 -- Restore height and width
162 new
.width
= geometry
.width
163 new
.height
= geometry
.height
165 return c
:geometry(new
)
168 --- Place the client under the mouse.
169 -- @param c The client.
170 -- @return The new client geometry.
171 function under_mouse(c
)
172 local c
= c
or capi
.client
.focus
173 local c_geometry
= c
:geometry()
174 local m_coords
= capi
.mouse
.coords()
175 return c
:geometry({ x
= m_coords
.x
- c_geometry
.width
/ 2,
176 y
= m_coords
.y
- c_geometry
.height
/ 2 })
179 --- Place the client centered with respect to a parent or the clients screen.
180 -- @param c The client.
181 -- @param p The parent (optional, nil for screen centering).
182 -- @return The new client geometry.
183 function centered(c
, p
)
184 local c
= c
or capi
.client
.focus
185 local c_geometry
= c
:geometry()
188 s_geometry
= p
:geometry()
190 s_geometry
= capi
.screen
[c
.screen
].geometry
192 return c
:geometry({ x
= s_geometry
.x
+ (s_geometry
.width
- c_geometry
.width
) / 2,
193 y
= s_geometry
.y
+ (s_geometry
.height
- c_geometry
.height
) / 2 })
196 --- Place the client centered on the horizontal axis with respect to a parent or the clients screen.
197 -- @param c The client.
198 -- @param p The parent (optional, nil for screen centering).
199 -- @return The new client geometry.
200 function center_horizontal(c
, p
)
201 local c
= c
or capi
.client
.focus
202 local c_geometry
= c
:geometry()
205 s_geometry
= p
:geometry()
207 s_geometry
= capi
.screen
[c
.screen
].geometry
209 return c
:geometry({ x
= s_geometry
.x
+ (s_geometry
.width
- c_geometry
.width
) / 2 })
212 --- Place the client centered on the vertical axis with respect to a parent or the clients screen.
213 -- @param c The client.
214 -- @param p The parent (optional, nil for screen centering).
215 -- @return The new client geometry.
216 function center_vertical(c
, p
)
217 local c
= c
or capi
.client
.focus
218 local c_geometry
= c
:geometry()
221 s_geometry
= p
:geometry()
223 s_geometry
= capi
.screen
[c
.screen
].geometry
225 return c
:geometry({ y
= s_geometry
.y
+ (s_geometry
.height
- c_geometry
.height
) / 2 })
229 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80