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 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 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, 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/icon.lua b/lib/naughty/widget/icon.lua index 971fb84b..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 @@ -153,10 +156,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 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 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