diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,45 @@
 % xmobar - Release notes
 % Jose A. Ortega Ruiz
 
+## Version 0.14
+
+_New features_
+
+  - New brightness monitor, courtesy of Martin Perner.
+  - New DateZone plugin, for configurable timezone and localized
+    datetimes, also by Martin.
+  - New keyboard layout monitor (Kbd).  Yes, by Martin.
+  - Rewrite of the event handling ([issue 53], [issue 57]), you
+    guessed it.
+  - Cpu monitor now also reports `iowait` field ([issue 55]).
+  - Battery monitor: the full charge file is now settable in the
+    monitor arguments (olpc systems use charge_full_design; see [issue 62]).
+
+_Bug fixes_
+
+  - [issue 45]: Fix for crashes with AC status changes in battery monitor.
+  - [issue 48]: The <quality> field of Wireless behaves like a percentage.
+  - [issue 50]/[issue 61]: `MPD` monitor now works with libmpd 0.6.
+  - [issue 60]: Fixes for crashes on power resume for battery monitor.
+  - Template sections without fields are now correctly displayed.
+  - Catch errors when reading battery status (Ben Boeckel).
+  - Compilation issues with ghc 7.x (Sergei Trofimovich).
+  - Fixes for CoreTemp monitor in new kernels (Norbert Zeh).
+  - Fix for pulseaudio problems in volume monitor (Martin Perner).
+  - Fix for parsing errors when a `Run` entry ended in an array
+    (Martin).
+  - Fixed compilation in OpenBSD (Ivo van der Sangen).
+
+[issue 45]: http://code.google.com/p/xmobar/issues/detail?id=45
+[issue 48]: http://code.google.com/p/xmobar/issues/detail?id=48
+[issue 50]: http://code.google.com/p/xmobar/issues/detail?id=50
+[issue 53]: http://code.google.com/p/xmobar/issues/detail?id=53
+[issue 55]: http://code.google.com/p/xmobar/issues/detail?id=55
+[issue 57]: http://code.google.com/p/xmobar/issues/detail?id=57
+[issue 60]: http://code.google.com/p/xmobar/issues/detail?id=60
+[issue 61]: http://code.google.com/p/xmobar/issues/detail?id=61
+[issue 62]: http://code.google.com/p/xmobar/issues/detail?id=62
+
 ## Version 0.13 (March 28, 2011)
 
 _New features_
@@ -15,6 +54,9 @@
 
 _Incompatible changes_
 
+  - In the process of solving [issue 14], we've broken those
+    configurations that rely on including alignment separators in the
+    input fed to `StdinReader`.
   - The MPD plugin does not accept host and port options anymore: use
     the environment variables MPD_HOST and MPD_PORT instead.
   - The `Mail` plugin now takes a second parameter (a string)
diff --git a/README b/README
--- a/README
+++ b/README
@@ -1,5 +1,4 @@
 % xmobar - A Minimalistic Text Based Status Bar
-% Andrea Rossato, Jose A. Ortega Ruiz
 
 About
 =====
@@ -12,19 +11,27 @@
 features, like dynamic color management, output templates, and
 extensibility through plugins.
 
-This page documents xmobar 0.13 (see [release notes]).
+This page documents xmobar 0.14 (see [release notes]).
 
 [This is a screen shot] of Andrea's desktop with [xmonad] and xmobar.
-[This] is xmobar running under [sawfish], with antialiased fonts. And
-[this one] is my desktop with [xmonad] and two instances of xmobar.
+[This screenshot] shows xmobar running under [sawfish], with
+antialiased fonts. And [this one] is my desktop with [xmonad] and two
+instances of xmobar.
 
 [release notes]: http://projects.haskell.org/xmobar/releases.html
 [xmonad]: http://xmonad.org
 [Ion3]: http://tuomov.iki.fi/software/
-[This is a screen shot]: http://haskell.org/sitewiki/images/a/ae/Arossato-config.png
-[This]: http://projects.haskell.org/xmobar/xmobar-sawfish.png
+[This screenshot]: http://projects.haskell.org/xmobar/xmobar-sawfish.png
 [this one]: http://projects.haskell.org/xmobar/xmobar-xmonad.png
 
+Bug Reports
+===========
+
+To submit bug reports you can use the [bug tracker over at Google
+code] or send mail to our [Mailing list].
+
+[bug tracker over at Google code]: http://code.google.com/p/xmobar/issues
+
 Installation
 ============
 
@@ -46,7 +53,7 @@
 If you don't have `cabal-install` installed, you can get xmobar's
 source code in a variety of ways:
 
-  - From [Hackage]. Just download [xmobar-0.13.tar.gz] from xmobar's
+  - From [Hackage]. Just download [xmobar-0.14.tar.gz] from xmobar's
     hackage page.
   - From [Github]. You can also obtain a tarball in [Github's
     downloads page]. You'll find there links to each tagged release.
@@ -55,13 +62,13 @@
     git:
         git clone git://github.com/jaor/xmobar
 
-[xmobar-0.13.tar.gz]: http://hackage.haskell.org/packages/archive/xmobar/0.13/xmobar-0.13.tar.gz
+[xmobar-0.14.tar.gz]: http://hackage.haskell.org/packages/archive/xmobar/0.14/xmobar-0.14.tar.gz
 [Github's downloads page]: https://github.com/jaor/xmobar/downloads
 
 To install simply run (if needed):
 
-        tar xvfz xmobar-0.13
-        cd xmobar-0.13
+        tar xvfz xmobar-0.14
+        cd xmobar-0.14
 
 If you have cabal installed, you can now use it from within xmobar's
 source tree. Otherwise, run the configure script:
@@ -124,6 +131,10 @@
 :    Support for ALSA sound cards. Enables the Volume plugin. Requires the
      [alsa-mixer] package.
 
+`with_datezone`
+:    Support for other timezones. Enables the DateZone plugin.
+     Requires [timezone-olson] and [timezone-series] package.
+
 `all_extensions`
 :    Enables all the extensions above.
 
@@ -140,6 +151,14 @@
 
 if you have the default configuration file saved as `~/.xmobarrc`
 
+### Signal Handling
+
+Since 0.14 xmobar reacts to SIGUSR1 and SIGUSR2:
+
+- After receiving SIGUSR1 xmobar moves its position to the next screen.
+
+- After receiving SIGUSR2 xmobar repositions it self on the current screen.
+
 Configuration
 =============
 
@@ -225,26 +244,13 @@
 `template`
 :    The output template.
 
-## Running xmobar with i3status
-
-xmobar can be used to display information gathered by [i3status], a
-small program that gathers information and formats it suitable for
-being displayed by the dzen2 status bar, wmii's status bar or xmobar's
-StdinReader.
-
-Since xmobar support has been added only recently you need to get the
-git repository, and build it with the appropriate flags:
-
-    git clone git://code.stapelberg.de/i3status
-
-and then build it:
-
-    cd i3status
-    make EXTRA_CFLAGS="-DXMOBAR
-
-Then you can run it with:
+### Running xmobar with i3status
 
-    ./i3status -c i3status.conf | xmobar -o -t "%StdinReader%" -c "[Run StdinReader]"
+xmobar can be used to display information generated by [i3status], a
+small program that gathers system information and outputs it in
+formats suitable for being displayed by the dzen2 status bar, wmii's
+status bar or xmobar's `StdinReader`.  See [i3status manual] for
+further details.
 
 ## Command Line Options
 
@@ -313,13 +319,8 @@
 The only internal available command is `Com` (see below Executing
 External Commands). All other commands are provided by plugins. 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`, `Wireless` (optional), `Memory`, `Swap`, `Cpu`,
-`MultiCpu`, `Battery`, `TopProc`, `TopMem`, `DiskU`, `DiskIO`,
-`Thermal`, `ThermalZone`, `CpuFreq`, `CoreTemp`, `Volume` (optional),
-`MPD` (optional), `Mail` (optional), `MBox` (optional), `Date`,
-`Uptime`, `StdinReader`, `CommandReader`, and `PipeReader`.
+standard input reader, an Unix named pipe reader, a configurable date
+plugin, and much more: we list all available plugins below.
 
 To remove them see below Installing/Removing a Plugin
 
@@ -403,7 +404,7 @@
 - Aliases to `cpu`
 - Args: default monitor arguments (see below)
 - Variables that can be used with the `-t`/`--template` argument:
-	    `total`, `bar`, `user`, `nice`, `system`, `idle`
+	    `total`, `bar`, `user`, `nice`, `system`, `idle`, `iowait`
 - Default template: `Cpu: <total>%`
 
 `MultiCpu Args RefreshRate`
@@ -441,6 +442,10 @@
     - `-p`: color to display positive power (battery charging)
     - `-f`: file in `/sys/class/power_supply` with AC info (default:
       "AC/online")
+    - `-c`: file in `/sys/class/power/<BAT>/` with full charge
+    information (default: "charge_full"; for instance, olpc systems
+    use "charge_full_design")
+
 - Variables that can be used with the `-t`/`--template` argument:
 	    `left`, `leftbar`, `timeleft`, `watts`, `acstatus`
 - Default template: `Batt: <watts>, <left>% / <timeleft>`
@@ -452,7 +457,8 @@
                        "-L", "10", "-H", "80", "-p", "3",
                        "--", "-O", "<fc=green>On</fc> - ", "-o", "",
                        "-L", "-15", "-H", "-5",
-                       "-l", "red", "-m", "blue", "-h", "green"]
+                       "-l", "red", "-m", "blue", "-h", "green",
+                       "-c", "charge_full_design"]
                       600
   In the above example, the thresholds before the "--" separator
   refer to the `<left>` field, while those after the separator affect
@@ -599,10 +605,12 @@
     - `--lowd` _number_ Low threshold for dB. Defaults to -30.0.
 - Variables that can be used with the `-t`/`--template` argument:
             `volume`, `volumebar`, `dB`, `status`
+- Note that `dB` might only return 0 on your system. This is known
+  to happen on systems with a pulseaudio backend.
 - Default template: `Vol: <volume>% <status>`
-- Requires the package [alsa-mixer] installed in your system. In addition,
-  to activate this plugin you must pass `--flags="with_alsa"` during
-  compilation.
+- Requires the package [alsa-core] and [alsa-mixer] installed in your
+  system. In addition, to activate this plugin you must pass
+  `--flags="with_alsa"` during compilation.
 
 `MPD Args RefreshRate`
 
@@ -679,6 +687,36 @@
 
 [samples/xmonadpropwrite.hs script]: https://github.com/jaor/xmobar/raw/master/samples/xmonadpropwrite.hs
 
+`Brightness Args RefreshRate`
+
+- Aliases to `bright`
+- Args: default monitor arguments (see below), plus the following specif ones:
+    - `-D`: directory in `/sys/class/backlight/` with files in it
+       (default: "acpi_video0")
+    - `-C`: file with the current brightness (default:
+       actual_brightness)
+    - `-M`: file with the maximum brightness (default:
+       max_brigtness)
+- Variables that can be used with the `-t`/`--template` argument:
+	    `hbar`, `percent`, `bar`
+- Default template: `<percent>`
+- Example:
+
+       Run Brightness ["-t", "<bar>"] 60
+
+`Kbd Opts`
+
+- Registers to XKB/X11-Events and output the currently active keyboard layout.
+  Supports replacement of layoutnames.
+- Aliases to `kbd`
+- Opts is a list of tuple:
+    -  first element of the tuple is the search string
+    -  second element of the tuple is the corresponding replacement
+- Example:
+
+		Run Kbd [("us(dvorak)", "DV"), ("us", "US")]
+
+
 ## Monitor Plugins Commands Arguments
 
 These are the arguments that can be used for internal commands in the
@@ -828,6 +866,19 @@
   `strftime` function (or Haskell's `formatCalendarTime`).
 - Sample usage: `Run Date "%a %b %_d %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10`
 
+`DateZone Format Locale Zone Alias RefreshRate`
+
+- Format is a time format string, as accepted by the standard ISO C
+  `strftime` function (or Haskell's `formatCalendarTime`).
+- If Locale is "" the default locale of the system is used, otherwise the given
+  locale. If there are more instances of DateZone, using "" as input for Locale
+  is not recommended.
+- Zone is the name of the TimeZone. It is assumed that the tz database is stored
+  in /usr/share/zoneinfo/. If "" is given as Zone, the default system time is
+  used.
+- Sample usage:
+  `Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10`
+
 `CommandReader "/path/to/program" Alias`
 
 - Runs the given program, and displays its standard output.
@@ -971,23 +1022,15 @@
 
 3. rebuild xmobar.
 
-Bug Reports
-===========
-
-To submit bug reports you can use the [bug tracker over at Google
-code] or send mail to our [Mailing list].
-
-[bug tracker over at Google code]: http://code.google.com/p/xmobar/issues
-
 Credits
 =======
 
 xmobar [incorporates patches] by Ben Boeckel, Roman Cheplyaka, John
 Goerzen, Juraj Hercek, Tomas Janousek, Spencer Janssen, Lennart
-Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Svein Ove, Jens
-Petersen, Petr Rockai, Andrew Sackville-West, Alexander Solovyov,
-Sergei Trofimovich, Thomas Tuegel, Jan Vornberger, Daniel Wagner and
-Norbert Zeh.
+Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Svein Ove,
+Martin Perner, Jens Petersen, Petr Rockai, Andrew Sackville-West,
+Alexander Solovyov, Sergei Trofimovich, Thomas Tuegel, Jan Vornberger,
+Daniel Wagner and Norbert Zeh.
 
 [incorporates patches]: http://www.ohloh.net/p/xmobar/contributors
 
@@ -1011,7 +1054,6 @@
 - [Github page].
 - [Mailing list].
 - [xmobar's Ohloh page].
-- Andrea's original [xmobar] home page, and [xmobar darcs repository].
 
 - To understand the internal mysteries of xmobar you may try reading
   [this tutorial] on X Window Programming in Haskell.
@@ -1020,8 +1062,6 @@
   in [sawfish].
 
 [xmobar's Ohloh page]: https://www.ohloh.net/p/xmobar
-[xmobar]: http://code.haskell.org/~arossato/xmobar/
-[xmobar darcs repository]: http://code.haskell.org/xmobar
 [this tutorial]: http://www.haskell.org/haskellwiki/X_window_programming_in_Haskell
 [sawflibs]: http://github.com/jaor/sawflibs
 
@@ -1049,10 +1089,14 @@
 [Mailing list]: http://projects.haskell.org/cgi-bin/mailman/listinfo/xmobar
 [MPD]: http://mpd.wikia.com/
 [X11-xft]: http://hackage.haskell.org/package/X11-xft/
-[i3status]: http://i3.zekjur.net/i3status/
+[i3status]: http://i3wm.org/i3status/
+[i3status manual]: http://i3wm.org/i3status/manpage.html#_using_i3status_with_xmobar
 [iwlib]: http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
 [hinotify]: http://hackage.haskell.org/package/hinotify/
 [libmpd]: http://hackage.haskell.org/package/libmpd/
 [sawfish]: http://sawfish.wikia.com/
 [utf8-string]: http://hackage.haskell.org/package/utf8-string/
+[alsa-core]: http://hackage.haskell.org/package/alsa-core
 [alsa-mixer]: http://hackage.haskell.org/package/alsa-mixer
+[timezone-olson]: http://hackage.haskell.org/package/timezone-olson
+[timezone-series]: http://hackage.haskell.org/package/timezone-series
diff --git a/src/Commands.hs b/src/Commands.hs
--- a/src/Commands.hs
+++ b/src/Commands.hs
@@ -75,8 +75,7 @@
 -- is not possible to set a thread delay grater than about 45 minutes.
 -- With a little recursion we solve the problem.
 tenthSeconds :: Int -> IO ()
-tenthSeconds s | s >= x = do threadDelay y
-                             tenthSeconds (x - s)
+tenthSeconds s | s >= x = do threadDelay (x * 100000)
+                             tenthSeconds (s - x)
                | otherwise = threadDelay (s * 100000)
-               where y = maxBound :: Int
-                     x = y `div` 100000
+               where x = (maxBound :: Int) `div` 100000
diff --git a/src/Config.hs b/src/Config.hs
--- a/src/Config.hs
+++ b/src/Config.hs
@@ -32,12 +32,17 @@
 import Plugins.StdinReader
 import Plugins.XMonadLog
 import Plugins.EWMH
+import Plugins.Kbd
 
 #ifdef INOTIFY
 import Plugins.Mail
 import Plugins.MBox
 #endif
 
+#ifdef DATEZONE
+import Plugins.DateZone
+#endif
+
 -- $config
 -- Configuration data type and default configuration
 
@@ -108,9 +113,12 @@
 -- the 'Runnable.Runnable' Read instance. To install a plugin just add
 -- the plugin's type to the list of types (separated by ':*:') appearing in
 -- this function's type signature.
-runnableTypes :: Command :*: Monitors :*: Date :*: PipeReader :*: CommandReader :*: StdinReader :*: XMonadLog :*: EWMH :*:
+runnableTypes :: Command :*: Monitors :*: Date :*: PipeReader :*: CommandReader :*: StdinReader :*: XMonadLog :*: EWMH :*: Kbd :*:
 #ifdef INOTIFY
                  Mail :*: MBox :*:
+#endif
+#ifdef DATEZONE
+                 DateZone :*:
 #endif
                  ()
 runnableTypes = undefined
diff --git a/src/Localize.hsc b/src/Localize.hsc
new file mode 100644
--- /dev/null
+++ b/src/Localize.hsc
@@ -0,0 +1,85 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Localize
+-- Copyright   :  (C) 2011 Martin Perner
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Martin Perner <martin@perner.cc>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- This module provides an interface to locale information e.g. for DateL
+--
+-----------------------------------------------------------------------------
+
+module Localize
+    ( setupTimeLocale,
+      getTimeLocale
+    ) where
+
+import Foreign.C
+import qualified System.Locale as L
+
+#ifdef UTF8
+import Codec.Binary.UTF8.String
+#endif
+
+--  get localized strings
+type NlItem = CInt
+
+#include <langinfo.h>
+foreign import ccall unsafe "langinfo.h nl_langinfo"
+  nl_langinfo :: NlItem -> IO CString
+
+#{enum NlItem,
+  , AM_STR , PM_STR \
+  , D_T_FMT , D_FMT , T_FMT , T_FMT_AMPM \
+  , ABDAY_1, ABDAY_7 \
+  , DAY_1, DAY_7 \
+  , ABMON_1, ABMON_12 \
+  , MON_1, MON_12\
+ }
+
+getLangInfo :: NlItem -> IO String
+getLangInfo item = do
+  itemStr <- nl_langinfo item
+#ifdef UTF8
+  str <- peekCString itemStr
+  return $ decodeString str
+#else
+  peekCString itemStr
+#endif
+
+#include <locale.h>
+foreign import ccall unsafe "locale.h setlocale"
+    setlocale :: CInt -> CString -> IO CString
+
+setupTimeLocale :: String -> IO ()
+setupTimeLocale l = withCString l (setlocale #const LC_TIME) >> return ()
+
+getTimeLocale :: IO L.TimeLocale
+getTimeLocale = do
+  -- assumes that the defined values are increasing by exactly one.
+  -- as they are defined consecutive in an enum this is reasonable
+  days   <- mapM getLangInfo [day1 .. day7]
+  abdays <- mapM getLangInfo [abday1 .. abday7]
+
+  mons   <- mapM getLangInfo [mon1 .. mon12]
+  abmons <- mapM getLangInfo [abmon1 .. abmon12]
+
+  amstr <- getLangInfo amStr
+  pmstr <- getLangInfo pmStr
+  dtfmt <- getLangInfo dTFmt
+  dfmt  <- getLangInfo dFmt
+  tfmt  <- getLangInfo tFmt
+  tfmta <- getLangInfo tFmtAmpm
+
+  let t =  L.defaultTimeLocale {L.wDays  = zip days abdays
+                               ,L.months = zip mons abmons
+                               ,L.amPm = (amstr, pmstr)
+                               ,L.dateTimeFmt = dtfmt
+                               ,L.dateFmt = dfmt
+                               ,L.timeFmt = tfmt
+                               ,L.time12Fmt = tfmta}
+  return t
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -41,6 +41,7 @@
 -- | The main entry point
 main :: IO ()
 main = do
+  initThreads
   d   <- openDisplay ""
   args     <- getArgs
   (o,file) <- getOpts args
@@ -51,16 +52,12 @@
   unless (null defaultings) $ putStrLn $ "Fields missing from config defaulted: "
                                             ++ intercalate "," defaultings
 
-  -- listen for ConfigureEvents on the root window, for xrandr support:
-  rootw <- rootWindow d (defaultScreen d)
-  selectInput d rootw structureNotifyMask
-
   conf  <- doOpts c o
   fs    <- initFont d (font conf)
   cls   <- mapM (parseTemplate conf) (splitTemplate conf)
   vars  <- mapM (mapM startCommand) cls
   (r,w) <- createWin d fs conf
-  eventLoop (XConf d r w fs conf) vars
+  startLoop (XConf d r w fs conf) vars
 
 -- | Splits the template in its parts
 splitTemplate :: Config -> [String]
diff --git a/src/Parsers.hs b/src/Parsers.hs
--- a/src/Parsers.hs
+++ b/src/Parsers.hs
@@ -87,7 +87,7 @@
 parseTemplate :: Config -> String -> IO [(Runnable,String,String)]
 parseTemplate c s =
     do str <- case parse (templateParser c) "" s of
-                Left _  -> return [("","","")]
+                Left _  -> return [("", s, "")]
                 Right x -> return x
        let cl = map alias (commands c)
            m  = Map.fromList $ zip cl (commands c)
@@ -159,7 +159,8 @@
                      return ("Static {"  ++ p  ++ "}")
       tillFieldEnd = staticPos <|> many (noneOf ",}\n\r")
 
-      commandsEnd  = wrapSkip (string "]") >> oneOf "},"
+      commandsEnd  = wrapSkip (string "]") >> (string "}" <|> notNextRun)
+      notNextRun = do { string ","; notFollowedBy $ wrapSkip $ string "Run"; return ","} 
       readCommands = manyTill anyChar (try commandsEnd) >>= read' commandsErr . flip (++) "]"
 
       strField e n = field e n . between (strDel "start" n) (strDel "end" n) . many $ noneOf "\"\n\r"
diff --git a/src/Plugins/DateZone.hs b/src/Plugins/DateZone.hs
new file mode 100644
--- /dev/null
+++ b/src/Plugins/DateZone.hs
@@ -0,0 +1,72 @@
+{-# LANGUAGE DoAndIfThenElse #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.DateZone
+-- Copyright   :  (c) Martin Perner
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Martin Perner <martin@perner.cc>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- A date plugin with localization and location support for Xmobar
+--
+-- Based on Plugins.Date
+--
+-- Usage example: in template put
+--
+-- > Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "UTC" "utcDate" 10
+--
+-----------------------------------------------------------------------------
+
+module Plugins.DateZone (DateZone(..)) where
+
+import Plugins
+
+import Localize
+
+import Control.Concurrent.STM
+
+import Data.Time.LocalTime
+import Data.Time.Format
+import Data.Time.LocalTime.TimeZone.Olson
+import Data.Time.LocalTime.TimeZone.Series
+
+import System.IO.Unsafe
+import System.Locale (TimeLocale)
+import System.Time
+
+
+
+{-# NOINLINE localeLock #-}
+-- ensures that only one plugin instance sets the locale
+localeLock :: TMVar Bool
+localeLock = unsafePerformIO (newTMVarIO False)
+
+data DateZone = DateZone String String String String Int
+    deriving (Read, Show)
+
+instance Exec DateZone where
+    alias (DateZone _ _ _ a _) = a
+    start (DateZone f l z _ r) cb = do
+      lock <- atomically $ takeTMVar localeLock
+      setupTimeLocale l
+      locale <- getTimeLocale
+      atomically $ putTMVar localeLock lock
+      if z /= "" then do
+        timeZone <- getTimeZoneSeriesFromOlsonFile ("/usr/share/zoneinfo/" ++ z)
+        go (dateZone f locale timeZone)
+       else
+        go (date f locale)
+
+      where go func = func >>= cb >> tenthSeconds r >> go func
+
+date :: String -> TimeLocale -> IO String
+date format loc = do
+  t <- toCalendarTime =<< getClockTime
+  return $ formatCalendarTime loc format t
+
+dateZone :: String -> TimeLocale -> TimeZoneSeries -> IO String
+dateZone format loc timeZone = do
+  zonedTime <- getZonedTime
+  return $ formatTime loc format $ utcToLocalTime' timeZone $ zonedTimeToUTC zonedTime
diff --git a/src/Plugins/Kbd.hsc b/src/Plugins/Kbd.hsc
new file mode 100644
--- /dev/null
+++ b/src/Plugins/Kbd.hsc
@@ -0,0 +1,397 @@
+{-# LANGUAGE ScopedTypeVariables, ForeignFunctionInterface, MultiParamTypeClasses, DeriveDataTypeable, FlexibleInstances, PatternGuards #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Plugins.Kbd
+-- Copyright   :  (c) Martin Perner
+-- License     :  BSD-style (see LICENSE)
+--
+-- Maintainer  :  Martin Perner <martin@perner.cc>
+-- Stability   :  unstable
+-- Portability :  unportable
+--
+-- A keyboard layout indicator for Xmobar
+--
+-----------------------------------------------------------------------------
+
+module Plugins.Kbd where
+
+import Graphics.X11.Xlib
+import Graphics.X11.Xlib.Extras
+import Foreign
+import Foreign.C.Types (CUInt,CULong,CInt,CUShort,CChar,CUChar)
+import Foreign.C.String
+import Plugins
+import Control.Monad (forever)
+import XUtil (nextEvent')
+import Data.List (isPrefixOf, findIndex)
+import Data.Maybe (fromJust)
+
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKB.h>
+#include <X11/extensions/XKBstr.h>
+
+-- 
+-- Definition for XkbStaceRec and getKbdLayout taken from
+-- XMonad.Layout.XKBLayout
+--
+data XkbStateRec = XkbStateRec {
+    group :: CUChar,
+    locked_group :: CUChar,
+    base_group :: CUShort,
+    latched_group :: CUShort,
+    mods :: CUChar,
+    base_mods :: CUChar,
+    latched_mods :: CUChar,
+    locked_mods :: CUChar,
+    compat_state :: CUChar,
+    grab_mods :: CUChar,
+    compat_grab_mods :: CUChar,
+    lookup_mods :: CUChar,
+    compat_lookup_mods :: CUChar,
+    ptr_buttons :: CUShort
+}
+
+instance Storable XkbStateRec where
+    sizeOf _ = (#size XkbStateRec)
+    alignment _ = alignment (undefined :: CUShort)
+    peek ptr = do
+        r_group <- (#peek XkbStateRec, group) ptr
+        r_locked_group <- (#peek XkbStateRec, locked_group) ptr
+        r_base_group <- (#peek XkbStateRec, base_group) ptr
+        r_latched_group <- (#peek XkbStateRec, latched_group) ptr
+        r_mods <- (#peek XkbStateRec, mods) ptr
+        r_base_mods <- (#peek XkbStateRec, base_mods) ptr
+        r_latched_mods <- (#peek XkbStateRec, latched_mods) ptr
+        r_locked_mods <- (#peek XkbStateRec, locked_mods) ptr
+        r_compat_state <- (#peek XkbStateRec, compat_state) ptr
+        r_grab_mods <- (#peek XkbStateRec, grab_mods) ptr
+        r_compat_grab_mods <- (#peek XkbStateRec, compat_grab_mods) ptr
+        r_lookup_mods <- (#peek XkbStateRec, lookup_mods) ptr
+        r_compat_lookup_mods <- (#peek XkbStateRec, compat_lookup_mods) ptr
+        r_ptr_buttons <- (#peek XkbStateRec, ptr_buttons) ptr
+        return XkbStateRec {
+            group = r_group,
+            locked_group = r_locked_group,
+            base_group = r_base_group,
+            latched_group = r_latched_group,
+            mods = r_mods,
+            base_mods = r_base_mods,
+            latched_mods = r_latched_mods,
+            locked_mods = r_locked_mods,
+            compat_state = r_compat_state,
+            grab_mods = r_grab_mods,
+            compat_grab_mods = r_compat_grab_mods,
+            lookup_mods = r_lookup_mods,
+            compat_lookup_mods = r_compat_lookup_mods,
+            ptr_buttons = r_ptr_buttons
+        }
+
+foreign import ccall unsafe "X11/XKBlib.h XkbGetState"
+    xkbGetState :: Display -> CUInt -> Ptr XkbStateRec -> IO CInt
+
+
+getKbdLayout :: Display -> IO Int
+getKbdLayout d = alloca $ \stRecPtr -> do
+    xkbGetState d 0x100 stRecPtr
+    st <- peek stRecPtr
+    return $ fromIntegral (group st)
+
+--
+--
+--
+
+data XkbKeyNameRec = XkbKeyNameRec {
+	name :: Ptr CChar -- array
+}
+
+--
+-- the t_ before alias is just because of name collisions
+--
+data XkbKeyAliasRec = XkbKeyAliasRec {
+	real  :: Ptr CChar, -- array
+	t_alias :: Ptr CChar  -- array
+} 
+
+--
+-- the t_ before geometry is just because of name collisions
+--
+data XkbNamesRec = XkbNamesRec {
+    keycodes :: Atom,
+    t_geometry :: Atom,
+    symbols :: Atom,
+    types :: Atom,
+    compat :: Atom,
+    vmods :: Ptr Atom,
+    indicators :: Ptr Atom, -- array
+    groups :: Ptr Atom, -- array
+    keys :: Ptr XkbKeyNameRec,
+    key_aliases :: Ptr CChar, -- dont care XkbKeyAliasRec,
+    radio_groups :: Ptr Atom,
+    phys_symbols :: Atom,
+    num_keys :: CUChar,
+    num_key_aliases :: CUChar,
+    num_rg :: CUShort
+}
+
+--
+-- the t_ before map, indicators and compat are just because of name collisions
+--
+data XkbDescRec = XkbDescRec {
+    t_dpy :: Ptr CChar, -- struct _XDisplay* ; don't care
+    flags :: CUShort,
+    device_spec :: CUShort,
+    min_key_code :: KeyCode,
+    max_key_code :: KeyCode,
+    ctrls :: Ptr CChar, -- XkbControlsPtr ;  dont' care
+    server :: Ptr CChar, -- XkbServerMapPtr ;  dont' care
+    t_map :: Ptr CChar, --XkbClientMapPtr ;  dont' care
+    t_indicators :: Ptr CChar, -- XkbIndicatorPtr ;  dont' care
+	names :: Ptr XkbNamesRec, -- array
+    t_compat :: Ptr CChar, -- XkbCompatMap ;  dont' care
+    geom :: Ptr CChar -- XkbGeometryPtr ;  dont' care
+
+}
+
+instance Storable XkbKeyNameRec where
+    sizeOf _ = (#size XkbKeyNameRec)
+    alignment _ = alignment (undefined :: CUShort)
+    peek ptr = do
+        r_name <- (#peek XkbKeyNameRec, name) ptr
+
+        return XkbKeyNameRec {
+            name = r_name
+        }
+
+instance Storable XkbKeyAliasRec where
+    sizeOf _ = (#size XkbKeyAliasRec)
+    alignment _ = alignment (undefined :: CUShort)
+    peek ptr = do
+        r_real <- (#peek XkbKeyAliasRec, real) ptr
+        r_alias <- (#peek XkbKeyAliasRec, alias) ptr
+
+        return XkbKeyAliasRec {
+            real = r_real,
+            t_alias = r_alias
+        }
+
+instance Storable XkbNamesRec where
+    sizeOf _ = (#size XkbNamesRec)
+    alignment _ = alignment (undefined :: CUShort)
+    peek ptr = do
+        r_keycodes <- (#peek XkbNamesRec, keycodes) ptr
+        r_geometry <- (#peek XkbNamesRec, geometry) ptr
+        r_symbols <- (#peek XkbNamesRec, symbols ) ptr
+        r_types <- (#peek XkbNamesRec, types ) ptr
+        r_compat <- (#peek XkbNamesRec, compat ) ptr  
+        r_vmods <- (#peek XkbNamesRec,  vmods ) ptr
+        r_indicators <- (#peek XkbNamesRec, indicators ) ptr  
+        r_groups <- (#peek XkbNamesRec, groups ) ptr 
+        r_keys <- (#peek XkbNamesRec, keys ) ptr   
+        r_key_aliases <- (#peek XkbNamesRec, key_aliases  ) ptr
+        r_radio_groups <- (#peek XkbNamesRec, radio_groups  ) ptr 
+        r_phys_symbols <- (#peek XkbNamesRec, phys_symbols ) ptr  
+        r_num_keys <- (#peek XkbNamesRec,num_keys  ) ptr
+        r_num_key_aliases <- (#peek XkbNamesRec, num_key_aliases  ) ptr
+        r_num_rg <- (#peek XkbNamesRec, num_rg ) ptr
+
+        return XkbNamesRec {
+            keycodes = r_keycodes,
+            t_geometry = r_geometry,
+            symbols = r_symbols,
+            types = r_types,
+            compat = r_compat,
+            vmods = r_vmods,
+            indicators = r_indicators,
+            groups = r_groups,
+            keys = r_keys,
+            key_aliases = r_key_aliases,
+            radio_groups = r_radio_groups,
+            phys_symbols = r_phys_symbols,
+            num_keys = r_num_keys,
+            num_key_aliases = r_num_key_aliases,
+            num_rg = r_num_rg
+       }
+
+instance Storable XkbDescRec where
+    sizeOf _ = (#size XkbDescRec)
+    alignment _ = alignment (undefined :: CUShort)
+    peek ptr = do
+        r_dpy <- (#peek XkbDescRec, dpy) ptr
+        r_flags <- (#peek XkbDescRec, flags) ptr
+        r_device_spec <- (#peek XkbDescRec, device_spec) ptr
+        r_min_key_code <- (#peek XkbDescRec, min_key_code) ptr
+        r_max_key_code <- (#peek XkbDescRec, max_key_code) ptr
+        r_ctrls <- (#peek XkbDescRec, ctrls) ptr
+        r_server <- (#peek XkbDescRec, server) ptr
+        r_map <- (#peek XkbDescRec, map) ptr
+        r_indicators <- (#peek XkbDescRec, indicators) ptr
+        r_names <- (#peek XkbDescRec, names) ptr
+        r_compat <- (#peek XkbDescRec, compat) ptr
+        r_geom <- (#peek XkbDescRec, geom) ptr
+
+        return XkbDescRec {
+            t_dpy = r_dpy,
+            flags = r_flags,
+            device_spec = r_device_spec,
+            min_key_code = r_min_key_code,
+            max_key_code = r_max_key_code,
+            ctrls = r_ctrls,
+            server = r_server,
+            t_map = r_map,
+            t_indicators = r_indicators,
+            names = r_names,
+            t_compat = r_compat,
+            geom = r_geom
+        }
+
+--
+-- C bindings
+--
+
+foreign import ccall unsafe "X11/XKBlib.h XkbAllocKeyboard"
+    xkbAllocKeyboard :: IO (Ptr XkbDescRec)
+
+foreign import ccall unsafe "X11/XKBlib.h XkbGetNames"
+    xkbGetNames :: Display -> CUInt -> (Ptr XkbDescRec)  -> IO Status
+
+foreign import ccall unsafe "X11/XKBlib.h XGetAtomName"
+    xGetAtomName :: Display -> Atom -> IO CString
+
+foreign import ccall unsafe "X11/XKBlib.h XkbFreeNames"
+    xkbFreeNames :: (Ptr XkbDescRec) -> CUInt -> CInt -> IO ()
+
+foreign import ccall unsafe "X11/XKBlib.h XkbFreeKeyboard"
+    xkbFreeKeyboard :: (Ptr XkbDescRec) -> CUInt -> CInt -> IO ()
+
+foreign import ccall unsafe "X11/XKBlib.h XkbSelectEventDetails"
+	xkbSelectEventDetails :: Display -> CUInt -> CUInt -> CULong -> CULong -> IO CUInt
+
+foreign import ccall unsafe "X11/XKBlib.h XkbSelectEvents"
+	xkbSelectEvents :: Display -> CUInt -> CUInt -> CUInt -> IO CUInt
+
+
+xkbUseCoreKbd :: CUInt
+xkbUseCoreKbd = #const XkbUseCoreKbd
+
+xkbStateNotify :: CUInt
+xkbStateNotify = #const XkbStateNotify
+
+xkbMapNotify :: CUInt
+xkbMapNotify = #const XkbMapNotify
+
+xkbMapNotifyMask :: CUInt
+xkbMapNotifyMask = #const XkbMapNotifyMask
+
+xkbNewKeyboardNotifyMask :: CUInt
+xkbNewKeyboardNotifyMask  = #const XkbNewKeyboardNotifyMask
+
+xkbAllStateComponentsMask :: CULong
+xkbAllStateComponentsMask = #const XkbAllStateComponentsMask
+
+xkbGroupStateMask :: CULong
+xkbGroupStateMask = #const XkbGroupStateMask
+
+xkbSymbolsNameMask :: CUInt
+xkbSymbolsNameMask = #const XkbSymbolsNameMask
+
+xkbGroupNamesMask :: CUInt
+xkbGroupNamesMask = #const XkbGroupNamesMask
+
+type KbdOpts = [(String, String)]
+
+-- gets the layout string
+getLayoutStr :: Display -> IO String
+getLayoutStr dpy =  do
+        kbdDescPtr <- xkbAllocKeyboard
+        status <- xkbGetNames dpy xkbSymbolsNameMask kbdDescPtr
+        str <- getLayoutStr' status dpy kbdDescPtr
+        xkbFreeNames kbdDescPtr xkbGroupNamesMask 1
+        xkbFreeKeyboard kbdDescPtr 0 1
+        return str
+
+getLayoutStr' :: Status -> Display -> (Ptr XkbDescRec) -> IO String
+getLayoutStr' st dpy kbdDescPtr =
+        if st == 0 then -- Success
+            do
+            kbdDesc <- peek kbdDescPtr
+            nameArray <- peek (names kbdDesc)
+            atom <- xGetAtomName dpy (symbols nameArray)
+            str <- peekCString atom
+            return str
+        else -- Behaviour on error
+            do
+                return "Error while requesting layout!"
+
+
+-- 'Bad' prefixes of layouts
+noLaySymbols :: [String]
+noLaySymbols = ["group", "inet", "ctr", "pc", "ctrl"]
+
+
+-- splits the layout string into the actual layouts
+splitLayout :: String -> [String]
+splitLayout s = splitLayout' noLaySymbols $ split s '+' 
+
+splitLayout' :: [String] ->  [String] -> [String]
+--                  end of recursion, remove empty strings
+splitLayout' [] s = map (takeWhile (\x -> x /= ':')) $ filter (\x -> length x > 0) s
+--                    remove current string if it has a 'bad' prefix
+splitLayout' bad s  = splitLayout' (tail bad) [x | x <- s, not $ isPrefixOf (head bad) x]
+
+-- split String at each Char
+split :: String -> Char -> [String]
+split [] _ = [""]
+split (c:cs) delim
+    | c == delim = "" : rest
+    | otherwise = (c : head rest) : tail rest
+        where
+            rest = split cs delim
+
+-- replaces input string if on search list (exact match) with corresponding
+-- element on replacement list.
+-- 
+-- if not found, return string unchanged
+searchReplaceLayout :: KbdOpts -> String -> String
+searchReplaceLayout opts s = let c = findIndex (\x -> fst x == s) opts in
+    case c of
+        Nothing -> s
+        x -> let i = (fromJust x) in
+            snd $ opts!!i
+
+-- returns the active layout
+getKbdLay :: Display -> KbdOpts -> IO String
+getKbdLay dpy opts = do
+        lay <- getLayoutStr dpy
+        curLay <- getKbdLayout dpy
+        return $ searchReplaceLayout opts $ (splitLayout lay)!!(curLay)
+
+
+
+data Kbd = Kbd [(String, String)]
+	deriving (Read, Show)
+
+instance Exec Kbd where
+	alias (Kbd _) = "kbd"
+	start (Kbd opts) cb = do
+
+        dpy <- openDisplay ""
+
+        -- initial set of layout
+        cb =<< (getKbdLay dpy opts)
+
+        -- enable listing for
+        -- group changes
+        _ <- xkbSelectEventDetails dpy xkbUseCoreKbd xkbStateNotify xkbAllStateComponentsMask xkbGroupStateMask
+        -- layout/geometry changes
+        _ <- xkbSelectEvents dpy  xkbUseCoreKbd xkbNewKeyboardNotifyMask xkbNewKeyboardNotifyMask
+
+        allocaXEvent $ \e -> forever $ do
+            nextEvent' dpy e
+            _ <- getEvent e
+            cb =<< (getKbdLay dpy opts)
+
+        closeDisplay dpy
+        return ()
+
+-- vim:ft=haskell:ts=4:shiftwidth=4:softtabstop=4:expandtab:foldlevel=20:
+
diff --git a/src/Plugins/Monitors.hs b/src/Plugins/Monitors.hs
--- a/src/Plugins/Monitors.hs
+++ b/src/Plugins/Monitors.hs
@@ -27,6 +27,7 @@
 import Plugins.Monitors.Cpu
 import Plugins.Monitors.MultiCpu
 import Plugins.Monitors.Batt
+import Plugins.Monitors.Bright
 import Plugins.Monitors.Thermal
 import Plugins.Monitors.ThermalZone
 import Plugins.Monitors.CpuFreq
@@ -56,6 +57,7 @@
               | Cpu          Args       Rate
               | MultiCpu     Args       Rate
               | Battery      Args       Rate
+              | Brightness   Args       Rate
               | CpuFreq      Args       Rate
               | CoreTemp     Args       Rate
               | TopProc      Args       Rate
@@ -93,6 +95,7 @@
     alias (MultiCpu _ _) = "multicpu"
     alias (Battery _ _) = "battery"
     alias (BatteryP _ _ _)= "battery"
+    alias (Brightness _ _) = "bright"
     alias (CpuFreq _ _) = "cpufreq"
     alias (TopProc _ _) = "top"
     alias (TopMem _ _) = "topmem"
@@ -122,6 +125,7 @@
     start (Swap a r) = runM a swapConfig runSwap r
     start (Battery a r) = runM a battConfig runBatt r
     start (BatteryP s a r) = runM a battConfig (runBatt' s) r
+    start (Brightness a r) = runM a brightConfig runBright 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
diff --git a/src/Plugins/Monitors/Batt.hs b/src/Plugins/Monitors/Batt.hs
--- a/src/Plugins/Monitors/Batt.hs
+++ b/src/Plugins/Monitors/Batt.hs
@@ -13,11 +13,14 @@
 --
 -----------------------------------------------------------------------------
 
+{-# LANGUAGE BangPatterns #-}
+
 module Plugins.Monitors.Batt ( battConfig, runBatt, runBatt' ) where
 
-import qualified Data.ByteString.Lazy.Char8 as B
+import Control.Exception (SomeException, handle)
 import Plugins.Monitors.Common
 import System.FilePath ((</>))
+import System.IO (IOMode(ReadMode), hGetLine, withFile)
 import System.Posix.Files (fileExist)
 import System.Console.GetOpt
 
@@ -31,6 +34,7 @@
   , lowThreshold :: Float
   , highThreshold :: Float
   , onlineFile :: FilePath
+  , chargeFile :: FilePath
   }
 
 defaultOpts :: BattOpts
@@ -44,6 +48,7 @@
   , lowThreshold = -12
   , highThreshold = -10
   , onlineFile = "AC/online"
+  , chargeFile = "charge_full"
   }
 
 options :: [OptDescr (BattOpts -> BattOpts)]
@@ -57,6 +62,7 @@
   , Option "L" ["lowt"] (ReqArg (\x o -> o { lowThreshold = read x }) "") ""
   , Option "H" ["hight"] (ReqArg (\x o -> o { highThreshold = read x }) "") ""
   , Option "f" ["online"] (ReqArg (\x o -> o { onlineFile = x }) "") ""
+  , Option "c" ["charge"] (ReqArg (\x o -> o { chargeFile = x }) "") ""
   ]
 
 parseOpts :: [String] -> IO BattOpts
@@ -83,35 +89,36 @@
   } | NoFiles
 
 data Battery = Battery
-  { full :: Float
-  , now :: Float
-  , voltage :: Float
-  , current :: Float
+  { full :: !Float
+  , now :: !Float
+  , voltage :: !Float
+  , current :: !Float
   }
 
-batteryFiles :: String -> IO Files
-batteryFiles bat =
-  do is_charge <- fileExist $ prefix </> "charge_now"
-     is_energy <- fileExist $ prefix </> "energy_now"
-     is_current <- fileExist $ prefix </> "current_now"
+safeFileExist :: String -> IO Bool
+safeFileExist f = handle noErrors $ fileExist f
+  where noErrors = const (return False) :: SomeException -> IO Bool
+
+batteryFiles :: String -> String -> IO Files
+batteryFiles charge_file bat =
+  do is_charge <- safeFileExist $ prefix </> "charge_now"
+     is_energy <- safeFileExist $ prefix </> "energy_now"
+     is_current <- safeFileExist $ prefix </> "current_now"
      let cf = if is_current then "current_now" else "power_now"
      return $ case (is_charge, is_energy) of
        (True, _) -> files "charge" cf
        (_, True) -> files "energy" cf
        _ -> NoFiles
   where prefix = sysDir </> bat
-        files ch cf = Files { fFull = prefix </> ch ++ "_full"
+        files ch cf = Files { fFull = prefix </> charge_file
                             , fNow = prefix </> ch ++ "_now"
                             , fCurrent = prefix </> cf
                             , fVoltage = prefix </> "voltage_now" }
 
 haveAc :: FilePath -> IO Bool
-haveAc f = do
-  exists <- fileExist ofile
-  if exists
-    then fmap ((== "1\n") . B.unpack) (B.readFile ofile)
-    else return False
-  where ofile = sysDir </> f
+haveAc f =
+  handle onError $ withFile (sysDir </> f) ReadMode (fmap (== "1") . hGetLine)
+  where onError = const (return False) :: SomeException -> IO Bool
 
 readBattery :: Files -> IO Battery
 readBattery NoFiles = return $ Battery 0 0 0 0
@@ -123,18 +130,21 @@
        return $ Battery (3600 * a / 1000000) -- wattseconds
                         (3600 * b / 1000000) -- wattseconds
                         (c / 1000000) -- volts
-                        (d / c) -- amperes
-    where grab = fmap (read . B.unpack) . B.readFile
+                        (if c > 0 then (d / c) else -1) -- amperes
+    where grab f = handle onError $ withFile f ReadMode (fmap read . hGetLine)
+          onError = const (return (-1)) :: SomeException -> IO Float
 
 readBatteries :: BattOpts -> [Files] -> IO Result
 readBatteries opts bfs =
     do bats <- mapM readBattery (take 3 bfs)
        ac <- haveAc (onlineFile opts)
        let sign = if ac then 1 else -1
-           left = sum (map now bats) / sum (map full bats)
+           ft = sum (map full bats)
+           left = if ft > 0 then sum (map now bats) / ft else 0
            watts = sign * sum (map voltage bats) * sum (map current bats)
            time = if watts == 0 then 0 else sum $ map time' bats
-           time' b = (if ac then full b - now b else now b) / (sign * watts)
+           mwatts = if watts == 0 then 1 else sign * watts
+           time' b = (if ac then full b - now b else now b) / mwatts
            acstr = if ac then onString opts else offString opts
        return $ if isNaN left then NA else Result left watts time acstr
 
@@ -144,26 +154,26 @@
 runBatt' :: [String] -> [String] -> Monitor String
 runBatt' bfs args = do
   opts <- io $ parseOpts args
-  c <- io $ readBatteries opts =<< mapM batteryFiles bfs
+  c <- io $ readBatteries opts =<< mapM (batteryFiles (chargeFile opts)) bfs
   case c of
     Result x w t s ->
       do l <- fmtPercent x
          parseTemplate (l ++ s:[fmtTime $ floor t, fmtWatts w opts])
     NA -> return "N/A"
- where fmtPercent :: Float -> Monitor [String]
-       fmtPercent x = do
-         p <- showPercentWithColors x
-         b <- showPercentBar (100 * x) x
-         return [b, p]
-       fmtWatts x o = color x o $ showDigits 1 x ++ "W"
-       fmtTime :: Integer -> String
-       fmtTime x = hours ++ ":" ++ if length minutes == 2
-                                   then minutes else '0' : minutes
-         where hours = show (x `div` 3600)
-               minutes = show ((x `mod` 3600) `div` 60)
-       maybeColor Nothing _ = ""
-       maybeColor (Just c) str = "<fc=" ++ c ++ ">" ++ str ++ "</fc>"
-       color x o | x >= 0 = maybeColor (posColor o)
-                 | x >= highThreshold o = maybeColor (highWColor o)
-                 | x >= lowThreshold o = maybeColor (mediumWColor o)
-                 | otherwise = maybeColor (lowWColor o)
+  where fmtPercent :: Float -> Monitor [String]
+        fmtPercent x = do
+          p <- showPercentWithColors x
+          b <- showPercentBar (100 * x) x
+          return [b, p]
+        fmtWatts x o = color x o $ showDigits 1 x ++ "W"
+        fmtTime :: Integer -> String
+        fmtTime x = hours ++ ":" ++ if length minutes == 2
+                                    then minutes else '0' : minutes
+          where hours = show (x `div` 3600)
+                minutes = show ((x `mod` 3600) `div` 60)
+        maybeColor Nothing _ = ""
+        maybeColor (Just c) str = "<fc=" ++ c ++ ">" ++ str ++ "</fc>"
+        color x o | x >= 0 = maybeColor (posColor o)
+                  | x >= highThreshold o = maybeColor (highWColor o)
+                  | x >= lowThreshold o = maybeColor (mediumWColor o)
+                  | otherwise = maybeColor (lowWColor o)
diff --git a/src/Plugins/Monitors/Bright.hs b/src/Plugins/Monitors/Bright.hs
new file mode 100644
--- /dev/null
+++ b/src/Plugins/Monitors/Bright.hs
@@ -0,0 +1,118 @@
+-----------------------------------------------------------------------------
+---- |
+---- Module      :  Plugins.Monitors.Birght
+---- Copyright   :  (c) Martin Perner
+---- License     :  BSD-style (see LICENSE)
+----
+---- Maintainer  :  Martin Perner <martin@perner.cc>
+---- Stability   :  unstable
+---- Portability :  unportable
+----
+----  A screen brightness monitor for Xmobar
+----
+-------------------------------------------------------------------------------
+
+module Plugins.Monitors.Bright (brightConfig, runBright) where
+
+import Plugins.Monitors.Common
+import qualified Data.ByteString.Lazy.Char8 as B
+import Data.Char
+import System.FilePath ((</>))
+import System.Posix.Files (fileExist)
+import System.Console.GetOpt
+
+data BrightOpts = BrightOpts
+	{ subDir :: String
+	, currBright :: String
+	, maxBright :: String
+	}
+
+defaultOpts :: BrightOpts
+defaultOpts = BrightOpts
+	{ subDir = "acpi_video0"
+	, currBright = "actual_brightness"
+	, maxBright = "max_brightness"
+	}
+
+options :: [OptDescr (BrightOpts -> BrightOpts)]
+options =
+	[ Option "D" ["device"] (ReqArg (\x o -> o { subDir = x }) "") ""
+	, Option "C" ["curr"] (ReqArg (\x o -> o { currBright = x }) "") ""
+	, Option "M" ["max"] (ReqArg (\x o -> o { maxBright = x }) "") ""
+	]
+
+-- from Batt.hs
+parseOpts :: [String] -> IO BrightOpts
+parseOpts argv =
+	case getOpt Permute options argv of
+		(o, _, []) -> return $ foldr id defaultOpts o
+		(_, _, errs) -> ioError . userError $ concat errs
+
+sysDir :: FilePath
+sysDir = "/sys/class/backlight/"
+
+brightConfig :: IO MConfig
+brightConfig = mkMConfig
+		"<percent>" -- template
+		["hbar", "percent", "bar"] -- replacements
+
+data Files = Files
+	{ fCurr :: String
+	, fMax :: String
+	} | NoFiles
+
+brightFiles :: BrightOpts -> IO Files
+brightFiles opts =
+	do
+		is_curr <- fileExist $ (fCurr files)
+		is_max  <- fileExist $ (fCurr files)
+		if is_curr && is_max
+			then return files
+			else return NoFiles
+	where
+		prefix = sysDir </> (subDir opts)
+		files = Files { fCurr = prefix </> (currBright opts)
+		              , fMax = prefix </> (maxBright opts)
+		              }
+
+
+runBright :: [String] ->  Monitor String
+runBright args = do
+	opts <- io $ parseOpts args
+	f <- io $ brightFiles opts
+	c <- io $ readBright f
+	case f of
+		NoFiles -> return "hurz"
+		_ -> do x <- fmtPercent c
+			parseTemplate (x)
+	where
+		fmtPercent :: Float -> Monitor [String]
+		fmtPercent c = do
+			r <- showHorizontalBar (100 * c)
+			s <- showPercentWithColors c
+			t <- showPercentBar (100 * c) c
+			return [r,s,t]
+
+readBright :: Files -> IO Float
+readBright NoFiles = return 0
+readBright files =
+	do
+		currVal<- grab $ (fCurr files)
+		maxVal <- grab $ (fMax files)
+		return $ (currVal / maxVal) 
+	where
+		grab f = catch (fmap (read . B.unpack) $ B.readFile f)(\_ -> return 0)
+
+
+showHorizontalBar :: Float -> Monitor String
+showHorizontalBar x = do
+	return $ [convert x]
+	where
+		convert :: Float -> Char
+		convert val 
+			| t <= 9600 = ' '
+			| t > 9608 = chr 9608
+			| otherwise = chr t
+			where
+				-- we scale from 0 to 100, we have 8 slots (9 elements), 100/8 = 12
+				t = 9600 + ((round val) `div` 12)
diff --git a/src/Plugins/Monitors/CoreCommon.hs b/src/Plugins/Monitors/CoreCommon.hs
--- a/src/Plugins/Monitors/CoreCommon.hs
+++ b/src/Plugins/Monitors/CoreCommon.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE PatternGuards, CPP #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Plugins.Monitors.CoreCommon
@@ -14,46 +16,128 @@
 
 module Plugins.Monitors.CoreCommon where
 
+import Control.Applicative
+import Control.Monad
+import Data.Char hiding (Space)
+import Data.Function
+import Data.List
+import Data.Maybe
 import Plugins.Monitors.Common
-import System.Posix.Files (fileExist)
-import System.IO (withFile, IOMode(ReadMode), hGetLine)
 import System.Directory
-import Data.Char (isDigit)
-import Data.List (isPrefixOf)
 
--- |
--- 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 :: (Num a, Ord a, Show a) =>
-                        String -> String -> String -> String -> (Double -> a)
-                        -> (a -> String) -> Monitor String
-checkedDataRetrieval failureMessage dir file pattern trans fmt = do
-    exists <- io $ fileExist $ concat [dir, "/", pattern, "0/", file]
-    case exists of
-         False  -> return failureMessage
-         True   -> retrieveData dir file pattern trans fmt
+#ifdef GHC6
+import Control.Monad.Reader
 
--- |
--- 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) -> (a -> String) ->
-                Monitor String
-retrieveData dir file pattern trans fmt = do
-    count <- io $ dirCount dir pattern
-    contents <- io $ mapM getGuts $ files count
-    values <- mapM (showWithColors fmt) $ map conversion contents
-    parseTemplate values
-    where
-        getGuts f = withFile f ReadMode hGetLine
-        dirCount path str = getDirectoryContents path
-                            >>= return . length
-                                       . filter (\s -> str `isPrefixOf` s
-                                                       && isDigit (last s))
-        files count = map (\i -> concat [dir, "/", pattern, show i, "/", file])
-                          [0 .. count - 1]
-        conversion = trans . (read :: String -> Double)
+instance (Monad f, Applicative f) => Applicative (ReaderT r f) where
+    pure a = ReaderT $ const (pure a)
+    f <*> a = ReaderT $ \r -> 
+              ((runReaderT f r) <*> (runReaderT a r))
+#endif
 
+checkedDataRetrieval :: (Ord a, Num a)
+                     => String -> [String] -> Maybe (String, String -> Int)
+                     -> (Double -> a) -> (a -> String) -> Monitor String
+checkedDataRetrieval msg path lbl trans fmt = liftM (maybe msg id) $
+                                              retrieveData path lbl trans fmt
+
+retrieveData :: (Ord a, Num a)
+             => [String] -> Maybe (String, String -> Int)
+             -> (Double -> a) -> (a -> String) -> Monitor (Maybe String)
+retrieveData path lbl trans fmt = do
+  pairs <- map snd . sortBy (compare `on` fst) <$> (mapM readFiles =<< findFiles path lbl)
+  if null pairs
+    then return Nothing
+    else Just <$> (     parseTemplate
+                    =<< mapM (showWithColors fmt . trans . read) pairs
+                  )
+
+-- | Represents the different types of path components
+data Comp = Fix String
+          | Var [String]
+          deriving Show
+
+-- | Used to represent parts of file names separated by slashes and spaces
+data CompOrSep = Slash
+               | Space
+               | Comp String
+               deriving (Eq, Show)
+
+-- | Function to turn a list of of strings into a list of path components
+pathComponents :: [String] -> [Comp]
+pathComponents = joinComps . drop 2 . concat . intersperse [Space] . map splitParts
+  where
+    splitParts p | (l, _:r) <- break (== '/') p = (Comp l):Slash:splitParts r
+                 | otherwise                    = [Comp p]
+
+    joinComps = uncurry joinComps' . partition isComp
+
+    isComp (Comp _) = True
+    isComp _        = False
+
+    fromComp (Comp s) = s
+    fromComp _        = error "fromComp applied to value other than (Comp _)"
+
+    joinComps' cs []     = [Fix $ fromComp $ head cs] -- cs should have only one element here,
+                                                      -- but this keeps the pattern matching
+                                                      -- exhaustive
+    joinComps' cs (p:ps) = let (ss, ps') = span (== p) ps
+                               ct        = if null ps' || (p == Space) then length ss + 1
+                                                                       else length ss
+                               (ls, rs)  = splitAt (ct+1) cs
+                               c         = case p of
+                                             Space -> Var $ map fromComp ls
+                                             Slash -> Fix $ intercalate "/" $ map fromComp ls
+                                             _     -> error "Should not happen"
+                           in  if null ps' then [c]
+                                           else c:joinComps' rs (drop ct ps)
+
+-- | Function to find all files matching the given path and possible label file.
+-- The path must be absolute (start with a leading slash).
+findFiles :: [String] -> Maybe (String, String -> Int)
+          -> Monitor [(String, Either Int (String, String -> Int))]
+findFiles path lbl  =  catMaybes
+                   <$> (     mapM addLabel . zip [0..] . sort
+                         =<< recFindFiles (pathComponents path) "/"
+                       )
+  where
+    addLabel (i, f) = maybe (return $ Just (f, Left i))
+                            (\(s, t) -> justIfExists f s t)
+                            lbl
+
+    justIfExists f s t = let f' = take (length f - length s) f ++ s
+                         in  ifthen (Just (f, Right (f', t))) Nothing <$> (io $ doesFileExist f')
+
+    recFindFiles [] d  =  ifthen [d] []
+                      <$> (io $ if null d then return False else doesFileExist d)
+    recFindFiles ps d  =  ifthen (recFindFiles' ps d) (return [])
+                      =<< (io $ if null d then return True else doesDirectoryExist d)
+
+    recFindFiles' []         _  =  error "Should not happen"
+    recFindFiles' (Fix p:ps) d  =  recFindFiles ps (d ++ "/" ++ p)
+    recFindFiles' (Var p:ps) d  =  concat
+                               <$> (     mapM (recFindFiles ps)
+                                      .  map (\f -> d ++ "/" ++ f)
+                                      .  filter (matchesVar p)
+                                     =<< (io $ getDirectoryContents d)
+                                   )
+
+    matchesVar []     _  = False
+    matchesVar [v]    f  = v == f
+    matchesVar (v:vs) f  = let f'  = drop (length v) f
+                               f'' = dropWhile isDigit f'
+                           in  and [ v `isPrefixOf` f
+                                   , not (null f')
+                                   , isDigit (head f')
+                                   , matchesVar vs f''
+                                   ]
+
+-- | Function to read the contents of the given file(s)
+readFiles :: (String, Either Int (String, String -> Int))
+          -> Monitor (Int, String)
+readFiles (fval, flbl) = (,) <$> either return (\(f, ex) -> liftM ex
+                                                          $ io $ readFile f) flbl
+                             <*> (io $ readFile fval)
+
+-- | Function that captures if-then-else
+ifthen :: a -> a -> Bool -> a
+ifthen thn els cnd = if cnd then thn else els
diff --git a/src/Plugins/Monitors/CoreTemp.hs b/src/Plugins/Monitors/CoreTemp.hs
--- a/src/Plugins/Monitors/CoreTemp.hs
+++ b/src/Plugins/Monitors/CoreTemp.hs
@@ -31,11 +31,9 @@
 -- Function retrieves monitor string holding the core temperature
 -- (or temperatures)
 runCoreTemp :: [String] -> Monitor String
-runCoreTemp _ = do
-    let dir = "/sys/bus/platform/devices"
-        file = "temp1_input"
-        pattern = "coretemp."
-        divisor = 1e3 :: Double
-        failureMessage = "CoreTemp: N/A"
-    checkedDataRetrieval failureMessage dir file pattern (/divisor) show
+runCoreTemp _ = let path = ["/sys/bus/platform/devices/coretemp.", "/temp", "_input"]
+                    lbl  = Just ("_label", read . drop 5)
+                    divisor = 1e3 :: Double
+                    failureMessage = "CoreTemp: N/A"
+                in  checkedDataRetrieval failureMessage path lbl (/divisor) show
 
diff --git a/src/Plugins/Monitors/Cpu.hs b/src/Plugins/Monitors/Cpu.hs
--- a/src/Plugins/Monitors/Cpu.hs
+++ b/src/Plugins/Monitors/Cpu.hs
@@ -22,7 +22,7 @@
 cpuConfig :: IO MConfig
 cpuConfig = mkMConfig
        "Cpu: <total>%"
-       ["bar","total","user","nice","system","idle"]
+       ["bar","total","user","nice","system","idle","iowait"]
 
 type CpuDataRef = IORef [Float]
 
@@ -45,7 +45,7 @@
 formatCpu :: [Float] -> Monitor [String]
 formatCpu [] = return $ replicate 6 ""
 formatCpu xs = do
-  let t = foldr (+) 0 $ take 3 xs
+  let t = sum $ take 3 xs
   b <- showPercentBar (100 * t) t
   ps <- showPercentsWithColors (t:xs)
   return (b:ps)
diff --git a/src/Plugins/Monitors/CpuFreq.hs b/src/Plugins/Monitors/CpuFreq.hs
--- a/src/Plugins/Monitors/CpuFreq.hs
+++ b/src/Plugins/Monitors/CpuFreq.hs
@@ -28,16 +28,12 @@
                                                               -- replacements
 
 -- |
--- Function retrieves monitor string holding the cpu frequency (or
--- frequencies)
+-- Function retrieves monitor string holding the cpu frequency (or frequencies)
 runCpuFreq :: [String] -> Monitor String
-runCpuFreq _ = do
-    let dir = "/sys/devices/system/cpu"
-        file = "cpufreq/scaling_cur_freq"
-        pattern = "cpu"
-        divisor = 1e6 :: Double
-        failureMessage = "CpuFreq: N/A"
-        fmt x | x < 1     = show (round (x * 1000) :: Integer) ++ "MHz"
-              | otherwise = showDigits 1 x ++ "GHz"
-    checkedDataRetrieval failureMessage dir file pattern (/divisor) fmt
+runCpuFreq _ = let path = ["/sys/devices/system/cpu/cpu", "/cpufreq/scaling_cur_freq"]
+                   divisor = 1e6 :: Double
+                   failureMessage = "CpuFreq: N/A"
+                   fmt x | x < 1     = (show (round (x * 1000) :: Integer)) ++ "MHz"
+                         | otherwise = (show x) ++ "GHz"
+               in  checkedDataRetrieval failureMessage path Nothing (/divisor) fmt
 
diff --git a/src/Plugins/Monitors/MPD.hs b/src/Plugins/Monitors/MPD.hs
--- a/src/Plugins/Monitors/MPD.hs
+++ b/src/Plugins/Monitors/MPD.hs
@@ -91,7 +91,7 @@
 parseSong (Right (Just s)) =
   let join [] = ""
       join (x:xs) = foldl (\a o -> a ++ ", " ++ o) x xs
-      str sel = maybe "" join (M.sgGet sel s)
+      str sel = maybe "" join (M.sgGetTag sel s)
       sels = [ M.Name, M.Artist, M.Composer, M.Performer
              , M.Album, M.Title, M.Track, M.Genre ]
       fields = M.sgFilePath s : map str sels
diff --git a/src/Plugins/Monitors/Top.hs b/src/Plugins/Monitors/Top.hs
--- a/src/Plugins/Monitors/Top.hs
+++ b/src/Plugins/Monitors/Top.hs
@@ -13,6 +13,7 @@
 -----------------------------------------------------------------------------
 
 {-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE BangPatterns #-}
 
 module Plugins.Monitors.Top (startTop, topMemConfig, runTopMem) where
 
diff --git a/src/Plugins/Monitors/Volume.hs b/src/Plugins/Monitors/Volume.hs
--- a/src/Plugins/Monitors/Volume.hs
+++ b/src/Plugins/Monitors/Volume.hs
@@ -14,10 +14,12 @@
 
 module Plugins.Monitors.Volume (runVolume, volumeConfig) where
 
+import Prelude hiding ( catch )
 import Control.Monad ( liftM, mplus )
 import Data.Maybe
 import Plugins.Monitors.Common
 import Sound.ALSA.Mixer
+import Sound.ALSA.Exception ( catch )
 import System.Console.GetOpt
 
 volumeConfig :: IO MConfig
@@ -115,7 +117,8 @@
         maybeNA = maybe (return "N/A")
     (lo, hi) <- io $ getRange volumeControl
     val <- io $ getChannel FrontLeft $ value volumeControl
-    db <- io $ getChannel FrontLeft $ dB volumeControl
+    db <- io $ catch (getChannel FrontLeft $ dB volumeControl)
+                     (\_ -> return $ Just 0)
     sw <- io $ getChannel FrontLeft switchControl
     p <- maybeNA (formatVol lo hi) val
     b <- maybeNA (formatVolBar lo hi) val
diff --git a/src/Plugins/Monitors/Wireless.hs b/src/Plugins/Monitors/Wireless.hs
--- a/src/Plugins/Monitors/Wireless.hs
+++ b/src/Plugins/Monitors/Wireless.hs
@@ -25,10 +25,9 @@
 runWireless (iface:_) = do
   wi <- io $ getWirelessInfo iface
   let essid = wiEssid wi
-      qlty = wiQuality wi
-      fqlty = fromIntegral qlty
+      qlty = fromIntegral $ wiQuality wi
       e = if essid == "" then "N/A" else essid
-  q <- if qlty >= 0 then showWithColors show qlty else showWithPadding ""
-  qb <- showPercentBar fqlty (fqlty / 100)
+  q <- if qlty >= 0 then showPercentWithColors (qlty/100) else showWithPadding ""
+  qb <- showPercentBar qlty (qlty / 100)
   parseTemplate [e, q, qb]
 runWireless _ = return ""
diff --git a/src/StatFS.hsc b/src/StatFS.hsc
--- a/src/StatFS.hsc
+++ b/src/StatFS.hsc
@@ -23,7 +23,11 @@
 import Data.ByteString (useAsCString)
 import Data.ByteString.Char8 (pack)
 
-#if defined (__FreeBSD__) || defined (__APPLE__)
+#if  defined (__FreeBSD__) || defined (__OpenBSD__) ||  defined (__APPLE__)
+#define IS_BSD_SYSTEM
+#endif
+
+#ifdef IS_BSD_SYSTEM
 # include <sys/param.h>
 # include <sys/mount.h>
 #else
@@ -47,7 +51,7 @@
 
 data CStatfs
 
-#if defined (__FreeBSD__) || defined (__APPLE__)
+#ifdef IS_BSD_SYSTEM
 foreign import ccall unsafe "sys/mount.h statfs"
 #else
 foreign import ccall unsafe "sys/vfs.h statfs64"
diff --git a/src/XUtil.hsc b/src/XUtil.hsc
--- a/src/XUtil.hsc
+++ b/src/XUtil.hsc
@@ -1,8 +1,8 @@
-{-# OPTIONS -fglasgow-exts #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  XUtil
--- Copyright   :  (C) 2007 Andrea Rossato
+-- Copyright   :  (C) 2007, 2011 Andrea Rossato
 -- License     :  BSD3
 --
 -- Maintainer  :  andrea.rossato@unitn.it
@@ -28,12 +28,15 @@
     , fi
     , withColors
     , DynPixel(..)
+    , xrrSelectInput
+    , xrrQueryExtension
     ) where
 
 import Control.Concurrent
 import Control.Monad.Trans
 import Data.IORef
 import Foreign
+import Foreign.C.Types
 import Graphics.X11.Xlib hiding (textExtents, textWidth)
 import qualified Graphics.X11.Xlib as Xlib (textExtents, textWidth)
 import Graphics.X11.Xlib.Extras
@@ -257,3 +260,12 @@
 setupLocale :: IO ()
 setupLocale = return ()
 #endif
+
+--  XRRSelectInput
+#include <X11/extensions/Xrandr.h>
+foreign import ccall unsafe "X11/extensions/Xrandr.h XRRSelectInput"
+  xrrSelectInput :: Display -> Window -> EventMask -> IO ()
+
+--  XRRQueryExtension
+foreign import ccall unsafe "X11/extensions/Xrandr.h XRRQueryExtension"
+  xrrQueryExtension :: Display -> Ptr CInt -> Ptr CInt -> IO (Bool)
diff --git a/src/Xmobar.hs b/src/Xmobar.hs
--- a/src/Xmobar.hs
+++ b/src/Xmobar.hs
@@ -17,7 +17,7 @@
     ( -- * Main Stuff
       -- $main
       X , XConf (..), runX
-    , eventLoop
+    , startLoop
     -- * Program Execution
     -- $command
     , startCommand
@@ -42,7 +42,9 @@
 import Data.Bits
 import Data.Maybe(fromMaybe)
 import Data.Typeable (Typeable)
+import Foreign
 import System.Posix.Process (getProcessID)
+import System.Posix.Signals
 
 import Config
 import Parsers
@@ -73,46 +75,107 @@
 data WakeUp = WakeUp deriving (Show,Typeable)
 instance Exception WakeUp
 
--- | The event loop
-eventLoop :: XConf -> [[(Maybe ThreadId, TVar String)]] -> IO ()
-eventLoop xc@(XConf d _ w fs c) vs = block $ do
+data SignalType = Wakeup | Reposition | ChangeScreen
+
+-- | Starts the main event loop and threads
+startLoop :: XConf -> [[(Maybe ThreadId, TVar String)]] -> IO ()
+startLoop xcfg@(XConf _ _ w _ _) vs = do
     tv <- atomically $ newTVar []
-    t  <- myThreadId
-    ct <- forkIO (checker t tv [] `catch` \(SomeException _) -> return ())
-    go tv ct
- where
-    -- interrupt the drawing thread every time a var is updated
-    checker t tvar ov = do
+    sig <- setupSignalHandler
+    _ <- forkIO (checker tv [] vs sig `catch` \(SomeException _) -> putStrLn "Thread checker failed" >> return ())
+    _ <- forkOS (eventer sig `catch` \(SomeException _) -> putStrLn "Thread eventer failed" >> return ())
+    eventLoop tv xcfg sig
+  where
+    -- Reacts on events from X
+    eventer signal =
+      alloca $ \ptrEventBase ->
+      alloca $ \ptrErrorBase ->
+      allocaXEvent $ \e -> do
+
+        dpy <- openDisplay ""
+        --  keyPressMask is the same value as RRScreenChangeNotifyMask
+        xrrSelectInput    dpy (defaultRootWindow dpy) keyPressMask
+        selectInput       dpy w (exposureMask .|. structureNotifyMask)
+
+        _ <- xrrQueryExtension dpy ptrEventBase ptrErrorBase
+        xrrEventBase <- peek ptrEventBase
+
+        forever $ do
+          nextEvent dpy e
+          ev <- getEvent e
+          case ev of
+            ConfigureEvent {} -> putMVar signal Reposition
+            ExposeEvent {} -> putMVar signal Wakeup
+            _ ->
+              --  0 is the value of RRScreenChangeNotify
+              when ( (fromIntegral (ev_event_type ev) - xrrEventBase) == 0)
+                   $ putMVar signal Reposition
+
+-- | Send signal to eventLoop every time a var is updated
+checker :: TVar [String] -> [String] -> [[(Maybe ThreadId, TVar String)]] -> MVar SignalType -> IO ()
+checker tvar ov vs signal = do
       nval <- atomically $ do
               nv <- mapM concatV vs
               guard (nv /= ov)
               writeTVar tvar nv
               return nv
-      throwTo t WakeUp
-      checker t tvar nval
+      putMVar signal Wakeup
+      checker tvar nval vs signal
+    where
+      concatV = fmap concat . mapM (readTVar . snd)
 
-    concatV = fmap concat . mapM (readTVar . snd)
 
-    -- Continuously wait for a timer interrupt or an expose event
-    go tv ct = do
-      catch (unblock $ allocaXEvent $ \e ->
-                 handle tv ct =<< (nextEvent' d e >> getEvent e))
-            (\WakeUp -> runX xc (updateWin tv) >> return ())
-      go tv ct
+-- | Continuously wait for a signal from a thread or a interrupt handler
+eventLoop :: TVar [String] -> XConf -> MVar SignalType -> IO ()
+eventLoop tv xc@(XConf d _ w fs cfg) signal = do
+      typ <- takeMVar signal
+      case typ of
+         Wakeup -> do
+            runX xc (updateWin tv)
+            eventLoop tv xc signal
 
-    -- event hanlder
-    handle _ ct (ConfigureEvent {ev_window = win}) = do
-      rootw <- rootWindow d (defaultScreen d)
-      when (win == rootw) $ block $ do
-                      killThread ct
-                      destroyWindow d w
-                      (r',w') <- createWin d fs c
-                      eventLoop (XConf d r' w' fs c) vs
+         Reposition ->
+            reposWindow cfg
 
-    handle tvar _ (ExposeEvent {}) = runX xc (updateWin tvar)
+         ChangeScreen -> do
+            ncfg <- updateConfigPosition cfg
+            reposWindow ncfg
 
-    handle _ _ _  = return ()
+    where
+        reposWindow rcfg = do
+          r' <- repositionWin d w fs rcfg
+          eventLoop tv (XConf d r' w fs rcfg) signal
 
+        updateConfigPosition ocfg =
+          case position ocfg of
+            OnScreen n o -> do
+              srs <- getScreenInfo d
+              if n == length srs then
+                  return (ocfg {position = OnScreen 1 o})
+                else
+                  return (ocfg {position = OnScreen (n+1) o})
+            o ->
+              return (ocfg {position = OnScreen 1 o})
+
+
+-- | Signal handling
+setupSignalHandler :: IO (MVar SignalType)
+setupSignalHandler = do
+   tid   <- newEmptyMVar
+   installHandler sigUSR2 (Catch $ updatePosHandler tid) Nothing
+   installHandler sigUSR1 (Catch $ changeScreenHandler tid) Nothing
+   return tid
+
+updatePosHandler :: MVar SignalType -> IO ()
+updatePosHandler sig = do
+   putMVar sig Reposition
+   return ()
+
+changeScreenHandler :: MVar SignalType -> IO ()
+changeScreenHandler sig = do
+   putMVar sig ChangeScreen
+   return ()
+
 -- $command
 
 -- | Runs a command as an independent thread and returns its thread id
@@ -120,7 +183,7 @@
 startCommand :: (Runnable,String,String) -> IO (Maybe ThreadId, TVar String)
 startCommand (com,s,ss)
     | alias com == "" = do var <- atomically $ newTVar is
-                           atomically $ writeTVar var "Could not parse the template"
+                           atomically $ writeTVar var (s ++ ss)
                            return (Nothing,var)
     | otherwise       = do var <- atomically $ newTVar is
                            let cb str = atomically $ writeTVar var (s ++ str ++ ss)
@@ -140,12 +203,22 @@
   let ht    = as + ds + 4
       (r,o) = setPosition (position c) srs (fi ht)
   win <- newWindow  d (defaultScreenOfDisplay d) rootw r o
-  selectInput       d win (exposureMask .|. structureNotifyMask)
   setProperties r c d win srs
   when (lowerOnStart c) (lowerWindow d win)
   mapWindow         d win
   return (r,win)
 
+-- | Updates the size and position of the window
+repositionWin :: Display -> Window -> XFont -> Config -> IO (Rectangle)
+repositionWin d win fs c = do
+  srs     <- getScreenInfo d
+  (as,ds) <- textExtents fs "0"
+  let ht    = as + ds + 4
+      (r,_) = setPosition (position c) srs (fi ht)
+  moveResizeWindow d win (rect_x r) (rect_y r) (rect_width r) (rect_height r)
+  setProperties r c d win srs
+  return r
+
 setPosition :: XPosition -> [Rectangle] -> Dimension -> (Rectangle,Bool)
 setPosition p rs ht =
   case p' of
@@ -292,7 +365,8 @@
   let (conf,d)             = (config &&& display) r
       Rectangle _ _ wid ht = rect r
       totSLen              = foldr (\(_,_,len) -> (+) len) 0 sl
-      valign               = (fi ht + fi (as + ds)) `div` 2 - 1
+      fntsize              = fi (as + ds)
+      valign               = fi ht - 1 - (fi ht - fntsize) `div` 2
       remWidth             = fi wid - fi totSLen
       offset               = case a of
                                C -> (remWidth + offs) `div` 2
diff --git a/xmobar.cabal b/xmobar.cabal
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,5 +1,5 @@
 name:               xmobar
-version:            0.13
+version:            0.14
 homepage:           http://projects.haskell.org/xmobar/
 bug-reports:        http://code.google.com/p/xmobar/issues
 synopsis:           A Minimalistic Text Based Status Bar
@@ -57,33 +57,45 @@
   description: Use alsa-mixer to get the volume from soundcards.
   default: False
 
+flag with_datezone
+  description: Enables localized date support
+  default: False
+
 executable xmobar
     hs-source-dirs:     src
     main-is:            Main.hs
     other-modules:
-      Xmobar, Config, Parsers, Commands, XUtil, StatFS, Runnable,
+      Xmobar, Config, Parsers, Commands, Localize, XUtil, StatFS, Runnable,
       Plugins, Plugins.CommandReader, Plugins.Date, Plugins.EWMH,
       Plugins.PipeReader, Plugins.StdinReader, Plugins.XMonadLog,
-      Plugins.Utils, Plugins.Monitors, Plugins.Monitors.Batt,
-      Plugins.Monitors.Common, Plugins.Monitors.CoreCommon,
-      Plugins.Monitors.CoreTemp, Plugins.Monitors.CpuFreq,
-      Plugins.Monitors.Cpu, Plugins.Monitors.Disk, Plugins.Monitors.Mem,
+      Plugins.Utils, Plugins.Kbd, Plugins.Monitors,
+      Plugins.Monitors.Batt, Plugins.Monitors.Common,
+      Plugins.Monitors.CoreCommon, Plugins.Monitors.CoreTemp,
+      Plugins.Monitors.CpuFreq, Plugins.Monitors.Cpu,
+      Plugins.Monitors.Disk, Plugins.Monitors.Mem,
       Plugins.Monitors.MultiCpu, Plugins.Monitors.Net,
       Plugins.Monitors.Swap, Plugins.Monitors.Thermal,
       Plugins.Monitors.ThermalZone, Plugins.Monitors.Top,
-      Plugins.Monitors.Uptime, Plugins.Monitors.Weather
+      Plugins.Monitors.Uptime, Plugins.Monitors.Weather,
+      Plugins.Monitors.Bright
 
     ghc-prof-options:   -prof -auto-all
 
     if true
-       ghc-options: -funbox-strict-fields -Wall
+       ghc-options: -funbox-strict-fields -Wall -threaded
+       extra-libraries: Xrandr
 
-    if impl (ghc == 6.10.1) && arch (x86_64)
-       ghc-options: -O0
+    -- Use --disable-optimization configure flag
+    -- if impl (ghc == 6.10.1) && arch (x86_64)
+    --    ghc-options: -O0
 
     if impl (ghc >= 6.12.1)
        ghc-options: -fno-warn-unused-do-bind
 
+    --  for instance declaration in src/Plugins/Monitors/CoreCommon.hs
+    if impl (ghc < 7)
+       cpp-options: -DGHC6
+
     build-depends: X11>=1.3.0, mtl, unix, parsec, filepath, stm, time
 
     if flag(small_base)
@@ -111,11 +123,17 @@
        cpp-options: -DIWLIB
 
     if flag(with_mpd) || flag(all_extensions)
-       build-depends: libmpd >= 0.5
+       build-depends: libmpd >= 0.6
        other-modules: Plugins.Monitors.MPD
        cpp-options: -DLIBMPD
 
     if flag(with_alsa) || flag(all_extensions)
        build-depends: alsa-mixer == 0.1.*
+       build-depends: alsa-core == 0.5.*
        other-modules: Plugins.Monitors.Volume
        cpp-options: -DALSA
+
+    if flag(with_datezone) || flag(all_extensions)
+       build-depends: timezone-olson, timezone-series
+       other-modules: Plugins.DateZone
+       cpp-options: -DDATEZONE
