diff --git a/Config.hs b/Config.hs
--- a/Config.hs
+++ b/Config.hs
@@ -35,6 +35,7 @@
 
 #ifdef INOTIFY
 import Plugins.Mail
+import Plugins.MBox
 #endif
 
 -- $config
@@ -58,8 +59,10 @@
 
 data XPosition = Top
                | TopW Align Int
+               | TopSize Align Int Int
                | Bottom
                | BottomW Align Int
+               | BottomSize Align Int Int
                | Static {xpos, ypos, width, height :: Int}
                | OnScreen Int XPosition
                  deriving ( Read, Eq )
@@ -94,7 +97,7 @@
 -- this function's type signature.
 runnableTypes :: Command :*: Monitors :*: Date :*: PipeReader :*: CommandReader :*: StdinReader :*: XMonadLog :*: EWMH :*:
 #ifdef INOTIFY
-                 Mail :*:
+                 Mail :*: MBox :*:
 #endif
                  ()
 runnableTypes = undefined
diff --git a/IWlib.hsc b/IWlib.hsc
new file mode 100644
--- /dev/null
+++ b/IWlib.hsc
@@ -0,0 +1,77 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  IWlib
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+--  A partial binding to iwlib
+--
+-----------------------------------------------------------------------------
+
+{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}
+
+
+module IWlib (WirelessInfo(..), getWirelessInfo) where
+
+import Foreign
+import Foreign.C.Types
+import Foreign.C.String
+
+data WirelessInfo = WirelessInfo { wiEssid :: String,  wiQuality :: Int }
+                  deriving Show
+
+#include <iwlib.h>
+
+data WCfg
+data WStats
+data WRange
+
+foreign import ccall "iwlib.h iw_sockets_open"
+  c_iw_open :: IO CInt
+
+foreign import ccall "unistd.h close"
+  c_iw_close :: CInt -> IO ()
+
+foreign import ccall "iwlib.h iw_get_basic_config"
+  c_iw_basic_config :: CInt -> CString -> Ptr WCfg -> IO CInt
+
+foreign import ccall "iwlib.h iw_get_stats"
+  c_iw_stats :: CInt -> CString -> Ptr WStats -> Ptr WRange -> CInt -> IO CInt
+
+foreign import ccall "iwlib.h iw_get_range_info"
+  c_iw_range :: CInt -> CString -> Ptr WRange -> IO CInt
+
+getWirelessInfo :: String -> IO WirelessInfo
+getWirelessInfo iface =
+  allocaBytes (#size struct wireless_config) $ \wc ->
+  allocaBytes (#size struct iw_statistics) $ \stats ->
+  allocaBytes (#size struct iw_range) $ \rng ->
+  withCString iface $ \istr -> do
+    i <- c_iw_open
+    bcr <- c_iw_basic_config i istr wc
+    str <- c_iw_stats i istr stats rng 1
+    rgr <- c_iw_range i istr rng
+    c_iw_close i
+    if (bcr < 0) then return nullInfo else
+      do hase <- (#peek struct wireless_config, has_essid) wc :: IO CInt
+         eon <- (#peek struct wireless_config, essid_on) wc :: IO CInt
+         essid <- if hase /= 0 && eon /= 0 then
+                    do l <- (#peek struct wireless_config, essid_len) wc
+                       let e = (#ptr struct wireless_config, essid) wc
+                       peekCStringLen (e, fromIntegral (l :: CInt))
+                  else return ""
+         q <- if str >= 0 && rgr >=0 then
+                do qualv <- xqual $ (#ptr struct iw_statistics, qual) stats
+                   mv <- xqual $ (#ptr struct iw_range, max_qual) rng
+                   let mxv = if mv /= 0 then fromIntegral mv else 1
+                   return $ fromIntegral qualv / mxv
+              else return (-1)
+         let qv = round (100 * (q :: Double))
+         return $ WirelessInfo { wiEssid = essid, wiQuality = min 100 qv }
+    where nullInfo = WirelessInfo { wiEssid = "", wiQuality = -1 }
+          xqual p = let qp = (#ptr struct iw_param, value) p in
+            (#peek struct iw_quality, qual) qp :: IO CChar
diff --git a/Plugins/MBox.hs b/Plugins/MBox.hs
new file mode 100644
--- /dev/null
+++ b/Plugins/MBox.hs
@@ -0,0 +1,124 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.MBox
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- A plugin for checking mail in mbox files.
+--
+-----------------------------------------------------------------------------
+
+module Plugins.MBox (MBox(..)) where
+
+import Prelude hiding (catch)
+import Plugins
+
+import Control.Monad
+import Control.Concurrent.STM
+import Control.Exception (SomeException, handle, evaluate)
+
+import System.Directory
+import System.FilePath
+import System.Console.GetOpt
+import System.INotify
+
+
+import qualified Data.ByteString.Lazy.Char8 as B
+
+data Options = Options
+               { oAll :: Bool
+               , oUniq :: Bool
+               , oDir :: FilePath
+               , oPrefix :: String
+               , oSuffix :: String
+               }
+
+defaults :: Options
+defaults = Options {
+  oAll = False, oUniq = False, oDir = "", oPrefix = "", oSuffix = ""
+  }
+
+options :: [OptDescr (Options -> Options)]
+options =
+  [ Option "a" ["all"] (NoArg (\o -> o { oAll = True })) ""
+  , Option "u" [] (NoArg (\o -> o { oUniq = True })) ""
+  , Option "d" ["dir"] (ReqArg (\x o -> o { oDir = x }) "") ""
+  , Option "p" ["prefix"] (ReqArg (\x o -> o { oPrefix = x }) "") ""
+  , Option "s" ["suffix"] (ReqArg (\x o -> o { oSuffix = x }) "") ""
+  ]
+
+parseOptions :: [String] -> IO Options
+parseOptions args =
+  case getOpt Permute options args of
+    (o, _, []) -> return $ foldr id defaults o
+    (_, _, errs) -> ioError . userError $ concat errs
+
+-- | A list of display names, paths to mbox files and display colours,
+-- followed by a list of options.
+data MBox = MBox [(String, FilePath, String)] [String] String
+          deriving (Read, Show)
+
+instance Exec MBox where
+  alias (MBox _ _ a) = a
+  start (MBox ms args _) cb = do
+    vs <- mapM (const $ newTVarIO ("", 0 :: Int)) ms
+
+    opts <- parseOptions args -- $ words args
+    let dir = oDir opts
+        allb = oAll opts
+        pref = oPrefix opts
+        suff = oSuffix opts
+        uniq = oUniq opts
+
+    dirExists <- doesDirectoryExist dir
+    let ts = map (\(t, _, _) -> t) ms
+        sec = \(_, f, _) -> f
+        md = if dirExists then (dir </>) . sec else sec
+        fs = map md ms
+        cs = map (\(_, _, c) -> c) ms
+        ev = [CloseWrite]
+
+    i <- initINotify
+    zipWithM_ (\f v -> addWatch i ev f (handleNotification v)) fs vs
+
+    forM_ (zip fs vs) $ \(f, v) -> do
+      exists <- doesFileExist f
+      n <- if exists then countMails f else return 0
+      atomically $ writeTVar v (f, n)
+
+    changeLoop (mapM (fmap snd . readTVar) vs) $ \ns ->
+      let s = unwords [ showC uniq m n c | (m, n, c) <- zip3 ts ns cs
+                                         , allb || n /= 0 ]
+      in cb (if length s == 0 then "" else pref ++ s ++ suff)
+
+showC :: Bool -> String -> Int -> String -> String
+showC u m n c =
+  if c == "" then msg else "<fc=" ++ c ++ ">" ++ msg ++ "</fc>"
+    where msg = m ++ if not u || n > 1 then show n else ""
+
+countMails :: FilePath -> IO Int
+countMails f =
+  handle ((\_ -> evaluate 0) :: SomeException -> IO Int)
+         (do txt <- B.readFile f
+             evaluate $! length . filter (B.isPrefixOf from) . B.lines $ txt)
+  where from = B.pack "From "
+
+handleNotification :: TVar (FilePath, Int) -> Event -> IO ()
+handleNotification v _ =  do
+  (p, _) <- atomically $ readTVar v
+  n <- countMails p
+  atomically $ writeTVar v (p, n)
+
+changeLoop :: Eq a => STM a -> (a -> IO ()) -> IO ()
+changeLoop s f = atomically s >>= go
+ where
+    go old = do
+        f old
+        go =<< atomically (do
+            new <- s
+            guard (new /= old)
+            return new)
diff --git a/Plugins/Mail.hs b/Plugins/Mail.hs
--- a/Plugins/Mail.hs
+++ b/Plugins/Mail.hs
@@ -15,7 +15,6 @@
 module Plugins.Mail where
 
 import Prelude hiding (catch)
-import System.IO
 import Plugins
 
 import Control.Monad
diff --git a/Plugins/Monitors.hs b/Plugins/Monitors.hs
--- a/Plugins/Monitors.hs
+++ b/Plugins/Monitors.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Xmobar.Plugins.Monitors
@@ -22,21 +24,41 @@
 import Plugins.Monitors.Mem
 import Plugins.Monitors.Swap
 import Plugins.Monitors.Cpu
+import Plugins.Monitors.MultiCpu
 import Plugins.Monitors.Batt
 import Plugins.Monitors.Thermal
 import Plugins.Monitors.CpuFreq
 import Plugins.Monitors.CoreTemp
+import Plugins.Monitors.Disk
+import Plugins.Monitors.Top
+#ifdef IWLIB
+import Plugins.Monitors.Wireless
+#endif
+#ifdef LIBMPD
+import Plugins.Monitors.MPD
+#endif
 
-data Monitors = Weather Station   Args Rate
-              | Network Interface Args Rate
-              | Memory            Args Rate
-              | Swap              Args Rate
-              | Cpu               Args Rate
-              | Battery           Args Rate
-              | BatteryP [String] Args Rate
-              | Thermal   Zone    Args Rate
-              | CpuFreq           Args Rate
-              | CoreTemp          Args Rate
+data Monitors = Weather  Station    Args Rate
+              | Network  Interface  Args Rate
+              | Memory   Args       Rate
+              | Swap     Args       Rate
+              | Cpu      Args       Rate
+              | MultiCpu Args       Rate
+              | Battery  Args       Rate
+              | BatteryP [String]   Args Rate
+              | DiskU    DiskSpec   Args Rate
+              | DiskIO   DiskSpec   Args Rate
+              | Thermal  Zone       Args Rate
+              | CpuFreq  Args       Rate
+              | CoreTemp Args       Rate
+              | TopProc  Args       Rate
+              | TopMem   Args       Rate
+#ifdef IWLIB
+              | Wireless Interface  Args Rate
+#endif
+#ifdef LIBMPD
+              | MPD      Args       Rate
+#endif
                 deriving (Show,Read,Eq)
 
 type Args      = [String]
@@ -46,6 +68,7 @@
 type Zone      = String
 type Interface = String
 type Rate      = Int
+type DiskSpec  = [(String, String)]
 
 instance Exec Monitors where
     alias (Weather  s _ _) = s
@@ -54,17 +77,39 @@
     alias (Memory     _ _) = "memory"
     alias (Swap       _ _) = "swap"
     alias (Cpu        _ _) = "cpu"
+    alias (MultiCpu   _ _) = "multicpu"
     alias (Battery    _ _) = "battery"
     alias (BatteryP  _ _ _)= "battery"
     alias (CpuFreq    _ _) = "cpufreq"
+    alias (TopProc    _ _) = "top"
+    alias (TopMem     _ _) = "topmem"
     alias (CoreTemp   _ _) = "coretemp"
-    start (Weather  s a r) = runM (a ++ [s]) weatherConfig  runWeather  r
-    start (Network  i a r) = runM (a ++ [i]) netConfig      runNet      r
-    start (Thermal  z a r) = runM (a ++ [z]) thermalConfig  runThermal  r
-    start (Memory     a r) = runM a          memConfig      runMem      r
-    start (Swap       a r) = runM a          swapConfig     runSwap     r
-    start (Cpu        a r) = runM a          cpuConfig      runCpu      r
-    start (Battery    a r) = runM a          battConfig     runBatt     r
-    start (BatteryP s a r) = runM a          battConfig    (runBatt' s) r
-    start (CpuFreq    a r) = runM a          cpuFreqConfig  runCpuFreq  r
-    start (CoreTemp   a r) = runM a          coreTempConfig runCoreTemp r
+    alias (DiskU    _ _ _) = "disku"
+    alias (DiskIO   _ _ _) = "diskio"
+#ifdef IWLIB
+    alias (Wireless i _ _) = i ++ "wi"
+#endif
+#ifdef LIBMPD
+    alias (MPD        _ _) = "mpd"
+#endif
+    start (Weather  s a r) = runM (a ++ [s]) weatherConfig  runWeather    r
+    start (Network  i a r) = runM (a ++ [i]) netConfig      runNet        r
+    start (Thermal  z a r) = runM (a ++ [z]) thermalConfig  runThermal    r
+    start (Memory     a r) = runM a          memConfig      runMem        r
+    start (Swap       a r) = runM a          swapConfig     runSwap       r
+    start (Cpu        a r) = runM a          cpuConfig      runCpu        r
+    start (MultiCpu   a r) = runM a          multiCpuConfig runMultiCpu   r
+    start (Battery    a r) = runM a          battConfig     runBatt       r
+    start (BatteryP s a r) = runM a          battConfig    (runBatt' s)   r
+    start (CpuFreq    a r) = runM a          cpuFreqConfig  runCpuFreq    r
+    start (CoreTemp   a r) = runM a          coreTempConfig runCoreTemp   r
+    start (DiskU    s a r) = runM a          diskUConfig   (runDiskU s)   r
+    start (DiskIO   s a r) = runM a          diskIOConfig  (runDiskIO s)  r
+    start (TopMem     a r) = runM a          topMemConfig   runTopMem     r
+    start (TopProc    a r) = startTop a r
+#ifdef IWLIB
+    start (Wireless i a r) = runM (a ++ [i]) wirelessConfig runWireless   r
+#endif
+#ifdef LIBMPD
+    start (MPD        a r) = runM a          mpdConfig      runMPD        r
+#endif
diff --git a/Plugins/Monitors/Batt.hs b/Plugins/Monitors/Batt.hs
--- a/Plugins/Monitors/Batt.hs
+++ b/Plugins/Monitors/Batt.hs
@@ -24,7 +24,7 @@
 battConfig :: IO MConfig
 battConfig = mkMConfig
        "Batt: <left>" -- template
-       ["left","status"] -- available replacements
+       ["leftbar", "left", "status"] -- available replacements
 
 type File = (String, String)
 
@@ -61,10 +61,10 @@
        return $ if isNaN left then NA else Batt left c0
 
 formatBatt :: Float -> Monitor [String]
-formatBatt x =
-    do let f s = floatToPercent (s / 100)
-       l <- showWithColors f (x * 100)
-       return [l]
+formatBatt x = do
+  p <- showPercentsWithColors [x]
+  b <- showPercentBar (100 * x) x
+  return (b:p)
 
 runBatt :: [String] -> Monitor String
 runBatt = runBatt' ["BAT0","BAT1","BAT2"]
diff --git a/Plugins/Monitors/Common.hs b/Plugins/Monitors/Common.hs
--- a/Plugins/Monitors/Common.hs
+++ b/Plugins/Monitors/Common.hs
@@ -3,7 +3,7 @@
 -- Module      :  Plugins.Monitors.Common
 -- Copyright   :  (c) Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
--- 
+--
 -- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>
 -- Stability   :  unstable
 -- Portability :  unportable
@@ -12,7 +12,7 @@
 --
 -----------------------------------------------------------------------------
 
-module Plugins.Monitors.Common ( 
+module Plugins.Monitors.Common (
                        -- * Monitors
                        -- $monitor
                          Monitor
@@ -35,7 +35,14 @@
                        , parseTemplate
                        -- ** String Manipulation
                        -- $strings
+                       , padString
+                       , showWithPadding
                        , showWithColors
+                       , showWithColors'
+                       , showPercentsWithColors
+                       , showPercentBar
+                       , showLogBar
+                       , showWithUnits
                        , takeDigits
                        , showDigits
                        , floatToPercent
@@ -51,13 +58,13 @@
 import Control.Monad.Reader
 import qualified Data.ByteString.Lazy.Char8 as B
 import Data.IORef
-import qualified Data.Map as Map 
+import qualified Data.Map as Map
 import Data.List
 import Numeric
 import Text.ParserCombinators.Parsec
 import System.Console.GetOpt
 import Control.Exception (SomeException,handle)
-import System.Process(readProcess)
+import System.Process (readProcess)
 
 import Plugins
 -- $monitor
@@ -72,18 +79,26 @@
        , highColor   :: IORef (Maybe String)
        , template    :: IORef String
        , export      :: IORef [String]
-       } 
+       , ppad        :: IORef Int
+       , minWidth    :: IORef Int
+       , maxWidth    :: IORef Int
+       , padChars    :: IORef [Char]
+       , padRight    :: IORef Bool
+       , barBack     :: IORef String
+       , barFore     :: IORef String
+       , barWidth    :: IORef Int
+       }
 
 -- | from 'http:\/\/www.haskell.org\/hawiki\/MonadState'
 type Selector a = MConfig -> IORef a
 
 sel :: Selector a -> Monitor a
-sel s = 
+sel s =
     do hs <- ask
        liftIO $ readIORef (s hs)
 
 mods :: Selector a -> (a -> a) -> Monitor ()
-mods s m = 
+mods s m =
     do v <- ask
        io $ modifyIORef (s v) m
 
@@ -106,7 +121,15 @@
        hc <- newIORef Nothing
        t  <- newIORef tmpl
        e  <- newIORef exprts
-       return $ MC nc l lc h hc t e
+       p  <- newIORef 0
+       mn <- newIORef 0
+       mx <- newIORef 0
+       pc <- newIORef " "
+       pr <- newIORef False
+       bb <- newIORef ":"
+       bf <- newIORef "#"
+       bw <- newIORef 10
+       return $ MC nc l lc h hc t e p mn mx pc pr bb bf bw
 
 data Opts = HighColor String
           | NormalColor String
@@ -114,18 +137,36 @@
           | Low String
           | High String
           | Template String
+          | PercentPad String
+          | MinWidth String
+          | MaxWidth String
+          | Width String
+          | PadChars String
+          | PadAlign String
+          | BarBack String
+          | BarFore String
+          | BarWidth String
 
 options :: [OptDescr Opts]
 options =
-    [ Option ['H']  ["High"]     (ReqArg High "number"              ) "The high threshold"
-    , Option ['L']  ["Low"]      (ReqArg Low "number"               ) "The low threshold"
-    , Option ['h']  ["high"]     (ReqArg HighColor "color number"   ) "Color for the high threshold: ex \"#FF0000\""
-    , Option ['n']  ["normal"]   (ReqArg NormalColor "color number" ) "Color for the normal threshold: ex \"#00FF00\""
-    , Option ['l']  ["low"]      (ReqArg LowColor "color number"    ) "Color for the low threshold: ex \"#0000FF\""
-    , Option ['t']  ["template"] (ReqArg Template "output template" ) "Output template."
+    [ Option ['H']  ["High"]     (ReqArg High "number"               )  "The high threshold"
+    , Option ['L']  ["Low"]      (ReqArg Low "number"                )  "The low threshold"
+    , Option ['h']  ["high"]     (ReqArg HighColor "color number"    )  "Color for the high threshold: ex \"#FF0000\""
+    , Option ['n']  ["normal"]   (ReqArg NormalColor "color number"  )  "Color for the normal threshold: ex \"#00FF00\""
+    , Option ['l']  ["low"]      (ReqArg LowColor "color number"     )  "Color for the low threshold: ex \"#0000FF\""
+    , Option ['t']  ["template"] (ReqArg Template "output template"  )  "Output template."
+    , Option ['p']  ["ppad"]     (ReqArg PercentPad "percent padding")  "Minimum percentage width."
+    , Option ['m']  ["minwidth"] (ReqArg MinWidth "minimum width"    )  "Minimum field width"
+    , Option ['M']  ["maxwidth"] (ReqArg MaxWidth "maximum width"    )  "Maximum field width"
+    , Option ['w']  ["width"]    (ReqArg Width "fixed width"         )  "Fixed field width"
+    , Option ['c']  ["padchars"] (ReqArg PadChars "padding chars"    )  "Characters to use for padding"
+    , Option ['a']  ["align"]    (ReqArg PadAlign "padding alignment")  "'l' for left padding, 'r' for right"
+    , Option ['b']  ["bback"]    (ReqArg BarBack "bar background"    )  "Characters used to draw bar backgrounds"
+    , Option ['f']  ["bfore"]    (ReqArg BarFore "bar foreground"    )  "Characters used to draw bar foregrounds"
+    , Option ['W']  ["bwidth"]   (ReqArg BarWidth "bar width"        )  "Bar width"
     ]
 
-doArgs :: [String] 
+doArgs :: [String]
        -> ([String] -> Monitor String)
        -> Monitor String
 doArgs args action =
@@ -138,6 +179,7 @@
 doConfigOptions [] = io $ return ()
 doConfigOptions (o:oo) =
     do let next = doConfigOptions oo
+           nz s = let x = read s in max 0 x
        case o of
          High         h -> setConfigValue (read h) high >> next
          Low          l -> setConfigValue (read l) low >> next
@@ -145,6 +187,16 @@
          NormalColor nc -> setConfigValue (Just nc) normalColor >> next
          LowColor    lc -> setConfigValue (Just lc) lowColor >> next
          Template     t -> setConfigValue t template >> next
+         PercentPad   p -> setConfigValue (nz p) ppad >> next
+         MinWidth    mn -> setConfigValue (nz mn) minWidth >> next
+         MaxWidth    mx -> setConfigValue (nz mx) maxWidth >> next
+         Width        w -> setConfigValue (nz w) minWidth >>
+                           setConfigValue (nz w) maxWidth >> next
+         PadChars    pc -> setConfigValue pc padChars >> next
+         PadAlign    pa -> setConfigValue (isPrefixOf "r" pa) padRight >> next
+         BarBack     bb -> setConfigValue bb barBack >> next
+         BarFore     bf -> setConfigValue bf barFore >> next
+         BarWidth    bw -> setConfigValue (nz bw) barWidth >> next
 
 runM :: [String] -> IO MConfig -> ([String] -> Monitor String) -> Int -> (String -> IO ()) -> IO ()
 runM args conf action r cb = do go
@@ -165,7 +217,7 @@
 -- $parsers
 
 runP :: Parser [a] -> String -> IO [a]
-runP p i = 
+runP p i =
     do case (parse p "" i) of
          Left _ -> return []
          Right x  -> return x
@@ -193,7 +245,7 @@
        } <|> return ("<" ++ s ++ " not found!>")
 
 skipTillString :: String -> Parser String
-skipTillString s = 
+skipTillString s =
     manyTill skipRestOfLine $ string s
 
 -- | Parses the output template string
@@ -203,7 +255,7 @@
        ; com <- templateCommandParser
        ; ss <- nonPlaceHolder
        ; return (s, com, ss)
-       } 
+       }
     where
       nonPlaceHolder = liftM concat . many $
                        (many1 $ noneOf "<") <|> colorSpec
@@ -238,14 +290,14 @@
     do t <- getConfigValue template
        s <- io $ runP templateParser t
        e <- getConfigValue export
-       let m = Map.fromList . zip e $ l 
-       return $ combine m s 
+       let m = Map.fromList . zip e $ l
+       return $ combine m s
 
 -- | Given a finite "Map" and a parsed templatet produces the
 -- | resulting output string.
 combine :: Map.Map String String -> [(String, String, String)] -> String
 combine _ [] = []
-combine m ((s,ts,ss):xs) = 
+combine m ((s,ts,ss):xs) =
     s ++ str ++ ss ++ combine m xs
         where str = Map.findWithDefault err ts m
               err = "<" ++ ts ++ " not found!>"
@@ -255,7 +307,7 @@
 type Pos = (Int, Int)
 
 takeDigits :: Int -> Float -> Float
-takeDigits d n = 
+takeDigits d n =
     fromIntegral ((round (n * fact)) :: Int) / fact
   where fact = 10 ^ d
 
@@ -263,13 +315,37 @@
 showDigits d n =
     showFFloat (Just d) n ""
 
-floatToPercent :: Float -> String
-floatToPercent n = 
-    showDigits 0 (n * 100) ++ "%"
+showWithUnits :: Int -> Int -> Float -> String
+showWithUnits d n x
+  | x < 0 = "-" ++ showWithUnits d n (-x)
+  | n > 3 || x < 10^(d + 1) = show (round x :: Int) ++ units n
+  | x <= 1024 = showDigits d (x/1024) ++ units (n+1)
+  | otherwise = showWithUnits d (n+1) (x/1024)
+  where units = (!!) ["B", "K", "M", "G", "T"]
 
+padString :: Int -> Int -> String -> Bool -> String -> String
+padString mnw mxw pad pr s =
+  let len = length s
+      rmin = if mnw == 0 then 1 else mnw
+      rmax = if mxw == 0 then max len rmin else mxw
+      (rmn, rmx) = if rmin <= rmax then (rmin, rmax) else (rmax, rmin)
+      rlen = min (max rmn len) rmx
+  in if rlen < len then
+       take rlen s
+     else let ps = take (rlen - len) (cycle pad)
+          in if pr then s ++ ps else ps ++ s
+
+floatToPercent :: Float -> Monitor String
+floatToPercent n =
+  do pad <- getConfigValue ppad
+     pc <- getConfigValue padChars
+     pr <- getConfigValue padRight
+     let p = showDigits 0 (n * 100)
+     return $ padString pad pad pc pr p ++ "%"
+
 stringParser :: Pos -> B.ByteString -> String
 stringParser (x,y) =
-     B.unpack . li x . B.words . li y . B.lines 
+     B.unpack . li x . B.words . li y . B.lines
     where li i l | length l > i = l !! i
                  | otherwise    = B.empty
 
@@ -281,20 +357,54 @@
             Just c -> return $
                 "<fc=" ++ c ++ ">" ++ str ++ "</fc>"
 
+showWithPadding :: String -> Monitor String
+showWithPadding s =
+    do mn <- getConfigValue minWidth
+       mx <- getConfigValue maxWidth
+       p <- getConfigValue padChars
+       pr <- getConfigValue padRight
+       return $ padString mn mx p pr s
+
+colorizeString :: (Num a, Ord a) => a -> String -> Monitor String
+colorizeString x s = do
+    h <- getConfigValue high
+    l <- getConfigValue low
+    let col = setColor s
+        [ll,hh] = map fromIntegral $ sort [l, h] -- consider high < low
+    head $ [col highColor   | x > hh ] ++
+           [col normalColor | x > ll ] ++
+           [col lowColor    | True]
+
 showWithColors :: (Num a, Ord a) => (a -> String) -> a -> Monitor String
-showWithColors f x =
-    do h <- getConfigValue high
-       l <- getConfigValue low
-       let col = setColor $ f x
-           [ll,hh] = map fromIntegral $ sort [l, h] -- consider high < low 
-       head $ [col highColor   | x > hh ] ++
-              [col normalColor | x > ll ] ++
-              [col lowColor    | True]
+showWithColors f x = showWithPadding (f x) >>= colorizeString x
 
+showWithColors' :: (Num a, Ord a) => String -> a -> Monitor String
+showWithColors' str v = showWithColors (const str) v
+
+showPercentsWithColors :: [Float] -> Monitor [String]
+showPercentsWithColors fs =
+  do fstrs <- mapM floatToPercent fs
+     zipWithM (showWithColors . const) fstrs (map (*100) fs)
+
+showPercentBar :: Float -> Float -> Monitor String
+showPercentBar v x = do
+  bb <- getConfigValue barBack
+  bf <- getConfigValue barFore
+  bw <- getConfigValue barWidth
+  let len = min bw $ round (fromIntegral bw * x)
+  s <- colorizeString v (take len $ cycle bf)
+  return $ s ++ (take (bw - len) $ cycle bb)
+
+showLogBar :: Float -> Float -> Monitor String
+showLogBar f v = do
+  h <- fromIntegral `fmap` getConfigValue high
+  bw <- fromIntegral `fmap` getConfigValue barWidth
+  showPercentBar v $ f + (logBase 10 (v / h)) / bw
+
 -- $threads
 
 doActionTwiceWithDelay :: Int -> IO [a] -> IO ([a], [a])
-doActionTwiceWithDelay delay action = 
+doActionTwiceWithDelay delay action =
     do v1 <- newMVar []
        forkIO $! getData action v1 0
        v2 <- newMVar []
diff --git a/Plugins/Monitors/CoreCommon.hs b/Plugins/Monitors/CoreCommon.hs
--- a/Plugins/Monitors/CoreCommon.hs
+++ b/Plugins/Monitors/CoreCommon.hs
@@ -25,19 +25,23 @@
 -- Function checks the existence of first file specified by pattern and if the
 -- file doesn't exists failure message is shown, otherwise the data retrieval
 -- is performed.
-checkedDataRetrieval :: String -> String -> String -> String -> Double -> Monitor String
-checkedDataRetrieval failureMessage dir file pattern divisor = do
+checkedDataRetrieval :: (Num a, Ord a, Show a) =>
+                        String -> String -> String -> String -> (Double -> a)
+                        -> Monitor String
+checkedDataRetrieval failureMessage dir file pattern trans = do
     exists <- io $ fileExist $ concat [dir, "/", pattern, "0/", file]
     case exists of
          False  -> return failureMessage
-         True   -> retrieveData dir file pattern divisor
+         True   -> retrieveData dir file pattern trans
 
 -- |
--- Function retrieves data from files in directory dir specified by pattern.
--- String values are converted to double and adjusted with divisor. Final array
--- is processed by template parser function and returned as monitor string.
-retrieveData :: String -> String -> String -> Double -> Monitor String
-retrieveData dir file pattern divisor = do
+-- Function retrieves data from files in directory dir specified by
+-- pattern. String values are converted to double and 'trans' applied
+-- to each one. Final array is processed by template parser function
+-- and returned as monitor string.
+retrieveData :: (Num a, Ord a, Show a) =>
+                String -> String -> String -> (Double -> a) -> Monitor String
+retrieveData dir file pattern trans = do
     count <- io $ dirCount dir pattern
     contents <- io $ mapM getGuts $ files count
     values <- mapM (showWithColors show) $ map conversion contents
@@ -50,5 +54,5 @@
                                                        && isDigit (last s))
         files count = map (\i -> concat [dir, "/", pattern, show i, "/", file])
                           [0 .. count - 1]
-        conversion = (/divisor) . (read :: String -> Double)
+        conversion = trans . (read :: String -> Double)
 
diff --git a/Plugins/Monitors/CoreTemp.hs b/Plugins/Monitors/CoreTemp.hs
--- a/Plugins/Monitors/CoreTemp.hs
+++ b/Plugins/Monitors/CoreTemp.hs
@@ -37,5 +37,5 @@
         pattern = "coretemp."
         divisor = 1e3 :: Double
         failureMessage = "CoreTemp: N/A"
-    checkedDataRetrieval failureMessage dir file pattern divisor
+    checkedDataRetrieval failureMessage dir file pattern (/divisor)
 
diff --git a/Plugins/Monitors/Cpu.hs b/Plugins/Monitors/Cpu.hs
--- a/Plugins/Monitors/Cpu.hs
+++ b/Plugins/Monitors/Cpu.hs
@@ -3,7 +3,7 @@
 -- Module      :  Plugins.Monitors.Cpu
 -- Copyright   :  (c) Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
--- 
+--
 -- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>
 -- Stability   :  unstable
 -- Portability :  unportable
@@ -20,7 +20,7 @@
 cpuConfig :: IO MConfig
 cpuConfig = mkMConfig
        "Cpu: <total>"                           -- template
-       ["total","user","nice","system","idle"]  -- available replacements
+       ["bar","total","user","nice","system","idle"]  -- available replacements
 
 cpuData :: IO [Float]
 cpuData = do s <- B.readFile "/proc/stat"
@@ -31,23 +31,23 @@
     map read . map B.unpack . tail . B.words . flip (!!) 0 . B.lines
 
 parseCPU :: IO [Float]
-parseCPU = 
+parseCPU =
     do (a,b) <- doActionTwiceWithDelay 750000 cpuData
        let dif = zipWith (-) b a
            tot = foldr (+) 0 dif
            percent = map (/ tot) dif
        return percent
 
-formatCpu :: [Float] -> Monitor [String] 
+formatCpu :: [Float] -> Monitor [String]
 formatCpu [] = return [""]
-formatCpu x =
-    do let f s = floatToPercent (s / 100)
-           t = foldr (+) 0 $ take 3 x
-           list = t:x
-       mapM (showWithColors f) . map (* 100) $ list
+formatCpu xs = do
+  let t = foldr (+) 0 $ take 3 xs
+  b <- showPercentBar (100 * t) t
+  ps <- showPercentsWithColors (t:xs)
+  return (b:ps)
 
 runCpu :: [String] -> Monitor String
 runCpu _ =
     do c <- io $ parseCPU
        l <- formatCpu c
-       parseTemplate l 
+       parseTemplate l
diff --git a/Plugins/Monitors/CpuFreq.hs b/Plugins/Monitors/CpuFreq.hs
--- a/Plugins/Monitors/CpuFreq.hs
+++ b/Plugins/Monitors/CpuFreq.hs
@@ -36,5 +36,5 @@
         pattern = "cpu"
         divisor = 1e6 :: Double
         failureMessage = "CpuFreq: N/A"
-    checkedDataRetrieval failureMessage dir file pattern divisor
+    checkedDataRetrieval failureMessage dir file pattern (/divisor)
 
diff --git a/Plugins/Monitors/Disk.hs b/Plugins/Monitors/Disk.hs
new file mode 100644
--- /dev/null
+++ b/Plugins/Monitors/Disk.hs
@@ -0,0 +1,137 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Monitors.Disk
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+--  Disk usage and throughput monitors for Xmobar
+--
+-----------------------------------------------------------------------------
+
+module Plugins.Monitors.Disk ( diskUConfig, runDiskU
+                             , diskIOConfig, runDiskIO
+                             ) where
+
+import Plugins.Monitors.Common
+import StatFS
+
+import Control.Monad (zipWithM)
+import qualified Data.ByteString.Lazy.Char8 as B
+import Data.List (isPrefixOf, find, intercalate)
+
+diskIOConfig :: IO MConfig
+diskIOConfig = mkMConfig "" ["total", "read", "write",
+                             "totalbar", "readbar", "writebar"]
+
+diskUConfig :: IO MConfig
+diskUConfig = mkMConfig ""
+              ["size", "free", "used", "freep", "usedp", "freebar", "usedbar"]
+
+type DevName = String
+type Path = String
+
+mountedDevices :: [String] -> IO [(DevName, Path)]
+mountedDevices req = do
+  s <- B.readFile "/etc/mtab"
+  return (parse s)
+  where
+    parse = map undev . filter isDev . map (firstTwo . B.words) . B.lines
+    firstTwo (a:b:_) = (B.unpack a, B.unpack b)
+    firstTwo _ = ("", "")
+    isDev (d, p) = "/dev/" `isPrefixOf` d &&
+                   (p `elem` req || drop 5 d `elem` req)
+    undev (d, f) = (drop 5 d, f)
+
+diskData :: IO [(DevName, [Float])]
+diskData = do
+  s <- B.readFile "/proc/diskstats"
+  let extract ws = (head ws, map read (tail ws))
+  return $ map (extract . map B.unpack . drop 2 . B.words) (B.lines s)
+
+mountedData :: [DevName] -> IO [(DevName, [Float])]
+mountedData devs = do
+  (dt, dt') <- doActionTwiceWithDelay 750000 diskData
+  return $ map (parseDev (zipWith diff dt' dt)) devs
+  where diff (dev, xs) (_, ys) = (dev, zipWith (-) xs ys)
+
+parseDev :: [(DevName, [Float])] -> DevName -> (DevName, [Float])
+parseDev dat dev =
+  case find ((==dev) . fst) dat of
+    Nothing -> (dev, [0, 0, 0])
+    Just (_, xs) ->
+      let rSp = speed (xs !! 2) (xs !! 3)
+          wSp = speed (xs !! 6) (xs !! 7)
+          sp =  speed (xs !! 2 + xs !! 6) (xs !! 3 + xs !! 7)
+          speed x t = if t == 0 then 0 else 500 * x / t
+          dat' = if length xs > 6 then [sp, rSp, wSp] else [0, 0, 0]
+      in (dev, dat')
+
+fsStats :: String -> IO [Integer]
+fsStats path = do
+  stats <- getFileSystemStats path
+  case stats of
+    Nothing -> return [-1, -1, -1]
+    Just f -> let tot = fsStatByteCount f
+                  free = fsStatBytesAvailable f
+                  used = fsStatBytesUsed f
+              in return [tot, free, used]
+
+speedToStr :: Float -> String
+speedToStr = showWithUnits 2 1
+
+sizeToStr :: Integer -> String
+sizeToStr = showWithUnits 3 0 . fromIntegral
+
+findTempl :: DevName -> Path -> [(String, String)] -> String
+findTempl dev path disks =
+  case find devOrPath disks of
+    Just (_, t) -> t
+    Nothing -> ""
+  where devOrPath (d, _) = d == dev || d == path
+
+devTemplates :: [(String, String)]
+                -> [(DevName, Path)]
+                -> [(DevName, [Float])]
+                -> [(String, [Float])]
+devTemplates disks mounted dat =
+  map (\(d, p) -> (findTempl d p disks, findData d)) mounted
+  where findData dev = case find ((==dev) . fst) dat of
+                         Nothing -> [0, 0, 0]
+                         Just (_, xs) -> xs
+
+runDiskIO' :: (String, [Float]) -> Monitor String
+runDiskIO' (tmp, xs) = do
+  s <- mapM (showWithColors speedToStr) xs
+  b <- mapM (showLogBar 0.8) xs
+  setConfigValue tmp template
+  parseTemplate $ s ++ b
+
+runDiskIO :: [(String, String)] -> [String] -> Monitor String
+runDiskIO disks _ = do
+  mounted <- io $ mountedDevices (map fst disks)
+  dat <- io $ mountedData (map fst mounted)
+  strs <- mapM runDiskIO' $ devTemplates disks mounted dat
+  return $ intercalate " " strs
+
+runDiskU' :: String -> String -> Monitor String
+runDiskU' tmp path = do
+  setConfigValue tmp template
+  fstats <- io $ fsStats path
+  let strs = map sizeToStr fstats
+      freep = (fstats !! 1) * 100 `div` head fstats
+      fr = fromIntegral freep / 100
+  s <- zipWithM showWithColors' strs [100, freep, 100 - freep]
+  sp <- showPercentsWithColors [fr, 1 - fr]
+  fb <- showPercentBar (fromIntegral freep) fr
+  ub <- showPercentBar (fromIntegral $ 100 - freep) (1 - fr)
+  parseTemplate $ s ++ sp ++ [fb, ub]
+
+runDiskU :: [(String, String)] -> [String] -> Monitor String
+runDiskU disks _ = do
+  devs <- io $ mountedDevices (map fst disks)
+  strs <- mapM (\(d, p) -> runDiskU' (findTempl d p disks) p) devs
+  return $ intercalate " " strs
diff --git a/Plugins/Monitors/MPD.hs b/Plugins/Monitors/MPD.hs
new file mode 100644
--- /dev/null
+++ b/Plugins/Monitors/MPD.hs
@@ -0,0 +1,92 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Monitors.MPD
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+--  MPD status and song
+--
+-----------------------------------------------------------------------------
+
+module Plugins.Monitors.MPD ( mpdConfig, runMPD ) where
+
+import Plugins.Monitors.Common
+import System.Console.GetOpt
+import qualified Network.MPD as M
+
+mpdConfig :: IO MConfig
+mpdConfig = mkMConfig "MPD: <state>"
+              [ "bar", "state", "statei", "volume", "length"
+              , "lapsed", "plength"
+              , "name", "artist", "composer", "performer"
+              , "album", "title", "track", "trackno", "file", "genre"
+              ]
+
+data MOpts = MOpts {mPlaying :: String, mStopped :: String, mPaused :: String}
+
+defaultOpts :: MOpts
+defaultOpts = MOpts { mPlaying = ">>", mStopped = "><", mPaused = "||" }
+
+options :: [OptDescr (MOpts -> MOpts)]
+options =
+  [ Option "P" ["playing"] (ReqArg (\x o -> o { mPlaying = x }) "") ""
+  , Option "S" ["stopped"] (ReqArg (\x o -> o { mStopped = x }) "") ""
+  , Option "Z" ["paused"] (ReqArg (\x o -> o { mPaused = x }) "") ""
+  ]
+
+runMPD :: [String] -> Monitor String
+runMPD args = do
+  status <- io $ M.withMPD M.status
+  song <- io $ M.withMPD M.currentSong
+  opts <- io $ mopts args
+  let (b, s) = parseMPD status song opts
+  bs <- showPercentBar (100 * b) b
+  parseTemplate (bs:s)
+
+mopts :: [String] -> IO MOpts
+mopts argv =
+  case getOpt Permute options argv of
+    (o, _, []) -> return $ foldr id defaultOpts o
+    (_, _, errs) -> ioError . userError $ concat errs
+
+parseMPD :: M.Response M.Status -> M.Response (Maybe M.Song) -> MOpts
+            -> (Float, [String])
+parseMPD (Left e) _ _ = (0, show e:repeat "")
+parseMPD (Right st) song opts = (b, [ss, si, vol, len, lap, plen] ++ sf)
+  where s = M.stState st
+        ss = show s
+        si = stateGlyph s opts
+        vol = int2Str $ M.stVolume st
+        (lap, len) = (showTime p, showTime t)
+        (p, t) = M.stTime st
+        b = if t > 0 then fromIntegral p / fromIntegral t else 0
+        plen = int2Str $ M.stPlaylistLength st
+        sf = parseSong song
+
+stateGlyph :: M.State -> MOpts -> String
+stateGlyph s o =
+  case s of
+    M.Playing -> mPlaying o
+    M.Paused -> mPaused o
+    M.Stopped -> mStopped o
+
+parseSong :: M.Response (Maybe M.Song) -> [String]
+parseSong (Left _) = repeat ""
+parseSong (Right Nothing) = repeat ""
+parseSong (Right (Just s)) =
+  [ M.sgName s, M.sgArtist s, M.sgComposer s, M.sgPerformer s
+  , M.sgAlbum s, M.sgTitle s, track, trackno, M.sgFilePath s, M.sgGenre s]
+  where (track, trackno) = (int2Str t, int2Str tn)
+        (t, tn) = M.sgTrack s
+
+showTime :: Integer -> String
+showTime t = int2Str minutes ++ ":" ++ int2Str seconds
+  where minutes = t `div` 60
+        seconds = t `mod` 60
+
+int2Str :: (Num a, Ord a) => a -> String
+int2Str x = if x < 10 then '0':sx else sx where sx = show x
diff --git a/Plugins/Monitors/Mem.hs b/Plugins/Monitors/Mem.hs
--- a/Plugins/Monitors/Mem.hs
+++ b/Plugins/Monitors/Mem.hs
@@ -3,7 +3,7 @@
 -- Module      :  Plugins.Monitors.Mem
 -- Copyright   :  (c) Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
--- 
+--
 -- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>
 -- Stability   :  unstable
 -- Portability :  unportable
@@ -12,36 +12,47 @@
 --
 -----------------------------------------------------------------------------
 
-module Plugins.Monitors.Mem where
+module Plugins.Monitors.Mem (memConfig, runMem, totalMem, usedMem) where
 
 import Plugins.Monitors.Common
 
 memConfig :: IO MConfig
 memConfig = mkMConfig
        "Mem: <usedratio>% (<cache>M)" -- template
-       ["total", "free", "buffer",    -- available replacements
-        "cache", "rest", "used", "usedratio"]
+       ["usedbar", "freebar", "usedratio", "total",  -- available replacements
+        "free", "buffer", "cache", "rest", "used"]
 
 fileMEM :: IO String
 fileMEM = readFile "/proc/meminfo"
 
 parseMEM :: IO [Float]
 parseMEM =
-    do file <- fileMEM 
+    do file <- fileMEM
        let content = map words $ take 4 $ lines file
            [total, free, buffer, cache] = map (\line -> (read $ line !! 1 :: Float) / 1024) content
            rest = free + buffer + cache
            used = total - rest
-           usedratio = used * 100 / total
-       return [total, free, buffer, cache, rest, used, usedratio]
+           usedratio = used / total
+       return [usedratio, total, free, buffer, cache, rest, used]
 
+totalMem :: IO Float
+totalMem = fmap ((*1024) . (!!1)) parseMEM
+
+usedMem :: IO Float
+usedMem = fmap ((*1024) . (!!6)) parseMEM
+
 formatMem :: [Float] -> Monitor [String]
-formatMem x =
-    do let f n = showDigits 0 n
-       mapM (showWithColors f) x
+formatMem (r:xs) =
+    do let f = showDigits 0
+           rr = 100 * r
+       ub <- showPercentBar rr r
+       fb <- showPercentBar (100 - rr) (1 - r)
+       s <- mapM (showWithColors f) (rr:xs)
+       return (ub:fb:s)
+formatMem _ = return $ replicate 9 "N/A"
 
 runMem :: [String] -> Monitor String
 runMem _ =
-    do m <- io $ parseMEM
+    do m <- io parseMEM
        l <- formatMem m
-       parseTemplate l 
+       parseTemplate l
diff --git a/Plugins/Monitors/MultiCpu.hs b/Plugins/Monitors/MultiCpu.hs
new file mode 100644
--- /dev/null
+++ b/Plugins/Monitors/MultiCpu.hs
@@ -0,0 +1,66 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Monitors.MultiCpu
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- A multi-cpu monitor for Xmobar
+--
+-----------------------------------------------------------------------------
+
+module Plugins.Monitors.MultiCpu(multiCpuConfig, runMultiCpu) where
+
+import Plugins.Monitors.Common
+import qualified Data.ByteString.Lazy.Char8 as B
+import Data.List (isPrefixOf)
+
+multiCpuConfig :: IO MConfig
+multiCpuConfig =
+  mkMConfig "Cpu: <total>"
+            [ k ++ n | n <- "" : map show [0 :: Int ..]
+                     , k <- ["bar","total","user","nice","system","idle"]]
+
+
+cpuData :: IO [[Float]]
+cpuData = do s <- B.readFile "/proc/stat"
+             return $ cpuParser s
+
+cpuParser :: B.ByteString -> [[Float]]
+cpuParser = map parseList . cpuLists
+  where cpuLists = takeWhile isCpu . map B.words . B.lines
+        isCpu (w:_) = "cpu" `isPrefixOf` B.unpack w
+        isCpu _ = False
+        parseList = map (read . B.unpack) . tail
+
+parseCpuData :: IO [[Float]]
+parseCpuData =
+  do (as, bs) <- doActionTwiceWithDelay 950000 cpuData
+     let p0 = zipWith percent bs as
+     return p0
+
+percent :: [Float] -> [Float] -> [Float]
+percent b a = if tot > 0 then map (/ tot) $ take 4 dif else [0, 0, 0, 0]
+  where dif = zipWith (-) b a
+        tot = foldr (+) 0 dif
+
+formatMultiCpus :: [[Float]] -> Monitor [String]
+formatMultiCpus [] = showPercentsWithColors $ replicate 15 0.0
+formatMultiCpus xs = fmap concat $ mapM formatCpu xs
+
+formatCpu :: [Float] -> Monitor [String]
+formatCpu xs
+  | length xs < 4 = showPercentsWithColors $ replicate 6 0.0
+  | otherwise = let t = foldr (+) 0 $ take 3 xs
+                in do b <- showPercentBar (100 * t) t
+                      ps <- showPercentsWithColors (t:xs)
+                      return (b:ps)
+
+runMultiCpu :: [String] -> Monitor String
+runMultiCpu _ =
+  do c <- io parseCpuData
+     l <- formatMultiCpus c
+     parseTemplate l
diff --git a/Plugins/Monitors/Net.hs b/Plugins/Monitors/Net.hs
--- a/Plugins/Monitors/Net.hs
+++ b/Plugins/Monitors/Net.hs
@@ -29,14 +29,14 @@
 netConfig :: IO MConfig
 netConfig = mkMConfig
     "<dev>: <rx>|<tx>"      -- template
-    ["dev", "rx", "tx"]     -- available replacements
+    ["dev", "rx", "tx", "rxbar", "txbar"]     -- available replacements
 
 -- Given a list of indexes, take the indexed elements from a list.
 getNElements :: [Int] -> [a] -> [a]
 getNElements ns as = map (as!!) ns
 
 -- Split into words, with word boundaries indicated by the given predicate.
--- Drops delimiters.  Duplicates 'Data.List.Split.wordsBy'. 
+-- Drops delimiters.  Duplicates 'Data.List.Split.wordsBy'.
 --
 -- > map (wordsBy (`elem` " :")) ["lo:31174097 31174097", "eth0:  43598 88888"]
 --
@@ -62,17 +62,19 @@
 netParser =
     map (readNetDev . getNElements [0,1,9] . wordsBy (`elem` " :") . B.unpack) . drop 2 . B.lines
 
-formatNet :: Float -> Monitor String
-formatNet d =
-    showWithColors f d
-        where f s = showDigits 1 s ++ "Kb"
+formatNet :: Float -> Monitor (String, String)
+formatNet d = do
+    b <- showLogBar 0.8 d
+    x <- showWithColors f d
+    return (x, b)
+      where f s = showDigits 1 s ++ "Kb"
 
 printNet :: NetDev -> Monitor String
 printNet nd =
     case nd of
-         ND d r t -> do rx <- formatNet r
-                        tx <- formatNet t
-                        parseTemplate [d,rx,tx]
+         ND d r t -> do (rx, rb) <- formatNet r
+                        (tx, tb) <- formatNet t
+                        parseTemplate [d,rx,tx,rb,tb]
          NA -> return "N/A"
 
 parseNET :: String -> IO [NetDev]
diff --git a/Plugins/Monitors/Swap.hs b/Plugins/Monitors/Swap.hs
--- a/Plugins/Monitors/Swap.hs
+++ b/Plugins/Monitors/Swap.hs
@@ -3,7 +3,7 @@
 -- Module      :  Plugins.Monitors.Swap
 -- Copyright   :  (c) Andrea Rossato
 -- License     :  BSD-style (see LICENSE)
--- 
+--
 -- Maintainer  :  Andrea Rossato <andrea.rossato@unibz.it>
 -- Stability   :  unstable
 -- Portability :  unportable
@@ -30,7 +30,7 @@
 parseMEM =
     do file <- fileMEM
        let li i l
-               | l /= [] = (head l) !! i 
+               | l /= [] = (head l) !! i
                | otherwise = B.empty
            fs s l
                | l == []    = False
@@ -41,17 +41,16 @@
            free = get_data "SwapFree:" st
        return [tot, (tot - free), free, (tot - free) / tot]
 
-formatSwap :: [Float] -> Monitor [String] 
+formatSwap :: [Float] -> Monitor [String]
 formatSwap x =
     do let f1 n = showDigits 2 n
-           f2 n = floatToPercent n
            (hd, tl) = splitAt 3 x
        firsts <- mapM (showWithColors f1) hd
-       lasts <- mapM (showWithColors f2) tl
+       lasts <- showPercentsWithColors (map (/100) tl)
        return $ firsts ++ lasts
 
 runSwap :: [String] -> Monitor String
 runSwap _ =
     do m <- io $ parseMEM
        l <- formatSwap m
-       parseTemplate l 
+       parseTemplate l
diff --git a/Plugins/Monitors/Top.hs b/Plugins/Monitors/Top.hs
new file mode 100644
--- /dev/null
+++ b/Plugins/Monitors/Top.hs
@@ -0,0 +1,156 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Monitors.Top
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+--  Process activity and memory consumption monitors
+--
+-----------------------------------------------------------------------------
+
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+module Plugins.Monitors.Top (startTop, topMemConfig, runTopMem) where
+
+import Plugins.Monitors.Common
+import Plugins.Monitors.Mem (usedMem)
+
+import Control.Exception (SomeException, handle)
+import System.Directory
+import System.FilePath
+import System.IO
+import System.Posix.Unistd (getSysVar, SysVar(ClockTick))
+import Foreign.C.Types
+import Data.List (sortBy)
+import Data.Ord (comparing)
+import Data.IORef
+import Data.Time.Clock
+
+import Data.IntMap (IntMap)
+import qualified Data.IntMap as M
+
+intStrs :: [String]
+intStrs = map show [(1::Int) ..]
+
+topMemConfig :: IO MConfig
+topMemConfig = mkMConfig "<both1>"
+                 [ k ++ n | n <- intStrs , k <- ["name", "mem", "both"]]
+
+topConfig :: IO MConfig
+topConfig = mkMConfig "<both1>"
+              ("no" : [ k ++ n | n <- intStrs
+                               , k <- [ "name", "cpu", "both"
+                                      , "mname", "mem", "mboth"]])
+
+foreign import ccall "unistd.h getpagesize"
+  c_getpagesize :: CInt
+
+pageSize :: Float
+pageSize = fromIntegral c_getpagesize / 1024
+
+showInfo :: String -> String -> Float -> Monitor [String]
+showInfo nm sms mms = do
+  mnw <- getConfigValue maxWidth
+  mxw <- getConfigValue minWidth
+  let lsms = length sms
+      nmw = mnw - lsms - 1
+      nmx = mxw - lsms - 1
+      rnm = if nmw > 0 then padString nmw nmx " " True nm else nm
+  mstr <- showWithColors' sms mms
+  both <- showWithColors' (rnm ++ " " ++ sms) mms
+  return [nm, mstr, both]
+
+processes :: IO [FilePath]
+processes = fmap (filter isPid) (getDirectoryContents "/proc")
+  where isPid = all (`elem` ['0'..'9'])
+
+getProcessData :: FilePath -> IO [String]
+getProcessData pidf =
+  handle (const (return []) :: SomeException -> IO [String])
+         (withFile ("/proc" </> pidf </> "stat") ReadMode readWords)
+  where readWords = fmap words . hGetLine
+
+handleProcesses :: ([String] -> a) -> IO [a]
+handleProcesses f =
+  fmap (foldr (\p ps -> if p == [] then ps else f p : ps) [])
+       (processes >>= mapM getProcessData)
+
+processName :: [String] -> String
+processName = drop 1 . init . (!!1)
+
+sortTop :: [(a, Float)] -> [(a, Float)]
+sortTop =  sortBy (flip (comparing snd))
+
+type Meminfo = (String, Float)
+
+meminfo :: [String] -> Meminfo
+meminfo fs = (processName fs, pageSize * read (fs!!23))
+
+meminfos :: IO [Meminfo]
+meminfos = handleProcesses meminfo
+
+showMeminfo :: Float -> Meminfo -> Monitor [String]
+showMeminfo scale (nm, rss) =
+  showInfo nm (showWithUnits 2 1 rss) (rss / (1024 * scale))
+
+runTopMem :: [String] -> Monitor String
+runTopMem _ = do
+  ps <- io meminfos
+  pstr <- mapM (showMeminfo 1) $ sortTop ps
+  parseTemplate $ concat pstr
+
+type Pid = Int
+type TimeInfo = (String, Float)
+type TimeEntry = (Pid, TimeInfo)
+type Times = IntMap TimeInfo
+type TimesRef = IORef (Times, UTCTime)
+
+timeMemEntry :: [String] -> (TimeEntry, Meminfo)
+timeMemEntry fs = ((p, (n, t)), (n, r))
+  where p = read (head fs)
+        n = processName fs
+        t = read (fs!!13) + read (fs!!14)
+        (_, r) = meminfo fs
+
+timeMemEntries :: IO [(TimeEntry, Meminfo)]
+timeMemEntries = handleProcesses timeMemEntry
+
+timeMemInfos :: IO (Times, [Meminfo], Int)
+timeMemInfos =
+  fmap (\x -> (M.fromList . map fst $ x, map snd x, length x)) timeMemEntries
+
+combineTimeInfos :: Times -> Times -> Times
+combineTimeInfos t0 t1 = M.intersectionWith timeDiff t1 t0
+  where timeDiff (n, x1) (_, x0) = (n, x1 - x0)
+
+topProcesses :: TimesRef -> Float -> IO (Int, [TimeInfo], [Meminfo])
+topProcesses tref scale = do
+  (t1, mis, len) <- timeMemInfos
+  c1 <- getCurrentTime
+  atomicModifyIORef tref $ \(t0, c0) ->
+    let scx = (fromRational . toRational $ diffUTCTime c1 c0) * scale / 100
+        ts = M.elems $ combineTimeInfos t0 t1
+        nts = map (\(nm, t) -> (nm, t / scx)) ts
+    in ((t1, c1), (len, sortTop nts, sortTop mis))
+
+showTimeInfo :: TimeInfo -> Monitor [String]
+showTimeInfo (n, t) = showInfo n (showDigits 1 t) t
+
+runTop :: TimesRef -> Float -> Float -> [String] -> Monitor String
+runTop tref scale mscale _ = do
+  (no, ps, ms) <- io $ topProcesses tref scale
+  pstr <- mapM showTimeInfo ps
+  mstr <- mapM (showMeminfo mscale) ms
+  parseTemplate $! show no : concat (zipWith (++) pstr mstr)
+
+startTop :: [String] -> Int -> (String -> IO ()) -> IO ()
+startTop a r cb = do
+  cr <- getSysVar ClockTick
+  m <- usedMem
+  c <- getCurrentTime
+  tref <- newIORef (M.empty, c)
+  runM a topConfig (runTop tref (fromIntegral cr) m) r cb
diff --git a/Plugins/Monitors/Wireless.hs b/Plugins/Monitors/Wireless.hs
new file mode 100644
--- /dev/null
+++ b/Plugins/Monitors/Wireless.hs
@@ -0,0 +1,34 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Monitors.Wireless
+-- Copyright   :  (c) Jose Antonio Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose Antonio Ortega Ruiz
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- A monitor reporting ESSID and link quality for wireless interfaces
+--
+-----------------------------------------------------------------------------
+
+module Plugins.Monitors.Wireless (wirelessConfig, runWireless)  where
+
+import Plugins.Monitors.Common
+import IWlib
+
+wirelessConfig :: IO MConfig
+wirelessConfig =
+  mkMConfig "<essid> <quality>" ["essid", "quality", "qualitybar"]
+
+runWireless :: [String] -> Monitor String
+runWireless (iface:_) = do
+  wi <- io $ getWirelessInfo iface
+  let essid = wiEssid wi
+      qlty = wiQuality wi
+      fqlty = fromIntegral qlty
+      e = if essid == "" then "N/A" else essid
+  q <- if qlty >= 0 then showWithColors show qlty else showWithPadding ""
+  qb <- showPercentBar fqlty (fqlty / 100)
+  parseTemplate [e, q, qb]
+runWireless _ = return ""
diff --git a/README b/README
--- a/README
+++ b/README
@@ -131,13 +131,18 @@
 :    Default font color.
 
 `position`
-:     Top, TopW, Bottom, BottomW or Static (with x, y, width and height).
+:     Top, TopW, TopSize, Bottom, BottomW, BottomSize or Static (with x, y,
+      width and height).
 
 :     TopW and BottomW take 2 arguments: an alignment parameter (L for
       left, C for centered, R for Right) and an integer for the
       percentage width xmobar window will have in respect to the
       screen width.
 
+:     TopSize and BottomSize take 3 arguments: an alignment parameter, an
+      integer for the percentage width, and an integer for the minimum pixel
+      height that the xmobar window will have.
+
 :     For example:
 
 :          position = BottomW C 75
@@ -258,8 +263,9 @@
 [xmobar] comes with some plugins, providing a set of system monitors,
 a standard input reader, an Unix named pipe reader, and a configurable
 date plugin. These plugins install the following internal commands:
-`Weather`, `Network`, `Memory`, `Swap`, `Cpu`, `Battery`, `Thermal`,
-`CpuFreq`, `CoreTemp`, `Date`, `StdinReader`, `CommandReader`, and `PipeReader`.
+`Weather`, `Network`, `Memory`, `Swap`, `Cpu`, `MultiCpu`, `Battery`,
+`Thermal`, `CpuFreq`, `CoreTemp`, `Date`, `StdinReader`,
+`CommandReader`, and `PipeReader`.
 
 To remove them see below Installing/Removing a Plugin
 
@@ -291,15 +297,29 @@
 - aliases to the interface name: so `Network "eth0" []` can be used as `%eth0%`
 - Args: the argument list (see below)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `dev`, `rx`, `tx`
+	    `dev`, `rx`, `tx`, `rxbar`, `txbar`
 - Default template: `<dev>: <rx>|<tx>`
 
+`Wireless Interface Args RefreshRate`
+
+- aliases to the interface name with the suffix "wi": thus, `Wirelss
+  "wlan0" []` can be used as `%wlan0wi%`
+- Args: the argument list (see below)
+- Variables that can be used with the `-t`/`--template` argument:
+            `essid`, `quality`, `qualitybar`
+- Default template: `<essid> <quality>`
+- Requires the C library libiw (part of the wireless tools suite)
+  installed in your system. In addition, to activate this plugin you
+  must pass --flags="with_iwlib" to "runhaskell Setup configure"
+  or to "cabal install".
+
 `Memory Args RefreshRate`
 
 - aliases to `memory`
 - Args: the argument list (see below)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `total`, `free`, `buffer`, `cache`, `rest`, `used`, `usedratio`
+             `total`, `free`, `buffer`, `cache`, `rest`, `used`,
+             `usedratio`, `usedbar`, `freebar`
 - Default template: `Mem: <usedratio>% (<cache>M)`
 
 `Swap Args RefreshRate`
@@ -315,29 +335,83 @@
 - aliases to `cpu`
 - Args: the argument list (see below)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `total`, `user`, `nice`, `system`, `idle`
+	    `total`, `bar`, `user`, `nice`, `system`, `idle`
 - Default template: `Cpu: <total>`
 
+`MultiCpu Args RefreshRate`
+
+- aliases to `multicpu`
+- Args: the argument list (see below)
+- Variables that can be used with the `-t`/`--template` argument:
+	    `total`, `bar`, `user`, `nice`, `system`, `idle`,
+	    `total0`, `bar0`, `user0`, `nice0`, `system0`, `idle0`, ...
+- Default template: `Cpu: <total>`
+
 `Battery Args RefreshRate`
 
 - aliases to `battery`
 - Args: the argument list (see below)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `left`
+	    `left`, `leftbar`, `status`
 - Default template: `Batt: <left>`
 
 `BatteryP Dirs Args RefreshRate`
 
 - aliases to `battery`
-- Files: list of directories in /proc/acpi/battery/ directory where to
+- Dirs: list of directories in /proc/acpi/battery/ directory where to
   look for the `state` and `info` files. Example:
   `["BAT0","BAT1","BAT2"]`. Only the first 3 directories will be
   searched.
 - Args: the argument list (see below)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `left`
+	    `left`, `leftbar`, `status`
 - Default template: `Batt: <left>`
 
+`TopProc Args RefreshRate`
+
+- aliases to `top`
+- Args: the argument list (see below)
+- Variables that can be used with the `-t`/`--template` argument:
+	    `no`, `name1`, `cpu1`, `both1`, `mname1`, `mem1`, `mboth1`,
+            `name2`, `cpu2`, `both2`, `mname2`, `mem2`, `mboth2`, ...
+- Default template: `<both1>`
+- Displays the name and cpu/mem usage of running processes (`bothn`
+  and `mboth` display both, and is useful to specify an overall
+  maximum and/or minimum width, using the `-m`/`-M` arguments. `no` gives
+  the total number of processes.
+
+`TopMem Args RefreshRate`
+
+- aliases to `topmem`
+- Args: the argument list (see below)
+- Variables that can be used with the `-t`/`--template` argument:
+	    `name1`, `mem1`, `both1`, `name2`, `mem2`, `both2`, ...
+- Default template: `<both1>`
+- Displays the name and RSS (resident memory size) of running
+  processes (`bothn` displays both, and is useful to specify an
+  overall maximum and/or minimum width, using the `-m`/`-M` arguments.
+
+`DiskU Disks Args RefreshRate`
+
+- aliases to `disku`
+- Disks: list of pairs of the form (device or mount point, template),
+  where the template can contain <size>, <free>, <used>, <freep> or
+  <usedp>, <freebar> or <usedbar> for total, free, used, free
+  percentage and used percentage of the given file system capacity. Example:
+  `[("/", "<used>/<size>"), ("sdb1", "<usedbar>")]`
+- Args: the argument list (see above). `-t`/`--template` is ignored.
+- Default template: none (you must specify a template for each file system).
+
+`DiskIO Disks Args RefreshRate`
+
+- aliases to `diskio`
+- Disks: list of pairs of the form (device or mount point, template),
+  where the template can contain <total>, <read>, <write> for total,
+  read and write speed, respectively. Example:
+  `[("/", "<read> <write>"), ("sdb1", "<total>")]`
+- Args: the argument list (see above). `-t`/`--template` is ignored.
+- Default template: none (you must specify a template for each file system).
+
 `Thermal Zone Args RefreshRate`
 
 - aliases to the Zone: so `Zone "THRM" []` can be used in template as `%THRM%`
@@ -369,13 +443,60 @@
 - This monitor requires coretemp module to be loaded in kernel
 - Example: `Run CoreTemp ["-t","Temp:\<core0\>|\<core1\>C","-L","40","-H","60","-l","lightblue","-n","gray90","-h","red"] 50`
 
+
+`MPD Args RefreshRate`
+
+- aliases to `mpd`
+- Args: the argument list (see below). In addition you can provide
+  `-P`, `-S` and `-Z`, with an string argument, to represent the
+  playing, stopped and paused states in the `statei` template field.
+- Variables that can be used with the `-t`/`--template` argument:
+             `bar`, `state`, `statei`, `volume`, `length`
+             `lapsed`, `plength`
+             `name`, `artist`, `composer`, `performer`
+             `album`, `title`, `track`, `file`, `genre`
+- Default template: `MPD: <state>`
+- Example:
+    Run MPD ["-t",
+             "<composer> <title> (<album>) <track>/<plength> <statei> ",
+             "--", "-P", ">>", "-Z", "|", "-S", "><"] 10
+   Note that you need "--" to separate regular monitor options from
+   MPD's specific ones.
+- This monitor will only be compiled if you ask for it using the
+  `with_mpd` flag. It needs libmpd 4.1 or later (available on Hackage).
+
 `Mail Args`
 
 - aliases to `Mail`
 - Args: list of maildirs in form [("name1","path1"),("name2","path2")]
 - This plugin requires INOTIFY support in Linux kernel and hinotify library.
-  To activate, pass --flags="with_inotify" to "runhaskell Setup configure".
+  To activate, pass --flags="with_inotify" to "runhaskell Setup configure"
+  or to "cabal install".
 
+`MBox Mboxes Opts Alias`
+
+- Mboxes a list of mbox files of the form [("name", "path", "color")],
+  where name is the displayed name, path the absolute or relative (to
+  BaseDir) path of the mbox file, and color the color to use to display
+  the mail count (use an empty string for the default).
+- Opts is a possibly empty list of options, as flags. Possible values:
+   -a  --all (no arg)  Show all mailboxes, even if empty.
+   -d dir  --dir dir a string giving the base directory where mbox files with
+                     a relative path live.
+   -p prefix --prefix prefix  a string giving a prefix for the list
+                      of displayed mail coints
+   -s suffix --suffix suffix  a string giving a suffix for the list
+                      of displayed mail coints
+- This plugin requires INOTIFY support in Linux kernel and hinotify library.
+  To activate, pass --flags="with_inotify" to "runhaskell Setup
+  configure" or to "cabal install".
+- Example:
+   `Run MBox [("I ", "inbox", "red"), ("O ", "/foo/mbox", "")]
+             ["-d", "/var/mail/", "-p", " "] "mbox"`
+  will look for mails in `/var/mail/inbox` and `/foo/mbox`, and will put
+  a space in front of the printed string (when it's not empty); it
+  can be used in the template with the alias `mbox`.
+
 ### Monitor Plugins Commands Arguments
 
 These are the arguments that can be used for internal commands in the
@@ -386,6 +507,15 @@
     -h color number     --high=color number         Color for the high threshold: es "#FF0000"
     -n color number     --normal=color number       Color for the normal threshold: es "#00FF00"
     -l color number     --low=color number          Color for the low threshold: es "#0000FF"
+    -p number           --ppad=number               Pad percentages to given width
+    -m number           --minwidth=number           Minimum field width
+    -M number           --maxwidth=number           Maximum field width
+    -w number           --width=number              Fixed field width
+    -c chars            --padchars=chars            Chars used (cyclically) for padding
+    -a ["r" or "l"]     --align=["r" or "l"]        Pad alignment (right/left)
+    -b chars            --bback=chars               Chars used to draw bar backgrounds (default ":")
+    -f chars            --bfore=chars               Chars used to draw bar foregrounds (default "#")
+    -W number           --bwidth=number             Bar width (default 10)
     -t output template  --template=output template  Output template of the command.
 
 Commands' arguments must be set as a list. Es:
diff --git a/StatFS.hsc b/StatFS.hsc
new file mode 100644
--- /dev/null
+++ b/StatFS.hsc
@@ -0,0 +1,70 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  StatFS
+-- Copyright   :  (c) Jose A Ortega Ruiz
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+--  A binding to C's statvfs(2)
+--
+-----------------------------------------------------------------------------
+
+{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}
+
+
+module StatFS ( FileSystemStats(..), getFileSystemStats ) where
+
+import Foreign
+import Foreign.C.Types
+import Foreign.C.String
+import Data.ByteString (useAsCString)
+import Data.ByteString.Char8 (pack)
+
+#include <sys/vfs.h>
+
+data FileSystemStats = FileSystemStats {
+  fsStatBlockSize :: Integer
+  -- ^ Optimal transfer block size.
+  , fsStatBlockCount :: Integer
+  -- ^ Total data blocks in file system.
+  , fsStatByteCount :: Integer
+  -- ^ Total bytes in file system.
+  , fsStatBytesFree :: Integer
+  -- ^ Free bytes in file system.
+  , fsStatBytesAvailable :: Integer
+  -- ^ Free bytes available to non-superusers.
+  , fsStatBytesUsed :: Integer
+  -- ^ Bytes used.
+  } deriving (Show, Eq)
+
+data CStatfs
+
+foreign import ccall unsafe "sys/vfs.h statfs64"
+  c_statfs :: CString -> Ptr CStatfs -> IO CInt
+
+toI :: CLong -> Integer
+toI = toInteger
+
+getFileSystemStats :: String -> IO (Maybe FileSystemStats)
+getFileSystemStats path =
+  allocaBytes (#size struct statfs) $ \vfs ->
+  useAsCString (pack path) $ \cpath -> do
+    res <- c_statfs cpath vfs
+    if res == -1 then return Nothing
+      else do
+        bsize <- (#peek struct statfs, f_bsize) vfs
+        bcount <- (#peek struct statfs, f_blocks) vfs
+        bfree <- (#peek struct statfs, f_bfree) vfs
+        bavail <- (#peek struct statfs, f_bavail) vfs
+        let bpb = toI bsize
+        return $ Just FileSystemStats
+                       { fsStatBlockSize = bpb
+                       , fsStatBlockCount = toI bcount
+                       , fsStatByteCount = toI bcount * bpb
+                       , fsStatBytesFree = toI bfree * bpb
+                       , fsStatBytesAvailable = toI bavail * bpb
+                       , fsStatBytesUsed = toI (bcount - bfree) * bpb
+                       }
diff --git a/Xmobar.hs b/Xmobar.hs
--- a/Xmobar.hs
+++ b/Xmobar.hs
@@ -147,13 +147,11 @@
 setPosition p rs ht =
     case p' of
     Top                -> (Rectangle rx          ry      rw      h     , True)
-    TopW L i           -> (Rectangle rx          ry     (nw i)   h     , True)
-    TopW R i           -> (Rectangle (right  i)  ry     (nw i)   h     , True)
-    TopW C i           -> (Rectangle (center i)  ry     (nw i)   h     , True)
+    TopW a i           -> (Rectangle (ax a i  )  ry     (nw i )  h     , True)
+    TopSize a i ch     -> (Rectangle (ax a i  )  ry     (nw i ) (mh ch), True)
     Bottom             -> (Rectangle rx          ny      rw      h     , True)
-    BottomW L i        -> (Rectangle rx          ny     (nw i)   h     , True)
-    BottomW R i        -> (Rectangle (right  i)  ny     (nw i)   h     , True)
-    BottomW C i        -> (Rectangle (center i)  ny     (nw i)   h     , True)
+    BottomW a i        -> (Rectangle (ax a i  )  ny     (nw i )  h     , True)
+    BottomSize a i ch  -> (Rectangle (ax a i  )  ny     (nw i ) (mh ch), True)
     Static cx cy cw ch -> (Rectangle (fi cx   ) (fi cy) (fi cw) (fi ch), True)
     OnScreen _ p''     -> setPosition p'' [scr] ht
     where
@@ -164,9 +162,13 @@
       center i = rx + (fi $ div (remwid i) 2)
       right  i = rx + (fi $ remwid i)
       remwid i = rw - pw (fi i)
+      ax L     = const rx
+      ax R     = right
+      ax C     = center
       pw i     = rw * (min 100 i) `div` 100
       nw       = fi . pw . fi
       h        = fi ht
+      mh h'    = max (fi h') h
 
       safeIndex i = lookup i . zip [0..]
 
@@ -192,8 +194,10 @@
     OnScreen _ p'   -> getStrutValues r p' rwh
     Top             -> [0, 0, st,  0, 0, 0, 0, 0, nx, nw,  0,  0]
     TopW    _ _     -> [0, 0, st,  0, 0, 0, 0, 0, nx, nw,  0,  0]
+    TopSize      {} -> [0, 0, st,  0, 0, 0, 0, 0, nx, nw,  0,  0]
     Bottom          -> [0, 0,  0, sb, 0, 0, 0, 0,  0,  0, nx, nw]
     BottomW _ _     -> [0, 0,  0, sb, 0, 0, 0, 0,  0,  0, nx, nw]
+    BottomSize   {} -> [0, 0,  0, sb, 0, 0, 0, 0,  0,  0, nx, nw]
     Static _ _ _ _  -> getStaticStrutValues p rwh
     where st = fi y + fi h
           sb = rwh - fi y
diff --git a/xmobar.cabal b/xmobar.cabal
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,11 +1,11 @@
 name:               xmobar
-version:            0.10
+version:            0.11
 homepage:           http://code.haskell.org/~arossato/xmobar
 synopsis:           A Minimalistic Text Based Status Bar
 description: 	    Xmobar is a minimalistic text based status bar.
 		    .
-                    Inspired by the Ion3 status bar, it supports similar features, 
-		    like dynamic color management, output templates, and extensibility 
+                    Inspired by the Ion3 status bar, it supports similar features,
+		    like dynamic color management, output templates, and extensibility
                     through plugins.
 category:           System
 license:            BSD3
@@ -26,25 +26,36 @@
 
 flag with_utf8
   description: With UTF-8 support.
+  default: True
 
 flag with_inotify
   description: inotify support (modern Linux only).  Required for the Mail plugin.
   default: False
 
+flag with_iwlib
+  description: wireless info support. Required for the Wireless plugin, needs iwlib installed.
+  default: False
+
+flag with_mpd
+  description: mpd support. Needs libmpd installed.
+  default: False
+
 executable xmobar
     main-is:            Main.hs
-    other-Modules:      Xmobar, Config, Parsers, Commands, XUtil, Runnable, Plugins
+    other-modules:      Xmobar, Config, Parsers, Commands, XUtil, StatFS, Runnable, Plugins
     ghc-prof-options:   -prof -auto-all
 
     if true
-        ghc-options: -funbox-strict-fields -Wall
+       ghc-options: -funbox-strict-fields -Wall
 
     if impl (ghc == 6.10.1) && arch (x86_64)
-            ghc-options: -O0
+       ghc-options: -O0
 
     if impl (ghc >= 6.12.1)
-            ghc-options: -fno-warn-unused-do-bind
+       ghc-options: -fno-warn-unused-do-bind
 
+    build-depends: X11>=1.3.0, mtl, unix, parsec, filepath, stm, time
+
     if flag(small_base)
        build-depends: base == 4.*, containers, process, old-time, old-locale, bytestring, directory
 
@@ -52,15 +63,22 @@
        build-depends: base < 3
 
     if flag(with_xft)
-        build-depends: utf8-string, X11-xft >= 0.2
-        cpp-options: -DXFT
+       build-depends: utf8-string, X11-xft >= 0.2
+       cpp-options: -DXFT
 
-    if flag(with_utf8) && impl (ghc < 6.12.1)
-        build-depends: utf8-string
-        cpp-options: -DUTF8
+    if flag(with_utf8)
+       build-depends: utf8-string
+       cpp-options: -DUTF8
 
     if flag(with_inotify)
-        build-depends: hinotify
-        cpp-options: -DINOTIFY
+       build-depends: hinotify
+       cpp-options: -DINOTIFY
 
-    build-depends: X11>=1.3.0, mtl, unix, parsec, filepath, stm
+    if flag(with_iwlib)
+       extra-libraries: iw
+       other-modules: IWlib
+       cpp-options: -DIWLIB
+
+    if flag(with_mpd)
+       build-depends: libmpd > 0.4
+       cpp-options: -DLIBMPD
