content: {-# LANGUAGE DeriveDataTypeable #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  XMonad.Util.SpawnNamedPipe
  -- Copyright   :  (c) Christian Wills 2014 
  -- License     :  BSD3-style (see LICENSE)
  --
  -- Maintainer  :  cwills.dev@gmail.com
  -- Stability   :  unstable
  -- Portability :  not portable
  --
  -- A module for spawning a pipe whose "Handle" lives in the Xmonad state.
  --
  -----------------------------------------------------------------------------
  
  module XMonad.Util.SpawnNamedPipe (
    -- * Usage
    -- $usage
      spawnNamedPipe
    , getNamedPipe
    ) where
  
  import XMonad
  import XMonad.Util.Run
  import System.IO
  import qualified XMonad.Util.ExtensibleState as XS
  import Control.Monad
  import qualified Data.Map as Map
  
  -- $usage
  -- This module makes it possible to spawn a pipe to Dzen2 in the startupHook
  -- and write to it from inside the logHook without the need for global
  -- variables.
  --
  -- > import XMonad.Util.SpawnNamedPipe
  -- > import Data.Maybe
  -- > 
  -- > -- StartupHook
  -- > startupHook' = spawnNamedPipe "dzen2" "dzenPipe" 
  -- > 
  -- > -- LogHook
  -- > logHook' = do
  -- >     mh <- getNamedPipeHandle "dzenPipe" 
  -- >         dynamicLogWithPP $ defaultPP {
  -- >             ppOutput = maybe (\s -> return ()) (hPutStrLn) mh}
  -- >
  -- > -- Main
  -- > main = xmonad $ defaultConfig {
  -- >                      startupHook = startupHook'
  -- >                    , logHook = logHook'}
  --
  
  data NamedPipes = NamedPipes { pipeMap :: Map.Map String Handle }
      deriving (Show, Typeable)
  
  instance ExtensionClass NamedPipes where
      initialValue = NamedPipes Map.empty 
  
  -- | When 'spawnNamedPipe' is executed with a command "String" and a name
  -- "String" respectively.  The command string is spawned with 'spawnPipe' (as
  -- long as the name chosen hasn't been used already) and the "Handle" returned
  -- is saved in Xmonad's state associated with the name "String". 
  spawnNamedPipe :: String -> String -> X ()
  spawnNamedPipe cmd name = do
    b <- XS.gets (Map.member name . pipeMap) 
    unless b $ do
      h <- spawnPipe cmd 
      XS.modify (NamedPipes . Map.insert name h . pipeMap)   
  
  -- | Attempts to retrieve a "Handle" to a pipe previously stored in Xmonad's
  -- state associated with the given string via a call to 'spawnNamedPipe'. If the
  -- given string doesn't exist in the map stored in Xmonad's state Nothing is
  -- returned.   
  getNamedPipe :: String -> X (Maybe Handle)
  getNamedPipe name = XS.gets (Map.lookup name . pipeMap)
  