xmobar 0.35.1 → 0.36
raw patch · 22 files changed
+532/−287 lines, 22 files
Files
- changelog.md +16/−0
- license +2/−1
- readme.md +278/−164
- src/Xmobar/App/Config.hs +18/−32
- src/Xmobar/App/EventLoop.hs +4/−5
- src/Xmobar/App/Main.hs +2/−3
- src/Xmobar/Plugins/MarqueePipeReader.hs +0/−1
- src/Xmobar/Plugins/Monitors/Bright.hs +0/−2
- src/Xmobar/Plugins/Monitors/Common/Output.hs +7/−4
- src/Xmobar/Plugins/Monitors/Common/Parsers.hs +1/−2
- src/Xmobar/Plugins/Monitors/Mpris.hs +17/−12
- src/Xmobar/Plugins/Monitors/MultiCpu.hs +0/−1
- src/Xmobar/Plugins/Monitors/Net.hs +0/−1
- src/Xmobar/Plugins/Monitors/Volume.hs +8/−7
- src/Xmobar/Plugins/PipeReader.hs +0/−1
- src/Xmobar/System/Environment.hs +0/−1
- src/Xmobar/X11/Bitmap.hs +2/−2
- src/Xmobar/X11/Draw.hs +73/−19
- src/Xmobar/X11/MinXft.hsc +7/−1
- src/Xmobar/X11/Parsers.hs +95/−25
- src/Xmobar/X11/Window.hs +1/−2
- xmobar.cabal +1/−1
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 @@ [](http://hackage.haskell.org/package/xmobar)-[](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 © 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.