ewmh.activate: focus and especially raise clients during startup
[awesome.git] / lib / awful / wibox.lua.in
blobf48ece3bc1e96aaa5b9c72203f3254ee5d1d55fe
1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2009 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
8 local capi =
10 awesome = awesome,
11 screen = screen,
12 client = client
14 local setmetatable = setmetatable
15 local tostring = tostring
16 local ipairs = ipairs
17 local table = table
18 local error = error
19 local wibox = require("wibox")
20 local beautiful = require("beautiful")
22 --- Wibox module for awful.
23 -- This module allows you to easily create wibox and attach them to the edge of
24 -- a screen.
25 -- awful.wibox
26 local awfulwibox = { mt = {} }
28 -- Array of table with wiboxes inside.
29 -- It's an array so it is ordered.
30 local wiboxes = {}
32 --- Get a wibox position if it has been set, or return top.
33 -- @param wibox The wibox
34 -- @return The wibox position.
35 function awfulwibox.get_position(wibox)
36 for _, wprop in ipairs(wiboxes) do
37 if wprop.wibox == wibox then
38 return wprop.position
39 end
40 end
41 return "top"
42 end
44 --- Put a wibox on a screen at this position.
45 -- @param wibox The wibox to attach.
46 -- @param position The position: top, bottom left or right.
47 -- @param screen If the wibox it not attached to a screen, specified on which
48 -- screen the position should be set.
49 function awfulwibox.set_position(wibox, position, screen)
50 local area = capi.screen[screen].geometry
52 -- The "length" of a wibox is always chosen to be the optimal size
53 -- (non-floating).
54 -- The "width" of a wibox is kept if it exists.
55 if position == "right" then
56 wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
57 elseif position == "left" then
58 wibox.x = area.x
59 elseif position == "bottom" then
60 wibox.y = (area.y + area.height) - (wibox.height + 2 * wibox.border_width)
61 elseif position == "top" then
62 wibox.y = area.y
63 end
65 for _, wprop in ipairs(wiboxes) do
66 if wprop.wibox == wibox then
67 wprop.position = position
68 break
69 end
70 end
71 end
73 -- Reset all wiboxes positions.
74 local function update_all_wiboxes_position()
75 for _, wprop in ipairs(wiboxes) do
76 awfulwibox.set_position(wprop.wibox, wprop.position, wprop.screen)
77 end
78 end
80 local function call_wibox_position_hook_on_prop_update(w)
81 update_all_wiboxes_position()
82 end
84 local function wibox_update_strut(wibox)
85 for _, wprop in ipairs(wiboxes) do
86 if wprop.wibox == wibox then
87 if not wibox.visible then
88 wibox:struts { left = 0, right = 0, bottom = 0, top = 0 }
89 elseif wprop.position == "top" then
90 wibox:struts { left = 0, right = 0, bottom = 0, top = wibox.height + 2 * wibox.border_width }
91 elseif wprop.position == "bottom" then
92 wibox:struts { left = 0, right = 0, bottom = wibox.height + 2 * wibox.border_width, top = 0 }
93 elseif wprop.position == "left" then
94 wibox:struts { left = wibox.width + 2 * wibox.border_width, right = 0, bottom = 0, top = 0 }
95 elseif wprop.position == "right" then
96 wibox:struts { left = 0, right = wibox.width + 2 * wibox.border_width, bottom = 0, top = 0 }
97 end
98 break
99 end
103 --- Attach a wibox to a screen.
104 -- If a wibox is attached, it will be automatically be moved when other wiboxes
105 -- will be attached.
106 -- @param wibox The wibox to attach.
107 -- @param position The position of the wibox: top, bottom, left or right.
108 -- @param screen TODO, this seems to be unused
109 function awfulwibox.attach(wibox, position, screen)
110 -- Store wibox as attached in a weak-valued table
111 local wibox_prop_table
112 -- Start from end since we sometimes remove items
113 for i = #wiboxes, 1, -1 do
114 -- Since wiboxes are stored as weak value, they can disappear.
115 -- If they did, remove their entries
116 if wiboxes[i].wibox == nil then
117 table.remove(wiboxes, i)
118 elseif wiboxes[i].wibox == wibox then
119 wibox_prop_table = wiboxes[i]
120 -- We could break here, but well, let's check if there is no other
121 -- table with their wiboxes been garbage collected.
125 if not wibox_prop_table then
126 table.insert(wiboxes, setmetatable({ wibox = wibox, position = position, screen = screen }, { __mode = 'v' }))
127 else
128 wibox_prop_table.position = position
131 wibox:connect_signal("property::width", wibox_update_strut)
132 wibox:connect_signal("property::height", wibox_update_strut)
133 wibox:connect_signal("property::visible", wibox_update_strut)
135 wibox:connect_signal("property::width", call_wibox_position_hook_on_prop_update)
136 wibox:connect_signal("property::height", call_wibox_position_hook_on_prop_update)
137 wibox:connect_signal("property::visible", call_wibox_position_hook_on_prop_update)
138 wibox:connect_signal("property::border_width", call_wibox_position_hook_on_prop_update)
141 --- Align a wibox.
142 -- @param wibox The wibox.
143 -- @param align The alignment: left, right or center.
144 -- @param screen If the wibox is not attached to any screen, you can specify the
145 -- screen where to align. Otherwise 1 is assumed.
146 function awfulwibox.align(wibox, align, screen)
147 local position = awfulwibox.get_position(wibox)
148 local area = capi.screen[screen].workarea
150 if position == "right" then
151 if align == "right" then
152 wibox.y = area.y
153 elseif align == "left" then
154 wibox.y = area.y + area.height - (wibox.height + 2 * wibox.border_width)
155 elseif align == "center" then
156 wibox.y = area.y + (area.height - wibox.height) / 2
158 elseif position == "left" then
159 if align == "right" then
160 wibox.y = (area.y + area.height) - (wibox.height + 2 * wibox.border_width)
161 elseif align == "left" then
162 wibox.y = area.y
163 elseif align == "center" then
164 wibox.y = area.y + (area.height - wibox.height) / 2
166 elseif position == "bottom" then
167 if align == "right" then
168 wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
169 elseif align == "left" then
170 wibox.x = area.x
171 elseif align == "center" then
172 wibox.x = area.x + (area.width - wibox.width) / 2
174 elseif position == "top" then
175 if align == "right" then
176 wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
177 elseif align == "left" then
178 wibox.x = area.x
179 elseif align == "center" then
180 wibox.x = area.x + (area.width - wibox.width) / 2
184 -- Update struts regardless of changes
185 wibox_update_strut(wibox)
188 --- Stretch a wibox so it takes all screen width or height.
189 -- @param wibox The wibox.
190 -- @param screen The screen to stretch on, or the wibox screen.
191 function awfulwibox.stretch(wibox, screen)
192 if screen then
193 local position = awfulwibox.get_position(wibox)
194 local area = capi.screen[screen].workarea
195 if position == "right" or position == "left" then
196 wibox.height = area.height - (2 * wibox.border_width)
197 wibox.y = area.y
198 else
199 wibox.width = area.width - (2 * wibox.border_width)
200 wibox.x = area.x
205 --- Create a new wibox and attach it to a screen edge.
206 -- @see wibox
207 -- @param arg A table with standard arguments to wibox() creator.
208 -- You can add also position key with value top, bottom, left or right.
209 -- You can also use width or height in % and set align to center, right or left.
210 -- You can also set the screen key with a screen number to attach the wibox.
211 -- If not specified, 1 is assumed.
212 -- @return The wibox created.
213 function awfulwibox.new(arg)
214 local arg = arg or {}
215 local position = arg.position or "top"
216 local has_to_stretch = true
217 local screen = arg.screen or 1
219 arg.type = arg.type or "dock"
221 if position ~= "top" and position ~="bottom"
222 and position ~= "left" and position ~= "right" then
223 error("Invalid position in awful.wibox(), you may only use"
224 .. " 'top', 'bottom', 'left' and 'right'")
227 -- Set default size
228 if position == "left" or position == "right" then
229 arg.width = arg.width or beautiful.get_font_height(arg.font) * 1.5
230 if arg.height then
231 has_to_stretch = false
232 if arg.screen then
233 local hp = tostring(arg.height):match("(%d+)%%")
234 if hp then
235 arg.height = capi.screen[arg.screen].geometry.height * hp / 100
239 else
240 arg.height = arg.height or beautiful.get_font_height(arg.font) * 1.5
241 if arg.width then
242 has_to_stretch = false
243 if arg.screen then
244 local wp = tostring(arg.width):match("(%d+)%%")
245 if wp then
246 arg.width = capi.screen[arg.screen].geometry.width * wp / 100
252 local w = wibox(arg)
254 w.visible = true
256 awfulwibox.attach(w, position, screen)
257 if has_to_stretch then
258 awfulwibox.stretch(w, screen)
259 else
260 awfulwibox.align(w, arg.align, screen)
263 awfulwibox.set_position(w, position, screen)
265 return w
268 local function update_wiboxes_on_struts(c)
269 local struts = c:struts()
270 if struts.left ~= 0 or struts.right ~= 0
271 or struts.top ~= 0 or struts.bottom ~= 0 then
272 update_all_wiboxes_position()
276 -- Hook registered to reset all wiboxes position.
277 capi.client.connect_signal("property::struts", update_wiboxes_on_struts)
278 capi.client.connect_signal("unmanage", update_wiboxes_on_struts)
280 function awfulwibox.mt:__call(...)
281 return awfulwibox.new(...)
284 return setmetatable(awfulwibox, awfulwibox.mt)
286 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80