Haskell 来自 X11 库的 fetchName 没有 return window 的名称

Haskell fetchName from X11 library does not return the name of the window

具有以下 Haskell 代码:

import           Control.Concurrent
import           Data.Time.Clock
import           Debug.Trace
import           Graphics.X11
import           Graphics.X11.Xlib.Extras

main :: IO ()
main = do
  d <- openDisplay ""
  loop d

loop :: Display -> IO ()
loop d = do
  time <- getCurrentTime
  (w, _) <- getInputFocus d
  maybeName <- fetchName d w
  windowAttrs <- getWindowAttributes d w
  print $ show time ++ " Name: " ++ show maybeName ++ " Width: " ++ show (wa_width windowAttrs)
  threadDelay 1000000
  loop d

fetchName返回的window标题总是Nothing

Haskell X11 library is a wrapper around Xlib

可能相关的问题:

看起来 fetchName 并不总是填写。相反,您需要使用 _NET_WM_NAME 属性:

import           Control.Concurrent
import           Data.Time.Clock
import           Debug.Trace
import           Graphics.X11
import           Graphics.X11.Xlib.Extras

main :: IO ()
main = do
  d <- openDisplay ""
  loop d

loop :: Display -> IO ()
loop d = do
  time <- getCurrentTime
  (w, _) <- getInputFocus d
  a <- internAtom d "_NET_WM_NAME" False
  p <- getTextProperty d w a
  ps <- wcTextPropertyToTextList d p
  windowAttrs <- getWindowAttributes d w
  print $ show time ++ " Name: " ++ show ps ++ " Width: " ++ show (wa_width windowAttrs)
  threadDelay 1000000
  loop d

这就是 XMonad 所做的:

https://github.com/xmonad/xmonad/blob/8b055621e92e7ade127043e968f50713c15a00a0/src/XMonad/ManageHook.hs#L71-L80

最后我不得不将 Brian 的回答改编为 XMonad 中更完整的定义(因为某些 windows 抛出异常):

import           Control.Exception.Extensible          (SomeException (..),
                                                        bracket)
import qualified Control.Exception.Extensible          as E
import           Graphics.X11
import           Graphics.X11.Xlib.Extras

getWindowTitle :: Display -> IO String
getWindowTitle d = do
  (w, _) <- getInputFocus d
  let getProp =
          (internAtom d "_NET_WM_NAME" False >>= getTextProperty d w)
              `E.catch` \(SomeException _) -> getTextProperty d w wM_NAME
      extract prop = do l <- wcTextPropertyToTextList d prop
                        return $ if null l then "" else head l
  bracket getProp (xFree . tp_value) extract `E.catch` \(SomeException _) -> return ""