diff --git a/lib/wibox/layout/align.lua.in b/lib/wibox/layout/align.lua.in index 1631c68e..8465560b 100644 --- a/lib/wibox/layout/align.lua.in +++ b/lib/wibox/layout/align.lua.in @@ -28,10 +28,10 @@ function align:draw(wibox, cr, width, height) if self.first then local w, h, _ = width, height, nil if self.dir == "y" then - _, h = self.first:fit(w, h) + _, h = base.fit_widget(self.first, w, h) size_first = h else - w, _ = self.first:fit(w, h) + w, _ = base.fit_widget(self.first, w, h) size_first = w end base.draw_widget(wibox, cr, self.first, 0, 0, w, h) @@ -41,12 +41,12 @@ function align:draw(wibox, cr, width, height) local w, h, x, y, _ if self.dir == "y" then w, h = width, height - size_first - _, h = self.third:fit(w, h) + _, h = base.fit_widget(self.third, w, h) x, y = 0, height - h size_third = h else w, h = width - size_first, height - w, _ = self.third:fit(w, h) + w, _ = base.fit_widget(self.third, w, h) x, y = width - w, 0 size_third = w end @@ -57,12 +57,12 @@ function align:draw(wibox, cr, width, height) local x, y, w, h if self.dir == "y" then w, h = width, size_limit - size_first - size_third - local real_w, real_h = self.second:fit(w, h) + local real_w, real_h = base.fit_widget(self.second, w, h) x, y = 0, size_first + h / 2 - real_h / 2 h = real_h else w, h = size_limit - size_first - size_third, height - local real_w, real_h = self.second:fit(w, h) + local real_w, real_h = base.fit_widget(self.second, w, h) x, y = size_first + w / 2 - real_w / 2, 0 w = real_w end @@ -108,7 +108,7 @@ function align:fit(orig_width, orig_height) local used_max = 0 for k, v in pairs{self.first, self.second, self.third} do - local w, h = v:fit(orig_width, orig_height) + local w, h = base.fit_widget(v, orig_width, orig_height) local max = self.dir == "y" and w or h diff --git a/lib/wibox/layout/base.lua.in b/lib/wibox/layout/base.lua.in index 0d7e787b..f0f99646 100644 --- a/lib/wibox/layout/base.lua.in +++ b/lib/wibox/layout/base.lua.in @@ -26,6 +26,27 @@ function base.rect_to_device_geometry(cr, x, y, width, height) return x, y, width, height end +--- Fit a widget for the given available width and height +-- @param widget The widget to fit (this uses widget:fit(width, height)). +-- @param width The available width for the widget +-- @param height The available height for the widget +-- @return The width and height that the widget wants to use +function base.fit_widget(widget, width, height) + local cache = widget._fit_geometry_cache + local result = cache[width] + if not result then + result = {} + cache[width] = result + end + cache, result = result, result[height] + if not result then + local w, h = widget:fit(width, height) + result = { width = w, height = h } + cache[height] = result + end + return result.width, result.height +end + --- Draw a widget via a cairo context -- @param wibox The wibox on which we are drawing -- @param cr The cairo context used diff --git a/lib/wibox/layout/constraint.lua.in b/lib/wibox/layout/constraint.lua.in index 9f75f032..0870f8b2 100644 --- a/lib/wibox/layout/constraint.lua.in +++ b/lib/wibox/layout/constraint.lua.in @@ -30,7 +30,7 @@ function constraint:fit(width, height) w = self._strategy(width, self._width) h = self._strategy(height, self._height) - w, h = self.widget:fit(w, h) + w, h = base.fit_widget(self.widget, w, h) else w, h = 0, 0 end diff --git a/lib/wibox/layout/fixed.lua.in b/lib/wibox/layout/fixed.lua.in index bb898f6a..ef800b45 100644 --- a/lib/wibox/layout/fixed.lua.in +++ b/lib/wibox/layout/fixed.lua.in @@ -28,7 +28,7 @@ function fixed:draw(wibox, cr, width, height) x, y = 0, pos w, h = width, height - pos if k ~= #self.widgets or not self.fill_space then - _, h = v:fit(w, h); + _, h = base.fit_widget(v, w, h); end pos = pos + h in_dir = h @@ -36,7 +36,7 @@ function fixed:draw(wibox, cr, width, height) x, y = pos, 0 w, h = width - pos, height if k ~= #self.widgets or not self.fill_space then - w, _ = v:fit(w, h); + w, _ = base.fit_widget(v, w, h); end pos = pos + w in_dir = w @@ -66,7 +66,7 @@ function fixed:fit(orig_width, orig_height) local used_in_dir, used_max = 0, 0 for k, v in pairs(self.widgets) do - local w, h = v:fit(width, height) + local w, h = base.fit_widget(v, width, height) local in_dir, max if self.dir == "y" then max, in_dir = w, h diff --git a/lib/wibox/layout/flex.lua.in b/lib/wibox/layout/flex.lua.in index 0b2b5a84..3b8e4c84 100644 --- a/lib/wibox/layout/flex.lua.in +++ b/lib/wibox/layout/flex.lua.in @@ -90,7 +90,7 @@ function flex:fit(orig_width, orig_height) local sub_width = self.dir == "y" and orig_width or floor(used_in_dir / #self.widgets) for k, v in pairs(self.widgets) do - local w, h = v:fit(sub_width, sub_height) + local w, h = base.fit_widget(v, sub_width, sub_height) local max if self.dir == "y" then max = w diff --git a/lib/wibox/layout/margin.lua.in b/lib/wibox/layout/margin.lua.in index 98d770dd..1a278d0c 100644 --- a/lib/wibox/layout/margin.lua.in +++ b/lib/wibox/layout/margin.lua.in @@ -33,7 +33,7 @@ function margin:fit(width, height) local extra_h = self.top + self.bottom local w, h = 0, 0 if self.widget then - w, h = self.widget:fit(width - extra_w, height - extra_h) + w, h = base.fit_widget(self.widget, width - extra_w, height - extra_h) end return w + extra_w, h + extra_h end diff --git a/lib/wibox/layout/mirror.lua.in b/lib/wibox/layout/mirror.lua.in index 1b550664..758e9f86 100644 --- a/lib/wibox/layout/mirror.lua.in +++ b/lib/wibox/layout/mirror.lua.in @@ -49,7 +49,7 @@ function mirror:fit(...) if not self.widget then return 0, 0 end - return self.widget:fit(...) + return base.fit_widget(self.widget, ...) end --- Set the widget that this layout mirrors. diff --git a/lib/wibox/layout/rotate.lua.in b/lib/wibox/layout/rotate.lua.in index ac262f3a..9895da84 100644 --- a/lib/wibox/layout/rotate.lua.in +++ b/lib/wibox/layout/rotate.lua.in @@ -51,7 +51,7 @@ function rotate:fit(width, height) if not self.widget then return 0, 0 end - return transform(self, self.widget:fit(transform(self, width, height))) + return transform(self, base.fit_widget(self.widget, transform(self, width, height))) end --- Set the widget that this layout rotates. diff --git a/lib/wibox/widget/base.lua.in b/lib/wibox/widget/base.lua.in index 33d48082..11e978cb 100644 --- a/lib/wibox/widget/base.lua.in +++ b/lib/wibox/widget/base.lua.in @@ -6,6 +6,7 @@ local debug = require("gears.debug") local object = require("gears.object") +local setmetatable = setmetatable local pairs = pairs local type = type local table = table @@ -94,6 +95,12 @@ function base.make_widget(proxy) end) end + -- Add a geometry for base.fit_widget() that is cleared when necessary + ret._fit_geometry_cache = setmetatable({}, { __mode = 'v' }) + ret:connect_signal("widget::updated", function() + ret._fit_geometry_cache = setmetatable({}, { __mode = 'v' }) + end) + return ret end