From 816188163a9599e738041eb47b13e5add50dcd0d Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 9 Feb 2020 04:00:36 -0500 Subject: [PATCH] naughty: Fix an internal index corruption issue. Due to some signal callbacks, some notifications could be added twice to the by-position index. --- lib/naughty/core.lua | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/naughty/core.lua b/lib/naughty/core.lua index 13519a4aa..bc10e46c8 100644 --- a/lib/naughty/core.lua +++ b/lib/naughty/core.lua @@ -227,6 +227,7 @@ local function remove_from_index(n) for _, ns in pairs(positions) do for k, n2 in ipairs(ns) do if n2 == n then + assert(ns[k+1] ~= n, "The notification index is corrupted") table.remove(ns, k) return end @@ -237,6 +238,11 @@ end -- When id or screen are set after the object is created, update the indexing. local function update_index(n) + -- Do things in the right order. + if not n._private.registered then return end + + assert(not n._private.is_destroyed, "The notification index is corrupted") + -- Find the only index and remove it (there's an useless loop, but it's small). remove_from_index(n) @@ -373,6 +379,9 @@ function naughty.destroy_all_notifications(screens, reason) for _, scr in pairs(screens) do for _, list in pairs(naughty.notifications[scr]) do while #list > 0 do + -- Better cause an error than risk an infinite loop. + assert(not list[1]._private.is_destroyed) + ret = ret and list[1]:destroy(reason) end end @@ -580,14 +589,28 @@ naughty.connect_signal("request::screen", naughty.default_screen_handler) -- @tparam naughty.action action The action. -- @tparam string icon_name The icon name. +--- Emitted when the screen is not defined or being removed. +-- @signal request::screen +-- @tparam table notification The `naughty.notification` object. This is +-- currently either "new" or "removed". +-- @tparam string context Why is the signal sent. + -- Register a new notification object. local function register(notification, args) + assert(not notification._private.registered) + -- Add the some more properties rawset(notification, "get_suspended", get_suspended) local s = get_screen(notification.screen or args.screen - or (notification.preset and notification.preset.screen) - or screen.focused()) + or (notification.preset and notification.preset.screen)) + + if not s then + naughty.emit_signal("request::screen", notification, "new", {}) + s = notification.screen + end + + assert(s) -- insert the notification to the table table.insert(naughty._active, notification) @@ -595,6 +618,8 @@ local function register(notification, args) notification.idx = #naughty.notifications[s][notification.position] notification.screen = s + notification._private.registered = true + if properties.suspended and not args.ignore_suspend then notification._private.args = args table.insert(naughty.notifications.suspended, notification)