    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Util.DebugWindow
    -- Copyright   :  (c) Brandon S Allbery KF8NH, 2014
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  allbery.b@gmail.com
    -- Stability   :  unstable
    -- Portability :  not portable
    --
    -- Module to dump window information for diagnostic/debugging purposes. See
    -- "XMonad.Hooks.DebugEvents" and "XMonad.Hooks.DebugStack" for practical uses.
    --
    -----------------------------------------------------------------------------

    module XMonad.Util.DebugWindow (debugWindow) where

    import           Prelude

    import           XMonad

    import           Codec.Binary.UTF8.String        (decodeString)
    import           Control.Exception.Extensible                          as E
    import           Control.Monad                   (when)
    import           Data.List                       (unfoldr
                                                     ,intercalate
                                                     )
    import           Foreign
    import           Foreign.C.String
    import           Numeric                         (showHex)
    import           System.Exit

    -- | Output a window by ID in hex, decimal, its ICCCM resource name and class,
    --   and its title if available.  Also indicate override_redirect with an
    --   exclamation mark, and wrap in brackets if it is unmapped or withdrawn.
    debugWindow   :: Window -> X String
    debugWindow :: Window -> X String
    debugWindow 0 =  String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return "-no window-"
    debugWindow w :: Window
    w =  do
      let wx :: String
    wx = Int -> Char -> String -> String
    pad 8 '0' (String -> String) -> String -> String
    forall a b. (a -> b) -> a -> b
    $ Window -> String -> String
    forall a. (Integral a, Show a) => a -> String -> String
    showHex Window
    w ""
      Maybe WindowAttributes
    w' <- (Display -> X (Maybe WindowAttributes))
    -> X (Maybe WindowAttributes)
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X (Maybe WindowAttributes))
     -> X (Maybe WindowAttributes))
    -> (Display -> X (Maybe WindowAttributes))
    -> X (Maybe WindowAttributes)
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d -> IO (Maybe WindowAttributes) -> X (Maybe WindowAttributes)
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (Display -> Window -> IO (Maybe WindowAttributes)
    safeGetWindowAttributes Display
    d Window
    w)
      case Maybe WindowAttributes
    w' of
        Nothing                                   ->
          String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> X String) -> String -> X String
    forall a b. (a -> b) -> a -> b
    $ "(deleted window " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    wx String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ ")"
        Just (WindowAttributes
          { wa_x :: WindowAttributes -> CInt
    wa_x                 = CInt
    x
          , wa_y :: WindowAttributes -> CInt
    wa_y                 = CInt
    y
          , wa_width :: WindowAttributes -> CInt
    wa_width             = CInt
    wid
          , wa_height :: WindowAttributes -> CInt
    wa_height            = CInt
    ht
          , wa_border_width :: WindowAttributes -> CInt
    wa_border_width      = CInt
    bw
          , wa_map_state :: WindowAttributes -> CInt
    wa_map_state         = CInt
    m
          , wa_override_redirect :: WindowAttributes -> Bool
    wa_override_redirect = Bool
    o
          }) -> do
          Maybe [CChar]
    c' <- (Display -> X (Maybe [CChar])) -> X (Maybe [CChar])
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X (Maybe [CChar])) -> X (Maybe [CChar]))
    -> (Display -> X (Maybe [CChar])) -> X (Maybe [CChar])
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d ->
                IO (Maybe [CChar]) -> X (Maybe [CChar])
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (Display -> Window -> Window -> IO (Maybe [CChar])
    getWindowProperty8 Display
    d Window
    wM_CLASS Window
    w)
          let c :: String
    c = case Maybe [CChar]
    c' of
                    Nothing -> ""
                    Just c'' :: [CChar]
    c''  -> String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate "/" ([String] -> String) -> [String] -> String
    forall a b. (a -> b) -> a -> b
    $
                                 ((String -> Maybe (String, String)) -> String -> [String])
    -> String -> (String -> Maybe (String, String)) -> [String]
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (String -> Maybe (String, String)) -> String -> [String]
    forall b a. (b -> Maybe (a, b)) -> b -> [a]
    unfoldr ((CChar -> Char) -> [CChar] -> String
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> Char
    forall a. Enum a => Int -> a
    toEnum (Int -> Char) -> (CChar -> Int) -> CChar -> Char
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CChar -> Int
    forall a. Enum a => a -> Int
    fromEnum) [CChar]
    c'') ((String -> Maybe (String, String)) -> [String])
    -> (String -> Maybe (String, String)) -> [String]
    forall a b. (a -> b) -> a -> b
    $
                                 \s :: String
    s -> if String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    s
                                         then Maybe (String, String)
    forall a. Maybe a
    Nothing
                                         else let (w'' :: String
    w'',s'' :: String
    s'') = (Char -> Bool) -> String -> (String, String)
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == '\NUL') String
    s
                                                  s' :: String
    s'      = if String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    s''
                                                              then String
    s''
                                                              else String -> String
    forall a. [a] -> [a]
    tail String
    s''
                                              in (String, String) -> Maybe (String, String)
    forall a. a -> Maybe a
    Just (String
    w'',String
    s')
          String
    t <- X String -> X String -> X String
    forall a. X a -> X a -> X a
    catchX' (String -> String
    wrap (String -> String) -> X String -> X String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` String -> Window -> X String
    getEWMHTitle  "VISIBLE" Window
    w) (X String -> X String) -> X String -> X String
    forall a b. (a -> b) -> a -> b
    $
               X String -> X String -> X String
    forall a. X a -> X a -> X a
    catchX' (String -> String
    wrap (String -> String) -> X String -> X String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` String -> Window -> X String
    getEWMHTitle  ""        Window
    w) (X String -> X String) -> X String -> X String
    forall a b. (a -> b) -> a -> b
    $
               X String -> X String -> X String
    forall a. X a -> X a -> X a
    catchX' (String -> String
    wrap (String -> String) -> X String -> X String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Window -> X String
    getICCCMTitle           Window
    w) (X String -> X String) -> X String -> X String
    forall a b. (a -> b) -> a -> b
    $
               String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return ""
          String
    h' <- Window -> X String
    getMachine Window
    w
          let h :: String
    h = if String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    h' then "" else '@'Char -> String -> String
    forall a. a -> [a] -> [a]
    :String
    h'
          -- if it has WM_COMMAND use it, else use the appName
          -- NB. modern stuff often does not set WM_COMMAND since it's only ICCCM required and not some
          -- horrible gnome/freedesktop session manager thing like Wayland intended. How helpful of them.
          [String]
    p' <- (Display -> X [String]) -> X [String]
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X [String]) -> X [String])
    -> (Display -> X [String]) -> X [String]
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d -> Display -> Window -> X [String]
    safeGetCommand Display
    d Window
    w
          let p :: String
    p = if [String] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [String]
    p' then "" else String -> String
    wrap (String -> String) -> String -> String
    forall a b. (a -> b) -> a -> b
    $ String -> [String] -> String
    forall a. [a] -> [[a]] -> [a]
    intercalate " " [String]
    p'
          Window
    nWP <- String -> X Window
    getAtom "_NET_WM_PID"
          Maybe [CLong]
    pid' <- (Display -> X (Maybe [CLong])) -> X (Maybe [CLong])
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X (Maybe [CLong])) -> X (Maybe [CLong]))
    -> (Display -> X (Maybe [CLong])) -> X (Maybe [CLong])
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d -> IO (Maybe [CLong]) -> X (Maybe [CLong])
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO (Maybe [CLong]) -> X (Maybe [CLong]))
    -> IO (Maybe [CLong]) -> X (Maybe [CLong])
    forall a b. (a -> b) -> a -> b
    $ Display -> Window -> Window -> IO (Maybe [CLong])
    getWindowProperty32 Display
    d Window
    nWP Window
    w
          let pid :: String
    pid = case Maybe [CLong]
    pid' of
                      Just [pid'' :: CLong
    pid''] -> '('Char -> String -> String
    forall a. a -> [a] -> [a]
    :CLong -> String
    forall a. Show a => a -> String
    show CLong
    pid'' String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ ")"
                      _            -> ""
          let cmd :: String
    cmd = String
    p String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    pid String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    h
          let (lb :: String
    lb,rb :: String
    rb) = case () of
                          () | CInt
    m CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    == CInt
    waIsViewable -> ("","")
                             | Bool
    otherwise         -> ("[","]")
              o' :: String
    o'      = if Bool
    o then "!" else ""
          String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> X String) -> String -> X String
    forall a b. (a -> b) -> a -> b
    $ [String] -> String
    forall (t :: * -> *) a. Foldable t => t [a] -> [a]
    concat [String
    lb
                          ,String
    o'
                          ,String
    wx
                          ,String
    t
                          ," "
                          ,CInt -> String
    forall a. Show a => a -> String
    show CInt
    wid
                          ,'x'Char -> String -> String
    forall a. a -> [a] -> [a]
    :CInt -> String
    forall a. Show a => a -> String
    show CInt
    ht
                          ,if CInt
    bw CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    == 0 then "" else '+'Char -> String -> String
    forall a. a -> [a] -> [a]
    :CInt -> String
    forall a. Show a => a -> String
    show CInt
    bw
                          ,"@"
                          ,CInt -> String
    forall a. Show a => a -> String
    show CInt
    x
                          ,','Char -> String -> String
    forall a. a -> [a] -> [a]
    :CInt -> String
    forall a. Show a => a -> String
    show CInt
    y
                          ,if String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    c then "" else ' 'Char -> String -> String
    forall a. a -> [a] -> [a]
    :String
    c
                          ,if String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    cmd then "" else ' 'Char -> String -> String
    forall a. a -> [a] -> [a]
    :String
    cmd
                          ,String
    rb
                          ]

    getEWMHTitle       :: String -> Window -> X String
    getEWMHTitle :: String -> Window -> X String
    getEWMHTitle sub :: String
    sub w :: Window
    w =  do
      Window
    a <- String -> X Window
    getAtom (String -> X Window) -> String -> X Window
    forall a b. (a -> b) -> a -> b
    $ "_NET_WM_" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ (if String -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    sub then "" else '_'Char -> String -> String
    forall a. a -> [a] -> [a]
    :String
    sub) String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "_NAME"
      (Just t :: [CLong]
    t) <- (Display -> X (Maybe [CLong])) -> X (Maybe [CLong])
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X (Maybe [CLong])) -> X (Maybe [CLong]))
    -> (Display -> X (Maybe [CLong])) -> X (Maybe [CLong])
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d -> IO (Maybe [CLong]) -> X (Maybe [CLong])
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO (Maybe [CLong]) -> X (Maybe [CLong]))
    -> IO (Maybe [CLong]) -> X (Maybe [CLong])
    forall a b. (a -> b) -> a -> b
    $ Display -> Window -> Window -> IO (Maybe [CLong])
    getWindowProperty32 Display
    d Window
    a Window
    w
      String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return (String -> X String) -> String -> X String
    forall a b. (a -> b) -> a -> b
    $ (CLong -> Char) -> [CLong] -> String
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> Char
    forall a. Enum a => Int -> a
    toEnum (Int -> Char) -> (CLong -> Int) -> CLong -> Char
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CLong -> Int
    forall a. Enum a => a -> Int
    fromEnum) [CLong]
    t

    getICCCMTitle   :: Window -> X String
    getICCCMTitle :: Window -> X String
    getICCCMTitle w :: Window
    w =  Window -> Window -> X String
    getDecodedStringProp Window
    w Window
    wM_NAME

    getDecodedStringProp     :: Window -> Atom -> X String
    getDecodedStringProp :: Window -> Window -> X String
    getDecodedStringProp w :: Window
    w a :: Window
    a =  do
      t :: TextProperty
    t@(TextProperty t' :: CString
    t' _ 8 _) <- (Display -> X TextProperty) -> X TextProperty
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X TextProperty) -> X TextProperty)
    -> (Display -> X TextProperty) -> X TextProperty
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d -> IO TextProperty -> X TextProperty
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO TextProperty -> X TextProperty)
    -> IO TextProperty -> X TextProperty
    forall a b. (a -> b) -> a -> b
    $ Display -> Window -> Window -> IO TextProperty
    getTextProperty Display
    d Window
    w Window
    a
      [s :: String
    s] <- X [String] -> X [String] -> X [String]
    forall a. X a -> X a -> X a
    catchX' (TextProperty -> X [String]
    tryUTF8     TextProperty
    t) (X [String] -> X [String]) -> X [String] -> X [String]
    forall a b. (a -> b) -> a -> b
    $
             X [String] -> X [String] -> X [String]
    forall a. X a -> X a -> X a
    catchX' (TextProperty -> X [String]
    tryCompound TextProperty
    t) (X [String] -> X [String]) -> X [String] -> X [String]
    forall a b. (a -> b) -> a -> b
    $
             IO [String] -> X [String]
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io ((String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[]) (String -> [String]) -> IO String -> IO [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` CString -> IO String
    peekCString CString
    t')
      String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return String
    s

    tryUTF8                          :: TextProperty -> X [String]
    tryUTF8 :: TextProperty -> X [String]
    tryUTF8 (TextProperty s :: CString
    s enc :: Window
    enc _ _) =  do
      Window
    uTF8_STRING <- String -> X Window
    getAtom "UTF8_STRING"
      Bool -> X () -> X ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Window
    enc Window -> Window -> Bool
    forall a. Eq a => a -> a -> Bool
    == Window
    uTF8_STRING) (X () -> X ()) -> X () -> X ()
    forall a b. (a -> b) -> a -> b
    $ String -> X ()
    forall a. HasCallStack => String -> a
    error "String is not UTF8_STRING"
      ((String -> String) -> [String] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map String -> String
    decodeString ([String] -> [String])
    -> (String -> [String]) -> String -> [String]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [String]
    splitNul) (String -> [String]) -> X String -> X [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` IO String -> X String
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (CString -> IO String
    peekCString CString
    s)

    tryCompound                            :: TextProperty -> X [String]
    tryCompound :: TextProperty -> X [String]
    tryCompound t :: TextProperty
    t@(TextProperty _ enc :: Window
    enc _ _) =  do
      Window
    cOMPOUND_TEXT <- String -> X Window
    getAtom "COMPOUND_TEXT"
      Bool -> X () -> X ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Window
    enc Window -> Window -> Bool
    forall a. Eq a => a -> a -> Bool
    == Window
    cOMPOUND_TEXT) (X () -> X ()) -> X () -> X ()
    forall a b. (a -> b) -> a -> b
    $ String -> X ()
    forall a. HasCallStack => String -> a
    error "String is not COMPOUND_TEXT"
      (Display -> X [String]) -> X [String]
    forall a. (Display -> X a) -> X a
    withDisplay ((Display -> X [String]) -> X [String])
    -> (Display -> X [String]) -> X [String]
    forall a b. (a -> b) -> a -> b
    $ \d :: Display
    d -> IO [String] -> X [String]
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO [String] -> X [String]) -> IO [String] -> X [String]
    forall a b. (a -> b) -> a -> b
    $ Display -> TextProperty -> IO [String]
    wcTextPropertyToTextList Display
    d TextProperty
    t

    splitNul    :: String -> [String]
    splitNul :: String -> [String]
    splitNul "" =  []
    splitNul s :: String
    s  =  let (s' :: String
    s',ss' :: String
    ss') = (Char -> Bool) -> String -> (String, String)
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == '\NUL') String
    s in String
    s' String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : String -> [String]
    splitNul String
    ss'

    pad       :: Int -> Char -> String -> String
    pad :: Int -> Char -> String -> String
    pad w :: Int
    w c :: Char
    c s :: String
    s =  Int -> Char -> String
    forall a. Int -> a -> [a]
    replicate (Int
    w Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - String -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length String
    s) Char
    c String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    s

    -- modified 'catchX' without the print to 'stderr'
    catchX' :: X a -> X a -> X a
    catchX' :: X a -> X a -> X a
    catchX' job :: X a
    job errcase :: X a
    errcase = do
      XState
    st <- X XState
    forall s (m :: * -> *). MonadState s m => m s
    get
      XConf
    c <- X XConf
    forall r (m :: * -> *). MonadReader r m => m r
    ask
      (a :: a
    a, s' :: XState
    s') <- IO (a, XState) -> X (a, XState)
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO (a, XState) -> X (a, XState))
    -> IO (a, XState) -> X (a, XState)
    forall a b. (a -> b) -> a -> b
    $ XConf -> XState -> X a -> IO (a, XState)
    forall a. XConf -> XState -> X a -> IO (a, XState)
    runX XConf
    c XState
    st X a
    job IO (a, XState)
    -> (SomeException -> IO (a, XState)) -> IO (a, XState)
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `E.catch` \e :: SomeException
    e -> case SomeException -> Maybe ExitCode
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e of
        Just x :: ExitCode
    x -> SomeException -> IO (a, XState)
    forall a e. Exception e => e -> a
    throw SomeException
    e IO (a, XState) -> ExitCode -> IO (a, XState)
    forall a b. a -> b -> a
    `const` (ExitCode
    x ExitCode -> ExitCode -> ExitCode
    forall a. a -> a -> a
    `asTypeOf` ExitCode
    ExitSuccess)
        _ -> XConf -> XState -> X a -> IO (a, XState)
    forall a. XConf -> XState -> X a -> IO (a, XState)
    runX XConf
    c XState
    st X a
    errcase
      XState -> X ()
    forall s (m :: * -> *). MonadState s m => s -> m ()
    put XState
    s'
      a -> X a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    a

    wrap   :: String -> String
    wrap :: String -> String
    wrap s :: String
    s =  ' ' Char -> String -> String
    forall a. a -> [a] -> [a]
    : '"' Char -> String -> String
    forall a. a -> [a] -> [a]
    : String -> String
    wrap' String
    s String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ "\""
      where
        wrap' :: String -> String
    wrap' (s' :: Char
    s':ss :: String
    ss) | Char
    s' Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == '"'  = '\\' Char -> String -> String
    forall a. a -> [a] -> [a]
    : Char
    s' Char -> String -> String
    forall a. a -> [a] -> [a]
    : String -> String
    wrap' String
    ss
                      | Char
    s' Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == '\\' = '\\' Char -> String -> String
    forall a. a -> [a] -> [a]
    : Char
    s' Char -> String -> String
    forall a. a -> [a] -> [a]
    : String -> String
    wrap' String
    ss
                      | Bool
    otherwise  =        Char
    s' Char -> String -> String
    forall a. a -> [a] -> [a]
    : String -> String
    wrap' String
    ss
        wrap' ""                   =             ""

    -- Graphics.X11.Extras.getWindowAttributes is bugggggggy
    safeGetWindowAttributes     :: Display -> Window -> IO (Maybe WindowAttributes)
    safeGetWindowAttributes :: Display -> Window -> IO (Maybe WindowAttributes)
    safeGetWindowAttributes d :: Display
    d w :: Window
    w =  (Ptr WindowAttributes -> IO (Maybe WindowAttributes))
    -> IO (Maybe WindowAttributes)
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
    alloca ((Ptr WindowAttributes -> IO (Maybe WindowAttributes))
     -> IO (Maybe WindowAttributes))
    -> (Ptr WindowAttributes -> IO (Maybe WindowAttributes))
    -> IO (Maybe WindowAttributes)
    forall a b. (a -> b) -> a -> b
    $ \p :: Ptr WindowAttributes
    p -> do
      CInt
    s <- Display -> Window -> Ptr WindowAttributes -> IO CInt
    xGetWindowAttributes Display
    d Window
    w Ptr WindowAttributes
    p
      case CInt
    s of
        0 -> Maybe WindowAttributes -> IO (Maybe WindowAttributes)
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe WindowAttributes
    forall a. Maybe a
    Nothing
        _ -> WindowAttributes -> Maybe WindowAttributes
    forall a. a -> Maybe a
    Just (WindowAttributes -> Maybe WindowAttributes)
    -> IO WindowAttributes -> IO (Maybe WindowAttributes)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Ptr WindowAttributes -> IO WindowAttributes
    forall a. Storable a => Ptr a -> IO a
    peek Ptr WindowAttributes
    p

    -- and so is getCommand
    safeGetCommand     :: Display -> Window -> X [String]
    safeGetCommand :: Display -> Window -> X [String]
    safeGetCommand d :: Display
    d w :: Window
    w =  do
      Window
    wC <- String -> X Window
    getAtom "WM_COMMAND"
      Maybe [CChar]
    p <- IO (Maybe [CChar]) -> X (Maybe [CChar])
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    io (IO (Maybe [CChar]) -> X (Maybe [CChar]))
    -> IO (Maybe [CChar]) -> X (Maybe [CChar])
    forall a b. (a -> b) -> a -> b
    $ Display -> Window -> Window -> IO (Maybe [CChar])
    getWindowProperty8 Display
    d Window
    wC Window
    w
      case Maybe [CChar]
    p of
        Nothing  -> [String] -> X [String]
    forall (m :: * -> *) a. Monad m => a -> m a
    return []
        Just cs' :: [CChar]
    cs' -> do
          let cs :: String
    cs                    = (CChar -> Char) -> [CChar] -> String
    forall a b. (a -> b) -> [a] -> [b]
    map (Int -> Char
    forall a. Enum a => Int -> a
    toEnum (Int -> Char) -> (CChar -> Int) -> CChar -> Char
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CChar -> Int
    forall a. Enum a => a -> Int
    fromEnum) [CChar]
    cs'
              go :: ([String], (String, String)) -> ([String], (String, String))
    go  (a :: [String]
    a,(s :: String
    s,"\NUL"))    = (String
    sString -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    a,("",""))
              go  (a :: [String]
    a,(s :: String
    s,'\NUL':ss :: String
    ss)) = ([String], (String, String)) -> ([String], (String, String))
    go (String
    sString -> [String] -> [String]
    forall a. a -> [a] -> [a]
    :[String]
    a,String -> (String, String)
    go' String
    ss)
              go  r :: ([String], (String, String))
    r                 = ([String], (String, String))
    r -- ???
              go' :: String -> (String, String)
    go'                   = (Char -> Bool) -> String -> (String, String)
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    == '\NUL')
           in [String] -> X [String]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([String] -> X [String]) -> [String] -> X [String]
    forall a b. (a -> b) -> a -> b
    $ [String] -> [String]
    forall a. [a] -> [a]
    reverse ([String] -> [String]) -> [String] -> [String]
    forall a b. (a -> b) -> a -> b
    $ ([String], (String, String)) -> [String]
    forall a b. (a, b) -> a
    fst (([String], (String, String)) -> [String])
    -> ([String], (String, String)) -> [String]
    forall a b. (a -> b) -> a -> b
    $ ([String], (String, String)) -> ([String], (String, String))
    go ([],String -> (String, String)
    go' String
    cs)

    getMachine   :: Window -> X String
    getMachine :: Window -> X String
    getMachine w :: Window
    w =  X String -> X String -> X String
    forall a. X a -> X a -> X a
    catchX' (String -> X Window
    getAtom "WM_CLIENT_MACHINE" X Window -> (Window -> X String) -> X String
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Window -> Window -> X String
    getDecodedStringProp Window
    w) (String -> X String
    forall (m :: * -> *) a. Monad m => a -> m a
    return "")