StatC /.xmonad/xmonad.hs

xmonad window manager config. TODO: Find a way to send windows to the current workspace when they appears or a way to show windows on all workspaces. Important for IM client chat window. See also xmonad hacking thread: http://bbs.archlinux.org/viewtopic.php?id=40636
-- Haskell common
import qualified Data.Map as M
-- System.IO.UTF8 is not currently available from Arch Linux repositories
-- import qualified System.IO.UTF8

import System.Exit
import System.IO(hPutStrLn)

-- XMonad common
import XMonad
import qualified XMonad.StackSet as W

-- XMonad actions
import qualified XMonad.Actions.FlexibleResize as Flex
import XMonad.Actions.UpdatePointer
import XMonad.Actions.Submap -- not used currently
import XMonad.Actions.CycleWS

-- XMonad hooks
import XMonad.Hooks.DynamicLog

-- XMonad layouts
import XMonad.Layout.WindowNavigation
import XMonad.Layout.NoBorders(smartBorders, noBorders)
import XMonad.Layout.Tabbed
import XMonad.Layout.PerWorkspace

-- XMonad utils
import XMonad.Util.Run(spawnPipe)

-- general --------------------------------------------------------------------

statusBarCmd = "dzen2 -sa c -ta l -bg '#E8E8E8' -fg '#000000' -fn '-*-terminus-medium-r-normal-*-12-*-*-*-*-*-iso10646-1' -h 15"

-- main -----------------------------------------------------------------------

main = do din <- spawnPipe statusBarCmd
          xmonad $ defaultConfig
                    { workspaces = workspaces'
                    , modMask = modMask'
                    , borderWidth = borderWidth'
                    , normalBorderColor = normalBorderColor'
                    , focusedBorderColor = focusedBorderColor'
                    , defaultGaps = defaultGaps'
                    , terminal = terminal'
                    , keys = keys'
                    , logHook = logHook' din
                    , layoutHook = layoutHook'
                    , manageHook = manageHook'
                    , mouseBindings = mouseBindings'
                    }

-- misc -----------------------------------------------------------------------

workspaces' :: [WorkspaceId]
workspaces' = ["inet", "util", "chat", "doc", "dev", "misc", "vbox", "k3b", "game"]

modMask' :: KeyMask
--
-- mod1Mask = alt
-- mod4Mask = windows key
-- mod5Mask = hyper key
--
modMask' = mod4Mask

borderWidth' :: Dimension
borderWidth' = 1

normalBorderColor', focusedBorderColor' :: String
normalBorderColor'  = "#CCCCCC"
focusedBorderColor' = "#000000"

defaultGaps' :: [(Int,Int,Int,Int)]
defaultGaps' = [(15,0,0,0)]

terminal' :: String
terminal' = "konsole"

-- keys -----------------------------------------------------------------------

keys' :: XConfig Layout -> M.Map (KeyMask, KeySym) (X ())
keys' conf@(XConfig {XMonad.modMask = modMask}) = M.fromList $
  [
  -- keys for Window Navigation hook
    ((modMask,               xK_Right       ), sendMessage $ Go R)
  , ((modMask,               xK_Left        ), sendMessage $ Go L)
  , ((modMask,               xK_Up          ), sendMessage $ Go U)
  , ((modMask,               xK_Down        ), sendMessage $ Go D)
  , ((modMask .|. shiftMask, xK_Right       ), sendMessage $ Swap R)
  , ((modMask .|. shiftMask, xK_Left        ), sendMessage $ Swap L)
  , ((modMask .|. shiftMask, xK_Up          ), sendMessage $ Swap U)
  , ((modMask .|. shiftMask, xK_Down        ), sendMessage $ Swap D)

  -- run programs
  , ((modMask,               xK_r           ), spawn "gmrun")
  --
  , ((modMask,               xK_KP_Multiply ), spawn "amixer -q set Master 1%+")
  , ((modMask,               xK_KP_Divide   ), spawn "amixer -q set Master 1%-")

  -- adjust current window
  , ((modMask,               xK_f           ), withFocused $ windows . W.sink)
  , ((modMask,               xK_c           ), kill)

  -- switch window
  , ((modMask,               xK_z           ), windows W.focusUp)
  , ((modMask,               xK_x           ), windows W.focusDown)

  -- adjust current layout
  , ((modMask,               xK_comma       ), sendMessage Shrink)
  , ((modMask,               xK_period      ), sendMessage Expand)
  , ((modMask .|. mod1Mask,  xK_comma       ), sendMessage (IncMasterN (-1)))
  , ((modMask .|. mod1Mask,  xK_period      ), sendMessage (IncMasterN 1))

  -- switch layout
  , ((modMask,               xK_slash       ), sendMessage NextLayout)

  -- switch workspace
  , ((modMask .|. mod1Mask,  xK_z           ), prevWS)
  , ((modMask .|. mod1Mask,  xK_x           ), nextWS)

  -- switch to particular workspace
  , ((modMask,               xK_KP_End      ), windows $ W.greedyView "inet" )
  , ((modMask,               xK_KP_Down     ), windows $ W.greedyView "util" )
  , ((modMask,               xK_KP_Next     ), windows $ W.greedyView "chat" )
  , ((modMask,               xK_KP_Left     ), windows $ W.greedyView "doc"  )
  , ((modMask,               xK_KP_Begin    ), windows $ W.greedyView "dev"  )
  , ((modMask,               xK_KP_Right    ), windows $ W.greedyView "misc" )
  , ((modMask,               xK_KP_Home     ), windows $ W.greedyView "vbox" )
  , ((modMask,               xK_KP_Up       ), windows $ W.greedyView "k3b"  )
  , ((modMask,               xK_KP_Prior    ), windows $ W.greedyView "game" )

  -- move the current window to particular workspace
  , ((modMask .|. shiftMask, xK_KP_End      ), windows $ W.shift "inet" )
  , ((modMask .|. shiftMask, xK_KP_Down     ), windows $ W.shift "util" )
  , ((modMask .|. shiftMask, xK_KP_Next     ), windows $ W.shift "chat" )
  , ((modMask .|. shiftMask, xK_KP_Left     ), windows $ W.shift "doc"  )
  , ((modMask .|. shiftMask, xK_KP_Begin    ), windows $ W.shift "dev"  )
  , ((modMask .|. shiftMask, xK_KP_Right    ), windows $ W.shift "misc" )
  , ((modMask .|. shiftMask, xK_KP_Home     ), windows $ W.shift "vbox" )
  , ((modMask .|. shiftMask, xK_KP_Up       ), windows $ W.shift "k3b"  )
  , ((modMask .|. shiftMask, xK_KP_Prior    ), windows $ W.shift "game" )

  -- XMonad general
  , ((modMask,               xK_q           ), restart "xmonad" True)
  , ((modMask .|. shiftMask, xK_q           ), io (exitWith ExitSuccess))
  ]

-- logHook --------------------------------------------------------------------

-- dynamicLog pretty printer for dzen
pp' din = defaultPP
            { ppCurrent         = id                          . \wsId -> if (':' `elem` wsId) then drop 2 wsId else wsId    -- Trim the '[Int]:' from workspace tags
            , ppVisible         = wrap "^fg(#999999)" "^fg()" . \wsId -> if (':' `elem` wsId) then drop 2 wsId else wsId
            , ppHidden          = wrap "^fg(#999999)" "^fg()" . \wsId -> if (':' `elem` wsId) then drop 2 wsId else wsId
            , ppHiddenNoWindows = wrap "^fg(#999999)" "^fg()" . \wsId -> if (':' `elem` wsId) then drop 2 wsId else wsId
            , ppSep             = " ^r(2x2) "
            , ppWsSep           = " "
            , ppLayout          = dzenColor "" "" .
                                    (\x -> case x of
                                             "Tall"            -> "tall"
                                             "Tabbed Simplest" -> "tabbed"
                                    )
            , ppTitle           = dzenColor "" ""

            , ppOutput          = hPutStrLn din
            -- System.IO.UTF8 is not currently available from Arch Linux repositories
            -- , ppOutput = System.IO.UTF8.hPutStrLn din
            }

logHook' din = (dynamicLogWithPP $ pp' din)
               >> updatePointer (Relative 0.5 0.5)

-- layoutHook -----------------------------------------------------------------

tabConfig' = defaultTheme
  {
    activeColor   = "#E8E8E8"
  , inactiveColor = "#E8E8E8"
  , urgentColor   = "#E8E8E8"

  , activeBorderColor   = "#CCCCCC"
  , inactiveBorderColor = "#CCCCCC"
  , urgentBorderColor   = "#CCCCCC"

  , activeTextColor   = "#000000"
  , inactiveTextColor = "#999999"
  , urgentTextColor   = "#990000"

  , fontName = "-*-terminus-medium-r-normal-*-12-*-*-*-*-*-iso10646-1"
  }

layoutHook' = configurableNavigation noNavigateBorders $ smartBorders $ layouts

layouts = onWorkspace "inet" myTabbed
        $ onWorkspace "doc"  myTabbed
        $ onWorkspace "dev"  myTabbed
        $ onWorkspace "vbox" myTabbed
        $ tiled ||| myTabbed
  where
    tiled = Tall 1 (3/100) (1/2)
    myTabbed = noBorders(tabbed shrinkText tabConfig')

-- manageHook -----------------------------------------------------------------

manageHook' = composeAll
  [
  -- force floating
    className =? "MPlayer"        --> doFloat
  , className =? "Gimp"           --> doFloat
  , className =? "Xmessage"       --> doFloat
  , className =? "psi"            --> doFloat
  --
  , className =? "PyDbTask1.py"   --> doFloat

  -- bind windows to workspaces
  , className =? "Minefield"      --> doF (W.shift "inet" ) --firefox3
  , className =? "Ktorrent"       --> doF (W.shift "inet" )
  , className =? "Konsole"        --> doF (W.shift "util" )
  , className =? "Geany"          --> doF (W.shift "util" )
  , className =? "Pcmanfm"        --> doF (W.shift "util" )
  , className =? "psi"            --> doF (W.shift "chat" )
  , className =? "Virtualbox"     --> doF (W.shift "vbox" )
  , className =? "K3b"            --> doF (W.shift "k3b"  )
  ]

-- mouseBindings --------------------------------------------------------------

mouseBindings' (XConfig {XMonad.modMask = modMask}) = M.fromList $
  [
    ((modMask, button1), (\w -> focus w >> mouseMoveWindow w))
  , ((modMask, button2), (\w -> focus w >> windows W.swapMaster))
  , ((modMask, button3), (\w -> focus w >> Flex.mouseResizeWindow w))
  ]