1 ---------------------------------------------------------------------------
2 -- @author Julien Danjou <julien@danjou.info>
3 -- @copyright 2009 Julien Danjou
4 -- @release @AWESOME_VERSION@
5 ---------------------------------------------------------------------------
7 -- Grab environment we need
15 local setmetatable
= setmetatable
22 --- Wibox module for awful.
23 -- This module allows you to easily create wibox and attach them to the edge of
27 -- Array of table with wiboxes inside.
28 -- It's an array so it is ordered.
31 --- Get a wibox position if it has been set, or return top.
32 -- @param wibox The wibox
33 -- @return The wibox position.
34 function get_position(wibox
)
35 for _
, wprop
in ipairs(wiboxes
) do
36 if wprop
.wibox
== wibox
then
43 --- Put a wibox on a screen at this position.
44 -- @param wibox The wibox to attach.
45 -- @param position The position: top, bottom left or right.
46 -- @param screen If the wibox it not attached to a screen, specified on which
47 -- screen the position should be set.
48 function set_position(wibox
, position
, screen
)
49 local screen
= screen
or wibox
.screen
or 1
50 local area
= capi
.screen
[screen
].geometry
52 -- The "length" of a wibox is always chosen to be the optimal size
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
59 elseif position
== "bottom" then
60 wibox
.y
= (area
.y
+ area
.height
) - (wibox
.height
+ 2 * wibox
.border_width
)
61 elseif position
== "top" then
65 for _
, wprop
in ipairs(wiboxes
) do
66 if wprop
.wibox
== wibox
then
67 wprop
.position
= position
73 -- Reset all wiboxes positions.
74 local function update_all_wiboxes_position()
75 for _
, wprop
in ipairs(wiboxes
) do
76 set_position(wprop
.wibox
, wprop
.position
)
80 local function call_wibox_position_hook_on_prop_update(w
)
81 update_all_wiboxes_position()
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
}
91 elseif wprop
.position
== "bottom" then
92 wibox
:struts
{ left
= 0, right
= 0, bottom
= wibox
.height
, top
= 0 }
93 elseif wprop
.position
== "left" then
94 wibox
:struts
{ left
= wibox
.width
, right
= 0, bottom
= 0, top
= 0 }
95 elseif wprop
.position
== "right" then
96 wibox
:struts
{ left
= 0, right
= wibox
.width
, bottom
= 0, top
= 0 }
103 --- Attach a wibox to a screen.
104 -- If a wibox is attached, it will be automatically be moved when other wiboxes
106 -- @param wibox The wibox to attach.
107 -- @param position The position of the wibox: top, bottom, left or right.
108 function attach(wibox
, position
)
109 -- Store wibox as attached in a weak-valued table
110 local wibox_prop_table
111 -- Start from end since we sometimes remove items
112 for i
= #wiboxes
, 1, -1 do
113 -- Since wiboxes are stored as weak value, they can disappear.
114 -- If they did, remove their entries
115 if wiboxes
[i
].wibox
== nil then
116 table.remove(wiboxes
, i
)
117 elseif wiboxes
[i
].wibox
== wibox
then
118 wibox_prop_table
= wiboxes
[i
]
119 -- We could break here, but well, let's check if there is no other
120 -- table with their wiboxes been garbage collected.
124 if not wibox_prop_table
then
125 table.insert(wiboxes
, setmetatable({ wibox
= wibox
, position
= position
}, { __mode
= 'v' }))
127 wibox_prop_table
.position
= position
130 wibox
:add_signal("property::width", wibox_update_strut
)
131 wibox
:add_signal("property::height", wibox_update_strut
)
132 wibox
:add_signal("property::visible", wibox_update_strut
)
134 wibox
:add_signal("property::screen", call_wibox_position_hook_on_prop_update
)
135 wibox
:add_signal("property::visible", call_wibox_position_hook_on_prop_update
)
136 wibox
:add_signal("property::border_width", call_wibox_position_hook_on_prop_update
)
140 -- @param wibox The wibox.
141 -- @param align The alignment: left, right or center.
142 -- @param screen If the wibox is not attached to any screen, you can specify the
143 -- screen where to align. Otherwise 1 is assumed.
144 function align(wibox
, align
, screen
)
145 local position
= get_position(wibox
)
146 local screen
= screen
or wibox
.screen
or 1
147 local area
= capi
.screen
[screen
].geometry
149 if position
== "right" then
150 if align
== "right" then
152 elseif align
== "left" then
153 wibox
.y
= area
.y
+ area
.height
- (wibox
.height
+ 2 * wibox
.border_width
)
154 elseif align
== "center" then
155 wibox
.y
= area
.y
+ (area
.height
- wibox
.height
) / 2
157 elseif position
== "left" then
158 if align
== "right" then
159 wibox
.y
= (area
.y
+ area
.height
) - (wibox
.height
+ 2 * wibox
.border_width
)
160 elseif align
== "left" then
162 elseif align
== "center" then
163 wibox
.y
= area
.y
+ (area
.height
- wibox
.height
) / 2
165 elseif position
== "bottom" then
166 if align
== "right" then
167 wibox
.x
= area
.x
+ area
.width
- (wibox
.width
+ 2 * wibox
.border_width
)
168 elseif align
== "left" then
170 elseif align
== "center" then
171 wibox
.x
= area
.x
+ (area
.width
- wibox
.width
) / 2
173 elseif position
== "top" then
174 if align
== "right" then
175 wibox
.x
= area
.x
+ area
.width
- (wibox
.width
+ 2 * wibox
.border_width
)
176 elseif align
== "left" then
178 elseif align
== "center" then
179 wibox
.x
= area
.x
+ (area
.width
- wibox
.width
) / 2
184 --- Stretch a wibox so it takes all screen width or height.
185 -- @param wibox The wibox.
186 -- @param screen The screen to stretch on, or the wibox screen.
187 function stretch(wibox
, screen
)
188 local screen
= screen
or wibox
.screen
190 local position
= get_position(wibox
)
191 local area
= capi
.screen
[screen
].workarea
192 if position
== "right" or position
== "left" then
193 wibox
.height
= area
.height
- (2 * wibox
.border_width
)
194 align(wibox
, "center")
196 wibox
.width
= area
.width
- (2 * wibox
.border_width
)
202 --- Create a new wibox and attach it to a screen edge.
204 -- @param args A table with standard arguments to wibox() creator.
205 -- You can add also position key with value top, bottom, left or right.
206 -- You can also use width or height in % and set align to center, right or left.
207 -- You can also set the screen key with a screen number to attach the wibox.
208 -- If not specified, 1 is assumed.
209 -- @return The wibox created.
211 local arg
= arg
or {}
212 local position
= arg
.position
or "top"
213 local has_to_stretch
= true
214 -- Empty position and align in arg so we are passing deprecation warning
217 if position
~= "top" and position
~="bottom"
218 and position
~= "left" and position
~= "right" then
219 error("Invalid position in awful.wibox(), you may only use"
220 .. " 'top', 'bottom', 'left' and 'right'")
224 if position
== "left" or position
== "right" then
225 arg
.width
= arg
.width
or capi
.awesome
.font_height
* 1.5
227 has_to_stretch
= false
229 local hp
= arg
.height
:match("(%d+)%%")
231 arg
.height
= capi
.screen
[arg
.screen
].geometry
.height
* hp
/ 100
236 arg
.height
= arg
.height
or capi
.awesome
.font_height
* 1.5
238 has_to_stretch
= false
240 local wp
= arg
.width
:match("(%d+)%%")
242 arg
.width
= capi
.screen
[arg
.screen
].geometry
.width
* wp
/ 100
248 local w
= capi
.wibox(arg
)
250 if position
== "left" then
251 w
.orientation
= "north"
252 elseif position
== "right" then
253 w
.orientation
= "south"
256 w
.screen
= arg
.screen
or 1
259 if has_to_stretch
then
265 set_position(w
, position
)
270 local function do_rounded_corners(width
, height
, corner
)
271 local img
= image
.argb32(width
, height
, nil)
273 -- The image starts completely black which is fully opaque for our use
275 local function transp_rect(x
, y
)
276 img
:draw_rectangle(x
, y
, corner
, corner
, true, "#ffffff")
278 local function opaque_circle(x
, y
)
279 -- x, y are the center of the circle
280 img
:draw_circle(x
, y
, corner
, corner
, true, "#000000")
284 -- First make a 'corner times corner' rectangle transparent
286 -- Then add the rounded corner
287 opaque_circle(corner
, corner
)
289 -- Upper right corner
290 transp_rect(width
- corner
, 0)
291 opaque_circle(width
- corner
- 1, corner
)
293 -- Bottom left corner
294 transp_rect(0, height
- corner
)
295 opaque_circle(corner
, height
- corner
- 1)
297 -- Bottom right corner
298 transp_rect(width
- corner
, height
- corner
)
299 opaque_circle(width
- corner
- 1, height
- corner
- 1)
304 --- Add rounded corners to a wibox
305 -- @param wibox The wibox.
306 -- @param corner_size The size in pixel of the rounded corners.
307 function rounded_corners(wibox
, corner_size
)
308 local border
= wibox
.border_width
310 -- Corners can't be larger than half the wibox' space
311 if wibox
.width
/ 2 < corner_size
then
312 corner_size
= wibox
.width
/ 2
314 if wibox
.height
/ 2 < corner_size
then
315 corner_size
= wibox
.height
/ 2
318 wibox
.shape_clip
= do_rounded_corners(wibox
.width
, wibox
.height
, corner_size
)
319 wibox
.shape_bounding
= do_rounded_corners(wibox
.width
+ border
* 2, wibox
.height
+ border
* 2, corner_size
+ border
)
322 local function update_wiboxes_on_struts(c
)
323 local struts
= c
:struts()
324 if struts
.left
~= 0 or struts
.right
~= 0
325 or struts
.top
~= 0 or struts
.bottom
~= 0 then
326 update_all_wiboxes_position()
330 -- Hook registered to reset all wiboxes position.
331 capi
.client
.add_signal("manage", function(c
)
332 update_wiboxes_on_struts(c
)
333 c
:add_signal("property::struts", update_wiboxes_on_struts
)
335 capi
.client
.add_signal("unmanage", update_wiboxes_on_struts
)
337 setmetatable(_M
, { __call
= function(_
, ...) return new(...) end })
339 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80