packages feed

xmobar 0.35.1 → 0.36

raw patch · 22 files changed

+532/−287 lines, 22 files

Files

changelog.md view
@@ -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)
license view
@@ -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. 
readme.md view
@@ -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
src/Xmobar/App/Config.hs view
@@ -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
src/Xmobar/App/EventLoop.hs view
@@ -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)
src/Xmobar/App/Main.hs view
@@ -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(..)) 
src/Xmobar/Plugins/MarqueePipeReader.hs view
@@ -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
src/Xmobar/Plugins/Monitors/Bright.hs view
@@ -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-
src/Xmobar/Plugins/Monitors/Common/Output.hs view
@@ -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 ""
src/Xmobar/Plugins/Monitors/Common/Parsers.hs view
@@ -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
src/Xmobar/Plugins/Monitors/Mpris.hs view
@@ -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)
src/Xmobar/Plugins/Monitors/MultiCpu.hs view
@@ -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)
src/Xmobar/Plugins/Monitors/Net.hs view
@@ -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)
src/Xmobar/Plugins/Monitors/Volume.hs view
@@ -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
src/Xmobar/Plugins/PipeReader.hs view
@@ -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)
src/Xmobar/System/Environment.hs view
@@ -13,7 +13,6 @@ ----------------------------------------------------------------------------- module Xmobar.System.Environment(expandEnv) where -import Control.Applicative  ((<$>)) import Data.Maybe (fromMaybe) import System.Environment   (lookupEnv) 
src/Xmobar/X11/Bitmap.hs view
@@ -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
src/Xmobar/X11/Draw.hs view
@@ -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"
src/Xmobar/X11/MinXft.hsc view
@@ -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 ->
src/Xmobar/X11/Parsers.hs view
@@ -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 '#')
src/Xmobar/X11/Window.hs view
@@ -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
xmobar.cabal view
@@ -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.