haskellfunctional-programmingconfigurationxmonadxmobar

How do I make xmonad use a haskell-based xmobar?


tl;dr

How do I change this xmonad.hs,

import XMonad
main :: IO ()
main = xmonad def { terminal = "urxvt" , modMask = mod4Mask }

in order for XMonad to spawn xmobar correctly (spawn once, and kill and re-spawn if I restart XMonad in place, and any other sensible requirement) without an xmobarrc config file but with an actual xmobar.hs Haskell file containing the following?

import Xmobar
main :: IO ()
main = xmobar defaultConfig { commands = [Run XMonadLog], template = "%XMonadLog%" }

More datails

From XMonad tutorial I read

It is also possible to completely configure xmobar in Haskell, just like xmonad. If you want to know more about that, you can check out the xmobar.hs example in the official documentation. For a more complicated example, you can also check out jao’s xmobar.hs (he’s the current maintainer of xmobar).

In the file at the first link, the instruction is

-- An example of a Haskell-based xmobar. Compile it with
--   ghc --make -- xmobar.hs
-- with the xmobar library installed or simply call:
--   xmobar /path/to/xmobar.hs
-- and xmobar will compile and launch it for you and

and I have verified that indeed executing ghc --make xmbobar.hs (GHC 9.4.8) generates an xmobar executable that, when executed, spawns the bar (xmobar /path/to/xmobar.hs instead just never returns).

But what is the proper way to tell XMonad to run xmobar?

From the first link in the quote above, I can get here, where I read

Or put your xmobar.hs program in ~/.config/xmobar/xmobar.hs and, when running the system-wide xmobar, it will notice that you have your own implementation and (re)compile and run it as needed.

but I still don't know how to have XMobar do the "running system-wide xmobar".


Some more finding

I think I've got to a minimal working example, but I don't really understand quite a few details.

Given this ~/.config/xmonad/xmonad.hs,

import XMonad
import XMonad.Hooks.EwmhDesktops
import XMonad.Hooks.StatusBar.PP
import XMonad.Util.Run

main :: IO ()
main = do
     xmproc <- spawnPipe "xmobar ~/.config/xmonad/xmobar.hs"
     xmonad . ewmhFullscreen
            . ewmh
            $ myConfig xmproc

myConfig h = def
    { terminal = "urxvt"
    , modMask = mod4Mask
    , logHook = dynamicLogWithPP xmobarPP
    { ppOutput = hPutStrLn h
    }
    }

and this ~/.config/xmonad/xmobar.hs,

import Xmobar

config :: Config
config = defaultConfig
    {
      commands =
        [ Run StdinReader,
          Run $ Date "%a %_d %b %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10
        ],
      template = "%StdinReader% }{ %date%",
      alignSep = "}{"
    }

main :: IO ()
main = xmobar config

the two seem to work fine together.

However, below is what I don't understand.


Solution

  • Well, my mistake consisted in think that moving from one approach (xmonad.hs + xmobarrc), call it A, to the other approach (xmonad.hs + xmobar.hs), call it B, I was also removing the usage of withEasySB,

         . withEasySB (statusBarProp (unwords ["xmobar", xmobarhs]) (pure myXmobarPP)) toggleStrutsKey
    

    to launch xmobar and just using spawnPipe (as shown in the question), thinking that with the approach B the configuration of xmobar was all up to xmobar.hs.

    Apparently, I've misunderstood the way XMonad and XMobar are supposed to work together: