Refactor all X.L.LayoutBuilderP functionality into X.L.LayoutBuilder

X.L.LayoutBuilderP is nearly identical to X.L.LayoutBuilder.  Originally
I wanted to add the ability to dynamically resize the layout boxes so it
make a lot of sense to join these two modules together so I wouldn't
have to do it in both.  Even though I never got around to that I still
think it's a good idea to merge these two modules into one.

I believe I was able to merge these without creating any
backward-compatibility issues.  I've been sitting on these changes since
2015 and they work for me without having to change older parts of my
config (relating to X.L.LayoutBuilder).

If anyone wants to work on dynamically resizing layout boxes the issue I
created for it is #36.
This commit is contained in:
Peter Jones 2016-11-05 09:51:28 -07:00
parent ec5f9a9e59
commit ca5fbc155b
No known key found for this signature in database
GPG Key ID: 9DAFAA8D01941E49
2 changed files with 303 additions and 132 deletions

View File

@ -1,11 +1,26 @@
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, PatternGuards, DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- | -- |
-- Module : XMonad.Layout.LayoutBuilder -- Module : XMonad.Layout.LayoutBuilder
-- Copyright : (c) 2009 Anders Engstrom <ankaan@gmail.com> --
-- Copyright : (c) 2009 Anders Engstrom <ankaan@gmail.com>,
-- 2011 Ilya Portnov <portnov84@rambler.ru>,
-- 2015 Peter Jones <pjones@devalot.com>
--
-- License : BSD3-style (see LICENSE) -- License : BSD3-style (see LICENSE)
-- --
-- Maintainer : Anders Engstrom <ankaan@gmail.com> -- Maintainer : Anders Engstrom <ankaan@gmail.com>,
-- Ilya Portnov <portnov84@rambler.ru>,
-- Peter Jones <pjones@devalot.com>
--
-- Stability : unstable -- Stability : unstable
-- Portability : unportable -- Portability : unportable
-- --
@ -17,25 +32,40 @@
-- ("XMonad.Layout.LayoutHints", "XMonad.Layout.HintedGrid" etc.) -- ("XMonad.Layout.LayoutHints", "XMonad.Layout.HintedGrid" etc.)
-- --
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module XMonad.Layout.LayoutBuilder ( module XMonad.Layout.LayoutBuilder (
-- * Usage -- * Usage
-- $usage -- $usage
layoutN, layoutN,
layoutR, layoutR,
layoutP,
layoutAll, layoutAll,
-- * Selecting Windows
-- $selectWin
Predicate (..),
Proxy(..),
-- * Messages
IncLayoutN (..), IncLayoutN (..),
-- * Utilities
SubMeasure (..), SubMeasure (..),
SubBox (..), SubBox (..),
absBox, absBox,
relBox, relBox,
LayoutB,
LayoutN, LayoutN,
) where ) where
--------------------------------------------------------------------------------
import Control.Applicative ((<|>))
import Control.Monad (foldM)
import Data.Maybe
import XMonad import XMonad
import qualified XMonad.StackSet as W import qualified XMonad.StackSet as W
import Data.Maybe (isJust,isNothing,listToMaybe) import XMonad.Util.WindowProperties
--------------------------------------------------------------------------------
-- $usage -- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: -- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
-- --
@ -89,56 +119,126 @@ import Data.Maybe (isJust,isNothing,listToMaybe)
-- --
-- "XMonad.Doc.Extending#Editing_key_bindings". -- "XMonad.Doc.Extending#Editing_key_bindings".
type WindowNum = Either Int (Rational,Rational) --------------------------------------------------------------------------------
-- $selectWin
--
-- 'Predicate' exists because layouts are required to be serializable, and
-- "XMonad.Util.WindowProperties" is not sufficient (for example it does not
-- allow using regular expressions).
--
-- compare "XMonad.Util.Invisible"
-- | Use one layout in the specified area for a number of windows and possibly let another layout handle the rest. -- | Type class for predicates. This enables us to manage not only Windows,
data LayoutN l1 l2 a = -- but any objects, for which instance Predicate is defined.
LayoutN (Maybe a) (Maybe a) WindowNum SubBox (Maybe SubBox) (l1 a) (Maybe (l2 a)) --
deriving (Show,Read) -- Another instance exists in XMonad.Util.WindowPropertiesRE in xmonad-extras
class Predicate p w where
alwaysTrue :: Proxy w -> p -- ^ A predicate that is always True.
checkPredicate :: p -> w -> X Bool -- ^ Check if given object (window or smth else) matches that predicate
-- | Use the specified layout in the described area for N windows and send the rest of the windows to the next layout in the chain. instance Predicate () a where
-- It is possible to supply an alternative area that will then be used instead, if there are no windows to send to the next layout. alwaysTrue _ = ()
checkPredicate _ _ = return True
instance Predicate Property Window where
alwaysTrue _ = Const True
checkPredicate = hasProperty
--------------------------------------------------------------------------------
-- | Contains no actual data, but is needed to help select the correct instance
-- of 'Predicate'
data Proxy a = Proxy
--------------------------------------------------------------------------------
-- | Information about how to split windows between layouts.
data Limit p = LimitN Int -- ^ See: 'layoutN'.
| LimitR (Rational, Rational) -- ^ See: 'layoutR'.
| LimitP p -- ^ See: 'layoutP'.
deriving (Show, Read)
--------------------------------------------------------------------------------
-- | Use one layout in the specified area for a number of windows and
-- possibly let another layout handle the rest.
data LayoutB l1 l2 p a = LayoutB
{ subFocus :: Maybe a -- ^ The focused window in this layout.
, nextFocus :: Maybe a -- ^ The focused window in the next layout.
, limit :: Limit p -- ^ How to split windows between layouts.
, box :: SubBox -- ^ Normal size of layout.
, mbox :: Maybe SubBox -- ^ Size of layout when handling all windows.
, sub :: l1 a -- ^ The layout to use in this box.
, next :: Maybe (l2 a) -- ^ The next layout in the chain.
} deriving (Show, Read)
--------------------------------------------------------------------------------
-- | A variant of 'LayoutB' that can't use 'layoutP'. For backwards
-- compatibility with previous versions of LayoutBuilder.
type LayoutN l1 l2 a = LayoutB l1 l2 () a
--------------------------------------------------------------------------------
-- | Use the specified layout in the described area for N windows and
-- send the rest of the windows to the next layout in the chain. It
-- is possible to supply an alternative area that will then be used
-- instead, if there are no windows to send to the next layout.
layoutN :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a) => layoutN :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a) =>
Int -- ^ The number of windows to handle Int -- ^ The number of windows to handle
-> SubBox -- ^ The box to place the windows in -> SubBox -- ^ The box to place the windows in
-> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left -> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left
-> l1 a -- ^ The layout to use in the specified area -> l1 a -- ^ The layout to use in the specified area
-> LayoutN l2 l3 a -- ^ Where to send the remaining windows -> LayoutB l2 l3 p a -- ^ Where to send the remaining windows
-> LayoutN l1 (LayoutN l2 l3) a -- ^ The resulting layout -> LayoutB l1 (LayoutB l2 l3 p) () a -- ^ The resulting layout
layoutN num box mbox sub next = LayoutN Nothing Nothing (Left num) box mbox sub (Just next) layoutN num box mbox sub next = LayoutB Nothing Nothing (LimitN num) box mbox sub (Just next)
-- | As layoutN, but the number of windows is given relative to the total number of windows remaining to be handled. The first -- | As layoutN, but the number of windows is given relative to the total number of windows remaining to be handled. The first
-- argument is how much to change the ratio when using IncLayoutN, and the second is the initial ratio. -- argument is how much to change the ratio when using IncLayoutN, and the second is the initial ratio.
layoutR :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a) => layoutR :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a) =>
Rational -- ^ How much to change the ratio with each IncLayoutN Rational -- ^ How much to change the ratio with each IncLayoutN
-> Rational -- ^ The ratio of the remaining windows to handle -> Rational -- ^ The ratio of the remaining windows to handle
-> SubBox -- ^ The box to place the windows in -> SubBox -- ^ The box to place the windows in
-> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left -> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left
-> l1 a -- ^ The layout to use in the specified area -> l1 a -- ^ The layout to use in the specified area
-> LayoutN l2 l3 a -- ^ Where to send the remaining windows -> LayoutB l2 l3 p a -- ^ Where to send the remaining windows
-> LayoutN l1 (LayoutN l2 l3) a -- ^ The resulting layout -> LayoutB l1 (LayoutB l2 l3 p) p a -- ^ The resulting layout
layoutR numdiff num box mbox sub next = LayoutN Nothing Nothing (Right (numdiff,num)) box mbox sub (Just next) layoutR numdiff num box mbox sub next = LayoutB Nothing Nothing (LimitR (numdiff,num)) box mbox sub (Just next)
--------------------------------------------------------------------------------
-- | Use the specified layout in the described area windows that match
-- given predicate and send the rest of the windows to the next layout
-- in the chain. It is possible to supply an alternative area that
-- will then be used instead, if there are no windows to send to the
-- next layout.
layoutP :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a, Predicate p a, Predicate p' a) =>
p -- ^ The predicate to use
-> SubBox -- ^ The box to place the windows in
-> Maybe SubBox -- ^ Possibly an alternative box that is used when this layout handles all windows that are left
-> l1 a -- ^ The layout to use in the specified area
-> LayoutB l2 l3 p' a -- ^ Where to send the remaining windows
-> LayoutB l1 (LayoutB l2 l3 p') p a -- ^ The resulting layout
layoutP prop box mbox sub next = LayoutB Nothing Nothing (LimitP prop) box mbox sub (Just next)
--------------------------------------------------------------------------------
-- | Use the specified layout in the described area for all remaining windows. -- | Use the specified layout in the described area for all remaining windows.
layoutAll :: (Read a, Eq a, LayoutClass l1 a) => layoutAll :: (Read a, Eq a, LayoutClass l1 a) =>
SubBox -- ^ The box to place the windows in SubBox -- ^ The box to place the windows in
-> l1 a -- ^ The layout to use in the specified area -> l1 a -- ^ The layout to use in the specified area
-> LayoutN l1 Full a -- ^ The resulting layout -> LayoutB l1 Full () a -- ^ The resulting layout
layoutAll box sub = LayoutN Nothing Nothing (Right (0,1)) box Nothing sub Nothing layoutAll box sub = LayoutB Nothing Nothing (LimitR (0,1)) box Nothing sub Nothing
--------------------------------------------------------------------------------
-- | Change the number of windows handled by the focused layout. -- | Change the number of windows handled by the focused layout.
data IncLayoutN = IncLayoutN Int deriving Typeable data IncLayoutN = IncLayoutN Int deriving Typeable
instance Message IncLayoutN instance Message IncLayoutN
--------------------------------------------------------------------------------
-- | The absolute or relative measures used to describe the area a layout should be placed in. For negative absolute values -- | The absolute or relative measures used to describe the area a layout should be placed in. For negative absolute values
-- the total remaining space will be added. For sizes, the remaining space will also be added for zeroes. Relative values -- the total remaining space will be added. For sizes, the remaining space will also be added for zeroes. Relative values
-- are applied on the remaining space after the top-left corner of the box have been removed. -- are applied on the remaining space after the top-left corner of the box have been removed.
data SubMeasure = Abs Int | Rel Rational deriving (Show,Read) data SubMeasure = Abs Int | Rel Rational deriving (Show,Read)
--------------------------------------------------------------------------------
-- | A box to place a layout in. The stored values are xpos, ypos, width and height. -- | A box to place a layout in. The stored values are xpos, ypos, width and height.
data SubBox = SubBox SubMeasure SubMeasure SubMeasure SubMeasure deriving (Show,Read) data SubBox = SubBox SubMeasure SubMeasure SubMeasure SubMeasure deriving (Show,Read)
--------------------------------------------------------------------------------
-- | Create a box with only absolute measurements. If the values are negative, the total remaining space will be added. For -- | Create a box with only absolute measurements. If the values are negative, the total remaining space will be added. For
-- sizes it will also be added for zeroes. -- sizes it will also be added for zeroes.
absBox :: Int -- ^ Absolute X-Position absBox :: Int -- ^ Absolute X-Position
@ -148,7 +248,7 @@ absBox :: Int -- ^ Absolute X-Position
-> SubBox -- ^ The resulting 'SubBox' describing the area -> SubBox -- ^ The resulting 'SubBox' describing the area
absBox x y w h = SubBox (Abs x) (Abs y) (Abs w) (Abs h) absBox x y w h = SubBox (Abs x) (Abs y) (Abs w) (Abs h)
--------------------------------------------------------------------------------
-- | Create a box with only relative measurements. -- | Create a box with only relative measurements.
relBox :: Rational -- ^ Relative X-Position with respect to the surrounding area relBox :: Rational -- ^ Relative X-Position with respect to the surrounding area
-> Rational -- ^ Relative Y-Position with respect to the surrounding area -> Rational -- ^ Relative Y-Position with respect to the surrounding area
@ -157,138 +257,209 @@ relBox :: Rational -- ^ Relative X-Position with respect to the surrounding are
-> SubBox -- ^ The resulting 'SubBox' describing the area -> SubBox -- ^ The resulting 'SubBox' describing the area
relBox x y w h = SubBox (Rel x) (Rel y) (Rel w) (Rel h) relBox x y w h = SubBox (Rel x) (Rel y) (Rel w) (Rel h)
--------------------------------------------------------------------------------
instance ( LayoutClass l1 a, LayoutClass l2 a
, Read a, Show a, Show p, Eq a, Typeable a, Predicate p a
) => LayoutClass (LayoutB l1 l2 p) a where
instance (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => -- | Update window locations.
LayoutClass (LayoutN l1 l2) a where runLayout (W.Workspace _ LayoutB {..} s) rect = do
(subs, nexts, subFocus', nextFocus') <- splitStack s limit subFocus nextFocus
-- | Update window locations. let selBox = if isJust nextFocus' then box else fromMaybe box mbox
runLayout (W.Workspace _ (LayoutN subf nextf num box mbox sub next) s) rect
= do let (subs,nexts,subf',nextf') = splitStack s num subf nextf
selBox = if isJust nextf'
then box
else maybe box id mbox
(sublist,sub',schange) <- handle sub subs $ calcArea selBox rect (sublist, sub', schange) <- handle sub subs (calcArea selBox rect)
(nextlist,next',nchange) <- case next of Nothing -> return ([], Nothing, False) (nextlist, next', nchange) <- case next of
Just n -> do (res, l, ch) <- handle n nexts rect Nothing -> return ([], Nothing, False)
return (res, Just l, ch) Just n -> do (res, l, ch) <- handle n nexts rect
return (res, Just l, ch)
let newlist = if (length $ maybe [] W.up s) < (length $ W.integrate' subs) let newlist = if length (maybe [] W.up s) < length (W.integrate' subs)
then sublist++nextlist then sublist++nextlist
else nextlist++sublist else nextlist++sublist
newstate = if subf' /= subf || nextf' /= nextf || schange || nchange
then Just $ LayoutN subf' nextf' num box mbox sub' next'
else Nothing
return (newlist, newstate) newstate = if subFocus' /= subFocus || nextFocus' /= nextFocus || schange || nchange
where then Just $ LayoutB subFocus' nextFocus' limit box mbox sub' next'
handle l s' r = do (res,ml) <- runLayout (W.Workspace "" l s') r else Nothing
l' <- return $ maybe l id ml
return (res, l', isNothing ml)
-- | Propagate messages. return (newlist, newstate)
handleMessage l m where
| Just (IncLayoutN _) <- fromMessage m = windowNum l m handle l s' r = do (res,ml) <- runLayout (W.Workspace "" l s') r
| Just (IncMasterN _) <- fromMessage m = sendFocus l m return (res, fromMaybe l ml, isNothing ml)
| Just (Shrink) <- fromMessage m = sendFocus l m
| Just (Expand) <- fromMessage m = sendFocus l m
| otherwise = sendBoth l m
-- | Descriptive name for layout. -- | Propagate messages.
description (LayoutN _ _ _ _ _ sub Nothing) = "layoutAll "++ description sub handleMessage l m
description (LayoutN _ _ (Left _) _ _ sub (Just next)) = "layoutN "++ description sub ++" "++ description next | Just (IncLayoutN n) <- fromMessage m = incLayoutN l m n
description (LayoutN _ _ (Right _) _ _ sub (Just next)) = "layoutR "++ description sub ++" "++ description next | Just (IncMasterN _) <- fromMessage m = sendFocus l m
| Just Shrink <- fromMessage m = sendFocus l m
| Just Expand <- fromMessage m = sendFocus l m
| otherwise = sendBoth l m
-- | Descriptive name for layout.
description layout = case layout of
(LayoutB _ _ _ _ _ sub Nothing) ->
"layoutAll " ++ description sub
windowNum :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a)) (LayoutB _ _ (LimitN _) _ _ sub (Just next)) ->
windowNum l@(LayoutN subf nextf num box mbox subl nextl) m | (Just (IncLayoutN n)) <- fromMessage m = "layoutN " ++ description sub ++ " " ++ description next
do foc <- isFocus subf
if foc then do let newnum = case num of
(Left oldnum) -> Left $ max 1 $ oldnum + n
(Right (diff,oldnum)) -> Right (diff, min 1 $ max 0 $ oldnum + (fromIntegral n)*diff)
return $ Just $ LayoutN subf nextf newnum box mbox subl nextl
else sendNext l m
windowNum l m = sendNext l m
sendSub :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a)) (LayoutB _ _ (LimitR _) _ _ sub (Just next)) ->
sendSub (LayoutN subf nextf num box mbox sub next) m = "layoutR " ++ description sub ++ " " ++ description next
(LayoutB _ _ (LimitP _) _ _ sub (Just next)) ->
"layoutP " ++ description sub ++ " " ++ description next
--------------------------------------------------------------------------------
-- | Increase the number of windows allowed in the focused layout.
incLayoutN :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a)
=> LayoutB l1 l2 p a
-> SomeMessage
-> Int
-> X (Maybe (LayoutB l1 l2 p a))
incLayoutN layout@LayoutB {..} message n = do
incThis <- isFocus subFocus
if incThis
then return $ Just layout { limit = newLimit }
else sendNext layout message
where
newLimit = case limit of
LimitN oldnum -> LimitN (max 1 $ oldnum + n)
LimitR (diff, oldnum) -> LimitR (diff, min 1 $ max 0 $ oldnum + fromIntegral n * diff)
LimitP _ -> limit
--------------------------------------------------------------------------------
sendSub :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutB l1 l2 p a -> SomeMessage -> X (Maybe (LayoutB l1 l2 p a))
sendSub (LayoutB subFocus nextFocus num box mbox sub next) m =
do sub' <- handleMessage sub m do sub' <- handleMessage sub m
return $ if isJust sub' return $ if isJust sub'
then Just $ LayoutN subf nextf num box mbox (maybe sub id sub') next then Just $ LayoutB subFocus nextFocus num box mbox (fromMaybe sub sub') next
else Nothing else Nothing
sendBoth :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a)) --------------------------------------------------------------------------------
sendBoth l@(LayoutN _ _ _ _ _ _ Nothing) m = sendSub l m sendBoth :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutB l1 l2 p a -> SomeMessage -> X (Maybe (LayoutB l1 l2 p a))
sendBoth (LayoutN subf nextf num box mbox sub (Just next)) m = sendBoth l@(LayoutB _ _ _ _ _ _ Nothing) m = sendSub l m
sendBoth (LayoutB subFocus nextFocus num box mbox sub (Just next)) m =
do sub' <- handleMessage sub m do sub' <- handleMessage sub m
next' <- handleMessage next m next' <- handleMessage next m
return $ if isJust sub' || isJust next' return $ if isJust sub' || isJust next'
then Just $ LayoutN subf nextf num box mbox (maybe sub id sub') (Just $ maybe next id next') then Just $ LayoutB subFocus nextFocus num box mbox (fromMaybe sub sub') (next' <|> Just next)
else Nothing else Nothing
sendNext :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a)) --------------------------------------------------------------------------------
sendNext (LayoutN _ _ _ _ _ _ Nothing) _ = return Nothing sendNext :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutB l1 l2 p a -> SomeMessage -> X (Maybe (LayoutB l1 l2 p a))
sendNext (LayoutN subf nextf num box mbox sub (Just next)) m = sendNext (LayoutB _ _ _ _ _ _ Nothing) _ = return Nothing
sendNext (LayoutB subFocus nextFocus num box mbox sub (Just next)) m =
do next' <- handleMessage next m do next' <- handleMessage next m
return $ if isJust next' return $ if isJust next'
then Just $ LayoutN subf nextf num box mbox sub next' then Just $ LayoutB subFocus nextFocus num box mbox sub next'
else Nothing else Nothing
sendFocus :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutN l1 l2 a -> SomeMessage -> X (Maybe (LayoutN l1 l2 a)) --------------------------------------------------------------------------------
sendFocus l@(LayoutN subf _ _ _ _ _ _) m = do foc <- isFocus subf sendFocus :: (LayoutClass l1 a, LayoutClass l2 a, Read a, Show a, Eq a, Typeable a) => LayoutB l1 l2 p a -> SomeMessage -> X (Maybe (LayoutB l1 l2 p a))
if foc then sendSub l m sendFocus l@(LayoutB subFocus _ _ _ _ _ _) m = do
else sendNext l m foc <- isFocus subFocus
if foc
then sendSub l m
else sendNext l m
--------------------------------------------------------------------------------
-- | Check to see if the given window is currently focused.
isFocus :: (Show a) => Maybe a -> X Bool isFocus :: (Show a) => Maybe a -> X Bool
isFocus Nothing = return False isFocus Nothing = return False
isFocus (Just w) = do ms <- (W.stack . W.workspace . W.current) `fmap` gets windowset isFocus (Just w) = do ms <- (W.stack . W.workspace . W.current) `fmap` gets windowset
return $ maybe False (\s -> show w == (show $ W.focus s)) ms return $ maybe False (\s -> show w == show (W.focus s)) ms
--------------------------------------------------------------------------------
calcNum :: Int -> Limit p -> Int
calcNum tot num = max 1 $ case num of LimitN i -> i
LimitR (_,r) -> ceiling $ r * fromIntegral tot
LimitP _ -> 1
calcNum :: Int -> WindowNum -> Int --------------------------------------------------------------------------------
calcNum tot num = max 1 $ case num of Left i -> i -- | Split given list of objects (i.e. windows) using predicate.
Right (_,r) -> ceiling $ r * fromIntegral tot splitBy :: (Predicate p a) => p -> [a] -> X ([a], [a])
splitBy prop = foldM step ([], [])
where
step (good, bad) w = do
ok <- checkPredicate prop w
return $ if ok
then (w:good, bad)
else (good, w:bad)
splitStack :: Eq a => Maybe (W.Stack a) -> WindowNum -> Maybe a -> Maybe a -> (Maybe (W.Stack a),Maybe (W.Stack a),Maybe a,Maybe a) --------------------------------------------------------------------------------
splitStack Nothing _ _ _ = (Nothing,Nothing,Nothing,Nothing) splitStack :: forall a p. (Eq a, Predicate p a)
splitStack (Just s) num subf nextf = ( differentiate' subf' subl => Maybe (W.Stack a) -- ^ Window set.
, differentiate' nextf' nextl -> Limit p -- ^ How to split the stack.
, subf' -> Maybe a -- ^ The window that was focused in this layout.
, nextf' -> Maybe a -- ^ The window that was focused in the next layout.
) -> X (Maybe (W.Stack a), Maybe (W.Stack a), Maybe a, Maybe a)
where splitStack Nothing _ _ _ = return (Nothing, Nothing, Nothing, Nothing)
ws = W.integrate s splitStack (Just s) limit subFocus nextFocus =
n = calcNum (length ws) num case limit of
subl = take n ws LimitN _ -> splitN
nextl = drop n ws LimitR _ -> splitN
subf' = foc subl subf LimitP prop -> splitP prop
nextf' = foc nextl nextf
foc [] _ = Nothing
foc l f | W.focus s `elem` l = Just $ W.focus s
| maybe False (`elem` l) f = f
| otherwise = listToMaybe l
where
ws = W.integrate s
n = calcNum (length ws) limit
subl = take n ws
nextl = drop n ws
subFocus' xs = foc xs subFocus
nextFocus' xs = foc xs nextFocus
-- Pick a new focused window if necessary.
foc :: [a] -> Maybe a -> Maybe a
foc [] _ = Nothing
foc l f | W.focus s `elem` l = Just (W.focus s)
| maybe False (`elem` l) f = f
| otherwise = listToMaybe l
-- Split based on max number of windows.
splitN = return ( differentiate' (subFocus' subl) subl
, differentiate' (nextFocus' nextl) nextl
, subFocus' subl
, nextFocus' nextl
)
-- Split based on a predicate.
splitP prop = do
(this, other) <- splitBy prop ws
return ( differentiate' (subFocus' this) this
, differentiate' (nextFocus' other) other
, subFocus' this
, nextFocus' other
)
--------------------------------------------------------------------------------
calcArea :: SubBox -> Rectangle -> Rectangle calcArea :: SubBox -> Rectangle -> Rectangle
calcArea (SubBox xpos ypos width height) rect = Rectangle (rect_x rect + fromIntegral xpos') (rect_y rect + fromIntegral ypos') width' height' calcArea (SubBox xpos ypos width height) rect =
where Rectangle (rect_x rect + fromIntegral xpos')
xpos' = calc False xpos $ rect_width rect (rect_y rect + fromIntegral ypos')
ypos' = calc False ypos $ rect_height rect width' height'
width' = calc True width $ rect_width rect - xpos' where
height' = calc True height $ rect_height rect - ypos' xpos' = calc False xpos $ rect_width rect
ypos' = calc False ypos $ rect_height rect
width' = calc True width $ rect_width rect - xpos'
height' = calc True height $ rect_height rect - ypos'
calc zneg val tot = fromIntegral $ min (fromIntegral tot) $ max 0 $ calc zneg val tot = fromIntegral $ min (fromIntegral tot) $ max 0 $
case val of Rel v -> floor $ v * fromIntegral tot case val of Rel v -> floor $ v * fromIntegral tot
Abs v -> if v<0 || (zneg && v==0) Abs v -> if v<0 || (zneg && v==0)
then (fromIntegral tot)+v then fromIntegral tot + v
else v else v
--------------------------------------------------------------------------------
differentiate' :: Eq q => Maybe q -> [q] -> Maybe (W.Stack q) differentiate' :: Eq q => Maybe q -> [q] -> Maybe (W.Stack q)
differentiate' _ [] = Nothing differentiate' _ [] = Nothing
differentiate' Nothing w = W.differentiate w differentiate' Nothing w = W.differentiate w
differentiate' (Just f) w differentiate' (Just f) w
| f `elem` w = Just $ W.Stack { W.focus = f | f `elem` w = Just W.Stack { W.focus = f
, W.up = reverse $ takeWhile (/=f) w , W.up = reverse $ takeWhile (/=f) w
, W.down = tail $ dropWhile (/=f) w , W.down = tail $ dropWhile (/=f) w
} }
| otherwise = W.differentiate w | otherwise = W.differentiate w

View File

@ -9,12 +9,11 @@
-- Stability : unstable -- Stability : unstable
-- Portability : unportable -- Portability : unportable
-- --
-- A layout combinator that sends windows matching given predicate to one rectangle -- DEPRECATED. Use 'XMonad.Layout.LayoutBuilder' instead.
-- and the rest to another.
-- --
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module XMonad.Layout.LayoutBuilderP ( module XMonad.Layout.LayoutBuilderP {-# DEPRECATED "Use XMonad.Layout.LayoutBuilder instead" #-} (
LayoutP (..), LayoutP (..),
layoutP, layoutAll, layoutP, layoutAll,
B.relBox, B.absBox, B.relBox, B.absBox,
@ -59,6 +58,7 @@ data LayoutP p l1 l2 a =
-- | Use the specified layout in the described area windows that match given predicate and send the rest of the windows to the next layout in the chain. -- | Use the specified layout in the described area windows that match given predicate and send the rest of the windows to the next layout in the chain.
-- It is possible to supply an alternative area that will then be used instead, if there are no windows to send to the next layout. -- It is possible to supply an alternative area that will then be used instead, if there are no windows to send to the next layout.
{-# DEPRECATED layoutP "Use XMonad.Layout.LayoutBuilder.layoutP instead." #-}
layoutP :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a, Predicate p a) => layoutP :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a, Predicate p a) =>
p p
-> B.SubBox -- ^ The box to place the windows in -> B.SubBox -- ^ The box to place the windows in
@ -69,6 +69,7 @@ layoutP :: (Read a, Eq a, LayoutClass l1 a, LayoutClass l2 a, LayoutClass l3 a,
layoutP prop box mbox sub next = LayoutP Nothing Nothing prop box mbox sub (Just next) layoutP prop box mbox sub next = LayoutP Nothing Nothing prop box mbox sub (Just next)
-- | Use the specified layout in the described area for all remaining windows. -- | Use the specified layout in the described area for all remaining windows.
{-# DEPRECATED layoutAll "Use XMonad.Layout.LayoutBuilder.layoutAll instead." #-}
layoutAll :: forall l1 p a. (Read a, Eq a, LayoutClass l1 a, Predicate p a) => layoutAll :: forall l1 p a. (Read a, Eq a, LayoutClass l1 a, Predicate p a) =>
B.SubBox -- ^ The box to place the windows in B.SubBox -- ^ The box to place the windows in
-> l1 a -- ^ The layout to use in the specified area -> l1 a -- ^ The layout to use in the specified area
@ -207,4 +208,3 @@ differentiate' (Just f) w
instance Predicate Property Window where instance Predicate Property Window where
alwaysTrue _ = Const True alwaysTrue _ = Const True
checkPredicate = hasProperty checkPredicate = hasProperty