如何让XMonad的manageHook在窗口属性动态变更时重新执行?
XMonad窗口动态属性变更后重新应用manageHook规则的解决方法
XMonad自带的manageHook只会在窗口创建时执行一次,要是窗口后续动态修改了WM_NAME或WM_CLASS属性,之前设置的规则就没法触发了。要解决这个问题,我们可以监听这些属性的变更事件,一旦检测到变化就重新对目标窗口执行manageHook规则。
实现步骤
1. 导入必要模块
先把需要的模块导进来,这些模块负责处理X11事件、重新管理窗口等核心功能:
import XMonad import XMonad.Hooks.EwmhDesktops (ewmh) import XMonad.Query (runQuery) import qualified XMonad.StackSet as W import Data.Monoid (Endo)
2. 编写属性变更监听钩子
写一个事件处理函数,专门监听PropertyNotify事件——当窗口的WM_NAME或WM_CLASS属性变更时,重新执行myManageHook规则:
myPropertyHook :: Event -> X () myPropertyHook (PropertyNotifyEvent { ev_window = w, ev_atom = a }) = do -- 获取WM_NAME和WM_CLASS对应的X11 Atom wmName <- getAtom "WM_NAME" wmClass <- getAtom "WM_CLASS" -- 检测变更的属性是否是我们关心的 if a == wmName || a == wmClass then do -- 对当前窗口执行manageHook规则 ruleActions <- runQuery myManageHook w windows $ appEndo ruleActions -- 强制刷新窗口状态,确保变更生效 refresh else return () -- 忽略其他类型的事件 myPropertyHook _ = return ()
3. 整合到XMonad主配置
把上面写的钩子加到主配置的handleEventHook里,同时记得启用ewmh(它是处理X11属性事件的基础):
main :: IO () main = xmonad $ ewmh $ def { manageHook = myManageHook -- 组合默认事件钩子和我们自定义的属性监听钩子 , handleEventHook = myPropertyHook <+> handleEventHook def -- 这里可以加你的其他配置,比如修饰键、工作区设置等 , modMask = mod4Mask -- 示例:用Win键作为修饰键 }
4. 注意事项
- 确保
myManageHook里的规则是幂等的:比如多次执行doFloat不会出问题(XMonad本身已经处理了重复浮动的情况,但自定义动作要注意)。 - 不要直接覆盖
handleEventHook,要用<+>和默认钩子组合,避免丢失其他默认事件处理逻辑。 - 测试的时候可以用
xprop工具手动修改窗口的WM_NAME或WM_CLASS,看看规则会不会触发。
完整配置片段
import XMonad import XMonad.Hooks.EwmhDesktops (ewmh) import XMonad.Query (runQuery) import qualified XMonad.StackSet as W import Data.Monoid (Endo) -- 你的原有manageHook规则 myManageHook :: X (Endo WindowSet) myManageHook = composeAll [ className =? "confirm" --> doFloat , title =? "My App" --> doFloat -- 其他自定义规则... ] -- 自定义属性变更监听钩子 myPropertyHook :: Event -> X () myPropertyHook (PropertyNotifyEvent { ev_window = w, ev_atom = a }) = do wmName <- getAtom "WM_NAME" wmClass <- getAtom "WM_CLASS" when (a == wmName || a == wmClass) $ do ruleActions <- runQuery myManageHook w windows $ appEndo ruleActions refresh myPropertyHook _ = return () main :: IO () main = xmonad $ ewmh $ def { manageHook = myManageHook , handleEventHook = myPropertyHook <+> handleEventHook def , modMask = mod4Mask -- 其他配置项... }
内容的提问来源于stack exchange,提问作者Oh Fiveight
相关产品推荐
相关产品推荐

