wibox: Add widget geometry cache
This commit adds and uses wibox.layout.base.fit_widget(). This function is a wrapper for widget:fit() that caches the result and thus speeds things up. This is necessary because some layouts call :fit() from their :fit() and :draw() functions. Nesting such layouts means that at the widget at the tail of the stack gets its :fit() function called quite often. If this function is not blazingly fast, this results in noticeable slowness. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
a0e45e878e
commit
3edd216560
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue