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

Haskell中订阅X11事件代码挂起,求排查原因

问题分析与解决方案

你的代码挂起无响应的核心原因是错误设置了X11窗口的事件监听掩码,具体有两个关键问题:


1. 属性修改掩码与事件掩码混淆

changeWindowAttributes的第三个参数是属性选择掩码(用来告知X服务器要修改窗口的哪些属性),而非直接传事件掩码。你需要传入cWEventMask来指定要修改窗口的eventMask属性,同时在SetWindowAttributes结构体中设置实际要监听的事件类型掩码。

2. 未正确配置事件监听的结构体字段

你没有给SetWindowAttributes结构体的eventMask字段赋值,导致X服务器从未收到你要监听特定事件的指令,nextEvent会一直阻塞等待不存在的事件。


修正后的代码(监听活动窗口切换)

对应原方案的逻辑(监听根窗口_NET_ACTIVE_WINDOW属性变化):

import Graphics.X11.Xlib
import Foreign.Marshal.Alloc (alloca)

main :: IO ()
main = do
    disp <- openDisplay ""
    let root = defaultRootWindow disp
    -- 正确配置根窗口的事件监听掩码
    allocaSetWindowAttributes $ \swaPtr -> do
        set_swa_event_mask swaPtr propertyChangeMask
        changeWindowAttributes disp root cWEventMask swaPtr
    -- 等待并打印事件类型
    allocaXEvent $ \e -> do
        nextEvent disp e
        eventType <- get_event_type e
        putStrLn $ "收到事件:" ++ show eventType
    closeDisplay disp

关键修改说明

  • set_swa_event_mask swaPtr propertyChangeMask:给结构体的eventMask字段赋值,指定要监听属性变化事件(对应活动窗口切换时的_NET_ACTIVE_WINDOW属性更新)。
  • changeWindowAttributes disp root cWEventMask swaPtr:告知X服务器,要修改根窗口的eventMask属性,使用结构体中配置的掩码。
  • 新增closeDisplay disp:释放X11显示资源,避免内存泄漏。

如果需要监听焦点切换事件(FocusIn/FocusOut),只需将propertyChangeMask替换为focusChangeMask即可。


内容的提问来源于stack exchange,提问作者radrow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:14:56