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")
20 local a_screen
= require("awful.screen")
22 --- Places client according to special criteria.
26 -- Check if an area intersect another area.
28 -- @param b The other area.
29 -- @return True if they intersect, false otherwise.
30 local function area_intersect_area(a
, b
)
31 return (b
.x
< a
.x
+ a
.width
32 and b
.x
+ b
.width
> a
.x
33 and b
.y
< a
.y
+ a
.height
34 and b
.y
+ b
.height
> a
.y
)
37 -- Get the intersect area between a and b.
39 -- @param b The other area.
40 -- @return The intersect area.
41 local function area_intersect_area_get(a
, b
)
43 g
.x
= math
.max(a
.x
, b
.x
)
44 g
.y
= math
.max(a
.y
, b
.y
)
45 g
.width
= math
.min(a
.x
+ a
.width
, b
.x
+ b
.width
) - g
.x
46 g
.height
= math
.min(a
.y
+ a
.height
, b
.y
+ b
.height
) - g
.y
50 -- Remove an area from a list, splitting the space between several area that
52 -- @param areas Table of areas.
53 -- @param elem Area to remove.
54 -- @return The new area list.
55 local function area_remove(areas
, elem
)
56 for i
= #areas
, 1, -1 do
57 -- Check if the 'elem' intersect
58 if area_intersect_area(areas
[i
], elem
) then
60 local r
= table.remove(areas
, i
)
61 local inter
= area_intersect_area_get(r
, elem
)
67 width
= inter
.x
- r
.x
,
77 height
= inter
.y
- r
.y
81 if inter
.x
+ inter
.width
< r
.x
+ r
.width
then
83 x
= inter
.x
+ inter
.width
,
85 width
= (r
.x
+ r
.width
) - (inter
.x
+ inter
.width
),
90 if inter
.y
+ inter
.height
< r
.y
+ r
.height
then
93 y
= inter
.y
+ inter
.height
,
95 height
= (r
.y
+ r
.height
) - (inter
.y
+ inter
.height
)
104 --- Place the client so no part of it will be outside the screen.
105 -- @param c The client.
106 -- @return The new client geometry.
107 function placement
.no_offscreen(c
)
108 local c
= c
or capi
.client
.focus
109 local geometry
= c
:geometry()
110 local screen
= c
.screen
or a_screen
.getbycoord(geometry
.x
, geometry
.y
)
111 local border
= c
.border_width
112 local screen_geometry
= capi
.screen
[screen
].workarea
114 if geometry
.x
+ geometry
.width
+ 2*border
> screen_geometry
.x
+ screen_geometry
.width
then
115 geometry
.x
= screen_geometry
.x
+ screen_geometry
.width
- geometry
.width
- 2*border
116 elseif geometry
.x
< screen_geometry
.x
then
117 geometry
.x
= screen_geometry
.x
120 if geometry
.y
+ geometry
.height
+ border
> screen_geometry
.y
+ screen_geometry
.height
then
121 geometry
.y
= screen_geometry
.y
+ screen_geometry
.height
- geometry
.height
- 2*border
122 elseif geometry
.y
< screen_geometry
.y
then
123 geometry
.y
= screen_geometry
.y
129 --- Place the client where there's place available with minimum overlap.
130 -- @param c The client.
131 function placement
.no_overlap(c
)
132 local geometry
= c
:geometry()
133 local screen
= c
.screen
or a_screen
.getbycoord(geometry
.x
, geometry
.y
)
134 local cls
= client
.visible(screen
)
135 local curlay
= layout
.get()
136 local areas
= { capi
.screen
[screen
].workarea
}
137 for i
, cl
in pairs(cls
) do
138 if cl
~= c
and cl
.type ~= "desktop" and (client
.floating
.get(cl
) or curlay
== layout
.suit
.floating
) then
139 areas
= area_remove(areas
, cl
:geometry())
143 -- Look for available space
145 local new
= { x
= geometry
.x
, y
= geometry
.y
, width
= 0, height
= 0 }
146 for i
, r
in ipairs(areas
) do
147 if r
.width
>= geometry
.width
148 and r
.height
>= geometry
.height
149 and r
.width
* r
.height
> new
.width
* new
.height
then
152 -- Check if the client's current position is available
153 -- and prefer that one (why move it around pointlessly?)
155 and geometry
.y
>= r
.y
156 and geometry
.x
+ geometry
.width
<= r
.x
+ r
.width
157 and geometry
.y
+ geometry
.height
<= r
.y
+ r
.height
then
164 -- We did not find an area with enough space for our size:
165 -- just take the biggest available one and go in
167 for i
, r
in ipairs(areas
) do
168 if r
.width
* r
.height
> new
.width
* new
.height
then
174 -- Restore height and width
175 new
.width
= geometry
.width
176 new
.height
= geometry
.height
178 return c
:geometry(new
)
181 --- Place the client under the mouse.
182 -- @param c The client.
183 -- @return The new client geometry.
184 function placement
.under_mouse(c
)
185 local c
= c
or capi
.client
.focus
186 local c_geometry
= c
:geometry()
187 local m_coords
= capi
.mouse
.coords()
188 return c
:geometry({ x
= m_coords
.x
- c_geometry
.width
/ 2,
189 y
= m_coords
.y
- c_geometry
.height
/ 2 })
192 --- Place the client centered with respect to a parent or the clients screen.
193 -- @param c The client.
194 -- @param p The parent (optional, nil for screen centering).
195 -- @return The new client geometry.
196 function placement
.centered(c
, p
)
197 local c
= c
or capi
.client
.focus
198 local c_geometry
= c
:geometry()
199 local screen
= c
.screen
or a_screen
.getbycoord(c_geometry
.x
, c_geometry
.y
)
202 s_geometry
= p
:geometry()
204 s_geometry
= capi
.screen
[screen
].geometry
206 return c
:geometry({ x
= s_geometry
.x
+ (s_geometry
.width
- c_geometry
.width
) / 2,
207 y
= s_geometry
.y
+ (s_geometry
.height
- c_geometry
.height
) / 2 })
210 --- Place the client centered on the horizontal axis with respect to a parent or the clients screen.
211 -- @param c The client.
212 -- @param p The parent (optional, nil for screen centering).
213 -- @return The new client geometry.
214 function placement
.center_horizontal(c
, p
)
215 local c
= c
or capi
.client
.focus
216 local c_geometry
= c
:geometry()
217 local screen
= c
.screen
or a_screen
.getbycoord(c_geometry
.x
, c_geometry
.y
)
220 s_geometry
= p
:geometry()
222 s_geometry
= capi
.screen
[screen
].geometry
224 return c
:geometry({ x
= s_geometry
.x
+ (s_geometry
.width
- c_geometry
.width
) / 2 })
227 --- Place the client centered on the vertical axis with respect to a parent or the clients screen.
228 -- @param c The client.
229 -- @param p The parent (optional, nil for screen centering).
230 -- @return The new client geometry.
231 function placement
.center_vertical(c
, p
)
232 local c
= c
or capi
.client
.focus
233 local c_geometry
= c
:geometry()
234 local screen
= c
.screen
or a_screen
.getbycoord(c_geometry
.x
, c_geometry
.y
)
237 s_geometry
= p
:geometry()
239 s_geometry
= capi
.screen
[screen
].geometry
241 return c
:geometry({ y
= s_geometry
.y
+ (s_geometry
.height
- c_geometry
.height
) / 2 })
246 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80