Xmobar does not appear on top of window stack when xmonad starts

xmonad

I'm experiencing a strange behaviour of xmobar right after i enter xmonad. When i xmonad (from .xinitrc, i use XDM) my xmobar appears but it is not either at the top or bottom of the window stack. Once i start an application (e.g. terminal emulator by pressing Mod + Shift + Return) the application uses the entire screen, as if the xmobar was at the bottom. Then i press Mod + B and nothing happens, once i press Mod + B a second time xmobar is lifted to the top reducing the application window size.

After that Mod + B works correctly for the remainder of the xmonad session, i.e. it lowers/raises (hides/shows) the xmobar.

I'm confident i misconfigured something. My xmonad.hs looks like:

import XMonad
import XMonad.Hooks.SetWMName
import XMonad.Hooks.DynamicLog

main = do
  xmonad =<< statusBar "xmobar" myPP toggleStrutsKey defaultConfig
    { terminal           = "urxvt"
    , focusFollowsMouse  = True
    , clickJustFocuses   = False
    , borderWidth        = 1
    , modMask            = mod4Mask
    , workspaces         = myworkspaces
    , normalBorderColor  = "#dddddd"
    , focusedBorderColor = "#00dd00"
    , manageHook         = mymanager
    , startupHook        = setWMName "LG3D"
    }

myPP = xmobarPP { ppOutput          = putStrLn
                , ppCurrent         = xmobarColor "#336433" "" . wrap "[" "]"
                --, ppHiddenNoWindows = xmobarColor "grey" ""
                , ppTitle           = xmobarColor "darkgreen"  "" . shorten 20
                , ppLayout          = shorten 6
                --, ppVisible         = wrap "(" ")"
                , ppUrgent          = xmobarColor "red" "yellow"
                }

toggleStrutsKey XConfig { XMonad.modMask = modMask } = (modMask, xK_b)

myworkspaces = [ "code"
               , "web"
               , "media"
               , "irc"
               , "random"
               , "mail"
               , "docs"
               , "music"
               , "root"
               ]

mymanager = composeAll
  [ className =? "gimp" --> doFloat
  , className =? "vlc"  --> doFloat
  ]

Whilst the beginning of my .xmobarrc looks as follows:

Config {
  -- appearance
    font =         "xft:Bitstream Vera Sans Mono:size=9:bold:antialias=true"
  , bgColor =      "black"
  , fgColor =      "#646464"
  , position =     Top
  , border =       BottomB
  , borderColor =  "#646464"

  -- layout
  , sepChar =  "%"   -- delineator between plugin names and straight text
  , alignSep = "}{"  -- separator between left-right alignment
  , template = "%battery% | %multicpu% | %coretemp% | %memory% | %dynnetwork% | %StdinReader% }{ %date% || %kbd% "

  -- general behavior
  , lowerOnStart =     False   -- send to bottom of window stack on start
  , hideOnStart =      False   -- start with window unmapped (hidden)
  , allDesktops =      True    -- show on all desktops
  , overrideRedirect = True    -- set the Override Redirect flag (Xlib)
  , pickBroadest =     False   -- choose widest display (multi-monitor)
  , persistent =       True    -- enable/disable hiding (True = disabled)

  -- plugins (i do not use any)

  , commands = [  -- actually several commands are in here
  ]
}

I tried several combinations of:

, lowerOnStart =
, hideOnStart =

(True/True, True/False, False/True and False/False as shown now). But the behaviour before i press Mod + B two times does not change. I believe that i have misconfigured xmonad in some way not xmobar but that is just a guess.

My .xinitrc might be of help:

#!/bin/sh

if test -d /etc/X11/xinit/xinitrc.d
then
    # /etc/X11/xinit/xinitrc.d is actually empty
    for f in /etc/X11/xinit/xinitrc.d/*
    do
        [ -x "$f" ] && source "$f"
    done
    unset f
fi

# uk keyboard
setxkbmap gb

xrdb .Xresources
xscreensaver -no-splash &

# java behaves badly in non-reparenting window managers (e.g. xmonad)
export _JAVA_AWT_WM_NONREPARENTING=1

# set the background (again, because qiv uses a different buffer)
/usr/bin/feh --bg-scale --no-fehbg -z /usr/share/archlinux/wallpaper/a*.jpg

# pulse audio for alsa
then
    /usr/bin/start-pulseaudio-x11
fi

exec xmonad

Best Answer

Two months later I figured it out. The problem is that statusBar does not register the events of Hooks.manageDocks properly. Once xmonad is running all works well because manageDocks is able to update the Struts on every window event. But in the moment that xmonad is starting the event of making the first windows fullscreen happens before the events from manageDocks. This mages that first open window to ignore the existence of xmobar.

manageDocks has its event handler that must be set as the last event handler, therefore statusBar cannot be used. Instead, it is necessary to make xmonad call and configure xmobar manually through dynamicLog, manageHook, layoutHook and handleEventHook. A minimalistic configuration for this would be:

main = do
    xmproc <- spawnPipe "xmobar"
    xmonad $ defaultConfig
      { modMask            = mod4Mask
      , manageHook         = manageDocks <+> manageHook defaultConfig
      , layoutHook         = avoidStruts  $ layoutHook defaultConfig
      -- this must be in this order, docksEventHook must be last
      , handleEventHook    = handleEventHook defaultConfig <+> docksEventHook
      , logHook            = dynamicLogWithPP xmobarPP
          { ppOutput          = hPutStrLn xmproc
          , ppTitle           = xmobarColor "darkgreen"  "" . shorten 20
          , ppHiddenNoWindows = xmobarColor "grey" ""
          }
      , startupHook        = setWMName "LG3D"
      } `additionalKeys`
      [ ((mod4Mask, xK_b), sendMessage ToggleStruts) ]

This makes all events to be processed by docsEventHook and ensures that layout changes made by docsEventHook are the last ones applied. Now

lowerOnStart = False

(or True) works as expected in all cases within xmobarrc.

Related Question