    {-# LANGUAGE DeriveDataTypeable #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Util.SessionStart
    -- Copyright   :  (c) Markus Ongyerth 2017
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  markus@ongy.net
    -- Stability   :  unstable
    -- Portability :  not portable
    --
    -- A module for detectiong session startup.  Useful to start
    -- status bars, compositors and session initialization.
    -- This is a more general approach than spawnOnce and allows spawnOn etc.
    -----------------------------------------------------------------------------

    module XMonad.Util.SessionStart
        ( doOnce
        , isSessionStart
        , setSessionStarted
        )
    where

    import Control.Monad (when)
    import Control.Applicative ((<$>))

    import XMonad
    import qualified XMonad.Util.ExtensibleState as XS

    -- ---------------------------------------------------------------------
    -- $usage
    --
    -- Add 'setSessionStarted' at the end of the 'startupHook' to set the
    -- flag.
    --
    -- To do something only when the session is started up, use
    -- 'isSessionStart' to query or wrap it in 'doOnce' to only do it when
    -- the flag isn't set.
    -- ---------------------------------------------------------------------

    data SessionStart = SessionStart { SessionStart -> Bool
    unSessionStart :: Bool }
        deriving (ReadPrec [SessionStart]
    ReadPrec SessionStart
    Int -> ReadS SessionStart
    ReadS [SessionStart]
    (Int -> ReadS SessionStart)
    -> ReadS [SessionStart]
    -> ReadPrec SessionStart
    -> ReadPrec [SessionStart]
    -> Read SessionStart
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [SessionStart]
    $creadListPrec :: ReadPrec [SessionStart]
    readPrec :: ReadPrec SessionStart
    $creadPrec :: ReadPrec SessionStart
    readList :: ReadS [SessionStart]
    $creadList :: ReadS [SessionStart]
    readsPrec :: Int -> ReadS SessionStart
    $creadsPrec :: Int -> ReadS SessionStart
    Read, Int -> SessionStart -> ShowS
    [SessionStart] -> ShowS
    SessionStart -> String
    (Int -> SessionStart -> ShowS)
    -> (SessionStart -> String)
    -> ([SessionStart] -> ShowS)
    -> Show SessionStart
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [SessionStart] -> ShowS
    $cshowList :: [SessionStart] -> ShowS
    show :: SessionStart -> String
    $cshow :: SessionStart -> String
    showsPrec :: Int -> SessionStart -> ShowS
    $cshowsPrec :: Int -> SessionStart -> ShowS
    Show, Typeable)

    instance ExtensionClass SessionStart where
        initialValue :: SessionStart
    initialValue = Bool -> SessionStart
    SessionStart Bool
    True
        extensionType :: SessionStart -> StateExtension
    extensionType = SessionStart -> StateExtension
    forall a. (Read a, Show a, ExtensionClass a) => a -> StateExtension
    PersistentExtension

    -- | Use this to only do a part of your hook on session start
    doOnce :: X () -> X ()
    doOnce :: X () -> X ()
    doOnce act :: X ()
    act = do
        Bool
    startup <- X Bool
    isSessionStart
        Bool -> X () -> X ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when Bool
    startup X ()
    act

    -- | Query if the current startup is the session start
    isSessionStart :: X Bool
    isSessionStart :: X Bool
    isSessionStart = SessionStart -> Bool
    unSessionStart (SessionStart -> Bool) -> X SessionStart -> X Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> X SessionStart
    forall a (m :: * -> *). (ExtensionClass a, XLike m) => m a
    XS.get

    -- This should become a noop/be deprecated when merged into master, and
    -- the flag should be set when the state file is loaded.
    -- | This currently has to be added to the end of the startup hook to
    -- set the flag.
    setSessionStarted :: X ()
    setSessionStarted :: X ()
    setSessionStarted = SessionStart -> X ()
    forall a (m :: * -> *). (ExtensionClass a, XLike m) => a -> m ()
    XS.put (SessionStart -> X ()) -> SessionStart -> X ()
    forall a b. (a -> b) -> a -> b
    $ Bool -> SessionStart
    SessionStart Bool
    False