From 8e1c6c8409cf87e08c78d81d6a1bf9092472e88d Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Mon, 26 Oct 2020 12:28:00 +0100 Subject: [PATCH] UIManager: Handle covers_fullscreen properly in close (#6828) * When closing a widget, stop sending setDirty call for widgets lower on the stack as soon as we hit a full-screen one. This prevents inflated refresh regions when closing stuff on top of a stack of multiple covers_fullscreen widgets (i.e., InfoMessages on top of the Favorites page on top of the FM, for instance). And, while we're there, also prevent getting infected by dithered widgets when they're below a non dithered full-screen widget (the exact same examples works, if the underlying FM page requires dithering). --- frontend/ui/uimanager.lua | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 14f601083..47c4528ec 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -425,6 +425,8 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither) -- make it disabled by default and check if any widget wants it disabled or enabled Input.disable_double_tap = true local requested_disable_double_tap = nil + local is_covered = false + local start_idx = 1 -- then remove all references to that widget on stack and refresh for i = #self._window_stack, 1, -1 do if self._window_stack[i].widget == widget then @@ -432,12 +434,23 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither) table.remove(self._window_stack, i) dirty = true else - -- If anything else on the stack was dithered, honor the hint - if self._window_stack[i].widget.dithered then + -- If anything else on the stack not already hidden by (i.e., below) a fullscreen widget was dithered, honor the hint + if self._window_stack[i].widget.dithered and not is_covered then refreshdither = true logger.dbg("Lower widget", self._window_stack[i].widget.name or self._window_stack[i].widget.id or tostring(self._window_stack[i].widget), "was dithered, honoring the dithering hint") end + -- Remember the uppermost widget that covers the full screen, so we don't bother calling setDirty on hidden (i.e., lower) widgets in the following dirty loop. + -- _repaint already does that later on to skip the actual paintTo calls, so this ensures we limit the refresh queue to stuff that will actually get painted. + if not is_covered and self._window_stack[i].widget.covers_fullscreen then + is_covered = true + start_idx = i + logger.dbg("Lower widget", self._window_stack[i].widget.name or self._window_stack[i].widget.id or tostring(self._window_stack[i].widget), "covers the full screen") + if i > 1 then + logger.dbg("not refreshing", i-1, "covered widget(s)") + end + end + -- Set double tap to how the topmost specifying widget wants it if requested_disable_double_tap == nil and self._window_stack[i].widget.disable_double_tap ~= nil then requested_disable_double_tap = self._window_stack[i].widget.disable_double_tap @@ -448,8 +461,8 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither) Input.disable_double_tap = requested_disable_double_tap end if dirty and not widget.invisible then - -- schedule remaining widgets to be painted - for i = 1, #self._window_stack do + -- schedule the remaining visible (i.e., uncovered) widgets to be painted + for i = start_idx, #self._window_stack do self:setDirty(self._window_stack[i].widget) end self:_refresh(refreshtype, refreshregion, refreshdither)