From 0614ffb65c15658bf9fe9375ab95a18d2b26a8cb Mon Sep 17 00:00:00 2001 From: "L. S. Leary" <LSLeary@users.noreply.github.com> Date: Wed, 1 Aug 2018 00:45:41 +1200 Subject: [PATCH] `XMonad.Operations` * Add `windowBracket`: provide a means of handling windowset changes made during the course of arbitrary `X` actions. Buys composability. * Add `windowBracket_` variant. * Add `modifyWindowSet` utility for use with the above. * Re-implement `sendMessage` using `windowBracket_` so that its refresh handles changes made to the windowset by the message handler. --- src/XMonad/Operations.hs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/XMonad/Operations.hs b/src/XMonad/Operations.hs index 05e100a..2845a6e 100644 --- a/src/XMonad/Operations.hs +++ b/src/XMonad/Operations.hs @@ -21,7 +21,7 @@ import XMonad.Layout (Full(..)) import qualified XMonad.StackSet as W import Data.Maybe -import Data.Monoid (Endo(..)) +import Data.Monoid (Endo(..),Any(..)) import Data.List (nub, (\\), find) import Data.Bits ((.|.), (.&.), complement, testBit) import Data.Ratio @@ -30,6 +30,7 @@ import qualified Data.Set as S import Control.Applicative((<$>), (<*>)) import Control.Arrow (second) +import Control.Monad (void) import Control.Monad.Reader import Control.Monad.State import qualified Control.Exception.Extensible as C @@ -176,6 +177,25 @@ windows f = do unless isMouseFocused $ clearEvents enterWindowMask asks (logHook . config) >>= userCodeDef () +-- | Modify the @WindowSet@ in state with no special handling. +modifyWindowSet :: (WindowSet -> WindowSet) -> X () +modifyWindowSet f = modify $ \xst -> xst { windowset = f (windowset xst) } + +-- | Perform an @X@ action and check its return value against a predicate p. +-- If p holds, unwind changes to the @WindowSet@ and replay them using @windows@. +windowBracket :: (a -> Bool) -> X a -> X a +windowBracket p action = withWindowSet $ \old -> do + a <- action + when (p a) . withWindowSet $ \new -> do + modifyWindowSet $ \_ -> old + windows $ \_ -> new + return a + +-- | A version of @windowBracket@ that discards the return value, and handles an +-- @X@ action reporting its need for refresh via @Any@. +windowBracket_ :: X Any -> X () +windowBracket_ = void . windowBracket getAny + -- | Produce the actual rectangle from a screen and a ratio on that screen. scaleRationalRect :: Rectangle -> W.RationalRect -> Rectangle scaleRationalRect (Rectangle sx sy sw sh) (W.RationalRect rx ry rw rh) @@ -371,15 +391,16 @@ setFocusX w = withWindowSet $ \ws -> do -- Message handling -- | Throw a message to the current 'LayoutClass' possibly modifying how we --- layout the windows, then refresh. +-- layout the windows, in which case changes are handled through a refresh. sendMessage :: Message a => a -> X () -sendMessage a = do +sendMessage a = windowBracket_ $ do w <- W.workspace . W.current <$> gets windowset ml' <- handleMessage (W.layout w) (SomeMessage a) `catchX` return Nothing whenJust ml' $ \l' -> - windows $ \ws -> ws { W.current = (W.current ws) + modifyWindowSet $ \ws -> ws { W.current = (W.current ws) { W.workspace = (W.workspace $ W.current ws) { W.layout = l' }}} + return (Any $ isJust ml') -- | Send a message to all layouts, without refreshing. broadcastMessage :: Message a => a -> X ()