diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,19 @@
+## Version 0.36 (August, 2020)
+
+_New features_
+
+  - Monitor progress bars: a value of 0 for `-W` denotes an index in
+    the `-f` string, similar to icon patterns but using characters.
+  - New tag `<box>` to add borders around text (Unoqwy).
+  - `fc` color background now accepts an offset (Unoqwy).
+
+_Bug fixes_
+
+  - Documentation fixes (Tomáš Janoušek)
+  - Don't get confused by empty configuration dirs (fixes #412)
+  - Xft rendering: Avoid encoding to UTF8 on all scenarios. This
+    causes issue to StdinReader monitor when the handle wasn't binary.
+
 ## Version 0.35.1 (June, 2020)
 
 - Dropped support for GHC < 8.4 (see issue #461)
diff --git a/license b/license
--- a/license
+++ b/license
@@ -1,4 +1,5 @@
-Copyright (c) Andrea Rossato
+Copyright (c) 2007-2010 Andrea Rossato
+Copyright (c) 2010-2020 Jose A Ortega Ruiz
 
 All rights reserved.
 
diff --git a/readme.md b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -1,6 +1,91 @@
 [![Hackage](https://img.shields.io/hackage/v/xmobar.svg)](http://hackage.haskell.org/package/xmobar)
-[![Build Status](https://travis-ci.org/jaor/xmobar.svg?branch=master)](https://travis-ci.org/jaor/xmobar)
 
+<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
+**Table of Contents**
+
+- [About](#about)
+- [Bug reports](#bug-reports)
+- [Installation](#installation)
+    - [Using cabal-install](#using-cabal-install)
+    - [From source](#from-source)
+    - [Optional features](#optional-features)
+- [Running xmobar](#running-xmobar)
+    - [Signal Handling](#signal-handling)
+- [Configuration](#configuration)
+    - [Quick Start](#quick-start)
+        - [Running xmobar with i3status](#running-xmobar-with-i3status)
+        - [Dynamically sizing xmobar](#dynamically-sizing-xmobar)
+    - [Command Line Options](#command-line-options)
+    - [The Output Template](#the-output-template)
+    - [The `commands` Configuration Option](#the-commands-configuration-option)
+- [System Monitor Plugins](#system-monitor-plugins)
+    - [Icon patterns](#icon-patterns)
+    - [Default Monitor Arguments](#default-monitor-arguments)
+    - [`Uptime Args RefreshRate`](#uptime-args-refreshrate)
+    - [`Weather StationID Args RefreshRate`](#weather-stationid-args-refreshrate)
+    - [`WeatherX StationID SkyConditions Args RefreshRate`](#weatherx-stationid-skyconditions-args-refreshrate)
+    - [`Network Interface Args RefreshRate`](#network-interface-args-refreshrate)
+    - [`DynNetwork Args RefreshRate`](#dynnetwork-args-refreshrate)
+    - [`Wireless Interface Args RefreshRate`](#wireless-interface-args-refreshrate)
+    - [`Memory Args RefreshRate`](#memory-args-refreshrate)
+    - [`Swap Args RefreshRate`](#swap-args-refreshrate)
+    - [`Cpu Args RefreshRate`](#cpu-args-refreshrate)
+    - [`MultiCpu Args RefreshRate`](#multicpu-args-refreshrate)
+    - [`Battery Args RefreshRate`](#battery-args-refreshrate)
+    - [`BatteryP Dirs Args RefreshRate`](#batteryp-dirs-args-refreshrate)
+    - [`BatteryN Dirs Args RefreshRate Alias`](#batteryn-dirs-args-refreshrate-alias)
+    - [`TopProc Args RefreshRate`](#topproc-args-refreshrate)
+    - [`TopMem Args RefreshRate`](#topmem-args-refreshrate)
+    - [`DiskU Disks Args RefreshRate`](#disku-disks-args-refreshrate)
+    - [`DiskIO Disks Args RefreshRate`](#diskio-disks-args-refreshrate)
+    - [`ThermalZone Number Args RefreshRate`](#thermalzone-number-args-refreshrate)
+    - [`Thermal Zone Args RefreshRate`](#thermal-zone-args-refreshrate)
+    - [`CpuFreq Args RefreshRate`](#cpufreq-args-refreshrate)
+    - [`CoreTemp Args RefreshRate`](#coretemp-args-refreshrate)
+    - [`MultiCoreTemp Args RefreshRate`](#multicoretemp-args-refreshrate)
+    - [`Volume Mixer Element Args RefreshRate`](#volume-mixer-element-args-refreshrate)
+    - [`Alsa Mixer Element Args`](#alsa-mixer-element-args)
+    - [`MPD Args RefreshRate`](#mpd-args-refreshrate)
+    - [`Mpris1 PlayerName Args RefreshRate`](#mpris1-playername-args-refreshrate)
+    - [`Mpris2 PlayerName Args RefreshRate`](#mpris2-playername-args-refreshrate)
+    - [`Mail Args Alias`](#mail-args-alias)
+    - [`MailX Args Opts Alias`](#mailx-args-opts-alias)
+    - [`MBox Mboxes Opts Alias`](#mbox-mboxes-opts-alias)
+    - [`XPropertyLog PropName`](#xpropertylog-propname)
+    - [`UnsafeXPropertyLog PropName`](#unsafexpropertylog-propname)
+    - [`NamedXPropertyLog PropName Alias`](#namedxpropertylog-propname-alias)
+    - [`UnsafeNamedXPropertyLog PropName Alias`](#unsafenamedxpropertylog-propname-alias)
+    - [`Brightness Args RefreshRate`](#brightness-args-refreshrate)
+    - [`Kbd Opts`](#kbd-opts)
+    - [`Locks`](#locks)
+    - [`CatInt n filename`](#catint-n-filename)
+    - [`UVMeter`](#uvmeter)
+- [Executing External Commands](#executing-external-commands)
+- [Other Plugins](#other-plugins)
+    - [`StdinReader`](#stdinreader)
+    - [`UnsafeStdinReader`](#unsafestdinreader)
+    - [`Date Format Alias RefreshRate`](#date-format-alias-refreshrate)
+    - [`DateZone Format Locale Zone Alias RefreshRate`](#datezone-format-locale-zone-alias-refreshrate)
+    - [`CommandReader "/path/to/program" Alias`](#commandreader-pathtoprogram-alias)
+    - [`PipeReader "default text:/path/to/pipe" Alias`](#pipereader-default-textpathtopipe-alias)
+    - [`MarqueePipeReader "default text:/path/to/pipe" (length, rate, sep) Alias`](#marqueepipereader-default-textpathtopipe-length-rate-sep-alias)
+    - [`BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]`](#bufferedpipereader-alias-timeout-bool-pathtopipe1-)
+    - [`XMonadLog`](#xmonadlog)
+    - [`UnsafeXMonadLog`](#unsafexmonadlog)
+    - [`HandleReader Handle Alias`](#handlereader-handle-alias)
+- [The DBus Interface](#the-dbus-interface)
+    - [Example for using the DBus IPC interface with XMonad](#example-for-using-the-dbus-ipc-interface-with-xmonad)
+- [User plugins](#user-plugins)
+    - [Writing a Plugin](#writing-a-plugin)
+    - [Using a Plugin](#using-a-plugin)
+    - [Configurations written in pure Haskell](#configurations-written-in-pure-haskell)
+- [Authors and credits](#authors-and-credits)
+    - [Thanks](#thanks)
+- [Related](#related)
+- [License](#license)
+
+<!-- markdown-toc end -->
+
 # About
 
 Xmobar is a minimalistic status bar. It was originally designed and
@@ -23,7 +108,7 @@
 [xmonad]: http://xmonad.org
 [Ion3]: http://tuomov.iki.fi/software/
 
-# Bug Reports
+# Bug reports
 
 To submit bug reports you can use the [bug tracker over at
 Github](https://github.com/jaor/xmobar/issues).
@@ -182,8 +267,35 @@
   may contain markups to change the characters' color.
 
 - `<fc=#FF0000>string</fc>` will print `string` with `#FF0000` color
-  (red).
+  (red). `<fc=#FF0000,#000000>string</fc>` will print `string` in red with
+  a black background (`#000000`). Background absolute offsets can be specified
+  for XFT fonts. `<fc=#FF0000,#000000:0>string</fc>` will have a background
+  matching the bar's height.
 
+- `<box>string</box>` will print string surrounded by a box in the
+  foreground color.  The `box` tag accepts several optional arguments
+  to tailor its looks:
+  - `type`: `Top`, `Bottom`, `VBoth` (a single line above or below
+    string, or both), `Left`, `Right`, `HBoth` (single vertical
+    lines), `Full` (a rectangle, the default).
+  - `color`: the color of the box lines.
+  - `width`: the width of the box lines.
+  - `offset`: an alignment char (L, C or R) followed by the amount of
+    pixels to offset the box lines; the alignment denotes the position
+    of the resulting line, with L/R meaning top/bottom for the
+    vertical lines, and left/right for horizontal ones.
+  - `mt`, `mb`, `ml`, `mr` specify margins to be added at the top,
+    bottom, left and right lines.
+
+  For example, a box underlining its text with a red line of width 2:
+
+           <box type=Bottom width=2 color=red>string</box>
+
+  and if you wanted an underline and an overline with a margin of 2
+  pixels either side:
+
+           <box type=VBoth mt=2 mb=2>string</box>
+
 - `<fn=1>string</fn>` will print `string` with the first font from
   `additionalFonts`.  The index `0` corresponds to the standard font.
 
@@ -393,107 +505,7 @@
 
     Mail bug reports and suggestions to <mail@jao.io>
 
-## The DBus Interface
 
-When compiled with the optional `with_dbus` flag, xmobar can be
-controlled over dbus. All signals defined in [src/Signal.hs] as `data
-SignalType` can now be sent over dbus to xmobar.  Due to current
-limitations of the implementation only one process of xmobar can
-acquire the dbus. This is handled on a first-come-first-served basis,
-meaning that the first process will get the dbus interface. Other
-processes will run without further problems, yet have no dbus
-interface.
-
-[src/Signal.hs]: https://github.com/jaor/xmobar/blob/master/src/Xmobar/System/Signal.hs
-
-- Bus Name: `org.Xmobar.Control`
-- Object Path: `/org/Xmobar/Control`
-- Member Name: Any of SignalType, e.g. `string:Reveal`
-- Interface Name: `org.Xmobar.Control`
-
-An example using the `dbus-send` command line utility:
-
-        dbus-send \
-            --session \
-            --dest=org.Xmobar.Control \
-            --type=method_call \
-            --print-reply \
-            '/org/Xmobar/Control' \
-            org.Xmobar.Control.SendSignal \
-            "string:Toggle 0"
-
-It is also possible to send multiple signals at once:
-
-        # send to another screen, reveal and toggle the persistent flag
-        dbus-send [..] \
-            "string:ChangeScreen 0" "string:Reveal 0" "string:TogglePersistent"
-
-The `Toggle`, `Reveal`, and `Hide` signals take an additional integer
-argument that denotes an initial delay, in tenths of a second, before
-the command takes effect.
-
-### Example for using the DBus IPC interface with XMonad
-
-Bind the key which should {,un}map xmobar to a dummy value. This is necessary
-for {,un}grabKey in xmonad.
-
-    ((0, xK_Alt_L   ), return ())
-
-Also, install `avoidStruts` layout modifier from `XMonad.Hooks.ManageDocks`
-
-Finally, install these two event hooks (`handleEventHook` in `XConfig`)
-`myDocksEventHook` is a replacement for `docksEventHook` which reacts on unmap
-events as well (which `docksEventHook` doesn't).
-
-    import qualified XMonad.Util.ExtensibleState as XS
-
-    data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable)
-
-    instance ExtensionClass DockToggleTime where
-        initialValue = DTT 0
-
-    toggleDocksHook :: Int -> KeySym -> Event -> X All
-    toggleDocksHook to ks ( KeyEvent { ev_event_display = d
-                                     , ev_event_type    = et
-                                     , ev_keycode       = ekc
-                                     , ev_time          = etime
-                                     } ) =
-            io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)
-        where
-        toggleDocks kc
-            | ekc == kc && et == keyPress = do
-                safeSendSignal ["Reveal 0", "TogglePersistent"]
-                XS.put ( DTT etime )
-            | ekc == kc && et == keyRelease = do
-                gap <- XS.gets ( (-) etime . lastTime )
-                safeSendSignal [ "TogglePersistent"
-                               , "Hide " ++ show (if gap < 400 then to else 0)
-                               ]
-            | otherwise = return ()
-
-        safeSendSignal s = catchX (io $ sendSignal s) (return ())
-        sendSignal    = withSession . callSignal
-        withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c
-        callSignal :: [String] -> MethodCall
-        callSignal s = ( methodCall
-                         ( objectPath_    "/org/Xmobar/Control" )
-                         ( interfaceName_ "org.Xmobar.Control"  )
-                         ( memberName_    "SendSignal"          )
-                       ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"
-                         , methodCallBody        = map toVariant s
-                         }
-
-    toggleDocksHook _ _ _ = return (All True)
-
-    myDocksEventHook :: Event -> X All
-    myDocksEventHook e = do
-        when (et == mapNotify || et == unmapNotify) $
-            whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh
-        return (All True)
-        where w  = ev_window e
-              et = ev_event_type e
-
-
 ## The Output Template
 
 The output template must contain at least one command. xmobar will
@@ -558,7 +570,7 @@
 Other commands can be created as plugins with the Plugin
 infrastructure. See below.
 
-## System Monitor Plugins
+# System Monitor Plugins
 
 This is the description of the system monitor plugins available in
 xmobar.  Some of them are only installed when an optional build option
@@ -569,7 +581,7 @@
 monitor in turn, but before we provide a list of the configuration
 options (or *monitor arguments*) they all share.
 
-### Icon patterns
+## Icon patterns
 
 Some monitors allow usage of strings that depend on some integer value
 from 0 to 8 by replacing all occurrences of `"%%"` with it
@@ -587,7 +599,7 @@
 Will display `bright_0.xpm` to `bright_8.xpm` depending on current brightness
 value.
 
-### Default Monitor Arguments
+## Default Monitor Arguments
 
 Monitors accept a common set of arguments, described in the first
 subsection below.  In addition, some monitors accept additional options
@@ -706,6 +718,10 @@
     - Total number of characters used to draw bars.
     - Long option: `--bwidth`
     - Default value: 10
+    - Special value: 0.  When this parameter is 0, the percentage to
+      display is interpreted as a position in the bar foreground
+      string (given by `-f`), and the character at that position is
+      displayed.
 - `-x` _string_ N/A string
     - String to be used when the monitor is not available
     - Long option: `--nastring`
@@ -723,7 +739,7 @@
     Glasgow Airport: 16.0C
 
 
-### `Uptime Args RefreshRate`
+## `Uptime Args RefreshRate`
 
 - Aliases to `uptime`
 - Args: default monitor arguments. The low and high
@@ -734,7 +750,7 @@
   to add units to the display of those numeric fields.
 - Default template: `Up: <days>d <hours>h <minutes>m`
 
-### `Weather StationID Args RefreshRate`
+## `Weather StationID Args RefreshRate`
 
 - Aliases to the Station ID: so `Weather "LIPB" []` can be used in
   template as `%LIPB%`
@@ -757,7 +773,7 @@
 - Default template: `<station>: <tempC>C, rh <rh>% (<hour>)`
 - Retrieves weather information from http://tgftp.nws.noaa.gov.
 
-### `WeatherX StationID SkyConditions Args RefreshRate`
+## `WeatherX StationID SkyConditions Args RefreshRate`
 
 - Works in the same way as `Weather`, but takes an additional
   argument, a list of pairs from sky conditions to their replacement
@@ -790,7 +806,7 @@
 As mentioned, the replacement string can also be an icon
 specification, such as `("clear", "<icon=weather-clear.xbm/>")`.
 
-### `Network Interface Args RefreshRate`
+## `Network Interface Args RefreshRate`
 
 - Aliases to the interface name: so `Network "eth0" []` can be used as
   `%eth0%`
@@ -808,7 +824,7 @@
   Mb/s, etc.).
 - Default template: `<dev>: <rx>KB|<tx>KB`
 
-### `DynNetwork Args RefreshRate`
+## `DynNetwork Args RefreshRate`
 
 - Active interface is detected automatically
 - Aliases to "dynnetwork"
@@ -825,7 +841,7 @@
 - Default template: `<dev>: <rx>KB|<tx>KB`
 - Example of usage of `--devices` option: `["--", "--devices", "wlp2s0,enp0s20f41"]`
 
-### `Wireless Interface Args RefreshRate`
+## `Wireless Interface Args RefreshRate`
 
 - If set to "", first suitable wireless interface is used.
 - Aliases to the interface name with the suffix "wi": thus, `Wireless
@@ -843,7 +859,7 @@
 - To activate this plugin you must pass `--flags="with_nl80211"` or
   `--flags="with_iwlib"` during compilation
 
-### `Memory Args RefreshRate`
+## `Memory Args RefreshRate`
 
 - Aliases to `memory`
 - Args: default monitor arguments, plus:
@@ -858,7 +874,7 @@
              `availableratio`, `availablebar`, `availablevbar`, `availableipat`
 - Default template: `Mem: <usedratio>% (<cache>M)`
 
-### `Swap Args RefreshRate`
+## `Swap Args RefreshRate`
 
 - Aliases to `swap`
 - Args: default monitor arguments
@@ -867,7 +883,7 @@
 	    `total`, `used`, `free`, `usedratio`
 - Default template: `Swap: <usedratio>%`
 
-### `Cpu Args RefreshRate`
+## `Cpu Args RefreshRate`
 
 - Aliases to `cpu`
 - Args: default monitor arguments, plus:
@@ -877,7 +893,7 @@
 	    `total`, `bar`, `vbar`, `ipat`, `user`, `nice`, `system`, `idle`, `iowait`
 - Default template: `Cpu: <total>%`
 
-### `MultiCpu Args RefreshRate`
+## `MultiCpu Args RefreshRate`
 
 - Aliases to `multicpu`
 - Args: default monitor arguments, plus:
@@ -899,11 +915,11 @@
   and display one entry for each.
 - Default template: `Cpu: <total>%`
 
-### `Battery Args RefreshRate`
+## `Battery Args RefreshRate`
 
 - Same as `BatteryP ["BAT", "BAT0", "BAT1", "BAT2"] Args RefreshRate`.
 
-### `BatteryP Dirs Args RefreshRate`
+## `BatteryP Dirs Args RefreshRate`
 
 - Aliases to `battery`
 
@@ -984,13 +1000,13 @@
 - The "idle" AC state is selected whenever the AC power entering the
   battery is zero.
 
-### `BatteryN Dirs Args RefreshRate Alias`
+## `BatteryN Dirs Args RefreshRate Alias`
 
 Works like `BatteryP`, but lets you specify an alias for the monitor
 other than "battery".  Useful in case you one separate monitors for
 more than one battery.
 
-### `TopProc Args RefreshRate`
+## `TopProc Args RefreshRate`
 
 - Aliases to `top`
 - Args: default monitor arguments. The low and high
@@ -1007,7 +1023,7 @@
   maximum and/or minimum width, using the `-m`/`-M` arguments. `no` gives
   the total number of processes.
 
-### `TopMem Args RefreshRate`
+## `TopMem Args RefreshRate`
 
 - Aliases to `topmem`
 - Args: default monitor arguments. The low and high
@@ -1020,7 +1036,7 @@
   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`
+## `DiskU Disks Args RefreshRate`
 
 - Aliases to `disku`
 - Disks: list of pairs of the form (device or mount point, template),
@@ -1039,7 +1055,7 @@
                ["-L", "20", "-H", "50", "-m", "1", "-p", "3"]
                20
 
-### `DiskIO Disks Args RefreshRate`
+## `DiskIO Disks Args RefreshRate`
 
 - Aliases to `diskio`
 - Disks: list of pairs of the form (device or mount point, template),
@@ -1062,7 +1078,7 @@
 
          DiskIO [("/", "<read> <write>"), ("sdb1", "<total>")] [] 10
 
-### `ThermalZone Number Args RefreshRate`
+## `ThermalZone Number Args RefreshRate`
 
 - Aliases to "thermaln": so `ThermalZone 0 []` can be used in template
   as `%thermal0%`
@@ -1079,7 +1095,7 @@
 
          Run ThermalZone 0 ["-t","<id>: <temp>C"] 30
 
-#### `Thermal Zone Args RefreshRate`
+## `Thermal Zone Args RefreshRate`
 
 - **This plugin is deprecated. Use `ThermalZone` instead.**
 
@@ -1096,7 +1112,7 @@
 
          Run Thermal "THRM" ["-t","iwl4965-temp: <temp>C"] 50
 
-### `CpuFreq Args RefreshRate`
+## `CpuFreq Args RefreshRate`
 
 - Aliases to `cpufreq`
 - Args: default monitor arguments
@@ -1110,7 +1126,7 @@
          Run CpuFreq ["-t", "Freq:<cpu0>|<cpu1>GHz", "-L", "0", "-H", "2",
                       "-l", "lightblue", "-n","white", "-h", "red"] 50
 
-### `CoreTemp Args RefreshRate`
+## `CoreTemp Args RefreshRate`
 
 - Aliases to `coretemp`
 - Args: default monitor arguments
@@ -1125,7 +1141,7 @@
                        "-L", "40", "-H", "60",
                        "-l", "lightblue", "-n", "gray90", "-h", "red"] 50
 
-### `MultiCoreTemp Args RefreshRate`
+## `MultiCoreTemp Args RefreshRate`
 
 - Aliases to `multicoretemp`
 - Args: default monitor arguments, plus:
@@ -1162,7 +1178,7 @@
                             "-l", "green", "-n", "yellow", "-h", "red",
                             "--", "--mintemp", "20", "--maxtemp", "100"] 50
 
-### `Volume Mixer Element Args RefreshRate`
+## `Volume Mixer Element Args RefreshRate`
 
 - Aliases to the mixer name and element name separated by a colon. Thus,
   `Volume "default" "Master" [] 10` can be used as `%default:Master%`.
@@ -1215,7 +1231,7 @@
   system. In addition, to activate this plugin you must pass
   `--flags="with_alsa"` during compilation.
 
-### `Alsa Mixer Element Args`
+## `Alsa Mixer Element Args`
 
 Like [Volume](#volume-mixer-element-args-refreshrate), but with the
 following differences:
@@ -1234,7 +1250,7 @@
 - `stdbuf` (from coreutils) must be (and most probably already is) in
   your `PATH`.
 
-### `MPD Args RefreshRate`
+## `MPD Args RefreshRate`
 
 - This monitor will only be compiled if you ask for it using the
   `with_mpd` flag. It needs [libmpd] 5.0 or later (available on Hackage).
@@ -1262,7 +1278,7 @@
                   "<composer> <title> (<album>) <track>/<plength> <statei> [<flags>]",
                   "--", "-P", ">>", "-Z", "|", "-S", "><"] 10
 
-### `Mpris1 PlayerName Args RefreshRate`
+## `Mpris1 PlayerName Args RefreshRate`
 
 - Aliases to `mpris1`
 - Requires [dbus] and [text] packages.
@@ -1278,7 +1294,7 @@
 
          Run Mpris1 "clementine" ["-t", "<artist> - [<tracknumber>] <title>"] 10
 
-### `Mpris2 PlayerName Args RefreshRate`
+## `Mpris2 PlayerName Args RefreshRate`
 
 - Aliases to `mpris2`
 - Requires [dbus] and [text] packages.
@@ -1295,7 +1311,7 @@
 
          Run Mpris2 "spotify" ["-t", "<artist> - [<composer>] <title>"] 10
 
-### `Mail Args Alias`
+## `Mail Args Alias`
 
 - Args: list of maildirs in form
   `[("name1","path1"),...]`. Paths may start with a '~'
@@ -1309,7 +1325,7 @@
                    ("lists", "~/var/mail/lists")]
                   "mail"
 
-### `MailX Args Opts Alias`
+## `MailX Args Opts Alias`
 
 - Args: list of maildirs in form
   `[("name1","path1","color1"),...]`. Paths may start with a '~'
@@ -1333,7 +1349,7 @@
                    "mail"
 
 
-### `MBox Mboxes Opts Alias`
+## `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
@@ -1360,7 +1376,7 @@
          Run MBox [("I ", "inbox", "red"), ("O ", "~/foo/mbox", "")]
                   ["-d", "/var/mail/", "-p", " "] "mbox"
 
-### `XPropertyLog PropName`
+## `XPropertyLog PropName`
 
 - Aliases to `PropName`
 - Reads the X property named by `PropName` (a string) and displays its
@@ -1370,7 +1386,7 @@
 
 [examples/xmonadpropwrite.hs script]: https://github.com/jaor/xmobar/raw/master/examples/xmonadpropwrite.hs
 
-### `UnsafeXPropertyLog PropName`
+## `UnsafeXPropertyLog PropName`
 
 - Aliases to `PropName`
 - Same as `XPropertyLog`, but the input is not filtered to avoid
@@ -1378,17 +1394,17 @@
   the value of the read property is responsible of performing any
   needed cleanups.
 
-### `NamedXPropertyLog PropName Alias`
+## `NamedXPropertyLog PropName Alias`
 
 - Aliases to `Alias`
 - Same as `XPropertyLog`, but a custom alias can be specified.
 
-### `NamedXPropertyLog PropName Alias`
+## `UnsafeNamedXPropertyLog PropName Alias`
 
 - Aliases to `Alias`
 - Same as `UnsafeXPropertyLog`, but a custom alias can be specified.
 
-### `Brightness Args RefreshRate`
+## `Brightness Args RefreshRate`
 
 - Aliases to `bright`
 - Args: default monitor arguments, plus the following specif ones:
@@ -1406,7 +1422,7 @@
 
        Run Brightness ["-t", "<bar>"] 60
 
-### `Kbd Opts`
+## `Kbd Opts`
 
 - Registers to XKB/X11-Events and output the currently active keyboard layout.
   Supports replacement of layout names.
@@ -1418,7 +1434,7 @@
 
 		Run Kbd [("us(dvorak)", "DV"), ("us", "US")]
 
-### `Locks`
+## `Locks`
 
 - Displays the status of Caps Lock, Num Lock and Scroll Lock.
 - Aliases to `locks`
@@ -1426,7 +1442,7 @@
 
 	Run Locks
 
-### `CatInt n filename`
+## `CatInt n filename`
 
 - Reads and displays an integer from the file whose path is `filename`
   (especially useful with files in `/sys`).
@@ -1436,7 +1452,7 @@
 
     Run CatInt 0 "/sys/devices/platform/thinkpad_hwmon/fan1_input" [] 50
 
-### `UVMeter`
+## `UVMeter`
 
 - Aliases to "uv " + station id. For example: `%uv Brisbane%` or `%uv
   Alice Springs%`
@@ -1455,7 +1471,7 @@
 
         Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900
 
-## Executing External Commands
+# Executing External Commands
 
 In order to execute an external command you can either write the
 command name in the template, in this case it will be executed without
@@ -1496,9 +1512,9 @@
 
 will display "N/A" if for some reason the `date` invocation fails.
 
-## Other Plugins
+# Other Plugins
 
-### `StdinReader`
+## `StdinReader`
 
 - Aliases to StdinReader
 - Displays any text received by xmobar on its standard input.
@@ -1506,27 +1522,26 @@
   actions via stdin.  This is safer than `UnsafeStdinReader` because there is
   no need to escape the content before passing it to xmobar's standard input.
 
-### `UnsafeStdinReader`
+## `UnsafeStdinReader`
 
 - Aliases to UnsafeStdinReader
 - Displays any text received by xmobar on its standard input.
 - Will not do anything to the text received.  This means you can pass dynamic
-  actions via stdin.  Be careful to remove tags from dynamic text that you
-  pipe-thru to xmobar's standard input, e.g. window's title.  There is no way
-  to escape the tags, i.e. you can't print a literal `<action>` tag as a text
-  on xmobar.
+  actions via stdin.  Be careful to escape (using `<raw=…>`) or remove tags
+  from dynamic text that you pipe-thru to xmobar's standard input, e.g.
+  window's title.
 - Sample usage: send to xmobar's stdin the list of your workspaces enclosed by
   actions tags that switches the workspaces to be able to switch workspaces by
   clicking on xmobar:
   ```<action=`xdotool key alt+1`>ws1</action> <action=`xdotool key alt+1`>ws2</action>```
 
-### `Date Format Alias RefreshRate`
+## `Date Format Alias RefreshRate`
 
 - Format is a time format string, as accepted by the standard ISO C
   `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`
+## `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`).
@@ -1539,17 +1554,17 @@
 - Sample usage:
   `Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10`
 
-### `CommandReader "/path/to/program" Alias`
+## `CommandReader "/path/to/program" Alias`
 
 - Runs the given program, and displays its standard output.
 
-### `PipeReader "default text:/path/to/pipe" Alias`
+## `PipeReader "default text:/path/to/pipe" Alias`
 
 - Reads its displayed output from the given pipe.
 - Prefix an optional default text separated by a colon
 - Expands environment variables in the first argument of syntax '${VAR}' or '$VAR'
 
-### `MarqueePipeReader "default text:/path/to/pipe" (length, rate, sep) Alias`
+## `MarqueePipeReader "default text:/path/to/pipe" (length, rate, sep) Alias`
 
 - Generally equivalent to PipeReader
 - Text is displayed as marquee with the specified length, rate in 10th
@@ -1559,7 +1574,7 @@
 
 - Expands environment variables in the first argument
 
-### `BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]`
+## `BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]`
 
 - Display data from multiple pipes.
 - Timeout (in tenth of seconds) is the value after which the previous
@@ -1591,7 +1606,7 @@
 [examples/status.sh]: http://github.com/jaor/xmobar/raw/master/examples/status.sh
 
 
-### `XMonadLog`
+## `XMonadLog`
 
 - Aliases to XMonadLog
 - Displays information from xmonad's `_XMONAD_LOG`. You can set this
@@ -1609,7 +1624,7 @@
 
 [here]: http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Hooks-DynamicLog.html
 
-### `UnsafeXMonadLog`
+## `UnsafeXMonadLog`
 
 - Aliases to UnsafeXMonadLog
 - Similar to StdinReader versus UnsafeStdinReader, this does not strip `<action
@@ -1622,7 +1637,7 @@
           logHook = dynamicLogString myPP >>= xmonadPropLog
         }
 
-### `HandleReader Handle Alias`
+## `HandleReader Handle Alias`
 
 - Display data from a Haskell `Handle`
 - This plugin is only useful if you are running xmobar from another Haskell
@@ -1638,9 +1653,108 @@
                 }
         hPutStr writeHandle "Hello World"
 
+# The DBus Interface
 
-# Plugins
+When compiled with the optional `with_dbus` flag, xmobar can be
+controlled over dbus. All signals defined in [src/Signal.hs] as `data
+SignalType` can now be sent over dbus to xmobar.  Due to current
+limitations of the implementation only one process of xmobar can
+acquire the dbus. This is handled on a first-come-first-served basis,
+meaning that the first process will get the dbus interface. Other
+processes will run without further problems, yet have no dbus
+interface.
 
+[src/Signal.hs]: https://github.com/jaor/xmobar/blob/master/src/Xmobar/System/Signal.hs
+
+- Bus Name: `org.Xmobar.Control`
+- Object Path: `/org/Xmobar/Control`
+- Member Name: Any of SignalType, e.g. `string:Reveal`
+- Interface Name: `org.Xmobar.Control`
+
+An example using the `dbus-send` command line utility:
+
+        dbus-send \
+            --session \
+            --dest=org.Xmobar.Control \
+            --type=method_call \
+            --print-reply \
+            '/org/Xmobar/Control' \
+            org.Xmobar.Control.SendSignal \
+            "string:Toggle 0"
+
+It is also possible to send multiple signals at once:
+
+        # send to another screen, reveal and toggle the persistent flag
+        dbus-send [..] \
+            "string:ChangeScreen 0" "string:Reveal 0" "string:TogglePersistent"
+
+The `Toggle`, `Reveal`, and `Hide` signals take an additional integer
+argument that denotes an initial delay, in tenths of a second, before
+the command takes effect.
+
+## Example for using the DBus IPC interface with XMonad
+
+Bind the key which should {,un}map xmobar to a dummy value. This is necessary
+for {,un}grabKey in xmonad.
+
+    ((0, xK_Alt_L   ), return ())
+
+Also, install `avoidStruts` layout modifier from `XMonad.Hooks.ManageDocks`
+
+Finally, install these two event hooks (`handleEventHook` in `XConfig`)
+`myDocksEventHook` is a replacement for `docksEventHook` which reacts on unmap
+events as well (which `docksEventHook` doesn't).
+
+    import qualified XMonad.Util.ExtensibleState as XS
+
+    data DockToggleTime = DTT { lastTime :: Time } deriving (Eq, Show, Typeable)
+
+    instance ExtensionClass DockToggleTime where
+        initialValue = DTT 0
+
+    toggleDocksHook :: Int -> KeySym -> Event -> X All
+    toggleDocksHook to ks ( KeyEvent { ev_event_display = d
+                                     , ev_event_type    = et
+                                     , ev_keycode       = ekc
+                                     , ev_time          = etime
+                                     } ) =
+            io (keysymToKeycode d ks) >>= toggleDocks >> return (All True)
+        where
+        toggleDocks kc
+            | ekc == kc && et == keyPress = do
+                safeSendSignal ["Reveal 0", "TogglePersistent"]
+                XS.put ( DTT etime )
+            | ekc == kc && et == keyRelease = do
+                gap <- XS.gets ( (-) etime . lastTime )
+                safeSendSignal [ "TogglePersistent"
+                               , "Hide " ++ show (if gap < 400 then to else 0)
+                               ]
+            | otherwise = return ()
+
+        safeSendSignal s = catchX (io $ sendSignal s) (return ())
+        sendSignal    = withSession . callSignal
+        withSession mc = connectSession >>= \c -> callNoReply c mc >> disconnect c
+        callSignal :: [String] -> MethodCall
+        callSignal s = ( methodCall
+                         ( objectPath_    "/org/Xmobar/Control" )
+                         ( interfaceName_ "org.Xmobar.Control"  )
+                         ( memberName_    "SendSignal"          )
+                       ) { methodCallDestination = Just $ busName_ "org.Xmobar.Control"
+                         , methodCallBody        = map toVariant s
+                         }
+
+    toggleDocksHook _ _ _ = return (All True)
+
+    myDocksEventHook :: Event -> X All
+    myDocksEventHook e = do
+        when (et == mapNotify || et == unmapNotify) $
+            whenX ((not `fmap` (isClient w)) <&&> runQuery checkDock w) refresh
+        return (All True)
+        where w  = ev_window e
+              et = ev_event_type e
+
+# User plugins
+
 ## Writing a Plugin
 
 Writing a plugin for xmobar should be very simple. You need to create
@@ -1767,7 +1881,7 @@
 
 # License
 
-This software is released under a BSD-style license. See [LICENSE] for
+This software is released under a BSD-style license. See [license] for
 more details.
 
 Copyright &copy; 2010-2020 Jose Antonio Ortega Ruiz
diff --git a/src/Xmobar/App/Config.hs b/src/Xmobar/App/Config.hs
--- a/src/Xmobar/App/Config.hs
+++ b/src/Xmobar/App/Config.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.Config.Defaults
--- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -17,11 +17,10 @@
 
 
 module Xmobar.App.Config (defaultConfig,
-                          xmobarConfigDir,
                           xmobarDataDir,
                           xmobarConfigFile) where
 
-import Control.Monad (when)
+import Control.Monad (when, filterM)
 
 import System.Environment
 import System.Directory
@@ -66,29 +65,6 @@
            , verbose = False
            }
 
--- | Return the path to the xmobar configuration directory.  This
--- directory is where user configuration files are stored (e.g, the
--- xmobar.hs file).  You may also create a @lib@ subdirectory in the
--- configuration directory and the default recompile command will add
--- it to the GHC include path.
---
--- Several directories are considered.  In order of
--- preference:
---
---   1. The directory specified in the @XMOBAR_CONFIG_DIR@ environment variable.
---   2. The @~\/.xmobar@ directory.
---   3. The @XDG_CONFIG_HOME/xmobar@ directory.
---
--- The first directory that exists will be used.  If none of the
--- directories exist then (1) will be used if it is set, otherwise (2)
--- will be used.
-xmobarConfigDir :: IO String
-xmobarConfigDir =
-    findFirstDirWithEnv False "XMOBAR_CONFIG_DIR"
-      [ getAppUserDataDirectory "xmobar"
-      , getXdgDirectory XdgConfig "xmobar"
-      ]
-
 -- | Return the path to the xmobar data directory.  This directory is
 -- used by Xmobar to store data files such as the run-time state file
 -- and the configuration binary generated by GHC.
@@ -140,11 +116,21 @@
       Nothing -> findFirstDirOf create paths
       Just envPath -> findFirstDirOf create (return envPath:paths)
 
+xmobarInConfigDirs :: FilePath -> IO (Maybe FilePath)
+xmobarInConfigDirs fn  = do
+    env <- lookupEnv "XMOBAR_CONFIG_DIR"
+    xdg <- getXdgDirectory XdgConfig "xmobar"
+    app <- getAppUserDataDirectory "xmobar"
+    hom <- getHomeDirectory
+    let candidates = case env of
+                       Nothing -> [app, xdg, hom]
+                       Just p -> [p, app, xdg, hom]
+    fs <- filterM (\d -> fileExist (d </> fn)) candidates
+    return $ if null fs then Nothing else Just (head fs </> fn)
+
 xmobarConfigFile :: IO (Maybe FilePath)
 xmobarConfigFile =
-  ffirst [ xdg "xmobar.hs", xdg "xmobarrc", home ".xmobarrc"]
-  where xdg p = fmap (</> p) xmobarConfigDir
-        home p = fmap (</> p) getHomeDirectory
-        ffirst [] = return Nothing
-        ffirst (f:fs) =
-          f >>= fileExist >>= \e -> if e then fmap Just f else ffirst fs
+  fmap ffirst $ mapM xmobarInConfigDirs ["xmobar.hs", ".xmobarrc", "xmobarrc"]
+  where ffirst [] = Nothing
+        ffirst (Nothing:fs) = ffirst fs
+        ffirst (p:_) = p
diff --git a/src/Xmobar/App/EventLoop.hs b/src/Xmobar/App/EventLoop.hs
--- a/src/Xmobar/App/EventLoop.hs
+++ b/src/Xmobar/App/EventLoop.hs
@@ -3,7 +3,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.X11.EventLoop
--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -31,7 +31,6 @@
 import Graphics.X11.Xrandr
 
 import Control.Arrow ((&&&))
-import Control.Applicative ((<$>))
 import Control.Monad.Reader
 import Control.Concurrent
 import Control.Concurrent.Async (Async, async)
@@ -251,17 +250,17 @@
     where is = s ++ "Updating..." ++ ss
 
 updateString :: Config -> TVar [String]
-                -> IO [[(Widget, String, Int, Maybe [Action])]]
+                -> IO [[(Widget, TextRenderInfo, Int, Maybe [Action])]]
 updateString conf v = do
   s <- readTVarIO v
   let l:c:r:_ = s ++ repeat ""
   liftIO $ mapM (parseString conf) [l, c, r]
 
-updateActions :: XConf -> Rectangle -> [[(Widget, String, Int, Maybe [Action])]]
+updateActions :: XConf -> Rectangle -> [[(Widget, TextRenderInfo, Int, Maybe [Action])]]
                  -> IO [([Action], Position, Position)]
 updateActions conf (Rectangle _ _ wid _) ~[left,center,right] = do
   let (d,fs) = (display &&& fontListS) conf
-      strLn :: [(Widget, String, Int, Maybe [Action])] -> IO [(Maybe [Action], Position, Position)]
+      strLn :: [(Widget, TextRenderInfo, Int, Maybe [Action])] -> IO [(Maybe [Action], Position, Position)]
       strLn  = liftIO . mapM getCoords
       iconW i = maybe 0 Bitmap.width (lookup i $ iconS conf)
       getCoords (Text s,_,i,a) = textWidth d (safeIndex fs i) s >>= \tw -> return (a, 0, fi tw)
diff --git a/src/Xmobar/App/Main.hs b/src/Xmobar/App/Main.hs
--- a/src/Xmobar/App/Main.hs
+++ b/src/Xmobar/App/Main.hs
@@ -1,7 +1,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.App.Main
--- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -26,8 +26,7 @@
 import Data.List (intercalate)
 import System.Posix.Process (executeFile)
 import System.Environment (getArgs)
-import System.FilePath
-import System.FilePath.Posix (takeBaseName, takeDirectory)
+import System.FilePath ((</>), takeBaseName, takeDirectory, takeExtension)
 import Text.Parsec.Error (ParseError)
 import Data.List.NonEmpty (NonEmpty(..))
 
diff --git a/src/Xmobar/Plugins/MarqueePipeReader.hs b/src/Xmobar/Plugins/MarqueePipeReader.hs
--- a/src/Xmobar/Plugins/MarqueePipeReader.hs
+++ b/src/Xmobar/Plugins/MarqueePipeReader.hs
@@ -22,7 +22,6 @@
 import Control.Concurrent.STM (TChan, atomically, writeTChan, tryReadTChan, newTChan)
 import Control.Exception
 import Control.Monad(forever, unless)
-import Control.Applicative ((<$>))
 
 type Length = Int       -- length of the text to display
 type Rate = Int         -- delay in tenth seconds
diff --git a/src/Xmobar/Plugins/Monitors/Bright.hs b/src/Xmobar/Plugins/Monitors/Bright.hs
--- a/src/Xmobar/Plugins/Monitors/Bright.hs
+++ b/src/Xmobar/Plugins/Monitors/Bright.hs
@@ -14,7 +14,6 @@
 
 module Xmobar.Plugins.Monitors.Bright (brightConfig, runBright) where
 
-import Control.Applicative ((<$>))
 import Control.Exception (SomeException, handle)
 import qualified Data.ByteString.Lazy.Char8 as B
 import System.FilePath ((</>))
@@ -89,4 +88,3 @@
   return (currVal / maxVal)
   where grab f = handle handler (read . B.unpack <$> B.readFile f)
         handler = const (return 0) :: SomeException -> IO Float
-
diff --git a/src/Xmobar/Plugins/Monitors/Common/Output.hs b/src/Xmobar/Plugins/Monitors/Common/Output.hs
--- a/src/Xmobar/Plugins/Monitors/Common/Output.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Output.hs
@@ -3,7 +3,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.Plugins.Monitors.Strings
--- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -221,9 +221,12 @@
   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)
+  let c = bw < 1
+      w = if c then length bf else bw
+      len = min w $ round (fromIntegral w * x)
+      bfs = if c then [bf !! max 0 (len - 1)] else take len $ cycle bf
+  s <- colorizeString v bfs
+  return $ s ++ if c then "" else take (bw - len) (cycle bb)
 
 showIconPattern :: Maybe IconPattern -> Float -> Monitor String
 showIconPattern Nothing _ = return ""
diff --git a/src/Xmobar/Plugins/Monitors/Common/Parsers.hs b/src/Xmobar/Plugins/Monitors/Common/Parsers.hs
--- a/src/Xmobar/Plugins/Monitors/Common/Parsers.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Parsers.hs
@@ -4,7 +4,7 @@
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.Plugins.Monitors.Parsers
--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -36,7 +36,6 @@
 
 import Xmobar.Plugins.Monitors.Common.Types
 
-import Control.Applicative ((<$>))
 import qualified Data.Map as Map
 import System.Console.GetOpt (ArgOrder(Permute), OptDescr, getOpt)
 import Text.ParserCombinators.Parsec
diff --git a/src/Xmobar/Plugins/Monitors/Mpris.hs b/src/Xmobar/Plugins/Monitors/Mpris.hs
--- a/src/Xmobar/Plugins/Monitors/Mpris.hs
+++ b/src/Xmobar/Plugins/Monitors/Mpris.hs
@@ -28,7 +28,8 @@
 import Control.Arrow ((***))
 import Data.Maybe ( fromJust )
 import Data.Int ( Int32, Int64 )
-import System.IO.Unsafe (unsafePerformIO)
+import Data.Word ( Word32 )
+import System.IO.Unsafe ( unsafePerformIO )
 
 import Control.Exception (try)
 
@@ -127,21 +128,25 @@
                            where hh = (n `div` 60) `div` 60
                                  mm = (n `div` 60) `mod` 60
                                  ss = n `mod` 60
+            pInt str v = let num = fromVar v in
+                           case str of
+                             "mtime" -> formatTime (num `div` 1000)
+                             "tracknumber" -> printf "%02d" num
+                             "mpris:length" -> formatTime (num `div` 1000000)
+                             "xesam:trackNumber" -> printf "%02d" num
+                             _ -> (show::Int32 -> String) num
+            pw32 v = printf "%02d" (fromVar v::Word32)
+            plen str v = let num = fromVar v in
+                           case str of
+                             "mpris:length" -> formatTime (num `div` 1000000)
+                             _ -> (show::Int64 -> String) num
             getStr str = case lookup str md of
                 Nothing -> ""
                 Just v -> case variantType v of
                             TypeString -> fromVar v
-                            TypeInt32 -> let num = fromVar v in
-                                          case str of
-                                           "mtime" -> formatTime (num `div` 1000)
-                                           "tracknumber" -> printf "%02d" num
-                                           "mpris:length" -> formatTime (num `div` 1000000)
-                                           "xesam:trackNumber" -> printf "%02d" num
-                                           _ -> (show::Int32 -> String) num
-                            TypeInt64 -> let num = fromVar v in
-                                          case str of
-                                           "mpris:length" -> formatTime (num `div` 1000000)
-                                           _ -> (show::Int64 -> String) num
+                            TypeInt32 -> pInt str v
+                            TypeWord32 -> pw32 v
+                            TypeInt64 -> plen str v
                             TypeArray TypeString ->
                               let x = arrayItems (fromVar v) in
                                 if null x then "" else fromVar (head x)
diff --git a/src/Xmobar/Plugins/Monitors/MultiCpu.hs b/src/Xmobar/Plugins/Monitors/MultiCpu.hs
--- a/src/Xmobar/Plugins/Monitors/MultiCpu.hs
+++ b/src/Xmobar/Plugins/Monitors/MultiCpu.hs
@@ -15,7 +15,6 @@
 module Xmobar.Plugins.Monitors.MultiCpu (startMultiCpu) where
 
 import Xmobar.Plugins.Monitors.Common
-import Control.Applicative ((<$>))
 import qualified Data.ByteString.Lazy.Char8 as B
 import Data.List (isPrefixOf, transpose, unfoldr)
 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
diff --git a/src/Xmobar/Plugins/Monitors/Net.hs b/src/Xmobar/Plugins/Monitors/Net.hs
--- a/src/Xmobar/Plugins/Monitors/Net.hs
+++ b/src/Xmobar/Plugins/Monitors/Net.hs
@@ -23,7 +23,6 @@
 import Xmobar.Plugins.Monitors.Common
 
 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
-import Data.Monoid ((<>))
 import Data.Time.Clock (UTCTime, getCurrentTime, diffUTCTime)
 import Data.Word (Word64)
 import Control.Monad (forM, filterM)
diff --git a/src/Xmobar/Plugins/Monitors/Volume.hs b/src/Xmobar/Plugins/Monitors/Volume.hs
--- a/src/Xmobar/Plugins/Monitors/Volume.hs
+++ b/src/Xmobar/Plugins/Monitors/Volume.hs
@@ -21,9 +21,8 @@
   , VolumeOpts
   ) where
 
-import Control.Applicative ( (<$>), liftA3 )
+import Control.Applicative ( liftA3 )
 import Control.Monad ( liftM2, liftM3, mplus )
-import Data.Traversable (sequenceA)
 import Xmobar.Plugins.Monitors.Common
 import Sound.ALSA.Mixer
 import qualified Sound.ALSA.Exception as AE
@@ -229,21 +228,23 @@
     liftMonitor Nothing = unavailable
     liftMonitor (Just m) = m
 
-    channel' v r = AE.catch (getChannel FrontLeft v) (const $ return $ Just r)
+    channel' :: PerChannel a -> IO (Maybe a)
+    channel' v = AE.catch (getChannel FrontLeft v) (const (return Nothing))
 
-    channel v r = channel' v r >>= \x -> return (x >>= Just . toInteger)
+    channel :: PerChannel CLong -> IO (Maybe Integer)
+    channel v = fmap (fmap toInteger) (channel' v)
 
     getDB :: Maybe Volume -> IO (Maybe Integer)
     getDB Nothing = return Nothing
-    getDB (Just v) = channel (dB v) 0
+    getDB (Just v) = channel (dB v)
 
     getVal :: Maybe Volume -> IO (Maybe Integer)
     getVal Nothing = return Nothing
-    getVal (Just v) = channel (value v) 0
+    getVal (Just v) = channel (value v)
 
     getSw :: Maybe Switch -> IO (Maybe Bool)
     getSw Nothing = return Nothing
-    getSw (Just s) = channel' s False
+    getSw (Just s) = channel' s
 
     getFormatDB :: VolumeOpts -> Maybe Integer -> Monitor String
     getFormatDB _ Nothing = unavailable
diff --git a/src/Xmobar/Plugins/PipeReader.hs b/src/Xmobar/Plugins/PipeReader.hs
--- a/src/Xmobar/Plugins/PipeReader.hs
+++ b/src/Xmobar/Plugins/PipeReader.hs
@@ -21,7 +21,6 @@
 import Control.Concurrent(threadDelay)
 import Control.Exception
 import Control.Monad(forever, unless)
-import Control.Applicative ((<$>))
 
 data PipeReader = PipeReader String String
     deriving (Read, Show)
diff --git a/src/Xmobar/System/Environment.hs b/src/Xmobar/System/Environment.hs
--- a/src/Xmobar/System/Environment.hs
+++ b/src/Xmobar/System/Environment.hs
@@ -13,7 +13,6 @@
 -----------------------------------------------------------------------------
 module Xmobar.System.Environment(expandEnv) where
 
-import Control.Applicative  ((<$>))
 import Data.Maybe (fromMaybe)
 import System.Environment   (lookupEnv)
 
diff --git a/src/Xmobar/X11/Bitmap.hs b/src/Xmobar/X11/Bitmap.hs
--- a/src/Xmobar/X11/Bitmap.hs
+++ b/src/Xmobar/X11/Bitmap.hs
@@ -24,7 +24,7 @@
 import System.FilePath ((</>))
 import System.Mem.Weak ( addFinalizer )
 import Xmobar.X11.ColorCache
-import Xmobar.X11.Parsers (Widget(..))
+import Xmobar.X11.Parsers (TextRenderInfo(..), Widget(..))
 import Xmobar.X11.Actions (Action)
 
 #ifdef XPM
@@ -54,7 +54,7 @@
                      }
 
 updateCache :: Display -> Window -> Map FilePath Bitmap -> FilePath ->
-               [[(Widget, String, Int, Maybe [Action])]] -> IO (Map FilePath Bitmap)
+               [[(Widget, TextRenderInfo, Int, Maybe [Action])]] -> IO (Map FilePath Bitmap)
 updateCache dpy win cache iconRoot ps = do
   let paths = map (\(Icon p, _, _, _) -> p) . concatMap (filter icons) $ ps
       icons (Icon _, _, _, _) = True
diff --git a/src/Xmobar/X11/Draw.hs b/src/Xmobar/X11/Draw.hs
--- a/src/Xmobar/X11/Draw.hs
+++ b/src/Xmobar/X11/Draw.hs
@@ -1,9 +1,10 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE TupleSections #-}
 
 ------------------------------------------------------------------------------
 -- |
 -- Module: Xmobar.X11.Draw
--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz
 -- License: BSD3-style (see LICENSE)
 --
 -- Maintainer: jao@gnu.org
@@ -22,9 +23,9 @@
 import Prelude hiding (lookup)
 import Control.Monad.IO.Class
 import Control.Monad.Reader
-import Control.Monad (when)
 import Control.Arrow ((&&&))
-import Data.Map hiding (foldr, map, filter)
+import Data.Map hiding ((\\), foldr, map, filter)
+import Data.List ((\\))
 import qualified Data.List.NonEmpty as NE
 
 import Graphics.X11.Xlib hiding (textExtents, textWidth)
@@ -37,7 +38,7 @@
 import Xmobar.X11.Text
 import Xmobar.X11.ColorCache
 import Xmobar.X11.Window (drawBorder)
-import Xmobar.X11.Parsers (Widget(..))
+import Xmobar.X11.Parsers hiding (parseString)
 import Xmobar.System.Utils (safeIndex)
 
 #ifdef XFT
@@ -49,7 +50,7 @@
 fi = fromIntegral
 
 -- | Draws in and updates the window
-drawInWin :: Rectangle -> [[(Widget, String, Int, Maybe [Action])]] -> X ()
+drawInWin :: Rectangle -> [[(Widget, TextRenderInfo, Int, Maybe [Action])]] -> X ()
 drawInWin wr@(Rectangle _ _ wid ht) ~[left,center,right] = do
   r <- ask
   let (c,d) = (config &&& display) r
@@ -77,9 +78,9 @@
       liftIO $ setForeground d gc bgcolor
       liftIO $ fillRectangle d p gc 0 0 wid ht
     -- write to the pixmap the new string
-    printStrings p gc fs vs 1 L =<< strLn left
-    printStrings p gc fs vs 1 R =<< strLn right
-    printStrings p gc fs vs 1 C =<< strLn center
+    printStrings p gc fs vs 1 L [] =<< strLn left
+    printStrings p gc fs vs 1 R [] =<< strLn right
+    printStrings p gc fs vs 1 C [] =<< strLn center
     -- draw border if requested
     liftIO $ drawBorder (border c) (borderWidth c) d p gc bdcolor wid ht
     -- copy the pixmap with the new string to the window
@@ -103,35 +104,37 @@
   | otherwise = return $ fi (ht `div` 2) - 1
 
 printString :: Display -> Drawable -> XFont -> GC -> String -> String
-            -> Position -> Position -> String -> Int -> IO ()
-printString d p (Core fs) gc fc bc x y s a = do
+            -> Position -> Position -> Position -> Position -> String -> Int -> IO ()
+printString d p (Core fs) gc fc bc x y _ _ s a = do
     setFont d gc $ fontFromFontStruct fs
     withColors d [fc, bc] $ \[fc', bc'] -> do
       setForeground d gc fc'
       when (a == 255) (setBackground d gc bc')
       drawImageString d p gc x y s
 
-printString d p (Utf8 fs) gc fc bc x y s a =
+printString d p (Utf8 fs) gc fc bc x y _ _ s a =
     withColors d [fc, bc] $ \[fc', bc'] -> do
       setForeground d gc fc'
       when (a == 255) (setBackground d gc bc')
       liftIO $ wcDrawImageString d p fs gc x y s
 
 #ifdef XFT
-printString dpy drw fs@(Xft fonts) _ fc bc x y s al =
+printString dpy drw fs@(Xft fonts) _ fc bc x y ay ht s al =
   withDrawingColors dpy drw fc bc $ \draw fc' bc' -> do
     when (al == 255) $ do
       (a,d)  <- textExtents fs s
       gi <- xftTxtExtents' dpy fonts s
-      drawXftRect draw bc' x (y - a) (1 + xglyphinfo_xOff gi) (a + d + 2)
+      if ay < 0
+        then drawXftRect draw bc' x (y - a) (1 + xglyphinfo_xOff gi) (a + d + 2)
+        else drawXftRect draw bc' x ay (1 + xglyphinfo_xOff gi) ht
     drawXftString' draw fc' fonts (toInteger x) (toInteger y) s
 #endif
 
 -- | An easy way to print the stuff we need to print
 printStrings :: Drawable -> GC -> NE.NonEmpty XFont -> [Int] -> Position
-             -> Align -> [(Widget, String, Int, Position)] -> X ()
-printStrings _ _ _ _ _ _ [] = return ()
-printStrings dr gc fontlist voffs offs a sl@((s,c,i,l):xs) = do
+             -> Align -> [((Position, Position), Box)] -> [(Widget, TextRenderInfo, Int, Position)] -> X ()
+printStrings _ _ _ _ _ _ _ [] = return ()
+printStrings dr gc fontlist voffs offs a boxes sl@((s,c,i,l):xs) = do
   r <- ask
   let (conf,d) = (config &&& display) r
       alph = alpha conf
@@ -143,13 +146,64 @@
                  C -> (remWidth + offs) `div` 2
                  R -> remWidth
                  L -> offs
-      (fc,bc) = case break (==',') c of
+      (fc,bc) = case break (==',') (tColorsString c) of
                  (f,',':b) -> (f, b           )
                  (f,    _) -> (f, bgColor conf)
   valign <- verticalOffset ht s (NE.head fontlist) (voffs !! i) conf
+  let (ht',ay) = case (tBgTopOffset c, tBgBottomOffset c) of
+                   (-1,_)  -> (0, -1)
+                   (_,-1)  -> (0, -1)
+                   (ot,ob) -> (fromIntegral ht - ot - ob, ob)
   case s of
-    (Text t) -> liftIO $ printString d dr fontst gc fc bc offset valign t alph
+    (Text t) -> liftIO $ printString d dr fontst gc fc bc offset valign ay ht' t alph
     (Icon p) -> liftIO $ maybe (return ())
                            (B.drawBitmap d dr gc fc bc offset valign)
                            (lookup p (iconS r))
-  printStrings dr gc fontlist voffs (offs + l) a xs
+  let triBoxes = tBoxes c
+      dropBoxes = filter (\(_,b) -> b `notElem` triBoxes) boxes
+      boxes' = map (\((x1,_),b) -> ((x1, offset + l), b)) (filter (\(_,b) -> b `elem` triBoxes) boxes)
+            ++ map ((offset, offset + l),) (triBoxes \\ map snd boxes)
+  if Prelude.null xs
+    then liftIO $ drawBoxes d dr gc (fromIntegral ht) (dropBoxes ++ boxes')
+    else liftIO $ drawBoxes d dr gc (fromIntegral ht) dropBoxes
+  printStrings dr gc fontlist voffs (offs + l) a boxes' xs
+
+drawBoxes :: Display -> Drawable -> GC -> Position -> [((Position, Position), Box)] -> IO ()
+drawBoxes _ _ _ _ [] = return ()
+drawBoxes d dr gc ht (b:bs) = do
+  let (xx, Box bb offset lineWidth fc mgs) = b
+      lw = fromIntegral lineWidth :: Position
+  withColors d [fc] $ \[fc'] -> do
+    setForeground d gc fc'
+    setLineAttributes d gc lineWidth lineSolid capNotLast joinMiter
+    case bb of
+      BBVBoth -> do
+        drawBoxBorder d dr gc BBTop    offset ht xx lw mgs
+        drawBoxBorder d dr gc BBBottom offset ht xx lw mgs
+      BBHBoth -> do
+        drawBoxBorder d dr gc BBLeft   offset ht xx lw mgs
+        drawBoxBorder d dr gc BBRight  offset ht xx lw mgs
+      BBFull  -> do
+        drawBoxBorder d dr gc BBTop    offset ht xx lw mgs
+        drawBoxBorder d dr gc BBBottom offset ht xx lw mgs
+        drawBoxBorder d dr gc BBLeft   offset ht xx lw mgs
+        drawBoxBorder d dr gc BBRight  offset ht xx lw mgs
+      _ -> drawBoxBorder d dr gc bb    offset ht xx lw mgs
+  drawBoxes d dr gc ht bs
+
+drawBoxBorder :: Display -> Drawable -> GC -> BoxBorder -> BoxOffset -> Position
+                 -> (Position, Position) -> Position -> BoxMargins -> IO ()
+drawBoxBorder d dr gc pos (BoxOffset alg offset) ht (x1,x2) lw (BoxMargins mt mr mb ml) = do
+  let (p1,p2) = case alg of
+                 L -> (0,      -offset)
+                 C -> (offset, -offset)
+                 R -> (offset, 0      )
+      lc = lw `div` 2
+  case pos of
+    BBTop    -> drawLine d dr gc (x1 + p1) (mt + lc) (x2 + p2) (mt + lc)
+    BBBottom -> do
+      let lc' = max lc 1 + mb
+      drawLine d dr gc (x1 + p1) (ht - lc') (x2 + p2) (ht - lc')
+    BBLeft   -> drawLine d dr gc (x1 - 1 + ml) p1 (x1 - 1 + ml) (ht + p2)
+    BBRight  -> drawLine d dr gc (x2 + lc - 1 - mr) p1 (x2 + lc - 1 - mr) (ht + p2)
+    _ -> error "unreachable code"
diff --git a/src/Xmobar/X11/MinXft.hsc b/src/Xmobar/X11/MinXft.hsc
--- a/src/Xmobar/X11/MinXft.hsc
+++ b/src/Xmobar/X11/MinXft.hsc
@@ -161,10 +161,16 @@
 foreign import ccall "XftDrawStringUtf8"
   cXftDrawStringUtf8 :: AXftDraw -> AXftColor -> AXftFont -> CInt -> CInt -> Ptr (#type FcChar8) -> CInt -> IO ()
 
+-- Fixes https://github.com/jaor/xmobar/issues/476
+utf8EncodeString :: Num b => String -> [b]
+utf8EncodeString str = if UTF8.isUTF8Encoded str
+                       then map (fi . ord) str
+                       else map fi (UTF8.encode str)
+
 drawXftString :: (Integral a1, Integral a) =>
                  AXftDraw -> AXftColor -> AXftFont -> a -> a1 -> String -> IO ()
 drawXftString d c f x y string =
-    withArrayLen (map fi (UTF8.encode string))
+    withArrayLen (utf8EncodeString string)
       (\len ptr -> cXftDrawStringUtf8 d c f (fi x) (fi y) ptr (fi len))
 
 drawXftString' :: AXftDraw ->
diff --git a/src/Xmobar/X11/Parsers.hs b/src/Xmobar/X11/Parsers.hs
--- a/src/Xmobar/X11/Parsers.hs
+++ b/src/Xmobar/X11/Parsers.hs
@@ -14,62 +14,86 @@
 --
 -----------------------------------------------------------------------------
 
-module Xmobar.X11.Parsers (parseString, Widget(..)) where
+module Xmobar.X11.Parsers (parseString, Box(..), BoxBorder(..), BoxOffset(..),
+  BoxMargins(..), TextRenderInfo(..), Widget(..)) where
 
 import Xmobar.Config.Types
 import Xmobar.X11.Actions
 
 import Control.Monad (guard, mzero)
 import Data.Maybe (fromMaybe)
+import Data.Int (Int32)
 import Text.ParserCombinators.Parsec
 import Text.Read (readMaybe)
 import Graphics.X11.Types (Button)
+import Foreign.C.Types (CInt)
 
 data Widget = Icon String | Text String
 
-type ColorString = String
+data BoxOffset = BoxOffset Align Int32 deriving Eq 
+-- margins: Top, Right, Bottom, Left
+data BoxMargins = BoxMargins Int32 Int32 Int32 Int32 deriving Eq
+data BoxBorder = BBTop
+               | BBBottom
+               | BBVBoth
+               | BBLeft
+               | BBRight
+               | BBHBoth
+               | BBFull
+                 deriving ( Read, Eq )
+data Box = Box BoxBorder BoxOffset CInt String BoxMargins deriving Eq
+data TextRenderInfo =
+    TextRenderInfo { tColorsString   :: String
+                   , tBgTopOffset    :: Int32
+                   , tBgBottomOffset :: Int32
+                   , tBoxes          :: [Box]
+                   }
 type FontIndex   = Int
 
 -- | Runs the string parser
 parseString :: Config -> String
-               -> IO [(Widget, ColorString, FontIndex, Maybe [Action])]
+               -> IO [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 parseString c s =
-    case parse (stringParser (fgColor c) 0 Nothing) "" s of
+    case parse (stringParser ci 0 Nothing) "" s of
       Left  _ -> return [(Text $ "Could not parse string: " ++ s
-                          , fgColor c
+                          , ci
                           , 0
                           , Nothing)]
       Right x -> return (concat x)
+    where ci = TextRenderInfo (fgColor c) 0 0 []
 
-allParsers :: ColorString
+allParsers :: TextRenderInfo
            -> FontIndex
            -> Maybe [Action]
-           -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
+           -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 allParsers c f a =  textParser c f a
                 <|> try (iconParser c f a)
                 <|> try (rawParser c f a)
                 <|> try (actionParser c f a)
                 <|> try (fontParser c a)
-                <|> colorParser f a
+                <|> try (boxParser c f a)
+                <|> colorParser c f a
 
 -- | Gets the string and combines the needed parsers
-stringParser :: String -> FontIndex -> Maybe [Action]
-                -> Parser [[(Widget, ColorString, FontIndex, Maybe [Action])]]
+stringParser :: TextRenderInfo -> FontIndex -> Maybe [Action]
+                -> Parser [[(Widget, TextRenderInfo, FontIndex, Maybe [Action])]]
 stringParser c f a = manyTill (allParsers c f a) eof
 
 -- | Parses a maximal string without markup.
-textParser :: String -> FontIndex -> Maybe [Action]
-              -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
+textParser :: TextRenderInfo -> FontIndex -> Maybe [Action]
+              -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 textParser c f a = do s <- many1 $
                             noneOf "<" <|>
                               try (notFollowedBy' (char '<')
                                     (try (string "fc=")  <|>
+                                     try (string "box")  <|>
                                      try (string "fn=")  <|>
                                      try (string "action=") <|>
                                      try (string "/action>") <|>
                                      try (string "icon=") <|>
                                      try (string "raw=") <|>
                                      try (string "/fn>") <|>
+                                     try (string "/box>") <|>
                                      string "/fc>"))
                       return [(Text s, c, f, a)]
 
@@ -78,10 +102,10 @@
 -- string of digits (base 10) denoting the length of the raw string,
 -- a literal ":" as digit-string-terminator, the raw string itself, and
 -- then a literal "/>".
-rawParser :: ColorString
+rawParser :: TextRenderInfo
           -> FontIndex
           -> Maybe [Action]
-          -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
+          -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 rawParser c f a = do
   string "<raw="
   lenstr <- many1 digit
@@ -102,15 +126,15 @@
                         notFollowedBy $ try (e >> return '*')
                         return x
 
-iconParser :: String -> FontIndex -> Maybe [Action]
-              -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
+iconParser :: TextRenderInfo -> FontIndex -> Maybe [Action]
+              -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 iconParser c f a = do
   string "<icon="
   i <- manyTill (noneOf ">") (try (string "/>"))
   return [(Icon i, c, f, a)]
 
-actionParser :: String -> FontIndex -> Maybe [Action]
-                -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
+actionParser :: TextRenderInfo -> FontIndex -> Maybe [Action]
+                -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 actionParser c f act = do
   string "<action="
   command <- choice [between (char '`') (char '`') (many1 (noneOf "`")),
@@ -128,16 +152,62 @@
 toButtons = map (\x -> read [x])
 
 -- | Parsers a string wrapped in a color specification.
-colorParser :: FontIndex -> Maybe [Action]
-               -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
-colorParser f a = do
+colorParser :: TextRenderInfo -> FontIndex -> Maybe [Action]
+               -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
+colorParser (TextRenderInfo _ _ _ bs) f a = do
   c <- between (string "<fc=") (string ">") colors
-  s <- manyTill (allParsers c f a) (try $ string "</fc>")
+  let colorParts = break (==':') c
+  let (ot,ob) = case break (==',') (Prelude.drop 1 $ snd colorParts) of
+             (top,',':btm) -> (top, btm)
+             (top,      _) -> (top, top)
+  s <- manyTill
+       (allParsers (TextRenderInfo (fst colorParts) (fromMaybe (-1) $ readMaybe ot) (fromMaybe (-1) $ readMaybe ob) bs) f a)
+       (try $ string "</fc>")
   return (concat s)
 
+-- | Parses a string wrapped in a box specification.
+boxParser :: TextRenderInfo -> FontIndex -> Maybe [Action]
+              -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
+boxParser (TextRenderInfo cs ot ob bs) f a = do
+  c <- between (string "<box") (string ">") (option "" (many1 (alphaNum <|> char '=' <|> char ' ' <|> char '#' <|> char ',')))
+  let b = Box BBFull (BoxOffset C 0) 1 cs (BoxMargins 0 0 0 0)
+  let g = boxReader b (words c)
+  s <- manyTill
+       (allParsers (TextRenderInfo cs ot ob (g : bs)) f a)
+       (try $ string "</box>")
+  return (concat s)
+
+boxReader :: Box -> [String] -> Box
+boxReader b [] = b
+boxReader b (x:xs) = do
+  let (param,val) = case break (=='=') x of
+                 (p,'=':v) -> (p, v)
+                 (p,    _) -> (p, "")
+  boxReader (boxParamReader b param val) xs
+ 
+boxParamReader :: Box -> String -> String -> Box
+boxParamReader b _ "" = b
+boxParamReader (Box bb off lw fc mgs) "type" val = 
+  Box (fromMaybe bb $ readMaybe ("BB" ++ val)) off lw fc mgs
+boxParamReader (Box bb (BoxOffset alg off) lw fc mgs) "offset" (a:o) =
+  Box bb (BoxOffset (fromMaybe alg $ readMaybe [a]) (fromMaybe off $ readMaybe o)) lw fc mgs
+boxParamReader (Box bb off lw fc mgs) "width" val = 
+  Box bb off (fromMaybe lw $ readMaybe val) fc mgs
+boxParamReader (Box bb off lw _ mgs) "color" val = 
+  Box bb off lw val mgs
+boxParamReader (Box bb off lw fc mgs@(BoxMargins mt mr mb ml)) ('m':pos) val = do
+  let mgs' = case pos of
+         "t" -> BoxMargins (fromMaybe mt $ readMaybe val) mr mb ml
+         "r" -> BoxMargins mt (fromMaybe mr $ readMaybe val) mb ml
+         "b" -> BoxMargins mt mr (fromMaybe mb $ readMaybe val) ml
+         "l" -> BoxMargins mt mr mb (fromMaybe ml $ readMaybe val)
+         _ -> mgs
+  Box bb off lw fc mgs'
+boxParamReader b _ _ = b
+
 -- | Parsers a string wrapped in a font specification.
-fontParser :: ColorString -> Maybe [Action]
-              -> Parser [(Widget, ColorString, FontIndex, Maybe [Action])]
+fontParser :: TextRenderInfo -> Maybe [Action]
+              -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]
 fontParser c a = do
   f <- between (string "<fn=") (string ">") colors
   s <- manyTill (allParsers c (fromMaybe 0 $ readMaybe f) a) (try $ string "</fn>")
@@ -145,4 +215,4 @@
 
 -- | Parses a color specification (hex or named)
 colors :: Parser String
-colors = many1 (alphaNum <|> char ',' <|> char '#')
+colors = many1 (alphaNum <|> char ',' <|> char ':' <|> char '#')
diff --git a/src/Xmobar/X11/Window.hs b/src/Xmobar/X11/Window.hs
--- a/src/Xmobar/X11/Window.hs
+++ b/src/Xmobar/X11/Window.hs
@@ -1,7 +1,7 @@
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Window
--- Copyright   :  (c) 2011-18 Jose A. Ortega Ruiz
+-- Copyright   :  (c) 2011-18, 20 Jose A. Ortega Ruiz
 --             :  (c) 2012 Jochen Keil
 -- License     :  BSD-style (see LICENSE)
 --
@@ -16,7 +16,6 @@
 module Xmobar.X11.Window where
 
 import Prelude
-import Control.Applicative ((<$>))
 import Control.Monad (when, unless)
 import Graphics.X11.Xlib hiding (textExtents)
 import Graphics.X11.Xlib.Extras
diff --git a/xmobar.cabal b/xmobar.cabal
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,5 +1,5 @@
 name:               xmobar
-version:            0.35.1
+version:            0.36
 homepage:           http://xmobar.org
 synopsis:           A Minimalistic Text Based Status Bar
 description: 	    Xmobar is a minimalistic text based status bar.
