    {-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, TypeSynonymInstances, PatternGuards #-}

    ----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Layout.Hidden
    -- Description :  Hide windows from layouts.
    -- Copyright   :  (c) Peter Jones 2015
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  pjones@devalot.com
    -- Stability   :  unstable
    -- Portability :  not portable
    --
    -- Similar to "XMonad.Layout.Minimize" but completely removes windows
    -- from the window set so "XMonad.Layout.BoringWindows" isn't
    -- necessary.  Perfect companion to
    -- "XMonad.Layout.BinarySpacePartition" since it can be used to move
    -- windows to another part of the BSP tree.
    --
    -----------------------------------------------------------------------------
    module XMonad.Layout.Hidden
           ( -- * Usage
             -- $usage
             HiddenWindows
           , HiddenMsg (..)
           , hiddenWindows
           , hideWindow
           , popOldestHiddenWindow
           , popNewestHiddenWindow
           , popHiddenWindow
           ) where

    --------------------------------------------------------------------------------
    import XMonad
    import XMonad.Layout.LayoutModifier
    import qualified XMonad.StackSet as W

    --------------------------------------------------------------------------------
    -- $usage
    -- You can use this module with the following in your @xmonad.hs@:
    --
    -- > import XMonad.Layout.Hidden
    --
    -- Then edit your @layoutHook@ by adding the @HiddenWindows@ layout modifier:
    --
    -- > myLayout = hiddenWindows (Tall 1 (3/100) (1/2)) ||| Full ||| etc..
    -- > main = xmonad def { layoutHook = myLayout }
    --
    -- For more detailed instructions on editing the layoutHook see
    -- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial> and
    -- "XMonad.Doc.Extending#Editing_the_layout_hook".
    --
    -- In the key bindings, do something like:
    --
    -- >        , ((modMask, xK_backslash), withFocused hideWindow)
    -- >        , ((modMask .|. shiftMask, xK_backslash), popOldestHiddenWindow)
    -- >        ...
    --
    -- For detailed instruction on editing the key bindings see:
    --
    -- <https://xmonad.org/TUTORIAL.html#customizing-xmonad the tutorial>.

    --------------------------------------------------------------------------------
    newtype HiddenWindows a = HiddenWindows [Window] deriving (Int -> HiddenWindows a -> ShowS
    [HiddenWindows a] -> ShowS
    HiddenWindows a -> String
    (Int -> HiddenWindows a -> ShowS)
    -> (HiddenWindows a -> String)
    -> ([HiddenWindows a] -> ShowS)
    -> Show (HiddenWindows a)
    forall a. Int -> HiddenWindows a -> ShowS
    forall a. [HiddenWindows a] -> ShowS
    forall a. HiddenWindows a -> String
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: forall a. Int -> HiddenWindows a -> ShowS
    showsPrec :: Int -> HiddenWindows a -> ShowS
    $cshow :: forall a. HiddenWindows a -> String
    show :: HiddenWindows a -> String
    $cshowList :: forall a. [HiddenWindows a] -> ShowS
    showList :: [HiddenWindows a] -> ShowS
    Show, ReadPrec [HiddenWindows a]
    ReadPrec (HiddenWindows a)
    Int -> ReadS (HiddenWindows a)
    ReadS [HiddenWindows a]
    (Int -> ReadS (HiddenWindows a))
    -> ReadS [HiddenWindows a]
    -> ReadPrec (HiddenWindows a)
    -> ReadPrec [HiddenWindows a]
    -> Read (HiddenWindows a)
    forall a. ReadPrec [HiddenWindows a]
    forall a. ReadPrec (HiddenWindows a)
    forall a. Int -> ReadS (HiddenWindows a)
    forall a. ReadS [HiddenWindows a]
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: forall a. Int -> ReadS (HiddenWindows a)
    readsPrec :: Int -> ReadS (HiddenWindows a)
    $creadList :: forall a. ReadS [HiddenWindows a]
    readList :: ReadS [HiddenWindows a]
    $creadPrec :: forall a. ReadPrec (HiddenWindows a)
    readPrec :: ReadPrec (HiddenWindows a)
    $creadListPrec :: forall a. ReadPrec [HiddenWindows a]
    readListPrec :: ReadPrec [HiddenWindows a]
    Read)

    --------------------------------------------------------------------------------
    -- | Messages for the @HiddenWindows@ layout modifier.
    data HiddenMsg = HideWindow Window                -- ^ Hide a window.
                   | PopNewestHiddenWindow            -- ^ Restore window (FILO).
                   | PopOldestHiddenWindow            -- ^ Restore window (FIFO).
                   | PopSpecificHiddenWindow Window   -- ^ Restore specific window.
                   deriving (HiddenMsg -> HiddenMsg -> Bool
    (HiddenMsg -> HiddenMsg -> Bool)
    -> (HiddenMsg -> HiddenMsg -> Bool) -> Eq HiddenMsg
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: HiddenMsg -> HiddenMsg -> Bool
    == :: HiddenMsg -> HiddenMsg -> Bool
    $c/= :: HiddenMsg -> HiddenMsg -> Bool
    /= :: HiddenMsg -> HiddenMsg -> Bool
    Eq)

    instance Message HiddenMsg

    --------------------------------------------------------------------------------
    instance LayoutModifier HiddenWindows Window where
      handleMess :: HiddenWindows Window
    -> SomeMessage -> X (Maybe (HiddenWindows Window))
    handleMess h :: HiddenWindows Window
    h@(HiddenWindows [Window]
    hidden) SomeMessage
    mess
        | Just (HideWindow Window
    win)              <- SomeMessage -> Maybe HiddenMsg
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    mess = HiddenWindows Window -> Window -> X (Maybe (HiddenWindows Window))
    forall a. HiddenWindows a -> Window -> X (Maybe (HiddenWindows a))
    hideWindowMsg HiddenWindows Window
    h Window
    win
        | Just HiddenMsg
    PopNewestHiddenWindow         <- SomeMessage -> Maybe HiddenMsg
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    mess = HiddenWindows Window -> X (Maybe (HiddenWindows Window))
    forall a. HiddenWindows a -> X (Maybe (HiddenWindows a))
    popNewestMsg HiddenWindows Window
    h
        | Just HiddenMsg
    PopOldestHiddenWindow         <- SomeMessage -> Maybe HiddenMsg
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    mess = HiddenWindows Window -> X (Maybe (HiddenWindows Window))
    forall a. HiddenWindows a -> X (Maybe (HiddenWindows a))
    popOldestMsg HiddenWindows Window
    h
        | Just (PopSpecificHiddenWindow Window
    win) <- SomeMessage -> Maybe HiddenMsg
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    mess = Window -> HiddenWindows Window -> X (Maybe (HiddenWindows Window))
    forall a. Window -> HiddenWindows a -> X (Maybe (HiddenWindows a))
    popSpecificMsg Window
    win HiddenWindows Window
    h
        | Just LayoutMessages
    ReleaseResources              <- SomeMessage -> Maybe LayoutMessages
    forall m. Message m => SomeMessage -> Maybe m
    fromMessage SomeMessage
    mess = X (Maybe (HiddenWindows Window))
    forall {a}. X (Maybe a)
    doUnhook
        | Bool
    otherwise                                        = Maybe (HiddenWindows Window) -> X (Maybe (HiddenWindows Window))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (HiddenWindows Window)
    forall a. Maybe a
    Nothing
        where doUnhook :: X (Maybe a)
    doUnhook = do (Window -> X ()) -> [Window] -> X ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ Window -> X ()
    restoreWindow [Window]
    hidden
                            Maybe a -> X (Maybe a)
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe a
    forall a. Maybe a
    Nothing

      modifierDescription :: HiddenWindows Window -> String
    modifierDescription HiddenWindows Window
    _ = String
    "Hidden"

    --------------------------------------------------------------------------------
    -- | Apply the @HiddenWindows@ layout modifier.
    hiddenWindows :: LayoutClass l Window => l Window -> ModifiedLayout HiddenWindows l Window
    hiddenWindows :: forall (l :: * -> *).
    LayoutClass l Window =>
    l Window -> ModifiedLayout HiddenWindows l Window
    hiddenWindows = HiddenWindows Window
    -> l Window -> ModifiedLayout HiddenWindows l Window
    forall (m :: * -> *) (l :: * -> *) a.
    m a -> l a -> ModifiedLayout m l a
    ModifiedLayout (HiddenWindows Window
     -> l Window -> ModifiedLayout HiddenWindows l Window)
    -> HiddenWindows Window
    -> l Window
    -> ModifiedLayout HiddenWindows l Window
    forall a b. (a -> b) -> a -> b
    $ [Window] -> HiddenWindows Window
    forall a. [Window] -> HiddenWindows a
    HiddenWindows []

    --------------------------------------------------------------------------------
    -- | Remove the given window from the current layout.  It is placed in
    -- list of hidden windows so it can be restored later.
    hideWindow :: Window -> X ()
    hideWindow :: Window -> X ()
    hideWindow = HiddenMsg -> X ()
    forall a. Message a => a -> X ()
    sendMessage (HiddenMsg -> X ()) -> (Window -> HiddenMsg) -> Window -> X ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Window -> HiddenMsg
    HideWindow

    --------------------------------------------------------------------------------
    -- | Restore a previously hidden window.  Using this function will
    -- treat the list of hidden windows as a FIFO queue.  That is, the
    -- first window hidden will be restored.
    popOldestHiddenWindow :: X ()
    popOldestHiddenWindow :: X ()
    popOldestHiddenWindow = HiddenMsg -> X ()
    forall a. Message a => a -> X ()
    sendMessage HiddenMsg
    PopOldestHiddenWindow

    --------------------------------------------------------------------------------
    -- | Restore a previously hidden window.  Using this function will
    -- treat the list of hidden windows as a FILO queue.  That is, the
    -- most recently hidden window will be restored.
    popNewestHiddenWindow :: X ()
    popNewestHiddenWindow :: X ()
    popNewestHiddenWindow = HiddenMsg -> X ()
    forall a. Message a => a -> X ()
    sendMessage HiddenMsg
    PopNewestHiddenWindow

    popHiddenWindow :: Window -> X ()
    popHiddenWindow :: Window -> X ()
    popHiddenWindow = HiddenMsg -> X ()
    forall a. Message a => a -> X ()
    sendMessage (HiddenMsg -> X ()) -> (Window -> HiddenMsg) -> Window -> X ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Window -> HiddenMsg
    PopSpecificHiddenWindow

    --------------------------------------------------------------------------------
    hideWindowMsg :: HiddenWindows a -> Window -> X (Maybe (HiddenWindows a))
    hideWindowMsg :: forall a. HiddenWindows a -> Window -> X (Maybe (HiddenWindows a))
    hideWindowMsg (HiddenWindows [Window]
    hidden) Window
    win = do
      (XState -> XState) -> X ()
    forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
    modify (\XState
    s -> XState
    s { windowset = W.delete' win $ windowset s })
      Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a)))
    -> ([Window] -> Maybe (HiddenWindows a))
    -> [Window]
    -> X (Maybe (HiddenWindows a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HiddenWindows a -> Maybe (HiddenWindows a)
    forall a. a -> Maybe a
    Just (HiddenWindows a -> Maybe (HiddenWindows a))
    -> ([Window] -> HiddenWindows a)
    -> [Window]
    -> Maybe (HiddenWindows a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Window] -> HiddenWindows a
    forall a. [Window] -> HiddenWindows a
    HiddenWindows ([Window] -> X (Maybe (HiddenWindows a)))
    -> [Window] -> X (Maybe (HiddenWindows a))
    forall a b. (a -> b) -> a -> b
    $ [Window]
    hidden [Window] -> [Window] -> [Window]
    forall a. [a] -> [a] -> [a]
    ++ [Window
    win]

    --------------------------------------------------------------------------------
    popNewestMsg :: HiddenWindows a -> X (Maybe (HiddenWindows a))
    popNewestMsg :: forall a. HiddenWindows a -> X (Maybe (HiddenWindows a))
    popNewestMsg (HiddenWindows [])     = Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (HiddenWindows a)
    forall a. Maybe a
    Nothing
    popNewestMsg (HiddenWindows [Window]
    hidden) = do
      let (Window
    win, [Window]
    rest) = ([Window] -> Window
    forall a. HasCallStack => [a] -> a
    last [Window]
    hidden, [Window] -> [Window]
    forall a. HasCallStack => [a] -> [a]
    init [Window]
    hidden)
      Window -> X ()
    restoreWindow Window
    win
      Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a)))
    -> ([Window] -> Maybe (HiddenWindows a))
    -> [Window]
    -> X (Maybe (HiddenWindows a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HiddenWindows a -> Maybe (HiddenWindows a)
    forall a. a -> Maybe a
    Just (HiddenWindows a -> Maybe (HiddenWindows a))
    -> ([Window] -> HiddenWindows a)
    -> [Window]
    -> Maybe (HiddenWindows a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Window] -> HiddenWindows a
    forall a. [Window] -> HiddenWindows a
    HiddenWindows ([Window] -> X (Maybe (HiddenWindows a)))
    -> [Window] -> X (Maybe (HiddenWindows a))
    forall a b. (a -> b) -> a -> b
    $ [Window]
    rest

    --------------------------------------------------------------------------------
    popOldestMsg :: HiddenWindows a -> X (Maybe (HiddenWindows a))
    popOldestMsg :: forall a. HiddenWindows a -> X (Maybe (HiddenWindows a))
    popOldestMsg (HiddenWindows [])         = Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (HiddenWindows a)
    forall a. Maybe a
    Nothing
    popOldestMsg (HiddenWindows (Window
    win:[Window]
    rest)) = do
      Window -> X ()
    restoreWindow Window
    win
      Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a)))
    -> ([Window] -> Maybe (HiddenWindows a))
    -> [Window]
    -> X (Maybe (HiddenWindows a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HiddenWindows a -> Maybe (HiddenWindows a)
    forall a. a -> Maybe a
    Just (HiddenWindows a -> Maybe (HiddenWindows a))
    -> ([Window] -> HiddenWindows a)
    -> [Window]
    -> Maybe (HiddenWindows a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Window] -> HiddenWindows a
    forall a. [Window] -> HiddenWindows a
    HiddenWindows ([Window] -> X (Maybe (HiddenWindows a)))
    -> [Window] -> X (Maybe (HiddenWindows a))
    forall a b. (a -> b) -> a -> b
    $ [Window]
    rest

    --------------------------------------------------------------------------------
    popSpecificMsg :: Window -> HiddenWindows a -> X (Maybe (HiddenWindows a))
    popSpecificMsg :: forall a. Window -> HiddenWindows a -> X (Maybe (HiddenWindows a))
    popSpecificMsg Window
    _   (HiddenWindows []) = Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (HiddenWindows a)
    forall a. Maybe a
    Nothing
    popSpecificMsg Window
    win (HiddenWindows [Window]
    hiddenWins) = if Window
    win Window -> [Window] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [Window]
    hiddenWins
      then do
        Window -> X ()
    restoreWindow Window
    win
        Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a)))
    -> ([Window] -> Maybe (HiddenWindows a))
    -> [Window]
    -> X (Maybe (HiddenWindows a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HiddenWindows a -> Maybe (HiddenWindows a)
    forall a. a -> Maybe a
    Just (HiddenWindows a -> Maybe (HiddenWindows a))
    -> ([Window] -> HiddenWindows a)
    -> [Window]
    -> Maybe (HiddenWindows a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Window] -> HiddenWindows a
    forall a. [Window] -> HiddenWindows a
    HiddenWindows ([Window] -> X (Maybe (HiddenWindows a)))
    -> [Window] -> X (Maybe (HiddenWindows a))
    forall a b. (a -> b) -> a -> b
    $ (Window -> Bool) -> [Window] -> [Window]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Window -> Window -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Window
    win) [Window]
    hiddenWins
      else
        Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a))
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe (HiddenWindows a) -> X (Maybe (HiddenWindows a)))
    -> ([Window] -> Maybe (HiddenWindows a))
    -> [Window]
    -> X (Maybe (HiddenWindows a))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HiddenWindows a -> Maybe (HiddenWindows a)
    forall a. a -> Maybe a
    Just (HiddenWindows a -> Maybe (HiddenWindows a))
    -> ([Window] -> HiddenWindows a)
    -> [Window]
    -> Maybe (HiddenWindows a)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Window] -> HiddenWindows a
    forall a. [Window] -> HiddenWindows a
    HiddenWindows ([Window] -> X (Maybe (HiddenWindows a)))
    -> [Window] -> X (Maybe (HiddenWindows a))
    forall a b. (a -> b) -> a -> b
    $ [Window]
    hiddenWins

    --------------------------------------------------------------------------------
    restoreWindow :: Window -> X ()
    restoreWindow :: Window -> X ()
    restoreWindow = (StackSet String (Layout Window) Window ScreenId ScreenDetail
     -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> X ()
    windows ((StackSet String (Layout Window) Window ScreenId ScreenDetail
      -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
     -> X ())
    -> (Window
        -> StackSet String (Layout Window) Window ScreenId ScreenDetail
        -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> Window
    -> X ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Window
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    forall a i l s sd.
    Eq a =>
    a -> StackSet i l a s sd -> StackSet i l a s sd
    W.insertUp