diff --git a/docs/03-declarative-layout.md b/docs/03-declarative-layout.md
index 0ba6e931f..c27ba19b6 100644
--- a/docs/03-declarative-layout.md
+++ b/docs/03-declarative-layout.md
@@ -28,6 +28,15 @@ configurable rules.
@DOC_layout_WIDGET_LIST@
+### Other
+
+Notifications also have their own widgets.
+
+
+
+More information about the notification widgets can be found on the
+`naughty.notification` documentation page.
+
### The different type of widget boxes (Wibox)
The Awesome API uses the word "wibox" (widget box) to describe an area of the
@@ -54,6 +63,9 @@ positioning, relative positioning, and manual positioning.
The `awful.tooltip` is a very simple `wibox` that allows to display text next
to an object such as the mouse.
+The `naughty.layout.box` allows to provide custom widgets to use within the
+notifications.
+
Finally, the `awful.titlebar`, while not technically a real `wibox`, acts
exactly the same way and allows to attach widgets on each side of clients.
@@ -424,3 +436,27 @@ Code:
s.mywibox : setup (three_circle)
+### Instantiation rules
+
+Whenever it can, Awesome tries to be asynchronous. This can take various form
+depending on the situation. For example, the `connect_signal` method allows to
+execute code when an event arrives. `awful.screen.connect_for_each_screen` also
+allows to instantiate various elements when a new screen is added. In the later
+case, it is why some widgets are added as properties to other objects instead of
+being global variables like in previous versions of Awesome.
+
+However, there is a case where this isn't enough and another abstract widget has
+to be used. This concept is called the `widget_template` and is an optional
+property of many widgets such as the `awful.widget.taglist`,
+`awful.widget.tasklist` and `naughty.layout.box`. These templates are a
+**table** using the exact same syntax as the declarative widgets, but without
+the `wibox.widget` prefix in front of the curly braces. These templates
+represents future widgets that will be created by their parent widget. This is
+necessary for three reasons:
+
+ * The widget must create many instances of the template at different points in
+ time.
+ * The widget data is only partially available and other fields must be set
+ at a later time (by the parent widget).
+ * The code is highly redundant and some of the logic is delegated to the parent
+ widget to simplify everything.
diff --git a/docs/config.ld b/docs/config.ld
index 64bf0cb2c..854a223e9 100644
--- a/docs/config.ld
+++ b/docs/config.ld
@@ -149,6 +149,10 @@ file = {
-- Ignore some parts of the widget library
'../lib/awful/widget/init.lua',
'../lib/naughty/layout/init.lua',
+ '../lib/naughty/widget/init.lua',
+ '../lib/naughty/container/init.lua',
+ '../lib/naughty/list/init.lua',
+ '../lib/naughty/widget/_default.lua',
-- Deprecated classes for one years or more don't deserve entries
-- in the index
diff --git a/lib/naughty/action.lua b/lib/naughty/action.lua
index 28e0de033..abc24c4da 100644
--- a/lib/naughty/action.lua
+++ b/lib/naughty/action.lua
@@ -6,7 +6,7 @@
--
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
-- @copyright 2019 Emmanuel Lepage Vallee
--- @classmod naughty.action
+-- @coreclassmod naughty.action
---------------------------------------------------------------------------
local gtable = require("gears.table" )
local gobject = require("gears.object")
@@ -43,6 +43,10 @@ local action = {}
-- @property icon
-- @tparam gears.surface|string icon
+--- If the action should hide the label and only display the icon.
+-- @property icon_only
+-- @param[opt=false] boolean
+
--- The notification.
-- @property notification
-- @tparam naughty.notification notification
@@ -80,7 +84,7 @@ function action:set_position(value)
--TODO make sure the position is unique
end
-for _, prop in ipairs { "name", "icon", "notification" } do
+for _, prop in ipairs { "name", "icon", "notification", "icon_only" } do
action["get_"..prop] = function(self)
return self._private[prop]
end
@@ -97,6 +101,10 @@ for _, prop in ipairs { "name", "icon", "notification" } do
end
--- Execute this action.
+--
+-- This only emits the `invoked` signal.
+--
+-- @method invoke
function action:invoke()
assert(self._private.notification,
"Cannot invoke an action without a notification")
diff --git a/lib/naughty/container/background.lua b/lib/naughty/container/background.lua
new file mode 100644
index 000000000..5bc97fa06
--- /dev/null
+++ b/lib/naughty/container/background.lua
@@ -0,0 +1,99 @@
+----------------------------------------------------------------------------
+--- A notification background.
+--
+-- This widget holds the boilerplate code associated with the notification
+-- background. This includes the color and potentially some other styling
+-- elements such as the shape and border.
+--
+-- * Honor the `beautiful` notification variables.
+-- * React to the `naughty.notification` changes.
+--
+--@DOC_wibox_nwidget_background_simple_EXAMPLE@
+--
+-- Note that this widget is based on the `wibox.container.background`. This is
+-- an implementation detail and may change in the future without prior notice.
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2019 Emmanuel Lepage Vallee
+-- @containermod naughty.widget.background
+-- @see wibox.container.background
+----------------------------------------------------------------------------
+local wbg = require("wibox.container.background")
+local gtable = require("gears.table")
+local beautiful = require("beautiful")
+local gshape = require("gears.shape")
+
+local background = {}
+
+local function update_background(notif, wdg)
+ local bg = notif.bg or beautiful.notification_bg
+ local bw = notif.border_width or beautiful.notification_border_width
+ local bc = notif.border_color or beautiful.notification_border_color
+
+ -- Always fallback to the rectangle to make sure the border works
+ local shape = notif.shape or
+ beautiful.notification_shape or gshape.rectangle
+
+ wdg:set_bg(bg)
+ wdg:set_shape(shape) -- otherwise there's no borders
+ wdg:set_shape_border_width(bw)
+ wdg:set_shape_border_color(bc)
+end
+
+--- The attached notification.
+-- @property notification
+-- @tparam naughty.notification notification
+
+function background:set_notification(notif)
+ if self._private.notification == notif then return end
+
+ if self._private.notification then
+ self._private.notification:disconnect_signal("poperty::bg",
+ self._private.background_changed_callback)
+ self._private.notification:disconnect_signal("poperty::border_width",
+ self._private.background_changed_callback)
+ self._private.notification:disconnect_signal("poperty::border_color",
+ self._private.background_changed_callback)
+ self._private.notification:disconnect_signal("poperty::shape",
+ self._private.background_changed_callback)
+ end
+
+ update_background(notif, self)
+
+ self._private.notification = notif
+
+ notif:connect_signal("poperty::bg" , self._private.background_changed_callback)
+ notif:connect_signal("poperty::border_width", self._private.background_changed_callback)
+ notif:connect_signal("poperty::border_color", self._private.background_changed_callback)
+ notif:connect_signal("poperty::shape" , self._private.background_changed_callback)
+end
+
+--- Create a new naughty.container.background.
+-- @tparam table args
+-- @tparam naughty.notification args.notification The notification.
+-- @constructorfct naughty.container.background
+
+local function new(args)
+ args = args or {}
+
+ local bg = wbg()
+ bg:set_border_strategy("inner")
+
+ gtable.crush(bg, background, true)
+
+ function bg._private.background_changed_callback()
+ update_background(bg._private.notification, bg)
+ end
+
+ if args.notification then
+ bg:set_notification(args.notification)
+ end
+
+ return bg
+end
+
+--@DOC_widget_COMMON@
+
+--@DOC_object_COMMON@
+
+return setmetatable(background, {__call = function(_, ...) return new(...) end})
diff --git a/lib/naughty/container/init.lua b/lib/naughty/container/init.lua
new file mode 100644
index 000000000..1e3af095e
--- /dev/null
+++ b/lib/naughty/container/init.lua
@@ -0,0 +1,9 @@
+---------------------------------------------------------------------------
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2019 Emmanuel Lepage Vallee
+-- @module naughty.container
+---------------------------------------------------------------------------
+
+return {
+ background = require( "naughty.container.background" );
+}
diff --git a/lib/naughty/core.lua b/lib/naughty/core.lua
index 3b93f7745..f57a51d08 100644
--- a/lib/naughty/core.lua
+++ b/lib/naughty/core.lua
@@ -122,6 +122,10 @@ gtable.crush(naughty, require("naughty.constants"))
-- @property active
-- @param table
+--- True when there is a handler connected to `request::display`.
+-- @property has_display_handler
+-- @param boolean
+
local properties = {
suspended = false,
expiration_paused = false
@@ -346,6 +350,10 @@ function naughty.get_active()
return naughty._active
end
+function naughty.get_has_display_handler()
+ return conns["request::display"] and #conns["request::display"] > 0 or false
+end
+
--- Set new notification timeout.
--
-- This function is deprecated, use `notification:reset_timeout(new_timeout)`.
@@ -454,7 +462,7 @@ end
--- Emitted when a notification has to be displayed.
--
--- To add an handler, use:
+-- To add a handler, use:
--
-- naughty.connect_signal("request::display", function(notification, args)
-- -- do something
diff --git a/lib/naughty/init.lua b/lib/naughty/init.lua
index 2a096df5c..e94f366d3 100644
--- a/lib/naughty/init.lua
+++ b/lib/naughty/init.lua
@@ -10,7 +10,11 @@ if dbus then
end
naughty.action = require("naughty.action")
+naughty.list = require("naughty.list")
naughty.layout = require("naughty.layout")
+naughty.widget = require("naughty.widget")
+naughty.container = require("naughty.container")
+naughty.action = require("naughty.action")
naughty.notification = require("naughty.notification")
return naughty
diff --git a/lib/naughty/layout/box.lua b/lib/naughty/layout/box.lua
new file mode 100644
index 000000000..780bd5398
--- /dev/null
+++ b/lib/naughty/layout/box.lua
@@ -0,0 +1,261 @@
+----------------------------------------------------------------------------
+--- A notification popup widget.
+--
+-- By default, the box is composed of many other widgets:
+--
+--@DOC_wibox_nwidget_default_EXAMPLE@
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @popupmod naughty.layout.box
+----------------------------------------------------------------------------
+
+local beautiful = require("beautiful")
+local gtable = require("gears.table")
+local wibox = require("wibox")
+local popup = require("awful.popup")
+local awcommon = require("awful.widget.common")
+local placement = require("awful.placement")
+local abutton = require("awful.button")
+
+local default_widget = require("naughty.widget._default")
+
+local box, by_position = {}, {}
+
+-- Init the weak tables for each positions. It is done ahead of time rather
+-- than when notifications are added to simplify the code.
+for _, pos in ipairs { "top_left" , "top_middle" , "top_right",
+ "bottom_left", "bottom_middle", "bottom_right" } do
+ by_position[pos] = setmetatable({},{__mode = "v"})
+end
+
+local function get_spacing()
+ local margin = beautiful.notification_spacing or 2
+ return {top = margin, bottom = margin}
+end
+
+-- Leverage `awful.placement` to create the stacks.
+local function update_position(position)
+ local pref = position:match("top_") and "bottom" or "top"
+ local align = position:match("_(.*)")
+ :gsub("left", "front"):gsub("right", "back")
+
+ for k, wdg in ipairs(by_position[position]) do
+ local args = {
+ geometry = by_position[position][k-1],
+ preferred_positions = {pref },
+ preferred_anchors = {align},
+ margins = get_spacing(),
+ honor_workarea = true,
+ }
+
+ -- The first entry is aligned to the workarea, then the following to the
+ -- previous widget.
+ placement[k==1 and position:gsub("_middle", "") or "next_to"](wdg, args)
+
+ wdg.visible = true
+ end
+end
+
+local function finish(self)
+ self.visible = false
+ assert(by_position[self.position])
+
+ for k, v in ipairs(by_position[self.position]) do
+ if v == self then
+ table.remove(by_position[self.position], k)
+ break
+ end
+ end
+
+ update_position(self.position)
+end
+
+--- The maximum notification width.
+-- @beautiful beautiful.notification_max_width
+-- @tparam[opt=500] number notification_max_width
+
+--- The maximum notification position.
+--
+-- Valid values are:
+--
+-- * top_left
+-- * top_middle
+-- * top_right
+-- * bottom_left
+-- * bottom_middle
+-- * bottom_right
+--
+-- @beautiful beautiful.notification_position
+-- @tparam[opt="top_right"] string notification_position
+
+--- The widget notification object.
+-- @property notification
+-- @param naughty.notification
+
+--- The widget template to construct the box content.
+--
+--@DOC_wibox_nwidget_default_EXAMPLE@
+--
+-- The default template is (less or more):
+--
+-- {
+-- {
+-- {
+-- {
+-- {
+-- naughty.widget.icon,
+-- {
+-- naughty.widget.title,
+-- naughty.widget.message,
+-- spacing = 4,
+-- layout = wibox.layout.fixed.vertical,
+-- },
+-- fill_space = true,
+-- spacing = 4,
+-- layout = wibox.layout.fixed.horizontal,
+-- },
+-- naughty.list.actions,
+-- spacing = 10,
+-- layout = wibox.layout.fixed.vertical,
+-- },
+-- margins = beautiful.notification_margin,
+-- widget = wibox.container.margins,
+-- },
+-- id = "background_role",
+-- widget = naughty.container.background,
+-- },
+-- strategy = "max",
+-- width = width(beautiful.notification_max_width
+-- or beautiful.xresources.apply_dpi(500)
+-- widget = wibox.container.constraint,
+-- }
+--
+-- @property widget_template
+-- @param widget
+
+local function generate_widget(args, n)
+ local w = wibox.widget.base.make_widget_from_value(
+ args.widget_template or default_widget
+ )
+
+ -- Call `:set_notification` on all children
+ awcommon._set_common_property(w, "notification", n or args.notification)
+
+ return w
+end
+
+local function init(self, notification)
+ local args = self._private.args
+
+ local preset = notification.preset
+ assert(preset)
+
+ local position = args.position or notification.position or
+ beautiful.notification_position or preset.position or "top_right"
+
+ if not self.widget then
+ self.widget = generate_widget(self._private.args, notification)
+ end
+
+ local bg = self._private.widget:get_children_by_id( "background_role" )[1]
+
+ -- Make sure the border isn't set twice, favor the widget one since it is
+ -- shared by the notification list and the notification box.
+ if bg then
+ if bg.set_notification then
+ bg:set_notification(notification)
+ self.border_width = 0
+ else
+ bg:set_bg(notification.bg)
+ self.border_width = notification.border_width
+ end
+ end
+
+ -- Add the notification to the active list
+ assert(by_position[position])
+
+ self:_apply_size_now()
+
+ table.insert(by_position[position], self)
+
+ local function update() update_position(position) end
+
+ self:connect_signal("property::geometry", update)
+ notification:connect_signal("property::margin", update)
+ notification:connect_signal("destroyed", self._private.destroy_callback)
+
+ update_position(position)
+
+end
+
+function box:set_notification(notif)
+ if self._private.notification == notif then return end
+
+ if self._private.notification then
+ self._private.notification:disconnect_signal("destroyed",
+ self._private.destroy_callback)
+ end
+
+ init(self, notif)
+
+ self._private.notification = notif
+end
+
+function box:get_position()
+ if self._private.notification then
+ return self._private.notification:get_position()
+ end
+
+ return "top_right"
+end
+
+local function new(args)
+ -- Set the default wibox values
+ local new_args = {
+ ontop = true,
+ visible = false,
+ bg = args and args.bg or beautiful.notification_bg,
+ fg = args and args.fg or beautiful.notification_fg,
+ shape = args and args.shape or beautiful.notification_shape,
+ border_width = args and args.border_width or beautiful.notification_border_width or 1,
+ border_color = args and args.border_color or beautiful.notification_border_color,
+ }
+
+ new_args = args and setmetatable(new_args, {__index = args}) or new_args
+
+ -- Generate the box before the popup is created to avoid the size changing
+ new_args.widget = generate_widget(new_args)
+
+ local ret = popup(new_args)
+ ret._private.args = new_args
+
+ gtable.crush(ret, box, true)
+
+ function ret._private.destroy_callback()
+ finish(ret)
+ end
+
+ if new_args.notification then
+ ret:set_notification(new_args.notification)
+ end
+
+ --TODO remove
+ local function hide()
+ if ret._private.notification then
+ ret._private.notification:destroy()
+ end
+ end
+
+ --FIXME there's another pull request for this
+ ret:buttons(gtable.join(
+ abutton({ }, 1, hide),
+ abutton({ }, 3, hide)
+ ))
+
+ return ret
+end
+
+--@DOC_wibox_COMMON@
+
+return setmetatable(box, {__call = function(_, args) return new(args) end})
diff --git a/lib/naughty/layout/init.lua b/lib/naughty/layout/init.lua
index c6df968a1..11b187f35 100644
--- a/lib/naughty/layout/init.lua
+++ b/lib/naughty/layout/init.lua
@@ -5,5 +5,6 @@
---------------------------------------------------------------------------
return {
- legacy = require("naughty.layout.legacy")
+ legacy = require( "naughty.layout.legacy" );
+ box = require( "naughty.layout.box" );
}
diff --git a/lib/naughty/layout/legacy.lua b/lib/naughty/layout/legacy.lua
index c09732906..745ae6de7 100644
--- a/lib/naughty/layout/legacy.lua
+++ b/lib/naughty/layout/legacy.lua
@@ -13,6 +13,11 @@
--
--@DOC_naughty_actions_EXAMPLE@
--
+-- Use the `naughty.notification.position` property to control where the popup
+-- is located.
+--
+--@DOC_awful_notification_corner_EXAMPLE@
+--
-- @author koniu <gkusnierz@gmail.com>
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
-- @copyright 2008 koniu
@@ -279,23 +284,10 @@ end
naughty.connect_signal("destroyed", cleanup)
---- The default notification GUI handler.
---
--- To disable this handler, use:
---
--- naughty.disconnect_signal(
--- "request::display", naughty.default_notification_handler
--- )
---
--- It looks like:
---
---@DOC_naughty_actions_EXAMPLE@
---
--- @tparam table notification The `naughty.notification` object.
--- @tparam table args Any arguments passed to the `naughty.notify` function,
--- including, but not limited to all `naughty.notification` properties.
--- @signalhandler naughty.default_notification_handler
function naughty.default_notification_handler(notification, args)
+ -- This is a fallback for users whose config doesn't have the newer
+ -- `request::display` section.
+ if naughty.has_display_handler then return end
-- If request::display is called more than once, simply make sure the wibox
-- is visible.
@@ -415,8 +407,14 @@ function naughty.default_notification_handler(notification, args)
local action_width = w + 2 * margin
actionmarginbox:buttons(gtable.join(
- button({ }, 1, function() action:invoke() end),
- button({ }, 3, function() action:invoke() end)
+ button({ }, 1, function()
+ action:invoke()
+ notification:destroy()
+ end),
+ button({ }, 3, function()
+ action:invoke()
+ notification:destroy()
+ end)
))
actionslayout:add(actionmarginbox)
@@ -561,4 +559,4 @@ function naughty.default_notification_handler(notification, args)
end
end
-naughty.connect_signal("request::display", naughty.default_notification_handler)
+naughty.connect_signal("request::fallback", naughty.default_notification_handler)
diff --git a/lib/naughty/list/actions.lua b/lib/naughty/list/actions.lua
new file mode 100644
index 000000000..cc37d703c
--- /dev/null
+++ b/lib/naughty/list/actions.lua
@@ -0,0 +1,324 @@
+----------------------------------------------------------------------------
+--- Manage a notification action list.
+--
+-- A notification action is a "button" that will trigger an action on the sender
+-- process. `notify-send` doesn't support actions, but `libnotify` based
+-- applications do.
+--
+--@DOC_wibox_nwidget_actionlist_simple_EXAMPLE@
+--
+-- This example has a custom vertical widget template:
+--
+--@DOC_wibox_nwidget_actionlist_fancy_EXAMPLE@
+--
+-- This example has a horizontal widget template and icons:
+--
+--@DOC_wibox_nwidget_actionlist_fancy_icons_EXAMPLE@
+--
+-- This example uses the theme/style variables instead of the template. This is
+-- less flexible, but easier to put in the theme file. Note that each style
+-- variable has a `beautiful` equivalent.
+--
+--@DOC_wibox_nwidget_actionlist_style_EXAMPLE@
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @widgetmod naughty.list.actions
+-- @see awful.widget.common
+----------------------------------------------------------------------------
+
+local wibox = require("wibox")
+local awcommon = require("awful.widget.common")
+local abutton = require("awful.button")
+local gtable = require("gears.table")
+local beautiful= require("beautiful")
+
+local module = {}
+
+--- Whether or not to underline the action name.
+-- @beautiful beautiful.notification_action_underline_normal
+-- @param[opt=true] boolean
+
+--- Whether or not to underline the selected action name.
+-- @beautiful beautiful.notification_action_underline_selected
+-- @param[opt=true] boolean
+
+--- Whether or not the action label should be shown.
+-- @beautiful beautiful.notification_action_icon_only
+-- @param[opt=false] boolean
+
+--- Whether or not the action icon should be shown.
+-- @beautiful beautiful.notification_action_label_only
+-- @param[opt=false] boolean
+
+--- The shape used for a normal action.
+-- @beautiful beautiful.notification_action_shape_normal
+-- @tparam[opt=gears.shape.rectangle] gears.shape shape
+-- @see gears.shape
+
+--- The shape used for a selected action.
+-- @beautiful beautiful.notification_action_shape_selected
+-- @tparam[opt=gears.shape.rectangle] gears.shape shape
+-- @see gears.shape
+
+--- The shape border color for normal actions.
+-- @beautiful beautiful.notification_action_shape_border_color_normal
+-- @param color
+-- @see gears.color
+
+--- The shape border color for selected actions.
+-- @beautiful beautiful.notification_action_shape_border_color_selected
+-- @param color
+-- @see gears.color
+
+--- The shape border width for normal actions.
+-- @beautiful beautiful.notification_action_shape_border_width_normal
+-- @param[opt=0] number
+
+--- The shape border width for selected actions.
+-- @beautiful beautiful.notification_action_shape_border_width_selected
+-- @param[opt=0] number
+
+--- The action icon size.
+-- @beautiful beautiful.notification_action_icon_size_normal
+-- @param[opt=0] number
+
+--- The selected action icon size.
+-- @beautiful beautiful.notification_action_icon_size_selected
+-- @param[opt=0] number
+
+--- The background color for normal actions.
+-- @beautiful beautiful.notification_action_bg_normal
+-- @param color
+-- @see gears.color
+
+--- The background color for selected actions.
+-- @beautiful beautiful.notification_action_bg_selected
+-- @param color
+-- @see gears.color
+
+--- The foreground color for normal actions.
+-- @beautiful beautiful.notification_action_fg_normal
+-- @param color
+-- @see gears.color
+
+--- The foreground color for selected actions.
+-- @beautiful beautiful.notification_action_fg_selected
+-- @param color
+-- @see gears.color
+
+--- The background image for normal actions.
+-- @beautiful beautiful.notification_action_bgimage_normal
+-- @tparam gears.surface|string action_bgimage_normal
+-- @see gears.surface
+
+--- The background image for selected actions.
+-- @beautiful beautiful.notification_action_bgimage_selected
+-- @tparam gears.surface|string action_bgimage_selected
+-- @see gears.surface
+
+local default_buttons = gtable.join(
+ abutton({ }, 1, function(a) a:invoke() end)
+)
+
+local props = {"shape_border_color", "bg_image" , "fg",
+ "shape_border_width", "underline", "bg",
+ "shape", "icon_size", }
+
+-- Use a cached loop instead of an large function like the taglist and tasklist
+local function update_style(self)
+ self._private.style_cache = self._private.style_cache or {}
+
+ for _, state in ipairs {"normal", "selected"} do
+ local s = {}
+
+ for _, prop in ipairs(props) do
+ if self._private.style[prop.."_"..state] ~= nil then
+ s[prop] = self._private.style[prop.."_"..state]
+ else
+ s[prop] = beautiful["notification_action_"..prop.."_"..state]
+ end
+ end
+
+ -- Set a fallback for the icon size to prevent them from being gigantic
+ s.icon_size = s.icon_size
+ or beautiful.get_font_height(beautiful.font) * 1.5
+
+ self._private.style_cache[state] = s
+ end
+end
+
+local function wb_label(action, self)
+ -- Get the name
+ local name = action.name
+
+ local style = self._private.style_cache[action.selected and "selected" or "normal"]
+
+ -- Add the underline
+ name = style.underline ~= false and
+ (""..name.."") or name
+
+ local icon = beautiful.notification_action_label_only ~= true and action.icon or nil
+
+ if style.fg then
+ name = "" .. name .. ""
+ end
+
+ if action.icon_only or beautiful.notification_action_icon_only then
+ name = nil
+ end
+
+ return name, style.bg, style.bg_image, icon, style
+end
+
+local function update(self)
+ if not self._private.layout or not self._private.notification then return end
+
+ awcommon.list_update(
+ self._private.layout,
+ default_buttons,
+ function(o) return wb_label(o, self) end,
+ self._private.data,
+ self._private.notification.actions,
+ {
+ widget_template = self._private.widget_template
+ }
+ )
+end
+
+local actionlist = {}
+
+--- The actionlist parent notification.
+-- @property notification
+-- @param notification
+-- @see naughty.notification
+
+--- The actionlist layout.
+-- If no layout is specified, a `wibox.layout.fixed.horizontal` will be created
+-- automatically.
+-- @property layout
+-- @param widget
+-- @see wibox.layout.fixed.horizontal
+
+--- The actionlist parent notification.
+-- @property widget_template
+-- @param table
+
+--- A table with values to override each `beautiful.notification_action` values.
+-- @property style
+-- @param table
+
+function actionlist:set_notification(notif)
+ self._private.notification = notif
+
+ if not self._private.layout then
+ self._private.layout = wibox.layout.fixed.horizontal()
+ end
+
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+end
+
+function actionlist:set_base_layout(layout)
+ self._private.layout = layout
+
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+end
+
+function actionlist:set_widget_template(widget_template)
+ self._private.widget_template = widget_template
+
+ -- Remove the existing instances
+ self._private.data = {}
+
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+end
+
+function actionlist:set_style(style)
+ self._private.style = style or {}
+
+ update_style(self)
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+end
+
+function actionlist:get_notification()
+ return self._private.notification
+end
+
+function actionlist:layout(_, width, height)
+ if self._private.layout then
+ return { wibox.widget.base.place_widget_at(self._private.layout, 0, 0, width, height) }
+ end
+end
+
+function actionlist:fit(context, width, height)
+ if not self._private.layout then
+ return 0, 0
+ end
+
+ return wibox.widget.base.fit_widget(self, context, self._private.layout, width, height)
+end
+
+--- Create an action list.
+--
+-- @tparam table args
+-- @tparam naughty.notification args.notification The notification/
+-- @tparam widget args.base_layout The action layout.
+-- @tparam table args.style Override the beautiful values.
+-- @tparam boolean args.style.underline_normal
+-- @tparam boolean args.style.underline_selected
+-- @tparam gears.shape args.style.shape_normal
+-- @tparam gears.shape args.style.shape_selected
+-- @tparam gears.color|string args.style.shape_border_color_normal
+-- @tparam gears.color|string args.style.shape_border_color_selected
+-- @tparam number args.style.shape_border_width_normal
+-- @tparam number args.style.shape_border_width_selected
+-- @tparam number args.style.icon_size
+-- @tparam gears.color|string args.style.bg_normal
+-- @tparam gears.color|string args.style.bg_selected
+-- @tparam gears.color|string args.style.fg_normal
+-- @tparam gears.color|string args.style.fg_selected
+-- @tparam gears.surface|string args.style.bgimage_normal
+-- @tparam gears.surface|string args.style.bgimage_selected
+-- @tparam[opt] table widget_template A custom widget to be used for each action.
+-- @treturn widget The action widget.
+-- @constructorfct naughty.list.actions
+
+local function new(_, args)
+ args = args or {}
+
+ local wdg = wibox.widget.base.make_widget(nil, nil, {
+ enable_properties = true,
+ })
+
+ gtable.crush(wdg, actionlist, true)
+
+ wdg._private.data = {}
+
+ gtable.crush(wdg, args)
+
+ wdg._private.style = wdg._private.style or {}
+
+ update_style(wdg)
+
+ return wdg
+end
+
+--@DOC_widget_COMMON@
+
+--@DOC_object_COMMON@
+
+return setmetatable(module, {__call = new})
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/naughty/list/init.lua b/lib/naughty/list/init.lua
new file mode 100644
index 000000000..46470f127
--- /dev/null
+++ b/lib/naughty/list/init.lua
@@ -0,0 +1,10 @@
+---------------------------------------------------------------------------
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017-2019 Emmanuel Lepage Vallee
+-- @module naughty.list
+---------------------------------------------------------------------------
+
+return {
+ actions = require( "naughty.list.actions" );
+ notifications = require( "naughty.list.notifications" );
+}
diff --git a/lib/naughty/list/notifications.lua b/lib/naughty/list/notifications.lua
new file mode 100644
index 000000000..3e388ccc4
--- /dev/null
+++ b/lib/naughty/list/notifications.lua
@@ -0,0 +1,356 @@
+----------------------------------------------------------------------------
+--- Get a list of all currently active notifications.
+--
+-- @DOC_awful_notification_notificationlist_bottombar_EXAMPLE@
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @widgetmod naughty.list.notifications
+-- @see awful.widget.common
+----------------------------------------------------------------------------
+
+local wibox = require("wibox")
+local awcommon = require("awful.widget.common")
+local abutton = require("awful.button")
+local gtable = require("gears.table")
+local gtimer = require("gears.timer")
+local beautiful= require("beautiful")
+local naughty = require("naughty.core")
+
+local default_widget = require("naughty.widget._default")
+
+local module = {}
+
+--- The shape used for a normal notification.
+-- @beautiful beautiful.notification_shape_normal
+-- @tparam[opt=gears.shape.rectangle] gears.shape shape
+-- @see gears.shape
+
+--- The shape used for a selected notification.
+-- @beautiful beautiful.notification_shape_selected
+-- @tparam[opt=gears.shape.rectangle] gears.shape shape
+-- @see gears.shape
+
+--- The shape border color for normal notifications.
+-- @beautiful beautiful.notification_shape_border_color_normal
+-- @param color
+-- @see gears.color
+
+--- The shape border color for selected notifications.
+-- @beautiful beautiful.notification_shape_border_color_selected
+-- @param color
+-- @see gears.color
+
+--- The shape border width for normal notifications.
+-- @beautiful beautiful.notification_shape_border_width_normal
+-- @param[opt=0] number
+
+--- The shape border width for selected notifications.
+-- @beautiful beautiful.notification_shape_border_width_selected
+-- @param[opt=0] number
+
+--- The notification icon size.
+-- @beautiful beautiful.notification_icon_size_normal
+-- @param[opt=0] number
+
+--- The selected notification icon size.
+-- @beautiful beautiful.notification_icon_size_selected
+-- @param[opt=0] number
+
+--- The background color for normal notifications.
+-- @beautiful beautiful.notification_bg_normal
+-- @param color
+-- @see gears.color
+
+--- The background color for selected notifications.
+-- @beautiful beautiful.notification_bg_selected
+-- @param color
+-- @see gears.color
+
+--- The foreground color for normal notifications.
+-- @beautiful beautiful.notification_fg_normal
+-- @param color
+-- @see gears.color
+
+--- The foreground color for selected notifications.
+-- @beautiful beautiful.notification_fg_selected
+-- @param color
+-- @see gears.color
+
+--- The background image for normal notifications.
+-- @beautiful beautiful.notification_bgimage_normal
+-- @tparam string|gears.surface bgimage_normal
+-- @see gears.surface
+
+--- The background image for selected notifications.
+-- @beautiful beautiful.notification_bgimage_selected
+-- @tparam string|gears.surface bgimage_selected
+-- @see gears.surface
+
+local default_buttons = gtable.join(
+ abutton({ }, 1, function(n) n:destroy() end),
+ abutton({ }, 3, function(n) n:destroy() end)
+)
+
+local props = {"shape_border_color", "bg_image" , "fg",
+ "shape_border_width", "shape" , "bg",
+ "icon_size"}
+
+-- Use a cached loop instead of an large function like the taglist and tasklist
+local function update_style(self)
+ self._private.style_cache = self._private.style_cache or {}
+
+ for _, state in ipairs {"normal", "selected"} do
+ local s = {}
+
+ for _, prop in ipairs(props) do
+ if self._private.style[prop.."_"..state] ~= nil then
+ s[prop] = self._private.style[prop.."_"..state]
+ else
+ s[prop] = beautiful["notification_"..prop.."_"..state]
+ end
+ end
+
+ self._private.style_cache[state] = s
+ end
+end
+
+local function wb_label(notification, self)
+ -- Get the title
+ local title = notification.title
+
+ local style = self._private.style_cache[notification.selected and "selected" or "normal"]
+
+ if notification.fg or style.fg then
+ title = "" .. title .. ""
+ end
+
+ return title, notification.bg or style.bg, style.bg_image, notification.icon, {
+ shape = notification.shape or style.shape,
+ shape_border_width = notification.border_width or style.shape_border_width,
+ shape_border_color = notification.border_color or style.shape_border_color,
+ icon_size = style.icon_size,
+ }
+end
+
+-- Remove some callback boilerplate from the user provided templates.
+local function create_callback(w, n)
+ awcommon._set_common_property(w, "notification", n)
+end
+
+local function update(self)
+ -- Checking style_cache helps to avoid useless redraw during initialization
+ if not self._private.base_layout or not self._private.style_cache then return end
+
+ awcommon.list_update(
+ self._private.base_layout,
+ default_buttons,
+ function(o) return wb_label(o, self) end,
+ self._private.data,
+ naughty.active,
+ {
+ create_callback = create_callback,
+ widget_template = self._private.widget_template or default_widget
+ }
+ )
+end
+
+local notificationlist = {}
+
+--- The notificationlist parent notification.
+-- @property notification
+-- @param notification
+-- @see naughty.notification
+
+--- The notificationlist layout.
+-- If no layout is specified, a `wibox.layout.fixed.vertical` will be created
+-- automatically.
+-- @property layout
+-- @param widget
+-- @see wibox.layout.fixed.vertical
+
+--- The notificationlist parent notification.
+-- @property widget_template
+-- @param table
+
+--- A table with values to override each `beautiful.notification_action` values.
+-- @property style
+-- @param table
+
+function notificationlist:set_widget_template(widget_template)
+ self._private.widget_template = widget_template
+
+ -- Remove the existing instances
+ self._private.data = {}
+
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+end
+
+function notificationlist:set_style(style)
+ self._private.style = style or {}
+
+ update_style(self)
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+end
+
+function notificationlist:layout(_, width, height)
+ if self._private.base_layout then
+ return { wibox.widget.base.place_widget_at(self._private.base_layout, 0, 0, width, height) }
+ end
+end
+
+function notificationlist:fit(context, width, height)
+ if not self._private.base_layout then
+ return 0, 0
+ end
+
+ return wibox.widget.base.fit_widget(self, context, self._private.base_layout, width, height)
+end
+
+--- A `wibox.layout` to be used to place the entries.
+-- @property base_layout
+-- @param widget
+-- @see wibox.layout.fixed.horizontal
+-- @see wibox.layout.fixed.vertical
+-- @see wibox.layout.flex.horizontal
+-- @see wibox.layout.flex.vertical
+-- @see wibox.layout.grid
+
+--- A function to prevent some notifications from being added to the list.
+-- @property filter
+-- @param function
+
+for _, prop in ipairs { "filter", "client", "clients", "tag", "tags", "screen", "base_layout" } do
+ notificationlist["set_"..prop] = function(self, value)
+ self._private[prop] = value
+
+ update(self)
+
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("widget::redraw_needed")
+ end
+
+ notificationlist["get_"..prop] = function(self)
+ return self._private[prop]
+ end
+end
+
+--- Create an notification list.
+--
+-- @tparam table args
+-- @tparam widget args.base_layout The notification list base_layout.
+-- @tparam widget args.filter The list filter.
+-- @tparam table args.style Override the beautiful values.
+-- @tparam gears.shape args.style.shape_normal
+-- @tparam gears.shape args.style.shape_selected
+-- @tparam gears.color|string args.style.shape_border_color_normal
+-- @tparam gears.color|string args.style.shape_border_color_selected
+-- @tparam number args.style.shape_border_width_normal
+-- @tparam number args.style.shape_border_width_selected
+-- @tparam number args.style.icon_size
+-- @tparam gears.color|string args.style.bg_normal
+-- @tparam gears.color|string args.style.bg_selected
+-- @tparam gears.color|string args.style.fg_normal
+-- @tparam gears.color|string args.style.fg_selected
+-- @tparam gears.surface|string args.style.bgimage_normal
+-- @tparam gears.surface|string args.style.bgimage_selected
+-- @tparam[opt] table widget_template A custom widget to be used for each
+-- notifications.
+-- @treturn widget The notification list widget.
+-- @constructorfct naughty.list.notifications
+
+local function new(_, args)
+ args = args or {}
+
+ local wdg = wibox.widget.base.make_widget(nil, nil, {
+ enable_properties = true,
+ })
+
+ gtable.crush(wdg, notificationlist, true)
+
+ wdg._private.data = {}
+
+ gtable.crush(wdg, args)
+
+ wdg._private.style = wdg._private.style or {}
+
+ -- Don't do this right away since the base_layout may not have been set yet.
+ -- This also avoids `update()` being executed during initialization and
+ -- causing an output that isn't reproducible.
+ gtimer.delayed_call(function()
+ update_style(wdg)
+
+ if not wdg._private.base_layout then
+ wdg._private.base_layout = wibox.layout.flex.horizontal()
+ wdg._private.base_layout:set_spacing(beautiful.notification_spacing or 0)
+ wdg:emit_signal("widget::layout_changed")
+ wdg:emit_signal("widget::redraw_needed")
+ end
+
+ update(wdg)
+
+ local is_scheduled = false
+
+ -- Prevent multiple updates due to the many signals.
+ local function f()
+ if is_scheduled then return end
+
+ is_scheduled = true
+
+ gtimer.delayed_call(function() update(wdg); is_scheduled = false end)
+ end
+
+ -- Yes, this will cause 2 updates when a new notification arrives, but
+ -- on the other hand, request::display is required to auto-disable the
+ -- fallback legacy mode and property::active is needed to remove the
+ -- destroyed notifications.
+ naughty.connect_signal("property::active", f)
+ naughty.connect_signal("request::display", f)
+ end)
+
+ return wdg
+end
+
+module.filter = {}
+
+---
+-- @param n The notification.
+-- @return Always returns true because it doesn't filter anything at all.
+-- @filterfunction naughty.list.notifications.filter.all
+function module.filter.all(n) -- luacheck: no unused args
+ return true
+end
+
+--- Only get the most recent notification(s).
+--
+-- To set the count, the function needs to be wrapped:
+--
+-- filter = function(n) return naughty.list.notifications.filter.most_recent(n, 3) end
+--
+-- @param n The notification.
+-- @tparam[opt=1] number count The number of recent notifications to allow.
+-- @return Always returns true because it doesn't filter anything at all.
+-- @filterfunction naughty.list.notifications.filter.most_recent
+function module.filter.most_recent(n, count)
+ for i=1, count or 1 do
+ if n == naughty.active[i] then
+ return true
+ end
+ end
+
+ return false
+end
+
+--@DOC_widget_COMMON@
+
+--@DOC_object_COMMON@
+
+return setmetatable(module, {__call = new})
+
+-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua
index d7f2a77cc..5004cfc71 100644
--- a/lib/naughty/notification.lua
+++ b/lib/naughty/notification.lua
@@ -53,7 +53,7 @@ local notification = {}
-- @beautiful beautiful.notification_opacity
-- @tparam[opt] int notification_opacity
---- Notifications margin.
+--- The margins inside of the notification widget (or popup).
-- @beautiful beautiful.notification_margin
-- @tparam int notification_margin
@@ -65,6 +65,11 @@ local notification = {}
-- @beautiful beautiful.notification_height
-- @tparam int notification_height
+--- The spacing between the notifications.
+-- @beautiful beautiful.notification_spacing
+-- @param[opt=2] number
+-- @see gears.surface
+
-- Unique identifier of the notification.
-- This is the equivalent to a PID as allows external applications to select
-- notifications.
@@ -72,8 +77,12 @@ local notification = {}
-- @param string
-- @see title
--- Text of the notification [[deprecated]]
--- @property text
+--- Text of the notification.
+--
+-- This exists only for the pre-AwesomeWM v4.4 new notification implementation.
+-- Please always use `title`.
+--
+-- @deprecatedproperty text
-- @param string
-- @see title
@@ -107,22 +116,28 @@ local notification = {}
-- * *bottom_middle*
-- * *middle*
--
---@DOC_awful_notification_corner_EXAMPLE@
+--@DOC_awful_notification_box_corner_EXAMPLE@
--
-- @property position
-- @param string
+-- @see awful.placement.next_to
--- Boolean forcing popups to display on top.
-- @property ontop
-- @param boolean
--- Popup height.
+--
+--@DOC_awful_notification_geometry_EXAMPLE@
+--
-- @property height
-- @param number
+-- @see width
--- Popup width.
-- @property width
-- @param number
+-- @see height
--- Notification font.
--@DOC_naughty_colors_EXAMPLE@
@@ -138,12 +153,18 @@ local notification = {}
-- @param number
--- Foreground color.
+--
+--@DOC_awful_notification_fg_EXAMPLE@
+--
-- @property fg
-- @tparam string|color|pattern fg
-- @see title
-- @see gears.color
--- Background color.
+--
+--@DOC_awful_notification_bg_EXAMPLE@
+--
-- @property bg
-- @tparam string|color|pattern bg
-- @see title
@@ -155,32 +176,58 @@ local notification = {}
-- @see title
--- Border color.
+--
+--@DOC_awful_notification_border_color_EXAMPLE@
+--
-- @property border_color
-- @param string
-- @see title
-- @see gears.color
--- Widget shape.
+--
+-- Note that when using a custom `request::display` handler or `naughty.rules`,
+-- choosing between multiple shapes depending on the content can be done using
+-- expressions like:
+--
+-- -- The notification object is called `n`
+-- shape = #n.actions > 0 and
+-- gears.shape.rounded_rect or gears.shape.rounded_bar,
+--
+--@DOC_awful_notification_shape_EXAMPLE@
+--
--@DOC_naughty_shape_EXAMPLE@
+--
-- @property shape
--- @param gears.shape
+-- @tparam gears.shape shape
--- Widget opacity.
-- @property opacity
--- @param number From 0 to 1
+-- @tparam number opacity Between 0 to 1.
--- Widget margin.
+--
+--@DOC_awful_notification_margin_EXAMPLE@
+--
-- @property margin
-- @tparam number|table margin
-- @see shape
--- Function to run on left click.
--- @property run
+--
+-- Use the signals rather than this.
+--
+-- @deprecatedproperty run
-- @param function
+-- @see destroyed
--- Function to run when notification is destroyed.
--- @property destroy
+--
+-- Use the signals rather than this.
+--
+-- @deprecatedproperty destroy
-- @param function
+-- @see destroyed
--- Table with any of the above parameters.
-- args will override ones defined
@@ -380,16 +427,18 @@ local function convert_actions(actions)
local naction = require("naughty.action")
+ local new_actions = {}
+
-- Does not attempt to handle when there is a mix of strings and objects
for idx, name in pairs(actions) do
- local cb = nil
+ local cb, old_idx = nil, idx
if type(name) == "function" then
cb = name
end
if type(idx) == "string" then
- name, idx = idx, nil
+ name, idx = idx, #actions+1
end
local a = naction {
@@ -401,9 +450,14 @@ local function convert_actions(actions)
a:connect_signal("invoked", cb)
end
- -- Yes, it modifies `args`, this is legacy code, cloning the args
- -- just for this isn't worth it.
- actions[idx] = a
+ new_actions[old_idx] = a
+ end
+
+ -- Yes, it modifies `args`, this is legacy code, cloning the args
+ -- just for this isn't worth it.
+ for old_idx, a in pairs(new_actions) do
+ actions[a.position] = a
+ actions[ old_idx ] = nil
end
end
@@ -497,7 +551,7 @@ local function create(args)
rawget(n, "preset") or {}
))
- if is_old_action then
+ if is_old_action then
convert_actions(args.actions)
end
@@ -509,6 +563,16 @@ local function create(args)
private[k] = v
end
+ -- notif.actions should not be nil to allow cheching if there is actions
+ -- using the shorthand `if #notif.actions > 0 then`
+ private.actions = private.actions or {}
+
+ -- Make sure the action are for this notification. Sharing actions with
+ -- multiple notification is not supported.
+ for _, a in ipairs(private.actions) do
+ a.notification = n
+ end
+
-- It's an automatic property
n.is_expired = false
@@ -524,7 +588,8 @@ local function create(args)
-- Let all listeners handle the actual visual aspects
if (not n.ignore) and (not n.preset.ignore) then
- naughty.emit_signal("request::display", n, args)
+ naughty.emit_signal("request::display" , n, args)
+ naughty.emit_signal("request::fallback", n, args)
end
-- Because otherwise the setter logic would not be executed
diff --git a/lib/naughty/widget/_default.lua b/lib/naughty/widget/_default.lua
new file mode 100644
index 000000000..c964d9da6
--- /dev/null
+++ b/lib/naughty/widget/_default.lua
@@ -0,0 +1,85 @@
+----------------------------------------------------------------------------
+--- The default widget template for the notifications.
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2019 Emmanuel Lepage Vallee
+-- @classmod naughty.widget._default
+----------------------------------------------------------------------------
+
+local wibox = require("wibox")
+local actionlist = require("naughty.list.actions")
+local wtitle = require("naughty.widget.title")
+local wmessage = require("naughty.widget.message")
+local wicon = require("naughty.widget.icon")
+local wbg = require("naughty.container.background")
+local beautiful = require("beautiful")
+local dpi = require("beautiful").xresources.apply_dpi
+
+-- It is not worth doing a special widget for this.
+local function notif_size()
+ local constraint = wibox.container.constraint()
+ constraint:set_strategy("max")
+ constraint:set_width(beautiful.notification_max_width or dpi(500))
+
+ rawset(constraint, "set_notification", function(_, notif)
+ constraint._private.notification = notif
+ local s = false
+
+ if notif.width and notif.width ~= beautiful.notification_max_width then
+ constraint.width = notif.width
+ s = true
+ end
+ if notif.height then
+ constraint.height = notif.height
+ s = true
+ end
+
+ constraint.strategy = s and "exact" or "max"
+ end)
+
+ return constraint
+end
+
+-- It is not worth doing a special widget for this either.
+local function notif_margins()
+ local margins = wibox.container.margin()
+ margins:set_margins(beautiful.notification_margin or 4)
+
+ rawset(margins, "set_notification", function(_, notif)
+ if notif.margin then
+ margins:set_margins(notif.margin)
+ end
+ end)
+
+ return margins
+end
+
+-- Used as a fallback when no widget_template is provided, emulate the legacy
+-- widget.
+return {
+ {
+ {
+ {
+ {
+ wicon,
+ {
+ wtitle,
+ wmessage,
+ spacing = 4,
+ layout = wibox.layout.fixed.vertical,
+ },
+ fill_space = true,
+ spacing = 4,
+ layout = wibox.layout.fixed.horizontal,
+ },
+ actionlist,
+ spacing = 10,
+ layout = wibox.layout.fixed.vertical,
+ },
+ widget = notif_margins,
+ },
+ id = "background_role",
+ widget = wbg,
+ },
+ widget = notif_size,
+}
diff --git a/lib/naughty/widget/icon.lua b/lib/naughty/widget/icon.lua
new file mode 100644
index 000000000..cac135645
--- /dev/null
+++ b/lib/naughty/widget/icon.lua
@@ -0,0 +1,158 @@
+----------------------------------------------------------------------------
+--- A notification square icon.
+--
+-- This widget is a specialized `wibox.widget.imagebox` with the following extra
+-- features:
+--
+-- * Honor the `beautiful` notification variables.
+-- * Restrict the size avoid huge notifications
+-- * Provides some strategies to handle small icons
+-- * React to the `naughty.notification` object icon changes.
+--
+--@DOC_wibox_nwidget_icon_simple_EXAMPLE@
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @widgetmod naughty.widget.icon
+-- @see wibox.widget.imagebox
+----------------------------------------------------------------------------
+local imagebox = require("wibox.widget.imagebox")
+local gtable = require("gears.table")
+local beautiful = require("beautiful")
+local dpi = require("beautiful.xresources").apply_dpi
+
+local icon = {}
+
+-- The default way to resize the icon.
+-- @beautiful beautiful.notification_icon_resize_strategy
+-- @param number
+
+function icon:fit(_, width, height)
+ -- Until someone complains, adding a "leave blank space" isn't supported
+ if not self._private.image then return 0, 0 end
+
+ local maximum = math.min(width, height)
+ local strategy = self._private.resize_strategy or "resize"
+ local optimal = math.min(beautiful.notification_icon_size or dpi(48), maximum)
+
+ local w = self._private.image:get_width()
+ local h = self._private.image:get_height()
+
+ if strategy == "resize" then
+ return math.min(w, optimal, maximum), math.min(h, optimal, maximum)
+ else
+ return optimal, optimal
+ end
+end
+
+function icon:draw(_, cr, width, height)
+ if not self._private.image then return end
+ if width == 0 or height == 0 then return end
+
+ -- Let's scale the image so that it fits into (width, height)
+ local strategy = self._private.resize_strategy or "resize"
+ local w = self._private.image:get_width()
+ local h = self._private.image:get_height()
+ local aspect = width / w
+ local aspect_h = height / h
+
+ if aspect > aspect_h then aspect = aspect_h end
+
+ if aspect < 1 or (strategy == "scale" and (w < width or h < height)) then
+ cr:scale(aspect, aspect)
+ end
+
+ local x, y = 0, 0
+
+ if (strategy == "center" and aspect > 1) or strategy == "resize" then
+ x = math.floor((width - w) / 2)
+ y = math.floor((height - h) / 2)
+ end
+
+ cr:set_source_surface(self._private.image, x, y)
+ cr:paint()
+end
+
+--- The attached notification.
+-- @property notification
+-- @tparam naughty.notification notification
+
+function icon:set_notification(notif)
+ if self._private.notification == notif then return end
+
+ if self._private.notification then
+ self._private.notification:disconnect_signal("destroyed",
+ self._private.icon_changed_callback)
+ end
+
+ self:set_image(notif.icon)
+
+ self._private.notification = notif
+
+ notif:connect_signal("poperty::icon", self._private.icon_changed_callback)
+end
+
+local valid_strategies = {
+ scale = true,
+ center = true,
+ resize = true,
+}
+
+--- How small icons are handled.
+--
+-- Valid values are:
+--
+-- * **scale**: Scale the icon up to the optimal size.
+-- * **center**: Keep the icon size and draw it in the center
+-- * **resize**: Change the size of the widget itself (*default*).
+--
+-- Note that the size upper bound is defined by
+-- `beautiful.notification_icon_size`.
+--
+--@DOC_wibox_nwidget_icon_strategy_EXAMPLE@
+--
+-- @property resize_strategy
+-- @param string
+
+function icon:set_resize_strategy(strategy)
+ assert(valid_strategies[strategy], "Invalid strategy")
+
+ self._private.resize_strategy = strategy
+
+ self:emit_signal("widget::redraw_needed")
+end
+
+
+function icon:get_resize_strategy()
+ return self._private.resize_strategy
+ or beautiful.notification_icon_resize_strategy
+ or "resize"
+end
+
+--- Create a new naughty.widget.icon.
+-- @tparam table args
+-- @tparam naughty.notification args.notification The notification.
+-- @constructorfct naughty.widget.icon
+
+local function new(args)
+ args = args or {}
+ local tb = imagebox()
+
+ gtable.crush(tb, icon, true)
+
+ function tb._private.icon_changed_callback()
+ tb:set_image(tb._private.notification.icon)
+ end
+
+ if args.notification then
+ tb:set_notification(args.notification)
+ end
+
+ return tb
+end
+
+--@DOC_widget_COMMON@
+
+--@DOC_object_COMMON@
+
+return setmetatable(icon, {__call = function(_, ...) return new(...) end})
diff --git a/lib/naughty/widget/init.lua b/lib/naughty/widget/init.lua
new file mode 100644
index 000000000..85858f9ab
--- /dev/null
+++ b/lib/naughty/widget/init.lua
@@ -0,0 +1,11 @@
+---------------------------------------------------------------------------
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @module naughty.widget
+---------------------------------------------------------------------------
+
+return {
+ title = require( "naughty.widget.title" );
+ icon = require( "naughty.widget.icon" );
+ message = require( "naughty.widget.message" );
+}
diff --git a/lib/naughty/widget/message.lua b/lib/naughty/widget/message.lua
new file mode 100644
index 000000000..8a151b87c
--- /dev/null
+++ b/lib/naughty/widget/message.lua
@@ -0,0 +1,86 @@
+----------------------------------------------------------------------------
+--- A notification content message.
+--
+-- This widget is a specialized `wibox.widget.textbox` with the following extra
+-- features:
+--
+-- * Honor the `beautiful` notification variables.
+-- * React to the `naughty.notification` object message changes.
+--
+--@DOC_wibox_nwidget_message_simple_EXAMPLE@
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @widgetmod naughty.widget.message
+-- @see wibox.widget.textbox
+----------------------------------------------------------------------------
+local textbox = require("wibox.widget.textbox")
+local gtable = require("gears.table")
+local beautiful = require("beautiful")
+
+local message = {}
+
+local function markup(notif, wdg)
+ local ret = notif.message or ""
+ local fg = notif.fg or beautiful.notification_fg
+
+ wdg:set_font(notif.font or beautiful.notification_font)
+
+ if fg then
+ ret = "" .. ret .. ""
+ end
+
+ return ret
+end
+
+--- The attached notification.
+-- @property notification
+-- @tparam naughty.notification notification
+
+function message:set_notification(notif)
+ if self._private.notification == notif then return end
+
+ if self._private.notification then
+ self._private.notification:disconnect_signal("poperty::message",
+ self._private.message_changed_callback)
+ self._private.notification:disconnect_signal("poperty::fg",
+ self._private.message_changed_callback)
+ end
+
+ self:set_markup(markup(notif, self))
+
+ self._private.notification = notif
+
+ notif:connect_signal("poperty::message", self._private.message_changed_callback)
+ notif:connect_signal("poperty::fg" , self._private.message_changed_callback)
+end
+
+--- Create a new naughty.widget.message.
+-- @tparam table args
+-- @tparam naughty.notification args.notification The notification.
+-- @constructorfct naughty.widget.message
+
+local function new(args)
+ args = args or {}
+ local tb = textbox()
+ tb:set_wrap("word")
+ tb:set_font(beautiful.notification_font)
+
+ gtable.crush(tb, message, true)
+
+ function tb._private.message_changed_callback()
+ tb:set_markup(markup(tb._private.notification, tb))
+ end
+
+ if args.notification then
+ tb:set_notification(args.notification)
+ end
+
+ return tb
+end
+
+--@DOC_widget_COMMON@
+
+--@DOC_object_COMMON@
+
+return setmetatable(message, {__call = function(_, ...) return new(...) end})
diff --git a/lib/naughty/widget/title.lua b/lib/naughty/widget/title.lua
new file mode 100644
index 000000000..92bf4763f
--- /dev/null
+++ b/lib/naughty/widget/title.lua
@@ -0,0 +1,87 @@
+----------------------------------------------------------------------------
+--- A notification title.
+--
+-- This widget is a specialized `wibox.widget.textbox` with the following extra
+-- features:
+--
+-- * Honor the `beautiful` notification variables.
+-- * React to the `naughty.notification` object title changes.
+--
+--@DOC_wibox_nwidget_title_simple_EXAMPLE@
+--
+-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
+-- @copyright 2017 Emmanuel Lepage Vallee
+-- @widgetmod naughty.widget.title
+-- @see wibox.widget.textbox
+----------------------------------------------------------------------------
+local textbox = require("wibox.widget.textbox")
+local gtable = require("gears.table")
+local beautiful = require("beautiful")
+
+local title = {}
+
+local function markup(notif, wdg)
+ local ret = ""..(notif.title or "")..""
+ local fg = notif.fg or beautiful.notification_fg
+
+ wdg:set_font(notif.font or beautiful.notification_font)
+
+ if fg then
+ ret = "" .. ret .. ""
+ end
+
+ return ret
+end
+
+--- The attached notification.
+-- @property notification
+-- @tparam naughty.notification notification
+
+function title:set_notification(notif)
+ if self._private.notification == notif then return end
+
+ if self._private.notification then
+ self._private.notification:disconnect_signal("poperty::message",
+ self._private.title_changed_callback)
+ self._private.notification:disconnect_signal("poperty::fg",
+ self._private.title_changed_callback)
+ end
+
+ self:set_markup(markup(notif, self))
+
+ self._private.notification = notif
+ self._private.title_changed_callback()
+
+ notif:connect_signal("poperty::title", self._private.title_changed_callback)
+ notif:connect_signal("poperty::fg" , self._private.title_changed_callback)
+end
+
+--- Create a new naughty.widget.title.
+-- @tparam table args
+-- @tparam naughty.notification args.notification The notification.
+-- @constructorfct naughty.widget.title
+
+local function new(args)
+ args = args or {}
+ local tb = textbox()
+ tb:set_wrap("word")
+ tb:set_font(beautiful.notification_font)
+
+ gtable.crush(tb, title, true)
+
+ function tb._private.title_changed_callback()
+ tb:set_markup(markup(tb._private.notification, tb))
+ end
+
+ if args.notification then
+ tb:set_notification(args.notification)
+ end
+
+ return tb
+end
+
+--@DOC_widget_COMMON@
+
+--@DOC_object_COMMON@
+
+return setmetatable(title, {__call = function(_, ...) return new(...) end})
diff --git a/tests/examples/awful/notification/bg.lua b/tests/examples/awful/notification/bg.lua
new file mode 100644
index 000000000..8762be5a7
--- /dev/null
+++ b/tests/examples/awful/notification/bg.lua
@@ -0,0 +1,31 @@
+--DOC_GEN_IMAGE --DOC_NO_USAGE
+require("_default_look") --DOC_HIDE
+local awful = {wibar = require("awful.wibar")} --DOC_HIDE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 240} --DOC_HIDE
+
+local some_wibar = awful.wibar {position = "bottom", height = 48, visible = true} --DOC_HIDE
+
+--DOC_NEWLINE
+
+ -- A notification popup using the default widget_template.
+ naughty.connect_signal("request::display", function(n)
+ naughty.layout.box {notification = n}
+ end)
+
+--DOC_NEWLINE
+
+ -- Notifications as widgets for any `wibox`/`awful.wibar`/`awful.popup`
+ some_wibar.widget = naughty.list.notifications {}
+
+--DOC_NEWLINE
+
+ for _, color in ipairs {"#ff0000", "#00ff00", "#0000ff"} do
+ naughty.notification {
+ title = "A ".. color .." notification",
+ bg = color,
+ }
+ end
+
+require("gears.timer").run_delayed_calls_now()
diff --git a/tests/examples/awful/notification/border_color.lua b/tests/examples/awful/notification/border_color.lua
new file mode 100644
index 000000000..d89affe11
--- /dev/null
+++ b/tests/examples/awful/notification/border_color.lua
@@ -0,0 +1,32 @@
+--DOC_GEN_IMAGE --DOC_NO_USAGE
+require("_default_look") --DOC_HIDE
+local awful = {wibar = require("awful.wibar")} --DOC_HIDE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 240} --DOC_HIDE
+
+local some_wibar = awful.wibar {position = "bottom", height = 48, visible = true} --DOC_HIDE
+
+--DOC_NEWLINE
+
+ -- A notification popup using the default widget_template.
+ naughty.connect_signal("request::display", function(n)
+ naughty.layout.box {notification = n}
+ end)
+
+--DOC_NEWLINE
+
+ -- Notifications as widgets for any `wibox`/`awful.wibar`/`awful.popup`
+ some_wibar.widget = naughty.list.notifications {}
+
+--DOC_NEWLINE
+
+ for bw, color in ipairs {"#ff0000", "#00ff00", "#0000ff"} do
+ naughty.notification {
+ title = "A ".. color .." notification",
+ border_color = color,
+ border_width = bw*2,
+ }
+ end
+
+require("gears.timer").run_delayed_calls_now()
diff --git a/tests/examples/awful/notification/box_corner.lua b/tests/examples/awful/notification/box_corner.lua
new file mode 100644
index 000000000..d1f316c61
--- /dev/null
+++ b/tests/examples/awful/notification/box_corner.lua
@@ -0,0 +1,37 @@
+--DOC_HIDE --DOC_GEN_IMAGE --DOC_NO_USAGE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 480} --DOC_HIDE
+require("_date") --DOC_HIDE
+require("_default_look") --DOC_HIDE
+
+local function ever_longer_messages(iter) --DOC_HIDE
+ local ret = "content! " --DOC_HIDE
+ for _=1, iter do --DOC_HIDE
+ ret = ret.."more! " --DOC_HIDE
+ end --DOC_HIDE
+ return ret --DOC_HIDE
+end --DOC_HIDE
+
+--DOC_NEWLINE
+
+naughty.connect_signal("request::display", function(n) --DOC_HIDE
+ naughty.layout.box {notification = n} --DOC_HIDE
+end) --DOC_HIDE
+
+--DOC_NEWLINE
+
+ for _, pos in ipairs {
+ "top_left" , "top_middle" , "top_right",
+ "bottom_left", "bottom_middle", "bottom_right",
+ } do
+ for i=1, 3 do
+ naughty.notification {
+ position = pos,
+ title = pos .. " " .. i,
+ message = ever_longer_messages(i)
+ }
+ end
+ end
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/awful/notification/box_corner.output.txt b/tests/examples/awful/notification/box_corner.output.txt
new file mode 100644
index 000000000..0e74ebd85
--- /dev/null
+++ b/tests/examples/awful/notification/box_corner.output.txt
@@ -0,0 +1,4 @@
+
+
+
+====================VVVVVV table: 0x5602abbcedd0
diff --git a/tests/examples/awful/notification/corner.lua b/tests/examples/awful/notification/corner.lua
index 539d0b773..b0722be1a 100644
--- a/tests/examples/awful/notification/corner.lua
+++ b/tests/examples/awful/notification/corner.lua
@@ -1,4 +1,5 @@
--DOC_HIDE_ALL
+--DOC_GEN_IMAGE
local naughty = require("naughty") --DOC_HIDE
for _, pos in ipairs {
@@ -13,7 +14,7 @@ for _, pos in ipairs {
naughty.notify {
title = pos,
position = pos,
- text = "",
+ message = "",
}
end
diff --git a/tests/examples/awful/notification/fg.lua b/tests/examples/awful/notification/fg.lua
new file mode 100644
index 000000000..b3f461e85
--- /dev/null
+++ b/tests/examples/awful/notification/fg.lua
@@ -0,0 +1,32 @@
+--DOC_GEN_IMAGE --DOC_NO_USAGE
+require("_default_look") --DOC_HIDE
+local awful = {wibar = require("awful.wibar")} --DOC_HIDE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 240} --DOC_HIDE
+
+local some_wibar = awful.wibar {position = "bottom", height = 48, visible = true} --DOC_HIDE
+
+--DOC_NEWLINE
+
+ -- A notification popup using the default widget_template.
+ naughty.connect_signal("request::display", function(n)
+ naughty.layout.box {notification = n}
+ end)
+
+--DOC_NEWLINE
+
+ -- Notifications as widgets for any `wibox`/`awful.wibar`/`awful.popup`
+ some_wibar.widget = naughty.list.notifications {}
+
+--DOC_NEWLINE
+
+ for _, color in ipairs {"#ff0000", "#00ff00", "#0000ff"} do
+ naughty.notification {
+ title = "A ".. color .." notification",
+ message = "Message",
+ fg = color,
+ }
+ end
+
+require("gears.timer").run_delayed_calls_now()
diff --git a/tests/examples/awful/notification/geometry.lua b/tests/examples/awful/notification/geometry.lua
new file mode 100644
index 000000000..a6a3aab2e
--- /dev/null
+++ b/tests/examples/awful/notification/geometry.lua
@@ -0,0 +1,30 @@
+--DOC_HIDE --DOC_GEN_IMAGE --DOC_NO_USAGE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 480} --DOC_HIDE
+require("_date") --DOC_HIDE
+require("_default_look") --DOC_HIDE
+
+naughty.connect_signal("request::display", function(n) --DOC_HIDE
+ naughty.layout.box {notification = n} --DOC_HIDE
+end) --DOC_HIDE
+
+--DOC_NEWLINE
+
+ for _, pos in ipairs {
+ "top_left" , "top_middle" , "top_right",
+ "bottom_left", "bottom_middle", "bottom_right",
+ } do
+ for i=1, 2 do
+ naughty.notification {
+ position = pos,
+ title = pos .. " " .. i,
+ width = 50*i,
+ height = 50*i,
+ message = "This is a very, very, very, "..
+ "very, very very long message",
+ }
+ end
+ end
+
+--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/awful/notification/margin.lua b/tests/examples/awful/notification/margin.lua
new file mode 100644
index 000000000..ac0da4eac
--- /dev/null
+++ b/tests/examples/awful/notification/margin.lua
@@ -0,0 +1,40 @@
+--DOC_GEN_IMAGE --DOC_NO_USAGE
+require("_default_look") --DOC_HIDE
+local awful = {wibar = require("awful.wibar")} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local naughty = require("naughty") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 240} --DOC_HIDE
+
+local some_wibar = awful.wibar {position = "bottom", height = 48, visible = true} --DOC_HIDE
+
+--DOC_NEWLINE
+
+ -- A notification popup using the default widget_template.
+ naughty.connect_signal("request::display", function(n)
+ naughty.layout.box {notification = n}
+ end)
+
+--DOC_NEWLINE
+
+ -- Notifications as widgets for any `wibox`/`awful.wibar`/`awful.popup`
+ some_wibar.widget = naughty.list.notifications {
+ base_layout = wibox.widget {
+ spacing = beautiful.notification_spacing,
+ layout = wibox.layout.fixed.horizontal
+ },
+ }
+
+--DOC_NEWLINE
+
+ for margin = 10, 20, 5 do
+ naughty.notification {
+ title = "A notification",
+ margin = margin,
+ border_width = 1,
+ border_color = "#ff0000",
+ }
+ end
+
+require("gears.timer").run_delayed_calls_now()
diff --git a/tests/examples/awful/notification/notificationlist/bottombar.lua b/tests/examples/awful/notification/notificationlist/bottombar.lua
new file mode 100644
index 000000000..7e16f78c0
--- /dev/null
+++ b/tests/examples/awful/notification/notificationlist/bottombar.lua
@@ -0,0 +1,129 @@
+--DOC_GEN_IMAGE
+--DOC_NO_USAGE
+require("_date") --DOC_HIDE
+require("_default_look") --DOC_HIDE
+local awful = require("awful") --DOC_HIDE
+local gears = require("gears") --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 240} --DOC_HIDE
+
+--DOC_HIDE Give some context, otherwise it doesn't look like a screen
+local c = client.gen_fake {hide_first=true} --DOC_HIDE
+c:geometry { x = 50, y = 45, height = 100, width = 250} --DOC_HIDE
+c._old_geo = {c:geometry()} --DOC_HIDE
+c:set_label("A client") --DOC_HIDE
+c:emit_signal("request::titlebars", "rules", {})--DOC_HIDE
+
+beautiful.notification_icon_size = 48 --DOC_HIDE
+beautiful.notification_action_label_only = true --DOC_HIDE
+
+--DOC_NEWLINE
+
+ -- This awful.wibar will be placed at the bottom and contain the notifications.
+ local notif_wb = awful.wibar {
+ position = "bottom",
+ height = 48,
+ visible = #naughty.active > 0,
+ }
+
+--DOC_NEWLINE
+
+ notif_wb:setup {
+ nil,
+ {
+ base_layout = wibox.widget {
+ spacing_widget = wibox.widget {
+ orientation = "vertical",
+ span_ratio = 0.5,
+ widget = wibox.widget.separator,
+ },
+ forced_height = 30,
+ spacing = 3,
+ layout = wibox.layout.flex.horizontal
+ },
+ widget_template = {
+ {
+ naughty.widget.icon,
+ {
+ naughty.widget.title,
+ naughty.widget.message,
+ {
+ layout = wibox.widget {
+ -- Adding the `wibox.widget` allows to share a
+ -- single instance for all spacers.
+ spacing_widget = wibox.widget {
+ orientation = "vertical",
+ span_ratio = 0.9,
+ widget = wibox.widget.separator,
+ },
+ spacing = 3,
+ layout = wibox.layout.flex.horizontal
+ },
+ widget = naughty.list.widgets,
+ },
+ layout = wibox.layout.align.vertical
+ },
+ spacing = 10,
+ fill_space = true,
+ layout = wibox.layout.fixed.horizontal
+ },
+ margins = 5,
+ widget = wibox.container.margin
+ },
+ widget = naughty.list.notifications,
+ },
+ -- Add a button to dismiss all notifications, because why not.
+ {
+ {
+ text = "Dismiss all",
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox
+ },
+ buttons = gears.table.join(
+ awful.button({ }, 1, function() naughty.destroy_all_notifications() end)
+ ),
+ forced_width = 75,
+ shape = gears.shape.rounded_bar,
+ shape_border_width = 1,
+ shape_border_color = beautiful.bg_highlight,
+ widget = wibox.container.background
+ },
+ layout = wibox.layout.align.horizontal
+ }
+
+--DOC_NEWLINE
+
+ -- We don't want to have that bar all the time, only when there is content.
+ naughty.connect_signal("property::active", function()
+ notif_wb.visible = #naughty.active > 0
+ end)
+
+
+--DOC_HIDE The delayed make sure the legacy popup gets disabled in time
+gears.timer.run_delayed_calls_now()--DOC_HIDE
+
+for i=1, 3 do --DOC_HIDE
+ naughty.notification { --DOC_HIDE
+ title = "A notification "..i, --DOC_HIDE
+ text = "Be notified! "..i, --DOC_HIDE
+ icon = i%2 == 1 and beautiful.awesome_icon, --DOC_HIDE
+ timeout = 999, --DOC_HIDE
+ actions = { --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Accept "..i, --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Refuse", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ } --DOC_HIDE
+ } --DOC_HIDE
+end --DOC_HIDE
+
+
+require("gears.timer").run_delayed_calls_now()
diff --git a/tests/examples/awful/notification/shape.lua b/tests/examples/awful/notification/shape.lua
new file mode 100644
index 000000000..8b48110e2
--- /dev/null
+++ b/tests/examples/awful/notification/shape.lua
@@ -0,0 +1,42 @@
+--DOC_GEN_IMAGE --DOC_NO_USAGE
+require("_default_look") --DOC_HIDE
+local gears = {shape = require("gears.shape")} --DOC_HIDE
+local awful = {wibar = require("awful.wibar")} --DOC_HIDE
+local naughty = require("naughty") --DOC_HIDE
+
+screen[1]._resize {width = 640, height = 240} --DOC_HIDE
+
+local some_wibar = awful.wibar {position = "bottom", height = 48, visible = true} --DOC_HIDE
+
+--DOC_NEWLINE
+
+ -- A notification popup using the default widget_template.
+ naughty.connect_signal("request::display", function(n)
+ naughty.layout.box {notification = n}
+ end)
+
+--DOC_NEWLINE
+
+ -- Notifications as widgets for any `wibox`/`awful.wibar`/`awful.popup`
+ some_wibar.widget = naughty.list.notifications {}
+
+--DOC_NEWLINE
+
+ local shapes = {
+ gears.shape.octogon,
+ gears.shape.rounded_rect,
+ gears.shape.rounded_bar
+ }
+
+--DOC_NEWLINE
+
+ for idx=1, 3 do
+ naughty.notification {
+ title = "A notification",
+ border_color = "#0000ff",
+ border_width = idx*2,
+ shape = shapes[idx],
+ }
+ end
+
+require("gears.timer").run_delayed_calls_now()
diff --git a/tests/examples/awful/popup/wiboxtypes.lua b/tests/examples/awful/popup/wiboxtypes.lua
index 02e851cba..c6fa28d9d 100644
--- a/tests/examples/awful/popup/wiboxtypes.lua
+++ b/tests/examples/awful/popup/wiboxtypes.lua
@@ -5,6 +5,7 @@
require("_date")
local awful = require("awful")
local gears = require("gears")
+local naughty = require("naughty")
local wibox = require("wibox")
local beautiful = require("beautiful") --DOC_HIDE
local look = require("_default_look")
@@ -136,6 +137,7 @@ local function create_info(text, x, y, width, height)
text = text,
align = "center",
ellipsize = "none",
+ wrap = "word",
widget = wibox.widget.textbox
},
margins = 10,
@@ -170,17 +172,29 @@ local function create_line(x1, y1, x2, y2)
}, {x=x1, y=y1})
end
-create_info("awful.wibar", 200, 50, 100, 30)
+naughty.connect_signal("request::display", function(n)
+ naughty.layout.box {notification = n}
+end)
+
+naughty.notification {
+ title = "A notification",
+ message = "With a message! ....",
+ position = "top_middle",
+}
+
+create_info("awful.wibar", 100, 50, 100, 30)
create_info("awful.titlebar", 250, 350, 100, 30)
create_info("awful.tooltip", 30, 130, 100, 30)
create_info("awful.popup", 450, 240, 100, 30)
+create_info("naughty.layout.box", 255, 110, 130, 30)
create_info("Standard `wibox`", 420, 420, 130, 30)
-create_line(250, 10, 250, 55)
+create_line(150, 10, 150, 55)
create_line(75, 100, 75, 135)
create_line(545, 432, 575, 432)
create_line(500, 165, 500, 245)
create_line(390, 250, 450, 250)
create_line(190, 365, 255, 365)
+create_line(320, 60, 320, 110)
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/naughty/actions.lua b/tests/examples/naughty/actions.lua
index f21d73ef2..34cd8fd43 100644
--- a/tests/examples/naughty/actions.lua
+++ b/tests/examples/naughty/actions.lua
@@ -1,5 +1,6 @@
--DOC_NO_USAGE
--DOC_HIDE_ALL
+--DOC_GEN_IMAGE
-- local naughty = require("naughty")
dbus.notify_send(
diff --git a/tests/examples/naughty/colors.lua b/tests/examples/naughty/colors.lua
index 2149e4297..3a050ed29 100644
--- a/tests/examples/naughty/colors.lua
+++ b/tests/examples/naughty/colors.lua
@@ -1,3 +1,4 @@
+--DOC_GEN_IMAGE
local beautiful = require("beautiful") --DOC_HIDE
@@ -5,7 +6,9 @@ local text = [[An important
notification
]]
-require("naughty").notify {
+--DOC_NEWLINE
+
+require("naughty").notification {
title = "Hello world!",
text = text,
icon = beautiful.icon,
diff --git a/tests/examples/naughty/helloworld.lua b/tests/examples/naughty/helloworld.lua
index 5c6daecce..83eb95739 100644
--- a/tests/examples/naughty/helloworld.lua
+++ b/tests/examples/naughty/helloworld.lua
@@ -1,4 +1,5 @@
--DOC_HIDE_ALL
+--DOC_GEN_IMAGE
-- local naughty = require("naughty")
dbus.notify_send(
diff --git a/tests/examples/naughty/shape.lua b/tests/examples/naughty/shape.lua
index b685b605c..e1a27657a 100644
--- a/tests/examples/naughty/shape.lua
+++ b/tests/examples/naughty/shape.lua
@@ -1,31 +1,36 @@
+--DOC_GEN_IMAGE --DOC_NO_USAGE
local beautiful = require("beautiful") --DOC_HIDE
local gears = {shape=require("gears.shape")} --DOC_HIDE
local naughty = require("naughty") --DOC_HIDE
-local text = [[An important
-notification
-]]
+ local text = [[An important
+ notification
+ ]]
-local shapes = {
- gears.shape.rounded_rect,
- gears.shape.hexagon,
- gears.shape.octogon,
- function(cr, w, h)
- return gears.shape.infobubble(cr, w, h, 20, 10, w/2 - 10)
- end
-}
+--DOC_NEWLINE
-for _, s in ipairs(shapes) do
- naughty.notify {
- title = "Hello world!",
- text = text,
- icon = beautiful.icon,
- shape = s,
- border_width = 3,
- border_color = beautiful.bg_highlight,
- margin = 15,
- }
-end
+ local shapes = {
+ gears.shape.rounded_rect,
+ gears.shape.hexagon,
+ gears.shape.octogon,
+ function(cr, w, h)
+ return gears.shape.infobubble(cr, w, h, 20, 10, w/2 - 10)
+ end
+ }
+
+--DOC_NEWLINE
+
+ for _, s in ipairs(shapes) do
+ naughty.notify {
+ title = "Hello world!",
+ text = text,
+ icon = beautiful.icon,
+ shape = s,
+ border_width = 3,
+ border_color = beautiful.bg_highlight,
+ margin = 15,
+ }
+ end
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/tests/examples/naughty/template.lua b/tests/examples/naughty/template.lua
index ca51770dd..92fd5572d 100644
--- a/tests/examples/naughty/template.lua
+++ b/tests/examples/naughty/template.lua
@@ -1,3 +1,4 @@
+--DOC_GEN_IMAGE
local file_path, image_path = ...
require("_common_template")(...)
local wibox = require("wibox")
diff --git a/tests/examples/wibox/nwidget/actionlist/fancy.lua b/tests/examples/wibox/nwidget/actionlist/fancy.lua
new file mode 100644
index 000000000..e607b5e65
--- /dev/null
+++ b/tests/examples/wibox/nwidget/actionlist/fancy.lua
@@ -0,0 +1,62 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE --DOC_NO_USAGE
+local naughty = { --DOC_HIDE
+ list = {actions = require("naughty.list.actions")}, --DOC_HIDE
+ notification = require("naughty.notification"), --DOC_HIDE
+ action = require("naughty.action") --DOC_HIDE
+} --DOC_HIDE
+local gears = {shape = require("gears.shape")} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification { --DOC_HIDE
+ title = "A notification", --DOC_HIDE
+ message = "This notification has actions!", --DOC_HIDE
+ actions = { --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Accept", --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Refuse", --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Ignore", --DOC_HIDE
+ }, --DOC_HIDE
+ } --DOC_HIDE
+ } --DOC_HIDE
+
+--DOC_NEWLINE
+
+parent:add( wibox.container.background(--DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ base_layout = wibox.widget {
+ spacing = 3,
+ spacing_widget = wibox.widget {
+ orientation = "horizontal",
+ widget = wibox.widget.separator,
+ },
+ layout = wibox.layout.fixed.vertical
+ },
+ widget_template = {
+ {
+ {
+ {
+ id = "text_role",
+ widget = wibox.widget.textbox
+ },
+ widget = wibox.container.place
+ },
+ shape = gears.shape.rounded_rect,
+ shape_border_width = 2,
+ shape_border_color = beautiful.bg_normal,
+ forced_height = 30,
+ widget = wibox.container.background,
+ },
+ margins = 4,
+ widget = wibox.container.margin,
+ },
+ forced_width = 100, --DOC_HIDE
+ widget = naughty.list.actions,
+ }
+,beautiful.bg_normal)) --DOC_HIDE
diff --git a/tests/examples/wibox/nwidget/actionlist/fancy_icons.lua b/tests/examples/wibox/nwidget/actionlist/fancy_icons.lua
new file mode 100644
index 000000000..d341a3cdf
--- /dev/null
+++ b/tests/examples/wibox/nwidget/actionlist/fancy_icons.lua
@@ -0,0 +1,68 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE --DOC_NO_USAGE
+local naughty = { --DOC_HIDE
+ list = {actions = require("naughty.list.actions")}, --DOC_HIDE
+ notification = require("naughty.notification"), --DOC_HIDE
+ action = require("naughty.action") --DOC_HIDE
+} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification { --DOC_HIDE
+ title = "A notification", --DOC_HIDE
+ message = "This notification has actions!", --DOC_HIDE
+ actions = { --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Accept", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Refuse", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Ignore", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ } --DOC_HIDE
+ } --DOC_HIDE
+
+--DOC_NEWLINE
+
+parent:add( wibox.container.background(--DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ forced_width = 250, --DOC_HIDE
+ base_layout = wibox.widget {
+ spacing = 3,
+ spacing_widget = wibox.widget {
+ orientation = "vertical",
+ widget = wibox.widget.separator,
+ },
+ layout = wibox.layout.flex.horizontal
+ },
+ widget_template = {
+ {
+ {
+ {
+ id = "icon_role",
+ forced_height = 16,
+ forced_width = 16,
+ widget = wibox.widget.imagebox
+ },
+ {
+ id = "text_role",
+ widget = wibox.widget.textbox
+ },
+ spacing = 5,
+ layout = wibox.layout.fixed.horizontal
+ },
+ id = "background_role",
+ widget = wibox.container.background,
+ },
+ margins = 4,
+ widget = wibox.container.margin,
+ },
+ widget = naughty.list.actions,
+ }
+,beautiful.bg_normal)) --DOC_HIDE
diff --git a/tests/examples/wibox/nwidget/actionlist/simple.lua b/tests/examples/wibox/nwidget/actionlist/simple.lua
new file mode 100644
index 000000000..672308a96
--- /dev/null
+++ b/tests/examples/wibox/nwidget/actionlist/simple.lua
@@ -0,0 +1,34 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE --DOC_NO_USAGE
+local naughty = { --DOC_HIDE
+ list = {actions = require("naughty.list.actions")}, --DOC_HIDE
+ notification = require("naughty.notification"), --DOC_HIDE
+ action = require("naughty.action") --DOC_HIDE
+} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification {
+ title = "A notification",
+ message = "This notification has actions!",
+ actions = {
+ naughty.action {
+ name = "Accept",
+ },
+ naughty.action {
+ name = "Refuse",
+ },
+ naughty.action {
+ name = "Ignore",
+ },
+ }
+ }
+
+--DOC_NEWLINE
+
+parent:add( wibox.container.background(--DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ widget = naughty.list.actions,
+ }
+,beautiful.bg_normal)) --DOC_HIDE
diff --git a/tests/examples/wibox/nwidget/actionlist/style.lua b/tests/examples/wibox/nwidget/actionlist/style.lua
new file mode 100644
index 000000000..c5cbdd1af
--- /dev/null
+++ b/tests/examples/wibox/nwidget/actionlist/style.lua
@@ -0,0 +1,63 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE --DOC_NO_USAGE
+local naughty = { --DOC_HIDE
+ list = {actions = require("naughty.list.actions")}, --DOC_HIDE
+ notification = require("naughty.notification"), --DOC_HIDE
+ action = require("naughty.action") --DOC_HIDE
+} --DOC_HIDE
+local gears = {shape = require("gears.shape")} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification { --DOC_HIDE
+ title = "A notification", --DOC_HIDE
+ message = "This notification has actions!", --DOC_HIDE
+ actions = { --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Accept", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Refuse", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ selected = true, --DOC_HIDE
+ }, --DOC_HIDE
+ naughty.action { --DOC_HIDE
+ name = "Ignore", --DOC_HIDE
+ icon = beautiful.awesome_icon, --DOC_HIDE
+ }, --DOC_HIDE
+ } --DOC_HIDE
+ } --DOC_HIDE
+
+--DOC_NEWLINE
+
+parent:add( wibox.container.margin(--DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ forced_width = 250, --DOC_HIDE
+ base_layout = wibox.widget {
+ spacing = 3,
+ spacing_widget = wibox.widget {
+ orientation = "vertical",
+ widget = wibox.widget.separator,
+ },
+ layout = wibox.layout.flex.horizontal
+ },
+ style = {
+ underline_normal = false,
+ underline_selected = true,
+ shape_normal = gears.shape.octogon,
+ shape_selected = gears.shape.hexagon,
+ shape_border_width_normal = 2,
+ shape_border_width_selected = 4,
+ icon_size_normal = 16,
+ icon_size_selected = 24,
+ shape_border_color_normal = "#0000ff",
+ shape_border_color_selected = "#ff0000",
+ bg_normal = "#ffff00",
+ bg_selected = "#00ff00",
+ },
+ forced_height = beautiful.get_font_height(beautiful.font) * 2.5,
+ widget = naughty.list.actions,
+ }
+,0,0,5,5)) --DOC_HIDE
diff --git a/tests/examples/wibox/nwidget/default.lua b/tests/examples/wibox/nwidget/default.lua
new file mode 100644
index 000000000..3f670c2ce
--- /dev/null
+++ b/tests/examples/wibox/nwidget/default.lua
@@ -0,0 +1,107 @@
+--DOC_GEN_IMAGE --DOC_HIDE_ALL
+local parent = ...
+local naughty = require("naughty")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local def = require("naughty.widget._default")
+local acommon = require("awful.widget.common")
+local aplace = require("awful.placement")
+local gears = require("gears")
+
+beautiful.notification_bg = beautiful.bg_normal
+
+local notif = naughty.notification {
+ title = "A notification",
+ message = "This notification has actions!",
+ icon = beautiful.awesome_icon,
+ actions = {
+ naughty.action {
+ name = "Accept",
+ icon = beautiful.awesome_icon,
+ },
+ naughty.action {
+ name = "Refuse",
+ icon = beautiful.awesome_icon,
+ },
+ naughty.action {
+ name = "Ignore",
+ icon = beautiful.awesome_icon,
+ },
+ }
+}
+
+local default = wibox.widget(def)
+
+acommon._set_common_property(default, "notification", notif)
+
+local w, h = default:fit({dpi=96}, 9999, 9999)
+default.forced_width = w + 25
+default.forced_height = h
+
+local canvas = wibox.layout.manual()
+canvas.forced_width = w + 150
+canvas.forced_height = h + 100
+
+canvas:add_at(default, aplace.centered)
+
+local function create_info(text, x, y, width, height)
+ canvas:add_at(wibox.widget {
+ {
+ {
+ text = text,
+ align = "center",
+ ellipsize = "none",
+ wrap = "word",
+ widget = wibox.widget.textbox
+ },
+ top = 2,
+ bottom = 2,
+ left = 10,
+ right = 10,
+ widget = wibox.container.margin
+ },
+ forced_width = width,
+ forced_height = height,
+ shape = gears.shape.rectangle,
+ shape_border_width = 1,
+ shape_border_color = beautiful.border_color,
+ bg = "#ffff0055",
+ widget = wibox.container.background
+ }, {x = x, y = y})
+end
+
+local function create_line(x1, y1, x2, y2)
+ return canvas:add_at(wibox.widget {
+ fit = function()
+ return x2-x1+6, y2-y1+6
+ end,
+ draw = function(_, _, cr)
+ cr:set_source_rgb(0,0,0)
+ cr:set_line_width(1)
+ cr:arc(1.5, 1.5, 1.5, 0, math.pi*2)
+ cr:arc(x2-x1+1.5, y2-y1+1.5, 1.5, 0, math.pi*2)
+ cr:fill()
+ cr:move_to(1.5,1.5)
+ cr:line_to(x2-x1+1.5, y2-y1+1.5)
+ cr:stroke()
+ end,
+ layout = wibox.widget.base.make_widget,
+ }, {x=x1, y=y1})
+end
+
+create_info("naughty.widget.background", 10, canvas.forced_height - 30, nil, nil)
+create_line(80, canvas.forced_height-55, 80, canvas.forced_height - 30)
+
+create_info("naughty.list.actions", 170, canvas.forced_height - 30, nil, nil)
+create_line(200, canvas.forced_height-105, 200, canvas.forced_height - 30)
+
+create_info("naughty.widget.icon", 20, 25, nil, nil)
+create_line(80, 40, 80, 60)
+
+create_info("naughty.widget.title", 90, 4, nil, nil)
+create_line(140, 20, 140, 60)
+
+create_info("naughty.widget.message", 150, 25, nil, nil)
+create_line(210, 40, 210, 75)
+
+parent:add(canvas)
diff --git a/tests/examples/wibox/nwidget/icon/simple.lua b/tests/examples/wibox/nwidget/icon/simple.lua
new file mode 100644
index 000000000..50cdac9ad
--- /dev/null
+++ b/tests/examples/wibox/nwidget/icon/simple.lua
@@ -0,0 +1,22 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE
+local naughty = { --DOC_HIDE
+ widget = { icon = require("naughty.widget.icon")}, --DOC_HIDE
+ notification = require("naughty.notification")} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification {
+ title = "A notification",
+ message = "This notification has actions!",
+ icon = beautiful.awesome_icon,
+ }
+
+--DOC_NEWLINE
+
+parent:add( --DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ widget = naughty.widget.icon,
+ }
+) --DOC_HIDE
diff --git a/tests/examples/wibox/nwidget/icon/strategy.lua b/tests/examples/wibox/nwidget/icon/strategy.lua
new file mode 100644
index 000000000..f7e2563fe
--- /dev/null
+++ b/tests/examples/wibox/nwidget/icon/strategy.lua
@@ -0,0 +1,62 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE_ALL
+local naughty = {
+ widget = { icon = require("naughty.widget.icon")},
+ notification = require("naughty.notification"),
+}
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+
+local notif = naughty.notification {
+ title = "A notification",
+ text = "This notification has actions!",
+ icon = beautiful.awesome_icon,
+ actions = {
+ ["Accept"] = function() end,
+ ["Refuse"] = function() end,
+ ["Ignore"] = function() end,
+ }
+}
+
+local icons = {}
+
+for _, strategy in ipairs {"resize", "scale", "center" } do
+ table.insert(icons, wibox.widget {
+ {
+ {
+ resize_strategy = strategy,
+ notification = notif,
+ widget = naughty.widget.icon,
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ },
+ valign = "top",
+ halign = "left",
+ widget = wibox.container.place
+ })
+end
+
+parent:add(
+ wibox.widget {
+ {
+ markup = "resize:",
+ widget = wibox.widget.textbox,
+ },
+ {
+ markup = "scale:",
+ widget = wibox.widget.textbox,
+ },
+ {
+ markup = "center:",
+ widget = wibox.widget.textbox,
+ },
+ icons[1],
+ icons[2],
+ icons[3],
+ forced_num_rows = 2,
+ forced_num_cols = 3,
+ spacing = 5,
+ widget = wibox.layout.grid,
+ }
+)
diff --git a/tests/examples/wibox/nwidget/message/simple.lua b/tests/examples/wibox/nwidget/message/simple.lua
new file mode 100644
index 000000000..fd320e57d
--- /dev/null
+++ b/tests/examples/wibox/nwidget/message/simple.lua
@@ -0,0 +1,22 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE
+local naughty = { --DOC_HIDE
+ widget = { message = require("naughty.widget.message")}, --DOC_HIDE
+ notification = require("naughty.notification")} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification {
+ title = "A notification",
+ message = "This notification no actions!",
+ icon = beautiful.awesome_icon,
+ }
+
+--DOC_NEWLINE
+
+parent:add( --DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ widget = naughty.widget.message,
+ }
+) --DOC_HIDE
diff --git a/tests/examples/wibox/nwidget/title/simple.lua b/tests/examples/wibox/nwidget/title/simple.lua
new file mode 100644
index 000000000..4553041a9
--- /dev/null
+++ b/tests/examples/wibox/nwidget/title/simple.lua
@@ -0,0 +1,22 @@
+--DOC_GEN_IMAGE
+local parent = ... --DOC_HIDE
+local naughty = { --DOC_HIDE
+ widget = { title = require("naughty.widget.title")}, --DOC_HIDE
+ notification = require("naughty.notification")} --DOC_HIDE
+local wibox = require("wibox") --DOC_HIDE
+local beautiful = require("beautiful") --DOC_HIDE
+
+ local notif = naughty.notification {
+ title = "A notification",
+ message = "This notification no actions!",
+ icon = beautiful.awesome_icon,
+ }
+
+--DOC_NEWLINE
+
+parent:add( --DOC_HIDE
+ wibox.widget {
+ notification = notif,
+ widget = naughty.widget.title,
+ }
+) --DOC_HIDE