awful.titlebar: Fix GC for titlebar widgets (#2830)
Some titlebar widgets (`awful.titlebar.widget.titlewidget`, `awful.titlebar.widget.button` and other specific button widgets) could not be garbage collected until the associated client was unmanaged, because the signal connection used to update the widget was never destroyed, and the signal handling function was keeping a reference to the widget in its environment. This resulted in high memory usage when the titlebar widgets were recreated multiple times for the same client (this does not happen with the default Awesome configuration, but may be needed for dynamic titlebar reconfiguration in a custom config). Modify the code to use weak tables instead of direct signal connections to avoid keeping strong references to widgets. The widget update functions still keep strong references to the widget itself (creating a reference loop, but the Lua GC should handle it correctly) and the client object, but this should not be a problem. One publicly visible change is that `awful.titlebar.widget.titlewidget` now has an `update` function, like the button widgets. Signed-off-by: Sergey Vlasov <sigprof@gmail.com>
This commit is contained in:
parent
1116bc47d0
commit
29f1719026
|
@ -13,6 +13,8 @@
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
local error = error
|
local error = error
|
||||||
|
local pairs = pairs
|
||||||
|
local table = table
|
||||||
local type = type
|
local type = type
|
||||||
local gmath = require("gears.math")
|
local gmath = require("gears.math")
|
||||||
local abutton = require("awful.button")
|
local abutton = require("awful.button")
|
||||||
|
@ -601,6 +603,33 @@ function titlebar.toggle(c, position)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local instances = {}
|
||||||
|
|
||||||
|
-- Do the equivalent of
|
||||||
|
-- c:connect_signal(signal, widget.update)
|
||||||
|
-- without keeping a strong reference to the widget.
|
||||||
|
local function update_on_signal(c, signal, widget)
|
||||||
|
local sig_instances = instances[signal]
|
||||||
|
if sig_instances == nil then
|
||||||
|
sig_instances = setmetatable({}, { __mode = "k" })
|
||||||
|
instances[signal] = sig_instances
|
||||||
|
capi.client.connect_signal(signal, function(cl)
|
||||||
|
local widgets = sig_instances[cl]
|
||||||
|
if widgets then
|
||||||
|
for _, w in pairs(widgets) do
|
||||||
|
w.update()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
local widgets = sig_instances[c]
|
||||||
|
if widgets == nil then
|
||||||
|
widgets = setmetatable({}, { __mode = "v" })
|
||||||
|
sig_instances[c] = widgets
|
||||||
|
end
|
||||||
|
table.insert(widgets, widget)
|
||||||
|
end
|
||||||
|
|
||||||
--- Create a new titlewidget. A title widget displays the name of a client.
|
--- Create a new titlewidget. A title widget displays the name of a client.
|
||||||
-- Please note that this returns a textbox and all of textbox' API is available.
|
-- Please note that this returns a textbox and all of textbox' API is available.
|
||||||
-- This way, you can e.g. modify the font that is used.
|
-- This way, you can e.g. modify the font that is used.
|
||||||
|
@ -612,7 +641,8 @@ function titlebar.widget.titlewidget(c)
|
||||||
local function update()
|
local function update()
|
||||||
ret:set_text(c.name or titlebar.fallback_name)
|
ret:set_text(c.name or titlebar.fallback_name)
|
||||||
end
|
end
|
||||||
c:connect_signal("property::name", update)
|
ret.update = update
|
||||||
|
update_on_signal(c, "property::name", ret)
|
||||||
update()
|
update()
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
@ -717,8 +747,8 @@ function titlebar.widget.button(c, name, selector, action)
|
||||||
|
|
||||||
-- We do magic based on whether a client is focused above, so we need to
|
-- We do magic based on whether a client is focused above, so we need to
|
||||||
-- connect to the corresponding signal here.
|
-- connect to the corresponding signal here.
|
||||||
c:connect_signal("focus", update)
|
update_on_signal(c, "focus", ret)
|
||||||
c:connect_signal("unfocus", update)
|
update_on_signal(c, "unfocus", ret)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
@ -728,7 +758,7 @@ end
|
||||||
-- @staticfct awful.titlebar.widget.floatingbutton
|
-- @staticfct awful.titlebar.widget.floatingbutton
|
||||||
function titlebar.widget.floatingbutton(c)
|
function titlebar.widget.floatingbutton(c)
|
||||||
local widget = titlebar.widget.button(c, "floating", aclient.object.get_floating, aclient.floating.toggle)
|
local widget = titlebar.widget.button(c, "floating", aclient.object.get_floating, aclient.floating.toggle)
|
||||||
c:connect_signal("property::floating", widget.update)
|
update_on_signal(c, "property::floating", widget)
|
||||||
return widget
|
return widget
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -741,7 +771,7 @@ function titlebar.widget.maximizedbutton(c)
|
||||||
end, function(cl, state)
|
end, function(cl, state)
|
||||||
cl.maximized = not state
|
cl.maximized = not state
|
||||||
end)
|
end)
|
||||||
c:connect_signal("property::maximized", widget.update)
|
update_on_signal(c, "property::maximized", widget)
|
||||||
return widget
|
return widget
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -752,7 +782,7 @@ function titlebar.widget.minimizebutton(c)
|
||||||
local widget = titlebar.widget.button(c, "minimize",
|
local widget = titlebar.widget.button(c, "minimize",
|
||||||
function() return "" end,
|
function() return "" end,
|
||||||
function(cl) cl.minimized = not cl.minimized end)
|
function(cl) cl.minimized = not cl.minimized end)
|
||||||
c:connect_signal("property::minimized", widget.update)
|
update_on_signal(c, "property::minimized", widget)
|
||||||
return widget
|
return widget
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -770,7 +800,7 @@ function titlebar.widget.ontopbutton(c)
|
||||||
local widget = titlebar.widget.button(c, "ontop",
|
local widget = titlebar.widget.button(c, "ontop",
|
||||||
function(cl) return cl.ontop end,
|
function(cl) return cl.ontop end,
|
||||||
function(cl, state) cl.ontop = not state end)
|
function(cl, state) cl.ontop = not state end)
|
||||||
c:connect_signal("property::ontop", widget.update)
|
update_on_signal(c, "property::ontop", widget)
|
||||||
return widget
|
return widget
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -781,7 +811,7 @@ function titlebar.widget.stickybutton(c)
|
||||||
local widget = titlebar.widget.button(c, "sticky",
|
local widget = titlebar.widget.button(c, "sticky",
|
||||||
function(cl) return cl.sticky end,
|
function(cl) return cl.sticky end,
|
||||||
function(cl, state) cl.sticky = not state end)
|
function(cl, state) cl.sticky = not state end)
|
||||||
c:connect_signal("property::sticky", widget.update)
|
update_on_signal(c, "property::sticky", widget)
|
||||||
return widget
|
return widget
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue