awful.widget.layout: Remove
[awesome.git] / lib / awful / placement.lua.in
blob38f39e06c93b4a17f18b95316b49cb5edbfb1d99
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2008 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
8 local ipairs = ipairs
9 local pairs = pairs
10 local math = math
11 local table = table
12 local capi =
14 screen = screen,
15 mouse = mouse,
16 client = client
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.
25 -- @param a The 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)
33 end
35 -- Get the intersect area between a and b.
36 -- @param a The area.
37 -- @param b The other area.
38 -- @return The intersect area.
39 local function area_intersect_area_get(a, b)
40 local g = {}
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
45 return g
46 end
48 -- Remove an area from a list, splitting the space between several area that
49 -- can overlap.
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
57 -- It does? remove it
58 local r = table.remove(areas, i)
59 local inter = area_intersect_area_get(r, elem)
61 if inter.x > r.x then
62 table.insert(areas, {
63 x = r.x,
64 y = r.y,
65 width = inter.x - r.x,
66 height = r.height
68 end
70 if inter.y > r.y then
71 table.insert(areas, {
72 x = r.x,
73 y = r.y,
74 width = r.width,
75 height = inter.y - r.y
77 end
79 if inter.x + inter.width < r.x + r.width then
80 table.insert(areas, {
81 x = inter.x + inter.width,
82 y = r.y,
83 width = (r.x + r.width) - (inter.x + inter.width),
84 height = r.height
86 end
88 if inter.y + inter.height < r.y + r.height then
89 table.insert(areas, {
90 x = r.x,
91 y = inter.y + inter.height,
92 width = r.width,
93 height = (r.y + r.height) - (inter.y + inter.height)
95 end
96 end
97 end
99 return areas
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
123 c:geometry(geometry)
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
140 local found = false
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
146 found = true
147 new = r
151 -- We did not foudn an area with enough space for our size:
152 -- just take the biggest available one and go in
153 if not found then
154 for i, r in ipairs(areas) do
155 if r.width * r.height > new.width * new.height then
156 new = r
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()
186 local s_geometry
187 if p then
188 s_geometry = p:geometry()
189 else
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()
203 local s_geometry
204 if p then
205 s_geometry = p:geometry()
206 else
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()
219 local s_geometry
220 if p then
221 s_geometry = p:geometry()
222 else
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