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

XMobar可点击功能生效后崩溃,求现代实现方案

XMobar点击操作触发后进程意外终止的问题

问题概述

我要实现可点击XMobar(不止工作区,后续要支持其他插件),通过以下方式给工作区标签添加点击动作:

定义包裹动作的函数:

foo = wrap "<action=`touch ~/foo` button=1>" "</action>"

或等价写法:

foo = xmobarAction "touch ~/foo" "1"

将其与XMobar的PP组合:

myXmobarPP :: PP
myXmobarPP = def { ppCurrent = foo . ppCurrent def }

点击当前工作区标签时,touch ~/foo能正常执行,但xmobar进程会直接终止。

已尝试的方法(均存在进程终止问题)

我试过多种方案,点击操作能生效,但都会导致xmobar崩溃:

  • 使用XMonad.Util.ClickableWorkspaces的clickablePP:
    在xmobar.hs中把XMonadLog替换为UnsafeXMonadLog,并在xmonad.hs中传入clickablePP:
    main = xmonad
         . ewmhFullscreen
         . ewmh
         . withEasySB (statusBarProp (unwords ["xmobar", xmobarhs]) (clickablePP myXmobarPP)) toggleStrutsKey
         $ myConfig
    
  • 手动给ppHidden添加点击动作:
    同样替换XMonadLog为UnsafeXMonadLog,自定义clickable函数并组合到ppHidden:
    clickable ws = "<action=xdotool key super+"++ws++">"++ws++"</action>"
    myXmobarPP :: PP
    myXmobarPP = def {
      ppHidden          = white . wrap " " "" . clickable,
      -- 其他配置...
    }
    
  • 使用clickableWrap函数:
    测试clickableWrap 2 "ciao"会生成<action=xdotool set_desktop 2 button=1>ciao</action>,验证xdotool set_desktop 2能正常切换工作区(xdotool工作区从零开始计数),并修改ppHidden为:
    ppHidden = \x -> clickableWrap ((read x :: Int) - 1) x
    

以上方法都能实现点击切换工作区,但触发点击后xmobar进程立即终止,手动启动xmobar查看错误仅得到:

xmobar: waitForProcess: does not exist (No child processes)

最小复现配置

xmonad.hs

import XMonad
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.StatusBar
import XMonad.Util.ClickableWorkspaces

main :: IO ()
main = xmonad
     . ewmhFullscreen
     . ewmh
     . withEasySB (statusBarProp myxmobar (clickablePP def)) defToggleStrutsKey
     $ myConfig
     where
       myxmobar = "xmobar ~/.config/xmobar/xmobar.hs"

myConfig = def
    { terminal = "urxvt"
    , modMask = mod4Mask
    }

xmobar.hs

import Xmobar

main :: IO ()
main = xmobar defaultConfig {
         overrideRedirect = False
       , position = BottomSize L 100 25
       , commands = [ Run UnsafeXMonadLog ]
       , sepChar  = "%"
       , alignSep = "}{"
       , template = "%UnsafeXMonadLog% }{"
       }

解决方案

问题出在UnsafeXMonadLog和statusBarProp的组合上:statusBarProp会让xmonad启动xmobar进程并监控它,而UnsafeXMonadLog执行外部命令时的进程处理逻辑会和xmonad的进程监控冲突,导致xmobar被误判为异常退出。

修复步骤:

  1. 替换启动方式:不要用statusBarProp,改用statusBar,让xmonad通过管道和xmobar通信,而非直接监控进程:
    修改xmonad.hs中的withEasySB部分:

    main = xmonad
         . ewmhFullscreen
         . ewmh
         . withEasySB (statusBar myxmobar (clickablePP def)) defToggleStrutsKey
         $ myConfig
         where
           myxmobar = "xmobar ~/.config/xmobar/xmobar.hs"
    

    statusBar会自动使用管道通信,避免进程监控冲突。

  2. 保持UnsafeXMonadLog配置:xmobar.hs中继续使用UnsafeXMonadLog,它是支持<action>标签的必要配置。

  3. 优化命令执行:如果自定义<action>中的命令,建议将命令放到后台执行(加&),避免命令阻塞导致xmobar异常:

    foo = xmobarAction "touch ~/foo &" "1"
    

原理说明

statusBarProp通过spawnPipe启动xmobar并监控其生命周期,而UnsafeXMonadLog执行<action>中的外部命令时会创建子进程,xmonad的进程监控逻辑可能把这个子进程误当成xmobar本身,当子进程退出时,xmonad会认为xmobar崩溃并终止它。而statusBar的管道通信方式,不会直接监控xmobar进程,而是通过管道传递日志,避免了这个冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:41:02