wibox: Fix __to_string and garbage collection.

There was no "real" unsolvable GC issues, but at least for Lua
5.2 and 5.3, it wasn't possible to GC a wibox anymore. This
commit unwind the circular references with 3 new weak refs. This
is enough to get a specific test to pass on Lua 5.3. It's voodoo,
but this was actually a pretty bad leak. There's other according
to some test I wrote, but that's one.

As for to_string, it appears to be accidental refactoring oversight.
This commit is contained in:
Emmanuel Lepage Vallee 2023-08-12 20:30:45 -07:00
parent 9a3b6fe2a2
commit 16b92a0614
2 changed files with 28 additions and 9 deletions

View File

@ -55,6 +55,10 @@ local function get_widget_context(self)
for k, v in pairs(self._widget_context_skeleton) do
context[k] = v
end
-- Set the metatable to give access to the weak wibox.
setmetatable(context, getmetatable(self._widget_context_skeleton))
self._widget_context = context
-- Give widgets a chance to react to the new context

View File

@ -254,7 +254,10 @@ local function setup_signals(w)
local function clone_signal(name)
-- When "name" is emitted on wibox.drawin, also emit it on wibox
obj:connect_signal(name, function(_, ...)
w:emit_signal(name, ...)
local wb = obj.get_wibox()
if wb then
wb:emit_signal(name, ...)
end
end)
end
@ -296,16 +299,30 @@ local function new(args)
local ret = object()
local w = capi.drawin(args)
local weak_wibox = setmetatable({ret}, {__mode = "v"})
-- Strong ref
function w.get_wibox()
return ret
end
ret.drawin = w
ret._drawable = wibox.drawable(w.drawable, { wibox = ret },
-- Do not pass a strong reference to the wibox, it will confuse the GC.
local context_skeleton = setmetatable({}, {
__index = function(_, key)
if key == "wibox" then return weak_wibox[1] end
return nil
end
})
ret._drawable = wibox.drawable(w.drawable, context_skeleton,
"wibox drawable (" .. object.modulename(3) .. ")")
-- Weak ref
function ret._drawable.get_wibox()
return ret
return weak_wibox[1]
end
ret._drawable:_inform_visible(w.visible)
@ -328,13 +345,7 @@ local function new(args)
ret:set_fg(args.fg or beautiful.fg_normal)
-- Add __tostring method to metatable.
local mt = {}
local orig_string = tostring(ret)
mt.__tostring = function()
return string.format("wibox: %s (%s)",
tostring(ret._drawable), orig_string)
end
ret = setmetatable(ret, mt)
-- Make sure the wibox is drawn at least once
ret.draw()
@ -359,6 +370,10 @@ local function new(args)
else
rawset(self, k, v)
end
end,
__tostring = function()
return string.format("wibox: %s (%s)",
tostring(ret._drawable), orig_string)
end
})