Make tasklist garbage-collectable

Again, instead of directly connecting to various signals for updating a
tasklist, this commit changes the code so that there is just a single, global
connections and based on this a weak table with all tasklist instances is used
do the updates.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2015-09-27 14:10:45 +02:00
parent 40db0b7337
commit abc5a552a4
2 changed files with 61 additions and 29 deletions

View File

@ -23,6 +23,8 @@ local timer = require("gears.timer")
local tasklist = { mt = {} } local tasklist = { mt = {} }
local instances
-- Public structures -- Public structures
tasklist.filter = {} tasklist.filter = {}
@ -169,7 +171,7 @@ function tasklist.new(screen, filter, buttons, style, update_function, base_widg
local data = setmetatable({}, { __mode = 'k' }) local data = setmetatable({}, { __mode = 'k' })
local queued_update = false local queued_update = false
local u = function () function w._do_tasklist_update()
-- Add a delayed callback for the first update. -- Add a delayed callback for the first update.
if not queued_update then if not queued_update then
timer.delayed_call(function() timer.delayed_call(function()
@ -179,34 +181,56 @@ function tasklist.new(screen, filter, buttons, style, update_function, base_widg
queued_update = true queued_update = true
end end
end end
tag.attached_connect_signal(screen, "property::selected", u) if instances == nil then
tag.attached_connect_signal(screen, "property::activated", u) instances = {}
capi.client.connect_signal("property::urgent", u) local function us(s)
capi.client.connect_signal("property::sticky", u) local i = instances[s]
capi.client.connect_signal("property::ontop", u) if i then
capi.client.connect_signal("property::above", u) for _, tlist in pairs(i) do
capi.client.connect_signal("property::below", u) tlist._do_tasklist_update()
capi.client.connect_signal("property::floating", u) end
capi.client.connect_signal("property::maximized_horizontal", u) end
capi.client.connect_signal("property::maximized_vertical", u)
capi.client.connect_signal("property::minimized", u)
capi.client.connect_signal("property::name", u)
capi.client.connect_signal("property::icon_name", u)
capi.client.connect_signal("property::icon", u)
capi.client.connect_signal("property::skip_taskbar", u)
capi.client.connect_signal("property::screen", function(c, old_screen)
if screen == c.screen or screen == old_screen then
u()
end end
end) local function u()
capi.client.connect_signal("property::hidden", u) for s in ipairs(instances) do
capi.client.connect_signal("tagged", u) us(s)
capi.client.connect_signal("untagged", u) end
capi.client.connect_signal("unmanage", u) end
capi.client.connect_signal("list", u)
capi.client.connect_signal("focus", u) tag.attached_connect_signal(nil, "property::selected", u)
capi.client.connect_signal("unfocus", u) tag.attached_connect_signal(nil, "property::activated", u)
u() capi.client.connect_signal("property::urgent", u)
capi.client.connect_signal("property::sticky", u)
capi.client.connect_signal("property::ontop", u)
capi.client.connect_signal("property::above", u)
capi.client.connect_signal("property::below", u)
capi.client.connect_signal("property::floating", u)
capi.client.connect_signal("property::maximized_horizontal", u)
capi.client.connect_signal("property::maximized_vertical", u)
capi.client.connect_signal("property::minimized", u)
capi.client.connect_signal("property::name", u)
capi.client.connect_signal("property::icon_name", u)
capi.client.connect_signal("property::icon", u)
capi.client.connect_signal("property::skip_taskbar", u)
capi.client.connect_signal("property::screen", function(c, old_screen)
us(c.screen)
us(old_screen)
end)
capi.client.connect_signal("property::hidden", u)
capi.client.connect_signal("tagged", u)
capi.client.connect_signal("untagged", u)
capi.client.connect_signal("unmanage", u)
capi.client.connect_signal("list", u)
capi.client.connect_signal("focus", u)
capi.client.connect_signal("unfocus", u)
end
w._do_tasklist_update()
local list = instances[s]
if not list then
list = setmetatable({}, { __mode = "v" })
instances[screen] = list
end
table.insert(list, w)
return w return w
end end

View File

@ -11,7 +11,8 @@ local errors = {}
local prepare_for_collect = nil local prepare_for_collect = nil
-- Test if some objects can be garbage collected -- Test if some objects can be garbage collected
local function collectable(a, b, c, d, e, f, g, h) local function collectable(a, b, c, d, e, f, g, h, last)
assert(last == nil, "got more arguments than supported")
local objs = setmetatable({ a, b, c, d, e, f, g, h }, { __mode = "v" }) local objs = setmetatable({ a, b, c, d, e, f, g, h }, { __mode = "v" })
a, b, c, d, e, f, g, h = nil, nil, nil, nil, nil, nil, nil, nil a, b, c, d, e, f, g, h = nil, nil, nil, nil, nil, nil, nil, nil
if prepare_for_collect then if prepare_for_collect then
@ -37,12 +38,19 @@ collectable(awful.widget.launcher({ image = cairo.ImageSurface(cairo.Format.ARGB
collectable(awful.widget.prompt()) collectable(awful.widget.prompt())
collectable(awful.widget.textclock()) collectable(awful.widget.textclock())
collectable(awful.widget.layoutbox(1)) collectable(awful.widget.layoutbox(1))
function prepare_for_collect() function prepare_for_collect()
-- Only after doing the pending update can a taglist be GC'd. -- Only after doing the pending update can a taglist be GC'd.
awesome.emit_signal("refresh") awesome.emit_signal("refresh")
end end
collectable(awful.widget.taglist(1, awful.widget.taglist.filter.all)) collectable(awful.widget.taglist(1, awful.widget.taglist.filter.all))
function prepare_for_collect()
-- Only after doing the pending update can a taglist be GC'd.
awesome.emit_signal("refresh")
end
collectable(awful.widget.tasklist(1, awful.widget.tasklist.filter.currenttags))
-- And finally a full wibox -- And finally a full wibox
function prepare_for_collect() function prepare_for_collect()
-- Only after doing the pending repaint can a wibox be GC'd. -- Only after doing the pending repaint can a wibox be GC'd.