    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Util.Dzen
    -- Description :  Handy wrapper for dzen.
    -- Copyright   :  (c) glasser@mit.edu
    -- License     :  BSD
    --
    -- Maintainer  :  glasser@mit.edu
    -- Stability   :  stable
    -- Portability :  unportable
    --
    -- Handy wrapper for dzen. Requires dzen >= 0.2.4.
    --
    -----------------------------------------------------------------------------

    module XMonad.Util.Dzen (
        -- * Flexible interface
        dzenConfig, DzenConfig,
        timeout,
        font,
        xScreen,
        vCenter,
        hCenter,
        center,
        onCurr,
        x,
        y,
        addArgs,
        fgColor,
        bgColor,
        align,
        slaveAlign,
        lineCount,

        -- * Legacy interface
        dzen,
        dzenScreen,
        dzenWithArgs,

        -- * Miscellaneous
        seconds,
        chomp,
        (>=>),
      ) where

    import XMonad.Prelude
    import XMonad
    import XMonad.StackSet
    import XMonad.Util.Run (runProcessWithInputAndWait, seconds)
    import XMonad.Util.Font (Align (..))

    type DzenConfig = (Int, [String]) -> X (Int, [String])

    -- | @dzenConfig config s@ will display the string @s@ according to the
    -- configuration @config@.  For example, to display the string @\"foobar\"@ with
    -- all the default settings, you can simply call
    --
    -- > dzenConfig return "foobar"
    --
    -- Or, to set a longer timeout, you could use
    --
    -- > dzenConfig (timeout 10) "foobar"
    --
    -- You can combine configurations with the (>=>) operator.  To display
    -- @\"foobar\"@ for 10 seconds on the first screen, you could use
    --
    -- > dzenConfig (timeout 10 >=> xScreen 0) "foobar"
    --
    -- As a final example, you could adapt the above to display @\"foobar\"@ for
    -- 10 seconds on the current screen with
    --
    -- > dzenConfig (timeout 10 >=> onCurr xScreen) "foobar"
    dzenConfig :: DzenConfig -> String -> X ()
    dzenConfig :: DzenConfig -> String -> X ()
    dzenConfig DzenConfig
    conf String
    s = do
        (Int
    t, [String]
    args) <- DzenConfig
    conf (Rational -> Int
    seconds Rational
    3, [])
        String -> [String] -> String -> Int -> X ()
    forall (m :: * -> *).
    MonadIO m =>
    String -> [String] -> String -> Int -> m ()
    runProcessWithInputAndWait String
    "dzen2" [String]
    args (String -> String
    chomp String
    s) Int
    t

    -- | dzen wants exactly one newline at the end of its input, so this can be
    -- used for your own invocations of dzen.  However, all functions in this
    -- module will call this for you.
    chomp :: String -> String
    chomp :: String -> String
    chomp = (String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++String
    "\n") (String -> String) -> (String -> String) -> String -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String
    forall a. [a] -> [a]
    reverse (String -> String) -> (String -> String) -> String -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    dropWhile (Char
    '\n' Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) (String -> String) -> (String -> String) -> String -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> String
    forall a. [a] -> [a]
    reverse

    -- | Set the timeout, in seconds.  This defaults to 3 seconds if not
    -- specified.
    timeout :: Rational -> DzenConfig
    timeout :: Rational -> DzenConfig
    timeout = Int -> DzenConfig
    timeoutMicro (Int -> DzenConfig) -> (Rational -> Int) -> Rational -> DzenConfig
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Rational -> Int
    seconds

    -- | Set the timeout, in microseconds.  Mostly here for the legacy
    -- interface.
    timeoutMicro :: Int -> DzenConfig
    timeoutMicro :: Int -> DzenConfig
    timeoutMicro Int
    n (Int
    _, [String]
    ss) = DzenConfig
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int
    n, [String]
    ss)

    -- | Add raw command-line arguments to the configuration.  These will be
    -- passed on verbatim to dzen2.  The default includes no arguments.
    addArgs :: [String] -> DzenConfig
    addArgs :: [String] -> DzenConfig
    addArgs [String]
    ss (Int
    n, [String]
    ss') = DzenConfig
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int
    n, [String]
    ss [String] -> [String] -> [String]
    forall a. [a] -> [a] -> [a]
    ++ [String]
    ss')

    -- | Start dzen2 on a particular screen.  Only works with versions of dzen
    -- that support the "-xs" argument.
    xScreen :: ScreenId -> DzenConfig
    xScreen :: ScreenId -> DzenConfig
    xScreen ScreenId
    sc = [String] -> DzenConfig
    addArgs [String
    "-xs", Int -> String
    forall a. Show a => a -> String
    show (ScreenId -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral ScreenId
    sc Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1 :: Int)]

    -- | Take a screen-specific configuration and supply it with the screen ID
    -- of the currently focused screen, according to xmonad.  For example, show
    -- a 100-pixel wide bar centered within the current screen, you could use
    --
    -- > dzenConfig (onCurr (hCenter 100)) "foobar"
    --
    -- Of course, you can still combine these with (>=>); for example, to center
    -- the string @\"foobar\"@ both horizontally and vertically in a 100x14 box
    -- using the lovely Terminus font, you could use
    --
    -- > terminus = "-*-terminus-*-*-*-*-12-*-*-*-*-*-*-*"
    -- > dzenConfig (onCurr (center 100 14) >=> font terminus) "foobar"
    onCurr :: (ScreenId -> DzenConfig) -> DzenConfig
    onCurr :: (ScreenId -> DzenConfig) -> DzenConfig
    onCurr ScreenId -> DzenConfig
    f (Int, [String])
    conf = (XState -> ScreenId) -> X ScreenId
    forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
    gets (Screen String (Layout Window) Window ScreenId ScreenDetail
    -> ScreenId
    forall i l a sid sd. Screen i l a sid sd -> sid
    screen (Screen String (Layout Window) Window ScreenId ScreenDetail
     -> ScreenId)
    -> (XState
        -> Screen String (Layout Window) Window ScreenId ScreenDetail)
    -> XState
    -> ScreenId
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Screen String (Layout Window) Window ScreenId ScreenDetail
    forall i l a sid sd. StackSet i l a sid sd -> Screen i l a sid sd
    current (StackSet String (Layout Window) Window ScreenId ScreenDetail
     -> Screen String (Layout Window) Window ScreenId ScreenDetail)
    -> (XState
        -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> XState
    -> Screen 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) X ScreenId -> (ScreenId -> X (Int, [String])) -> X (Int, [String])
    forall a b. X a -> (a -> X b) -> X b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= (ScreenId -> DzenConfig)
    -> (Int, [String]) -> ScreenId -> X (Int, [String])
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ScreenId -> DzenConfig
    f (Int, [String])
    conf

    -- | Put the top of the dzen bar at a particular pixel.
    x :: Int -> DzenConfig
    x :: Int -> DzenConfig
    x Int
    n = [String] -> DzenConfig
    addArgs [String
    "-x", Int -> String
    forall a. Show a => a -> String
    show Int
    n]
    -- | Put the left of the dzen bar at a particular pixel.
    y :: Int -> DzenConfig
    y :: Int -> DzenConfig
    y Int
    n = [String] -> DzenConfig
    addArgs [String
    "-y", Int -> String
    forall a. Show a => a -> String
    show Int
    n]

    -- | Set the foreground color.
    --
    -- Please be advised that @fgColor@ and @bgColor@ also exist in "XMonad.Prompt".
    -- If you use both modules, you might have to tell the compiler which one you mean:
    --
    -- > import XMonad.Prompt as P
    -- > import XMonad.Util.Dzen as D
    -- >
    -- > dzenConfig (D.fgColor "#f0f0f0") "foobar"
    fgColor :: String -> DzenConfig
    fgColor :: String -> DzenConfig
    fgColor String
    c = [String] -> DzenConfig
    addArgs [String
    "-fg", String
    c]

    -- | Set the background color.
    bgColor :: String -> DzenConfig
    bgColor :: String -> DzenConfig
    bgColor String
    c = [String] -> DzenConfig
    addArgs [String
    "-bg", String
    c]

    -- | Set the alignment of the title (main) window content.
    -- Note that @AlignRightOffset@ is treated as equal to @AlignRight@.
    --
    -- > import XMonad.Util.Font (Align(..))
    -- >
    -- > dzenConfig (align AlignLeft) "foobar"
    align :: Align -> DzenConfig
    align :: Align -> DzenConfig
    align = String -> Align -> DzenConfig
    align' String
    "-ta"

    -- | Set the alignment of the slave window content.
    -- Using this option only makes sense if you also use the @lineCount@ parameter.
    slaveAlign :: Align -> DzenConfig
    slaveAlign :: Align -> DzenConfig
    slaveAlign = String -> Align -> DzenConfig
    align' String
    "-sa"

    -- Set an alignment parameter
    align' :: String -> Align -> DzenConfig
    align' :: String -> Align -> DzenConfig
    align' String
    opt Align
    a = [String] -> DzenConfig
    addArgs [String
    opt, String
    s] where
      s :: String
    s = case Align
    a of
            Align
    AlignCenter        -> String
    "c"
            Align
    AlignLeft          -> String
    "l"
            Align
    AlignRight         -> String
    "r"
            AlignRightOffset Int
    _ -> String
    "r"

    -- | Specify the font.  Check out xfontsel to get the format of the String
    -- right; if your dzen supports xft, then you can supply that here, too.
    font :: String -> DzenConfig
    font :: String -> DzenConfig
    font String
    fn = [String] -> DzenConfig
    addArgs [String
    "-fn", String
    fn]

    -- | @vCenter height sc@ sets the configuration to have the dzen bar appear
    -- on screen @sc@ with height @height@, vertically centered with respect to
    -- the actual size of that screen.
    vCenter :: Int -> ScreenId -> DzenConfig
    vCenter :: Int -> ScreenId -> DzenConfig
    vCenter = (Rectangle -> Dimension)
    -> String -> String -> Int -> ScreenId -> DzenConfig
    center' Rectangle -> Dimension
    rect_height String
    "-h" String
    "-y"

    -- | @hCenter width sc@ sets the configuration to have the dzen bar appear
    -- on screen @sc@ with width @width@, horizontally centered with respect to
    -- the actual size of that screen.
    hCenter :: Int -> ScreenId -> DzenConfig
    hCenter :: Int -> ScreenId -> DzenConfig
    hCenter = (Rectangle -> Dimension)
    -> String -> String -> Int -> ScreenId -> DzenConfig
    center' Rectangle -> Dimension
    rect_width  String
    "-w" String
    "-x"

    -- | @center width height sc@ sets the configuration to have the dzen bar
    -- appear on screen @sc@ with width @width@ and height @height@, centered
    -- both horizontally and vertically with respect to the actual size of that
    -- screen.
    center :: Int -> Int -> ScreenId -> DzenConfig
    center :: Int -> Int -> ScreenId -> DzenConfig
    center Int
    width Int
    height ScreenId
    sc = Int -> ScreenId -> DzenConfig
    hCenter Int
    width ScreenId
    sc DzenConfig -> DzenConfig -> DzenConfig
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> Int -> ScreenId -> DzenConfig
    vCenter Int
    height ScreenId
    sc

    -- Center things along a single dimension on a particular screen.
    center' :: (Rectangle -> Dimension) -> String -> String -> Int -> ScreenId -> DzenConfig
    center' :: (Rectangle -> Dimension)
    -> String -> String -> Int -> ScreenId -> DzenConfig
    center' Rectangle -> Dimension
    selector String
    extentName String
    positionName Int
    extent ScreenId
    sc (Int, [String])
    conf = do
        Maybe Rectangle
    rect <- (XState -> Maybe Rectangle) -> X (Maybe Rectangle)
    forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
    gets (ScreenId
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Maybe Rectangle
    detailFromScreenId ScreenId
    sc (StackSet String (Layout Window) Window ScreenId ScreenDetail
     -> Maybe Rectangle)
    -> (XState
        -> StackSet String (Layout Window) Window ScreenId ScreenDetail)
    -> XState
    -> Maybe Rectangle
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . XState
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    windowset)
        case Maybe Rectangle
    rect of
            Maybe Rectangle
    Nothing -> DzenConfig
    forall a. a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Int, [String])
    conf
            Just Rectangle
    r  -> [String] -> DzenConfig
    addArgs
                [String
    extentName  , Int -> String
    forall a. Show a => a -> String
    show Int
    extent,
                 String
    positionName, Int -> String
    forall a. Show a => a -> String
    show ((Dimension -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Rectangle -> Dimension
    selector Rectangle
    r) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    extent) Int -> Int -> Int
    forall a. Integral a => a -> a -> a
    `div` Int
    2),
                 String
    "-xs"       , Int -> String
    forall a. Show a => a -> String
    show (ScreenId -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral ScreenId
    sc Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1 :: Int)
                ] (Int, [String])
    conf

    -- Get the rectangle outlining a particular screen.
    detailFromScreenId :: ScreenId -> WindowSet -> Maybe Rectangle
    detailFromScreenId :: ScreenId
    -> StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Maybe Rectangle
    detailFromScreenId ScreenId
    sc StackSet String (Layout Window) Window ScreenId ScreenDetail
    ws = (ScreenDetail -> Rectangle)
    -> Maybe ScreenDetail -> Maybe Rectangle
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ScreenDetail -> Rectangle
    screenRect Maybe ScreenDetail
    maybeSD where
        c :: Screen String (Layout Window) Window ScreenId ScreenDetail
    c       = StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> Screen String (Layout Window) Window ScreenId ScreenDetail
    forall i l a sid sd. StackSet i l a sid sd -> Screen i l a sid sd
    current StackSet String (Layout Window) Window ScreenId ScreenDetail
    ws
        v :: [Screen String (Layout Window) Window ScreenId ScreenDetail]
    v       = StackSet String (Layout Window) Window ScreenId ScreenDetail
    -> [Screen String (Layout Window) Window ScreenId ScreenDetail]
    forall i l a sid sd. StackSet i l a sid sd -> [Screen i l a sid sd]
    visible StackSet String (Layout Window) Window ScreenId ScreenDetail
    ws
        mapping :: [(ScreenId, ScreenDetail)]
    mapping = (Screen String (Layout Window) Window ScreenId ScreenDetail
     -> (ScreenId, ScreenDetail))
    -> [Screen String (Layout Window) Window ScreenId ScreenDetail]
    -> [(ScreenId, ScreenDetail)]
    forall a b. (a -> b) -> [a] -> [b]
    map (\Screen String (Layout Window) Window ScreenId ScreenDetail
    s -> (Screen String (Layout Window) Window ScreenId ScreenDetail
    -> ScreenId
    forall i l a sid sd. Screen i l a sid sd -> sid
    screen Screen String (Layout Window) Window ScreenId ScreenDetail
    s, Screen String (Layout Window) Window ScreenId ScreenDetail
    -> ScreenDetail
    forall i l a sid sd. Screen i l a sid sd -> sd
    screenDetail Screen String (Layout Window) Window ScreenId ScreenDetail
    s)) (Screen String (Layout Window) Window ScreenId ScreenDetail
    cScreen String (Layout Window) Window ScreenId ScreenDetail
    -> [Screen String (Layout Window) Window ScreenId ScreenDetail]
    -> [Screen String (Layout Window) Window ScreenId ScreenDetail]
    forall a. a -> [a] -> [a]
    :[Screen String (Layout Window) Window ScreenId ScreenDetail]
    v)
        maybeSD :: Maybe ScreenDetail
    maybeSD = ScreenId -> [(ScreenId, ScreenDetail)] -> Maybe ScreenDetail
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup ScreenId
    sc [(ScreenId, ScreenDetail)]
    mapping

    -- | Enable slave window and specify the number of lines.
    --
    -- Dzen can optionally draw a second window underneath the title window.
    -- By default, this window is only displayed if the mouse enters the title window.
    -- This option is only useful if the string you want to display contains more than one line.
    lineCount :: Int -> DzenConfig
    lineCount :: Int -> DzenConfig
    lineCount Int
    n = [String] -> DzenConfig
    addArgs [String
    "-l", Int -> String
    forall a. Show a => a -> String
    show Int
    n]

    -- | @dzen str timeout@ pipes @str@ to dzen2 for @timeout@ microseconds.
    -- Example usage:
    --
    -- > dzen "Hi, mom!" (5 `seconds`)
    dzen :: String -> Int -> X ()
    dzen :: String -> Int -> X ()
    dzen = (Int -> String -> X ()) -> String -> Int -> X ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (DzenConfig -> String -> X ()
    dzenConfig (DzenConfig -> String -> X ())
    -> (Int -> DzenConfig) -> Int -> String -> X ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> DzenConfig
    timeoutMicro)

    -- | @dzen str args timeout@ pipes @str@ to dzen2 for @timeout@ seconds, passing @args@ to dzen.
    -- Example usage:
    --
    -- > dzenWithArgs "Hi, dons!" ["-ta", "r"] (5 `seconds`)
    dzenWithArgs :: String -> [String] -> Int -> X ()
    dzenWithArgs :: String -> [String] -> Int -> X ()
    dzenWithArgs String
    str [String]
    args Int
    t = DzenConfig -> String -> X ()
    dzenConfig (Int -> DzenConfig
    timeoutMicro Int
    t DzenConfig -> DzenConfig -> DzenConfig
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> [String] -> DzenConfig
    addArgs [String]
    args) String
    str

    -- | @dzenScreen sc str timeout@ pipes @str@ to dzen2 for @timeout@ microseconds, and on screen @sc@.
    -- Requires dzen to be compiled with Xinerama support.
    dzenScreen :: ScreenId -> String -> Int -> X ()
    dzenScreen :: ScreenId -> String -> Int -> X ()
    dzenScreen ScreenId
    sc String
    str Int
    t = DzenConfig -> String -> X ()
    dzenConfig (Int -> DzenConfig
    timeoutMicro Int
    t DzenConfig -> DzenConfig -> DzenConfig
    forall (m :: * -> *) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> ScreenId -> DzenConfig
    xScreen ScreenId
    sc) String
    str