You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中X11库的fetchName无法返回窗口名称问题

解决Haskell X11库中fetchName无法返回窗口名称的问题

我来帮你分析这个问题的可能原因,以及对应的解决办法:

常见原因分析

1. 当前焦点窗口本身没有名称

当getInputFocus返回的是根窗口(桌面窗口)时,它通常没有设置WM_NAME属性,所以fetchName会返回Nothing。你可以通过打印窗口ID来验证:如果窗口ID和defaultRootWindow d一致,那就是根窗口。

2. fetchName只支持传统的WM_NAME属性

现代窗口管理器(比如GNOME、KDE、i3)通常使用_NET_WM_NAME属性(UTF-8编码)来存储窗口名称,而fetchName函数只读取旧的WM_NAME属性(通常是Latin1编码)。如果目标窗口只设置了_NET_WM_NAME而没有设置WM_NAME,fetchName就会返回Nothing。

解决办法

我们可以实现一个更健壮的窗口名称获取函数,优先读取_NET_WM_NAME(UTF8),失败时再回退到WM_NAME:

步骤1:导入额外的X11常量

首先需要导入Graphics.X11.Xlib.Atoms来获取_NET_WM_NAME的原子:

import Graphics.X11.Xlib.Atoms

步骤2:实现增强版的窗口名称获取函数

getWindowName :: Display -> Window -> IO (Maybe String)
getWindowName d w = do
  -- 先尝试获取_NET_WM_NAME(UTF8编码)
  netWmNameAtom <- getAtom d "_NET_WM_NAME"
  maybeNetName <- getTextProperty d w netWmNameAtom
  case maybeNetName of
    Just tp -> do
      str <- textPropertyToString tp
      return $ Just str
    Nothing -> do
      -- 回退到传统的WM_NAME
      fetchName d w

步骤3:修改主循环代码

把原来的fetchName替换成我们的getWindowName,同时可以加上根窗口的判断:

loop :: Display -> IO ()
loop d = do
  time <- getCurrentTime
  rootWin <- defaultRootWindow d
  (w, _) <- getInputFocus d
  maybeName <- if w == rootWin
               then return (Just "Root Window (Desktop)")
               else getWindowName d w
  windowAttrs <- getWindowAttributes d w
  print $ show time ++ " Name: " ++ show maybeName ++ " Width: " ++ show (wa_width windowAttrs)
  threadDelay 1000000
  loop d

额外验证建议

你可以先手动打印窗口ID和根窗口ID对比,确认是否是根窗口导致的Nothing:

rootWin <- defaultRootWindow d
print $ "Focused Window ID: " ++ show w ++ ", Root Window ID: " ++ show rootWin

这样修改后,就能正确获取绝大多数现代窗口的名称了。

内容的提问来源于stack exchange,提问作者Răzvan Flavius Panda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:30:06