raiseWindowByClass :: String -> X ()
raiseWindowByClass cls = withDisplay $ \d -> do
    XConf{ theRoot = r } <- ask
    (_, _, lowToHigh) <- io $ Xtras.queryTree d r
    case (reverse lowToHigh) of
      (top:r:rs) -> do
          tclass <- classOf top
          when (tclass /= Just cls) $ withDisplay $ \d -> do
              win <- findFirst (r:rs)
              maybe (pure ()) (io . raiseWindow d) win

      _ -> pure ()
    where
        findFirst :: [Window] -> X (Maybe Window)
        findFirst [] = pure Nothing
        findFirst (w:ws) = do
            c <- classOf w
            case c of
              Just x | x == cls -> return $ Just w
              _ -> findFirst ws

        classOf :: Window -> X (Maybe String)
        classOf win = do
            cs <- (classes win) `catchX` (pure [])
            case cs of
              (_:c:_) -> return $ Just c
              _ -> pure Nothing

        classes :: Window -> X [String]
        classes win = withDisplay $ \d -> io $ do
            p <- Xtras.getTextProperty d win Atom.wM_CLASS
            Xtras.wcTextPropertyToTextList d p
raiseWindowByClass :: String -> X ()
raiseWindowByClass cls = withDisplay $ \d -> do
    XConf{ theRoot = r } <- ask
    (_, _, lowToHigh) <- io $ Xtras.queryTree d r
    case (reverse lowToHigh) of
      (top:r:rs) -> do
          tclass <- classOf top
          when (tclass /= Just cls) $ withDisplay $ \d -> do
              win <- findFirst (r:rs)
              maybe (pure ()) (io . raiseWindow d) win

      _ -> pure ()
    where
        findFirst :: [Window] -> X (Maybe Window)
        findFirst [] = pure Nothing
        findFirst (w:ws) = do
            c <- classOf w
            case c of
              Just x | x == cls -> return $ Just w
              _ -> findFirst ws

        classOf :: Window -> X (Maybe String)
        classOf win = do
            cs <- (classes win) `catchX` (pure [])
            case cs of
              (_:c:_) -> return $ Just c
              _ -> pure Nothing

        classes :: Window -> X [String]
        classes win = withDisplay $ \d -> io $ do
            p <- Xtras.getTextProperty d win Atom.wM_CLASS
            Xtras.wcTextPropertyToTextList d p
raiseWindowByClass cls = withDisplay $ \d -> do
    XConf{ theRoot = r } <- ask
    (_, _, lowToHigh) <- io $ Xtras.queryTree d r
    case (reverse lowToHigh) of
      (top:r:rs) -> do
          tclass <- classOf top
          when (tclass /= Just cls) $ withDisplay $ \d -> do
              win <- findFirst (r:rs)
              maybe (pure ()) (io . raiseWindow d) win

      _ -> pure ()
    where
        findFirst :: [Window] -> X (Maybe Window)
        findFirst [] = pure Nothing
        findFirst (w:ws) = do
            c <- classOf w
            case c of
              Just x | x == cls -> return $ Just w
              _ -> findFirst ws

        classOf :: Window -> X (Maybe String)
        classOf win = do
            cs <- (classes win) `catchX` (pure [])
            case cs of
              (_:c:_) -> return $ Just c
              _ -> pure Nothing

        classes :: Window -> X [String]
        classes win = withDisplay $ \d -> io $ do
            p <- Xtras.getTextProperty d win Atom.wM_CLASS
            Xtras.wcTextPropertyToTextList d p