Window manager changed to xmonad

After having used awesome for more than two years, I just switched to xmonad. Main reasons for the change were the configuration mess (which rendered my carefully crafted CPU and memory indicators useless in one of the last major upgrades) and the way awesome handles multi-monitor setups (boils down to reloading after adding or removing an output).

The packages I use are:

xmonad
   suckless-tools # provides dmenu-run configured on Win-P
   gmrun # confiured on Win-Shift-P
   dzen2 # menu bar
   # needed for custom configuration:
   libghc6-xmonad-dev
   libghc6-xmonad-contrib-dev

My xmonad configuration looks like this:

(download)

import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Util.Run(spawnPipe)
import XMonad.Util.EZConfig(additionalKeys)
import System.IO
import qualified Data.Map as M
import XMonad.Actions.CycleWS
import XMonad.Actions.CycleRecentWS
import XMonad.Hooks.DynamicLog   (PP(..), dynamicLogWithPP, wrap, defaultPP)
import XMonad.Hooks.UrgencyHook

-- keybindings: similar to the awesome default config i got used to
-- ---------------------------------------------------------------------------

myKeys conf@(XConfig {XMonad.modMask = modm}) = [
    ((modm, xK_Down), nextScreen),
    ((modm .|. shiftMask, xK_Down), shiftNextScreen),
    ((modm, xK_Up), prevScreen),
    ((modm .|. shiftMask, xK_Up), shiftPrevScreen),

    ((modm, xK_Left), prevWS),
    ((modm .|. shiftMask, xK_Left), shiftToPrev),
    ((modm, xK_Right), nextWS),
    ((modm .|. shiftMask, xK_Right), shiftToNext),

    ((modm, xK_Escape), toggleWS),

    ((modm .|. shiftMask, xK_b), spawn "epiphany -p")
    ]
newKeys x  = M.union (keys defaultConfig x) (M.fromList (myKeys x))

-- main program
-- ---------------------------------------------------------------------------

main = do
    statusBarPipe <- spawnPipe statusBarCmd
    xmonad $ withUrgencyHook dzenUrgencyHook { args = ["-bg", "darkgreen", "-xs", "1"] }
            $ defaultConfig {
            modMask = mod4Mask, -- windows key
            terminal = "uxterm",
            manageHook = manageDocks <+> manageHook defaultConfig, -- autodetection for gnome panel and similar
            layoutHook = avoidStruts  $  layoutHook defaultConfig, -- adds gaps for panels
            keys = newKeys,
            logHook = dynamicLogWithPP $ myPP statusBarPipe
    }

-- status bar on top
-- ---------------------------------------------------------------------------

statusBarCmd= "dzen2 -p -h 16 -ta l -bg '" ++ myNormalBGColor ++ "' -fg '" ++ myNormalFGColor ++ "'"

-- helper function (my first haskell function *g*)
--
-- as ppUrgent is applied after ppHidden, the dzen markup has to be removed and new stuff added

dzenStripWrap :: String -> String -> String -> String
dzenStripWrap _ _ "" = ""
dzenStripWrap l r m = l ++ dzenStrip m ++ r

-- status bar design
--
-- based on http://www.haskell.org/haskellwiki/Xmonad/Config_archive/Xilon's_xmonad.hs

myNormalBGColor     = "#2e3436"
myNormalFGColor     = "#babdb6"
myEmptyBGColor      = myNormalBGColor
myEmptyFGColor      = "#7478f6" -- (myNormalBGColor + myNormalFGColor) / 2

myFocusedBGColor    = "#414141"
myFocusedFGColor    = "#73d216"
myOtherscreenBGColor= myFocusedBGColor
myOtherscreenFGColor= myNormalFGColor
mySeperatorColor    = "#000000"
myUrgentBGColor     = "#0000ff"
myUrgentFGColor     = "#f57900"


-- pretty printer

myPP handle = defaultPP {
        ppCurrent                   = wrap ("^fg(" ++ myFocusedFGColor ++ ")^bg(" ++ myFocusedBGColor ++ ")^p(4)") "^p(4)^fg()^bg()",
        ppUrgent                = dzenStripWrap ("^fg(" ++ myUrgentFGColor  ++ ")^bg(" ++ myUrgentBGColor  ++ ")^p(4)") ("^fg(" ++ myUrgentFGColor  ++ ")^bg(" ++ myUrgentBGColor  ++ ")^p(4)^fg()^bg()"),
        ppVisible               = wrap ("^fg(" ++ myOtherscreenFGColor  ++ ")^bg(" ++ myOtherscreenBGColor  ++ ")^p(4)") "^p(4)^fg()^bg()",
        ppHidden                = wrap ("^fg(" ++ myNormalFGColor  ++ ")^bg(" ++ myNormalBGColor  ++ ")^p(4)") "^p(4)^fg()^bg()",
        ppHiddenNoWindows       = wrap ("^fg(" ++ myEmptyFGColor  ++ ")^bg(" ++ myEmptyBGColor  ++ ")^p(4)") "^p(4)^fg()^bg()",
        ppWsSep     = "", -- explicit ^p(4) above provide coloured border
        ppSep     = "^fg(" ++ mySeperatorColor ++ ") * ^fg()",
        ppLayout = (\x -> ""), -- i usually see which layout is used and don't need an extra display
        ppTitle   = wrap ("^fg(" ++ myFocusedFGColor ++ ")") "^fg()" ,
        ppOutput  = hPutStrLn handle
}

All together, the transition was quite painless. I still miss my window list from awesome (the window list from gnome-panel seems not to work with xmonad) – any ideas how to get one easily?