From abc5a552a494b5cab0a842afb50cebf7a4fa4c52 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 27 Sep 2015 14:10:45 +0200 Subject: [PATCH] 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 --- lib/awful/widget/tasklist.lua | 80 +++++++++++++++++++++++------------ tests/test-leaks.lua | 10 ++++- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/lib/awful/widget/tasklist.lua b/lib/awful/widget/tasklist.lua index 401fe531c..294f0305e 100644 --- a/lib/awful/widget/tasklist.lua +++ b/lib/awful/widget/tasklist.lua @@ -23,6 +23,8 @@ local timer = require("gears.timer") local tasklist = { mt = {} } +local instances + -- Public structures tasklist.filter = {} @@ -169,7 +171,7 @@ function tasklist.new(screen, filter, buttons, style, update_function, base_widg local data = setmetatable({}, { __mode = 'k' }) local queued_update = false - local u = function () + function w._do_tasklist_update() -- Add a delayed callback for the first update. if not queued_update then timer.delayed_call(function() @@ -179,34 +181,56 @@ function tasklist.new(screen, filter, buttons, style, update_function, base_widg queued_update = true end end - tag.attached_connect_signal(screen, "property::selected", u) - tag.attached_connect_signal(screen, "property::activated", 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) - if screen == c.screen or screen == old_screen then - u() + if instances == nil then + instances = {} + local function us(s) + local i = instances[s] + if i then + for _, tlist in pairs(i) do + tlist._do_tasklist_update() + end + end end - 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) - u() + local function u() + for s in ipairs(instances) do + us(s) + end + end + + tag.attached_connect_signal(nil, "property::selected", u) + tag.attached_connect_signal(nil, "property::activated", 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 end diff --git a/tests/test-leaks.lua b/tests/test-leaks.lua index b7639642e..dd36ab9a7 100644 --- a/tests/test-leaks.lua +++ b/tests/test-leaks.lua @@ -11,7 +11,8 @@ local errors = {} local prepare_for_collect = nil -- 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" }) a, b, c, d, e, f, g, h = nil, nil, nil, nil, nil, nil, nil, nil 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.textclock()) collectable(awful.widget.layoutbox(1)) + function prepare_for_collect() -- Only after doing the pending update can a taglist be GC'd. awesome.emit_signal("refresh") end 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 function prepare_for_collect() -- Only after doing the pending repaint can a wibox be GC'd.