From 344edc64eddf32dc3b2480edb6200e823a12c7b0 Mon Sep 17 00:00:00 2001 From: Francisco Vallarino Date: Mon, 5 Dec 2022 22:54:27 -0300 Subject: [PATCH] Avoid infinite resize loop in multiline label (#233) * Avoid infinite resize loop in multiline label * Avoid weird macOS 'command encoder is already encoding to this command buffer' error when resizing window * Render resized window unconditionally when running on Linux --- src/Monomer/Main/Core.hs | 11 +++++----- src/Monomer/Widgets/Singles/Label.hs | 31 ++++++++++++++++------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Monomer/Main/Core.hs b/src/Monomer/Main/Core.hs index 3f9fd3ec..77667793 100644 --- a/src/Monomer/Main/Core.hs +++ b/src/Monomer/Main/Core.hs @@ -28,7 +28,8 @@ import Control.Monad.Extra import Control.Monad.State import Control.Monad.STM (atomically) import Data.Default -import Data.Maybe +import Data.Either (isLeft) +import Data.Maybe (fromMaybe) import Data.Map (Map) import Data.List (foldl') import Data.Text (Text) @@ -348,14 +349,14 @@ mainLoop window fontManager config loopArgs = do -- Rendering renderCurrentReq <- checkRenderCurrent startTs _mlLatestRenderTs + renderMethod <- use L.renderMethod let actionEvt = any isActionEvent eventsPayload - let windowRenderEvt = windowResized || any isWindowRenderEvent eventsPayload + let renderResize = windowResized && (isLinux wenv || isLeft renderMethod) + let windowRenderEvt = renderResize || any isWindowRenderEvent eventsPayload let renderNeeded = windowRenderEvt || actionEvt || renderCurrentReq - when (prevRenderNeeded || renderNeeded) $ do - renderMethod <- use L.renderMethod - + when (prevRenderNeeded || renderNeeded) $ case renderMethod of Right renderChan -> do liftIO . atomically $ writeTChan renderChan (MsgRender newWenv newRoot) diff --git a/src/Monomer/Widgets/Singles/Label.hs b/src/Monomer/Widgets/Singles/Label.hs index 18be5d8f..d5ac8d3e 100644 --- a/src/Monomer/Widgets/Singles/Label.hs +++ b/src/Monomer/Widgets/Singles/Label.hs @@ -154,7 +154,7 @@ data LabelState = LabelState { _lstStyle :: StyleState, _lstTextRect :: Rect, _lstTextLines :: Seq TextLine, - _lstPrevResize :: (Millisecond, Bool) + _lstResizeStep :: (Millisecond, Bool) } deriving (Eq, Show, Generic) -- | Creates a label using the provided 'Text'. @@ -201,7 +201,7 @@ makeLabel config state = widget where | otherwise = SingleLine maxLines = _lscTextMaxLines config labelCurrentStyle = fromMaybe currentStyle (_lscCurrentStyle config) - LabelState caption textStyle textRect textLines prevResize = state + LabelState caption textStyle textRect textLines resizeStep = state getBaseStyle wenv node | ignoreTheme = Nothing @@ -216,11 +216,12 @@ makeLabel config state = widget where & L.widget .~ makeLabel config newState merge wenv newNode oldNode oldState = result where + LabelState prevCaption prevStyle prevRect prevLines prevResize = oldState + (tsResized, alreadyResized) = prevResize + widgetId = newNode ^. L.info . L.widgetId style = labelCurrentStyle wenv newNode - prevStyle = _lstStyle oldState - - captionChanged = _lstCaption oldState /= caption + captionChanged = prevCaption /= caption styleChanged = prevStyle ^. L.text /= style ^. L.text || prevStyle ^. L.padding /= style ^. L.padding || prevStyle ^. L.border /= style ^. L.border @@ -231,11 +232,13 @@ makeLabel config state = widget where -- This is used in resize to know if glyphs have to be recalculated newRect | changeReq = def - | otherwise = _lstTextRect oldState - newState = oldState { + | otherwise = prevRect + newState = LabelState { _lstCaption = caption, _lstStyle = style, - _lstTextRect = newRect + _lstTextRect = newRect, + _lstTextLines = prevLines, + _lstResizeStep = (tsResized, alreadyResized && not captionChanged) } reqs = [ ResizeWidgets widgetId | changeReq ] @@ -246,7 +249,7 @@ makeLabel config state = widget where getSizeReq wenv node = (sizeW, sizeH) where ts = wenv ^. L.timestamp caption = _lstCaption state - prevResize = _lstPrevResize state + prevResize = _lstResizeStep state style = labelCurrentStyle wenv node cw = getContentArea node style ^. L.w @@ -286,18 +289,20 @@ makeLabel config state = widget where = fitTextToSize fontMgr style overflow mode trim maxLines size caption newTextLines = alignTextLines style alignRect fittedLines - (prevTs, prevStep) = prevResize - needsSndResize = mode == MultiLine && (prevTs /= ts || not prevStep) + rectEq = textRect == crect + (tsResized, alreadyResized) = resizeStep + resizeAgain = mode == MultiLine && (tsResized /= ts || not alreadyResized) + isResized = (alreadyResized && rectEq) || (resizeAgain && tsResized == ts) newState = state { _lstStyle = style, _lstTextRect = crect, _lstTextLines = newTextLines, - _lstPrevResize = (ts, needsSndResize && prevTs == ts) + _lstResizeStep = (ts, isResized) } newNode = node & L.widget .~ makeLabel config newState - result = resultReqs newNode [ResizeWidgets widgetId | needsSndResize] + result = resultReqs newNode [ResizeWidgets widgetId | resizeAgain] render wenv node renderer = do drawInScissor renderer True scissorVp $