ewmh.activate: focus and especially raise clients during startup
[awesome.git] / lib / awful / placement.lua.in
blobd334f7fc3572de1ef09d068f6d2c2f557a7b170d
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")
20 local a_screen = require("awful.screen")
22 --- Places client according to special criteria.
23 -- awful.placement
24 local placement = {}
26 -- Check if an area intersect another area.
27 -- @param a The 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)
35 end
37 -- Get the intersect area between a and b.
38 -- @param a The area.
39 -- @param b The other area.
40 -- @return The intersect area.
41 local function area_intersect_area_get(a, b)
42 local g = {}
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
47 return g
48 end
50 -- Remove an area from a list, splitting the space between several area that
51 -- can overlap.
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
59 -- It does? remove it
60 local r = table.remove(areas, i)
61 local inter = area_intersect_area_get(r, elem)
63 if inter.x > r.x then
64 table.insert(areas, {
65 x = r.x,
66 y = r.y,
67 width = inter.x - r.x,
68 height = r.height
70 end
72 if inter.y > r.y then
73 table.insert(areas, {
74 x = r.x,
75 y = r.y,
76 width = r.width,
77 height = inter.y - r.y
79 end
81 if inter.x + inter.width < r.x + r.width then
82 table.insert(areas, {
83 x = inter.x + inter.width,
84 y = r.y,
85 width = (r.x + r.width) - (inter.x + inter.width),
86 height = r.height
88 end
90 if inter.y + inter.height < r.y + r.height then
91 table.insert(areas, {
92 x = r.x,
93 y = inter.y + inter.height,
94 width = r.width,
95 height = (r.y + r.height) - (inter.y + inter.height)
97 end
98 end
99 end
101 return areas
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
126 c:geometry(geometry)
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
144 local found = false
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
150 found = true
151 new = r
152 -- Check if the client's current position is available
153 -- and prefer that one (why move it around pointlessly?)
154 if geometry.x >= r.x
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
158 new.x = geometry.x
159 new.y = geometry.y
164 -- We did not find an area with enough space for our size:
165 -- just take the biggest available one and go in
166 if not found then
167 for i, r in ipairs(areas) do
168 if r.width * r.height > new.width * new.height then
169 new = r
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)
200 local s_geometry
201 if p then
202 s_geometry = p:geometry()
203 else
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)
218 local s_geometry
219 if p then
220 s_geometry = p:geometry()
221 else
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)
235 local s_geometry
236 if p then
237 s_geometry = p:geometry()
238 else
239 s_geometry = capi.screen[screen].geometry
241 return c:geometry({ y = s_geometry.y + (s_geometry.height - c_geometry.height) / 2 })
244 return placement
246 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80