From 4d2a1d553464db8e29cc9947a9320ef8ca66f364 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 27 Nov 2016 18:09:10 +0100 Subject: [PATCH] wibox.drawable: Support forced screens Up to now, a drawable always figured out the screen that it is on by looking at its position. This causes memleak-like problems with wibars: A wibar has a screen assigned, but its underlying drawable will end up referring to another screen. Via this, we were managing to build a long reference chain of screens and drawable that meant that none of the fake screens that our test suite added could be garbage collected. To fix this, add wibox.drawable._force_screen(s). After this function is called, the normal screen detection based on the position is skipped and instead the given screen is always used. This breaks the above reference chain and things become garbage-collectable. Also, this chains the drawable to the life time of the screen: When the screen becomes invalid (.valid == false), the drawable will stop redrawing. Fixes: https://github.com/awesomeWM/awesome/issues/1237 Signed-off-by: Uli Schlachter --- lib/wibox/drawable.lua | 18 +++++++++++++----- lib/wibox/init.lua | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/wibox/drawable.lua b/lib/wibox/drawable.lua index 268c3282b..af8165f59 100644 --- a/lib/wibox/drawable.lua +++ b/lib/wibox/drawable.lua @@ -30,14 +30,17 @@ local visible_drawables = {} local function get_widget_context(self) local geom = self.drawable:geometry() - local sgeos = {} + local s = self._forced_screen + if not s then + local sgeos = {} - for s in capi.screen do - sgeos[s] = s.geometry + for s in capi.screen do + sgeos[s] = s.geometry + end + + s = grect.get_by_coord(sgeos, geom.x, geom.y) or capi.screen.primary end - local s = grect.get_by_coord(sgeos, geom.x, geom.y) or capi.screen.primary - local context = self._widget_context local dpi = beautiful.xresources.get_dpi(s) if (not context) or context.screen ~= s or context.dpi ~= dpi then @@ -59,6 +62,7 @@ end local function do_redraw(self) if not self.drawable.valid then return end + if self._forced_screen and not self._forced_screen.valid then return end local surf = surface.load_silently(self.drawable.surface, false) -- The surface can be nil if the drawable's parent was already finalized @@ -274,6 +278,10 @@ function drawable:set_fg(c) self._do_complete_repaint() end +function drawable:_force_screen(s) + self._forced_screen = s +end + function drawable:_inform_visible(visible) self._visible = visible if visible then diff --git a/lib/wibox/init.lua b/lib/wibox/init.lua index aa4f42d8d..e9c22b634 100644 --- a/lib/wibox/init.lua +++ b/lib/wibox/init.lua @@ -86,6 +86,7 @@ function wibox:set_screen(s) -- Remember this screen so things work correctly if screens overlap and -- (x,y) is not enough to figure out the correct screen. self.screen_assigned = s + self._drawable:_force_screen(s) end for _, k in pairs{ "buttons", "struts", "geometry", "get_xproperty", "set_xproperty" } do