From b6ce95cd1527f4130e16a9e19f318c87d9cf1155 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 7 Mar 2020 19:29:35 -0500 Subject: [PATCH 1/7] naughty: Improve the rendering of notifications with invalid markup. Some case like `foobar` still fail, but at least `foo<<<>>>bar` works. Fix #3022 --- lib/naughty/widget/_markup.lua | 62 ++++++++++++++++++++++++++++++++++ lib/naughty/widget/message.lua | 23 +++++-------- lib/naughty/widget/title.lua | 23 +++++-------- 3 files changed, 78 insertions(+), 30 deletions(-) create mode 100644 lib/naughty/widget/_markup.lua diff --git a/lib/naughty/widget/_markup.lua b/lib/naughty/widget/_markup.lua new file mode 100644 index 00000000..3077c02b --- /dev/null +++ b/lib/naughty/widget/_markup.lua @@ -0,0 +1,62 @@ +local beautiful = require("beautiful") + +local module = {} + +-- Since some escaping needs to be undone, we have to escape the escaped <>. +local pre_escape = {["<"] = "&zzlt;", [">"] = "&zzgt;"} + +local escape_pattern = "[<>&]" +local escape_subs = { ['<'] = "<", ['>'] = ">", ['&'] = "&" } + +-- Also reverse escaping some allowed tags because people actually use them. +local escape_undo = {['<span '] = "" + escape_undo['</'..allowed..'>'] = "" +end + +-- Best effort attempt to allow a subset of pango markup in the text while +-- removing invalid content. If invalid content is present, nothing is +-- displayed. +local function escape_text(text) + -- Take care of the already escaped content. + for pattern, subs in pairs(pre_escape) do + text = text:gsub(pattern, subs) + end + + -- Try to set the text while only interpreting
. + text = text:gsub("", "\n") + + -- Since the title cannot contain markup, it must be escaped first so that + -- it is not interpreted by Pango later. + text = text:gsub(escape_pattern, escape_subs) + + -- Restore a subset of markup tags. + for pattern, subs in pairs(escape_undo) do + text = text:gsub(pattern, subs) + end + + -- Restore pre-escaped content. + for subs, pattern in pairs(pre_escape) do + text = text:gsub(pattern, subs) + end + + return text +end + +function module.set_markup(wdg, text, fg, font) + local ret = escape_text(text or "") + fg = fg or beautiful.notification_fg + + wdg:set_font(font or beautiful.notification_font) + + if fg then + ret = "" .. ret .. "" + end + + wdg:set_markup_silently(ret) + return ret +end + +return module diff --git a/lib/naughty/widget/message.lua b/lib/naughty/widget/message.lua index c9f31fb7..0dac616e 100644 --- a/lib/naughty/widget/message.lua +++ b/lib/naughty/widget/message.lua @@ -17,22 +17,10 @@ local textbox = require("wibox.widget.textbox") local gtable = require("gears.table") local beautiful = require("beautiful") +local markup = require("naughty.widget._markup").set_markup 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 @@ -48,7 +36,7 @@ function message:set_notification(notif) self._private.message_changed_callback) end - self:set_markup(markup(notif, self)) + markup(self, notif.message, notif.fg, notif.font) self._private.notification = notif @@ -73,7 +61,12 @@ local function new(args) gtable.crush(tb, message, true) function tb._private.message_changed_callback() - tb:set_markup(markup(tb._private.notification, tb)) + markup( + tb, + tb._private.notification.message, + tb._private.notification.fg, + tb._private.notification.font + ) end if args.notification then diff --git a/lib/naughty/widget/title.lua b/lib/naughty/widget/title.lua index 38ce7327..6f35dc2b 100644 --- a/lib/naughty/widget/title.lua +++ b/lib/naughty/widget/title.lua @@ -17,22 +17,10 @@ local textbox = require("wibox.widget.textbox") local gtable = require("gears.table") local beautiful = require("beautiful") +local markup = require("naughty.widget._markup").set_markup 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 @@ -48,7 +36,7 @@ function title:set_notification(notif) self._private.title_changed_callback) end - self:set_markup(markup(notif, self)) + markup(self, notif.title, notif.fg, notif.font) self._private.notification = notif self._private.title_changed_callback() @@ -74,7 +62,12 @@ local function new(args) gtable.crush(tb, title, true) function tb._private.title_changed_callback() - tb:set_markup(markup(tb._private.notification, tb)) + markup( + tb, + tb._private.notification.title, + tb._private.notification.fg, + tb._private.notification.font + ) end if args.notification then From 92d6fcda9248c66fad245eddf37468d2189c2749 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 7 Mar 2020 19:31:58 -0500 Subject: [PATCH 2/7] client: Check if `border_widht` is `nil` before setting it. Fix #3026 --- lib/awful/client.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/awful/client.lua b/lib/awful/client.lua index 631cd979..559bfa93 100644 --- a/lib/awful/client.lua +++ b/lib/awful/client.lua @@ -1478,8 +1478,10 @@ for _, prop in ipairs { "border_width", "border_color", "opacity" } do return self["_"..prop] end client.object["set_"..prop] = function(self, value) - self._private["_user_"..prop] = true - self["_"..prop] = value + if value ~= nil then + self._private["_user_"..prop] = true + self["_"..prop] = value + end end end From d5b652973ff7acac7189eb4b97f4b3e668178f05 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 7 Mar 2020 20:35:33 -0500 Subject: [PATCH 3/7] naughty: Emit `property::icon` when the `image` or `images` change. This way updating the icon at least *can* work. --- lib/naughty/notification.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/naughty/notification.lua b/lib/naughty/notification.lua index 547da80e..f7d1f7b0 100644 --- a/lib/naughty/notification.lua +++ b/lib/naughty/notification.lua @@ -618,6 +618,17 @@ for _, prop in ipairs(properties) do end +-- Changing the image will change the icon, make sure property::icon is emitted. +for _, prop in ipairs {"image", "images" } do + local cur = notification["set_"..prop] + + notification["set_"..prop] = function(self, value) + cur(self, value) + self._private.icon = nil + self:emit_signal("property::icon") + end +end + local hints_default = { urgency = "normal", resident = false, From a69b6123b8883fbf7c21eeadbf0068d2bf1d0520 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 7 Mar 2020 20:36:21 -0500 Subject: [PATCH 4/7] naughty: Fix updating `naughty.widget.icon`. It was never call, untested and obviously broken... --- lib/naughty/widget/icon.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/naughty/widget/icon.lua b/lib/naughty/widget/icon.lua index 971fb84b..4f6b3c61 100644 --- a/lib/naughty/widget/icon.lua +++ b/lib/naughty/widget/icon.lua @@ -153,10 +153,11 @@ local function new(args) gtable.crush(tb, icon, true) function tb._private.icon_changed_callback() + local icn = gsurface.load_silently(tb._private.notification.icon) if icn then - tb:set_image() + tb:set_image(icn) end end From 97e403b4e921aa1747f04018576215c3f4bf1bf1 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sat, 7 Mar 2020 21:24:22 -0500 Subject: [PATCH 5/7] naughty: Correctly scale large square icons. Fix #3005 --- lib/naughty/widget/icon.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/naughty/widget/icon.lua b/lib/naughty/widget/icon.lua index 4f6b3c61..7eeb7db4 100644 --- a/lib/naughty/widget/icon.lua +++ b/lib/naughty/widget/icon.lua @@ -65,7 +65,10 @@ function icon:draw(_, cr, width, height) local x, y = 0, 0 - if (strategy == "center" and aspect > 1) or strategy == "resize" then + if (strategy == "center" and aspect < 1) or strategy == "resize" then + x = math.floor((width - w*aspect) / 2) + y = math.floor((height - h*aspect) / 2) + elseif strategy == "center" and aspect > 1 then x = math.floor((width - w) / 2) y = math.floor((height - h) / 2) end From 21cb4037bc23010829b82f5fb90d8bcecaabff26 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 8 Mar 2020 19:44:16 -0400 Subject: [PATCH 6/7] naughty: Fix updating the icon of DBus notification when passed by path. --- lib/naughty/dbus.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/naughty/dbus.lua b/lib/naughty/dbus.lua index 176371ef..ce7faea2 100644 --- a/lib/naughty/dbus.lua +++ b/lib/naughty/dbus.lua @@ -323,6 +323,13 @@ function notif_methods.Notify(sender, object_path, interface, method, parameters notification[k] = v end + -- Update the icon if necessary. + if app_icon ~= notification._private.app_icon then + notification._private.app_icon = app_icon + notification._private.icon = nil + notification:emit_signal("property::icon") + end + -- Even if no property changed, restart the timeout. notification:reset_timeout() else From b8e00b245f32eb808c24d003ab45b5bb43e316f0 Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 8 Mar 2020 19:48:03 -0400 Subject: [PATCH 7/7] tests: Trigger the widget "update content" code path. --- tests/test-naughty-legacy.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test-naughty-legacy.lua b/tests/test-naughty-legacy.lua index 6ef6542d..945ca779 100644 --- a/tests/test-naughty-legacy.lua +++ b/tests/test-naughty-legacy.lua @@ -1095,6 +1095,11 @@ table.insert(steps, function() assert(not n._private.widget_template_failed) assert(not n.box) + -- Check adding messages later + n.title = "foo" + n.message = "bar" + n.icon = big_icon + n:destroy() handler_called = false @@ -1111,6 +1116,12 @@ table.insert(steps, function() assert(had_error) assert(not n.box) + -- Check changing existing content. + n.title = "bar" + n.message = "foo" + n.icon = big_icon + n.image = small_icon + handler_called = false had_error = false