From 916b49bde0d53f354e8ac4da2cf3c49f2d0d5527 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:49:11 -0400 Subject: [PATCH 01/23] naughty: Add an actionlist widget. This widget allows to use the actions without all the boilerplate code associated with managing a list. --- lib/naughty/init.lua | 2 + lib/naughty/layout/init.lua | 2 +- lib/naughty/list/actions.lua | 324 +++++++++++++++++++++++++++++++++++ lib/naughty/list/init.lua | 9 + lib/naughty/widget/init.lua | 8 + 5 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 lib/naughty/list/actions.lua create mode 100644 lib/naughty/list/init.lua create mode 100644 lib/naughty/widget/init.lua diff --git a/lib/naughty/init.lua b/lib/naughty/init.lua index 2a096df5c..4450538c8 100644 --- a/lib/naughty/init.lua +++ b/lib/naughty/init.lua @@ -10,7 +10,9 @@ 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.notification = require("naughty.notification") return naughty diff --git a/lib/naughty/layout/init.lua b/lib/naughty/layout/init.lua index c6df968a1..5b49aba35 100644 --- a/lib/naughty/layout/init.lua +++ b/lib/naughty/layout/init.lua @@ -5,5 +5,5 @@ --------------------------------------------------------------------------- return { - legacy = require("naughty.layout.legacy") + legacy = require( "naughty.layout.legacy" ); } 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..6e74e739b --- /dev/null +++ b/lib/naughty/list/init.lua @@ -0,0 +1,9 @@ +--------------------------------------------------------------------------- +-- @author Emmanuel Lepage Vallee <elv1313@gmail.com> +-- @copyright 2017-2019 Emmanuel Lepage Vallee +-- @module naughty.list +--------------------------------------------------------------------------- + +return { + actions = require( "naughty.list.actions" ); +} diff --git a/lib/naughty/widget/init.lua b/lib/naughty/widget/init.lua new file mode 100644 index 000000000..b76f3cab3 --- /dev/null +++ b/lib/naughty/widget/init.lua @@ -0,0 +1,8 @@ +--------------------------------------------------------------------------- +-- @author Emmanuel Lepage Vallee <elv1313@gmail.com> +-- @copyright 2017 Emmanuel Lepage Vallee +-- @module naughty.widget +--------------------------------------------------------------------------- + +return { +} From 3592d33b6cacf99712dbf0e4f53103b7184efab7 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:50:19 -0400 Subject: [PATCH 02/23] naughty: Add a title widget. It is a normal textbox with some extra boilerplate code. Having this in a separate widget allows the notification to be defined from rc.lua without a ton of beautiful options and connect_signal. --- lib/naughty/widget/init.lua | 1 + lib/naughty/widget/title.lua | 87 ++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 lib/naughty/widget/title.lua diff --git a/lib/naughty/widget/init.lua b/lib/naughty/widget/init.lua index b76f3cab3..ff74b5387 100644 --- a/lib/naughty/widget/init.lua +++ b/lib/naughty/widget/init.lua @@ -5,4 +5,5 @@ --------------------------------------------------------------------------- return { + title = require( "naughty.widget.title" ); } 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}) From f31afd8cb79ec4a0f361e5b37c5dfe8d7e735bfc Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:50:19 -0400 Subject: [PATCH 03/23] naughty: Add an icon widget. This tracks the notification icon and add some resize strategies. --- lib/naughty/widget/icon.lua | 158 ++++++++++++++++++++++++++++++++++++ lib/naughty/widget/init.lua | 1 + 2 files changed, 159 insertions(+) create mode 100644 lib/naughty/widget/icon.lua 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 index ff74b5387..ff7c632bd 100644 --- a/lib/naughty/widget/init.lua +++ b/lib/naughty/widget/init.lua @@ -6,4 +6,5 @@ return { title = require( "naughty.widget.title" ); + icon = require( "naughty.widget.icon" ); } From cf364a7b356f1672f50a89f256a34b9650dd1f19 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:50:19 -0400 Subject: [PATCH 04/23] naughty: Add a `message` widget. It tracks the notification message. --- lib/naughty/widget/init.lua | 5 +- lib/naughty/widget/message.lua | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 lib/naughty/widget/message.lua diff --git a/lib/naughty/widget/init.lua b/lib/naughty/widget/init.lua index ff7c632bd..85858f9ab 100644 --- a/lib/naughty/widget/init.lua +++ b/lib/naughty/widget/init.lua @@ -5,6 +5,7 @@ --------------------------------------------------------------------------- return { - title = require( "naughty.widget.title" ); - icon = require( "naughty.widget.icon" ); + 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}) From 5b5a25a57c603ba1aba83253c4e77fa6ba403bc7 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Tue, 12 Mar 2019 14:23:09 -0400 Subject: [PATCH 05/23] naughty: Add a background widget. There is some boilerplate code that make using the widget_template harder when using the raw `wibox.container.background`. This widget takes care of it. --- lib/naughty/container/background.lua | 99 ++++++++++++++++++++++++++++ lib/naughty/container/init.lua | 9 +++ lib/naughty/init.lua | 2 + 3 files changed, 110 insertions(+) create mode 100644 lib/naughty/container/background.lua create mode 100644 lib/naughty/container/init.lua 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/init.lua b/lib/naughty/init.lua index 4450538c8..e94f366d3 100644 --- a/lib/naughty/init.lua +++ b/lib/naughty/init.lua @@ -13,6 +13,8 @@ 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 From 6e50ee2a41507ce5bc166ff2b837b99eee7f9fd2 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Tue, 12 Mar 2019 14:25:23 -0400 Subject: [PATCH 06/23] naughty: Add a shared default widget_template for the notifications. This will be shared by the notifications stored in a wibox/wibar and the ones using a popup. It extends the constraint and margins container to take care of some boilerplate code. While other widgets have their own public API, those 2 are private since they are not different enough to warrent a new public module. --- lib/naughty/widget/_default.lua | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 lib/naughty/widget/_default.lua 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, +} From d8d80ec69a05f0c96dec274d5d08b3f09539745a Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 28 May 2018 20:53:06 -0400 Subject: [PATCH 07/23] naughty: Add the `awful.popup` based notification `box` It replaces the legacy box popup. --- lib/naughty/layout/box.lua | 261 +++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 lib/naughty/layout/box.lua 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}) From 44e9ecdd304bb1f2a02470f2e990532c137b35ff Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 6 Mar 2019 23:45:11 -0500 Subject: [PATCH 08/23] naughty: Add an awful.widget.common based "notification list" This layout allows to place a list of notifications in a wibar or popup. --- lib/naughty/layout/init.lua | 1 + lib/naughty/list/init.lua | 1 + lib/naughty/list/notifications.lua | 356 +++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 lib/naughty/list/notifications.lua diff --git a/lib/naughty/layout/init.lua b/lib/naughty/layout/init.lua index 5b49aba35..11b187f35 100644 --- a/lib/naughty/layout/init.lua +++ b/lib/naughty/layout/init.lua @@ -6,4 +6,5 @@ return { legacy = require( "naughty.layout.legacy" ); + box = require( "naughty.layout.box" ); } diff --git a/lib/naughty/list/init.lua b/lib/naughty/list/init.lua index 6e74e739b..46470f127 100644 --- a/lib/naughty/list/init.lua +++ b/lib/naughty/list/init.lua @@ -6,4 +6,5 @@ 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 From 8951b8809558ca3f54ae6af227c07e9d7a204f8e Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:59:30 -0400 Subject: [PATCH 09/23] doc: Document the new template widget delegate system. --- docs/03-declarative-layout.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/03-declarative-layout.md b/docs/03-declarative-layout.md index 0ba6e931f..19b8479e2 100644 --- a/docs/03-declarative-layout.md +++ b/docs/03-declarative-layout.md @@ -424,3 +424,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 +allow 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 an 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.widget.box`. These templates are **table** +using the exact same syntax as the declarative widgets, but without the +`wibox.widget` prefix in front of the curly braces. These template 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 point 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. From 7bf1a276eff2c29f01669692d474b0db4f085ce9 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 4 Mar 2019 16:56:15 -0500 Subject: [PATCH 10/23] naughty: Use cleaner code to update the legacy actions. The old code surprisingly worked, but reading this again, better make some changes. --- lib/naughty/notification.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index d7f2a77cc..2e0b34cd6 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -380,16 +380,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 +403,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 +504,7 @@ local function create(args) rawget(n, "preset") or {} )) - if is_old_action then + if is_old_action then convert_actions(args.actions) end From 9acc452b1e0045d7ae8b7bc6789a2a291221dd6c Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 4 Mar 2019 17:01:36 -0500 Subject: [PATCH 11/23] naughty: Set an action table even if the notification has none. Less `if` in the code. --- docs/03-declarative-layout.md | 16 ++++++++-------- lib/naughty/notification.lua | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/03-declarative-layout.md b/docs/03-declarative-layout.md index 19b8479e2..d52efa78c 100644 --- a/docs/03-declarative-layout.md +++ b/docs/03-declarative-layout.md @@ -429,20 +429,20 @@ Code: 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 -allow to instantiate various elements when a new screen is added. In the later +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 an another abstract widget has +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.widget.box`. These templates are **table** -using the exact same syntax as the declarative widgets, but without the -`wibox.widget` prefix in front of the curly braces. These template represents -future widgets that will be created by their parent widget. This is necessary -for three reasons: +`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 point in + * 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). diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index 2e0b34cd6..f363a288d 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -516,6 +516,10 @@ 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 {} + -- It's an automatic property n.is_expired = false From fded165e41c09497cf8c01c3d71b410c3af49524 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 4 Mar 2019 17:06:42 -0500 Subject: [PATCH 12/23] doc: Document how to select different shapes based on the content. --- lib/naughty/notification.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index f363a288d..aa4145fdb 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -161,7 +161,17 @@ local notification = {} -- @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_naughty_shape_EXAMPLE@ +-- -- @property shape -- @param gears.shape From 4be58fb298d767f17b3caebe30a4eaa4603441d4 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 4 Mar 2019 22:47:36 -0500 Subject: [PATCH 13/23] naughty: Add an `icon_only` property to the action object. --- lib/naughty/action.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/naughty/action.lua b/lib/naughty/action.lua index 28e0de033..6d871da1e 100644 --- a/lib/naughty/action.lua +++ b/lib/naughty/action.lua @@ -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 From d956b5411b5432165c3fe9124503deb37f830294 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Mon, 4 Mar 2019 22:48:21 -0500 Subject: [PATCH 14/23] naughty: Initialize the action `notification` property --- lib/naughty/notification.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index aa4145fdb..fed40fa8b 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -530,6 +530,12 @@ local function create(args) -- 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 From 4aaf6ea73080ac407b289e4e44dc633ca0e98f7f Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Fri, 8 Mar 2019 14:39:38 -0500 Subject: [PATCH 15/23] naughty: Only enable the legacy mode when there is no other handlers. It was called legacy for a reason, it is meant to be used only when the rc.lua doesn't have the newer notification section. --- lib/naughty/core.lua | 10 +++++++++- lib/naughty/layout/legacy.lua | 21 ++++----------------- lib/naughty/notification.lua | 3 ++- 3 files changed, 15 insertions(+), 19 deletions(-) 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/layout/legacy.lua b/lib/naughty/layout/legacy.lua index c09732906..f374ed0fc 100644 --- a/lib/naughty/layout/legacy.lua +++ b/lib/naughty/layout/legacy.lua @@ -279,23 +279,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. @@ -561,4 +548,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/notification.lua b/lib/naughty/notification.lua index fed40fa8b..7fd39a87d 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -551,7 +551,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 From 9a7a313719f21437e5f37824b7ab4c76fa15fbf8 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Fri, 8 Mar 2019 14:41:52 -0500 Subject: [PATCH 16/23] naughty: Destroy the notification when an action is executed. Whoops, I changed the name of the method at some point and never updated this instance. It was also not clausing the notification like people expect. --- lib/naughty/layout/legacy.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/naughty/layout/legacy.lua b/lib/naughty/layout/legacy.lua index f374ed0fc..64572e30c 100644 --- a/lib/naughty/layout/legacy.lua +++ b/lib/naughty/layout/legacy.lua @@ -402,8 +402,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) From c47402d002257d7f9de39b41ad8a59fd5be311f7 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Tue, 12 Mar 2019 14:19:58 -0400 Subject: [PATCH 17/23] doc: Add an image for the position of naughty.layout.legacy --- lib/naughty/layout/legacy.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/naughty/layout/legacy.lua b/lib/naughty/layout/legacy.lua index 64572e30c..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 From 5261165be4c7a268a0db7bd65b6ee0611d30115a Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Tue, 12 Mar 2019 14:30:15 -0400 Subject: [PATCH 18/23] doc: Add many more examples to naughty.notification Also document the `test` property as deprecated. It exists because the older API (`naughty.notify`) had it. It exists on purpose in the rewrite, it cannot just be removed even if it was never in a release. --- lib/naughty/notification.lua | 37 ++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index 7fd39a87d..e9fb8d6c9 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,6 +176,9 @@ local notification = {} -- @see title --- Border color. +-- +--@DOC_awful_notification_border_color_EXAMPLE@ +-- -- @property border_color -- @param string -- @see title @@ -170,6 +194,8 @@ local notification = {} -- 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 @@ -180,6 +206,9 @@ local notification = {} -- @param number From 0 to 1 --- Widget margin. +-- +--@DOC_awful_notification_margin_EXAMPLE@ +-- -- @property margin -- @tparam number|table margin -- @see shape From 9be03b528c637fd8d8f43d4486071ba72c944e0f Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Tue, 12 Mar 2019 14:38:09 -0400 Subject: [PATCH 19/23] doc: Mentions the notifications in the widget page. --- docs/03-declarative-layout.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/03-declarative-layout.md b/docs/03-declarative-layout.md index d52efa78c..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. From c97cb5c28266f977b4a2ead954cffa0783c562a3 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:54:03 -0400 Subject: [PATCH 20/23] tests: Test the new naughty.widgets This commit also add some "magic" comments to existing tests so they render correctly. Note that some older commits predates these "magic" comments, which is why they are not there. --- tests/examples/awful/notification/bg.lua | 31 +++++ .../awful/notification/border_color.lua | 32 +++++ .../awful/notification/box_corner.lua | 37 +++++ .../awful/notification/box_corner.output.txt | 4 + tests/examples/awful/notification/corner.lua | 3 +- tests/examples/awful/notification/fg.lua | 32 +++++ .../examples/awful/notification/geometry.lua | 30 ++++ tests/examples/awful/notification/margin.lua | 40 ++++++ .../notificationlist/bottombar.lua | 129 ++++++++++++++++++ tests/examples/awful/notification/shape.lua | 42 ++++++ tests/examples/awful/popup/wiboxtypes.lua | 18 ++- tests/examples/naughty/actions.lua | 1 + tests/examples/naughty/colors.lua | 5 +- tests/examples/naughty/helloworld.lua | 1 + tests/examples/naughty/shape.lua | 49 ++++--- tests/examples/naughty/template.lua | 1 + .../wibox/nwidget/actionlist/fancy.lua | 62 +++++++++ .../wibox/nwidget/actionlist/fancy_icons.lua | 68 +++++++++ .../wibox/nwidget/actionlist/simple.lua | 34 +++++ .../wibox/nwidget/actionlist/style.lua | 63 +++++++++ tests/examples/wibox/nwidget/default.lua | 107 +++++++++++++++ tests/examples/wibox/nwidget/icon/simple.lua | 22 +++ .../examples/wibox/nwidget/icon/strategy.lua | 62 +++++++++ .../examples/wibox/nwidget/message/simple.lua | 22 +++ tests/examples/wibox/nwidget/title/simple.lua | 22 +++ 25 files changed, 891 insertions(+), 26 deletions(-) create mode 100644 tests/examples/awful/notification/bg.lua create mode 100644 tests/examples/awful/notification/border_color.lua create mode 100644 tests/examples/awful/notification/box_corner.lua create mode 100644 tests/examples/awful/notification/box_corner.output.txt create mode 100644 tests/examples/awful/notification/fg.lua create mode 100644 tests/examples/awful/notification/geometry.lua create mode 100644 tests/examples/awful/notification/margin.lua create mode 100644 tests/examples/awful/notification/notificationlist/bottombar.lua create mode 100644 tests/examples/awful/notification/shape.lua create mode 100644 tests/examples/wibox/nwidget/actionlist/fancy.lua create mode 100644 tests/examples/wibox/nwidget/actionlist/fancy_icons.lua create mode 100644 tests/examples/wibox/nwidget/actionlist/simple.lua create mode 100644 tests/examples/wibox/nwidget/actionlist/style.lua create mode 100644 tests/examples/wibox/nwidget/default.lua create mode 100644 tests/examples/wibox/nwidget/icon/simple.lua create mode 100644 tests/examples/wibox/nwidget/icon/strategy.lua create mode 100644 tests/examples/wibox/nwidget/message/simple.lua create mode 100644 tests/examples/wibox/nwidget/title/simple.lua 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 From 47750f62b293350c1740bb6f785e06fe065f8e92 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Wed, 13 Mar 2019 17:22:12 -0400 Subject: [PATCH 21/23] doc: Hide the empty notifications modules --- docs/config.ld | 4 ++++ 1 file changed, 4 insertions(+) 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 From 90396f33e79f34cdaef28cd2f49014187610484b Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 8 Jun 2019 18:28:39 -0400 Subject: [PATCH 22/23] doc: Tag the callback properties as deprecated. They exists to comply with the old `naughty.notify` API. They should not be used for new code. --- lib/naughty/notification.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index e9fb8d6c9..dbdb94294 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -214,12 +214,20 @@ local notification = {} -- @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 From 1b4d667b673487d760b47e6d34ce4948e42f96ab Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 8 Jun 2019 18:55:04 -0400 Subject: [PATCH 23/23] doc: Update to the newer doc conventions. --- lib/naughty/action.lua | 6 +++++- lib/naughty/notification.lua | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/naughty/action.lua b/lib/naughty/action.lua index 6d871da1e..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") @@ -101,6 +101,10 @@ for _, prop in ipairs { "name", "icon", "notification", "icon_only" } 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/notification.lua b/lib/naughty/notification.lua index dbdb94294..5004cfc71 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -199,11 +199,11 @@ local notification = {} --@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. --