1 ----------------------------------------------------------------------------
2 -- @author koniu <gkusnierz@gmail.com>
3 -- @copyright 2008 koniu
4 -- @release @AWESOME_VERSION@
5 ----------------------------------------------------------------------------
12 local hooks
= require("awful.hooks")
16 local capi
= { screen
= screen
}
17 local bt
= require("beautiful")
20 --- Notification library
23 --- Naughty configuration - a table containing common/default popup settings.
24 -- You can override some of these for individual popups using args to notify().
26 -- @field timeout Number of seconds after which popups disappear.
27 -- Set to 0 for no timeout. Default: 5
28 -- @field screen Screen on which the popups will appear number. Default: 1
29 -- @field position Corner of the workarea the popups will appear.
30 -- Valid values: 'top_right', 'top_left', 'bottom_right', 'bottom_left'.
31 -- Default: 'top_right'
32 -- @field padding Space between popups and edge of the workarea. Default: 4
33 -- @field height Height of a single line of text. Default: 16
34 -- @field width Width of a popup. Default: 300
35 -- @field spacing Spacing between popups. Default: 1
36 -- @field ontop Boolean forcing popups to display on top. Default: true
37 -- @field margin Space between popup edge and content. Default: 10
38 -- @field font Popup font. Default: beautiful.font or "Verdana 8"
39 -- @field icon Popup icon. Default: nil
40 -- @field icon_size Size of the icon in pixels. Default: 16
41 -- @field fg Foreground color. Default: beautiful.fg_focus or '#ffffff'
42 -- @field bg Background color. Default: beautiful.bg_focus or '#535d6c'
43 -- @field border_color Border color.
44 -- Default: beautiful.border_focus or '#535d6c'
45 -- @field border_width Border width. Default: 1
46 -- @field hover_timeout Delay in seconds after which hovered popup disappears.
53 config
.position
= "top_right"
62 config
.border_width
= 1
63 config
.hover_timeout
= nil
65 --- Index of notifications. See config table for valid 'position' values.
66 -- Each element is a table consisting of:
67 -- @field box Wibox object containing the popup
68 -- @field height Popup height
69 -- @field width Popup width
70 -- @field die Function to be executed on timeout
71 -- @name notifications[position]
75 for s
= 1, screen
.count() do
84 --- Evaluate desired position of the notification by index - internal
85 -- @param idx Index of the notification
86 -- @param position top_right | top_left | bottom_right | bottom_left
87 -- @param height Popup height
88 -- @param width Popup width (optional)
89 -- @return Absolute position in {x, y} dictionary
91 local function get_offset(screen
, position
, idx
, width
, height
)
92 local ws
= capi
.screen
[screen
].workarea
94 width
= width
or notifications
[screen
][position
][idx
].width
or config
.width
97 if position
:match("left") then
98 v
.x
= ws
.x
+ config
.padding
100 v
.x
= ws
.x
+ ws
.width
- (width
+ config
.border_width
*2 + config
.padding
)
103 -- calculate existing popups' height
105 for i
= 1, idx
-1, 1 do
106 existing
= existing
+ notifications
[screen
][position
][i
].height
+ config
.spacing
+ config
.border_width
*2
110 if position
:match("top") then
111 v
.y
= ws
.y
+ config
.padding
+ existing
113 v
.y
= ws
.y
+ ws
.height
- (config
.padding
+ config
.border_width
+ height
+ existing
)
116 -- if positioned outside workarea, destroy oldest popup and recalculate
117 if v
.y
+ height
> ws
.y
+ ws
.height
or v
.y
< ws
.y
then
119 destroy(notifications
[screen
][position
][1])
120 v
= get_offset(screen
, position
, idx
, width
, height
)
126 --- Re-arrange notifications according to their position and index - internal
128 local function arrange(screen
)
129 for p
,pos
in pairs(notifications
[screen
]) do
130 for i
,notification
in pairs(notifications
[screen
][p
]) do
131 local offset
= get_offset(screen
, p
, i
, notification
.width
, notification
.height
)
132 notification
.box
:geometry({ x
= offset
.x
, y
= offset
.y
, width
= notification
.width
, height
= notification
.height
})
138 --- Destroy notification by index
139 -- @param notification Notification object to be destroyed
140 -- @return True if the popup was successfully destroyed, nil otherwise
141 function destroy(notification
)
143 local scr
= notification
.box
.screen
144 table.remove(notifications
[notification
.box
.screen
][notification
.position
], notification
.idx
)
145 hooks
.timer
.unregister(notification
.die
)
146 notification
.box
.screen
= nil
152 --- Create notification. args is a dictionary of optional arguments. For more information and defaults see respective fields in config table.
153 -- @param text Text of the notification
154 -- @param timeout Time in seconds after which popup expires
155 -- @param title Title of the notification
156 -- @param position Corner of the workarea the popups will appear
157 -- @param icon Path to icon
158 -- @param icon_size Desired icon size in px
159 -- @param fg Foreground color
160 -- @param bg Background color
161 -- @param screen Target screen for the notification
162 -- @param ontop Target screen for the notification
163 -- @param run Function to run on left click
164 -- @param width The popup width
165 -- @usage naughty.notify({ title = 'Achtung!', text = 'You\'re idling', timeout = 0 })
166 -- @return The notification object
167 function notify(args
)
168 -- gather variables together
169 local timeout
= args
.timeout
or config
.timeout
170 local icon
= args
.icon
or config
.icon
171 local icon_size
= args
.icon_size
or config
.icon_size
172 local text
= args
.text
or ""
173 local screen
= args
.screen
or config
.screen
174 local ontop
= args
.ontop
or config
.ontop
175 local width
= args
.width
or config
.width
178 local beautiful
= bt
.get()
179 local font
= args
.font
or config
.font
or beautiful
.font
or "Verdana 8"
180 local fg
= args
.fg
or config
.fg
or beautiful
.fg_normal
or '#ffffff'
181 local bg
= args
.bg
or config
.bg
or beautiful
.bg_normal
or '#535d6c'
182 local border_color
= config
.border_color
or beautiful
.bg_focus
or '#535d6c'
183 local notification
= {}
184 notification
.position
= args
.position
or config
.position
185 notification
.idx
= #notifications
[screen
][notification
.position
] + 1
188 if args
.title
then title
= args
.title
.. "\n" end
191 local die
= function () destroy(notification
) end
192 hooks
.timer
.register(timeout
, die
)
193 notification
.die
= die
195 local run
= args
.run
or die
197 local hover_destroy
= function ()
198 if config
.hover_timeout
== 0 then die()
199 else hooks
.timer
.register(config
.hover_timeout
, die
) end
203 local textbox
= widget({ type = "textbox", name
= "text", align
= "flex" })
204 textbox
:buttons({ button({ }, 1, run
),
205 button({ }, 3, die
) })
206 textbox
.text
= string.format('<margin right="'..config
.margin
..'" left="'..config
.margin
..'"/><span font_desc="%s"><b>%s</b>%s</span>', font
, title
, text
)
207 if config
.hover_timeout
then textbox
.mouse_enter
= hover_destroy
end
212 iconbox
= widget({ type = "imagebox", name
= "icon", align
= "left" })
213 iconbox
:buttons({ button({ }, 1, run
),
214 button({ }, 3, die
) })
215 local img
= image(icon
)
217 img
= img
:crop_and_scale(0,0,img
.height
,img
.width
,icon_size
,icon_size
)
218 iconbox
.resize
= false
221 if config
.hover_timeout
then iconbox
.mouse_enter
= hover_destroy
end
224 -- create container wibox
225 notification
.box
= wibox({ name
= "not" .. notification
.idx
,
226 position
= "floating",
229 border_color
= config
.border_color
,
230 border_width
= config
.border_width
})
232 -- position the wibox
233 local lines
= 1; for i
in string.gmatch(title
..text
, "\n") do lines
= lines
+ 1 end
234 if iconbox
and iconbox
.image
.height
> lines
* config
.height
then
235 notification
.height
= iconbox
.image
.height
237 notification
.height
= lines
* config
.height
end
238 notification
.width
= width
239 local offset
= get_offset(screen
, notification
.position
, notification
.idx
, notification
.width
, notification
.height
)
240 notification
.box
:geometry({ width
= notification
.width
,
241 height
= notification
.height
,
244 notification
.box
.ontop
= ontop
245 notification
.box
.screen
= screen
248 notification
.box
.widgets
= { iconbox
, textbox
}
250 -- insert the notification to the table
251 table.insert(notifications
[screen
][notification
.position
], notification
)
253 -- return the notification
256 -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80