packages feed

xmobar 0.41 → 0.42

raw patch · 40 files changed

+3352/−2968 lines, 40 filesdep ~aeson

Dependency ranges changed: aeson

Files

changelog.md view
@@ -1,3 +1,17 @@+## Version 0.42 (March, 2022)++_New features_++  - New text mode (thanks to Pavel Kagulin, see issue #601), with+    output formats compatible with color terminals and pango.+  - New text mode with format following swaybar-protocol, supporting+    colors, faces, boxes and actions.++_Bug fixes_++   - Fix for bottom placement (#608)+   - Fix for memory leak during X drawing (#609)+ ## Version 0.41 (January, 2022)  _New features_
doc/plugins.org view
@@ -1,1640 +1,1326 @@-* 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 is set: we mention that fact, when needed, in their-  description.--  Each monitor has an =alias= to be used in the output-  template. Monitors may have default aliases, see the documentation-  of the monitor in question.--  There are two types of arguments: ones that all monitors share (the-  so called /default monitor arguments/) and arguments that are specific-  to a certain monitor.--  All Monitors accept a common set of arguments, described below in-  [[Default Monitor Arguments]]. Some monitors also accept additional-  options that are specific to them. When specifying the list of-  arguments in your configuration, the common options come first,-  followed by =--=, followed by any monitor-specific options. For-  example, the following [[=Battery Args RefreshRate=][Battery]] configuration first sets the global-  =template= and =Low= arguments and then specifies the battery-specific-  =off= option.--  #+begin_src haskell-    Run Battery-      [ "--template", "<acstatus>"-      , "--Low"     , "15"-      -- battery specific options start here.-      , "--"-      , "--off"     , "<left> (<timeleft>)"-      ]-      100-  #+end_src--** 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-(i.e. =<icon=/path/to/icon_%%.xpm/>= will be interpreted as-=<icon=/path/to/icon_3.xpm/>= when the value is =3=, also =%= is-interpreted as =%=, =%%= as =3=, =%%%= as =3%=, =%%%%= as =33= and so-on). Essentially it allows to replace vertical bars with custom-icons. For example,--#+begin_src haskell-  Run Brightness-    [ "-t", "<ipat>"-    , "--"-    , "--brightness-icon-pattern", "<icon=bright_%%.xpm/>"-    ] 30-#+end_src--Will display =bright_0.xpm= to =bright_8.xpm= depending on current-brightness value.--** Default Monitor Arguments--These are the options available for all monitors:--- =-t= /string/ Output template--  - Template for the monitor output. Field names must be enclosed-    between pointy brackets (=<foo>=) and will be substituted by the-    computed values. You can also specify the foreground (and-    optionally, background) color for a region by bracketing it between-    =<fc=fgcolor>= (or =<fc=fgcolor,bgcolor>=) and =</fc>=. The rest of-    the template is output verbatim.-  - Long option: =--template=-  - Default value: per monitor (see above).--- =-H= /number/ The high threshold.--  - Numerical values higher than /number/ will be displayed with the-    color specified by =-h= (see below).-  - Long option: =--High=-  - Default value: 66--- =-L= /number/ The low threshold.--  - Numerical values higher than /number/ and lower than the high-    threshold will be displayed with the color specified by =-n= (see-    below). Values lower than /number/ will use the =-l= color.-  - Long option: =--Low=-  - Default value: 33--- =-h= /color/ High threshold color.--  - Color for displaying values above the high threshold. /color/ can be-    either a name (e.g. "blue") or an hexadecimal RGB (e.g. "#FF0000").-  - Long option: =--high=-  - Default: none (use the default foreground).--- =-n= /color/ Color for 'normal' values--  - Color used for values greater than the low threshold but lower than-    the high one.-  - Long option: =--normal=-  - Default: none (use the default foreground).--- =-l= /color/ The low threshold color--  - Color for displaying values below the low threshold.-  - Long option: =--low=-  - Default: none (use the default foreground).--- =-S= /boolean/ Display optional suffixes--  - When set to a true designator ("True", "Yes" or "On"), optional-    value suffixes such as the '%' symbol or optional units will be-    displayed.-  - Long option: =--suffix=-  - Default: False.--- =-p= /number/ Percentages padding--  - Width, in number of digits, for quantities representing percentages.-    For instance =-p 3= means that all percentages in the monitor will-    be represented using 3 digits.-  - Long option: =--ppad=-  - Default value: 0 (don't pad)--- =-d= /number/ Decimal digits--  - Number of digits after the decimal period to use in float values.-  - Long option: =--ddigits=-  - Default value: 0 (display only integer part)--- =-m= /number/ Minimum field width--  - Minimum width, in number of characters, of the fields in the monitor-    template. Values whose printed representation is shorter than this-    value will be padded using the padding characters given by the =-c=-    option with the alignment specified by =-a= (see below).-  - Long option: =--minwidth=-  - Default: 0--- =-M= /number/ Maximum field width--  - Maximum width, in number of characters, of the fields in the monitor-    template. Values whose printed representation is longer than this-    value will be truncated.-  - Long option: =--maxwidth=-  - Default: 0 (no maximum width)--- =-e= /string/ Maximum width ellipsis--  - Ellipsis to be added to the field when it has reached its max width.-  - Long option: =--maxwidthellipsis=-  - Default: "" (no ellipsis)--- =-w= /number/ Fixed field width--  - All fields will be set to this width, padding or truncating as-    needed.-  - Long option: =--width=-  - Default: 0 (variable width)--- =-T= /number/ Maximum total width--  - Maximum total width of the text.-  - Long option: =--maxtwidth=-  - Default: 0 (no limit)--- =-E= /string/ Maximum total width ellipsis--  - Ellipsis to be added to the total text when it has reached its max-    width.-  - Long option: =--maxtwidthellipsis=-  - Default: "" (no ellipsis)--- =-c= /string/--  - Characters used for padding. The characters of /string/ are used-    cyclically. E.g., with =-P +- -w 6=, a field with value "foo" will-    be represented as "+-+foo".-  - Long option: =--padchars=-  - Default value: " "--- =-a= r|l Field alignment--  - Whether to use right (r) or left (l) alignment of field values when-    padding.-  - Long option: =--align=-  - Default value: r (padding to the left)--- =-b= /string/ Bar background--  - Characters used, cyclically, to draw the background of bars. For-    instance, if you set this option to "·.", an empty bar will look-    like this: =·.·.·.·.·.=-  - Long option: =--bback=-  - Default value: ":"--- =-f= /string/ Bar foreground--  - Characters used, cyclically, to draw the foreground of bars.-  - Long option: =--bfore=-  - Default value: "#"--- =-W= /number/ Bar width--  - 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=-  - Default value: "N/A"--Commands' arguments must be set as a list. E.g.:--#+begin_src haskell-  Run Weather "EGPF" ["-t", "<station>: <tempC>C"] 36000-#+end_src--In this case xmobar will run the weather monitor, getting information-for the weather station ID EGPF (Glasgow Airport, as a homage to GHC)-every hour (36000 tenth of seconds), with a template that will output-something like:--#+begin_src shell-  Glasgow Airport: 16.0C-#+end_src--** Battery Monitors-*** =Battery Args RefreshRate=-- Same as-- #+begin_src haskell-   BatteryP ["BAT", "BAT0", "BAT1", "BAT2"] Args RefreshRate- #+end_src--*** =BatteryP Dirs Args RefreshRate=-- - Aliases to =battery=-- - Dirs: list of directories in =/sys/class/power_supply/= where to look-   for the ACPI files of each battery. Example: =["BAT0","BAT1","BAT2"]=.-   Only up to 3 existing directories will be searched.-- - Args: default monitor arguments, plus the following specific ones-   (these options, being specific to the monitor, are to be specified-   after a =--= in the argument list):--   - =-O=: string for AC "on" status (default: "On")-   - =-i=: string for AC "idle" status (default: "On")-   - =-o=: string for AC "off" status (default: "Off")-   - =-L=: low power (=watts=) threshold (default: 10)-   - =-H=: high power threshold (default: 12)-   - =-l=: color to display power lower than the =-L= threshold-   - =-m=: color to display power lower than the =-H= threshold-   - =-h=: color to display power higher than the =-H= threshold-   - =-p=: color to display positive power (battery charging)-   - =-f=: file in =/sys/class/power_supply= with AC info (default:-     "AC/online")-   - =-A=: a number between 0 and 100, threshold below which the action-     given by =-a=, if any, is performed (default: 5)-   - =-a=: a string with a system command that is run when the percentage-     left in the battery is less or equal than the threshold given by the-     =-A= option. If not present, no action is undertaken.-   - =-P=: to include a percentage symbol in =left=.-   - =--on-icon-pattern=: dynamic string for current battery charge when-     AC is "on" in =leftipat=.-   - =--off-icon-pattern=: dynamic string for current battery charge when-     AC is "off" in =leftipat=.-   - =--idle-icon-pattern=: dynamic string for current battery charge-     when AC is "idle" in =leftipat=.-   - =--lows=: string for AC "off" status and power lower than the =-L=-     threshold (default: "")-   - =--mediums=: string for AC "off" status and power lower than the-     =-H= threshold (default: "")-   - =--highs=: string for AC "off" status and power higher than the =-H=-     threshold (default: "")-- - Variables that can be used with the =-t/--template= argument:-   =left=, =leftbar=, =leftvbar=, =leftipat=, =timeleft=, =watts=,-   =acstatus=-- - Default template: =Batt: <watts>, <left>% / <timeleft>=-- - Example (note that you need "--" to separate regular monitor options-   from Battery's specific ones):--   #+begin_src haskell-     Run BatteryP ["BAT0"]-                  ["-t", "<acstatus><watts> (<left>%)",-                   "-L", "10", "-H", "80", "-p", "3",-                   "--", "-O", "<fc=green>On</fc> - ", "-i", "",-                   "-L", "-15", "-H", "-5",-                   "-l", "red", "-m", "blue", "-h", "green",-                   "-a", "notify-send -u critical 'Battery running out!!'",-                   "-A", "3"]-                  600-   #+end_src--   In the above example, the thresholds before the =--= separator affect-   only the =<left>= and =<leftbar>= fields, while those after the-   separator affect how =<watts>= is displayed. For this monitor, neither-   the generic nor the specific options have any effect on =<timeleft>=.-   We are also telling the monitor to execute the unix command-   =notify-send= when the percentage left in the battery reaches 6%.--   It is also possible to specify template variables in the =-O= and =-o=-   switches, as in the following example:--   #+begin_src haskell-     Run BatteryP ["BAT0"]-                  ["-t", "<acstatus>"-                  , "-L", "10", "-H", "80"-                  , "-l", "red", "-h", "green"-                  , "--", "-O", "Charging", "-o", "Battery: <left>%"-                  ] 10-   #+end_src-- - The "idle" AC state is selected whenever the AC power entering the-   battery is zero.--*** =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.-** Cpu and Memory Monitors-*** =Cpu Args RefreshRate=-- - Aliases to =cpu=- - Args: default monitor arguments, plus:--   - =--load-icon-pattern=: dynamic string for cpu load in =ipat=-- - Thresholds refer to percentage of CPU load- - Variables that can be used with the =-t/--template= argument:-   =total=, =bar=, =vbar=, =ipat=, =user=, =nice=, =system=, =idle=,-   =iowait=- - Default template: =Cpu: <total>%=--*** =MultiCpu Args RefreshRate=-- - Aliases to =multicpu=- - Args: default monitor arguments, plus:--   - =--load-icon-pattern=: dynamic string for overall cpu load in-     =ipat=.-   - =--load-icon-patterns=: dynamic string for each cpu load in-     =autoipat=, =ipat{i}=. This option can be specified several times.-     nth option corresponds to nth cpu.-   - =--fallback-icon-pattern=: dynamic string used by =autoipat= and-     =ipat{i}= when no =--load-icon-patterns= has been provided for-     =cpu{i}=-   - =--contiguous-icons=: flag (no value needs to be provided) that-     causes the load icons to be drawn without padding.-- - Thresholds refer to percentage of CPU load- - Variables that can be used with the =-t/--template= argument:-   =autototal=, =autobar=, =autovbar=, =autoipat=, =autouser=,-   =autonice=, =autosystem=, =autoidle=, =total=, =bar=, =vbar=, =ipat=,-   =user=, =nice=, =system=, =idle=, =total0=, =bar0=, =vbar0=, =ipat0=,-   =user0=, =nice0=, =system0=, =idle0=, ... The auto* variables-   automatically detect the number of CPUs on the system and display one-   entry for each.- - Default template: =Cpu: <total>%=--*** =CpuFreq Args RefreshRate=-- - Aliases to =cpufreq=-- - Args: default monitor arguments-- - Thresholds refer to frequency in GHz-- - Variables that can be used with the =-t/--template= argument:-   =cpu0=, =cpu1=, .., =cpuN=-- - Default template: =Freq: <cpu0>GHz=-- - This monitor requires acpi_cpufreq module to be loaded in kernel-- - Example:--   #+begin_src haskell-     Run CpuFreq ["-t", "Freq:<cpu0>|<cpu1>GHz", "-L", "0", "-H", "2",-                  "-l", "lightblue", "-n","white", "-h", "red"] 50-   #+end_src--*** =CoreTemp Args RefreshRate=-- - Aliases to =coretemp=-- - Args: default monitor arguments-- - Thresholds refer to temperature in degrees-- - Variables that can be used with the =-t/--template= argument:-   =core0=, =core1=, .., =coreN=-- - Default template: =Temp: <core0>C=-- - This monitor requires coretemp module to be loaded in kernel-- - Example:--   #+begin_src haskell-     Run CoreTemp ["-t", "Temp:<core0>|<core1>C",-                   "-L", "40", "-H", "60",-                   "-l", "lightblue", "-n", "gray90", "-h", "red"] 50-   #+end_src--*** =MultiCoreTemp Args RefreshRate=-- - Aliases to =multicoretemp=-- - Args: default monitor arguments, plus:--   - =--max-icon-pattern=: dynamic string for overall cpu load in-     =maxipat=.-   - =--avg-icon-pattern=: dynamic string for overall cpu load in-     =avgipat=.-   - =--mintemp=: temperature in degree Celsius, that sets the lower-     limit for percentage calculation.-   - =--maxtemp=: temperature in degree Celsius, that sets the upper-     limit for percentage calculation.-   - =--hwmon-path=: this monitor tries to find coretemp devices by-     looking for them in directories following the pattern-     =/sys/bus/platform/devices/coretemp.*/hwmon/hwmon*=, but some-     processors (notably Ryzen) might expose those files in a different-     tree (e.g., Ryzen) puts them somewhere in "/sys/class/hwmon/hwmon*",-     and the lookup is most costly. With this option, it is possible to-     explicitly specify the full path to the directory where the-     =tempN_label= and =tempN_input= files are located.-- - Thresholds refer to temperature in degree Celsius-- - Variables that can be used with the =-t/--template= argument: =max=,-   =maxpc=, =maxbar=, =maxvbar=, =maxipat=, =avg=, =avgpc=, =avgbar=,-   =avgvbar=, =avgipat=, =core0=, =core1=, ..., =coreN=--   The /pc, /bar, /vbar and /ipat variables are showing percentages on-   the scale defined by =--mintemp= and =--maxtemp=. The max* and avg*-   variables to the highest and the average core temperature.-- - Default template: =Temp: <max>°C - <maxpc>%=-- - This monitor requires coretemp module to be loaded in kernel-- - Example:--   #+begin_src haskell-     Run MultiCoreTemp ["-t", "Temp: <avg>°C | <avgpc>%",-                        "-L", "60", "-H", "80",-                        "-l", "green", "-n", "yellow", "-h", "red",-                        "--", "--mintemp", "20", "--maxtemp", "100"] 50-   #+end_src--*** =K10Temp Slot Args RefreshRate=-- - Aliases to =k10temp=-- - Slot: The PCI slot address of the k10temp device as a string.  You-   can find it as a subdirectory in =/sys/bus/pci/drivers/k10temp/=.-- - Args: default monitor arguments-- - Thresholds refer to temperature in degrees-- - Variables that can be used with the =-t/--template= argument:-   =Tctl=, =Tdie=, =Tccd1=, .., =Tccd8=-- - Default template: =Temp: <Tdie>C=-- - This monitor requires k10temp module to be loaded in kernel-- - It is important to note that not all measurements are available-   on on all models of processor. Of particular importance - Tdie-   (used in the default template) may not be present on processors-   prior to Zen (17h). Tctl, however, may be offset from the real-   temperature and so is not used by default.-- - Example:--   #+begin_src haskell-     Run K10Temp "0000:00:18.3"-                 ["-t", "Temp: <Tdie>C|<Tccd1>C",-                  "-L", "40", "-H", "60",-                  "-l", "lightblue", "-n", "gray90", "-h", "red"]-                 50-   #+end_src---*** =Memory Args RefreshRate=-- - Aliases to =memory=- - Args: default monitor arguments, plus:--   - =--used-icon-pattern=: dynamic string for used memory ratio in-     =usedipat=.-   - =--free-icon-pattern=: dynamic string for free memory ratio in-     =freeipat=.-   - =--available-icon-pattern=: dynamic string for available memory-     ratio in =availableipat=.-- - Thresholds refer to percentage of used memory- - Variables that can be used with the =-t/--template= argument:-   =total=, =free=, =buffer=, =cache=, =available=, =used=, =usedratio=,-   =usedbar=, =usedvbar=, =usedipat=, =freeratio=, =freebar=, =freevbar=,-   =freeipat=, =availableratio=, =availablebar=, =availablevbar=,-   =availableipat=- - Default template: =Mem: <usedratio>% (<cache>M)=--*** =Swap Args RefreshRate=-- - Aliases to =swap=- - Args: default monitor arguments- - Thresholds refer to percentage of used swap- - Variables that can be used with the =-t/--template= argument:-   =total=, =used=, =free=, =usedratio=- - Default template: =Swap: <usedratio>%=-** Date Monitors-*** =Date Format Alias RefreshRate=-- - Format is a time format string, as accepted by the standard ISO C-   =strftime= function (or Haskell's =formatCalendarTime=).  Basically,-   if =date +"my-string"= works with your command then =Date= will handle-   it correctly.-- - Timezone changes are picked up automatically every minute.-- - Sample usage:--   #+begin_src haskell-     Run Date "%a %b %_d %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10-   #+end_src--*** =DateZone Format Locale Zone Alias RefreshRate=-- A variant of the =Date= monitor where one is able to explicitly set the- time-zone, as well as the locale.-- - The format of =DateZone= is exactly the same as =Date=.-- - If =Locale= is =""= (the empty string) the default locale of the-   system is used, otherwise use the given locale. If there are more-   instances of =DateZone=, using the empty string as input for =Locale=-   is not recommended.-- - =Zone= is the name of the =TimeZone=. It is assumed that the time-zone-   database is stored in =/usr/share/zoneinfo/=. If the empty string is-   given as =Zone=, the default system time is used.-- - Sample usage:--   #+begin_src haskell-     Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10-   #+end_src-** Disk Monitors-*** =DiskU Disks Args RefreshRate=-- - Aliases to =disku=-- - Disks: list of pairs of the form (device or mount point, template),-   where the template can contain =<size>=, =<free>=, =<used>=, =<freep>=-   or =<usedp>=, =<freebar>=, =<freevbar>=, =<freeipat>=, =<usedbar>=,-   =<usedvbar>= or =<usedipat>= for total, free, used, free percentage-   and used percentage of the given file system capacity.-- - Thresholds refer to usage percentage.-- - Args: default monitor arguments. =-t/--template= is ignored. Plus--   - =--free-icon-pattern=: dynamic string for free disk space in-     =freeipat=.-   - =--used-icon-pattern=: dynamic string for used disk space in-     =usedipat=.-- - Default template: none (you must specify a template for each file-   system).-- - Example:--   #+begin_src haskell-     DiskU [("/", "<used>/<size>"), ("sdb1", "<usedbar>")]-           ["-L", "20", "-H", "50", "-m", "1", "-p", "3"]-           20-   #+end_src--*** =DiskIO Disks Args RefreshRate=-- - Aliases to =diskio=-- - Disks: list of pairs of the form (device or mount point, template),-   where the template can contain =<total>=, =<read>=, =<write>= for-   total, read and write speed, respectively, as well as =<totalb>=,-   =<readb>=, =<writeb>=, which report number of bytes during the last-   refresh period rather than speed. There are also bar versions of each:-   =<totalbar>=, =<totalvbar>=, =<totalipat>=, =<readbar>=, =<readvbar>=,-   =<readipat>=, =<writebar>=, =<writevbar>=, and =<writeipat>=; and-   their "bytes" counterparts: =<totalbbar>=, =<totalbvbar>=,-   =<totalbipat>=, =<readbbar>=, =<readbvbar>=, =<readbipat>=,-   =<writebbar>=, =<writebvbar>=, and =<writebipat>=.-- - Thresholds refer to speed in b/s-- - Args: default monitor arguments. =-t/--template= is ignored. Plus--   - =--total-icon-pattern=: dynamic string for total disk I/O in-     =<totalipat>=.-   - =--write-icon-pattern=: dynamic string for write disk I/O in-     =<writeipat>=.-   - =--read-icon-pattern=: dynamic string for read disk I/O in-     =<readipat>=.-- - Default template: none (you must specify a template for each file-   system).-- - Example:--   #+begin_src haskell-     DiskIO [("/", "<read> <write>"), ("sdb1", "<total>")] [] 10-   #+end_src--** Keyboard Monitors-*** =Kbd Opts=-- - Registers to XKB/X11-Events and output the currently active keyboard-   layout. Supports replacement of layout names.-- - Aliases to =kbd=-- - Opts is a list of tuples:--   - first element of the tuple is the search string-   - second element of the tuple is the corresponding replacement-- - Example:--   #+begin_src haskell-     Run Kbd [("us(dvorak)", "DV"), ("us", "US")]-   #+end_src--*** =Locks=-- - Displays the status of Caps Lock, Num Lock and Scroll Lock.-- - Aliases to =locks=-- - Example:--   #+begin_src haskell-     Run Locks-   #+end_src-** Process Monitors-*** =TopProc Args RefreshRate=-- - Aliases to =top=- - Args: default monitor arguments. The low and high thresholds (=-L= and-   =-H=) denote, for memory entries, the percent of the process memory-   over the total amount of memory currently in use and, for cpu entries,-   the activity percentage (i.e., the value of =cpuN=, which takes values-   between 0 and 100).- - Variables that can be used with the =-t/--template= argument: =no=,-   =name1=, =cpu1=, =both1=, =mname1=, =mem1=, =mboth1=, =name2=, =cpu2=,-   =both2=, =mname2=, =mem2=, =mboth2=, ...- - Default template: =<both1>=- - Displays the name and cpu/mem usage of running processes (=bothn= and-   =mboth= display both, and is useful to specify an overall maximum-   and/or minimum width, using the =-m/-M= arguments. =no= gives the-   total number of processes.--*** =TopMem Args RefreshRate=-- - Aliases to =topmem=- - Args: default monitor arguments. The low and high thresholds (=-L= and-   =-H=) denote the percent of the process memory over the total amount-   of memory currently in use.- - Variables that can be used with the =-t/--template= argument:-   =name1=, =mem1=, =both1=, =name2=, =mem2=, =both2=, ...- - Default template: =<both1>=- - Displays the name and RSS (resident memory size) of running processes-   (=bothn= displays both, and is useful to specify an overall maximum-   and/or minimum width, using the =-m/-M= arguments.-** Thermal Monitors-*** =ThermalZone Number Args RefreshRate=-- - Aliases to "thermaln": so =ThermalZone 0 []= can be used in template-   as =%thermal0%=-- - Thresholds refer to temperature in degrees-- - Args: default monitor arguments-- - Variables that can be used with the =-t/--template= argument: =temp=-- - Default template: =<temp>C=-- - This plugin works only on systems with devices having thermal zone.-   Check directories in =/sys/class/thermal= for possible values of the-   zone number (e.g., 0 corresponds to =thermal_zone0= in that-   directory).-- - Example:--   #+begin_src haskell-     Run ThermalZone 0 ["-t","<id>: <temp>C"] 30-   #+end_src--*** =Thermal Zone Args RefreshRate=-- - *This plugin is deprecated. Use =ThermalZone= instead.*-- - Aliases to the Zone: so =Thermal "THRM" []= can be used in template as-   =%THRM%=-- - Args: default monitor arguments-- - Thresholds refer to temperature in degrees-- - Variables that can be used with the =-t/--template= argument: =temp=-- - Default template: =Thm: <temp>C=-- - This plugin works only on systems with devices having thermal zone.-   Check directories in /proc/acpi/thermal_zone for possible values.-- - Example:--   #+begin_src haskell-     Run Thermal "THRM" ["-t","iwl4965-temp: <temp>C"] 50-   #+end_src-** Volume Monitors-*** =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%=.- - Args: default monitor arguments. Also accepts:--   - =-O= /string/ On string--     - The string used in place of =<status>= when the mixer element is-       on. Defaults to "[on]".-     - Long option: =--on=--   - =-o= /string/ Off string--     - The string used in place of =<status>= when the mixer element is-       off. Defaults to "[off]".-     - Long option: =--off=--   - =-C= /color/ On color--     - The color to be used for =<status>= when the mixer element is on.-       Defaults to "green".-     - Long option: =--onc=--   - =-c= /color/ Off color--     - The color to be used for =<status>= when the mixer element is off.-       Defaults to "red".-     - Long option: =--offc=--   - =--highd= /number/ High threshold for dB. Defaults to -5.0.-   - =--lowd= /number/ Low threshold for dB. Defaults to -30.0.-   - =--volume-icon-pattern= /string/ dynamic string for current volume-     in =volumeipat=.-   - =-H= /number/ High threshold for volume (in %). Defaults to 60.0.--     - Long option: =--highv=--   - =-L= /number/ Low threshold for volume (in %). Defaults to 20.0.--     - Long option: =--lowv=--   - =-h=: /string/ High string--     - The string added in front of =<status>= when the mixer element is-       on and the volume percentage is higher than the =-H= threshold.-       Defaults to "".-     - Long option: =--highs=--   - =-m=: /string/ Medium string--     - The string added in front of =<status>= when the mixer element is-       on and the volume percentage is lower than the =-H= threshold.-       Defaults to "".-     - Long option: =--mediums=--   - =-l=: /string/ Low string--     - The string added in front of =<status>= when the mixer element is-       on and the volume percentage is lower than the =-L= threshold.-       Defaults to "".-     - Long option: =--lows=-- - Variables that can be used with the =-t/--template= argument:-   =volume=, =volumebar=, =volumevbar=, =volumeipat=, =dB=, =status=,-   =volumestatus=- - Note that =dB= might only return 0 on your system. This is known to-   happen on systems with a pulseaudio backend.- - Default template: =Vol: <volume>% <status>=- - Requires the package [[http://hackage.haskell.org/package/alsa-core][alsa-core]] and [[http://hackage.haskell.org/package/alsa-mixer][alsa-mixer]] installed in your-   system. In addition, to activate this plugin you must pass the-   =with_alsa= flag during compilation.--*** =Alsa Mixer Element Args=-- Like [[=Volume Mixer Element Args RefreshRate=][Volume]] but with the following differences:-- - Uses event-based refreshing via =alsactl monitor= instead of polling,-   so it will refresh instantly when there's a volume change, and won't-   use CPU until a change happens.- - Aliases to =alsa:= followed by the mixer name and element name-   separated by a colon. Thus, =Alsa "default" "Master" []= can be used-   as =%alsa:default:Master%=.- - Additional options (after the =--=):-   - =--alsactl=/path/to/alsactl=: If this option is not specified,-     =alsactl= will be sought in your =PATH= first, and failing that, at-     =/usr/sbin/alsactl= (this is its location on Debian systems.-     =alsactl monitor= works as a non-root user despite living in-     =/usr/sbin=.).-   - =stdbuf= (from coreutils) must be (and most probably already is) in-     your =PATH=.-** Mail Monitors-*** =Mail Args Alias=-- - Args: list of maildirs in form =[("name1","path1"),...]=. Paths may-   start with a '~' to expand to the user's home directory.-- - This plugin requires inotify support in your Linux kernel and the-   [[http://hackage.haskell.org/package/hinotify/][hinotify]] package. To activate, pass the =with_inotify= flag during-   compilation.-- - Example:--   #+begin_src haskell-     Run Mail [("inbox", "~/var/mail/inbox"),-               ("lists", "~/var/mail/lists")]-              "mail"-   #+end_src--*** =MailX Args Opts Alias=-- - Args: list of maildirs in form =[("name1","path1","color1"),...]=.-   Paths may start with a '~' to expand to the user's home directory.-   When mails are present, counts are displayed with the given name and-   color.-- - Opts is a possibly empty list of options, as flags. Possible values:-   -d dir --dir dir a string giving the base directory where maildir-   files with a relative path live. -p prefix --prefix prefix a string-   giving a prefix for the list of displayed mail counts -s suffix-   --suffix suffix a string giving a suffix for the list of displayed-   mail counts-- - This plugin requires inotify support in your Linux kernel and the-   [[http://hackage.haskell.org/package/hinotify/][hinotify]] package. To activate, pass the =with_inotify= flag during-   compilation.-- - Example:--   #+begin_src haskell-     Run MailX [("I", "inbox", "green"),-                ("L", "lists", "orange")]-               ["-d", "~/var/mail", "-p", " ", "-s", " "]-               "mail"-   #+end_src--*** =MBox Mboxes Opts Alias=-- - Mboxes a list of mbox files of the form =[("name", "path", "color")]=,-   where name is the displayed name, path the absolute or relative (to-   BaseDir) path of the mbox file, and color the color to use to display-   the mail count (use an empty string for the default).-- - Opts is a possibly empty list of options, as flags. Possible values:-   -a --all (no arg) Show all mailboxes, even if empty. -u (no arg) Show-   only the mailboxes' names, sans counts. -d dir --dir dir a string-   giving the base directory where mbox files with a relative path live.-   -p prefix --prefix prefix a string giving a prefix for the list of-   displayed mail counts -s suffix --suffix suffix a string giving a-   suffix for the list of displayed mail counts-- - Paths may start with a '~' to expand to the user's home directory.-- - This plugin requires inotify support in your Linux kernel and the-   [[http://hackage.haskell.org/package/hinotify/][hinotify]] package. To activate, pass the =with_inotify= flag during-   compilation.-- - Example. The following command look for mails in =/var/mail/inbox= and-   =~/foo/mbox=, and will put a space in front of the printed string-   (when it's not empty); it can be used in the template with the alias-   =mbox=:--   #+begin_src haskell-     Run MBox [("I ", "inbox", "red"), ("O ", "~/foo/mbox", "")]-              ["-d", "/var/mail/", "-p", " "] "mbox"-   #+end_src--*** =NotmuchMail Alias Args Rate=-- This plugin checks for new mail, provided that this mail is indexed by- =notmuch=. In the =notmuch= spirit, this plugin checks for new *threads*- and not new individual messages.-- - Alias: What name the plugin should have in your template string.-- - Args: A list of =MailItem= s of the form--   #+begin_src haskell-     [ MailItem "name" "address" "query"-     ...-     ]-   #+end_src--   where--   - =name= is what gets printed in the status bar before the number of-     new threads.-   - =address= is the e-mail address of the recipient, i.e. we only query-     mail that was send to this particular address (in more concrete-     terms, we pass the address to the =to:= constructor when performing-     the search). If =address= is empty, we search through all unread-     mail, regardless of whom it was sent to.-   - =query= is funneled to =notmuch search= verbatim. For the general-     query syntax, consult =notmuch search --help=, as well as-     =notmuch-search-terms(7)=. Note that the =unread= tag is *always*-     added in front of the query and composed with it via an *and*.-- - Rate: Rate with which to update the plugin (in deciseconds).-- - Example:--   - A single =MailItem= that displays all unread threads from the given-     address:--     #+begin_src haskell-       MailItem "mbs:" "soliditsallgood@mailbox.org" ""-     #+end_src--   - A single =MailItem= that displays all unread threads with-     "[My-Subject]" somewhere in the title:--     #+begin_src haskell-       MailItem "S:" "" "subject:[My-Subject]"-     #+end_src--   - A full example of a =NotmuchMail= configuration:--     #+begin_src haskell-       Run NotmuchMail "mail"  -- name for the template string-         [ -- All unread mail to the below address, but nothing that's tagged-           -- with @lists@ or @haskell@.-           MailItem "mbs:"-                    "soliditsallgood@mailbox.org"-                    "not tag:lists and not tag:haskell"--           -- All unread mail that has @[Haskell-Cafe]@ in the subject line.-         , MailItem "C:" "" "subject:[Haskell-Cafe]"--           -- All unread mail that's tagged as @lists@, but not @haskell@.-         , MailItem "H:" "" "tag:lists and not tag:haskell"-         ]-         600                   -- update every 60 seconds-     #+end_src--** Music Monitors-*** =MPD Args RefreshRate=-- - This monitor will only be compiled if you ask for it using the-   =with_mpd= flag. It needs [[http://hackage.haskell.org/package/libmpd/][libmpd]] 5.0 or later (available on Hackage).-- - Aliases to =mpd=-- - Args: default monitor arguments. In addition you can provide =-P=,-   =-S= and =-Z=, with an string argument, to represent the playing,-   stopped and paused states in the =statei= template field. The-   environment variables =MPD_HOST= and =MPD_PORT= are used to configure-   the mpd server to communicate with, unless given in the additional-   arguments =-p= (=--port=) and =-h= (=--host=). Also available:--   - =lapsed-icon-pattern=: dynamic string for current track position in-     =ipat=.-- - Variables that can be used with the =-t/--template= argument: =bar=,-   =vbar=, =ipat=, =state=, =statei=, =volume=, =length=, =lapsed=,-   =remaining=, =plength= (playlist length), =ppos= (playlist position),-   =flags= (ncmpcpp-style playback mode), =name=, =artist=, =composer=,-   =performer=, =album=, =title=, =track=, =file=, =genre=, =date=-- - Default template: =MPD: <state>=-- - Example (note that you need "--" to separate regular monitor options-   from MPD's specific ones):--   #+begin_src haskell-     Run MPD ["-t",-              "<composer> <title> (<album>) <track>/<plength> <statei> [<flags>]",-              "--", "-P", ">>", "-Z", "|", "-S", "><"] 10-   #+end_src--*** =MPDX Args RefreshRate Alias=-- Like =MPD= but uses as alias its last argument instead of "mpd".--*** =Mpris1 PlayerName Args RefreshRate=-- - Aliases to =mpris1=-- - Requires [[http://hackage.haskell.org/package/dbus][dbus]] and [[http://hackage.haskell.org/package/text][text]] packages. To activate, pass the =with_mpris=-   flag during compilation.-- - PlayerName: player supporting MPRIS v1 protocol. Some players need-   this to be an all lowercase name (e.g. "spotify"), but some others-   don't.-- - Args: default monitor arguments.-- - Variables that can be used with the =-t/--template= argument:-   =album=, =artist=, =arturl=, =length=, =title=, =tracknumber=-- - Default template: =<artist> - <title>=-- - Example:--   #+begin_src haskell-     Run Mpris1 "clementine" ["-t", "<artist> - [<tracknumber>] <title>"] 10-   #+end_src--*** =Mpris2 PlayerName Args RefreshRate=-- - Aliases to =mpris2=-- - Requires [[http://hackage.haskell.org/package/dbus][dbus]] and [[http://hackage.haskell.org/package/text][text]] packages. To activate, pass the =with_mpris=-   flag during compilation.-- - PlayerName: player supporting MPRIS v2 protocol. Some players need-   this to be an all lowercase name (e.g. "spotify"), but some others-   don't.-- - Args: default monitor arguments.-- - Variables that can be used with the =-t/--template= argument:-   =album=, =artist=, =arturl=, =length=, =title=, =tracknumber=,-   =composer=, =genre=-- - Default template: =<artist> - <title>=-- - Example:--   #+begin_src haskell-     Run Mpris2 "spotify" ["-t", "<artist> - [<composer>] <title>"] 10-   #+end_src-** Network Monitors-*** =Network Interface Args RefreshRate=-- - Aliases to the interface name: so =Network "eth0" []= can be used as-   =%eth0%=- - Thresholds refer to velocities expressed in Kb/s- - Args: default monitor arguments, plus:--   - =--rx-icon-pattern=: dynamic string for reception rate in =rxipat=.-   - =--tx-icon-pattern=: dynamic string for transmission rate in-     =txipat=.-   - =--up=: string used for the =up= variable value when the interface-     is up.-- - Variables that can be used with the =-t=/=--template= argument: =dev=,-   =rx=, =tx=, =rxbar=, =rxvbar=, =rxipat=, =txbar=, =txvbar=, =txipat=,-   =up=. Reception and transmission rates (=rx= and =tx=) are displayed-   by default as Kb/s, without any suffixes, but you can set the =-S= to-   "True" to make them displayed with adaptive units (Kb/s, Mb/s, etc.).- - Default template: =<dev>: <rx>KB|<tx>KB=--*** =DynNetwork Args RefreshRate=-- - Active interface is detected automatically- - Aliases to "dynnetwork"- - Thresholds are expressed in Kb/s- - Args: default monitor arguments, plus:-- - =--rx-icon-pattern=: dynamic string for reception rate in =rxipat=.- - =--tx-icon-pattern=: dynamic string for transmission rate in =txipat=- - =--devices=: comma-separated list of devices to show.-- - Variables that can be used with the =-t=/=--template= argument:-   =dev=, =rx=, =tx=, =rxbar=, =rxvbar=, =rxipat=, =txbar=, =txvbar=,-   =txipat=.-- Reception and transmission rates (=rx= and =tx=) are displayed in Kbytes- per second, and you can set the =-S= to "True" to make them displayed- with units (the string "Kb/s").- - Default template: =<dev>: <rx>KB|<tx>KB=- - Example of usage of =--devices= option:--     =["--", "--devices", "wlp2s0,enp0s20f41"]=--*** =Wireless Interface Args RefreshRate=-- - If set to "", first suitable wireless interface is used.- - Aliases to the interface name with the suffix "wi": thus,-   =Wireless   "wlan0" []= can be used as =%wlan0wi%=, and-   =Wireless "" []= as =%wi%=.- - Args: default monitor arguments, plus:--   - =--quality-icon-pattern=: dynamic string for connection quality in-     =qualityipat=.-- - Variables that can be used with the =-t=/=--template= argument:-   =ssid=, =signal=, =quality=, =qualitybar=, =qualityvbar=,-   =qualityipat=- - Thresholds refer to link quality on a =[0, 100]= scale. Note that-   =quality= is calculated from =signal= (in dBm) by a possibly lossy-   conversion. It is also not taking into account many factors such as-   noise level, air busy time, transcievers' capabilities and the others-   which can have drastic impact on the link performance.- - Default template: =<ssid> <quality>=- - To activate this plugin you must pass the =with_nl80211= or the-   =with_iwlib= flag during compilation.-** Weather Monitors-*** =Weather StationID Args RefreshRate=-- - Aliases to the Station ID: so =Weather "LIPB" []= can be used in-   template as =%LIPB%=- - Thresholds refer to temperature in the selected units- - Args: default monitor arguments, plus:--   - =--weathers= /string/ : display a default string when the =weather=-     variable is not reported.--     - short option: =-w=-     - Default: ""--   - =--useManager= /bool/ : Whether to use one single manager per-     monitor for managing network connections or create a new one every-     time a connection is made.--     - Short option: =-m=-     - Default: True-- - Variables that can be used with the =-t/--template= argument:-   =station=, =stationState=, =year=, =month=, =day=, =hour=,-   =windCardinal=, =windAzimuth=, =windMph=, =windKnots=, =windMs=,-   =windKmh= =visibility=, =skyCondition=, =weather=, =tempC=, =tempF=,-   =dewPointC=, =dewPointF=, =rh=, =pressure=- - Default template: =<station>: <tempC>C, rh <rh>% (<hour>)=- - Retrieves weather information from http://tgftp.nws.noaa.gov. Here is-   an [[https://tgftp.nws.noaa.gov/data/observations/metar/decoded/CYLD.TXT][example]], also showcasing the kind of information that may be-   extracted. Here is [[https://weather.rap.ucar.edu/surface/stations.txt][a sample list of station IDs]].--*** =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 (typically a-   unicode string or an icon specification).- - Use the variable =skyConditionS= to display the replacement of the-   corresponding sky condition. All other =Weather= template variables-   are available as well.-- For example:-- #+begin_src haskell-   WeatherX "LEBL"-            [ ("clear", "🌣")-            , ("sunny", "🌣")-            , ("mostly clear", "🌤")-            , ("mostly sunny", "🌤")-            , ("partly sunny", "⛅")-            , ("fair", "🌑")-            , ("cloudy","☁")-            , ("overcast","☁")-            , ("partly cloudy", "⛅")-            , ("mostly cloudy", "🌧")-            , ("considerable cloudiness", "⛈")]-            ["-t", "<fn=2><skyConditionS></fn> <tempC>° <rh>%  <windKmh> (<hour>)"-            , "-L","10", "-H", "25", "--normal", "black"-            , "--high", "lightgoldenrod4", "--low", "darkseagreen4"]-            18000- #+end_src-- As mentioned, the replacement string can also be an icon specification,- such as =("clear", "<icon=weather-clear.xbm/>")=.-** Other Monitors-*** =Brightness Args RefreshRate=-- - Aliases to =bright=-- - Args: default monitor arguments, plus the following specif ones:--   - =-D=: directory in =/sys/class/backlight/= with files in it-     (default: "acpi_video0")-   - =-C=: file with the current brightness (default: actual_brightness)-   - =-M=: file with the maximum brightness (default: max_brightness)-   - =--brightness-icon-pattern=: dynamic string for current brightness-     in =ipat=.-- - Variables that can be used with the =-t/--template= argument:-   =vbar=, =percent=, =bar=, =ipat=-- - Default template: =<percent>=-- - Example:--   #+begin_src haskell-     Run Brightness ["-t", "<bar>"] 60-   #+end_src--*** =CatInt n filename=-- - Reads and displays an integer from the file whose path is =filename=-   (especially useful with files in =/sys=).-- - Aliases as =catn= (e.g. =Cat 0= as =cat0=, etc.) so you can have-   several.-- - Example:--   #+begin_src haskell-     Run CatInt 0 "/sys/devices/platform/thinkpad_hwmon/fan1_input" [] 50-   #+end_src--*** =CommandReader "/path/to/program" Alias=-- - Runs the given program, and displays its standard output.--*** =Uptime Args RefreshRate=-- - Aliases to =uptime=- - Args: default monitor arguments. The low and high thresholds refer to-   the number of days.- - Variables that can be used with the =-t/--template= argument: =days=,-   =hours=, =minutes=, =seconds=. The total uptime is the sum of all-   those fields. You can set the =-S= argument to =True= to add units to-   the display of those numeric fields.- - Default template: =Up: <days>d <hours>h <minutes>m=--*** =UVMeter=-- - Aliases to "uv" + station id. For example: =%uv Brisbane%= or-   =%uv   Alice Springs%=-- - Args: default monitor arguments, plus:--   - =--useManager= /bool/ : Whether to use one single manager per-     monitor for managing network connections or create a new one every-     time a connection is made.--     - Short option: =-m=-     - Default: True-- - /Reminder:/ Keep the refresh rate high, to avoid making unnecessary-   requests every time the plug-in is run.-- - Station IDs can be found here:-   http://www.arpansa.gov.au/uvindex/realtime/xml/uvvalues.xml-- - Example:--   #+begin_src haskell-     Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900-   #+end_src--* Interfacing with Window Managers--  Listed below are ways to interface xmobar with your window manager-  of choice.--** Property-based Logging-*** =XMonadLog=-- - Aliases to XMonadLog-- - Displays information from xmonad's =_XMONAD_LOG=. You can use this by-   using functions from the [[https://hackage.haskell.org/package/xmonad-contrib-0.16/docs/XMonad-Hooks-DynamicLog.html][XMonad.Hooks.DynamicLog]] module. By using the-   =xmonadPropLog= function in your logHook, you can write the the above-   property. The following shows a minimal xmonad configuration that-   spawns xmobar and then writes to the =_XMONAD_LOG= property.--   #+begin_src haskell-     main = do-       spawn "xmobar"-       xmonad $ def-         { logHook = dynamicLogString defaultPP >>= xmonadPropLog-         }-   #+end_src--   This plugin can be used as a sometimes more convenient alternative to-   =StdinReader=. For instance, it allows you to (re)start xmobar outside-   xmonad.--*** =UnsafeXMonadLog=-- - Aliases to UnsafeXMonadLog- - Displays any text received by xmobar on the =_XMONAD_LOG= atom.- - Will not do anything to the text received. This means you can pass-   xmobar dynamic actions. Be careful to escape (using =<raw=…>=) or-   remove tags from dynamic text that you pipe through to xmobar in this-   way.-- - Sample usage: Send the list of your workspaces, enclosed by actions-   tags, to xmobar.  This enables you to switch to a workspace when you-   click on it in xmobar!--   #+begin_src shell-     <action=`xdotool key alt+1`>ws1</action> <action=`xdotool key alt+1`>ws2</action>-   #+end_src-- - If you use xmonad, It is advised that you still use =xmobarStrip= for-   the =ppTitle= in your logHook:--   #+begin_src haskell-     myPP = defaultPP { ppTitle = xmobarStrip }-     main = xmonad $ def-       { logHook = dynamicLogString myPP >>= xmonadPropLog-       }-   #+end_src--*** =XPropertyLog PropName=-- - Aliases to =PropName=- - Reads the X property named by =PropName= (a string) and displays its-   value. The [[https://github.com/jaor/xmobar/raw/master/examples/xmonadpropwrite.hs][examples/xmonadpropwrite.hs script]] in xmobar's distribution-   can be used to set the given property from the output of any other-   program or script.--*** =UnsafeXPropertyLog PropName=-- - Aliases to =PropName=- - Same as =XPropertyLog= but the input is not filtered to avoid-   injection of actions (cf. =UnsafeXMonadLog=). The program writing the-   value of the read property is responsible of performing any needed-   cleanups.--*** =NamedXPropertyLog PropName Alias=-- - Aliases to =Alias=- - Same as =XPropertyLog= but a custom alias can be specified.--*** =UnsafeNamedXPropertyLog PropName Alias=-- - Aliases to =Alias=- - Same as =UnsafeXPropertyLog=, but a custom alias can be specified.--** Logging via Stdin-*** =StdinReader=-- - Aliases to StdinReader- - Displays any text received by xmobar on its standard input.- - Strips actions from the text received. This means you can't pass-   dynamic 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=-- - Aliases to UnsafeStdinReader- - Displays any text received by xmobar on its standard input.- - Similar to [[=UnsafeXMonadLog=][UnsafeXMonadLog]], in the sense that it does not strip any-   actions from the received text, only using =stdin= and not a property-   atom of the root window. Please be equally carefully when using this-   as when using =UnsafeXMonadLog=!--** Pipe-based Logging-*** =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=-- - Generally equivalent to PipeReader-- - Text is displayed as marquee with the specified length, rate in 10th-   seconds and separator when it wraps around--   #+begin_src haskell-     Run MarqueePipeReader "/tmp/testpipe" (10, 7, "+") "mpipe"-   #+end_src-- - Expands environment variables in the first argument--*** =BufferedPipeReader Alias [(Timeout, Bool, "/path/to/pipe1"), ..]=-- - Display data from multiple pipes.-- - Timeout (in tenth of seconds) is the value after which the previous-   content is restored i.e. if there was already something from a-   previous pipe it will be put on display again, overwriting the current-   status.-- - A pipe with Timeout of 0 will be displayed permanently, just like-   =PipeReader=-- - The boolean option indicates whether new data for this pipe should-   make xmobar appear (unhide, reveal). In this case, the Timeout-   additionally specifies when the window should be hidden again. The-   output is restored in any case.-- - Use it for OSD-like status bars e.g. for setting the volume or-   brightness:--   #+begin_src haskell-     Run BufferedPipeReader "bpr"-         [ (  0, False, "/tmp/xmobar_window"  )-         , ( 15,  True, "/tmp/xmobar_status"  )-         ]-   #+end_src--   Have your window manager send window titles to =/tmp/xmobar_window=.-   They will always be shown and not reveal your xmobar. Sending some-   status information to =/tmp/xmobar_status= will reveal xmonad for 1.5-   seconds and temporarily overwrite the window titles.-- - Take a look at [[http://github.com/jaor/xmobar/raw/master/examples/status.sh][examples/status.sh]]-- - Expands environment variables for the pipe path--** Handle-based Logging-*** =HandleReader Handle Alias=-- - Display data from a Haskell =Handle=-- - This plugin is only useful if you are running xmobar from another-   Haskell program like XMonad.-- - You can use =System.Process.createPipe= to create a pair of =read= &-   =write= Handles. Pass the =read= Handle to HandleReader and write your-   output to the =write= Handle:--   #+begin_src haskell-     (readHandle, writeHandle) <- createPipe-     xmobarProcess <- forkProcess $ xmobar myConfig-             { commands =-                 Run (HandleReader readHandle "handle") : commands myConfig-             }-     hPutStr writeHandle "Hello World"-   #+end_src--** Software Transactional Memory--   When invoking xmobar from other Haskell code it can be easier and-   more performant to use shared memory.  The following plugins-   leverage =Control.Concurrent.STM= to realize these gains for xmobar.--*** =QueueReader (TQueue a) (a -> String) String=-- - Display data from a Haskell =TQueue a=.-- - This plugin is only useful if you are running xmobar from another-   haskell program like xmonad.-- - You should make an =IO= safe =TQueue a= with =Control.Concurrent.STM.newTQueueIO=.-   Write to it from the user code with =writeTQueue=, and read with =readTQueue=.-   A common use is to overwite =ppOutput= from =XMonad.Hooks.DynamicLog= as shown-   below.--   #+begin_src haskell-     main :: IO ()-     main = do-       q <- STM.newTQueueIO @String-       bar <- forkIO $ xmobar myConf-         { commands = Run (QueueReader q id "XMonadLog") : commands myConf }-       xmonad $ def { logHook = logWorkspacesToQueue q }--     logWorkspacesToQueue :: STM.TQueue String -> X ()-     logWorkspacesToQueue q =-       dynamicLogWithPP def { ppOutput = STM.atomically . STM.writeTQueue q }-       where-         -- Manage the PrettyPrinting configuration here.-         ppLayout' :: String -> String-         ppLayout' "Spacing Tall"        = xpm "layout-spacing-tall"-         ppLayout' "Spacing Mirror Tall" = xpm "layout-spacing-mirror"-         ppLayout' "Spacing Full"        = xpm "layout-full"-         ppLayout' x = x--         icon :: String -> String-         icon path = "<icon=" ++ path ++ "/>"--         xpm :: String -> String-         xpm = icon . (++ ".xpm")-   #+end_src--* 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 arguments, or you can configure it in the "commands"-  configuration option list with the Com template command:--  =Com ProgramName Args Alias RefreshRate=--  - ProgramName: the name of the program-  - Args: the arguments to be passed to the program at execution time-  - RefreshRate: number of tenths of second between re-runs of the-    command. A zero or negative rate means that the command will be-    executed only once.-  - Alias: a name to be used in the template. If the alias is en empty-    string the program name can be used in the template.--  E.g.:--  #+begin_src haskell-    Run Com "uname" ["-s","-r"] "" 0-  #+end_src--  can be used in the output template as =%uname%= (and xmobar will call-  /uname/ only once), while--  #+begin_src haskell-    Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600-  #+end_src--  can be used in the output template as =%mydate%=.--  Sometimes, you don't mind if the command executed exits with an-  error, or you might want to display a custom message in that-  case. To that end, you can use the =ComX= variant:--    =ComX ProgramName Args ExitMessage Alias RefreshRate=--  Works like =Com=, but displaying =ExitMessage= (a string) if the-  execution fails. For instance:--  #+begin_src haskell-    Run ComX "date" ["+\"%a %b %_d %H:%M\""] "N/A" "mydate" 600-  #+end_src--  will display "N/A" if for some reason the =date= invocation fails.--* The DBus Interface--  When compiled with the optional =with_dbus= flag, xmobar can be-  controlled over dbus. All signals defined in [[https://github.com/jaor/xmobar/blob/master/src/Xmobar/System/Signal.hs][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.--  - 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:--  #+begin_src shell-  dbus-send \-      --session \-      --dest=org.Xmobar.Control \-      --type=method_call \-      --print-reply \-      '/org/Xmobar/Control' \-      org.Xmobar.Control.SendSignal \-      "string:Toggle 0"-  #+end_src--  It is also possible to send multiple signals at once:--  #+begin_src shell-    # send to another screen, reveal and toggle the persistent flag-    dbus-send [..] \-        "string:ChangeScreen 0" "string:Reveal 0" "string:TogglePersistent"-  #+end_src--  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.--   #+begin_src haskell-     ((0, xK_Alt_L), pure ())-   #+end_src--   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).--   #+begin_src haskell-     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-   #+end_src+#+title: Plugins and monitors++* 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 is set: we mention that fact, when needed, in their+  description.++  Each monitor has an =alias= to be used in the output+  template. Monitors may have default aliases, see the documentation+  of the monitor in question.++  There are two types of arguments: ones that all monitors share (the+  so called /default monitor arguments/) and arguments that are specific+  to a certain monitor.++  All Monitors accept a common set of arguments, described below in+  [[Default Monitor Arguments]]. Some monitors also accept additional+  options that are specific to them. When specifying the list of+  arguments in your configuration, the common options come first,+  followed by =--=, followed by any monitor-specific options. For+  example, the following [[=Battery Args RefreshRate=][Battery]] configuration first sets the global+  =template= and =Low= arguments and then specifies the battery-specific+  =off= option.++  #+begin_src haskell+    Run Battery+      [ "--template", "<acstatus>"+      , "--Low"     , "15"+      -- battery specific options start here.+      , "--"+      , "--off"     , "<left> (<timeleft>)"+      ]+      100+  #+end_src++  See also [[./window-managers.org][Interfacing with window managers]] for a collection of+  plugins that let you interact and control xmobar from window+  managers.++*** 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+    (i.e. =<icon=/path/to/icon_%%.xpm/>= will be interpreted as+    =<icon=/path/to/icon_3.xpm/>= when the value is =3=, also =%= is+    interpreted as =%=, =%%= as =3=, =%%%= as =3%=, =%%%%= as =33= and so+    on). Essentially it allows to replace vertical bars with custom+    icons. For example,++    #+begin_src haskell+      Run Brightness+        [ "-t", "<ipat>"+        , "--"+        , "--brightness-icon-pattern", "<icon=bright_%%.xpm/>"+        ] 30+    #+end_src++    Will display =bright_0.xpm= to =bright_8.xpm= depending on current+    brightness value.++*** Default Monitor Arguments++    These are the options available for all monitors:++    - =-t= /string/ Output template++      - Template for the monitor output. Field names must be enclosed+        between pointy brackets (=<foo>=) and will be substituted by the+        computed values. You can also specify the foreground (and+        optionally, background) color for a region by bracketing it between+        =<fc=fgcolor>= (or =<fc=fgcolor,bgcolor>=) and =</fc>=. The rest of+        the template is output verbatim.+      - Long option: =--template=+      - Default value: per monitor (see above).++    - =-H= /number/ The high threshold.++      - Numerical values higher than /number/ will be displayed with the+        color specified by =-h= (see below).+      - Long option: =--High=+      - Default value: 66++    - =-L= /number/ The low threshold.++      - Numerical values higher than /number/ and lower than the high+        threshold will be displayed with the color specified by =-n= (see+        below). Values lower than /number/ will use the =-l= color.+      - Long option: =--Low=+      - Default value: 33++    - =-h= /color/ High threshold color.++      - Color for displaying values above the high threshold. /color/ can be+        either a name (e.g. "blue") or an hexadecimal RGB (e.g. "#FF0000").+      - Long option: =--high=+      - Default: none (use the default foreground).++    - =-n= /color/ Color for 'normal' values++      - Color used for values greater than the low threshold but lower than+        the high one.+      - Long option: =--normal=+      - Default: none (use the default foreground).++    - =-l= /color/ The low threshold color++      - Color for displaying values below the low threshold.+      - Long option: =--low=+      - Default: none (use the default foreground).++    - =-S= /boolean/ Display optional suffixes++      - When set to a true designator ("True", "Yes" or "On"), optional+        value suffixes such as the '%' symbol or optional units will be+        displayed.+      - Long option: =--suffix=+      - Default: False.++    - =-p= /number/ Percentages padding++      - Width, in number of digits, for quantities representing percentages.+        For instance =-p 3= means that all percentages in the monitor will+        be represented using 3 digits.+      - Long option: =--ppad=+      - Default value: 0 (don't pad)++    - =-d= /number/ Decimal digits++      - Number of digits after the decimal period to use in float values.+      - Long option: =--ddigits=+      - Default value: 0 (display only integer part)++    - =-m= /number/ Minimum field width++      - Minimum width, in number of characters, of the fields in the monitor+        template. Values whose printed representation is shorter than this+        value will be padded using the padding characters given by the =-c=+        option with the alignment specified by =-a= (see below).+      - Long option: =--minwidth=+      - Default: 0++    - =-M= /number/ Maximum field width++      - Maximum width, in number of characters, of the fields in the monitor+        template. Values whose printed representation is longer than this+        value will be truncated.+      - Long option: =--maxwidth=+      - Default: 0 (no maximum width)++    - =-e= /string/ Maximum width ellipsis++      - Ellipsis to be added to the field when it has reached its max width.+      - Long option: =--maxwidthellipsis=+      - Default: "" (no ellipsis)++    - =-w= /number/ Fixed field width++      - All fields will be set to this width, padding or truncating as+        needed.+      - Long option: =--width=+      - Default: 0 (variable width)++    - =-T= /number/ Maximum total width++      - Maximum total width of the text.+      - Long option: =--maxtwidth=+      - Default: 0 (no limit)++    - =-E= /string/ Maximum total width ellipsis++      - Ellipsis to be added to the total text when it has reached its max+        width.+      - Long option: =--maxtwidthellipsis=+      - Default: "" (no ellipsis)++    - =-c= /string/++      - Characters used for padding. The characters of /string/ are used+        cyclically. E.g., with =-P +- -w 6=, a field with value "foo" will+        be represented as "+-+foo".+      - Long option: =--padchars=+      - Default value: " "++    - =-a= r|l Field alignment++      - Whether to use right (r) or left (l) alignment of field values when+        padding.+      - Long option: =--align=+      - Default value: r (padding to the left)++    - =-b= /string/ Bar background++      - Characters used, cyclically, to draw the background of bars. For+        instance, if you set this option to "·.", an empty bar will look+        like this: =·.·.·.·.·.=+      - Long option: =--bback=+      - Default value: ":"++    - =-f= /string/ Bar foreground++      - Characters used, cyclically, to draw the foreground of bars.+      - Long option: =--bfore=+      - Default value: "#"++    - =-W= /number/ Bar width++      - 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=+      - Default value: "N/A"++    Commands' arguments must be set as a list. E.g.:++    #+begin_src haskell+      Run Weather "EGPF" ["-t", "<station>: <tempC>C"] 36000+    #+end_src++    In this case xmobar will run the weather monitor, getting information+    for the weather station ID EGPF (Glasgow Airport, as a homage to GHC)+    every hour (36000 tenth of seconds), with a template that will output+    something like:++    #+begin_src shell+      Glasgow Airport: 16.0C+    #+end_src++*** Battery Monitors+***** =Battery Args RefreshRate=++      Same as++      #+begin_src haskell+        BatteryP ["BAT", "BAT0", "BAT1", "BAT2"] Args RefreshRate+      #+end_src++***** =BatteryP Dirs Args RefreshRate=++      - Aliases to =battery=++      - Dirs: list of directories in =/sys/class/power_supply/= where to look+        for the ACPI files of each battery. Example: =["BAT0","BAT1","BAT2"]=.+        Only up to 3 existing directories will be searched.++      - Args: default monitor arguments, plus the following specific ones+        (these options, being specific to the monitor, are to be specified+        after a =--= in the argument list):++        - =-O=: string for AC "on" status (default: "On")+        - =-i=: string for AC "idle" status (default: "On")+        - =-o=: string for AC "off" status (default: "Off")+        - =-L=: low power (=watts=) threshold (default: 10)+        - =-H=: high power threshold (default: 12)+        - =-l=: color to display power lower than the =-L= threshold+        - =-m=: color to display power lower than the =-H= threshold+        - =-h=: color to display power higher than the =-H= threshold+        - =-p=: color to display positive power (battery charging)+        - =-f=: file in =/sys/class/power_supply= with AC info (default:+          "AC/online")+        - =-A=: a number between 0 and 100, threshold below which the action+          given by =-a=, if any, is performed (default: 5)+        - =-a=: a string with a system command that is run when the percentage+          left in the battery is less or equal than the threshold given by the+          =-A= option. If not present, no action is undertaken.+        - =-P=: to include a percentage symbol in =left=.+        - =--on-icon-pattern=: dynamic string for current battery charge when+          AC is "on" in =leftipat=.+        - =--off-icon-pattern=: dynamic string for current battery charge when+          AC is "off" in =leftipat=.+        - =--idle-icon-pattern=: dynamic string for current battery charge+          when AC is "idle" in =leftipat=.+        - =--lows=: string for AC "off" status and power lower than the =-L=+          threshold (default: "")+        - =--mediums=: string for AC "off" status and power lower than the+          =-H= threshold (default: "")+        - =--highs=: string for AC "off" status and power higher than the =-H=+          threshold (default: "")++      - Variables that can be used with the =-t/--template= argument:+        =left=, =leftbar=, =leftvbar=, =leftipat=, =timeleft=, =watts=,+        =acstatus=++      - Default template: =Batt: <watts>, <left>% / <timeleft>=++      - Example (note that you need "--" to separate regular monitor options+        from Battery's specific ones):++        #+begin_src haskell+          Run BatteryP ["BAT0"]+                       ["-t", "<acstatus><watts> (<left>%)",+                        "-L", "10", "-H", "80", "-p", "3",+                        "--", "-O", "<fc=green>On</fc> - ", "-i", "",+                        "-L", "-15", "-H", "-5",+                        "-l", "red", "-m", "blue", "-h", "green",+                        "-a", "notify-send -u critical 'Battery running out!!'",+                        "-A", "3"]+                       600+        #+end_src++        In the above example, the thresholds before the =--= separator affect+        only the =<left>= and =<leftbar>= fields, while those after the+        separator affect how =<watts>= is displayed. For this monitor, neither+        the generic nor the specific options have any effect on =<timeleft>=.+        We are also telling the monitor to execute the unix command+        =notify-send= when the percentage left in the battery reaches 6%.++        It is also possible to specify template variables in the =-O= and =-o=+        switches, as in the following example:++        #+begin_src haskell+          Run BatteryP ["BAT0"]+                       ["-t", "<acstatus>"+                       , "-L", "10", "-H", "80"+                       , "-l", "red", "-h", "green"+                       , "--", "-O", "Charging", "-o", "Battery: <left>%"+                       ] 10+        #+end_src++      - The "idle" AC state is selected whenever the AC power entering the+        battery is zero.++***** =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.+*** Cpu and Memory Monitors+***** =Cpu Args RefreshRate=++      - Aliases to =cpu=+      - Args: default monitor arguments, plus:++        - =--load-icon-pattern=: dynamic string for cpu load in =ipat=++      - Thresholds refer to percentage of CPU load+      - Variables that can be used with the =-t/--template= argument:+        =total=, =bar=, =vbar=, =ipat=, =user=, =nice=, =system=, =idle=,+        =iowait=+      - Default template: =Cpu: <total>%=++***** =MultiCpu Args RefreshRate=++      - Aliases to =multicpu=+      - Args: default monitor arguments, plus:++        - =--load-icon-pattern=: dynamic string for overall cpu load in+          =ipat=.+        - =--load-icon-patterns=: dynamic string for each cpu load in+          =autoipat=, =ipat{i}=. This option can be specified several times.+          nth option corresponds to nth cpu.+        - =--fallback-icon-pattern=: dynamic string used by =autoipat= and+          =ipat{i}= when no =--load-icon-patterns= has been provided for+          =cpu{i}=+        - =--contiguous-icons=: flag (no value needs to be provided) that+          causes the load icons to be drawn without padding.++      - Thresholds refer to percentage of CPU load+      - Variables that can be used with the =-t/--template= argument:+        =autototal=, =autobar=, =autovbar=, =autoipat=, =autouser=,+        =autonice=, =autosystem=, =autoidle=, =total=, =bar=, =vbar=, =ipat=,+        =user=, =nice=, =system=, =idle=, =total0=, =bar0=, =vbar0=, =ipat0=,+        =user0=, =nice0=, =system0=, =idle0=, ... The auto* variables+        automatically detect the number of CPUs on the system and display one+        entry for each.+      - Default template: =Cpu: <total>%=++***** =CpuFreq Args RefreshRate=++      - Aliases to =cpufreq=++      - Args: default monitor arguments++      - Thresholds refer to frequency in GHz++      - Variables that can be used with the =-t/--template= argument:+        =cpu0=, =cpu1=, .., =cpuN=++      - Default template: =Freq: <cpu0>GHz=++      - This monitor requires acpi_cpufreq module to be loaded in kernel++      - Example:++        #+begin_src haskell+          Run CpuFreq ["-t", "Freq:<cpu0>|<cpu1>GHz", "-L", "0", "-H", "2",+                       "-l", "lightblue", "-n","white", "-h", "red"] 50+        #+end_src++***** =CoreTemp Args RefreshRate=++      - Aliases to =coretemp=++      - Args: default monitor arguments++      - Thresholds refer to temperature in degrees++      - Variables that can be used with the =-t/--template= argument:+        =core0=, =core1=, .., =coreN=++      - Default template: =Temp: <core0>C=++      - This monitor requires coretemp module to be loaded in kernel++      - Example:++        #+begin_src haskell+          Run CoreTemp ["-t", "Temp:<core0>|<core1>C",+                        "-L", "40", "-H", "60",+                        "-l", "lightblue", "-n", "gray90", "-h", "red"] 50+        #+end_src++***** =MultiCoreTemp Args RefreshRate=++      - Aliases to =multicoretemp=++      - Args: default monitor arguments, plus:++        - =--max-icon-pattern=: dynamic string for overall cpu load in+          =maxipat=.+        - =--avg-icon-pattern=: dynamic string for overall cpu load in+          =avgipat=.+        - =--mintemp=: temperature in degree Celsius, that sets the lower+          limit for percentage calculation.+        - =--maxtemp=: temperature in degree Celsius, that sets the upper+          limit for percentage calculation.+        - =--hwmon-path=: this monitor tries to find coretemp devices by+          looking for them in directories following the pattern+          =/sys/bus/platform/devices/coretemp.*/hwmon/hwmon*=, but some+          processors (notably Ryzen) might expose those files in a different+          tree (e.g., Ryzen) puts them somewhere in "/sys/class/hwmon/hwmon*",+          and the lookup is most costly. With this option, it is possible to+          explicitly specify the full path to the directory where the+          =tempN_label= and =tempN_input= files are located.++      - Thresholds refer to temperature in degree Celsius++      - Variables that can be used with the =-t/--template= argument: =max=,+        =maxpc=, =maxbar=, =maxvbar=, =maxipat=, =avg=, =avgpc=, =avgbar=,+        =avgvbar=, =avgipat=, =core0=, =core1=, ..., =coreN=++        The /pc, /bar, /vbar and /ipat variables are showing percentages on+        the scale defined by =--mintemp= and =--maxtemp=. The max* and avg*+        variables to the highest and the average core temperature.++      - Default template: =Temp: <max>°C - <maxpc>%=++      - This monitor requires coretemp module to be loaded in kernel++      - Example:++        #+begin_src haskell+          Run MultiCoreTemp ["-t", "Temp: <avg>°C | <avgpc>%",+                             "-L", "60", "-H", "80",+                             "-l", "green", "-n", "yellow", "-h", "red",+                             "--", "--mintemp", "20", "--maxtemp", "100"] 50+        #+end_src++***** =K10Temp Slot Args RefreshRate=++      - Aliases to =k10temp=++      - Slot: The PCI slot address of the k10temp device as a string.  You+        can find it as a subdirectory in =/sys/bus/pci/drivers/k10temp/=.++      - Args: default monitor arguments++      - Thresholds refer to temperature in degrees++      - Variables that can be used with the =-t/--template= argument:+        =Tctl=, =Tdie=, =Tccd1=, .., =Tccd8=++      - Default template: =Temp: <Tdie>C=++      - This monitor requires k10temp module to be loaded in kernel++      - It is important to note that not all measurements are available+        on on all models of processor. Of particular importance - Tdie+        (used in the default template) may not be present on processors+        prior to Zen (17h). Tctl, however, may be offset from the real+        temperature and so is not used by default.++      - Example:++        #+begin_src haskell+          Run K10Temp "0000:00:18.3"+                      ["-t", "Temp: <Tdie>C|<Tccd1>C",+                       "-L", "40", "-H", "60",+                       "-l", "lightblue", "-n", "gray90", "-h", "red"]+                      50+        #+end_src+++***** =Memory Args RefreshRate=++      - Aliases to =memory=+      - Args: default monitor arguments, plus:++        - =--used-icon-pattern=: dynamic string for used memory ratio in+          =usedipat=.+        - =--free-icon-pattern=: dynamic string for free memory ratio in+          =freeipat=.+        - =--available-icon-pattern=: dynamic string for available memory+          ratio in =availableipat=.++      - Thresholds refer to percentage of used memory+      - Variables that can be used with the =-t/--template= argument:+        =total=, =free=, =buffer=, =cache=, =available=, =used=, =usedratio=,+        =usedbar=, =usedvbar=, =usedipat=, =freeratio=, =freebar=, =freevbar=,+        =freeipat=, =availableratio=, =availablebar=, =availablevbar=,+        =availableipat=+      - Default template: =Mem: <usedratio>% (<cache>M)=++***** =Swap Args RefreshRate=++      - Aliases to =swap=+      - Args: default monitor arguments+      - Thresholds refer to percentage of used swap+      - Variables that can be used with the =-t/--template= argument:+        =total=, =used=, =free=, =usedratio=+      - Default template: =Swap: <usedratio>%=++*** Date Monitors+***** =Date Format Alias RefreshRate=++      - Format is a time format string, as accepted by the standard ISO C+        =strftime= function (or Haskell's =formatCalendarTime=).  Basically,+        if =date +"my-string"= works with your command then =Date= will handle+        it correctly.++      - Timezone changes are picked up automatically every minute.++      - Sample usage:++        #+begin_src haskell+          Run Date "%a %b %_d %Y <fc=#ee9a00>%H:%M:%S</fc>" "date" 10+        #+end_src++***** =DateZone Format Locale Zone Alias RefreshRate=++      A variant of the =Date= monitor where one is able to explicitly set the+      time-zone, as well as the locale.++      - The format of =DateZone= is exactly the same as =Date=.++      - If =Locale= is =""= (the empty string) the default locale of the+        system is used, otherwise use the given locale. If there are more+        instances of =DateZone=, using the empty string as input for =Locale=+        is not recommended.++      - =Zone= is the name of the =TimeZone=. It is assumed that the time-zone+        database is stored in =/usr/share/zoneinfo/=. If the empty string is+        given as =Zone=, the default system time is used.++      - Sample usage:++        #+begin_src haskell+          Run DateZone "%a %H:%M:%S" "de_DE.UTF-8" "Europe/Vienna" "viennaTime" 10+        #+end_src+*** Disk Monitors+***** =DiskU Disks Args RefreshRate=++      - Aliases to =disku=++      - Disks: list of pairs of the form (device or mount point, template),+        where the template can contain =<size>=, =<free>=, =<used>=, =<freep>=+        or =<usedp>=, =<freebar>=, =<freevbar>=, =<freeipat>=, =<usedbar>=,+        =<usedvbar>= or =<usedipat>= for total, free, used, free percentage+        and used percentage of the given file system capacity.++      - Thresholds refer to usage percentage.++      - Args: default monitor arguments. =-t/--template= is ignored. Plus++        - =--free-icon-pattern=: dynamic string for free disk space in+          =freeipat=.+        - =--used-icon-pattern=: dynamic string for used disk space in+          =usedipat=.++      - Default template: none (you must specify a template for each file+        system).++      - Example:++        #+begin_src haskell+          DiskU [("/", "<used>/<size>"), ("sdb1", "<usedbar>")]+                ["-L", "20", "-H", "50", "-m", "1", "-p", "3"]+                20+        #+end_src++***** =DiskIO Disks Args RefreshRate=++      - Aliases to =diskio=++      - Disks: list of pairs of the form (device or mount point, template),+        where the template can contain =<total>=, =<read>=, =<write>= for+        total, read and write speed, respectively, as well as =<totalb>=,+        =<readb>=, =<writeb>=, which report number of bytes during the last+        refresh period rather than speed. There are also bar versions of each:+        =<totalbar>=, =<totalvbar>=, =<totalipat>=, =<readbar>=, =<readvbar>=,+        =<readipat>=, =<writebar>=, =<writevbar>=, and =<writeipat>=; and+        their "bytes" counterparts: =<totalbbar>=, =<totalbvbar>=,+        =<totalbipat>=, =<readbbar>=, =<readbvbar>=, =<readbipat>=,+        =<writebbar>=, =<writebvbar>=, and =<writebipat>=.++      - Thresholds refer to speed in b/s++      - Args: default monitor arguments. =-t/--template= is ignored. Plus++        - =--total-icon-pattern=: dynamic string for total disk I/O in+          =<totalipat>=.+        - =--write-icon-pattern=: dynamic string for write disk I/O in+          =<writeipat>=.+        - =--read-icon-pattern=: dynamic string for read disk I/O in+          =<readipat>=.++      - Default template: none (you must specify a template for each file+        system).++      - Example:++        #+begin_src haskell+          DiskIO [("/", "<read> <write>"), ("sdb1", "<total>")] [] 10+        #+end_src++*** Keyboard Monitors+***** =Kbd Opts=++      - Registers to XKB/X11-Events and output the currently active keyboard+        layout. Supports replacement of layout names.++      - Aliases to =kbd=++      - Opts is a list of tuples:++        - first element of the tuple is the search string+        - second element of the tuple is the corresponding replacement++      - Example:++        #+begin_src haskell+          Run Kbd [("us(dvorak)", "DV"), ("us", "US")]+        #+end_src++***** =Locks=++      - Displays the status of Caps Lock, Num Lock and Scroll Lock.++      - Aliases to =locks=++      - Example:++        #+begin_src haskell+          Run Locks+        #+end_src++*** Process Monitors+***** =TopProc Args RefreshRate=++      - Aliases to =top=+      - Args: default monitor arguments. The low and high thresholds (=-L= and+        =-H=) denote, for memory entries, the percent of the process memory+        over the total amount of memory currently in use and, for cpu entries,+        the activity percentage (i.e., the value of =cpuN=, which takes values+        between 0 and 100).+      - Variables that can be used with the =-t/--template= argument: =no=,+        =name1=, =cpu1=, =both1=, =mname1=, =mem1=, =mboth1=, =name2=, =cpu2=,+        =both2=, =mname2=, =mem2=, =mboth2=, ...+      - Default template: =<both1>=+      - Displays the name and cpu/mem usage of running processes (=bothn= and+        =mboth= display both, and is useful to specify an overall maximum+        and/or minimum width, using the =-m/-M= arguments. =no= gives the+        total number of processes.++***** =TopMem Args RefreshRate=++      - Aliases to =topmem=+      - Args: default monitor arguments. The low and high thresholds (=-L= and+        =-H=) denote the percent of the process memory over the total amount+        of memory currently in use.+      - Variables that can be used with the =-t/--template= argument:+        =name1=, =mem1=, =both1=, =name2=, =mem2=, =both2=, ...+      - Default template: =<both1>=+      - Displays the name and RSS (resident memory size) of running processes+        (=bothn= displays both, and is useful to specify an overall maximum+        and/or minimum width, using the =-m/-M= arguments.++*** Thermal Monitors+***** =ThermalZone Number Args RefreshRate=++      - Aliases to "thermaln": so =ThermalZone 0 []= can be used in template+        as =%thermal0%=++      - Thresholds refer to temperature in degrees++      - Args: default monitor arguments++      - Variables that can be used with the =-t/--template= argument: =temp=++      - Default template: =<temp>C=++      - This plugin works only on systems with devices having thermal zone.+        Check directories in =/sys/class/thermal= for possible values of the+        zone number (e.g., 0 corresponds to =thermal_zone0= in that+        directory).++      - Example:++        #+begin_src haskell+          Run ThermalZone 0 ["-t","<id>: <temp>C"] 30+        #+end_src++***** =Thermal Zone Args RefreshRate=++      - *This plugin is deprecated. Use =ThermalZone= instead.*++      - Aliases to the Zone: so =Thermal "THRM" []= can be used in template as+        =%THRM%=++      - Args: default monitor arguments++      - Thresholds refer to temperature in degrees++      - Variables that can be used with the =-t/--template= argument: =temp=++      - Default template: =Thm: <temp>C=++      - This plugin works only on systems with devices having thermal zone.+        Check directories in /proc/acpi/thermal_zone for possible values.++      - Example:++        #+begin_src haskell+          Run Thermal "THRM" ["-t","iwl4965-temp: <temp>C"] 50+        #+end_src++*** Volume Monitors+***** =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%=.+      - Args: default monitor arguments. Also accepts:++        - =-O= /string/ On string++          - The string used in place of =<status>= when the mixer element is+            on. Defaults to "[on]".+          - Long option: =--on=++        - =-o= /string/ Off string++          - The string used in place of =<status>= when the mixer element is+            off. Defaults to "[off]".+          - Long option: =--off=++        - =-C= /color/ On color++          - The color to be used for =<status>= when the mixer element is on.+            Defaults to "green".+          - Long option: =--onc=++        - =-c= /color/ Off color++          - The color to be used for =<status>= when the mixer element is off.+            Defaults to "red".+          - Long option: =--offc=++        - =--highd= /number/ High threshold for dB. Defaults to -5.0.+        - =--lowd= /number/ Low threshold for dB. Defaults to -30.0.+        - =--volume-icon-pattern= /string/ dynamic string for current volume+          in =volumeipat=.+        - =-H= /number/ High threshold for volume (in %). Defaults to 60.0.++          - Long option: =--highv=++        - =-L= /number/ Low threshold for volume (in %). Defaults to 20.0.++          - Long option: =--lowv=++        - =-h=: /string/ High string++          - The string added in front of =<status>= when the mixer element is+            on and the volume percentage is higher than the =-H= threshold.+            Defaults to "".+          - Long option: =--highs=++        - =-m=: /string/ Medium string++          - The string added in front of =<status>= when the mixer element is+            on and the volume percentage is lower than the =-H= threshold.+            Defaults to "".+          - Long option: =--mediums=++        - =-l=: /string/ Low string++          - The string added in front of =<status>= when the mixer element is+            on and the volume percentage is lower than the =-L= threshold.+            Defaults to "".+          - Long option: =--lows=++      - Variables that can be used with the =-t/--template= argument:+        =volume=, =volumebar=, =volumevbar=, =volumeipat=, =dB=, =status=,+        =volumestatus=+      - Note that =dB= might only return 0 on your system. This is known to+        happen on systems with a pulseaudio backend.+      - Default template: =Vol: <volume>% <status>=+      - Requires the package [[http://hackage.haskell.org/package/alsa-core][alsa-core]] and [[http://hackage.haskell.org/package/alsa-mixer][alsa-mixer]] installed in your+        system. In addition, to activate this plugin you must pass the+        =with_alsa= flag during compilation.++***** =Alsa Mixer Element Args=++      Like [[=Volume Mixer Element Args RefreshRate=][Volume]] but with the following differences:++      - Uses event-based refreshing via =alsactl monitor= instead of polling,+        so it will refresh instantly when there's a volume change, and won't+        use CPU until a change happens.+      - Aliases to =alsa:= followed by the mixer name and element name+        separated by a colon. Thus, =Alsa "default" "Master" []= can be used+        as =%alsa:default:Master%=.+      - Additional options (after the =--=):+        - =--alsactl=/path/to/alsactl=: If this option is not specified,+          =alsactl= will be sought in your =PATH= first, and failing that, at+          =/usr/sbin/alsactl= (this is its location on Debian systems.+          =alsactl monitor= works as a non-root user despite living in+          =/usr/sbin=.).+        - =stdbuf= (from coreutils) must be (and most probably already is) in+          your =PATH=.++*** Mail Monitors+***** =Mail Args Alias=++      - Args: list of maildirs in form =[("name1","path1"),...]=. Paths may+        start with a '~' to expand to the user's home directory.++      - This plugin requires inotify support in your Linux kernel and the+        [[http://hackage.haskell.org/package/hinotify/][hinotify]] package. To activate, pass the =with_inotify= flag during+        compilation.++      - Example:++        #+begin_src haskell+          Run Mail [("inbox", "~/var/mail/inbox"),+                    ("lists", "~/var/mail/lists")]+                   "mail"+        #+end_src++***** =MailX Args Opts Alias=++      - Args: list of maildirs in form =[("name1","path1","color1"),...]=.+        Paths may start with a '~' to expand to the user's home directory.+        When mails are present, counts are displayed with the given name and+        color.++      - Opts is a possibly empty list of options, as flags. Possible values:+        -d dir --dir dir a string giving the base directory where maildir+        files with a relative path live. -p prefix --prefix prefix a string+        giving a prefix for the list of displayed mail counts -s suffix+        --suffix suffix a string giving a suffix for the list of displayed+        mail counts++      - This plugin requires inotify support in your Linux kernel and the+        [[http://hackage.haskell.org/package/hinotify/][hinotify]] package. To activate, pass the =with_inotify= flag during+        compilation.++      - Example:++        #+begin_src haskell+          Run MailX [("I", "inbox", "green"),+                     ("L", "lists", "orange")]+                    ["-d", "~/var/mail", "-p", " ", "-s", " "]+                    "mail"+        #+end_src++***** =MBox Mboxes Opts Alias=++      - Mboxes a list of mbox files of the form =[("name", "path", "color")]=,+        where name is the displayed name, path the absolute or relative (to+        BaseDir) path of the mbox file, and color the color to use to display+        the mail count (use an empty string for the default).++      - Opts is a possibly empty list of options, as flags. Possible values:+        -a --all (no arg) Show all mailboxes, even if empty. -u (no arg) Show+        only the mailboxes' names, sans counts. -d dir --dir dir a string+        giving the base directory where mbox files with a relative path live.+        -p prefix --prefix prefix a string giving a prefix for the list of+        displayed mail counts -s suffix --suffix suffix a string giving a+        suffix for the list of displayed mail counts++      - Paths may start with a '~' to expand to the user's home directory.++      - This plugin requires inotify support in your Linux kernel and the+        [[http://hackage.haskell.org/package/hinotify/][hinotify]] package. To activate, pass the =with_inotify= flag during+        compilation.++      - Example. The following command look for mails in =/var/mail/inbox= and+        =~/foo/mbox=, and will put a space in front of the printed string+        (when it's not empty); it can be used in the template with the alias+        =mbox=:++        #+begin_src haskell+          Run MBox [("I ", "inbox", "red"), ("O ", "~/foo/mbox", "")]+                   ["-d", "/var/mail/", "-p", " "] "mbox"+        #+end_src++***** =NotmuchMail Alias Args Rate=++      This plugin checks for new mail, provided that this mail is indexed by+      =notmuch=. In the =notmuch= spirit, this plugin checks for new *threads*+      and not new individual messages.++      - Alias: What name the plugin should have in your template string.++      - Args: A list of =MailItem= s of the form++        #+begin_src haskell+          [ MailItem "name" "address" "query"+          ...+          ]+        #+end_src++        where++        - =name= is what gets printed in the status bar before the number of+          new threads.+        - =address= is the e-mail address of the recipient, i.e. we only query+          mail that was send to this particular address (in more concrete+          terms, we pass the address to the =to:= constructor when performing+          the search). If =address= is empty, we search through all unread+          mail, regardless of whom it was sent to.+        - =query= is funneled to =notmuch search= verbatim. For the general+          query syntax, consult =notmuch search --help=, as well as+          =notmuch-search-terms(7)=. Note that the =unread= tag is *always*+          added in front of the query and composed with it via an *and*.++      - Rate: Rate with which to update the plugin (in deciseconds).++      - Example:++        - A single =MailItem= that displays all unread threads from the given+          address:++          #+begin_src haskell+            MailItem "mbs:" "soliditsallgood@mailbox.org" ""+          #+end_src++        - A single =MailItem= that displays all unread threads with+          "[My-Subject]" somewhere in the title:++          #+begin_src haskell+            MailItem "S:" "" "subject:[My-Subject]"+          #+end_src++        - A full example of a =NotmuchMail= configuration:++          #+begin_src haskell+            Run NotmuchMail "mail"  -- name for the template string+              [ -- All unread mail to the below address, but nothing that's tagged+                -- with @lists@ or @haskell@.+                MailItem "mbs:"+                         "soliditsallgood@mailbox.org"+                         "not tag:lists and not tag:haskell"++                -- All unread mail that has @[Haskell-Cafe]@ in the subject line.+              , MailItem "C:" "" "subject:[Haskell-Cafe]"++                -- All unread mail that's tagged as @lists@, but not @haskell@.+              , MailItem "H:" "" "tag:lists and not tag:haskell"+              ]+              600                   -- update every 60 seconds+          #+end_src++*** Music Monitors+***** =MPD Args RefreshRate=++      - This monitor will only be compiled if you ask for it using the+        =with_mpd= flag. It needs [[http://hackage.haskell.org/package/libmpd/][libmpd]] 5.0 or later (available on Hackage).++      - Aliases to =mpd=++      - Args: default monitor arguments. In addition you can provide =-P=,+        =-S= and =-Z=, with an string argument, to represent the playing,+        stopped and paused states in the =statei= template field. The+        environment variables =MPD_HOST= and =MPD_PORT= are used to configure+        the mpd server to communicate with, unless given in the additional+        arguments =-p= (=--port=) and =-h= (=--host=). Also available:++        - =lapsed-icon-pattern=: dynamic string for current track position in+          =ipat=.++      - Variables that can be used with the =-t/--template= argument: =bar=,+        =vbar=, =ipat=, =state=, =statei=, =volume=, =length=, =lapsed=,+        =remaining=, =plength= (playlist length), =ppos= (playlist position),+        =flags= (ncmpcpp-style playback mode), =name=, =artist=, =composer=,+        =performer=, =album=, =title=, =track=, =file=, =genre=, =date=++      - Default template: =MPD: <state>=++      - Example (note that you need "--" to separate regular monitor options+        from MPD's specific ones):++        #+begin_src haskell+          Run MPD ["-t",+                   "<composer> <title> (<album>) <track>/<plength> <statei> [<flags>]",+                   "--", "-P", ">>", "-Z", "|", "-S", "><"] 10+        #+end_src++***** =MPDX Args RefreshRate Alias=++      Like =MPD= but uses as alias its last argument instead of "mpd".++***** =Mpris1 PlayerName Args RefreshRate=++      - Aliases to =mpris1=++      - Requires [[http://hackage.haskell.org/package/dbus][dbus]] and [[http://hackage.haskell.org/package/text][text]] packages. To activate, pass the =with_mpris=+        flag during compilation.++      - PlayerName: player supporting MPRIS v1 protocol. Some players need+        this to be an all lowercase name (e.g. "spotify"), but some others+        don't.++      - Args: default monitor arguments.++      - Variables that can be used with the =-t/--template= argument:+        =album=, =artist=, =arturl=, =length=, =title=, =tracknumber=++      - Default template: =<artist> - <title>=++      - Example:++        #+begin_src haskell+          Run Mpris1 "clementine" ["-t", "<artist> - [<tracknumber>] <title>"] 10+        #+end_src++***** =Mpris2 PlayerName Args RefreshRate=++      - Aliases to =mpris2=++      - Requires [[http://hackage.haskell.org/package/dbus][dbus]] and [[http://hackage.haskell.org/package/text][text]] packages. To activate, pass the =with_mpris=+        flag during compilation.++      - PlayerName: player supporting MPRIS v2 protocol. Some players need+        this to be an all lowercase name (e.g. "spotify"), but some others+        don't.++      - Args: default monitor arguments.++      - Variables that can be used with the =-t/--template= argument:+        =album=, =artist=, =arturl=, =length=, =title=, =tracknumber=,+        =composer=, =genre=++      - Default template: =<artist> - <title>=++      - Example:++        #+begin_src haskell+          Run Mpris2 "spotify" ["-t", "<artist> - [<composer>] <title>"] 10+        #+end_src++*** Network Monitors+***** =Network Interface Args RefreshRate=++      - Aliases to the interface name: so =Network "eth0" []= can be used as+        =%eth0%=+      - Thresholds refer to velocities expressed in Kb/s+      - Args: default monitor arguments, plus:++        - =--rx-icon-pattern=: dynamic string for reception rate in =rxipat=.+        - =--tx-icon-pattern=: dynamic string for transmission rate in+          =txipat=.+        - =--up=: string used for the =up= variable value when the interface+          is up.++      - Variables that can be used with the =-t=/=--template= argument: =dev=,+        =rx=, =tx=, =rxbar=, =rxvbar=, =rxipat=, =txbar=, =txvbar=, =txipat=,+        =up=. Reception and transmission rates (=rx= and =tx=) are displayed+        by default as Kb/s, without any suffixes, but you can set the =-S= to+        "True" to make them displayed with adaptive units (Kb/s, Mb/s, etc.).+      - Default template: =<dev>: <rx>KB|<tx>KB=++***** =DynNetwork Args RefreshRate=++      - Active interface is detected automatically+      - Aliases to "dynnetwork"+      - Thresholds are expressed in Kb/s+      - Args: default monitor arguments, plus:++      - =--rx-icon-pattern=: dynamic string for reception rate in =rxipat=.+      - =--tx-icon-pattern=: dynamic string for transmission rate in =txipat=+      - =--devices=: comma-separated list of devices to show.++      - Variables that can be used with the =-t=/=--template= argument:+        =dev=, =rx=, =tx=, =rxbar=, =rxvbar=, =rxipat=, =txbar=, =txvbar=,+        =txipat=.++      Reception and transmission rates (=rx= and =tx=) are displayed in Kbytes+      per second, and you can set the =-S= to "True" to make them displayed+      with units (the string "Kb/s").+      - Default template: =<dev>: <rx>KB|<tx>KB=+      - Example of usage of =--devices= option:++          =["--", "--devices", "wlp2s0,enp0s20f41"]=++***** =Wireless Interface Args RefreshRate=++      - If set to "", first suitable wireless interface is used.+      - Aliases to the interface name with the suffix "wi": thus,+        =Wireless   "wlan0" []= can be used as =%wlan0wi%=, and+        =Wireless "" []= as =%wi%=.+      - Args: default monitor arguments, plus:++        - =--quality-icon-pattern=: dynamic string for connection quality in+          =qualityipat=.++      - Variables that can be used with the =-t=/=--template= argument:+        =ssid=, =signal=, =quality=, =qualitybar=, =qualityvbar=,+        =qualityipat=+      - Thresholds refer to link quality on a =[0, 100]= scale. Note that+        =quality= is calculated from =signal= (in dBm) by a possibly lossy+        conversion. It is also not taking into account many factors such as+        noise level, air busy time, transcievers' capabilities and the others+        which can have drastic impact on the link performance.+      - Default template: =<ssid> <quality>=+      - To activate this plugin you must pass the =with_nl80211= or the+        =with_iwlib= flag during compilation.++*** Weather Monitors+***** =Weather StationID Args RefreshRate=++      - Aliases to the Station ID: so =Weather "LIPB" []= can be used in+        template as =%LIPB%=+      - Thresholds refer to temperature in the selected units+      - Args: default monitor arguments, plus:++        - =--weathers= /string/ : display a default string when the =weather=+          variable is not reported.++          - short option: =-w=+          - Default: ""++        - =--useManager= /bool/ : Whether to use one single manager per+          monitor for managing network connections or create a new one every+          time a connection is made.++          - Short option: =-m=+          - Default: True++      - Variables that can be used with the =-t/--template= argument:+        =station=, =stationState=, =year=, =month=, =day=, =hour=,+        =windCardinal=, =windAzimuth=, =windMph=, =windKnots=, =windMs=,+        =windKmh= =visibility=, =skyCondition=, =weather=, =tempC=, =tempF=,+        =dewPointC=, =dewPointF=, =rh=, =pressure=+      - Default template: =<station>: <tempC>C, rh <rh>% (<hour>)=+      - Retrieves weather information from http://tgftp.nws.noaa.gov. Here is+        an [[https://tgftp.nws.noaa.gov/data/observations/metar/decoded/CYLD.TXT][example]], also showcasing the kind of information that may be+        extracted. Here is [[https://weather.rap.ucar.edu/surface/stations.txt][a sample list of station IDs]].++***** =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 (typically a+        unicode string or an icon specification).+      - Use the variable =skyConditionS= to display the replacement of the+        corresponding sky condition. All other =Weather= template variables+        are available as well.++      For example:++      #+begin_src haskell+        WeatherX "LEBL"+                 [ ("clear", "🌣")+                 , ("sunny", "🌣")+                 , ("mostly clear", "🌤")+                 , ("mostly sunny", "🌤")+                 , ("partly sunny", "⛅")+                 , ("fair", "🌑")+                 , ("cloudy","☁")+                 , ("overcast","☁")+                 , ("partly cloudy", "⛅")+                 , ("mostly cloudy", "🌧")+                 , ("considerable cloudiness", "⛈")]+                 ["-t", "<fn=2><skyConditionS></fn> <tempC>° <rh>%  <windKmh> (<hour>)"+                 , "-L","10", "-H", "25", "--normal", "black"+                 , "--high", "lightgoldenrod4", "--low", "darkseagreen4"]+                 18000+      #+end_src++      As mentioned, the replacement string can also be an icon specification,+      such as =("clear", "<icon=weather-clear.xbm/>")=.++*** Other Monitors+***** =Brightness Args RefreshRate=++      - Aliases to =bright=++      - Args: default monitor arguments, plus the following specif ones:++        - =-D=: directory in =/sys/class/backlight/= with files in it+          (default: "acpi_video0")+        - =-C=: file with the current brightness (default: actual_brightness)+        - =-M=: file with the maximum brightness (default: max_brightness)+        - =--brightness-icon-pattern=: dynamic string for current brightness+          in =ipat=.++      - Variables that can be used with the =-t/--template= argument:+        =vbar=, =percent=, =bar=, =ipat=++      - Default template: =<percent>=++      - Example:++        #+begin_src haskell+          Run Brightness ["-t", "<bar>"] 60+        #+end_src++***** =CatInt n filename=++      - Reads and displays an integer from the file whose path is =filename=+        (especially useful with files in =/sys=).++      - Aliases as =catn= (e.g. =Cat 0= as =cat0=, etc.) so you can have+        several.++      - Example:++        #+begin_src haskell+          Run CatInt 0 "/sys/devices/platform/thinkpad_hwmon/fan1_input" [] 50+        #+end_src++***** =CommandReader "/path/to/program" Alias=++      - Runs the given program, and displays its standard output.++***** =Uptime Args RefreshRate=++      - Aliases to =uptime=+      - Args: default monitor arguments. The low and high thresholds refer to+        the number of days.+      - Variables that can be used with the =-t/--template= argument: =days=,+        =hours=, =minutes=, =seconds=. The total uptime is the sum of all+        those fields. You can set the =-S= argument to =True= to add units to+        the display of those numeric fields.+      - Default template: =Up: <days>d <hours>h <minutes>m=++***** =UVMeter=++      - Aliases to "uv" + station id. For example: =%uv Brisbane%= or+        =%uv   Alice Springs%=++      - Args: default monitor arguments, plus:++        - =--useManager= /bool/ : Whether to use one single manager per+          monitor for managing network connections or create a new one every+          time a connection is made.++          - Short option: =-m=+          - Default: True++      - /Reminder:/ Keep the refresh rate high, to avoid making unnecessary+        requests every time the plug-in is run.++      - Station IDs can be found here:+        http://www.arpansa.gov.au/uvindex/realtime/xml/uvvalues.xml++      - Example:++        #+begin_src haskell+          Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900+        #+end_src++* 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 arguments, or you can configure it in the "commands"+  configuration option list with the Com template command:++  =Com ProgramName Args Alias RefreshRate=++  - ProgramName: the name of the program+  - Args: the arguments to be passed to the program at execution time+  - RefreshRate: number of tenths of second between re-runs of the+    command. A zero or negative rate means that the command will be+    executed only once.+  - Alias: a name to be used in the template. If the alias is en empty+    string the program name can be used in the template.++  E.g.:++  #+begin_src haskell+    Run Com "uname" ["-s","-r"] "" 0+  #+end_src++  can be used in the output template as =%uname%= (and xmobar will call+  /uname/ only once), while++  #+begin_src haskell+    Run Com "date" ["+\"%a %b %_d %H:%M\""] "mydate" 600+  #+end_src++  can be used in the output template as =%mydate%=.++  Sometimes, you don't mind if the command executed exits with an+  error, or you might want to display a custom message in that+  case. To that end, you can use the =ComX= variant:++    =ComX ProgramName Args ExitMessage Alias RefreshRate=++  Works like =Com=, but displaying =ExitMessage= (a string) if the+  execution fails. For instance:++  #+begin_src haskell+    Run ComX "date" ["+\"%a %b %_d %H:%M\""] "N/A" "mydate" 600+  #+end_src++  will display "N/A" if for some reason the =date= invocation fails.
doc/quick-start.org view
@@ -1,3 +1,5 @@+#+title: Quick start: using xmobar+ Xmobar can either be configured using the configuration language, or used as a Haskell library (similar to xmonad) and compiled with your specific configuration. For an example of the latter, you can have a@@ -7,373 +9,461 @@ There is also an example of a config using the configuration language available [[http://github.com/jaor/xmobar/raw/master/examples/xmobar.config][here]]. -* Configuration Options+* Command Line Options -Here are all the global configuration options that you can set within-the =Config= block in your configuration.+  xmobar can be either configured with a configuration file or with+  command line options. In the second case, the command line options will+  overwrite the corresponding options set in the configuration file. -- =font= Name of the font to be used. Use the =xft:= prefix for XFT-  fonts.+  Example: -- =additionalFonts= Haskell-style list of fonts to be used with the-  =fn=-template. Use the =xft:= prefix for XFT fonts. See also-  =textOffsets= below. For example:+  #+begin_src shell+    xmobar -B white -a right -F blue -t '%LIPB%' -c '[Run Weather "LIPB" [] 36000]'+  #+end_src -  #+begin_src haskell-    additionalFonts = [iconFont, altIconFont]+  This is the list of command line options (the output of =xmobar --help=):++  #+begin_src shell+    Usage: xmobar [OPTION...] [FILE]+    Options:+      -h, -?        --help                 This help+      -v            --verbose              Emit verbose debugging messages+      -r            --recompile            Force recompilation+      -V            --version              Show version information+      -f font name  --font=font name       Font name+      -N font name  --add-font=font name   Add to the list of additional fonts+      -w class      --wmclass=class        X11 WM_CLASS property+      -n name       --wmname=name          X11 WM_NAME property+      -B bg color   --bgcolor=bg color     The background color. Default black+      -F fg color   --fgcolor=fg color     The foreground color. Default grey+      -i path       --iconroot=path        Root directory for icon pattern paths. Default '.'+      -A alpha      --alpha=alpha          Transparency: 0 is transparent, 255 is opaque. Default: 255+      -o            --top                  Place xmobar at the top of the screen+      -b            --bottom               Place xmobar at the bottom of the screen+      -d            --dock                 Don't override redirect from WM and function as a dock+      -a alignsep   --alignsep=alignsep    Separators for left, center and right text+                                           alignment. Default: '}{'+      -s char       --sepchar=char         Character used to separate commands in+                                           the output template. Default '%'+      -t template   --template=template    Output template+      -c commands   --commands=commands    List of commands to be executed+      -C command    --add-command=command  Add to the list of commands to be executed+      -x screen     --screen=screen        On which X screen number to start+      -p position   --position=position    Specify position of xmobar. Same syntax as in config file+      -T [format]   --text[=format]        Write output to stdout++    Mail bug reports and suggestions to <mail@jao.io>   #+end_src+* Configuration Options+*** Global options+    Here are all the global configuration options that you can set within+    the =Config= block in your configuration. -- =bgColor= Background color.+    - =font= Name of the font to be used. Use the =xft:= prefix for XFT+      fonts. -- =fgColor= Default font color.+    - =additionalFonts= Haskell-style list of fonts to be used with the+      =fn=-template. Use the =xft:= prefix for XFT fonts. See also+      =textOffsets= below. For example: -- =alpha= The transparency. 0 is transparent, 255 is opaque.+      #+begin_src haskell+        additionalFonts = [iconFont, altIconFont]+      #+end_src -- =position= Top, TopH, TopP, TopW, TopSize, Bottom, BottomH,-  BottomP, BottomW, BottomSize or Static (with x, y, width and height).+    - =bgColor= Background color. -  TopP and BottomP take 2 arguments: left padding and right padding.+    - =fgColor= Default font color. -  TopW and BottomW take 2 arguments: an alignment parameter (L for left,-  C for centered, R for Right) and an integer for the percentage width-  xmobar window will have in respect to the screen width.+    - =alpha= The transparency. 0 is transparent, 255 is opaque. -  TopSize and BottomSize take 3 arguments: an alignment parameter, an-  integer for the percentage width, and an integer for the minimum pixel-  height that the xmobar window will have.+    - =position= Top, TopH, TopP, TopW, TopSize, Bottom, BottomH,+      BottomP, BottomW, BottomSize or Static (with x, y, width and height). -  TopH and BottomH take one argument (Int) which adjusts the bar height.+      TopP and BottomP take 2 arguments: left padding and right padding. -  For example:+      TopW and BottomW take 2 arguments: an alignment parameter (L for left,+      C for centered, R for Right) and an integer for the percentage width+      xmobar window will have in respect to the screen width. -  #+begin_src haskell-    position = TopH 30-  #+end_src+      TopSize and BottomSize take 3 arguments: an alignment parameter, an+      integer for the percentage width, and an integer for the minimum pixel+      height that the xmobar window will have. -  to make a 30 tall bar on the top, or+      TopH and BottomH take one argument (Int) which adjusts the bar height. -  #+begin_src haskell-    position = BottomH 30-  #+end_src+      For example: -  to make a 30 tall bar on the bottom of the screen.+      #+begin_src haskell+        position = TopH 30+      #+end_src -  #+begin_src haskell-    position = BottomW C 75-  #+end_src+      to make a 30 tall bar on the top, or -  to place xmobar at the bottom, centered with the 75% of the screen-  width. Or+      #+begin_src haskell+        position = BottomH 30+      #+end_src -  #+begin_src haskell-    position = BottomP 120 0-  #+end_src+      to make a 30 tall bar on the bottom of the screen. -  to place xmobar at the bottom, with 120 pixel indent of the left. Or+      #+begin_src haskell+        position = BottomW C 75+      #+end_src -  #+begin_src haskell-    position = Static { xpos = 0 , ypos = 0, width = 1024, height = 15 }-  #+end_src+      to place xmobar at the bottom, centered with the 75% of the screen+      width. Or -  or+      #+begin_src haskell+        position = BottomP 120 0+      #+end_src -  #+begin_src haskell-    position = Top-  #+end_src+      to place xmobar at the bottom, with 120 pixel indent of the left. Or -- =textOffset= The vertical offset, in pixels, for the text baseline. If-  negative or not given, xmobar will try to center text vertically.+      #+begin_src haskell+        position = Static { xpos = 0 , ypos = 0, width = 1024, height = 15 }+      #+end_src -- =textOffsets= A list of vertical offsets, in pixels, for the text-  baseline, to be used with the each of the fonts in =additionalFonts=-  (if any). If negative or not given, xmobar will try to center text-  vertically for that font.+      or -- =iconOffset= The vertical offset, in pixels, for icons bottom line. If-  negative or not given, xmobar will try to center icons vertically.+      #+begin_src haskell+        position = Top+      #+end_src -- =lowerOnStart= When True the window is sent the bottom of the window-  stack initially.+    - =textOffset= The vertical offset, in pixels, for the text baseline. If+      negative or not given, xmobar will try to center text vertically. -- =hideOnStart= When set to True the window is initially not mapped,-  i.e. hidden. It then can be toggled manually (for example using the-  dbus interface) or automatically (by a plugin) to make it reappear.+    - =textOffsets= A list of vertical offsets, in pixels, for the text+      baseline, to be used with the each of the fonts in =additionalFonts=+      (if any). If negative or not given, xmobar will try to center text+      vertically for that font. -- =allDesktops= When set to True (the default), xmobar will tell the-  window manager explicitly to be shown in all desktops, by setting-  =_NET_WM_DESKTOP= to 0xffffffff.+    - =iconOffset= The vertical offset, in pixels, for icons bottom line. If+      negative or not given, xmobar will try to center icons vertically. -- =overrideRedirect= If you're running xmobar in a tiling window-  manager, you might need to set this option to =False= so that it-  behaves as a docked application. Defaults to =True=.+    - =lowerOnStart= When True the window is sent the bottom of the window+      stack initially. -- =pickBroadest= When multiple displays are available, xmobar will-  choose by default the first one to place itself. With this flag set to-  =True= (the default is =False=) it will choose the broadest one-  instead.+    - =hideOnStart= When set to True the window is initially not mapped,+      i.e. hidden. It then can be toggled manually (for example using the+      dbus interface) or automatically (by a plugin) to make it reappear. -- =persistent= When True the window status is fixed i.e. hiding or-  revealing is not possible. This option can be toggled at runtime.-  Defaults to False.+    - =allDesktops= When set to True (the default), xmobar will tell the+      window manager explicitly to be shown in all desktops, by setting+      =_NET_WM_DESKTOP= to 0xffffffff. -- =border= TopB, TopBM, BottomB, BottomBM, FullB, FullBM or NoBorder-  (default).+    - =overrideRedirect= If you're running xmobar in a tiling window+      manager, you might need to set this option to =False= so that it+      behaves as a docked application. Defaults to =True=. -  TopB, BottomB, FullB take no arguments, and request drawing a border-  at the top, bottom or around xmobar's window, respectively.+    - =pickBroadest= When multiple displays are available, xmobar will+      choose by default the first one to place itself. With this flag set to+      =True= (the default is =False=) it will choose the broadest one+      instead. -  TopBM, BottomBM, FullBM take an integer argument, which is the margin,-  in pixels, between the border of the window and the drawn border.+    - =persistent= When True the window status is fixed i.e. hiding or+      revealing is not possible. This option can be toggled at runtime.+      Defaults to False. -- =borderColor= Border color.+    - =border= TopB, TopBM, BottomB, BottomBM, FullB, FullBM or NoBorder+      (default). -- =borderWidth= Border width in pixels.+      TopB, BottomB, FullB take no arguments, and request drawing a border+      at the top, bottom or around xmobar's window, respectively. -- =iconRoot= Root folder where icons are stored. For =<icon=path/>= if-  path start with =/=, =./= or =../= it is interpreted as it is.-  Otherwise it will have+      TopBM, BottomBM, FullBM take an integer argument, which is the margin,+      in pixels, between the border of the window and the drawn border. -  #+begin_src haskell-    iconRoot ++ "/"-  #+end_src+    - =borderColor= Border color. -  prepended to it. Default is =.=.+    - =borderWidth= Border width in pixels. -- =commands= For setting the options of the programs to run (optional).+    - =iconRoot= Root folder where icons are stored. For =<icon=path/>= if+      path start with =/=, =./= or =../= it is interpreted as it is.+      Otherwise it will have -- =sepChar= The character to be used for indicating commands in the-  output template (default '%').+      #+begin_src haskell+        iconRoot ++ "/"+      #+end_src -- =alignSep= a 2 character string for aligning text in the output-  template. The text before the first character will be align to left,-  the text in between the 2 characters will be centered, and the text-  after the second character will be align to the right.+      prepended to it. Default is =.=. -- =template= The output template.+    - =commands= For setting the options of the programs to run (optional). -- =wmClass= The value for the window's X11 WM_CLASS property. Defaults-  to "xmobar".+    - =sepChar= The character to be used for indicating commands in the+      output template (default '%'). -- =wmName= The value for the window's X11 WM_NAME property. Defaults to-  "xmobar".+    - =alignSep= a 2 character string for aligning text in the output+      template. The text before the first character will be align to left,+      the text in between the 2 characters will be centered, and the text+      after the second character will be align to the right. -** The Output =template=+    - =template= The output template. -The output template is how xmobar will end up printing all of your-configured commands. It must contain at least one command. Xmobar will-parse the template and search for the command to be executed in the-=commands= configuration option. First an =alias= will be searched (some-plugins, such as =Weather= or =Network=, have default aliases, see the-[[./plugins.org][plugin documentation]]).  After that, the command name will be tried. If a-command is found, the arguments specified in the =commands= list will be-used.+    - =wmClass= The value for the window's X11 ~WM_CLASS~ property. Defaults+      to "xmobar". -If no command is found in the =commands= list, xmobar will ask the-operating system to execute a program with the name found in the-template. If the execution is not successful an error will be reported.+    - =wmName= The value for the window's X11 ~WM_NAME~ property. Defaults to+      "xmobar". -The syntax for the output template is as follows:+    - =textOutput= When True, instead of running as an X11 application,+      write output to stdout, with optional color escape sequences.  In+      this mode, icon and action specifications are ignored.  Default is+      False. -- =%command%= will execute command and print the output. The output may-  contain markups to change the characters' color.+    - =textOutputFormat= Plain, Ansi or Pango, to emit, when in text+      mode, escape color sequences using ANSI controls (for terminals) or+      pango markup.  Default is Plain. -- =<fc=#FF0000>string</fc>= will print =string= with =#FF0000= color-  (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.+*** The output =template= -- =<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:+    The output template is how xmobar will end up printing all of your+    configured commands. It must contain at least one command. Xmobar+    will parse the template and search for the command to be executed+    in the =commands= configuration option. First an =alias= will be+    searched (some plugins, such as =Weather= or =Network=, have default+    aliases, see the [[./plugins.org][plugin documentation]]).  After that, the command+    name will be tried. If a command is found, the arguments specified+    in the =commands= list will be used. -  - =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.+    If no command is found in the =commands= list, xmobar will ask the+    operating system to execute a program with the name found in the+    template. If the execution is not successful an error will be+    reported. -  For example, a box underlining its text with a red line of width 2:+***** Template syntax -  #+begin_src shell-    <box type=Bottom width=2 color=red>string</box>-  #+end_src+      The syntax for the output template is as follows: -  and if you wanted an underline and an overline with a margin of 2-  pixels either side:+      - =%command%= will execute command and print the output. The output may+        contain markups to change the characters' color. -  #+begin_src shell-    <box type=VBoth mt=2 mb=2>string</box>-  #+end_src+      - =<fc=#FF0000>string</fc>= will print =string= with =#FF0000= color+        (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. -- =<fn=1>string</fn>= will print =string= with the first font from-  =additionalFonts=. The index =0= corresponds to the standard font.+      - =<fn=1>string</fn>= will print =string= with the first font from+        =additionalFonts=. The index =0= corresponds to the standard font. -- =<hspace=X/>= will insert a blank horizontal space of =X= pixels.-  For example, to add a blank horizontal space of 123 pixels,-  =<hspace=123/>= may be used.+      - =<hspace=X/>= will insert a blank horizontal space of =X= pixels.+        For example, to add a blank horizontal space of 123 pixels,+        =<hspace=123/>= may be used. -- =<icon=/path/to/icon.xbm/>= will insert the given bitmap. XPM image-  format is also supported when compiled with the =with_xpm= flag.+       - =<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: see next section. -- =<action=`command` button=12345>= will execute given command when-  clicked with specified buttons. If not specified, button is equal to 1-  (left mouse button). Using old syntax (without backticks surrounding-  =command=) will result in =button= attribute being ignored.+      - =<icon=/path/to/icon.xbm/>= will insert the given bitmap. XPM image+        format is also supported when compiled with the =with_xpm= flag. -- =<raw=len:str/>= allows the encapsulation of arbitrary text =str=-  (which must be =len= =Char=s long, where =len= is encoded as a decimal-  sequence). Careful use of this and =UnsafeStdinReader=, for example,-  permits window managers to feed xmobar strings with =<action>= tags-  mixed with un-trusted content (e.g. window titles). For example, if-  xmobar is invoked as+      - =<action=`command` button=12345>= will execute given command when+        clicked with specified buttons. If not specified, button is equal to 1+        (left mouse button). Using old syntax (without backticks surrounding+        =command=) will result in =button= attribute being ignored. -  #+begin_src shell-    xmobar -c "[Run UnsafeStdinReader]" -t "%UnsafeStdinReader%"-  #+end_src+      - =<raw=len:str/>= allows the encapsulation of arbitrary text =str=+        (which must be =len= =Char=s long, where =len= is encoded as a decimal+        sequence). Careful use of this and =UnsafeStdinReader=, for example,+        permits window managers to feed xmobar strings with =<action>= tags+        mixed with un-trusted content (e.g. window titles). For example, if+        xmobar is invoked as -  and receives on standard input the line+        #+begin_src shell+          xmobar -c "[Run UnsafeStdinReader]" -t "%UnsafeStdinReader%"+        #+end_src -  #+begin_src shell-    <action=`echo test` button=1><raw=41:<action=`echo mooo` button=1>foo</action>/></action>`-  #+end_src+        and receives on standard input the line -  then it will display the text-  =<action=`echo mooo` button=1>foo</action>=, which, when clicked, will-  cause =test= to be echoed.+        #+begin_src shell+          <action=`echo test` button=1><raw=41:<action=`echo mooo` button=1>foo</action>/></action>`+        #+end_src -*** Bitmap Icons+        then it will display the text+        =<action=`echo mooo` button=1>foo</action>=, which, when clicked, will+        cause =test= to be echoed. -It's possible to insert in the global templates icon directives of the-form:+        See the subsections below for more information on ~<box/>~,+        ~<icon/>~ and ~<action/>~. -#+begin_src shell-  <icon=/path/to/bitmap.xbm/>-#+end_src+***** Boxes around text -which will produce the expected result. Accepted image formats are XBM-and XPM (when =with_xpm= flag is enabled). If path does not start with-=/=, =./=, =../= it will have+     - =<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: -#+begin_src haskell-  iconRoot ++ "/"-#+end_src+       - =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. -prepended to it.+       For example, a box underlining its text with a red line of width 2: -*** Action Directives+       #+begin_src shell+         <box type=Bottom width=2 color=red>string</box>+       #+end_src -It's also possible to use action directives of the form:+       and if you wanted an underline and an overline with a margin of 2+       pixels either side: -#+begin_src shell-  <action=`command` button=12345>-#+end_src+       #+begin_src shell+         <box type=VBoth mt=2 mb=2>string</box>+       #+end_src -which will be executed when clicked on with specified mouse buttons.-This tag can be nested, allowing different commands to be run depending-on button clicked.+       When xmobar is run in text mode with output format swaybar, box+       types, colors and widths are valid too, but margins and offsets+       are ignored. -** The =commands= Configuration Option+***** Bitmap Icons -The =commands= configuration option is a list of commands information-and arguments to be used by xmobar when parsing the output template.-Each member of the list consists in a command prefixed by the =Run=-keyword. Each command has arguments to control the way xmobar is going-to execute it.+      It's possible to insert in the global templates icon directives of the+      form: -The option consists in a list of commands separated by a comma and-enclosed by square parenthesis.+      prepended to it. Default is =.=. -Example: -#+begin_src haskell-  [Run Memory ["-t","Mem: <usedratio>%"] 10, Run Swap [] 10]-#+end_src -to run the Memory monitor plugin with the specified template, and the-swap monitor plugin, with default options, every second. And here's an-example of a template for the commands above using an icon:+      #+begin_src shell+        <icon=/path/to/bitmap.xbm/>+      #+end_src -#+begin_src haskell-  template = "<icon=/home/jao/.xmobar/mem.xbm/><memory> <swap>"-#+end_src+      which will produce the expected result. Accepted image formats are XBM+      and XPM (when =with_xpm= flag is enabled). If path does not start with+      =/=, =./=, =../= it will have -This example will run "xclock" command when date is clicked:+      #+begin_src haskell+        iconRoot ++ "/"+      #+end_src -#+begin_src haskell-  template = "<action=`xclock`>%date%</action>"-#+end_src+      prepended to it. -The only internal available command is =Com= (see below Executing-External Commands). All other commands are provided by plugins. xmobar-comes with some plugins, providing a set of system monitors, a standard-input reader, an Unix named pipe reader, a configurable date plugin, and-much more: we list all available plugins below.+      Icons are ignored when xmobar is run in text output mode. -Other commands can be created as plugins with the Plugin infrastructure.-See below.-** Running xmobar with =i3status=+***** Action Directives -xmobar can be used to display information generated by [[http://i3wm.org/i3status/][i3status]], a small-program that gathers system information and outputs it in formats-suitable for being displayed by the dzen2 status bar, wmii's status bar-or xmobar's =StdinReader=. See [[http://i3wm.org/i3status/manpage.html#_using_i3status_with_xmobar][i3status manual]] for further details.+      It's also possible to use action directives of the form: -** Dynamically sizing xmobar+      #+begin_src shell+        <action=`command` button=12345>+      #+end_src -See [[https://github.com/jaor/xmobar/issues/239#issuecomment-233206552][this idea]] by Jonas Camillus Jeppensen for a way of adapting-dynamically xmobar's size and run it alongside a system tray widget such-as trayer or stalonetray (although the idea is not limited to trays,-really). For your convenience, there is a version of Jonas' script in-[[../examples/padding-icon.sh][examples/padding-icon.sh]].+      which will be executed when clicked on with specified mouse+      buttons.  This tag can be nested, allowing different commands to+      be run depending on button clicked. -* Command Line Options+      Actions work also when xmobar is run in text mode and used as+      the status command of swaybar. -xmobar can be either configured with a configuration file or with-command line options. In the second case, the command line options will-overwrite the corresponding options set in the configuration file.+*** The =commands= configuration option -Example:+    The =commands= configuration option is a list of commands information+    and arguments to be used by xmobar when parsing the output template.+    Each member of the list consists in a command prefixed by the =Run=+    keyword. Each command has arguments to control the way xmobar is going+    to execute it. -#+begin_src shell-  xmobar -B white -a right -F blue -t '%LIPB%' -c '[Run Weather "LIPB" [] 36000]'-#+end_src+    The option consists in a list of commands separated by a comma and+    enclosed by square parenthesis. -This is the list of command line options (the output of =xmobar --help=):+    Example: -#+begin_src shell-  Usage: xmobar [OPTION...] [FILE]-  Options:-    -h, -?        --help                 This help-    -v            --verbose              Emit verbose debugging messages-    -r            --recompile            Force recompilation-    -V            --version              Show version information-    -f font name  --font=font name       Font name-    -N font name  --add-font=font name   Add to the list of additional fonts-    -w class      --wmclass=class        X11 WM_CLASS property-    -n name       --wmname=name          X11 WM_NAME property-    -B bg color   --bgcolor=bg color     The background color. Default black-    -F fg color   --fgcolor=fg color     The foreground color. Default grey-    -i path       --iconroot=path        Root directory for icon pattern paths. Default '.'-    -A alpha      --alpha=alpha          Transparency: 0 is transparent, 255 is opaque. Default: 255-    -o            --top                  Place xmobar at the top of the screen-    -b            --bottom               Place xmobar at the bottom of the screen-    -d            --dock                 Don't override redirect from WM and function as a dock-    -a alignsep   --alignsep=alignsep    Separators for left, center and right text-                                         alignment. Default: '}{'-    -s char       --sepchar=char         Character used to separate commands in-                                         the output template. Default '%'-    -t template   --template=template    Output template-    -c commands   --commands=commands    List of commands to be executed-    -C command    --add-command=command  Add to the list of commands to be executed-    -x screen     --screen=screen        On which X screen number to start-    -p position   --position=position    Specify position of xmobar. Same syntax as in config file+    #+begin_src haskell+      [Run Memory ["-t","Mem: <usedratio>%"] 10, Run Swap [] 10]+    #+end_src -  Mail bug reports and suggestions to <mail@jao.io>-#+end_src+    to run the Memory monitor plugin with the specified template, and the+    swap monitor plugin, with default options, every second. And here's an+    example of a template for the commands above using an icon:++    #+begin_src haskell+      template = "<icon=/home/jao/.xmobar/mem.xbm/><memory> <swap>"+    #+end_src++    This example will run "xclock" command when date is clicked:++    #+begin_src haskell+      template = "<action=`xclock`>%date%</action>"+    #+end_src++    The only internal available command is =Com= (see below Executing+    External Commands). All other commands are provided by plugins. xmobar+    comes with some plugins, providing a set of system monitors, a standard+    input reader, an Unix named pipe reader, a configurable date plugin, and+    much more: we list all available plugins below.++    Other commands can be created as plugins with the Plugin infrastructure.+    See below.++* Runtime behaviour+*** Running xmobar with =i3status=++ xmobar can be used to display information generated by [[http://i3wm.org/i3status/][i3status]], a small+ program that gathers system information and outputs it in formats+ suitable for being displayed by the dzen2 status bar, wmii's status bar+ or xmobar's =StdinReader=. See [[http://i3wm.org/i3status/manpage.html#_using_i3status_with_xmobar][i3status manual]] for further details.++*** Dynamically sizing xmobar++ See [[https://github.com/jaor/xmobar/issues/239#issuecomment-233206552][this idea]] by Jonas Camillus Jeppensen for a way of adapting+ dynamically xmobar's size and run it alongside a system tray widget such+ as trayer or stalonetray (although the idea is not limited to trays,+ really). For your convenience, there is a version of Jonas' script in+ [[../examples/padding-icon.sh][examples/padding-icon.sh]].++*** Signal Handling++    xmobar reacts to ~SIGUSR1~ and ~SIGUSR2~:++    - After receiving ~SIGUSR1~ xmobar moves its position to the next screen.++    - After receiving ~SIGUSR2~ xmobar repositions itself on the current+      screen.+* The DBus Interface++  When compiled with the optional =with_dbus= flag, xmobar can be+  controlled over dbus. All signals defined in [[https://github.com/jaor/xmobar/blob/master/src/Xmobar/System/Signal.hs][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.++  - 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:++  #+begin_src shell+  dbus-send \+      --session \+      --dest=org.Xmobar.Control \+      --type=method_call \+      --print-reply \+      '/org/Xmobar/Control' \+      org.Xmobar.Control.SendSignal \+      "string:Toggle 0"+  #+end_src++  It is also possible to send multiple signals at once:++  #+begin_src shell+    # send to another screen, reveal and toggle the persistent flag+    dbus-send [..] \+        "string:ChangeScreen 0" "string:Reveal 0" "string:TogglePersistent"+  #+end_src++  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.++  See [[window-managers.org::*Example of using][Interfacing with window managers]] for an example of how to use+  the DBus interface from xmonad.
examples/xmobar.config view
@@ -15,6 +15,7 @@        , iconRoot = "."        , allDesktops = True        , overrideRedirect = True+       , textOutputFormat = Ansi        , commands = [ Run Weather "EGPF" ["-t","<station>: <tempC>C",                                           "-L","18","-H","25",                                           "--normal","green",
examples/xmobar.hs view
@@ -1,6 +1,6 @@ ------------------------------------------------------------------------------ -- |--- Copyright: (c) 2018, 2019 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -49,6 +49,7 @@   , iconRoot = "."   , allDesktops = True   , overrideRedirect = True+  , textOutputFormat = Ansi   , commands = [ Run $ Weather "EGPH" ["-t","<station>: <tempC>C",                                         "-L","18","-H","25",                                         "--normal","green",
readme.org view
@@ -1,14 +1,15 @@-[[http://hackage.haskell.org/package/xmobar][https://img.shields.io/hackage/v/xmobar.svg]]+#+title: xmobar, a minimalistic status bar -* About+[[http://hackage.haskell.org/package/xmobar][https://img.shields.io/hackage/v/xmobar.svg]]  Xmobar is a minimalistic status bar. It was originally designed and-implemented by Andrea Rossato to work with [[http://xmonad.org][xmonad]], but it is actually-usable with any window manager.+implemented to work with [[http://xmonad.org][xmonad]], but it is actually usable with any+window manager in X11 and also (via its text output mode) Wayland.  Xmobar was inspired by the [[http://tuomov.iki.fi/software/][Ion3]] status bar, and supports similar features, like dynamic color management, icons, output templates, and-extensibility through plugins.+extensibility through plugins.  It is also able to write to standard+output, in a variety of formats.  These are some xmobar [[file:doc/screenshots][screenshots]] using the author's configuration: @@ -18,160 +19,208 @@  [[file:doc/screenshots/xmobar-exwm.png]] -This is the [[https://xmobar.org/changelog.html][changelog]] for recent releases.+Check [[./changelog.md][the change log]] for our release history.  We also have an IRC+channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].  * Installation-** From your Systems Package Manager+*** From your system's package manager -Xmobar is probably available from your distributions package manager!-Most distributions compile xmobar with the =all_extensions= flag, so you-don't have to.+    Xmobar is probably available from your distributions package+    manager!  Most distributions compile xmobar with the =all_extensions=+    flag, so you don't have to. -*** Arch Linux+***** Arch Linux -#+begin_src shell-  pacman -S xmobar-#+end_src+  #+begin_src shell+    pacman -S xmobar+  #+end_src -*** Debian/Ubuntu based+***** Debian/Ubuntu based -#+begin_src shell-  apt install xmobar-#+end_src+  #+begin_src shell+    apt install xmobar+  #+end_src -*** OpenSUSE+***** OpenSUSE -#+begin_src shell-  zypper install xmobar-#+end_src+  #+begin_src shell+    zypper install xmobar+  #+end_src -*** Void Linux+***** Void Linux -#+begin_src shell-  xbps-install xmobar-#+end_src+  #+begin_src shell+    xbps-install xmobar+  #+end_src -*** Gentoo-#+begin_src shell-  emerge --ask xmobar-#+end_src+***** Gentoo+  #+begin_src shell+    emerge --ask xmobar+  #+end_src -** Using cabal-install+*** Using cabal-install -Xmobar is available from [[http://hackage.haskell.org/package/xmobar/][Hackage]], and you can install it using-=cabal-install=:+    Xmobar is available from [[http://hackage.haskell.org/package/xmobar/][Hackage]], and you can install it using+    =cabal-install=: -#+begin_src shell-  cabal install xmobar-#+end_src+    #+begin_src shell+      cabal install xmobar+    #+end_src -Starting with version 0.35.1, xmobar now requires at least GHC version-8.4.x. to build. See [[https://github.com/jaor/xmobar/issues/461][this issue]] for more information.+    Starting with version 0.35.1, xmobar now requires at least GHC+    version 8.4.x. to build. See [[https://github.com/jaor/xmobar/issues/461][this issue]] for more information. -See [[file:doc/compiling.org][compiling]] for a list of optional compilation flags that will enable-some optional plugins. For instance, to install xmobar with all the-bells and whistles (this is probably what you want), use:+    See [[file:doc/compiling.org][compiling]] for a list of optional compilation flags that will+    enable some optional plugins. For instance, to install xmobar with+    all the bells and whistles (this is probably what you want), use: -#+begin_src shell-  cabal install xmobar --flags="all_extensions"-#+end_src+    #+begin_src shell+      cabal install xmobar --flags="all_extensions"+    #+end_src -** From source+*** From source -See [[file:doc/compiling.org][compiling]].+    See [[file:doc/compiling.org][compiling]].  * Running xmobar -You can run xmobar with:+  You can run xmobar with: -#+begin_src shell-  xmobar /path/to/config &-#+end_src+  #+begin_src shell+    xmobar /path/to/config &+  #+end_src -or+  or -#+begin_src shell-  xmobar &-#+end_src+  #+begin_src shell+    xmobar &+  #+end_src -if you have the default configuration file saved as-=$XDG\_CONFIG\_HOME/xmobar/xmobarrc= (defaulting to-=~/.config/xmobar/xmobarrc=), or =~/.xmobarrc=.+  if you have the default configuration file saved as+  =$XDG_CONFIG_HOME/xmobar/xmobarrc= (defaulting to+  =~/.config/xmobar/xmobarrc=), or =~/.xmobarrc=. -** Signal Handling+*** Running xmobar in text mode -Since 0.14 xmobar reacts to SIGUSR1 and SIGUSR2:+    By default, xmobar will run as an X11 application, in a docked+    window, but it is possible to redirect xmobar's to the standard+    output, optionally with color escape sequences.  In this mode,+    xmobar can be run inside a terminal o console, or its output piped+    to other applications, and there is no need for an X11 display+    (so, for instance, you could pipe xmobar's output to a Wayland+    application, such as swaybar.) -- After receiving SIGUSR1 xmobar moves its position to the next screen.+    To run xmobar in text mode, either pass the =-T= flag to its+    invocation: -- After receiving SIGUSR2 xmobar repositions itself on the current-  screen.+    #+begin_src shell+      xmobar -T /path/to/config &+    #+end_src -* Configuration and Further Links+    or set the parameter =textOutput= to True in its configuration.  You+    can also specify the format of color escapes, for instance,+    omitting them altogether with ~Plain~: -- If you want to jump straight into configuring xmobar, head over to the-  [[./doc/quick-start.org][quick-start]] guide.+    #+begin_src shell+      xmobar -TPlain /path/to/config &+    #+end_src -- If you want to get a detailed overview of all available plugins and-  monitors, visit the [[./doc/plugins.org][plugins]] file.+    Other options are ~Ansi~, ~Pango~, and ~Swaybar~. -- If you want to know how to contribute to the xmobar project, check out-  [[contributing.org][contributing]].+*** Using xmobar in Wayland with swaybar or waybar -- If you want to write your own plugins, see [[./doc/write-your-own-plugin.org][write-your-own-plugin]].+    In text mode, xmobar can be told to ouput its information using+    pango markup for colors and fonts, and it that way you can use it+    with swaybar or waybar, if you don't have actions or boxes in your+    template.  Here's a minimal ~bar~ configuration for sway's+    configuration file: -* Authors and credits+    #+begin_src conf+      bar {+        status_command xmobar -TPango+        pango_markup enabled+      }+    #+end_src -Andrea Rossato originally designed and implemented xmobar up to version-0.11.1. Since then, it is maintained and developed by [[https://jao.io][jao]], with the help-of the greater xmobar and Haskell communities.+    In case you want to use boxes around text or click actions in your+    template, you can use instead the format ~Swaybar~, which supports+    both.  This output format follows the JSON /swaybar-protocol/+    defined by swaybar.  Configure it simply with: -In particular, xmobar incorporates patches by Mohammed Alshiekh, Alex-Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos Boca, Ben-Boeckel, Ivan Brennan, Duncan Burke, Roman Cheplyaka, Patrick Chilton,-Antoine Eiche, Nathaniel Wesley Filardo, Guy Gastineau, John Goerzen,-Reto Hablützel, Juraj Hercek, Tomáš Janoušek, Ada Joule, Spencer-Janssen, Roman Joost, Jochen Keil, Sam Kirby, Lennart Kolmodin,-Krzysztof Kosciuszkiewicz, Dmitry Kurochkin, Todd Lunter, Vanessa-McHale, Robert J. Macomber, Dmitry Malikov, David McLean, Joan MIlev,-Marcin Mikołajczyk, Dino Morelli, Tony Morris, Eric Mrak, Thiago-Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Jens Petersen,-Alexander Polakov, Sibi Prabakaran, Pavan Rikhi, Petr Rockai, Andrew-Emmanuel Rosa, Sackville-West, Amir Saeid, Markus Scherer, Daniel-Schüssler, Olivier Schneider, Alexander Shabalin, Valentin Shirokov,-Peter Simons, Alexander Solovyov, Will Song, John Soo, John Soros,-Felix Springer, Travis Staton, Artem Tarasov, Samuli Thomasson, Edward-Tjörnhammar, Sergei Trofimovich, Thomas Tuegel, John Tyree, Jan-Vornberger, Anton Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun-Hu, Nikolay Yakimov, Edward Z. Yang, Leo Zhang, Norbert Zeh, and-Michal Zielonka.+    #+begin_src conf+      bar {+        status_command xmobar -TSwaybar+      }+    #+end_src -** Thanks+* Configuration and further Links -*Andrea Rossato*:+  - If you want to jump straight into running xmobar, head over to the+    [[./doc/quick-start.org][quick start guide]]. -Thanks to Robert Manea and Spencer Janssen for their help in-understanding how X works. They gave me suggestions on how to solve many-problems with xmobar.+  - If you want to get a detailed overview of all available plugins and+    monitors, visit the [[./doc/plugins.org][plugins index]]. -Thanks to Claus Reinke for make me understand existential types (or at-least for letting me think I grasp existential types...;-).+  - [[./doc/window-managers.org][Interfacing with window managers]] describes plugins and extensions+    for interacting with xmobar from your window manager. -*jao*:+  - If you want to know how to contribute to the xmobar project, check out+    [[contributing.org][contributing]]. -Thanks to Andrea for creating xmobar in the first place, and for giving-me the chance to contribute.+  - If you want to write your own plugins, see [[./doc/write-your-own-plugin.org][Write your own plugin]]. -* Related+  - To understand the internal mysteries of xmobar you may try reading+    [[https://wiki.haskell.org/X_window_programming_in_Haskell][this tutorial]] on X Window Programming in Haskell. -- To understand the internal mysteries of xmobar you may try reading-  [[https://wiki.haskell.org/X_window_programming_in_Haskell][this tutorial]] on X Window Programming in Haskell.+* Authors and credits +  Andrea Rossato originally designed and implemented xmobar up to+  version 0.11.1. Since then, it is maintained and developed by [[https://jao.io][jao]],+  with the help of the greater xmobar and Haskell communities.++  In particular, xmobar incorporates patches by Mohammed Alshiekh,+  Alex Ameen, Axel Angel, Dhananjay Balan, Claudio Bley, Dragos Boca,+  Ben Boeckel, Ivan Brennan, Duncan Burke, Roman Cheplyaka, Patrick+  Chilton, Antoine Eiche, Nathaniel Wesley Filardo, Guy Gastineau,+  John Goerzen, Reto Hablützel, Juraj Hercek, Tomáš Janoušek, Ada+  Joule, Spencer Janssen, Roman Joost, Pavel Kalugin, Jochen Keil, Sam+  Kirby, Lennart Kolmodin, Krzysztof Kosciuszkiewicz, Dmitry+  Kurochkin, Todd Lunter, Vanessa McHale, Robert J. Macomber, Dmitry+  Malikov, David McLean, Joan MIlev, Marcin Mikołajczyk, Dino Morelli,+  Tony Morris, Eric Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove,+  Martin Perner, Jens Petersen, Alexander Polakov, Sibi Prabakaran,+  Pavan Rikhi, Petr Rockai, Andrew Emmanuel Rosa, Sackville-West, Amir+  Saeid, Markus Scherer, Daniel Schüssler, Olivier Schneider,+  Alexander Shabalin, Valentin Shirokov, Peter Simons, Alexander+  Solovyov, Will Song, John Soo, John Soros, Felix Springer, Travis+  Staton, Artem Tarasov, Samuli Thomasson, Edward Tjörnhammar, Sergei+  Trofimovich, Thomas Tuegel, John Tyree, Jan Vornberger, Anton+  Vorontsov, Daniel Wagner, Zev Weiss, Phil Xiaojun Hu, Nikolay+  Yakimov, Edward Z. Yang, Leo Zhang, Norbert Zeh, and Michal+  Zielonka.++*** Thanks++  *Andrea Rossato*:++  Thanks to Robert Manea and Spencer Janssen for their help in+  understanding how X works. They gave me suggestions on how to solve many+  problems with xmobar.++  Thanks to Claus Reinke for make me understand existential types (or at+  least for letting me think I grasp existential types...;-).++  *jao*:++  Thanks to Andrea for creating xmobar in the first place, and for giving+  me the chance to contribute.++ * License  This software is released under a BSD-style license. See [[https://github.com/jaor/xmobar/raw/master/license][license]] for more details. -Copyright © 2010-2020 Jose Antonio Ortega Ruiz+Copyright © 2010-2022 Jose Antonio Ortega Ruiz  Copyright © 2007-2010 Andrea Rossato
src/Xmobar.hs view
@@ -3,7 +3,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  Xmobar--- Copyright   :  (c) 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2019 Jose Antonio Ortega Ruiz+-- Copyright   :  (c) 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2019, 2022 Jose Antonio Ortega Ruiz --                (c) 2007 Andrea Rossato -- License     :  BSD-style (see LICENSE) --@@ -51,9 +51,9 @@  import Xmobar.Run.Runnable import Xmobar.Run.Exec-import Xmobar.Run.Command import Xmobar.Config.Types import Xmobar.Config.Parse+import Xmobar.Plugins.Command import Xmobar.Plugins.BufferedPipeReader import Xmobar.Plugins.CommandReader import Xmobar.Plugins.Date
src/Xmobar/App/Config.hs view
@@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Config.Defaults--- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019, 2020, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -65,6 +65,8 @@                         "<fc=#00FF00>%uname%</fc> * <fc=#FF0000>%theDate%</fc>"            , verbose = False            , signal = SignalChan Nothing+           , textOutput = False+           , textOutputFormat = Plain            }  -- | Return the path to the xmobar data directory.  This directory is
− src/Xmobar/App/EventLoop.hs
@@ -1,283 +0,0 @@-{-# LANGUAGE CPP #-}----------------------------------------------------------------------------------- |--- Module: Xmobar.X11.EventLoop--- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz--- License: BSD3-style (see LICENSE)------ Maintainer: jao@gnu.org--- Stability: unstable--- Portability: portable--- Created: Sat Nov 24, 2018 19:40--------- Event loop-------------------------------------------------------------------------------------module Xmobar.App.EventLoop-    ( startLoop-    , startCommand-    , newRefreshLock-    , refreshLock-    ) where--import Prelude hiding (lookup)-import Graphics.X11.Xlib hiding (textExtents, textWidth)-import Graphics.X11.Xlib.Extras-import Graphics.X11.Xinerama-import Graphics.X11.Xrandr--import Control.Arrow ((&&&))-import Control.Monad.Reader-import Control.Concurrent-import Control.Concurrent.Async (Async, async)-import Control.Concurrent.STM-import Control.Exception (bracket_, handle, SomeException(..))-import Data.Bits-import Data.Map hiding (foldr, map, filter)-import Data.Maybe (fromJust, isJust)-import qualified Data.List.NonEmpty as NE--import Xmobar.System.Signal-import Xmobar.Config.Types (persistent, position, iconRoot, Config, Align(..), XPosition(..))-import Xmobar.Run.Exec-import Xmobar.Run.Runnable-import Xmobar.X11.Actions-import Xmobar.X11.Parsers-import Xmobar.X11.Window-import Xmobar.X11.Text-import Xmobar.X11.Draw-import Xmobar.X11.Bitmap as Bitmap-import Xmobar.X11.Types-import Xmobar.System.Utils (safeIndex)--#ifndef THREADED_RUNTIME-import Xmobar.X11.Events(nextEvent')-#endif--#ifdef XFT-import Graphics.X11.Xft-#endif--#ifdef DBUS-import Xmobar.System.DBus-#endif--runX :: XConf -> X () -> IO ()-runX xc f = runReaderT f xc--newRefreshLock :: IO (TMVar ())-newRefreshLock = newTMVarIO ()--refreshLock :: TMVar () -> IO a -> IO a-refreshLock var = bracket_ lock unlock-    where-        lock = atomically $ takeTMVar var-        unlock = atomically $ putTMVar var ()--refreshLockT :: TMVar () -> STM a -> STM a-refreshLockT var action = do-    takeTMVar var-    r <- action-    putTMVar var ()-    return r---- | Starts the main event loop and threads-startLoop :: XConf-          -> TMVar SignalType-          -> TMVar ()-          -> [[([Async ()], TVar String)]]-          -> IO ()-startLoop xcfg@(XConf _ _ w _ _ _ _) sig pauser vs = do-#ifdef XFT-    xftInitFtLibrary-#endif-    tv <- newTVarIO []-    _ <- forkIO (handle (handler "checker") (checker tv [] vs sig pauser))-#ifdef THREADED_RUNTIME-    _ <- forkOS (handle (handler "eventer") (eventer sig))-#else-    _ <- forkIO (handle (handler "eventer") (eventer sig))-#endif-#ifdef DBUS-    runIPC sig-#endif-    eventLoop tv xcfg [] sig-  where-    handler thing (SomeException e) =-      void $ putStrLn ("Thread " ++ thing ++ " failed: " ++ show e)-    -- Reacts on events from X-    eventer signal =-      allocaXEvent $ \e -> do-        dpy <- openDisplay ""-        xrrSelectInput dpy (defaultRootWindow dpy) rrScreenChangeNotifyMask-        selectInput dpy w (exposureMask .|. structureNotifyMask .|. buttonPressMask)--        forever $ do-#ifdef THREADED_RUNTIME-          nextEvent dpy e-#else-          nextEvent' dpy e-#endif-          ev <- getEvent e-          case ev of-            ConfigureEvent {} -> atomically $ putTMVar signal Reposition-            ExposeEvent {} -> atomically $ putTMVar signal Wakeup-            RRScreenChangeNotifyEvent {} -> atomically $ putTMVar signal Reposition-            ButtonEvent {} -> atomically $-                   putTMVar signal (Action (ev_button ev) (fi $ ev_x ev))-            _ -> return ()---- | Send signal to eventLoop every time a var is updated-checker :: TVar [String]-           -> [String]-           -> [[([Async ()], TVar String)]]-           -> TMVar SignalType-           -> TMVar ()-           -> IO ()-checker tvar ov vs signal pauser = do-      nval <- atomically $ refreshLockT pauser $ do-              nv <- mapM concatV vs-              guard (nv /= ov)-              writeTVar tvar nv-              return nv-      atomically $ putTMVar signal Wakeup-      checker tvar nval vs signal pauser-    where-      concatV = fmap concat . mapM (readTVar . snd)----- | Continuously wait for a signal from a thread or a interrupt handler-eventLoop :: TVar [String]-             -> XConf-             -> [([Action], Position, Position)]-             -> TMVar SignalType-             -> IO ()-eventLoop tv xc@(XConf d r w fs vos is cfg) as signal = do-      typ <- atomically $ takeTMVar signal-      case typ of-         Wakeup -> do-            str <- updateString cfg tv-            xc' <- updateCache d w is (iconRoot cfg) str >>=-                     \c -> return xc { iconS = c }-            as' <- updateActions xc r str-            runX xc' $ drawInWin r str-            eventLoop tv xc' as' signal--         Reposition ->-            reposWindow cfg--         ChangeScreen -> do-            ncfg <- updateConfigPosition cfg-            reposWindow ncfg--         Hide   t -> hide   (t*100*1000)-         Reveal t -> reveal (t*100*1000)-         Toggle t -> toggle t--         TogglePersistent -> eventLoop-            tv xc { config = cfg { persistent = not $ persistent cfg } } as signal--         Action but x -> action but x--    where-        isPersistent = not $ persistent cfg--        hide t-            | t == 0 =-                when isPersistent (hideWindow d w) >> eventLoop tv xc as signal-            | otherwise = do-                void $ forkIO-                     $ threadDelay t >> atomically (putTMVar signal $ Hide 0)-                eventLoop tv xc as signal--        reveal t-            | t == 0 = do-                when isPersistent (showWindow r cfg d w)-                eventLoop tv xc as signal-            | otherwise = do-                void $ forkIO-                     $ threadDelay t >> atomically (putTMVar signal $ Reveal 0)-                eventLoop tv xc as signal--        toggle t = do-            ismapped <- isMapped d w-            atomically (putTMVar signal $ if ismapped then Hide t else Reveal t)-            eventLoop tv xc as signal--        reposWindow rcfg = do-          r' <- repositionWin d w (NE.head fs) rcfg-          eventLoop tv (XConf d r' w fs vos is rcfg) as signal--        updateConfigPosition ocfg =-          case position ocfg of-            OnScreen n o -> do-              srs <- getScreenInfo d-              return (if n == length srs-                       then-                        (ocfg {position = OnScreen 1 o})-                       else-                        (ocfg {position = OnScreen (n+1) o}))-            o -> return (ocfg {position = OnScreen 1 o})--        action button x = do-          mapM_ runAction $-            filter (\(Spawn b _) -> button `elem` b) $-            concatMap (\(a,_,_) -> a) $-            filter (\(_, from, to) -> x >= from && x <= to) as-          eventLoop tv xc as signal---- $command---- | Runs a command as an independent thread and returns its Async handles--- and the TVar the command will be writing to.-startCommand :: TMVar SignalType-             -> (Runnable,String,String)-             -> IO ([Async ()], TVar String)-startCommand sig (com,s,ss)-    | alias com == "" = do var <- newTVarIO is-                           atomically $ writeTVar var (s ++ ss)-                           return ([], var)-    | otherwise = do var <- newTVarIO is-                     let cb str = atomically $ writeTVar var (s ++ str ++ ss)-                     a1 <- async $ start com cb-                     a2 <- async $ trigger com $ maybe (return ())-                                                 (atomically . putTMVar sig)-                     return ([a1, a2], var)-    where is = s ++ "Updating..." ++ ss--updateString :: Config -> TVar [String]-                -> 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, TextRenderInfo, Int, Maybe [Action])]]-                 -> IO [([Action], Position, Position)]-updateActions conf (Rectangle _ _ wid _) ~[left,center,right] = do-  let (d,fs) = (display &&& fontListS) conf-      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)-      getCoords (Icon s,_,_,a) = return (a, 0, fi $ iconW s)-      getCoords (Hspace w,_,_,a) = return (a, 0, fi w)-      partCoord off xs = map (\(a, x, x') -> (fromJust a, x, x')) $-                         filter (\(a, _,_) -> isJust a) $-                         scanl (\(_,_,x') (a,_,w') -> (a, x', x' + w'))-                               (Nothing, 0, off)-                               xs-      totSLen = foldr (\(_,_,len) -> (+) len) 0-      remWidth xs = fi wid - totSLen xs-      offs = 1-      offset a xs = case a of-                     C -> (remWidth xs + offs) `div` 2-                     R -> remWidth xs-                     L -> offs-  fmap concat $ mapM (\(a,xs) ->-                       (\xs' -> partCoord (offset a xs') xs') <$> strLn xs) $-                     zip [L,C,R] [left,center,right]
src/Xmobar/App/Main.hs view
@@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.Main--- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019, 2020, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -17,66 +17,29 @@  module Xmobar.App.Main (xmobar, xmobarMain, configFromArgs) where -import Control.Concurrent.Async (Async, cancel)-import Control.Concurrent.STM (newEmptyTMVarIO)-import Control.Exception (bracket)-import Control.Monad (unless) -import Data.Foldable (for_)-import qualified Data.Map as Map import Data.List (intercalate)-import Data.Maybe (isJust) import System.Posix.Process (executeFile) import System.Environment (getArgs) import System.FilePath ((</>), takeBaseName, takeDirectory, takeExtension) import Text.Parsec.Error (ParseError)-import Data.List.NonEmpty (NonEmpty(..)) -import Graphics.X11.Xlib+import Control.Monad (unless) +import Xmobar.App.Config import Xmobar.Config.Types import Xmobar.Config.Parse-import Xmobar.System.Signal (setupSignalHandler, withDeferSignals)-import Xmobar.Run.Template-import Xmobar.X11.Types-import Xmobar.X11.Text-import Xmobar.X11.Window+import Xmobar.X11.Loop (x11Loop)+import Xmobar.Text.Loop (textLoop) import Xmobar.App.Opts (recompileFlag, verboseFlag, getOpts, doOpts)-import Xmobar.App.EventLoop (startLoop, startCommand, newRefreshLock, refreshLock) import Xmobar.App.Compile (recompile, trace)-import Xmobar.App.Config-import Xmobar.App.Timer (withTimer)  xmobar :: Config -> IO ()-xmobar conf = withDeferSignals $ do-  initThreads-  d <- openDisplay ""-  fs    <- initFont d (font conf)-  fl    <- mapM (initFont d) (additionalFonts conf)-  cls   <- mapM (parseTemplate (commands conf) (sepChar conf))-                (splitTemplate (alignSep conf) (template conf))-  let confSig = unSignalChan (signal conf)-  sig   <- maybe newEmptyTMVarIO pure confSig-  unless (isJust confSig) $ setupSignalHandler sig-  refLock <- newRefreshLock-  withTimer (refreshLock refLock) $-    bracket (mapM (mapM $ startCommand sig) cls)-            cleanupThreads-            $ \vars -> do-      (r,w) <- createWin d fs conf-      let ic = Map.empty-          to = textOffset conf-          ts = textOffsets conf ++ replicate (length fl) (-1)-      startLoop (XConf d r w (fs :| fl) (to :| ts) ic conf) sig refLock vars+xmobar cfg = if textOutput cfg then textLoop cfg else x11Loop cfg  configFromArgs :: Config -> IO Config configFromArgs cfg = getArgs >>= getOpts >>= doOpts cfg . fst -cleanupThreads :: [[([Async ()], a)]] -> IO ()-cleanupThreads vars =-  for_ (concat vars) $ \(asyncs, _) ->-    for_ asyncs cancel- buildLaunch :: [String] -> Bool -> Bool -> String -> ParseError -> IO () buildLaunch args verb force p e = do   let exec = takeBaseName p@@ -110,5 +73,6 @@     Just p -> do r <- readConfig defaultConfig p                  case r of                    Left e ->-                     buildLaunch (filter (/= p) args) (verboseFlag flags) (recompileFlag flags) p e+                     buildLaunch (filter (/= p) args) (verboseFlag flags)+                                 (recompileFlag flags) p e                    Right (c, defs) -> doOpts c flags >>= xmobar' defs
src/Xmobar/App/Opts.hs view
@@ -1,7 +1,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.App.Opts--- Copyright: (c) 2018, 2019, 2020 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2019, 2020, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -14,7 +14,10 @@ -- ------------------------------------------------------------------------------ -module Xmobar.App.Opts (recompileFlag, verboseFlag, getOpts, doOpts) where+module Xmobar.App.Opts ( recompileFlag+                       , verboseFlag+                       , getOpts+                       , doOpts) where  import Control.Monad (when) import System.Console.GetOpt@@ -30,24 +33,25 @@           | Verbose           | Recompile           | Version-          | Font       String-          | AddFont    String-          | BgColor    String-          | FgColor    String-          | Alpha      String+          | TextOutput (Maybe String)+          | Font String+          | AddFont String+          | BgColor String+          | FgColor String+          | Alpha String           | T           | B           | D-          | AlignSep   String-          | Commands   String+          | AlignSep String+          | Commands String           | AddCommand String-          | SepChar    String-          | Template   String-          | OnScr      String-          | IconRoot   String-          | Position   String-          | WmClass    String-          | WmName     String+          | SepChar String+          | Template String+          | OnScr String+          | IconRoot String+          | Position String+          | WmClass String+          | WmName String        deriving (Show, Eq)  options :: [OptDescr Opts]@@ -56,8 +60,11 @@     , Option "v" ["verbose"] (NoArg Verbose) "Emit verbose debugging messages"     , Option "r" ["recompile"] (NoArg Recompile) "Force recompilation"     , Option "V" ["version"] (NoArg Version) "Show version information"+    , Option "T" ["text"] (OptArg TextOutput "color")+             "Write text-only output to stdout. Plain/Ansi/Pango/Swaybar"     , Option "f" ["font"] (ReqArg Font "font name") "Font name"-    , Option "N" ["add-font"] (ReqArg AddFont "font name") "Add to the list of additional fonts"+    , Option "N" ["add-font"] (ReqArg AddFont "font name")+             "Add to the list of additional fonts"     , Option "w" ["wmclass"] (ReqArg WmClass "class") "X11 WM_CLASS property"     , Option "n" ["wmname"] (ReqArg WmName "name") "X11 WM_NAME property"     , Option "B" ["bgcolor"] (ReqArg BgColor "bg color" )@@ -106,7 +113,7 @@  info :: String info = "xmobar " ++ showVersion version-        ++ "\n (C) 2010 - 2020 Jose A Ortega Ruiz"+        ++ "\n (C) 2010 - 2022 Jose A Ortega Ruiz"         ++ "\n (C) 2007 - 2010 Andrea Rossato\n "         ++ mail ++ "\n" ++ license ++ "\n" @@ -127,6 +134,10 @@     Help -> doOpts' conf     Version -> doOpts' conf     Recompile -> doOpts' conf+    TextOutput s -> doOpts' $ case s of+                                Just fmt -> conf {textOutput = True,+                                                  textOutputFormat = read fmt}+                                Nothing -> conf {textOutput = True}     Verbose -> doOpts' (conf {verbose = True})     Font s -> doOpts' (conf {font = s})     AddFont s -> doOpts' (conf {additionalFonts = additionalFonts conf ++ [s]})
− src/Xmobar/App/Timer.hs
@@ -1,221 +0,0 @@-{-# LANGUAGE LambdaCase #-}---------------------------------------------------------------------------------- |--- Module: Xmobar.App.Timer--- Copyright: (c) 2019, 2020 Tomáš Janoušek--- License: BSD3-style (see LICENSE)------ Maintainer: Tomáš Janoušek <tomi@nomi.cz>--- Stability: unstable------ Timer coalescing for recurring actions.------------------------------------------------------------------------------------module Xmobar.App.Timer-    ( doEveryTenthSeconds-    , tenthSeconds-    , withTimer-    ) where--import Control.Concurrent (threadDelay)-import Control.Concurrent.Async (withAsync)-import Control.Concurrent.STM-import Control.Exception-import Control.Monad (forever, forM, guard)-import Data.Foldable (foldrM, for_)-import Data.Int (Int64)-import Data.Map (Map)-import qualified Data.Map as M-import Data.Maybe (isJust, fromJust)-import Data.Time.Clock.POSIX (getPOSIXTime)-import Data.Unique-import System.IO.Unsafe (unsafePerformIO)--type Periods = Map Unique Period--data Tick = Tick (TMVar ()) | UnCoalesce--data Period = Period { rate :: Int64, next :: Int64, tick :: TMVar Tick }--data UnCoalesceException = UnCoalesceException deriving Show-instance Exception UnCoalesceException--{-# NOINLINE periodsVar #-}-periodsVar :: TVar (Maybe Periods)-periodsVar = unsafePerformIO $ newTVarIO Nothing--now :: IO Int64-now = do-    posix <- getPOSIXTime-    return $ floor (10 * posix)--newPeriod :: Int64 -> IO (Unique, Period)-newPeriod r = do-    u <- newUnique-    t <- now-    v <- newEmptyTMVarIO-    let t' = t - t `mod` r-    return (u, Period { rate = r, next = t', tick = v })---- | Perform a given action every N tenths of a second.------ The timer is aligned (coalesced) with other timers to minimize the number--- of wakeups and unnecessary redraws. If the action takes too long (one--- second or when the next timer is due), coalescing is disabled for it and it--- falls back to periodic sleep.-doEveryTenthSeconds :: Int -> IO () -> IO ()-doEveryTenthSeconds r action =-    doEveryTenthSecondsCoalesced r action `catch` \UnCoalesceException ->-        doEveryTenthSecondsSleeping r action---- | Perform a given action every N tenths of a second,--- coalesce with other timers using a given Timer instance.-doEveryTenthSecondsCoalesced :: Int -> IO () -> IO ()-doEveryTenthSecondsCoalesced r action = do-    (u, p) <- newPeriod (fromIntegral r)-    bracket_ (push u p) (pop u) $ forever $ bracket (wait p) done $ const action-    where-        push u p = atomically $ modifyTVar' periodsVar $ \case-            Just periods -> Just $ M.insert u p periods-            Nothing -> throw UnCoalesceException-        pop u = atomically $ modifyTVar' periodsVar $ \case-            Just periods -> Just $ M.delete u periods-            Nothing -> Nothing--        wait p = atomically (takeTMVar $ tick p) >>= \case-            Tick doneVar -> return doneVar-            UnCoalesce -> throwIO UnCoalesceException-        done doneVar = atomically $ putTMVar doneVar ()---- | Perform a given action every N tenths of a second,--- making no attempt to synchronize with other timers.-doEveryTenthSecondsSleeping :: Int -> IO () -> IO ()-doEveryTenthSecondsSleeping r action = go-    where go = action >> tenthSeconds r >> go---- | Sleep for a given amount of tenths of a second.------ (Work around the Int max bound: since threadDelay takes an Int, it--- is not possible to set a thread delay grater than about 45 minutes.--- With a little recursion we solve the problem.)-tenthSeconds :: Int -> IO ()-tenthSeconds s | s >= x = do threadDelay (x * 100000)-                             tenthSeconds (s - x)-               | otherwise = threadDelay (s * 100000)-               where x = (maxBound :: Int) `div` 100000---- | Start the timer coordination thread and perform a given IO action (this--- is meant to surround the entire xmobar execution), terminating the timer--- thread afterwards.------ Additionally, if the timer thread fails, individual--- 'doEveryTenthSecondsCoalesced' invocations that are waiting to be--- coordinated by it are notified to fall back to periodic sleeping.------ The timer thread _will_ fail immediately when running in a non-threaded--- RTS.-withTimer :: (IO () -> IO ()) -> IO a -> IO a-withTimer pauseRefresh action =-    withAsync (timerThread `finally` cleanup) $ const action-    where-        timerThread = do-            atomically $ writeTVar periodsVar $ Just M.empty-            timerLoop pauseRefresh--        cleanup = atomically $ readTVar periodsVar >>= \case-            Just periods -> do-                for_ periods unCoalesceTimer'-                writeTVar periodsVar Nothing-            Nothing -> return ()--timerLoop :: (IO () -> IO ()) -> IO ()-timerLoop pauseRefresh = forever $ do-    tNow <- now-    (toFire, tMaybeNext) <- atomically $ do-        periods <- fromJust <$> readTVar periodsVar-        let toFire = timersToFire tNow periods-        let periods' = advanceTimers tNow periods-        let tMaybeNext = nextFireTime periods'-        writeTVar periodsVar $ Just periods'-        return (toFire, tMaybeNext)-    pauseRefresh $ do-        -- To avoid multiple refreshes, pause refreshing for up to 1 second,-        -- fire timers and wait for them to finish (update their text).-        -- Those that need more time (e.g. weather monitors) will be dropped-        -- from timer coalescing and will fall back to periodic sleep.-        timeoutVar <- registerDelay $ case tMaybeNext of-            Just tNext -> fromIntegral ((tNext - tNow) `max` 10) * 100000-            Nothing -> 1000000-        fired <- fireTimers toFire-        timeouted <- waitForTimers timeoutVar fired-        unCoalesceTimers timeouted-    delayUntilNextFire--advanceTimers :: Int64 -> Periods -> Periods-advanceTimers t = M.map advance-    where-        advance p | next p <= t = p { next = t - t `mod` rate p + rate p }-                  | otherwise = p--timersToFire :: Int64 -> Periods -> [(Unique, Period)]-timersToFire t periods = [ (u, p) | (u, p) <- M.toList periods, next p <= t ]--nextFireTime :: Periods -> Maybe Int64-nextFireTime periods-    | M.null periods = Nothing-    | otherwise = Just $ minimum [ next p | p <- M.elems periods ]--fireTimers :: [(Unique, Period)] -> IO [(Unique, TMVar ())]-fireTimers toFire = atomically $ forM toFire $ \(u, p) -> do-    doneVar <- newEmptyTMVar-    putTMVar (tick p) (Tick doneVar)-    return (u, doneVar)--waitForTimers :: TVar Bool -> [(Unique, TMVar ())] -> IO [Unique]-waitForTimers timeoutVar fired = atomically $ do-    timeoutOver <- readTVar timeoutVar-    dones <- forM fired $ \(u, doneVar) -> do-        done <- isJust <$> tryReadTMVar doneVar-        return (u, done)-    guard $ timeoutOver || all snd dones-    return [u | (u, False) <- dones]---- | Handle slow timers (drop and signal them to stop coalescing).-unCoalesceTimers :: [Unique] -> IO ()-unCoalesceTimers timers = atomically $ do-    periods <- fromJust <$> readTVar periodsVar-    periods' <- foldrM unCoalesceTimer periods timers-    writeTVar periodsVar $ Just periods'--unCoalesceTimer :: Unique -> Periods -> STM Periods-unCoalesceTimer u periods = do-    unCoalesceTimer' (periods M.! u)-    return $ u `M.delete` periods--unCoalesceTimer' :: Period -> STM ()-unCoalesceTimer' p = do-    _ <- tryTakeTMVar (tick p)-    putTMVar (tick p) UnCoalesce--delayUntilNextFire :: IO ()-delayUntilNextFire = do-    Just periods <- readTVarIO periodsVar-    let tMaybeNext = nextFireTime periods-    tNow <- now-    delayVar <- case tMaybeNext of-        Just tNext -> do-            -- Work around the Int max bound: threadDelay takes an Int, we can-            -- only sleep for so long, which is okay, we'll just check timers-            -- sooner and sleep again.-            let maxDelay = (maxBound :: Int) `div` 100000-                delay = (tNext - tNow) `min` fromIntegral maxDelay-                delayUsec = fromIntegral delay * 100000-            registerDelay delayUsec-        Nothing -> newTVarIO False-    atomically $ do-        delayOver <- readTVar delayVar-        periods' <- fromJust <$> readTVar periodsVar-        let tMaybeNext' = nextFireTime periods'-        -- Return also if a new period is added (it may fire sooner).-        guard $ delayOver || tMaybeNext /= tMaybeNext'
src/Xmobar/Config/Parse.hs view
@@ -2,7 +2,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Config.Parse--- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2020, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -61,8 +61,9 @@        perms = permute $ Config               <$?> pFont <|?> pFontList <|?> pWmClass <|?> pWmName-              <|?> pBgColor <|?> pFgColor-              <|?> pPosition <|?> pTextOffset <|?> pTextOffsets+              <|?> pBgColor <|?> pFgColor <|?> pPosition+              <|?> pTextOutput <|?> pTextOutputFormat+              <|?> pTextOffset <|?> pTextOffsets               <|?> pIconOffset <|?> pBorder               <|?> pBdColor <|?> pBdWidth <|?> pAlpha <|?> pHideOnStart               <|?> pAllDesktops <|?> pOverrideRedirect <|?> pPickBroadest@@ -70,15 +71,18 @@               <|?> pCommands <|?> pSepChar <|?> pAlignSep <|?> pTemplate               <|?> pVerbose <|?> pSignal -      fields    = [ "font", "additionalFonts","bgColor", "fgColor"+      fields    = [ "font", "additionalFonts", "bgColor", "fgColor"                   , "wmClass", "wmName", "sepChar"                   , "alignSep" , "border", "borderColor" ,"template"                   , "position" , "textOffset", "textOffsets", "iconOffset"                   , "allDesktops", "overrideRedirect", "pickBroadest"                   , "hideOnStart", "lowerOnStart", "persistent", "iconRoot"-                  , "alpha", "commands", "verbose", "signal"+                  , "alpha", "commands", "verbose", "signal", "textOutput"+                  , "textOutputFormat"                   ] +      pTextOutput = readField textOutput "textOutput"+      pTextOutputFormat = readField textOutputFormat "textOutputFormat"       pFont = strField font "font"       pFontList = strListField additionalFonts "additionalFonts"       pWmClass = strField wmClass "wmClass"
src/Xmobar/Config/Types.hs view
@@ -16,7 +16,7 @@     ( -- * Configuration       -- $config       Config (..)-    , XPosition (..), Align (..), Border(..)+    , XPosition (..), Align (..), Border (..), TextOutputFormat (..)     , SignalChan (..)     ) where @@ -36,6 +36,8 @@            , bgColor :: String      -- ^ Backgroud color            , fgColor :: String      -- ^ Default font color            , position :: XPosition  -- ^ Top Bottom or Static+           , textOutput :: Bool     -- ^ Write data to stdout instead of X+           , textOutputFormat :: TextOutputFormat -- ^ Which color format to use for stdout: Ansi or Pango            , textOffset :: Int      -- ^ Offset from top of window for text            , textOffsets :: [Int]   -- ^ List of offsets for additionalFonts            , iconOffset :: Int      -- ^ Offset from top of window for icons@@ -95,6 +97,8 @@             | BottomBM Int             | FullBM Int               deriving ( Read, Show, Eq )++data TextOutputFormat = Plain | Ansi | Pango | Swaybar deriving (Read, Show, Eq)  newtype SignalChan = SignalChan { unSignalChan :: Maybe (STM.TMVar SignalType) } 
+ src/Xmobar/Plugins/Command.hs view
@@ -0,0 +1,54 @@+------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Plugins.Command+-- Copyright: (c) 2018, 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Sun Dec 02, 2018 05:29+--+--+-- The basic Command plugin+--+------------------------------------------------------------------------------+++module Xmobar.Plugins.Command where++import Control.Exception (handle, SomeException(..))+import System.Process+import System.Exit+import System.IO (hClose, hGetLine)++import Xmobar.Run.Exec++data Command = Com Program Args Alias Rate+             | ComX Program Args String Alias Rate+               deriving (Show,Read,Eq)++type Args    = [String]+type Program = String+type Alias   = String+type Rate    = Int++instance Exec Command where+    alias (ComX p _ _ a _) =+      if p /= "" then (if a == "" then p else a) else ""+    alias (Com p a al r) = alias (ComX p a "" al r)+    start (Com p as al r) cb =+      start (ComX p as ("Could not execute command " ++ p) al r) cb+    start (ComX prog args msg _ r) cb = if r > 0 then go else exec+        where go = doEveryTenthSeconds r exec+              exec = do+                (i,o,e,p) <- runInteractiveProcess prog args Nothing Nothing+                exit <- waitForProcess p+                let closeHandles = hClose o >> hClose i >> hClose e+                    getL = handle (\(SomeException _) -> return "")+                                  (hGetLine o)+                case exit of+                  ExitSuccess -> do str <- getL+                                    closeHandles+                                    cb str+                  _ -> closeHandles >> cb msg
src/Xmobar/Plugins/Monitors/Cpu.hs view
@@ -4,7 +4,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  Plugins.Monitors.Cpu--- Copyright   :  (c) 2011, 2017 Jose Antonio Ortega Ruiz+-- Copyright   :  (c) 2011, 2017, 2022 Jose Antonio Ortega Ruiz --                (c) 2007-2010 Andrea Rossato -- License     :  BSD-style (see LICENSE) --@@ -30,7 +30,7 @@ import Xmobar.Plugins.Monitors.Common import Data.IORef (newIORef) import System.Console.GetOpt-import Xmobar.App.Timer (doEveryTenthSeconds)+import Xmobar.Run.Timer (doEveryTenthSeconds) import Control.Monad (void) import Xmobar.Plugins.Monitors.Cpu.Common (CpuData(..)) 
src/Xmobar/Plugins/StdinReader.hs view
@@ -26,7 +26,7 @@ import System.IO import System.IO.Error (isEOFError) import Xmobar.Run.Exec-import Xmobar.X11.Actions (stripActions)+import Xmobar.Run.Actions (stripActions) import Control.Exception import Control.Monad (forever) 
src/Xmobar/Plugins/XMonadLog.hs view
@@ -21,14 +21,17 @@ import Graphics.X11 import Graphics.X11.Xlib.Extras import Xmobar.Run.Exec+import Xmobar.Run.Actions (stripActions)+ #ifdef UTF8 #undef UTF8 import Codec.Binary.UTF8.String as UTF8 #define UTF8 #endif+ import Foreign.C (CChar)+import Data.List (intercalate) import Xmobar.X11.Events (nextEvent')-import Xmobar.X11.Actions (stripActions)  data XMonadLog = XMonadLog                | UnsafeXMonadLog@@ -54,11 +57,12 @@                 UnsafeXPropertyLog a -> a                 NamedXPropertyLog a _ -> a                 UnsafeNamedXPropertyLog a _ -> a+            stripNL = intercalate " - " . lines             sanitize = case x of                 UnsafeXMonadLog -> id                 UnsafeXPropertyLog _ -> id                 UnsafeNamedXPropertyLog _ _ -> id-                _ -> stripActions+                _ -> stripActions . stripNL          d <- openDisplay ""         xlog <- internAtom d atom False
+ src/Xmobar/Run/Actions.hs view
@@ -0,0 +1,43 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Xmobar.Run.Actions+-- Copyright   :  (c) Alexander Polakov+-- License     :  BSD-style (see LICENSE)+--+-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability   :  unstable+-- Portability :  unportable+--+-----------------------------------------------------------------------------++module Xmobar.Run.Actions ( Button+                          , Action(..)+                          , runAction+                          , runAction'+                          , stripActions) where++import System.Process (system)+import Control.Monad (void)+import Text.Regex (Regex, subRegex, mkRegex, matchRegex)+import Data.Word (Word32)++type Button = Word32++data Action = Spawn [Button] String deriving (Eq, Read, Show)++runAction :: Action -> IO ()+runAction (Spawn _ s) = void $ system (s ++ "&")++-- | Run action with stdout redirected to stderr+runAction' :: Action -> IO ()+runAction' (Spawn _ s) = void $ system (s ++ " 1>&2 &")++stripActions :: String -> String+stripActions s = case matchRegex actionRegex s of+  Nothing -> s+  Just _  -> stripActions strippedOneLevel+  where+      strippedOneLevel = subRegex actionRegex s "[action=\\1\\2]\\3[/action]"++actionRegex :: Regex+actionRegex = mkRegex "<action=`?([^>`]*)`?( +button=[12345]+)?>(.+)</action>"
− src/Xmobar/Run/Command.hs
@@ -1,54 +0,0 @@---------------------------------------------------------------------------------- |--- Module: Xmobar.Plugins.Command--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz--- License: BSD3-style (see LICENSE)------ Maintainer: jao@gnu.org--- Stability: unstable--- Portability: portable--- Created: Sun Dec 02, 2018 05:29--------- The basic Command plugin-------------------------------------------------------------------------------------module Xmobar.Run.Command where--import Control.Exception (handle, SomeException(..))-import System.Process-import System.Exit-import System.IO (hClose, hGetLine)--import Xmobar.Run.Exec--data Command = Com Program Args Alias Rate-             | ComX Program Args String Alias Rate-               deriving (Show,Read,Eq)--type Args    = [String]-type Program = String-type Alias   = String-type Rate    = Int--instance Exec Command where-    alias (ComX p _ _ a _) =-      if p /= "" then (if a == "" then p else a) else ""-    alias (Com p a al r) = alias (ComX p a "" al r)-    start (Com p as al r) cb =-      start (ComX p as ("Could not execute command " ++ p) al r) cb-    start (ComX prog args msg _ r) cb = if r > 0 then go else exec-        where go = doEveryTenthSeconds r exec-              exec = do-                (i,o,e,p) <- runInteractiveProcess prog args Nothing Nothing-                exit <- waitForProcess p-                let closeHandles = hClose o >> hClose i >> hClose e-                    getL = handle (\(SomeException _) -> return "")-                                  (hGetLine o)-                case exit of-                  ExitSuccess -> do str <- getL-                                    closeHandles-                                    cb str-                  _ -> closeHandles >> cb msg
src/Xmobar/Run/Exec.hs view
@@ -22,7 +22,7 @@ import Prelude import Data.Char -import Xmobar.App.Timer (doEveryTenthSeconds, tenthSeconds)+import Xmobar.Run.Timer (doEveryTenthSeconds, tenthSeconds) import Xmobar.System.Signal  class Show e => Exec e where
+ src/Xmobar/Run/Loop.hs view
@@ -0,0 +1,126 @@+{-# LANGUAGE CPP #-}++------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Run.Loop+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: unportable+-- Created: Fri Jan 28, 2022 03:20+--+--+-- Running a thread for each defined Command in a loop+--+------------------------------------------------------------------------------++module Xmobar.Run.Loop (LoopFunction, loop) where++import Control.Concurrent (forkIO)+import Control.Exception (bracket_, bracket, handle, SomeException(..))+import Control.Concurrent.STM+import Control.Concurrent.Async (Async, async, cancel)+import Control.Monad (guard, void, unless)+import Data.Maybe (isJust)+import Data.Foldable (for_)++import Xmobar.System.Signal+import Xmobar.Config.Types+import Xmobar.Run.Runnable (Runnable)+import Xmobar.Run.Exec (start, trigger, alias)+import Xmobar.Run.Template+import Xmobar.Run.Timer (withTimer)++#ifdef DBUS+import Xmobar.System.DBus+#endif++newRefreshLock :: IO (TMVar ())+newRefreshLock = newTMVarIO ()++refreshLock :: TMVar () -> IO a -> IO a+refreshLock var = bracket_ lock unlock+    where+        lock = atomically $ takeTMVar var+        unlock = atomically $ putTMVar var ()++refreshLockT :: TMVar () -> STM a -> STM a+refreshLockT var action = do+    takeTMVar var+    r <- action+    putTMVar var ()+    return r++type LoopFunction = TMVar SignalType -> TVar [String] -> IO ()++loop :: Config -> LoopFunction -> IO ()+loop conf looper = withDeferSignals $ do+  cls <- mapM (parseTemplate (commands conf) (sepChar conf))+                (splitTemplate (alignSep conf) (template conf))+  let confSig = unSignalChan (signal conf)+  sig <- maybe newEmptyTMVarIO pure confSig+  unless (isJust confSig) $ setupSignalHandler sig+  refLock <- newRefreshLock+  withTimer (refreshLock refLock) $+    bracket (mapM (mapM $ startCommand sig) cls)+            cleanupThreads+            $ \vars -> do+      tv <- initLoop sig refLock vars+      looper sig tv++cleanupThreads :: [[([Async ()], a)]] -> IO ()+cleanupThreads vars =+  for_ (concat vars) $ \(asyncs, _) ->+    for_ asyncs cancel++-- | Initialises context for an event loop, returning a TVar that+-- will hold the current list of values computed by commands.+initLoop :: TMVar SignalType -> TMVar () -> [[([Async ()], TVar String)]]+         -> IO (TVar [String])+initLoop sig lock vs = do+  tv <- newTVarIO ([] :: [String])+  _ <- forkIO (handle (handler "checker") (checker tv [] vs sig lock))+#ifdef DBUS+  runIPC sig+#endif+  return tv+  where+    handler thing (SomeException e) =+      void $ putStrLn ("Thread " ++ thing ++ " failed: " ++ show e)++-- | Runs a command as an independent thread and returns its Async handles+-- and the TVar the command will be writing to.+startCommand :: TMVar SignalType+             -> (Runnable,String,String)+             -> IO ([Async ()], TVar String)+startCommand sig (com,s,ss)+    | alias com == "" = do var <- newTVarIO is+                           atomically $ writeTVar var (s ++ ss)+                           return ([], var)+    | otherwise = do var <- newTVarIO is+                     let cb str = atomically $ writeTVar var (s ++ str ++ ss)+                     a1 <- async $ start com cb+                     a2 <- async $ trigger com $ maybe (return ())+                                                 (atomically . putTMVar sig)+                     return ([a1, a2], var)+    where is = s ++ "Updating..." ++ ss++-- | Send signal to eventLoop every time a var is updated+checker :: TVar [String]+           -> [String]+           -> [[([Async ()], TVar String)]]+           -> TMVar SignalType+           -> TMVar ()+           -> IO ()+checker tvar ov vs sig pauser = do+      nval <- atomically $ refreshLockT pauser $ do+              nv <- mapM concatV vs+              guard (nv /= ov)+              writeTVar tvar nv+              return nv+      atomically $ putTMVar sig Wakeup+      checker tvar nval vs sig pauser+    where+      concatV = fmap concat . mapM (readTVar . snd)
+ src/Xmobar/Run/Parsers.hs view
@@ -0,0 +1,234 @@+{-# LANGUAGE FlexibleContexts #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Xmobar.Run.Parsers+-- Copyright   :  (c) Andrea Rossato+-- License     :  BSD-style (see LICENSE)+--+-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>+-- Stability   :  unstable+-- Portability :  portable+--+-- Parsing for template substrings+--+-----------------------------------------------------------------------------++module Xmobar.Run.Parsers ( parseString+                          , colorComponents+                          , Segment+                          , FontIndex+                          , Box(..)+                          , BoxBorder(..)+                          , BoxOffset(..)+                          , BoxMargins(..)+                          , TextRenderInfo(..)+                          , Widget(..)) where++import Control.Monad (guard, mzero)+import Data.Maybe (fromMaybe)+import Data.Int (Int32)+import Text.ParserCombinators.Parsec+import Text.Read (readMaybe)+import Foreign.C.Types (CInt)++import Xmobar.Config.Types+import Xmobar.Run.Actions++data Widget = Icon String | Text String | Hspace Int32 deriving Show++data BoxOffset = BoxOffset Align Int32 deriving (Eq, Show)+-- margins: Top, Right, Bottom, Left+data BoxMargins = BoxMargins Int32 Int32 Int32 Int32 deriving (Eq, Show)+data BoxBorder = BBTop+               | BBBottom+               | BBVBoth+               | BBLeft+               | BBRight+               | BBHBoth+               | BBFull+                 deriving ( Read, Eq, Show )+data Box = Box BoxBorder BoxOffset CInt String BoxMargins deriving (Eq, Show)+data TextRenderInfo =+    TextRenderInfo { tColorsString   :: String+                   , tBgTopOffset    :: Int32+                   , tBgBottomOffset :: Int32+                   , tBoxes          :: [Box]+                   } deriving Show+type FontIndex   = Int++type Segment = (Widget, TextRenderInfo, FontIndex, Maybe [Action])++-- | Runs the string parser+parseString :: Config -> String -> IO [Segment]+parseString c s =+    case parse (stringParser ci 0 Nothing) "" s of+      Left  _ -> return [(Text $ "Could not parse string: " ++ s+                          , ci+                          , 0+                          , Nothing)]+      Right x -> return (concat x)+    where ci = TextRenderInfo (fgColor c) 0 0 []++-- | Splits a colors string into its two components+colorComponents :: Config -> String -> (String, String)+colorComponents conf c =+  case break (==',') c of+    (f,',':b) -> (f, b)+    (f,    _) -> (f, bgColor conf)++allParsers :: TextRenderInfo+           -> FontIndex+           -> Maybe [Action]+           -> Parser [Segment]+allParsers c f a =  textParser c f a+                <|> try (iconParser c f a)+                <|> try (hspaceParser c f a)+                <|> try (rawParser c f a)+                <|> try (actionParser c f a)+                <|> try (fontParser c a)+                <|> try (boxParser c f a)+                <|> colorParser c f a++-- | Gets the string and combines the needed parsers+stringParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [[Segment]]+stringParser c f a = manyTill (allParsers c f a) eof++-- | Parses a maximal string without markup.+textParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [Segment]+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 "hspace=") <|>+                                     try (string "raw=") <|>+                                     try (string "/fn>") <|>+                                     try (string "/box>") <|>+                                     string "/fc>"))+                      return [(Text s, c, f, a)]++-- | Parse a "raw" tag, which we use to prevent other tags from creeping in.+-- The format here is net-string-esque: a literal "<raw=" followed by a+-- 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 :: TextRenderInfo+          -> FontIndex+          -> Maybe [Action]+          -> Parser [Segment]+rawParser c f a = do+  string "<raw="+  lenstr <- many1 digit+  char ':'+  case reads lenstr of+    [(len,[])] -> do+      guard ((len :: Integer) <= fromIntegral (maxBound :: Int))+      s <- count (fromIntegral len) anyChar+      string "/>"+      return [(Text s, c, f, a)]+    _ -> mzero++-- | Wrapper for notFollowedBy that returns the result of the first parser.+--   Also works around the issue that, at least in Parsec 3.0.0, notFollowedBy+--   accepts only parsers with return type Char.+notFollowedBy' :: Parser a -> Parser b -> Parser a+notFollowedBy' p e = do x <- p+                        notFollowedBy $ try (e >> return '*')+                        return x++iconParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [Segment]+iconParser c f a = do+  string "<icon="+  i <- manyTill (noneOf ">") (try (string "/>"))+  return [(Icon i, c, f, a)]++hspaceParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [Segment]+hspaceParser c f a = do+  string "<hspace="+  pVal <- manyTill digit (try (string "/>"))+  return [(Hspace (fromMaybe 0 $ readMaybe pVal), c, f, a)]++actionParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [Segment]+actionParser c f act = do+  string "<action="+  command <- choice [between (char '`') (char '`') (many1 (noneOf "`")),+                   many1 (noneOf ">")]+  buttons <- (char '>' >> return "1") <|> (space >> spaces >>+    between (string "button=") (string ">") (many1 (oneOf "12345")))+  let a = Spawn (toButtons buttons) command+      a' = case act of+        Nothing -> Just [a]+        Just act' -> Just $ a : act'+  s <- manyTill (allParsers c f a') (try $ string "</action>")+  return (concat s)++toButtons :: String -> [Button]+toButtons = map (\x -> read [x])++-- | Parsers a string wrapped in a color specification.+colorParser :: TextRenderInfo -> FontIndex -> Maybe [Action] -> Parser [Segment]+colorParser (TextRenderInfo _ _ _ bs) f a = do+  c <- between (string "<fc=") (string ">") colors+  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 [Segment]+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 :: TextRenderInfo -> Maybe [Action] -> Parser [Segment]+fontParser c a = do+  f <- between (string "<fn=") (string ">") colors+  s <- manyTill (allParsers c (fromMaybe 0 $ readMaybe f) a) (try $ string "</fn>")+  return (concat s)++-- | Parses a color specification (hex or named)+colors :: Parser String+colors = many1 (alphaNum <|> char ',' <|> char ':' <|> char '#')
src/Xmobar/Run/Template.hs view
@@ -20,8 +20,9 @@ import qualified Data.Map as Map import Text.ParserCombinators.Parsec +import Xmobar.Plugins.Command+ import Xmobar.Run.Exec-import Xmobar.Run.Command import Xmobar.Run.Runnable  defaultAlign :: String
+ src/Xmobar/Run/Timer.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE LambdaCase #-}+------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Run.Timer+-- Copyright: (c) 2019, 2020, 2022 Tomáš Janoušek+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: Tomáš Janoušek <tomi@nomi.cz>+-- Stability: unstable+--+-- Timer coalescing for recurring actions.+--+------------------------------------------------------------------------------++module Xmobar.Run.Timer+    ( doEveryTenthSeconds+    , tenthSeconds+    , withTimer+    ) where++import Control.Concurrent (threadDelay)+import Control.Concurrent.Async (withAsync)+import Control.Concurrent.STM+import Control.Exception+import Control.Monad (forever, forM, guard)+import Data.Foldable (foldrM, for_)+import Data.Int (Int64)+import Data.Map (Map)+import qualified Data.Map as M+import Data.Maybe (isJust, fromJust)+import Data.Time.Clock.POSIX (getPOSIXTime)+import Data.Unique+import System.IO.Unsafe (unsafePerformIO)++type Periods = Map Unique Period++data Tick = Tick (TMVar ()) | UnCoalesce++data Period = Period { rate :: Int64, next :: Int64, tick :: TMVar Tick }++data UnCoalesceException = UnCoalesceException deriving Show+instance Exception UnCoalesceException++{-# NOINLINE periodsVar #-}+periodsVar :: TVar (Maybe Periods)+periodsVar = unsafePerformIO $ newTVarIO Nothing++now :: IO Int64+now = do+    posix <- getPOSIXTime+    return $ floor (10 * posix)++newPeriod :: Int64 -> IO (Unique, Period)+newPeriod r = do+    u <- newUnique+    t <- now+    v <- newEmptyTMVarIO+    let t' = t - t `mod` r+    return (u, Period { rate = r, next = t', tick = v })++-- | Perform a given action every N tenths of a second.+--+-- The timer is aligned (coalesced) with other timers to minimize the number+-- of wakeups and unnecessary redraws. If the action takes too long (one+-- second or when the next timer is due), coalescing is disabled for it and it+-- falls back to periodic sleep.+doEveryTenthSeconds :: Int -> IO () -> IO ()+doEveryTenthSeconds r action =+    doEveryTenthSecondsCoalesced r action `catch` \UnCoalesceException ->+        doEveryTenthSecondsSleeping r action++-- | Perform a given action every N tenths of a second,+-- coalesce with other timers using a given Timer instance.+doEveryTenthSecondsCoalesced :: Int -> IO () -> IO ()+doEveryTenthSecondsCoalesced r action = do+    (u, p) <- newPeriod (fromIntegral r)+    bracket_ (push u p) (pop u) $ forever $ bracket (wait p) done $ const action+    where+        push u p = atomically $ modifyTVar' periodsVar $ \case+            Just periods -> Just $ M.insert u p periods+            Nothing -> throw UnCoalesceException+        pop u = atomically $ modifyTVar' periodsVar $ \case+            Just periods -> Just $ M.delete u periods+            Nothing -> Nothing++        wait p = atomically (takeTMVar $ tick p) >>= \case+            Tick doneVar -> return doneVar+            UnCoalesce -> throwIO UnCoalesceException+        done doneVar = atomically $ putTMVar doneVar ()++-- | Perform a given action every N tenths of a second,+-- making no attempt to synchronize with other timers.+doEveryTenthSecondsSleeping :: Int -> IO () -> IO ()+doEveryTenthSecondsSleeping r action = go+    where go = action >> tenthSeconds r >> go++-- | Sleep for a given amount of tenths of a second.+--+-- (Work around the Int max bound: since threadDelay takes an Int, it+-- is not possible to set a thread delay grater than about 45 minutes.+-- With a little recursion we solve the problem.)+tenthSeconds :: Int -> IO ()+tenthSeconds s | s >= x = do threadDelay (x * 100000)+                             tenthSeconds (s - x)+               | otherwise = threadDelay (s * 100000)+               where x = (maxBound :: Int) `div` 100000++-- | Start the timer coordination thread and perform a given IO action (this+-- is meant to surround the entire xmobar execution), terminating the timer+-- thread afterwards.+--+-- Additionally, if the timer thread fails, individual+-- 'doEveryTenthSecondsCoalesced' invocations that are waiting to be+-- coordinated by it are notified to fall back to periodic sleeping.+--+-- The timer thread _will_ fail immediately when running in a non-threaded+-- RTS.+withTimer :: (IO () -> IO ()) -> IO a -> IO a+withTimer pauseRefresh action =+    withAsync (timerThread `finally` cleanup) $ const action+    where+        timerThread = do+            atomically $ writeTVar periodsVar $ Just M.empty+            timerLoop pauseRefresh++        cleanup = atomically $ readTVar periodsVar >>= \case+            Just periods -> do+                for_ periods unCoalesceTimer'+                writeTVar periodsVar Nothing+            Nothing -> return ()++timerLoop :: (IO () -> IO ()) -> IO ()+timerLoop pauseRefresh = forever $ do+    tNow <- now+    (toFire, tMaybeNext) <- atomically $ do+        periods <- fromJust <$> readTVar periodsVar+        let toFire = timersToFire tNow periods+        let periods' = advanceTimers tNow periods+        let tMaybeNext = nextFireTime periods'+        writeTVar periodsVar $ Just periods'+        return (toFire, tMaybeNext)+    pauseRefresh $ do+        -- To avoid multiple refreshes, pause refreshing for up to 1 second,+        -- fire timers and wait for them to finish (update their text).+        -- Those that need more time (e.g. weather monitors) will be dropped+        -- from timer coalescing and will fall back to periodic sleep.+        timeoutVar <- registerDelay $ case tMaybeNext of+            Just tNext -> fromIntegral ((tNext - tNow) `max` 10) * 100000+            Nothing -> 1000000+        fired <- fireTimers toFire+        timeouted <- waitForTimers timeoutVar fired+        unCoalesceTimers timeouted+    delayUntilNextFire++advanceTimers :: Int64 -> Periods -> Periods+advanceTimers t = M.map advance+    where+        advance p | next p <= t = p { next = t - t `mod` rate p + rate p }+                  | otherwise = p++timersToFire :: Int64 -> Periods -> [(Unique, Period)]+timersToFire t periods = [ (u, p) | (u, p) <- M.toList periods, next p <= t ]++nextFireTime :: Periods -> Maybe Int64+nextFireTime periods+    | M.null periods = Nothing+    | otherwise = Just $ minimum [ next p | p <- M.elems periods ]++fireTimers :: [(Unique, Period)] -> IO [(Unique, TMVar ())]+fireTimers toFire = atomically $ forM toFire $ \(u, p) -> do+    doneVar <- newEmptyTMVar+    putTMVar (tick p) (Tick doneVar)+    return (u, doneVar)++waitForTimers :: TVar Bool -> [(Unique, TMVar ())] -> IO [Unique]+waitForTimers timeoutVar fired = atomically $ do+    timeoutOver <- readTVar timeoutVar+    dones <- forM fired $ \(u, doneVar) -> do+        done <- isJust <$> tryReadTMVar doneVar+        return (u, done)+    guard $ timeoutOver || all snd dones+    return [u | (u, False) <- dones]++-- | Handle slow timers (drop and signal them to stop coalescing).+unCoalesceTimers :: [Unique] -> IO ()+unCoalesceTimers timers = atomically $ do+    periods <- fromJust <$> readTVar periodsVar+    periods' <- foldrM unCoalesceTimer periods timers+    writeTVar periodsVar $ Just periods'++unCoalesceTimer :: Unique -> Periods -> STM Periods+unCoalesceTimer u periods = do+    unCoalesceTimer' (periods M.! u)+    return $ u `M.delete` periods++unCoalesceTimer' :: Period -> STM ()+unCoalesceTimer' p = do+    _ <- tryTakeTMVar (tick p)+    putTMVar (tick p) UnCoalesce++delayUntilNextFire :: IO ()+delayUntilNextFire = do+    Just periods <- readTVarIO periodsVar+    let tMaybeNext = nextFireTime periods+    tNow <- now+    delayVar <- case tMaybeNext of+        Just tNext -> do+            -- Work around the Int max bound: threadDelay takes an Int, we can+            -- only sleep for so long, which is okay, we'll just check timers+            -- sooner and sleep again.+            let maxDelay = (maxBound :: Int) `div` 100000+                delay = (tNext - tNow) `min` fromIntegral maxDelay+                delayUsec = fromIntegral delay * 100000+            registerDelay delayUsec+        Nothing -> newTVarIO False+    atomically $ do+        delayOver <- readTVar delayVar+        periods' <- fromJust <$> readTVar periodsVar+        let tMaybeNext' = nextFireTime periods'+        -- Return also if a new period is added (it may fire sooner).+        guard $ delayOver || tMaybeNext /= tMaybeNext'
src/Xmobar/Run/Types.hs view
@@ -2,7 +2,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.Run.Types--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -19,6 +19,7 @@ module Xmobar.Run.Types(runnableTypes) where  import {-# SOURCE #-} Xmobar.Run.Runnable()+import Xmobar.Plugins.Command import Xmobar.Plugins.Monitors import Xmobar.Plugins.Date import Xmobar.Plugins.PipeReader@@ -44,8 +45,6 @@ #ifdef KRAKEN import Xmobar.Plugins.Kraken #endif--import Xmobar.Run.Command  -- | An alias for tuple types that is more convenient for long lists. type a :*: b = (a, b)
src/Xmobar/System/Utils.hs view
@@ -3,7 +3,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Utils--- Copyright: (c) 2010, 2018, 2020 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2010, 2018, 2020, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: Jose A Ortega Ruiz <jao@gnu.org>@@ -21,10 +21,19 @@   ( expandHome   , changeLoop   , safeIndex+  , forkThread   ) where  import Control.Monad import Control.Concurrent.STM+import Control.Exception (handle, SomeException(..))++#ifdef THREADED_RUNTIME+import Control.Concurrent (forkOS)+#else+import Control.Concurrent (forkIO)+#endif+ import qualified Data.List.NonEmpty as NE import Data.Maybe (fromMaybe) @@ -34,6 +43,18 @@ expandHome :: FilePath -> IO FilePath expandHome ('~':'/':path) = fmap (</> path) (getEnv "HOME") expandHome p = return p++forkThread :: String -> IO () -> IO ()+forkThread name action = do+#ifdef THREADED_RUNTIME+    _ <- forkOS (handle (onError name) action)+#else+    _ <- forkIO (handle (onError name) action)+#endif+    return ()+  where+    onError thing (SomeException e) =+      void $ putStrLn ("Thread " ++ thing ++ " failed: " ++ show e)  changeLoop :: Eq a => STM a -> (a -> IO ()) -> IO () changeLoop s f = atomically s >>= go
+ src/Xmobar/Text/Ansi.hs view
@@ -0,0 +1,49 @@+------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Text.Ansi+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Fri Feb 4, 2022 01:10+--+--+-- Codification with ANSI (color) escape codes+--+------------------------------------------------------------------------------++module Xmobar.Text.Ansi (withAnsiColor) where++import Data.List (intercalate)+import Data.Char (toLower)++asInt :: String -> String+asInt x = case (reads $ "0x" ++ x)  :: [(Integer, String)] of+  [(v, "") ] -> show v+  _ -> ""++namedColor :: String -> String+namedColor c =+  case map toLower c of+    "black" -> "0"; "red" -> "1"; "green" -> "2"; "yellow" -> "3"; "blue" -> "4";+    "magenta" -> "5"; "cyan" -> "6"; "white" -> "7";+    "brightblack" -> "8"; "brightred" -> "9"; "brightgreen" -> "10";+    "brightyellow" -> "11"; "brightblue" -> "12";+    "brightmagenta" -> "13"; "brightcyan" -> "14"; "brightwhite" -> "15";+    _ -> ""++ansiCode :: String -> String+ansiCode ('#':r:g:[b]) = ansiCode ['#', '0', r, '0', g, '0', b]+ansiCode ('#':r0:r1:g0:g1:b0:[b1]) =+  "2;" ++ intercalate ";" (map asInt [[r0,r1], [g0,g1], [b0,b1]])+ansiCode ('#':n) = ansiCode n+ansiCode c = "5;" ++ if null i then namedColor c else i where i = asInt c++withAnsiColor :: (String, String) -> String -> String+withAnsiColor (fg, bg) s = wrap "38;" fg (wrap "48;" bg s)+  where wrap cd cl w =+          if null cl+          then w+          else "\x1b[" ++ cd ++ ansiCode cl ++ "m" ++ w ++ "\x1b[0m"
+ src/Xmobar/Text/Loop.hs view
@@ -0,0 +1,48 @@+------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Text.Loop+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: unportable+-- Created: Fri Jan 28, 2022 01:21+--+--+-- Text-only event loop+--+------------------------------------------------------------------------------++module Xmobar.Text.Loop (textLoop) where++import Prelude hiding (lookup)+import System.IO (hSetBuffering, stdin, stdout, BufferMode(LineBuffering))++import Control.Concurrent.STM++import Xmobar.System.Signal+import Xmobar.Config.Types (Config)+import Xmobar.Run.Loop (loop)+import Xmobar.Text.Output (initLoop, format)++-- | Starts the main event loop and threads+textLoop :: Config -> IO ()+textLoop conf = do+  hSetBuffering stdin LineBuffering+  hSetBuffering stdout LineBuffering+  initLoop conf+  loop conf (eventLoop conf)++-- | Continuously wait for a signal from a thread or a interrupt handler+eventLoop :: Config -> TMVar SignalType -> TVar [String] -> IO ()+eventLoop cfg signal tv = do+  typ <- atomically $ takeTMVar signal+  case typ of+    Wakeup -> updateString cfg tv >>= putStrLn >> eventLoop cfg signal tv+    _ -> eventLoop cfg signal tv++updateString :: Config -> TVar [String] -> IO String+updateString conf v = do+  s <- readTVarIO v+  format conf (concat s)
+ src/Xmobar/Text/Output.hs view
@@ -0,0 +1,55 @@+-- |+-- Module: Xmobar.Text.Output+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Fri Feb 4, 2022 01:10+--+--+-- Format strings emitted by Commands into output strings+--+------------------------------------------------------------------------------++module Xmobar.Text.Output (initLoop, format) where++import Xmobar.Config.Types (Config(textOutputFormat, additionalFonts, font)+                           , TextOutputFormat(..))+import Xmobar.Run.Parsers ( Segment+                          , Widget(..)+                          , parseString+                          , tColorsString+                          , colorComponents)++import Xmobar.Text.Ansi (withAnsiColor)+import Xmobar.Text.Pango (withPangoMarkup)+import Xmobar.Text.Swaybar (formatSwaybar, prepare)++initLoop :: Config -> IO ()+initLoop conf = case textOutputFormat conf of+  Swaybar -> prepare+  _ -> return ()++formatWithColor :: Config -> Segment -> String+formatWithColor conf (Text s, info, idx, _) =+  case textOutputFormat conf of+    Ansi -> withAnsiColor (fg, bg) s+    Pango -> withPangoMarkup fg bg fn s+    _ -> s+  where (fg, bg) = colorComponents conf (tColorsString info)+        fonts = additionalFonts conf+        fn = if idx < 1 || idx > length fonts+             then font conf+             else fonts !! (idx - 1)+formatWithColor conf (Hspace n, i, x, y) =+   formatWithColor conf (Text $ replicate (fromIntegral n) ' ', i, x, y)+formatWithColor _ _ = ""++format :: Config -> String -> IO String+format conf s = do+  segments <- parseString conf s+  case textOutputFormat conf of+    Swaybar -> return $ formatSwaybar conf segments+    _ -> return (concatMap (formatWithColor conf) segments)
+ src/Xmobar/Text/Pango.hs view
@@ -0,0 +1,48 @@+------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Text.Pango+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Author: Pavel Kalugin+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Fri Feb 4, 2022 01:15+--+--+-- Codification with Pango markup+--+------------------------------------------------------------------------------++module Xmobar.Text.Pango (withPangoColor, withPangoFont, withPangoMarkup) where++import Text.Printf (printf)+import Data.List (isPrefixOf)++replaceAll :: (Eq a) => a -> [a] -> [a] -> [a]+replaceAll c s = concatMap (\x -> if x == c then s else [x])++xmlEscape :: String -> String+xmlEscape s = replaceAll '"' "&quot;" $+              replaceAll '\'' "&apos;" $+              replaceAll '<' "&lt;" $+              replaceAll '>' "&gt;" $+              replaceAll '&' "&amp;" s++withPangoColor :: (String, String) -> String -> String+withPangoColor (fg, bg) s =+  printf fmt (xmlEscape fg) (xmlEscape bg) (xmlEscape s)+  where fmt = "<span foreground=\"%s\" background=\"%s\">%s</span>"++fixXft :: String -> String+fixXft font = if "xft:" `isPrefixOf` font then drop 4 font else font++withPangoFont :: String -> String -> String+withPangoFont font txt = printf fmt (fixXft font) (xmlEscape txt)+  where fmt = "<span font=\"%s\">%s</span>"++withPangoMarkup :: String -> String -> String -> String -> String+withPangoMarkup fg bg font txt =+  printf fmt (fixXft font) (xmlEscape fg) (xmlEscape bg) (xmlEscape txt)+  where fmt = "<span font=\"%s\" foreground=\"%s\" background=\"%s\">%s</span>"
+ src/Xmobar/Text/Swaybar.hs view
@@ -0,0 +1,147 @@+{-# LANGUAGE DeriveGeneric #-}++------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Text.Swaybar+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Fri Feb 4, 2022 03:58+--+--+-- Segment codification using swaybar-protocol JSON strings+--+------------------------------------------------------------------------------++module Xmobar.Text.Swaybar (prepare, formatSwaybar) where++import Data.Aeson++import Data.ByteString.Lazy.UTF8 (toString)++import GHC.Generics++import Xmobar.Config.Types (Config (additionalFonts))++import Xmobar.Run.Parsers ( Segment+                          , Widget(..)+                          , Box(..)+                          , BoxBorder(..)+                          , FontIndex+                          , tBoxes+                          , tColorsString+                          , colorComponents)++import Xmobar.Text.SwaybarClicks (startHandler)+import Xmobar.Text.Pango (withPangoFont)++data Preamble =+  Preamble {version :: !Int, click_events :: Bool} deriving (Eq,Show,Generic)++asString :: ToJSON a => a -> String+asString = toString . encode++preamble :: String+preamble = (asString $ Preamble { version = 1, click_events = True }) ++ "\x0A["++data Block =+  Block { full_text :: !String+        , name :: !String+        , color :: Maybe String+        , background :: Maybe String+        , separator :: !Bool+        , separator_block_width :: !Int+        , border :: Maybe String+        , border_top :: Maybe Int+        , border_bottom :: Maybe Int+        , border_left :: Maybe Int+        , border_right :: Maybe Int+        , markup :: Maybe String+        } deriving (Eq,Show,Generic)+++defaultBlock :: Block+defaultBlock = Block { full_text = ""+                     , name = ""+                     , color = Nothing+                     , background = Nothing+                     , separator = False+                     , separator_block_width = 0+                     , border = Nothing+                     , border_top = Nothing+                     , border_bottom = Nothing+                     , border_left = Nothing+                     , border_right = Nothing+                     , markup = Nothing+                     }++instance ToJSON Block where+  toJSON = genericToJSON defaultOptions+    { omitNothingFields = True }++instance ToJSON Preamble++withBox :: Box -> Block -> Block+withBox (Box b _ n c _) block =+  (case b of+     BBFull -> bl { border_right = w, border_left = w+                  , border_bottom = w, border_top = w  }+     BBTop -> bl { border_top = w }+     BBBottom -> bl { border_bottom = w }+     BBVBoth -> bl { border_bottom = w, border_top = w }+     BBLeft -> bl { border_left = w }+     BBRight -> bl { border_right = w }+     BBHBoth -> bl { border_right = w, border_left = w }+  ) { border = bc }+  where w = Just (fromIntegral n)+        bc = if null c then Nothing else Just c+        j0 = Just 0+        bl = block { border_right = j0, border_left = j0+                   , border_bottom = j0, border_top = j0  }++withFont :: Config -> FontIndex -> Block -> Block+withFont conf idx block =+  if idx < 1 || idx > length fonts then block+  else block { markup = Just $ fonts !! (idx - 1) }+  where fonts = additionalFonts conf++withPango :: Block -> Block+withPango block = case markup block of+  Nothing -> block+  Just fnt -> block { full_text = txt fnt, markup = Just "pango"}+  where txt fn = withPangoFont fn (full_text block)++formatSwaybar' :: Config -> Segment -> Block+formatSwaybar' conf (Text txt, info, idx, as) =+  foldr withBox (withFont conf idx block) (tBoxes info)+  where (fg, bg) = colorComponents conf (tColorsString info)+        block = defaultBlock { full_text = txt+                             , color = Just fg+                             , background = Just bg+                             , name = show as+                             }+formatSwaybar' conf (Hspace n, info, i, a) =+  formatSwaybar' conf (Text (replicate (fromIntegral n) ' '), info, i, a)+formatSwaybar' _ _ = defaultBlock++collectBlock :: Block -> [Block] -> [Block]+collectBlock b [] = [b]+collectBlock b (h:bs) =+  if b {full_text = ""} == h {full_text = ""} then+    h {full_text = full_text b ++ full_text h} : bs+  else b:h:bs++collectSegment :: Config -> Segment -> [Block] -> [Block]+collectSegment config segment blocks =+  if null $ full_text b then blocks else collectBlock b blocks+  where b = formatSwaybar' config segment++formatSwaybar :: Config -> [Segment] -> String+formatSwaybar conf segs = asString (map withPango blocks) ++ ","+  where blocks = foldr (collectSegment conf) [] segs++prepare :: IO ()+prepare = startHandler >> putStrLn preamble
+ src/Xmobar/Text/SwaybarClicks.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE DeriveGeneric #-}++------------------------------------------------------------------------------+-- |+-- Module: Xmobar.Text.SwaybarClicks+-- Copyright: (c) 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Fri Feb 4, 2022 03:58+--+--+-- Handling of "click" events sent by swaybar via stdin+--+------------------------------------------------------------------------------+++module Xmobar.Text.SwaybarClicks (startHandler) where++import Control.Monad (when)+++import Data.Aeson++-- import qualified Data.ByteString.Lazy as BL++import GHC.Generics++import Xmobar.System.Utils (forkThread)+import Xmobar.Run.Actions (Action (..), runAction')++import Data.ByteString.Lazy.UTF8 (fromString)++data Click =+  Click { name :: String , button :: Int } deriving (Eq,Show,Generic)++instance FromJSON Click++runClickAction :: Int -> Action -> IO ()+runClickAction b a@(Spawn bs _) =+  when (fromIntegral b `elem` bs) (runAction' a)++handleClick :: Maybe Click -> IO ()+handleClick Nothing = return ()+handleClick (Just click) = do+  let mas = read (name click) :: Maybe [Action]+      b = button click+  maybe (return ()) (mapM_ (runClickAction b)) mas++toClick :: String -> Maybe Click+toClick (',':s) = toClick s+toClick s = decode (fromString s)++readClicks :: IO ()+readClicks = getLine >>= handleClick . toClick >> readClicks++startHandler :: IO ()+startHandler = forkThread "Swaybar event handler" readClicks
− src/Xmobar/X11/Actions.hs
@@ -1,34 +0,0 @@--------------------------------------------------------------------------------- |--- Module      :  Xmobar.Actions--- Copyright   :  (c) Alexander Polakov--- License     :  BSD-style (see LICENSE)------ Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>--- Stability   :  unstable--- Portability :  unportable-----------------------------------------------------------------------------------module Xmobar.X11.Actions (Action(..), runAction, stripActions) where--import System.Process (system)-import Control.Monad (void)-import Text.Regex (Regex, subRegex, mkRegex, matchRegex)-import Graphics.X11.Types (Button)--data Action = Spawn [Button] String-                deriving (Eq, Show)--runAction :: Action -> IO ()-runAction (Spawn _ s) = void $ system (s ++ "&")--stripActions :: String -> String-stripActions s = case matchRegex actionRegex s of-  Nothing -> s-  Just _  -> stripActions strippedOneLevel-  where-      strippedOneLevel = subRegex actionRegex s "[action=\\1\\2]\\3[/action]"--actionRegex :: Regex-actionRegex = mkRegex "<action=`?([^>`]*)`?( +button=[12345]+)?>(.+)</action>"
src/Xmobar/X11/Bitmap.hs view
@@ -2,7 +2,7 @@ ----------------------------------------------------------------------------- -- | -- Module      :  X11.Bitmap--- Copyright   :  (C) 2013, 2015, 2017, 2018 Alexander Polakov+-- Copyright   :  (C) 2013, 2015, 2017, 2018, 2022 Alexander Polakov -- License     :  BSD3 -- -- Maintainer  :  jao@gnu.org@@ -23,9 +23,9 @@ import System.Directory (doesFileExist) import System.FilePath ((</>)) import System.Mem.Weak ( addFinalizer )+import Xmobar.Run.Actions (Action)+import Xmobar.Run.Parsers (TextRenderInfo(..), Widget(..)) import Xmobar.X11.ColorCache-import Xmobar.X11.Parsers (TextRenderInfo(..), Widget(..))-import Xmobar.X11.Actions (Action)  #ifdef XPM import Xmobar.X11.XPMFile(readXPMFile)
src/Xmobar/X11/Draw.hs view
@@ -4,7 +4,7 @@ ------------------------------------------------------------------------------ -- | -- Module: Xmobar.X11.Draw--- Copyright: (c) 2018, 2020 Jose Antonio Ortega Ruiz+-- Copyright: (c) 2018, 2020, 2022 Jose Antonio Ortega Ruiz -- License: BSD3-style (see LICENSE) -- -- Maintainer: jao@gnu.org@@ -28,17 +28,16 @@ import Data.List ((\\)) import qualified Data.List.NonEmpty as NE -import Graphics.X11.Xlib hiding (textExtents, textWidth)+import Graphics.X11.Xlib hiding (textExtents, textWidth, Segment) import Graphics.X11.Xlib.Extras  import Xmobar.Config.Types+import Xmobar.Run.Parsers hiding (parseString) import qualified Xmobar.X11.Bitmap as B-import Xmobar.X11.Actions (Action(..)) import Xmobar.X11.Types import Xmobar.X11.Text import Xmobar.X11.ColorCache import Xmobar.X11.Window (drawBorder)-import Xmobar.X11.Parsers hiding (parseString) import Xmobar.System.Utils (safeIndex)  #ifdef XFT@@ -50,7 +49,7 @@ fi = fromIntegral  -- | Draws in and updates the window-drawInWin :: Rectangle -> [[(Widget, TextRenderInfo, Int, Maybe [Action])]] -> X ()+drawInWin :: Rectangle -> [[Segment]] -> X () drawInWin wr@(Rectangle _ _ wid ht) ~[left,center,right] = do   r <- ask   let (c,d) = (config &&& display) r@@ -71,6 +70,7 @@ #endif   withColors d [bgColor c, borderColor c] $ \[bgcolor, bdcolor] -> do     gc <- liftIO $ createGC  d w+    liftIO $ setGraphicsExposures d gc False #if XFT     when (alpha c == 255) $ do #else@@ -89,8 +89,8 @@     -- free up everything (we do not want to leak memory!)     liftIO $ freeGC d gc     liftIO $ freePixmap d p-    -- resync-    liftIO $ sync d False+    -- resync (discard events, we don't read/process events from this display conn)+    liftIO $ sync d True  verticalOffset :: (Integral b, Integral a, MonadIO m) =>                   a -> Widget -> XFont -> Int -> Config -> m b@@ -105,8 +105,19 @@   | otherwise = return $ fi (ht `div` 2) - 1 verticalOffset _ (Hspace _) _ voffs _ = return $ fi voffs -printString :: Display -> Drawable -> XFont -> GC -> String -> String-            -> Position -> Position -> Position -> Position -> String -> Int -> IO ()+printString :: Display+            -> Drawable+            -> XFont+            -> GC+            -> String+            -> String+            -> 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@@ -133,8 +144,14 @@ #endif  -- | An easy way to print the stuff we need to print-printStrings :: Drawable -> GC -> NE.NonEmpty XFont -> NE.NonEmpty Int -> Position-             -> Align -> [((Position, Position), Box)] -> [(Widget, TextRenderInfo, Int, Position)] -> X ()+printStrings :: Drawable+             -> GC+             -> NE.NonEmpty XFont+             -> NE.NonEmpty Int+             -> Position+             -> 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@@ -149,9 +166,7 @@                  C -> (remWidth + offs) `div` 2                  R -> remWidth                  L -> offs-      (fc,bc) = case break (==',') (tColorsString c) of-                 (f,',':b) -> (f, b           )-                 (f,    _) -> (f, bgColor conf)+      (fc,bc) = colorComponents conf (tColorsString c)   valign <- verticalOffset ht s fontst voff conf   let (ht',ay) = case (tBgTopOffset c, tBgBottomOffset c) of                    (-1,_)  -> (0, -1)@@ -165,14 +180,20 @@     (Hspace _) -> liftIO $ return ()   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)+      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 :: 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@@ -195,9 +216,18 @@       _ -> 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+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)
+ src/Xmobar/X11/Loop.hs view
@@ -0,0 +1,229 @@+{-# LANGUAGE CPP #-}++------------------------------------------------------------------------------+-- |+-- Module: Xmobar.App.X11EventLoop+-- Copyright: (c) 2018, 2020, 2022 Jose Antonio Ortega Ruiz+-- License: BSD3-style (see LICENSE)+--+-- Maintainer: jao@gnu.org+-- Stability: unstable+-- Portability: portable+-- Created: Sat Nov 24, 2018 19:40+--+--+-- Event loop+--+------------------------------------------------------------------------------++module Xmobar.X11.Loop (x11Loop) where++import Prelude hiding (lookup)+import Graphics.X11.Xlib hiding (textExtents, textWidth, Segment)+import Graphics.X11.Xlib.Extras+import Graphics.X11.Xinerama+import Graphics.X11.Xrandr++import Control.Arrow ((&&&))+import Control.Monad.Reader+import Control.Concurrent+import Control.Concurrent.STM++import Data.Bits+import Data.Map hiding (foldr, map, filter)+import qualified Data.Map as Map+import Data.List.NonEmpty (NonEmpty(..))++import Data.Maybe (fromJust, isJust)+import qualified Data.List.NonEmpty as NE++import Xmobar.System.Signal+import Xmobar.Config.Types ( persistent+                           , font+                           , additionalFonts+                           , textOffset+                           , textOffsets+                           , position+                           , iconRoot+                           , Config+                           , Align(..)+                           , XPosition(..))++import Xmobar.Run.Actions+import Xmobar.Run.Parsers+import Xmobar.X11.Window+import Xmobar.X11.Text+import Xmobar.X11.Draw+import Xmobar.X11.Bitmap as Bitmap+import Xmobar.X11.Types+import Xmobar.System.Utils (safeIndex, forkThread)++import Xmobar.Run.Loop (loop)++#ifndef THREADED_RUNTIME+import Xmobar.X11.Events(nextEvent')+#endif++#ifdef XFT+import Graphics.X11.Xft+#endif++runX :: XConf -> X () -> IO ()+runX xc f = runReaderT f xc++-- | Starts the main event loop and threads+x11Loop :: Config -> IO ()+x11Loop conf = do+  initThreads+  d <- openDisplay ""+  fs <- initFont d (font conf)+  fl <- mapM (initFont d) (additionalFonts conf)+  let ic = Map.empty+      to = textOffset conf+      ts = textOffsets conf ++ replicate (length fl) (-1)+#ifdef XFT+  xftInitFtLibrary+#endif+  (r,w) <- createWin d fs conf+  loop conf (startLoop (XConf d r w (fs :| fl) (to :| ts) ic conf))++startLoop :: XConf -> TMVar SignalType -> TVar [String] -> IO ()+startLoop xcfg@(XConf _ _ w _ _ _ _) sig tv = do+    forkThread "X event handler" (x11EventLoop w sig)+    signalLoop xcfg [] sig tv++-- | Translates X11 events received by w to signals handled by signalLoop+x11EventLoop :: Window -> TMVar SignalType -> IO ()+x11EventLoop w signal =+  allocaXEvent $ \e -> do+    dpy <- openDisplay ""+    xrrSelectInput dpy (defaultRootWindow dpy) rrScreenChangeNotifyMask+    selectInput dpy w (exposureMask .|. structureNotifyMask .|. buttonPressMask)++    forever $ do+#ifdef THREADED_RUNTIME+      nextEvent dpy e+#else+      nextEvent' dpy e+#endif+      ev <- getEvent e+      case ev of+        ConfigureEvent {} -> atomically $ putTMVar signal Reposition+        ExposeEvent {} -> atomically $ putTMVar signal Wakeup+        RRScreenChangeNotifyEvent {} -> atomically $ putTMVar signal Reposition+        ButtonEvent {} -> atomically $+               putTMVar signal (Action (ev_button ev) (fi $ ev_x ev))+        _ -> return ()++-- | Continuously wait for a signal from a thread or an interrupt handler+signalLoop :: XConf+          -> [([Action], Position, Position)]+          -> TMVar SignalType+          -> TVar [String]+          -> IO ()+signalLoop xc@(XConf d r w fs vos is cfg) as signal tv = do+      typ <- atomically $ takeTMVar signal+      case typ of+         Wakeup -> do+            str <- updateString cfg tv+            xc' <- updateCache d w is (iconRoot cfg) str >>=+                     \c -> return xc { iconS = c }+            as' <- updateActions xc r str+            runX xc' $ drawInWin r str+            signalLoop xc' as' signal tv++         Reposition ->+            reposWindow cfg++         ChangeScreen -> do+            ncfg <- updateConfigPosition cfg+            reposWindow ncfg++         Hide   t -> hide   (t*100*1000)+         Reveal t -> reveal (t*100*1000)+         Toggle t -> toggle t++         TogglePersistent -> signalLoop+            xc { config = cfg { persistent = not $ persistent cfg } } as signal tv++         Action but x -> action but x++    where+        isPersistent = not $ persistent cfg+        loopOn = signalLoop xc as signal tv+        hide t+            | t == 0 =+                when isPersistent (hideWindow d w) >> loopOn+            | otherwise = do+                void $ forkIO+                     $ threadDelay t >> atomically (putTMVar signal $ Hide 0)+                loopOn++        reveal t+            | t == 0 = do+                when isPersistent (showWindow r cfg d w)+                loopOn+            | otherwise = do+                void $ forkIO+                     $ threadDelay t >> atomically (putTMVar signal $ Reveal 0)+                loopOn++        toggle t = do+            ismapped <- isMapped d w+            atomically (putTMVar signal $ if ismapped then Hide t else Reveal t)+            loopOn++        reposWindow rcfg = do+          r' <- repositionWin d w (NE.head fs) rcfg+          signalLoop (XConf d r' w fs vos is rcfg) as signal tv++        updateConfigPosition ocfg =+          case position ocfg of+            OnScreen n o -> do+              srs <- getScreenInfo d+              return (if n == length srs+                       then+                        (ocfg {position = OnScreen 1 o})+                       else+                        (ocfg {position = OnScreen (n+1) o}))+            o -> return (ocfg {position = OnScreen 1 o})++        action button x = do+          mapM_ runAction $+            filter (\(Spawn b _) -> button `elem` b) $+            concatMap (\(a,_,_) -> a) $+            filter (\(_, from, to) -> x >= from && x <= to) as+          loopOn++updateString :: Config -> TVar [String] -> IO [[Segment]]+updateString conf v = do+  s <- readTVarIO v+  let l:c:r:_ = s ++ repeat ""+  liftIO $ mapM (parseString conf) [l, c, r]++updateActions :: XConf -> Rectangle -> [[Segment]]+              -> IO [([Action], Position, Position)]+updateActions conf (Rectangle _ _ wid _) ~[left,center,right] = do+  let (d,fs) = (display &&& fontListS) conf+      strLn :: [Segment] -> 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)+      getCoords (Icon s,_,_,a) = return (a, 0, fi $ iconW s)+      getCoords (Hspace w,_,_,a) = return (a, 0, fi w)+      partCoord off xs = map (\(a, x, x') -> (fromJust a, x, x')) $+                         filter (\(a, _,_) -> isJust a) $+                         scanl (\(_,_,x') (a,_,w') -> (a, x', x' + w'))+                               (Nothing, 0, off)+                               xs+      totSLen = foldr (\(_,_,len) -> (+) len) 0+      remWidth xs = fi wid - totSLen xs+      offs = 1+      offset a xs = case a of+                     C -> (remWidth xs + offs) `div` 2+                     R -> remWidth xs+                     L -> offs+  fmap concat $ mapM (\(a,xs) ->+                       (\xs' -> partCoord (offset a xs') xs') <$> strLn xs) $+                     zip [L,C,R] [left,center,right]
− src/Xmobar/X11/Parsers.hs
@@ -1,227 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}---------------------------------------------------------------------------------- |--- Module      :  Xmobar.Parsers--- Copyright   :  (c) Andrea Rossato--- License     :  BSD-style (see LICENSE)------ Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>--- Stability   :  unstable--- Portability :  unportable------ Parsing for template substrings-----------------------------------------------------------------------------------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 | Hspace Int32 deriving Show--data BoxOffset = BoxOffset Align Int32 deriving (Eq, Show)--- margins: Top, Right, Bottom, Left-data BoxMargins = BoxMargins Int32 Int32 Int32 Int32 deriving (Eq, Show)-data BoxBorder = BBTop-               | BBBottom-               | BBVBoth-               | BBLeft-               | BBRight-               | BBHBoth-               | BBFull-                 deriving ( Read, Eq, Show )-data Box = Box BoxBorder BoxOffset CInt String BoxMargins deriving (Eq, Show)-data TextRenderInfo =-    TextRenderInfo { tColorsString   :: String-                   , tBgTopOffset    :: Int32-                   , tBgBottomOffset :: Int32-                   , tBoxes          :: [Box]-                   } deriving Show-type FontIndex   = Int---- | Runs the string parser-parseString :: Config -> String-               -> IO [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]-parseString c s =-    case parse (stringParser ci 0 Nothing) "" s of-      Left  _ -> return [(Text $ "Could not parse string: " ++ s-                          , ci-                          , 0-                          , Nothing)]-      Right x -> return (concat x)-    where ci = TextRenderInfo (fgColor c) 0 0 []--allParsers :: TextRenderInfo-           -> FontIndex-           -> Maybe [Action]-           -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]-allParsers c f a =  textParser c f a-                <|> try (iconParser c f a)-                <|> try (hspaceParser c f a)-                <|> try (rawParser c f a)-                <|> try (actionParser c f a)-                <|> try (fontParser c a)-                <|> try (boxParser c f a)-                <|> colorParser c f a---- | Gets the string and combines the needed parsers-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 :: 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 "hspace=") <|>-                                     try (string "raw=") <|>-                                     try (string "/fn>") <|>-                                     try (string "/box>") <|>-                                     string "/fc>"))-                      return [(Text s, c, f, a)]---- | Parse a "raw" tag, which we use to prevent other tags from creeping in.--- The format here is net-string-esque: a literal "<raw=" followed by a--- 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 :: TextRenderInfo-          -> FontIndex-          -> Maybe [Action]-          -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]-rawParser c f a = do-  string "<raw="-  lenstr <- many1 digit-  char ':'-  case reads lenstr of-    [(len,[])] -> do-      guard ((len :: Integer) <= fromIntegral (maxBound :: Int))-      s <- count (fromIntegral len) anyChar-      string "/>"-      return [(Text s, c, f, a)]-    _ -> mzero---- | Wrapper for notFollowedBy that returns the result of the first parser.---   Also works around the issue that, at least in Parsec 3.0.0, notFollowedBy---   accepts only parsers with return type Char.-notFollowedBy' :: Parser a -> Parser b -> Parser a-notFollowedBy' p e = do x <- p-                        notFollowedBy $ try (e >> return '*')-                        return x--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)]--hspaceParser :: TextRenderInfo -> FontIndex -> Maybe [Action]-              -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]-hspaceParser c f a = do-  string "<hspace="-  pVal <- manyTill digit (try (string "/>"))-  return [(Hspace (fromMaybe 0 $ readMaybe pVal), c, f, a)]--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 "`")),-                   many1 (noneOf ">")]-  buttons <- (char '>' >> return "1") <|> (space >> spaces >>-    between (string "button=") (string ">") (many1 (oneOf "12345")))-  let a = Spawn (toButtons buttons) command-      a' = case act of-        Nothing -> Just [a]-        Just act' -> Just $ a : act'-  s <- manyTill (allParsers c f a') (try $ string "</action>")-  return (concat s)--toButtons :: String -> [Button]-toButtons = map (\x -> read [x])---- | Parsers a string wrapped in a color specification.-colorParser :: TextRenderInfo -> FontIndex -> Maybe [Action]-               -> Parser [(Widget, TextRenderInfo, FontIndex, Maybe [Action])]-colorParser (TextRenderInfo _ _ _ bs) f a = do-  c <- between (string "<fc=") (string ">") colors-  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 :: 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>")-  return (concat s)---- | Parses a color specification (hex or named)-colors :: Parser String-colors = many1 (alphaNum <|> char ',' <|> char ':' <|> char '#')
src/Xmobar/X11/Window.hs view
@@ -84,7 +84,7 @@     TopW a i -> Rectangle (ax a i) ry (nw i) h     TopSize a i ch -> Rectangle (ax a i) ry (nw i) (mh ch)     Bottom -> Rectangle rx ny rw h-    BottomH ch -> Rectangle rx ny rw (mh ch)+    BottomH ch -> Rectangle rx (ny' ch) rw (mh ch)     BottomW a i -> Rectangle (ax a i) ny (nw i) h     BottomP l r -> Rectangle (rx + fi l) ny (rw - fi l - fi r) h     BottomSize a i ch  -> Rectangle (ax a i) (ny' ch) (nw i) (mh ch)
xmobar.cabal view
@@ -1,6 +1,6 @@ name:               xmobar-version:            0.41-homepage:           http://xmobar.org+version:            0.42+homepage:           https://github.com/jaor/xmobar synopsis:           A Minimalistic Text Based Status Bar description: 	    Xmobar is a minimalistic text based status bar.                     .@@ -110,31 +110,38 @@                    Xmobar.Config.Types,                    Xmobar.Config.Parse,                    Xmobar.Run.Types,+                   Xmobar.Run.Timer,                    Xmobar.Run.Template,                    Xmobar.Run.Exec,-                   Xmobar.Run.Command,                    Xmobar.Run.Runnable-                   Xmobar.App.EventLoop,+                   Xmobar.Run.Actions,+                   Xmobar.Run.Parsers,+                   Xmobar.Run.Loop,                    Xmobar.App.Config,                    Xmobar.App.Main,                    Xmobar.App.Opts,                    Xmobar.App.Compile,-                   Xmobar.App.Timer,                    Xmobar.System.Utils,                    Xmobar.System.StatFS,                    Xmobar.System.Environment,                    Xmobar.System.Localize,                    Xmobar.System.Signal,                    Xmobar.System.Kbd,-                   Xmobar.X11.Actions,+                   Xmobar.Text.Ansi,+                   Xmobar.Text.Loop,+                   Xmobar.Text.Pango,+                   Xmobar.Text.Swaybar,+                   Xmobar.Text.SwaybarClicks,+                   Xmobar.Text.Output,                    Xmobar.X11.Events,-                   Xmobar.X11.Parsers,+                   Xmobar.X11.Loop,                    Xmobar.X11.Types,                    Xmobar.X11.Text,                    Xmobar.X11.Bitmap,                    Xmobar.X11.ColorCache,                    Xmobar.X11.Window,                    Xmobar.X11.Draw,+                   Xmobar.Plugins.Command,                    Xmobar.Plugins.BufferedPipeReader,                    Xmobar.Plugins.CommandReader,                    Xmobar.Plugins.Date,@@ -179,24 +186,25 @@     ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind      build-depends:-      base >= 4.11.0 && < 4.16,-      containers,-      regex-compat,-      process,-      old-locale,-      bytestring >= 0.10.8.2,-      directory,-      unix,-      time,-      filepath,-      transformers,-      X11 >= 1.6.1,-      mtl >= 2.1 && < 2.3,-      parsec == 3.1.*,-      parsec-numbers >= 0.1.0,-      stm >= 2.3 && < 2.6,-      extensible-exceptions == 0.1.*,-      async+                  X11 >= 1.6.1,+                  aeson >= 1.4.7.1,+                  async,+                  base >= 4.11.0 && < 4.16,+                  bytestring >= 0.10.8.2,+                  containers,+                  directory,+                  extensible-exceptions == 0.1.*,+                  filepath,+                  mtl >= 2.1 && < 2.3,+                  old-locale,+                  parsec == 3.1.*,+                  parsec-numbers >= 0.1.0,+                  process,+                  regex-compat,+                  stm >= 2.3 && < 2.6,+                  time,+                  transformers,+                  unix      if impl(ghc < 8.0.2)        -- Disable building with GHC before 8.0.2.@@ -381,7 +389,7 @@                  Xmobar.Plugins.Monitors.CpuSpec                  Xmobar.Plugins.Monitors.Common.Run                  Xmobar.Run.Exec-                 Xmobar.App.Timer+                 Xmobar.Run.Timer                  Xmobar.System.Signal    if flag(with_alsa) || flag(all_extensions)