    {-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances #-}
    {- |

    Module      :  XMonad.Layout.FocusTracking
    Description :  Track focus in the tiled layer.
    Copyright   :  (c) 2010 & 2013 Adam Vogt
                       2011 Willem Vanlint
                       2018 & 2022 L.S.Leary
    License     :  BSD-style (see xmonad/LICENSE)

    Maintainer  :  @LSLeary (on github)
    Stability   :  unstable
    Portability :  unportable

    FocusTracking simply holds onto the last true focus it was given and continues
    to use it as the focus for the transformed layout until it sees another. It can
    be used to improve the behaviour of a child layout that has not been given the
    focused window, or equivalently, that of the layout itself when a float has
    focus.

    Relevant issues:

      * <http://code.google.com/p/xmonad/issues/detail?id=4>
      * <http://code.google.com/p/xmonad/issues/detail?id=306>

    --------------------------------------------------------------------------------
    -}
    module XMonad.Layout.FocusTracking
        ( -- * Usage
          -- $usage
          FocusTracking(..)
        , focusTracking
        ) where

    import XMonad.Prelude
    import XMonad
    import XMonad.Layout.LayoutModifier
    import XMonad.Util.Stack (findZ)
    import qualified XMonad.StackSet as W

    -- $usage
    --
    -- To use the module, first import it:
    --
    -- > import XMonad.Layout.FocusTracking
    --
    -- Then, a focus-dependent layout can be made to fall back on the last focus it
    -- saw, for example:
    --
    -- > main = xmonad def
    -- >  { layoutHook = someParentLayoutWith aChild (focusTracking anotherChild)
    -- >  , ...
    -- >  }
    --
    -- Or in a simpler case:
    --
    -- > main = xmonad def
    -- >  { layoutHook = myTiledLayout ||| focusTracking Full
    -- >  , ...
    -- >  }
    --

    -- | A 'LayoutModifier' that remembers the last focus it saw.
    newtype FocusTracking a = FocusTracking (Maybe Window)
        deriving (ReadPrec [FocusTracking a]
    ReadPrec (FocusTracking a)
    Int -> ReadS (FocusTracking a)
    ReadS [FocusTracking a]
    (Int -> ReadS (FocusTracking a))
    -> ReadS [FocusTracking a]
    -> ReadPrec (FocusTracking a)
    -> ReadPrec [FocusTracking a]
    -> Read (FocusTracking a)
    forall a. ReadPrec [FocusTracking a]
    forall a. ReadPrec (FocusTracking a)
    forall a. Int -> ReadS (FocusTracking a)
    forall a. ReadS [FocusTracking a]
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: forall a. Int -> ReadS (FocusTracking a)
    readsPrec :: Int -> ReadS (FocusTracking a)
    $creadList :: forall a. ReadS [FocusTracking a]
    readList :: ReadS [FocusTracking a]
    $creadPrec :: forall a. ReadPrec (FocusTracking a)
    readPrec :: ReadPrec (FocusTracking a)
    $creadListPrec :: forall a. ReadPrec [FocusTracking a]
    readListPrec :: ReadPrec [FocusTracking a]
    Read, Int -> FocusTracking a -> ShowS
    [FocusTracking a] -> ShowS
    FocusTracking a -> String
    (Int -> FocusTracking a -> ShowS)
    -> (FocusTracking a -> String)
    -> ([FocusTracking a] -> ShowS)
    -> Show (FocusTracking a)
    forall a. Int -> FocusTracking a -> ShowS
    forall a. [FocusTracking a] -> ShowS
    forall a. FocusTracking a -> String
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: forall a. Int -> FocusTracking a -> ShowS
    showsPrec :: Int -> FocusTracking a -> ShowS
    $cshow :: forall a. FocusTracking a -> String
    show :: FocusTracking a -> String
    $cshowList :: forall a. [FocusTracking a] -> ShowS
    showList :: [FocusTracking a] -> ShowS
    Show)

    instance LayoutModifier FocusTracking Window where
        modifyLayoutWithUpdate :: forall (l :: * -> *).
    LayoutClass l Window =>
    FocusTracking Window
    -> Workspace String (l Window) Window
    -> Rectangle
    -> X (([(Window, Rectangle)], Maybe (l Window)),
          Maybe (FocusTracking Window))
    modifyLayoutWithUpdate (FocusTracking Maybe Window
    mw) ws :: Workspace String (l Window) Window
    ws@W.Workspace{ stack :: forall i l a. Workspace i l a -> Maybe (Stack a)
    W.stack = Maybe (Stack Window)
    ms } Rectangle
    r
          = do
            Maybe Window
    xCur <- (XState -> Maybe Window) -> X (Maybe Window)
    forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
    gets (StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Maybe Window
    forall i l a s sd. StackSet i l a s sd -> Maybe a
    W.peek (StackSet String (Layout Window) Window ScreenId ScreenDetail
     -> Maybe Window)
    -> (XState
        -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> XState
    -> Maybe Window
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    forall s i l a sd.
    (Eq s, Eq i) =>
    i -> StackSet i l a s sd -> StackSet i l a s sd
    W.view (Workspace String (l Window) Window -> String
    forall i l a. Workspace i l a -> i
    W.tag Workspace String (l Window) Window
    ws) (StackSet String (Layout Window) Window ScreenId ScreenDetail
     -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> (XState
        -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> XState
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . XState
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    windowset)
            let isF :: Bool
    isF = Maybe Window
    xCur Maybe Window -> Maybe Window -> Bool
    forall a. Eq a => a -> a -> Bool
    /= (Stack Window -> Window
    forall a. Stack a -> a
    W.focus (Stack Window -> Window) -> Maybe (Stack Window) -> Maybe Window
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe (Stack Window)
    ms)
                -- use the remembered focus point when true focus differs from
                -- what this (sub)layout is given, which happens e.g. when true
                -- focus is in floating layer or when another sublayout has focus
                newStack :: Maybe (Stack Window)
    newStack | Bool
    isF = (Maybe Window
    mw Maybe Window
    -> (Window -> Maybe (Stack Window)) -> Maybe (Stack Window)
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \Window
    w -> (Window -> Bool) -> Maybe (Stack Window) -> Maybe (Stack Window)
    forall a. (a -> Bool) -> Zipper a -> Zipper a
    findZ (Window
    wWindow -> Window -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) Maybe (Stack Window)
    ms) Maybe (Stack Window)
    -> Maybe (Stack Window) -> Maybe (Stack Window)
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Maybe (Stack Window)
    ms
                         | Bool
    otherwise = Maybe (Stack Window)
    ms
                newState :: Maybe Window
    newState | Bool
    isF = Maybe Window
    mw
                         | Bool
    otherwise = Maybe Window
    xCur
            ([(Window, Rectangle)], Maybe (l Window))
    ran <- Workspace String (l Window) Window
    -> Rectangle -> X ([(Window, Rectangle)], Maybe (l Window))
    forall (layout :: * -> *) a.
    LayoutClass layout a =>
    Workspace String (layout a) a
    -> Rectangle -> X ([(a, Rectangle)], Maybe (layout a))
    runLayout Workspace String (l Window) Window
    ws{ W.stack = newStack } Rectangle
    r
            (([(Window, Rectangle)], Maybe (l Window)),
     Maybe (FocusTracking Window))
    -> X (([(Window, Rectangle)], Maybe (l Window)),
          Maybe (FocusTracking Window))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (([(Window, Rectangle)], Maybe (l Window))
    ran, Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Maybe Window
    newState Maybe Window -> Maybe Window -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Maybe Window
    mw) Maybe () -> FocusTracking Window -> Maybe (FocusTracking Window)
    forall (f :: * -> *) a b. Functor f => f a -> b -> f b
    $> Maybe Window -> FocusTracking Window
    forall a. Maybe Window -> FocusTracking a
    FocusTracking Maybe Window
    newState)

    -- | Transform a layout into one that remembers and uses the last focus it saw.
    focusTracking ::  l a -> ModifiedLayout FocusTracking l a
    focusTracking :: forall (l :: * -> *) a. l a -> ModifiedLayout FocusTracking l a
    focusTracking = FocusTracking a -> l a -> ModifiedLayout FocusTracking l a
    forall (m :: * -> *) (l :: * -> *) a.
    m a -> l a -> ModifiedLayout m l a
    ModifiedLayout (Maybe Window -> FocusTracking a
    forall a. Maybe Window -> FocusTracking a
    FocusTracking Maybe Window
    forall a. Maybe a
    Nothing)