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
21 --- Wibox module for awful.
24 -- Array of table with wiboxes inside.
25 -- It's an array so it is ordered.
28 --- Get a wibox position if it has been set, or return top.
29 -- @param wibox The wibox
30 -- @return The wibox position.
31 function get_position(wibox
)
32 for _
, wprop
in ipairs(wiboxes
) do
33 if wprop
.wibox
== wibox
then
40 --- Put a wibox on a screen at this position.
41 -- @param wibox The wibox to attach.
42 -- @param position The position: top, bottom left or right.
43 -- @param screen If the wibox it not attached to a screen, specified on which
44 -- screen the position should be set.
45 function set_position(wibox
, position
, screen
)
46 local screen
= screen
or wibox
.screen
or 1
47 local area
= capi
.screen
[screen
].geometry
49 -- The "length" of a wibox is always chosen to be the optimal size
51 -- The "width" of a wibox is kept if it exists.
52 if position
== "right" then
53 wibox
.x
= area
.x
+ area
.width
- (wibox
.width
+ 2 * wibox
.border_width
)
54 elseif position
== "left" then
56 elseif position
== "bottom" then
57 wibox
.y
= (area
.y
+ area
.height
) - (wibox
.height
+ 2 * wibox
.border_width
)
58 elseif position
== "top" then
62 for _
, wprop
in ipairs(wiboxes
) do
63 if wprop
.wibox
== wibox
then
64 wprop
.position
= position
70 -- Reset all wiboxes positions.
71 local function update_all_wiboxes_position()
72 for _
, wprop
in ipairs(wiboxes
) do
73 set_position(wprop
.wibox
, wprop
.position
)
77 local function call_wibox_position_hook_on_prop_update(w
)
78 update_all_wiboxes_position()
81 local function wibox_update_strut(wibox
)
82 for _
, wprop
in ipairs(wiboxes
) do
83 if wprop
.wibox
== wibox
then
84 if wprop
.position
== "top" then
85 wibox
:struts
{ left
= 0, right
= 0, bottom
= 0, top
= wibox
.height
}
86 elseif wprop
.position
== "bottom" then
87 wibox
:struts
{ left
= 0, right
= 0, bottom
= wibox
.height
, top
= 0 }
88 elseif wprop
.position
== "left" then
89 wibox
:struts
{ left
= wibox
.width
, right
= 0, bottom
= 0, top
= 0 }
90 elseif wprop
.position
== "right" then
91 wibox
:struts
{ left
= 0, right
= wibox
.width
, bottom
= 0, top
= 0 }
97 --- Attach a wibox to a screen.
98 -- If a wibox is attached, it will be automatically be moved when other wiboxes
100 -- @param wibox The wibox to attach.
101 -- @param position The position of the wibox: top, bottom, left or right.
102 function attach(wibox
, position
)
103 -- Store wibox as attached in a weak-valued table
104 local wibox_prop_table
105 -- Start from end since we sometimes remove items
106 for i
= #wiboxes
, 1, -1 do
107 -- Since wiboxes are stored as weak value, they can disappear.
108 -- If they did, remove their entries
109 if wiboxes
[i
].wibox
== nil then
110 table.remove(wiboxes
, i
)
111 elseif wiboxes
[i
].wibox
== wibox
then
112 wibox_prop_table
= wiboxes
[i
]
113 -- We could break here, but well, let's check if there is no other
114 -- table with their wiboxes been garbage collected.
118 if not wibox_prop_table
then
119 table.insert(wiboxes
, setmetatable({ wibox
= wibox
, position
= position
}, { __mode
= 'v' }))
121 wibox_prop_table
.position
= position
124 wibox
:add_signal("property::width", wibox_update_strut
)
125 wibox
:add_signal("property::height", wibox_update_strut
)
127 wibox
:add_signal("property::screen", call_wibox_position_hook_on_prop_update
)
128 wibox
:add_signal("property::visible", call_wibox_position_hook_on_prop_update
)
129 wibox
:add_signal("property::border_width", call_wibox_position_hook_on_prop_update
)
133 -- @param wibox The wibox.
134 -- @param align The alignment: left, right or center.
135 -- @param screen If the wibox is not attached to any screen, you can specify the
136 -- screen where to align. Otherwise 1 is assumed.
137 function align(wibox
, align
, screen
)
138 local position
= get_position(wibox
)
139 local screen
= screen
or wibox
.screen
or 1
140 local area
= capi
.screen
[screen
].geometry
142 if position
== "right" then
143 if align
== "right" then
145 elseif align
== "left" then
146 wibox
.y
= area
.y
+ area
.height
- (wibox
.height
+ 2 * wibox
.border_width
)
147 elseif align
== "center" then
148 wibox
.y
= area
.y
+ (area
.height
- wibox
.height
) / 2
150 elseif position
== "left" then
151 if align
== "right" then
152 wibox
.y
= (area
.y
+ area
.height
) - (wibox
.height
+ 2 * wibox
.border_width
)
153 elseif align
== "left" then
155 elseif align
== "center" then
156 wibox
.y
= area
.y
+ (area
.height
- wibox
.height
) / 2
158 elseif position
== "bottom" then
159 if align
== "right" then
160 wibox
.x
= area
.x
+ area
.width
- (wibox
.width
+ 2 * wibox
.border_width
)
161 elseif align
== "left" then
163 elseif align
== "center" then
164 wibox
.x
= area
.x
+ (area
.width
- wibox
.width
) / 2
166 elseif position
== "top" then
167 if align
== "right" then
168 wibox
.x
= area
.x
+ area
.width
- (wibox
.width
+ 2 * wibox
.border_width
)
169 elseif align
== "left" then
171 elseif align
== "center" then
172 wibox
.x
= area
.x
+ (area
.width
- wibox
.width
) / 2
177 --- Stretch a wibox so it takes all screen width or height.
178 -- @param wibox The wibox.
179 -- @param screen The screen to stretch on, or the wibox screen.
180 function stretch(wibox
, screen
)
181 local screen
= screen
or wibox
.screen
183 local position
= get_position(wibox
)
184 local area
= capi
.screen
[screen
].workarea
185 if position
== "right" or position
== "left" then
186 wibox
.height
= area
.height
- (2 * wibox
.border_width
)
187 align(wibox
, "center")
189 wibox
.width
= area
.width
- (2 * wibox
.border_width
)
195 --- Create a new wibox and attach it to a screen edge.
197 -- @param args A table with standard arguments to wibox() creator.
198 -- You can add also position key with value top, bottom, left or right.
199 -- You can also use width or height in % and set align to center, right or left.
200 -- You can also set the screen key with a screen number to attach the wibox.
201 -- If not specified, 1 is assumed.
202 -- @return The wibox created.
204 local arg
= arg
or {}
205 local position
= arg
.position
or "top"
206 local has_to_stretch
= true
207 -- Empty position and align in arg so we are passing deprecation warning
211 if position
== "left" or position
== "right" then
212 arg
.width
= arg
.width
or capi
.awesome
.font_height
* 1.5
214 has_to_stretch
= false
216 local hp
= arg
.height
:match("(%d+)%%")
218 arg
.height
= capi
.screen
[arg
.screen
].geometry
.height
* hp
/ 100
223 arg
.height
= arg
.height
or capi
.awesome
.font_height
* 1.5
225 has_to_stretch
= false
227 local wp
= arg
.width
:match("(%d+)%%")
229 arg
.width
= capi
.screen
[arg
.screen
].geometry
.width
* wp
/ 100
235 local w
= capi
.wibox(arg
)
237 if position
== "left" then
238 w
.orientation
= "north"
239 elseif position
== "right" then
240 w
.orientation
= "south"
243 w
.screen
= arg
.screen
or 1
246 if has_to_stretch
then
255 local function do_rounded_corners(width
, height
, corner
)
256 local img
= image
.argb32(width
, height
, nil)
258 -- The image starts completely black which is fully opaque for our use
260 local function transp_rect(x
, y
)
261 img
:draw_rectangle(x
, y
, corner
, corner
, true, "#ffffff")
263 local function opaque_circle(x
, y
)
264 -- x, y are the center of the circle
265 img
:draw_circle(x
, y
, corner
, corner
, true, "#000000")
269 -- First make a 'corner times corner' rectangle transparent
271 -- Then add the rounded corner
272 opaque_circle(corner
, corner
)
274 -- Upper right corner
275 transp_rect(width
- corner
, 0)
276 opaque_circle(width
- corner
- 1, corner
)
278 -- Bottom left corner
279 transp_rect(0, height
- corner
)
280 opaque_circle(corner
, height
- corner
- 1)
282 -- Bottom right corner
283 transp_rect(width
- corner
, height
- corner
)
284 opaque_circle(width
- corner
- 1, height
- corner
- 1)
289 --- Add rounded corners to a wibox
290 -- @param wibox The wibox.
291 -- @param corner_size The size in pixel of the rounded corners.
292 function rounded_corners(wibox
, corner_size
)
293 local border
= wibox
.border_width
295 -- Corners can't be larger than half the wibox' space
296 if wibox
.width
/ 2 < corner_size
then
297 corner_size
= wibox
.width
/ 2
299 if wibox
.height
/ 2 < corner_size
then
300 corner_size
= wibox
.height
/ 2
303 wibox
.shape_clip
= do_rounded_corners(wibox
.width
, wibox
.height
, corner_size
)
304 wibox
.shape_bounding
= do_rounded_corners(wibox
.width
+ border
* 2, wibox
.height
+ border
* 2, corner_size
+ border
)
307 local function update_wiboxes_on_struts(c
)
308 local struts
= c
:struts()
309 if struts
.left
~= 0 or struts
.right
~= 0
310 or struts
.top
~= 0 or struts
.bottom
~= 0 then
311 update_all_wiboxes_position()
315 -- Hook registered to reset all wiboxes position.
316 capi
.client
.add_signal("manage", function(c
)
317 update_wiboxes_on_struts(c
)
318 c
:add_signal("property::struts", update_wiboxes_on_struts
)
320 capi
.client
.add_signal("unmanage", update_wiboxes_on_struts
)
322 setmetatable(_M
, { __call
= function(_
, ...) return new(...) end })
324 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80