summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.drone.yml19
-rw-r--r--.woodpecker/build.yaml32
-rw-r--r--changelog.md82
-rw-r--r--doc/accordion.gifbin0 -> 71898 bytes
-rw-r--r--doc/compiling.org4
-rw-r--r--doc/plugins.org197
-rw-r--r--doc/quick-start.org501
-rw-r--r--doc/using-haskell.org22
-rw-r--r--etc/notify-once.sh31
-rw-r--r--flake.lock75
-rw-r--r--flake.nix45
-rw-r--r--nix/default.nix130
-rw-r--r--nix/flake.lock95
-rw-r--r--nix/flake.nix64
-rw-r--r--nix/readme.org80
-rw-r--r--readme.org124
-rw-r--r--src/Xmobar.hs9
-rw-r--r--src/Xmobar/App/Compile.hs36
-rw-r--r--src/Xmobar/App/Config.hs1
-rw-r--r--src/Xmobar/App/Opts.hs10
-rw-r--r--src/Xmobar/Config/Parse.hs16
-rw-r--r--src/Xmobar/Config/Template.hs188
-rw-r--r--src/Xmobar/Config/Types.hs141
-rw-r--r--src/Xmobar/Draw/Boxes.hs34
-rw-r--r--src/Xmobar/Draw/Cairo.hs65
-rw-r--r--src/Xmobar/Draw/Types.hs5
-rw-r--r--src/Xmobar/Plugins/Accordion.hs112
-rw-r--r--src/Xmobar/Plugins/EWMH.hs3
-rw-r--r--src/Xmobar/Plugins/Kraken.hs2
-rw-r--r--src/Xmobar/Plugins/Locks.hs58
-rw-r--r--src/Xmobar/Plugins/MarqueePipeReader.hs2
-rw-r--r--src/Xmobar/Plugins/Monitors/Alsa.hs6
-rw-r--r--src/Xmobar/Plugins/Monitors/Batt/Common.hs15
-rw-r--r--src/Xmobar/Plugins/Monitors/Batt/Linux.hs2
-rw-r--r--src/Xmobar/Plugins/Monitors/Bright.hs3
-rw-r--r--src/Xmobar/Plugins/Monitors/Common/Output.hs22
-rw-r--r--src/Xmobar/Plugins/Monitors/Disk.hs8
-rw-r--r--src/Xmobar/Plugins/Monitors/Disk/FreeBSD.hsc2
-rw-r--r--src/Xmobar/Plugins/Monitors/MPD.hs5
-rw-r--r--src/Xmobar/Plugins/Monitors/Mem/Linux.hs10
-rw-r--r--src/Xmobar/Plugins/Monitors/Mpris.hs10
-rw-r--r--src/Xmobar/Plugins/Monitors/Net/Linux.hs5
-rw-r--r--src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc5
-rw-r--r--src/Xmobar/Plugins/Monitors/Top.hs6
-rw-r--r--src/Xmobar/Plugins/Monitors/Weather.hs19
-rw-r--r--src/Xmobar/Plugins/PacmanUpdates.hs165
-rw-r--r--src/Xmobar/Run/Actions.hs7
-rw-r--r--src/Xmobar/Run/Loop.hs2
-rw-r--r--src/Xmobar/Run/Parsers.hs244
-rw-r--r--src/Xmobar/Run/Template.hs24
-rw-r--r--src/Xmobar/Run/Types.hs2
-rw-r--r--src/Xmobar/System/DBus.hs10
-rw-r--r--src/Xmobar/System/Environment.hs9
-rw-r--r--src/Xmobar/Text/Loop.hs2
-rw-r--r--src/Xmobar/Text/Output.hs24
-rw-r--r--src/Xmobar/Text/Swaybar.hs20
-rw-r--r--src/Xmobar/X11/Bitmap.hs7
-rw-r--r--src/Xmobar/X11/Draw.hs10
-rw-r--r--src/Xmobar/X11/Events.hs19
-rw-r--r--src/Xmobar/X11/Loop.hs20
-rw-r--r--src/Xmobar/X11/Window.hs30
-rw-r--r--src/Xmobar/X11/XRender.hsc38
-rw-r--r--stack.yaml5
-rw-r--r--test/Xmobar/Plugins/Monitors/CpuSpec.hs21
-rw-r--r--xmobar.cabal750
65 files changed, 2452 insertions, 1258 deletions
diff --git a/.drone.yml b/.drone.yml
deleted file mode 100644
index 4b6e816..0000000
--- a/.drone.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-matrix:
- GHC_VERSION:
- - 9
- - 8
-
-pipeline:
- test:
- image: haskell:${GHC_VERSION}
- commands:
- - apt-get update
- - apt-get install -y xorg-dev libxrandr-dev libpango1.0-dev
- - apt-get install -y libasound2-dev libxpm-dev libmpd-dev
- - apt-get install -y hspec-discover hlint
-
- - hlint src
-
- - cabal update
- - cabal test --enable-tests -fall_extensions
- - cabal test --enable-tests -fall_extensions -f-with_xrender
diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml
new file mode 100644
index 0000000..ef33379
--- /dev/null
+++ b/.woodpecker/build.yaml
@@ -0,0 +1,32 @@
+when:
+ - event: [push, pull_request, manual]
+
+matrix:
+ GHC:
+ # - '9.14' currently broken due to: https://github.com/gtk2hs/gtk2hs/issues/348
+ # - '9.12' currently broken due to: https://github.com/gtk2hs/gtk2hs/issues/348
+ - '9.10'
+ - '9.8'
+ - '9.6'
+
+steps:
+ - name: hlint
+ image: haskell:${GHC}
+ commands:
+ - apt-get update && apt-get install -y hlint
+ - hlint src
+
+ - name: build-and-test
+ image: haskell:${GHC}
+ commands:
+ - apt-get update
+ - >-
+ apt-get install -y
+ xorg-dev libxrandr-dev libpango1.0-dev
+ libasound2-dev libxpm-dev libmpd-dev
+ hspec-discover
+ - cabal update
+ - cabal build all --only-dependencies --enable-tests -fall_extensions --disable-documentation
+ - cabal build all --enable-tests -fall_extensions --disable-documentation
+ - cabal test all --enable-tests -fall_extensions --disable-documentation
+ - cabal test all --enable-tests -fall_extensions -f-with_xrender --disable-documentation
diff --git a/changelog.md b/changelog.md
index b4f5009..404d59f 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,85 @@
+## Version 0.51.1 (June, 2026)
+
+- Missing upper bounds for dependencies
+
+## Version 0.51 (June, 2026)
+
+- Improvements for `PacmanUpdates` (thanks, Enrico Maria and Alexander)
+- Fixes and improvements to `Accordion` (thanks, Enrico Maria)
+- Fixes to `Batt` (thanks, Leana)
+- Fix BadDrawable crash when wallpaper setters free the root pixmap while
+ alpha is 255 (thanks, Ashesh)
+- base dependency relaxed to 4.21
+
+## Version 0.50 (June, 2025)
+
+- New plugins: `PacmanUpdates` (thanks, Alexander)
+- `ArchUpdates` deprecated in favor of `PacmanUpdates`
+ - a deprecation notice will be shown to users of that plugin in the bar in
+ the zero updates case
+- `Accordion`: new constructor to allow short version to have plugins too
+- `Swap`: update for FreeBSD 15
+- `MPD` compiled again by default with `all_extensions`.
+
+## Version 0.49 (April, 2025)
+
+- New plugins: `ArchUpdates` and `Accordion` (thanks, Enrico Maria)
+- New template variable `weatherS` for `WeatherX`.
+- New Nix flake (thanks, refaelsh)
+- `MPRIS`: Fix for duration reported by Spotify (thanks, Claudio)
+- Base dep up to 4.20 (thanks, Alexander)
+
+## Version 0.48.1 (May, 2024)
+
+- Removing for now mouse support for `Kbd`, which can be recovered by
+ interested users using regular actions (see issue #703 for further details).
+
+## Version 0.48 (April, 2024)
+
+- The `Kbd` monitor is now clickable (thanks, Enrico Maria)
+- Fix zombie processes left by `<action>` tag and low battery action (thanks,
+ Ulrik)
+- Fix plugins such as `Alsa` and `Com` not working when configuration is
+ recompiled (#657, ditto)
+- New `Lock'` monitor with configurable labels (thanks, Enrico Maria)
+
+## Version 0.47.4 (March, 2024)
+
+- Bug fixes (launching processes from self-compiled instances)
+
+## Version 0.47.3 (February, 2024)
+
+- New flag `with_shared` to use xmobar with dynamic linking (see PR #690)
+- Fix for actions invoked from recompiled xmobar instances (issue #688)
+- Maximum base version bumped to 4.20
+
+## Version 0.47.2 (November, 2023)
+
+- Compatibility with GHC 9.6
+
+## Version 0.47.1 (September, 2023)
+
+- Allow compilation with libmpd even with GHC > 9.4, by requesting it
+ explicitly with `with_mpd`. See #667 for further details.
+
+## Version 0.47 (August, 2023)
+
+- Fix: center middle section for templates of the for }M{
+- Documentation fixes and improvements
+- Better error handling in network connections
+- Dependency fixes (libmpd excluded for GHC > 9.2)
+
+## Version 0.46 (January, 2023)
+
+- New bar position specifiers TopHM, BottomHM.
+- New configuration option, `dpi`, to set the font scaling factor.
+- Fixes and extensions for section alignment behaviour (#650, #655).
+- Fix: honour fc/bg specs for icons (#663).
+
+## Version 0.45 (October, 2022)
+
+- New cairo/pango font drawing backend, substituting the direct X11/Xft one.
+
## Version 0.44.2 (August, 2022)
- Documentation improvements.
diff --git a/doc/accordion.gif b/doc/accordion.gif
new file mode 100644
index 0000000..c21d2b0
--- /dev/null
+++ b/doc/accordion.gif
Binary files differ
diff --git a/doc/compiling.org b/doc/compiling.org
index 4e0125e..977ef2b 100644
--- a/doc/compiling.org
+++ b/doc/compiling.org
@@ -85,7 +85,9 @@
enters a high-CPU regime right after starting.
- =with_xrender= Enables the main bar background alpha parameter. Requires
- the [[http://hackage.haskell.org/package/X11-xft/][X11-xft]] package.
+ the [[http://hackage.haskell.org/package/X11-xft/][X11-xft]] package. The Xrender extension is not compatible with 10-bit
+ colour modes, i.e., setting ~DefaultDepth~ to 30 in your Xorg
+ configuration. See discussion in [[https://codeberg.org/xmobar/xmobar/issues/651][issue 651]] for details.
- =with_xpm= Support for xpm image file format. This will allow loading
.xpm files in =<icon>=. Requires the [[http://cgit.freedesktop.org/xorg/lib/libXpm][libXpm]] C library.
diff --git a/doc/plugins.org b/doc/plugins.org
index 2199659..ecc9507 100644
--- a/doc/plugins.org
+++ b/doc/plugins.org
@@ -16,11 +16,11 @@
to a certain monitor.
All Monitors accept a common set of arguments, described below in
- [[Default Monitor Arguments]]. Some monitors also accept additional
+ [[#default-arguments][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
+ example, the following [[#batteryp-dirs-args-refreshrate][Battery]] configuration first sets the global
=template= and =Low= arguments and then specifies the battery-specific
=off= option.
@@ -60,6 +60,9 @@
brightness value.
** Default monitor arguments
+ :PROPERTIES:
+ :CUSTOM_ID: default-arguments
+ :END:
These are the options available for all monitors:
@@ -303,8 +306,8 @@
"--", "-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"]
+ "-a", "notify-once \"xmobar\" -u critical 'Battery running out!!' \"$XMOBAR_BATT_LEFT% Remains\"",
+ "-A", "6"]
600
#+end_src
@@ -313,7 +316,22 @@
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%.
+ =notify-once= when the percentage left in the battery reaches 6%.
+
+ =XMOBAR_BATT_LEFT= environment variable is made available to the program being called.
+ You can use it to make the alert message more informative. It is an integer between 0 and 100.
+
+ =notify-once= is a bash wrapper script provided with the =xmobar= package.
+ =xmobar= will run the notification command according to the refresh period,
+ this has the effect of spamming the notification tray if calling =notify-send= directly.
+ =notify-once= script deduplicates the notification by indicating to =notify-send=
+ the last notification we want to replace.
+ See [[https://codeberg.org/xmobar/xmobar/issues/746][#746]] for more information.
+ Note that your notification daemon should handle notification replacement
+ for this to work. Whether the replacement resets the timeout is also handled by the
+ notification daemon.
+ For example, the =wired-notify= implementation has =replacing_enabled=
+ and =replacing_resets_timeout= configuration options [[https://github.com/Toqozz/wired-notify/wiki/Config]].
It is also possible to specify template variables in the =-O= and =-o=
switches, as in the following example:
@@ -694,18 +712,37 @@
#+begin_src haskell
Run Brightness ["-t", "<bar>"] 60
#+end_src
+
*** =Locks=
- Displays the status of Caps Lock, Num Lock and Scroll Lock.
- Aliases to =locks=
+ - Contructors:
+
+ - =Locks= is nullary and uses the strings =CAPS=, =NUM=, =SCROLL= to signal
+ that a lock is enabled (and empty strings to signal it's disabled)
+
+ - =Locks'= allow customizing the strings for the enabled/disabled states
+ of the 3 locks by accepting an assoc list of type =[(String, (String, String))]=,
+ which is expected to contain exactly 3 elements with keys
+ ="CAPS"=, ="NUM"=, ="SCROLL"=.
+
- Example:
#+begin_src haskell
+ -- using default labels
Run Locks
#+end_src
+ #+begin_src haskell
+ -- using custom labels
+ Run $ Locks' [("CAPS" , ("<fc=#00ff00>\xf023</fc>", "<fc=#777777>\xf09c</fc>") )
+ ,("NUM" , ("<fc=#777777>\xf047</fc>", "<fc=#00ff00>\xf047</fc>" ) )
+ ,("SCROLL", ("SlOCK", "" ))]
+ #+end_src
+
** Load and Process monitors
*** =Load Args RefreshRate=
@@ -814,6 +851,9 @@
** Volume monitors
*** =Volume Mixer Element Args RefreshRate=
+ :PROPERTIES:
+ :CUSTOM_ID: volume
+ :END:
- Aliases to the mixer name and element name separated by a
colon. Thus, =Volume "default" "Master" [] 10= can be used as
@@ -889,7 +929,7 @@
*** =Alsa Mixer Element Args=
- Like [[=Volume Mixer Element Args RefreshRate=][Volume]] but with the following differences:
+ Like [[#volume][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
@@ -1052,8 +1092,8 @@
** 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).
+ - 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]] 0.10.1 or later (available on Hackage).
- Aliases to =mpd=
@@ -1243,9 +1283,11 @@
- 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.
+ - Use the variable =skyConditionS= or =weatherS= to display the replacement of
+ the corresponding sky condition. =weatherS= uses the string returned by
+ =weather= to look up a replacement, and, if that one is not found, it
+ looks up the value of =skyConditionS=. All other =Weather= template
+ variables are available as well.
For example:
@@ -1296,7 +1338,7 @@
#+begin_src haskell
Run UVMeter "Brisbane" ["-H", "3", "-L", "3", "--low", "green", "--high", "red"] 900
#+end_src
-** Other monitors
+** Other monitors and plugins
*** =CatInt n filename=
- Reads and displays an integer from the file whose path is =filename=
@@ -1326,6 +1368,126 @@
the display of those numeric fields.
- Default template: =Up: <days>d <hours>h <minutes>m=
+*** =PacmanUpdates (Zero, One, Many, Error) Rate=
+
+ - *This constructor is deprecated. Use =PacmanUpdatesK=, =PacmanUpdatesPredicateK=, or =PacmanUpdatesNoK= instead.*
+ - Aliases to =pacman=
+ - =Zero=: a =String= to use when the system is up to date.
+ - =One=: a =String= to use when only one update is available.
+ - =Many=: a =String= to use when several updates are available; it can contain
+ a =?= character as a placeholder for the number of updates.
+ - =Error=: a =String= to use when pacman fails for unkown reasons (e.g.
+ network error)
+ - Example:
+ #+begin_src haskell
+ PacmanUpdates ("<fc=green>up to date</fc>",
+ "<fc=yellow>1 update</fc>,
+ "<fc=red>? updates</fc>",
+ "<fc=red>!Pacman Error!</fc>")
+ 600
+ #+end_src
+
+*** =PacmanUpdatesK Rate KernName (Bool -> Either String (Int, Bool) -> String)=
+
+ - Aliases to =pacman=
+ - =KernName=: a =String= containing the name of the kernel package, e.g. `linux`, `linux-lts`, …
+ - =(Bool -> Either String (Int, Bool) -> String)=: a function producing the
+ string to be shown by the plugin; it is fed with a `Bool` telling whether
+ the running kernel is older than the installed kernel, and an `Int` and
+ `Bool` telling the number of available updates and whether one of them is a
+ kernel update (or an error message if `checkupdates` fails).
+ - Example:
+ #+begin_src haskell
+ PacmanUpdatesK
+ 600
+ "linux"
+ $ \oldKern mayb -> (if oldKern then "Running old kernel!" else "") ++
+ case mayb of
+ Left _ -> "Some error occurred!"
+ Right (0, False) -> "Up to date"
+ Right (n, pendingK) | n >= 1 -> show n ++ " updates available"
+ ++ if pendingK then " including a kernel update" else ""
+ _ -> error "This is impossible"
+ #+end_src
+
+*** =PacmanUpdatesPredicateK Rate IsKernelUpdate (Bool -> Either String (Int, Bool) -> String)=
+
+ - Aliases to =pacman=
+ - =IsKernelUpdate=: a =String -> Bool= predicate that receives each available
+ package name and returns =True= for kernel packages. This is useful for
+ distributions with versioned kernel package names, such as Manjaro's
+ =linux618= or =linux70= packages.
+ - =(Bool -> Either String (Int, Bool) -> String)=: a function producing the
+ string to be shown by the plugin; it is fed with a =Bool= telling whether
+ the running kernel is older than the installed kernel, and an =Int= and
+ =Bool= telling the number of available updates and whether one of them
+ matches the kernel predicate (or an error message if =checkupdates= fails).
+ - Example:
+ This example requires =import Data.Char (isDigit)= and
+ =import Data.List (stripPrefix)= in your configuration.
+ #+begin_src haskell
+ PacmanUpdatesPredicateK
+ 600
+ ( \packageName ->
+ case stripPrefix "linux" packageName of
+ Just n -> not (null n) && all isDigit n
+ Nothing -> False
+ )
+ $ \oldKern mayb -> (if oldKern then "Running old kernel!" else "") ++
+ case mayb of
+ Left _ -> "Some error occurred!"
+ Right (0, False) -> "Up to date"
+ Right (n, pendingK) | n >= 1 -> show n ++ " updates available"
+ ++ if pendingK then " including a kernel update" else ""
+ _ -> error "This is impossible"
+ #+end_src
+
+*** =PacmanUpdatesNoK Rate (Bool -> Either String Int -> String)=
+
+ - Aliases to =pacman=
+ - =(Bool -> Either String Int -> String)=: a function producing the
+ string to be shown by the plugin; it is fed with a `Bool` telling whether
+ the running kernel is older than the installed kernel, and an `Int` telling
+ the number of available updates (or an error message if `checkupdates` fails).
+ - Example:
+ #+begin_src haskell
+ PacmanUpdatesNoK
+ 600
+ $ \oldKern mayb -> (if oldKern then "Running old kernel!" else "") ++
+ case mayb of
+ Left _ -> "Some error occurred!"
+ Right 0 -> ""
+ Right n | n >= 1 -> show n ++ " updates available"
+ _ -> error "impossible"
+ #+end_src
+
+*** =makeAccordion Tuning [Runnable]=
+
+ - Wraps other =Runnable= plugins and makes them all collapsible to a single string:
+
+ [[file:accordion.gif]]
+
+ - Aliases to =alias' tuning=, being =tuning= of type =Tuning=, so one can use multiple such "accordions"
+ - **Disclaimer**: This only works for Haskell =xmobar.hs=
+ - =Tuning=: the "settings", for which a default value is provided,
+ #+begin_src haskell
+ defaultTuning = Tuning {
+ alias' = "accordion"
+ , initial = True
+ , expand = "<>"
+ , shrink = "><"
+ }
+ #+end_src
+ - =expand=: =String= shown when the accordion is contracted (defaults to ="<>"=).
+ - =shrink=: =String= shown when the accordion is expanded (defaults to ="><"=).
+ - =initial=: =Bool= to tell whether the accordion is initially expanded (defaults to =True=).
+ - =[Runnable]=: a list of =Runnable= plugins
+
+*** =makeAccordion' Tuning [Runnable] [Runnable]=
+
+ - Like =makeAccordion=, but it accepts two distinct lists of runnables to be shown in the two states.
+ - One possible usage is to have a long-vs-short rather than an expanded-vs-collapsed policy, but it's up to you.
+
* Interfacing with window managers
:PROPERTIES:
:CUSTOM_ID: interfacing-with-window-managers
@@ -1355,6 +1517,9 @@
(re)start xmobar outside xmonad.
*** =UnsafeXMonadLog=
+ :PROPERTIES:
+ :CUSTOM_ID: UnsafeXMonadLog
+ :END:
- Aliases to UnsafeXMonadLog
- Displays any text received by xmobar on the =_XMONAD_LOG= atom.
@@ -1385,7 +1550,7 @@
- Aliases to =PropName=
- Reads the X property named by =PropName= (a string) and displays its
- value. The [[../etc/xmonadpropwrite.hs][etc/xmonadpropwrite.hs script]] in xmobar's distribution can be
+ value. The [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmonadpropwrite.hs][etc/xmonadpropwrite.hs script]] in xmobar's distribution can be
used to set the given property from the output of any other program or
script.
@@ -1421,7 +1586,7 @@
- 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
+ - 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=!
@@ -1480,7 +1645,7 @@
=/tmp/xmobar_status= will reveal xmonad for 1.5 seconds and
temporarily overwrite the window titles.
- - Take a look at [[../etc/status.sh][etc/status.sh]]
+ - Take a look at [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/status.sh][etc/status.sh]]
- Expands environment variables for the pipe path
@@ -1547,8 +1712,6 @@
xmonad configuration (=xmonad.hs=), e.g. by using a custom
=~/.xmonad/build= script.
-
-
* Executing external commands
In order to execute an external command you can either write the
diff --git a/doc/quick-start.org b/doc/quick-start.org
index d711138..fecd953 100644
--- a/doc/quick-start.org
+++ b/doc/quick-start.org
@@ -1,12 +1,12 @@
#+title: Quick start: using xmobar
-Xmobar can either be configured using the configuration language, or [[file:using-haskell.org][used as a
+Xmobar can either be configured using the configuration language, or [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/using-haskell.org][used as a
Haskell library]] (similar to xmonad) and compiled with your specific
configuration. For an example of a configuration file using the plain
-configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you can have a look at
-[[../etc/xmobar.hs][etc/xmobar.hs]] for an example of how to write your own xmobar using Haskell.
+configuration language, see [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.config][etc/xmobar.config]], and you can have a look at
+[[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs][etc/xmobar.hs]] for an example of how to write your own xmobar using Haskell.
-* Command Line Options
+* Command line options
xmobar can be either configured with a configuration file or with
command line options. In the second case, the command line options will
@@ -20,7 +20,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
This is the list of command line options (the output of =xmobar --help=):
- #+begin_src shell
+ #+begin_example
Usage: xmobar [OPTION...] [FILE]
Options:
-h, -? --help This help
@@ -38,187 +38,350 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
-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
+ -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
+ -D dpi --dpi=dpi The DPI scaling factor. Default 96.0
+
+ Mail bug reports and suggestions to <mail@jao.io>
+ #+end_example
+
+* Configuration options
:PROPERTIES:
:CUSTOM_ID: configuration-options
:END:
** Global options
- Here are all the global configuration options that you can set within
- the =Config= block in your configuration.
+ Here are all the global options that you can set within the =Config= block in
+ your configuration and will define the overall behaviour and looks of your
+ bar.
- - =font= Name of the font to be used.
+*** Fonts
+ :PROPERTIES:
+ :CUSTOM_ID: fonts
+ :END:
- - =additionalFonts= Haskell-style list of fonts to be used with the
- =fn=-template. See also =textOffsets= below. For example:
+ The following configuration options control the fonts used by xmobar:
- #+begin_src haskell
- additionalFonts = [iconFont, altIconFont]
- #+end_src
+ - =font= Name, as a string, of the default font to use.
- - =bgColor= Background color.
+ - =additionalFonts= Haskell-style list of fonts to us with the
+ =fn=-template. See also =textOffsets= below. For example:
- - =fgColor= Default font color.
+ #+begin_src haskell
+ additionalFonts = [iconFont, altIconFont]
+ #+end_src
+
+ - =dpi= The DPI scaling factor, as a decimal, to use. If 0, negative, or not
+ given, the default of 96 will be used, which corresponds to an average
+ screen. A 10pt font will therefore scale to 10pt * (1/72 pt/inch) * (96
+ pixel/inch) = 13.3 pixel. This is especially useful for HiDPI displays.
+
+ The global font is used by default when none of the others is specified
+ using the ~<fn=n>...</fn>~ markup, with ~n~ a 1-based index in the
+ ~additionalFonts~ array. So, for instance
+
+ #+begin_src
+ <fn=2>some text</fn>
+ #+end_src
- - =alpha= The transparency. 0 is transparent, 255 is opaque.
+ will use, in the configuration above, ~altIconFont~ to display "some text".
- - =position= Top, TopH, TopP, TopW, TopSize, Bottom, BottomH,
- BottomP, BottomW, BottomSize or Static (with x, y, width and height).
+ Font names use the [[https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html][Pango format]]. Here are a few simple examples:
- TopP and BottomP take 2 arguments: left padding and right padding.
+ #+begin_example
+ DejaVu Sans Mono 10
- 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.
+ Iosevka Comfy Semi-Bold Italic 12
- 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.
+ Noto Color Emoji 10
+ #+end_example
- TopH and BottomH take one argument (Int) which adjusts the bar height.
+ We start with a family name (DejaVu Sans Mono, Iosevka Comfy, etc.),
+ followed by optional, space-separated /style options/ (Semi-Bold Italic in
+ the second example above), and ending with a size, in points.
- For example:
+ There are many possible style options (if your font supports them). They
+ can be
- #+begin_src haskell
- position = TopH 30
- #+end_src
+ - *Plain styles*: Normal, Roman, Oblique, Italic.
+ - *Variants*: Small-Caps, All-Small-Caps, Petite-Caps, All-Petite-Caps,
+ Unicase, Title-Caps.
+ - *Weights*: Thin, Ultra-Light, Extra-Light, Light, Semi-Ligh, Demi-Light,
+ Book, Regular, Medium, Semi-Bold, Demi-Bold, Bold, Ultra-Bold,
+ Extra-Bold, Heavy, Black, Ultra-Black, Extra-Black.
+ - *Strectch values:* Thin, Ultra-Light, Extra-Light, Light, Semi-Light,
+ Demi-Light, Book, Regular, Medium, Semi-Bold, Demi-Bold, Bold,
+ Ultra-Bold, Extra-Bold, Heavy, Black, Ultra-Black, Extra-Black.
+ - *Gravity values*: Not-Rotated, South, Upside-Down, North, Rotated-Left,
+ East, Rotated-Right, West.
- to make a 30 tall bar on the top, or
+ So you can add up to 5 style options per family:
- #+begin_src haskell
- position = BottomH 30
- #+end_src
+ #+begin_example
+ Monospace Italic All-Small-Caps Extra-Light Thin North 12
+ #+end_example
- to make a 30 tall bar on the bottom of the screen.
+ It's also possible to specify a list of fonts, separating them by commas,
+ so that they act as fallbacks when the preceding one is not able to display
+ a given glyph. A bit confusingly, the styles and sizes come in reverse
+ order after the families:
- #+begin_src haskell
- position = BottomW C 75
- #+end_src
+ #+begin_example
+ Family 1, Family 2 Styles 2 Size 2, Styles 1 Size 1
+ #+end_example
- to place xmobar at the bottom, centered with the 75% of the screen
- width. Or
+ For instance you could have:
- #+begin_src haskell
- position = BottomP 120 0
- #+end_src
+ #+begin_example
+ Souce Code Pro, Noto Color Emoji Regular 12, Semi-Bold 10
+ #+end_example
- to place xmobar at the bottom, with 120 pixel indent of the left. Or
+ to use Source Code Pro Semi-Bold 10 when possible, and fall back to Noto
+ Color Emoji Regular 12 for characters that the former cannot display.
- #+begin_src haskell
- position = Static { xpos = 0 , ypos = 0, width = 1024, height = 15 }
- #+end_src
+**** X11 Bitmap fonts
- or
+ If you want to use traditional, non-aliased X11 fonts, you can do so via
+ the [[https://www.cl.cam.ac.uk/~mgk25/ucs-fonts.html][Unicode fonts and tools for X11]] package, which provides bitmap
+ versions of them, with a specification of the stytle ~"Fixed 8"~ for what
+ in the old days would have been something like
+ ~-Misc-Fixed-Medium-R-Normal--13-120-75-75-C-70-ISO10646-1~. See also
+ discussion in [[https://codeberg.org/xmobar/xmobar/issues/658][issue #658]].
- #+begin_src haskell
- position = Top
- #+end_src
+*** Colors
- - =textOffset= The vertical offset, in pixels, for the text baseline. If
- negative or not given, xmobar will try to center text vertically.
+ - =bgColor= Background color.
- - =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.
+ - =fgColor= Default font color.
- - =iconOffset= The vertical offset, in pixels, for icons bottom line. If
- negative or not given, xmobar will try to center icons vertically.
+ - =alpha= The transparency. 0 is transparent, 255 is opaque.
- - =lowerOnStart= When True the window is sent the bottom of the window
- stack initially.
+*** Vertical offsets
- - =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.
+ By default, all text and icons in the bar will be vertically centered
+ according to the configured height of the bar. You can override that
+ behaviour with the following options:
- - =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.
+ - =textOffset= The vertical offset, in pixels, for the text baseline. If
+ negative or not given, xmobar will try to center text 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=.
+ - =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.
- - =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.
+ - =iconOffset= The vertical offset, in pixels, for icons bottom line. If
+ negative or not given, xmobar will try to center icons vertically.
- - =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.
+*** Borders
+
+ - =border= TopB, TopBM, BottomB, BottomBM, FullB, FullBM or NoBorder
+ (default).
+
+ TopB, BottomB, FullB take no arguments, and request drawing a border
+ at the top, bottom or around xmobar's window, respectively.
+
+ TopBM, BottomBM, FullBM take an integer argument, which is the margin,
+ in pixels, between the border of the window and the drawn border.
+
+ - =borderColor= Border color.
+
+ - =borderWidth= Border width in pixels.
+
+ - =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
+
+ #+begin_src haskell
+ iconRoot ++ "/"
+ #+end_src
- - =border= TopB, TopBM, BottomB, BottomBM, FullB, FullBM or NoBorder
- (default).
+ prepended to it. Default is =.=.
- TopB, BottomB, FullB take no arguments, and request drawing a border
- at the top, bottom or around xmobar's window, respectively.
+*** Bar position
- TopBM, BottomBM, FullBM take an integer argument, which is the margin,
- in pixels, between the border of the window and the drawn border.
+ - =position= Top, TopH, TopHM, TopP, TopW, TopSize, Bottom, BottomH, BottomHM,
+ BottomP, BottomW, BottomSize or Static (with x, y, width and height).
- - =borderColor= Border color.
+ TopP and BottomP take 2 arguments: left padding and right padding.
- - =borderWidth= Border width in pixels.
+ 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.
- - =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
+ 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.
- #+begin_src haskell
- iconRoot ++ "/"
- #+end_src
+ TopH and BottomH take one argument (Int) which adjusts the bar height.
- prepended to it. Default is =.=.
+ For example:
- - =commands= For setting the options of the programs to run (optional).
+ #+begin_src haskell
+ position = TopH 30
+ #+end_src
+
+ to make a 30 tall bar on the top, or
+
+ #+begin_src haskell
+ position = BottomH 30
+ #+end_src
+
+ to make a 30 tall bar on the bottom of the screen. The corresponding
+ variants ~TopHM~ and ~BottomHM~ allow you to specify, in addition to a
+ height, margins (in pixels) with the borders of the screen (left, right
+ top and bottom); so they take five integers as arguments. For instance,
+ if you one a margin of 2 pixels to the left of the top bar in the above
+ example and 4 to its right and top, you could use:
+
+ #+begin_src haskell
+ position = TopHM 30 2 4 4 0
+ #+end_src
+
+ and similarly for ~BottomHM~.
+
+ #+begin_src haskell
+ position = BottomW C 75
+ #+end_src
+
+ to place xmobar at the bottom, centered with the 75% of the screen
+ width. Or
+
+ #+begin_src haskell
+ position = BottomP 120 0
+ #+end_src
+
+ to place xmobar at the bottom, with 120 pixel indent of the left. Or
+
+ #+begin_src haskell
+ position = Static { xpos = 0 , ypos = 0, width = 1024, height = 15 }
+ #+end_src
- - =sepChar= The character to be used for indicating commands in the
- output template (default '%').
+ or
+
+ #+begin_src haskell
+ position = Top
+ #+end_src
+
+ - =lowerOnStart= When True the window is sent the bottom of the window
+ stack initially.
+
+ - =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.
+
+ - =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.
+
+ - =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=.
+
+ - =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.
+
+ - =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.
+
+ - =wmClass= The value for the window's X11 ~WM_CLASS~ property. Defaults
+ to "xmobar".
+
+ - =wmName= The value for the window's X11 ~WM_NAME~ property. Defaults to
+ "xmobar".
+
+*** Text output
+
+ - =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.
+
+ - =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.
+
+*** Commands and monitors
+
+ - =commands= The list of monitors and plugins to run, together with their
+ individual configurations. The [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][plugin documentation]] details all the
+ available monitors, and you can also create new ones using Haskell. See
+ the [[#commands-list][commands list section]] below for more.
+
+ - =sepChar= The character to be used for indicating commands in the
+ output template (defaults to '%').
+
+ - =alignSep= a 2-character string for aligning text in the output
+ template. See [[#bar-sections][this section]] for details.
+
+ - =template= The output template: a string telling xmobar how to display the
+ outputs of all the =commands= above. See [[#output-template][the next section]] for a full
+ description.
+
+** The =commands= list
+ :PROPERTIES:
+ :CUSTOM_ID: commands-list
+ :END:
+
+ 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.
+
+ The options consist in a list of commands separated by a comma and enclosed
+ by square parenthesis.
+
+ Example:
+
+ #+begin_src haskell
+ [Run Memory ["-t","Mem: <usedratio>%"] 10, Run Swap [] 10]
+ #+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.
+ 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:
- - =template= The output template.
+ #+begin_src haskell
+ template = "<icon=/home/jao/.xmobar/mem.xbm/><memory> <swap>"
+ #+end_src
- - =wmClass= The value for the window's X11 ~WM_CLASS~ property. Defaults
- to "xmobar".
+ This example will run "xclock" command when date is clicked:
- - =wmName= The value for the window's X11 ~WM_NAME~ property. Defaults to
- "xmobar".
+ #+begin_src haskell
+ template = "<action=`xclock`>%date%</action>"
+ #+end_src
- - =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.
+ 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.
- - =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.
+ Other commands can be created as plugins with the Plugin infrastructure.
+ See below.
** The output =template=
+ :PROPERTIES:
+ :CUSTOM_ID: output-template
+ :END:
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
+ aliases, see the [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/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.
@@ -242,7 +405,8 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
opacity, with two additional hex digits (e.g. #FF00000aa).
- =<fn=1>string</fn>= will print =string= with the first font from
- =additionalFonts=. The index =0= corresponds to the standard font.
+ =additionalFonts=. The index =0= corresponds to the standard font. The
+ standard font is also used if the index is out of bounds.
- =<hspace=X/>= will insert a blank horizontal space of =X= pixels.
For example, to add a blank horizontal space of 123 pixels,
@@ -284,6 +448,37 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
See the subsections below for more information on ~<box/>~,
~<icon/>~ and ~<action/>~.
+ - The special characters =}= and ={= are used to delimit up to three sections
+ in the bar that are drawn and aligned independently. See [[#bar-sections][this section]]
+ for more.
+
+*** Bar sections
+ :PROPERTIES:
+ :CUSTOM_ID: bar-sections
+ :END:
+
+ You can use the special characters =}= and ={= are used to delimit up to three
+ sections in the bar, which are aligned and, if needed, overlapped
+ according to these rules:
+
+ - If the template has the form =L}M{R=, with L, R, M arbitrary specs, the
+ monitors in =L= are drawn first, aligned to the left, then =R=, aligned to
+ the right, and finally =M= is drawn centered in the bar. =R= is trimmed to
+ the space left by =L=, and =M= is trimmed to the space left by =L= and =R=. As
+ a particular case, =}M{= will draw a single segment centered in the bar.
+
+ - If the template has the form =L}{R=, =L= is drawn aligned to the left first
+ and then =R=, aligned to the right and trimmed if needed to fit in the
+ space left by =L=.
+
+ - If the template has the form =}L{R=, =R= is drawn first, aligned to the
+ right, and then =L=, aligned to the left and trimmed to the space left by
+ =R=.
+
+ When needed, sections are always trimmed on the right. The section
+ delimiters can be changed using the configuration option =alignSep,= a
+ two-character string.
+
*** Boxes around text
- =<box>string</box>= will print string surrounded by a box in the
@@ -319,7 +514,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
types, colors and widths are valid too, but margins and offsets
are ignored.
-*** Bitmap Icons
+*** Bitmap icons
It's possible to insert in the global templates icon directives of the
form:
@@ -344,7 +539,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
Icons are ignored when xmobar is run in text output mode.
-*** Action Directives
+*** Mouse actions
It's also possible to use action directives of the form:
@@ -359,46 +554,6 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
Actions work also when xmobar is run in text mode and used as
the status command of swaybar.
-** The =commands= configuration option
-
- 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.
-
- The option consists in a list of commands separated by a comma and
- enclosed by square parenthesis.
-
- 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 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 in text mode
:PROPERTIES:
@@ -430,7 +585,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
Other options are ~Ansi~, ~Pango~, and ~Swaybar~.
** Showing xmobar output in Emacs tab or mode line
Using xmobar's ANSI color text ouput, one can plug it inside Emacs, and
- display your monitors in the mode line or the tab bar. The [[../etc/xmobar.el][xmobar.el
+ display your monitors in the mode line or the tab bar. The [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.el][xmobar.el
package]] provides a simple way of doing it.
** Using xmobar in wayland with swaybar or waybar
:PROPERTIES:
@@ -474,7 +629,7 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
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
- [[../etc/padding-icon.sh][etc/padding-icon.sh]].
+ [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/padding-icon.sh][etc/padding-icon.sh]].
** Signal handling
@@ -484,10 +639,10 @@ configuration language, see [[../etc/xmobar.config][etc/xmobar.config]], and you
- After receiving ~SIGUSR2~ xmobar repositions itself on the current
screen.
-* The DBus Interface
+* The DBus interface
When compiled with the optional =with_dbus= flag, xmobar can be controlled
- over dbus. All signals defined in [[../src/Xmobar/System/Signal.hs][src/Signal.hs]] as =data SignalType= can now
+ over dbus. All signals defined in [[https://codeberg.org/xmobar/xmobar/src/branch/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
diff --git a/doc/using-haskell.org b/doc/using-haskell.org
index 4020557..9fd3d88 100644
--- a/doc/using-haskell.org
+++ b/doc/using-haskell.org
@@ -26,7 +26,7 @@
config :: Config
config =
defaultConfig
- { font = "xft:Terminus-8",
+ { font = "DejaVu Sans Mono 9",
allDesktops = True,
alpha = 200,
commands =
@@ -40,7 +40,7 @@
}
main :: IO ()
- main = xmobar config
+ main = xmobar config -- or: configFromArgs config >>= xmobar
#+end_src
You can then for instance run =ghc --make xmobar.hs= to create a new xmobar
@@ -49,6 +49,14 @@
system-wide xmobar, it will notice that you have your own implementation
and (re)compile and run it as needed.
+* Using dynamic linking
+
+ Setting the =with_shared= flag, which is off by default, enables (re)building
+ of xmobar with shared libraries. By default, =xmobar= rebuilds itself with
+ static linking, as is the common practice with Haskell programs, but some
+ distributions use dynamic linking in their packages, or you might also be so
+ inclined. If so, this is your flag.
+
* Writing a plugin
:PROPERTIES:
:CUSTOM_ID: writing-a-plugin
@@ -75,8 +83,8 @@
=run= can be used for simpler plugins. If you define only =run= the plugin
will be run every second. To overwrite this default you just need to
implement =rate=, which must return the number of tenth of seconds between
- every successive runs. See [[../etc/xmobar.hs][etc/xmobar.hs]] for an example of a plugin
- that runs just once, and [[../src/Xmobar/Plugins/Date.hs][src/Xmobar/Plugins/Date.hs]] for one that
+ every successive runs. See [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs][etc/xmobar.hs]] for an example of a plugin
+ that runs just once, and [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/Plugins/Date.hs][src/Xmobar/Plugins/Date.hs]] for one that
implements =rate=.
Notice that Date could be implemented as:
@@ -107,14 +115,14 @@
If your plugin only implements =alias= and =start=, then it is advisable to
put it into the =Xmobar/Plugins/Monitors= directory and use one of the many
- =run*= functions in [[../src/Xmobar/Plugins/Monitors/Common/Run.hs][Xmobar.Plugins.Monitors.Run]] in order to define
- =start=. The =Exec= instance should then live in [[../src/Xmobar/Plugins/Monitors.hs][Xmobar.Plugins.Monitors]].
+ =run*= functions in [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/Plugins/Monitors/Common/Run.hs][Xmobar.Plugins.Monitors.Run]] in order to define
+ =start=. The =Exec= instance should then live in [[https://codeberg.org/xmobar/xmobar/src/branch/master/src/Xmobar/Plugins/Monitors.hs][Xmobar.Plugins.Monitors]].
* Using a plugin
To use your new plugin, you just need to use a pure Haskell configuration
for xmobar (as explained [[#xmobar-in-haskell][above]]) and load your definitions in your =xmobar.hs=
- file. You can see an example in [[../etc/xmobar.hs][etc/xmobar.hs]] showing you how to write
+ file. You can see an example in [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.hs][etc/xmobar.hs]] showing you how to write
a Haskell configuration that uses a new plugin, all in one file.
When xmobar runs with the full path to that Haskell file as its argument
diff --git a/etc/notify-once.sh b/etc/notify-once.sh
new file mode 100644
index 0000000..1c46401
--- /dev/null
+++ b/etc/notify-once.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+help() {
+ echo "notify-send: send deduplicated notifications"
+ echo "Usage: notify-once <name> [ARGS]"
+ echo " ARGS are arguments passed directly to notify-send"
+}
+
+if [ $# -lt 1 ]; then
+ echo "Should get at least one argument, a name" >&2
+ help
+ exit 1
+fi
+APPNAME="$1"
+shift
+
+ID_PATH="/tmp/notify-state-$APPNAME"
+
+if [ -e "$ID_PATH" ]; then
+ # Exists, replace
+ ID=$(cat "$ID_PATH")
+ ID=$(notify-send -r "$ID" -p "$@")
+else
+ # Doesn't exist, create
+ ID=$(notify-send -p "$@")
+fi
+
+# Store new ID
+echo "$ID" >"$ID_PATH"
diff --git a/flake.lock b/flake.lock
deleted file mode 100644
index e60d10e..0000000
--- a/flake.lock
+++ /dev/null
@@ -1,75 +0,0 @@
-{
- "nodes": {
- "flake-utils": {
- "locked": {
- "lastModified": 1653893745,
- "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
- "owner": "numtide",
- "repo": "flake-utils",
- "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
- "type": "github"
- },
- "original": {
- "owner": "numtide",
- "repo": "flake-utils",
- "type": "github"
- }
- },
- "git-ignore-nix": {
- "inputs": {
- "nixpkgs": "nixpkgs"
- },
- "locked": {
- "lastModified": 1646480205,
- "narHash": "sha256-kekOlTlu45vuK2L9nq8iVN17V3sB0WWPqTTW3a2SQG0=",
- "owner": "hercules-ci",
- "repo": "gitignore.nix",
- "rev": "bff2832ec341cf30acb3a4d3e2e7f1f7b590116a",
- "type": "github"
- },
- "original": {
- "owner": "hercules-ci",
- "ref": "master",
- "repo": "gitignore.nix",
- "type": "github"
- }
- },
- "nixpkgs": {
- "locked": {
- "lastModified": 1632846328,
- "narHash": "sha256-sFi6YtlGK30TBB9o6CW7LG9mYHkgtKeWbSLAjjrNTX0=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "2b71ddd869ad592510553d09fe89c9709fa26b2b",
- "type": "github"
- },
- "original": {
- "id": "nixpkgs",
- "type": "indirect"
- }
- },
- "nixpkgs_2": {
- "locked": {
- "lastModified": 1654398695,
- "narHash": "sha256-Kw/KeoFXszNsF5mORP45mrxCP+k9Aq03hWcuWCL9sdI=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "c5d810f4c74c824ae0fb788103003c6c9d366a08",
- "type": "github"
- },
- "original": {
- "id": "nixpkgs",
- "type": "indirect"
- }
- },
- "root": {
- "inputs": {
- "flake-utils": "flake-utils",
- "git-ignore-nix": "git-ignore-nix",
- "nixpkgs": "nixpkgs_2"
- }
- }
- },
- "root": "root",
- "version": 7
-}
diff --git a/flake.nix b/flake.nix
deleted file mode 100644
index 7471fb9..0000000
--- a/flake.nix
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- inputs = {
- git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master";
- flake-utils.url = "github:numtide/flake-utils";
- };
- outputs = { self, nixpkgs, flake-utils, git-ignore-nix }:
- let
- overlay = final: prev: {
- haskellPackages = prev.haskellPackages.override (old: {
- overrides = prev.lib.composeExtensions (old.overrides or (_: _: { }))
- (hself: hsuper: {
- xmobar = prev.haskell.lib.compose.dontCheck (hself.callCabal2nix "xmobar"
- (git-ignore-nix.lib.gitignoreSource ./.) { });
- });
- });
- };
- overlays = [ overlay ];
- in flake-utils.lib.eachDefaultSystem (system:
- let pkgs = import nixpkgs { inherit system overlays; };
- dynamicLibraries = with pkgs; [
- xorg.libX11
- xorg.libXrandr
- xorg.libXrender
- xorg.libXScrnSaver
- xorg.libXext
- xorg.libXft
- xorg.libXpm.out
- xorg.libXrandr
- xorg.libXrender
- ];
- in rec {
- devShell = pkgs.haskellPackages.shellFor {
- packages = p: [ p.xmobar ];
- buildInputs = with pkgs; [
- haskellPackages.cabal-install
- #haskellPackages.haskell-language-server
- ] ++ dynamicLibraries;
-
- LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath dynamicLibraries;
- };
- defaultPackage = pkgs.haskellPackages.xmobar;
- }) // {
- inherit overlay overlays;
- };
-}
diff --git a/nix/default.nix b/nix/default.nix
new file mode 100644
index 0000000..aea52ed
--- /dev/null
+++ b/nix/default.nix
@@ -0,0 +1,130 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib;
+let
+ cfg = config.programs.nixmobar;
+in
+{
+ options.programs.nixmobar = {
+ enable = mkEnableOption (mdDoc "Xmobar, a minimalistic status bar");
+
+ font = mkOption {
+ type = types.str;
+ default = "Fira Code 13";
+ description = mdDoc "Main font for Xmobar.";
+ };
+
+ additionalFonts = mkOption {
+ type = types.listOf types.str;
+ default = [ "Fira Code 22" ];
+ description = mdDoc "Additional fonts for use in Xmobar.";
+ };
+
+ bgColor = mkOption {
+ type = types.str;
+ default = "#282a36";
+ description = mdDoc "Background color of Xmobar.";
+ };
+
+ fgColor = mkOption {
+ type = types.str;
+ default = "#f8f8f2";
+ description = mdDoc "Foreground (text) color of Xmobar.";
+ };
+
+ textOffset = mkOption {
+ type = types.int;
+ default = 2;
+ description = mdDoc "Offset of the text from the edge.";
+ };
+
+ verbose = mkOption {
+ type = types.bool;
+ default = true;
+ description = mdDoc "Enable verbose mode for Xmobar.";
+ };
+
+ allDesktops = mkOption {
+ type = types.bool;
+ default = true;
+ description = mdDoc "Show Xmobar on all desktops.";
+ };
+
+ lowerOnStart = mkOption {
+ type = types.bool;
+ default = true;
+ description = mdDoc "Whether Xmobar should be lowered on start.";
+ };
+
+ overrideRedirect = mkOption {
+ type = types.bool;
+ default = true;
+ description = mdDoc "If true, Xmobar will bypass window manager redirection.";
+ };
+
+ position = mkOption {
+ type = types.str;
+ default = "BottomH 26";
+ description = mdDoc "Position of Xmobar on the screen.";
+ };
+
+ alpha = mkOption {
+ type = types.int;
+ default = 200;
+ description = mdDoc "Transparency level of Xmobar (0-255).";
+ };
+
+ commands = mkOption {
+ type = types.lines;
+ default = ''
+ Run XMonadLog
+ Run DiskU ["/", "<fc=#bd93f9><fn=1>\\xf0a0</fn></fc> <free>"] [] 50
+ Run DiskIO ["/", "<read><fc=#bd93f9> R</fc> <fc=#bd93f9>W</fc> <write>"] ["-t", "", "-w", "4"] 10
+ Run Date "%a %_d %b %H:%M:%S" "date" 10
+ # Add more commands here, one per line
+ '';
+ description = mdDoc "List of commands to run in Xmobar, each on a new line.";
+ };
+
+ alignSep = mkOption {
+ type = types.str;
+ default = "}{";
+ description = mdDoc "Separators for alignment left and right.";
+ };
+
+ template = mkOption {
+ type = types.str;
+ default = "<hspace=8/>%XMonadLog% }{ %load%|%disku%|%diskio%|<fc=#bd93f9><fn=1></fn></fc>%wifi_signal%|%dynnetwork%|<fc=#bd93f9><fn=1>󰈐</fn></fc>%cat0%|%multicoretemp%|%cpufreq%|%multicpu%|<fc=#bd93f9><fn=1></fn></fc>%kbd%|%memory% %swap%|%battery%|%alsa:default:Master%|<fc=#bd93f9><fn=1></fn></fc>%kernel_version%|%date%|%_XMONAD_TRAYPAD%";
+ description = mdDoc "Template string for Xmobar layout.";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ home.packages = [ pkgs.xmobar ];
+ xdg.configFile."xmobar/.xmobarrc" = {
+ text = # haskell
+ ''
+ Config {
+ font = "${cfg.font}",
+ additionalFonts = [${lib.concatMapStringsSep ", " (s: "\"" + s + "\"") cfg.additionalFonts}],
+ bgColor = "${cfg.bgColor}",
+ fgColor = "${cfg.fgColor}",
+ textOffset = ${toString cfg.textOffset},
+ verbose = ${if cfg.verbose then "True" else "False"},
+ allDesktops = ${if cfg.allDesktops then "True" else "False"},
+ lowerOnStart = ${if cfg.lowerOnStart then "True" else "False"},
+ overrideRedirect = ${if cfg.overrideRedirect then "True" else "False"},
+ position = ${cfg.position},
+ alpha = ${toString cfg.alpha},
+ commands = [${cfg.commands}],
+ alignSep = "${cfg.alignSep}",
+ template = "${cfg.template}"
+ }
+ '';
+ };
+ };
+}
diff --git a/nix/flake.lock b/nix/flake.lock
new file mode 100644
index 0000000..c4d98f4
--- /dev/null
+++ b/nix/flake.lock
@@ -0,0 +1,95 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1726560853,
+ "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "git-ignore-nix": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "ref": "master",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1666603677,
+ "narHash": "sha256-apAEIj+z1iwMaMJ4tB21r/VTetfGDLDzuhXRHJknIAU=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "074da18a72269cc5a6cf444dce42daea5649b2fe",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1781074563,
+ "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "git-ignore-nix": "git-ignore-nix",
+ "nixpkgs": "nixpkgs_2"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/nix/flake.nix b/nix/flake.nix
new file mode 100644
index 0000000..2c0dbfb
--- /dev/null
+++ b/nix/flake.nix
@@ -0,0 +1,64 @@
+{
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+ git-ignore-nix.url = "github:hercules-ci/gitignore.nix/master";
+ flake-utils.url = "github:numtide/flake-utils";
+ };
+ outputs =
+ {
+ self,
+ nixpkgs,
+ flake-utils,
+ git-ignore-nix,
+ }:
+ let
+ overlay = final: prev: {
+ haskellPackages = prev.haskellPackages.override (old: {
+ overrides = prev.lib.composeExtensions (old.overrides or (_: _: { })) (
+ hself: hsuper: {
+ xmobar = prev.haskell.lib.compose.dontCheck (
+ hself.callCabal2nix "xmobar" (git-ignore-nix.lib.gitignoreSource ../.) { }
+ );
+ }
+ );
+ });
+ };
+ overlays = [ overlay ];
+
+ homeModules.mainmodule = import ./default.nix;
+ in
+ flake-utils.lib.eachDefaultSystem (
+ system:
+ let
+ pkgs = import nixpkgs { inherit system overlays; };
+ dynamicLibraries = with pkgs; [
+ libX11
+ libXrandr
+ libXrender
+ libXScrnSaver
+ libXext
+ libXft
+ libXpm.out
+ libXrandr
+ libXrender
+ ];
+ in
+ {
+ devShell = pkgs.haskellPackages.shellFor {
+ packages = p: [ p.xmobar ];
+ buildInputs =
+ with pkgs;
+ [
+ haskellPackages.cabal-install
+ ]
+ ++ dynamicLibraries;
+
+ LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath dynamicLibraries;
+ };
+ defaultPackage = pkgs.haskellPackages.xmobar;
+ }
+ )
+ // {
+ inherit overlay overlays homeModules;
+ };
+}
diff --git a/nix/readme.org b/nix/readme.org
new file mode 100644
index 0000000..6a492e5
--- /dev/null
+++ b/nix/readme.org
@@ -0,0 +1,80 @@
+* Nix flake for Xmobar
+This flake exposes a module to use with home-manager.
+Here is how to set it up:
+
+1. Add the nixmobar flake as an input to your NiOS flake:
+ #+BEGIN_SRC nix
+ inputs = {
+ nixmobar.url = "git+https://codeberg.org/xmobar/xmobar.git/?dir=nix";
+ };
+ #+END_SRC
+
+2. And then, where you import your `home.nix`, add `extraSpecialArgs` like this:
+ #+BEGIN_SRC nix
+ home-manager = {
+ extraSpecialArgs = {
+ inherit inputs nixmobar;
+ };
+ users.refaelsh = import ./home.nix;
+ };
+ #+END_SRC
+
+3. Final step, use the module in `home.nix`:
+ #+BEGIN_SRC nix
+ {
+ inputs,
+ ...
+ }:
+ {
+ home.stateversion = "24.05";
+
+ imports = [
+ inputs.nixmobar.homeModules.mainmodule
+ # Other imports go here.
+ ];
+
+ }
+ #+END_SRC
+
+* Example usage
+#+BEGIN_SRC haskell
+{
+ programs.nixmobar = {
+ enable = true;
+ font = "Fira Code 13";
+ additionalFonts = [ "Fira Code 22" ];
+ bgColor = "#282A36";
+ fgColor = "#F8F8F2";
+ textOffset = 2;
+ verbose = true;
+ allDesktops = true;
+ lowerOnStart = true;
+ overrideRedirect = true;
+ position = "BottomH 26";
+ alpha = 200;
+ alignSep = "}{";
+ template = "<hspace=8/>%XMonadLog% }{ %load%|%disku%|%diskio%|<fc=#bd93f9><fn=1></fn></fc>%wifi_signal%|%dynnetwork%|<fc=#bd93f9><fn=1>󰈐</fn></fc>%cat0%|%multicoretemp%|%cpufreq%|%multicpu%|<fc=#bd93f9><fn=1></fn></fc>%kbd%|%memory% %swap%|%battery%|%alsa:default:Master%|<fc=#bd93f9><fn=1></fn></fc>%kernel_version%|%date%|%_XMONAD_TRAYPAD%";
+ commands = # haskell
+ ''
+ Run XMonadLog,
+ Run DiskU [("/", "<fc=#bd93f9><fn=1>\xf0a0</fn></fc> <free>")] [] 50,
+ Run DiskIO [("/", "<read><fc=#bd93f9> R</fc> <fc=#bd93f9>W</fc> <write>")] ["-t", "", "-w", "4"] 10,
+ Run DynNetwork ["-t", "<rx>KB/s<fc=#bd93f9><fn=1>\x1F89B</fn></fc><fc=#bd93f9><fn=1>\x1F899</fn></fc><tx>KB/s", "-w", "5"] 10,
+ Run Memory ["-t", "<fc=#bd93f9><fn=1>\xE266</fn></fc><usedratio>%"] 10,
+ Run Swap ["-t", "<fc=#bd93f9>S</fc><usedratio>%"] 10,
+ Run Kbd [],
+ Run CpuFreq ["-t", "<avg>GHz"] 50,
+ Run MultiCoreTemp ["-t", "<fc=#bd93f9><fn=1>\xf2c9</fn></fc><avg>°", "-L", "60", "-H", "95", "-l", "white", "-n", "white", "-h", "red"] 50,
+ Run CatInt 0 "/sys/class/hwmon/hwmon4/fan1_input" [] 50,
+ Run MultiCpu ["-t", "<fc=#bd93f9><fn=1>\xf4bc</fn></fc> <vbar0><vbar1><vbar2><vbar3><vbar4><vbar5><vbar6><vbar7>", "-w", "99", "-L", "3", "-H", "50", "--normal", "green", "--high", "red"] 10,
+ Run BatteryP ["BAT0"] ["-t", "<fc=#bd93f9><fn=1>󱊣</fn></fc><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-once \"xmobar\" -u critical 'Battery running out!!'", "-A", "3"] 600,
+ Run Alsa "default" "Master" ["-t", "<fc=#bd93f9><fn=1>\xf028</fn></fc> <volume>%"],
+ Run Date "%a %_d %b %H:%M:%S" "date" 10,
+ Run Load ["-t", "<fc=#bd93f9><fn=0>L</fn></fc><load1>", "-L", "1", "-H", "3", "-d", "2"] 300,
+ Run ComX "nmcli" ["-t", "-f", "SIGNAL", "dev", "wifi"] "N/A" "wifi_signal" 50,
+ Run Com "uname" ["-r"] "kernel_version" 3600,
+ Run XPropertyLog "_XMONAD_TRAYPAD"
+ '';
+ };
+}
+#+END_SRC
diff --git a/readme.org b/readme.org
index f9226e9..81fdc48 100644
--- a/readme.org
+++ b/readme.org
@@ -5,8 +5,8 @@
<a href="http://hackage.haskell.org/package/xmobar">
<img src="https://img.shields.io/hackage/v/xmobar.svg" alt="hackage"/>
</a>
- <a href="https://ci.codeberg.org/xmobar/xmobar">
- <img src="https://ci.codeberg.org/api/badges/xmobar/xmobar/status.svg" alt="ci"/>
+ <a href="https://ci.codeberg.org/repos/17487" target="_blank">
+ <img src="https://ci.codeberg.org/api/badges/17487/status.svg" alt="status-badge" />
</a>
</p>
#+end_export
@@ -26,9 +26,25 @@ output, in a variety of formats.
[[file:doc/screenshots/xmobar-exwm.png]]
-Check [[./changelog.md][the change log]] for our release history. We also have an IRC
+Check [[https://codeberg.org/xmobar/xmobar/src/branch/master/changelog.md][the change log]] for our release history. We also have an IRC
channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].
+* Breaking news
+
+ - Starting with version 0.51, we introduced a new GHC support policy: xmobar
+ officially supports only the GHC versions that upstream marks as /suitable
+ for use/ in the [[https://gitlab.haskell.org/ghc/ghc/-/wikis/GHC-status][official GHC status overview]].
+ At the time of writing, this means GHC versions from 9.6 to 9.14.
+
+ - Starting with version 0.45, we use cairo/pango as our drawing engine
+ (instead of plain X11/Xft). From a user's point of view, that change
+ should be mostly transparent, except for the facts that it's allowed
+ fixing quite a few bugs and that your /font names/ in your configuration, if
+ you used ~xft~ ones, might need to be adapted to Pango's syntax: please see
+ [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#fonts][this section of the documentation]] for all the details. If you're
+ compiling your own xmobar, there's a new dependency on libpango (see
+ [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org#c-libraries][C library dependencies]]).
+
* Installation
:PROPERTIES:
:CUSTOM_ID: installation
@@ -64,10 +80,15 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].
emerge --ask xmobar
#+end_src
+ - FreeBSD
+ #+begin_src shell
+ pkg install hs-xmobar
+ #+end_src
+
** Using cabal or stack
Xmobar is available from [[http://hackage.haskell.org/package/xmobar/][Hackage]], and you can compile and install it using
- =cabal-install=, making sure the [[doc/compiling.org#c-libraries][required C libraries]] are in place. For a
+ =cabal-install=, making sure the [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org#c-libraries][required C libraries]] are in place. For a
full build with all available extensions:
#+begin_src shell
@@ -79,13 +100,10 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].
cabal install xmobar -fall_extensions
#+end_src
- Starting with version 0.35.1, xmobar requires at least GHC version
- 8.4.x. to build. See [[https://codeberg.org/xmobar/xmobar/issues/461][this issue]] for more information.
-
- See [[file:doc/compiling.org#optional-features][here]] for a list of optional compilation flags that will enable some
+ See [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org#optional-features][here]] for a list of optional compilation flags that will enable some
optional plugins.
- See [[file:doc/compiling.org][compiling]] for full compilation instructions starting from source.
+ See [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/compiling.org][compiling]] for full compilation instructions starting from source.
* Running xmobar
** Running xmobar with a configuration file
@@ -106,7 +124,7 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].
or =~/.xmobarrc=.
All the available command line switches and configuration parameters are
- described in [[file:quick-start.org][the quick start guide]] and [[file:doc/plugins.org][the plugins index]].
+ described in [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org][the quick start guide]] and [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][the plugins index]].
** Writing your own xmobar in Haskell
@@ -116,7 +134,7 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].
Haskell instead of using a configuration file. (This is very similar to
how [[http://xmonad.org][xmonad]] works.) That gives you the ability of using Haskell and its
libraries to extend xmobar to your heart's content. If you are a
- programmer, take a look [[file:doc/using-haskell.org][here]] to learn more.
+ programmer, take a look [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/using-haskell.org][here]] to learn more.
** Running xmobar in text mode
@@ -124,63 +142,71 @@ channel, ~#xmobar~, at [[ircs://irc.libera.chat][Libera]].
it is possible to redirect xmobar's output 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. See [[./doc/quick-start.org#text-mode][Running xmobar in text mode]] for
- details. Using this mode, you could [[file:doc/quick-start.org#wayland][pipe xmobar's output to, say, swaybar]],
- and use it in wayland, or, with the [[./etc/xmobar.el][xmobar.el]] package, show it in Emacs's
+ there is no need for an X11 display. See [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#text-mode][Running xmobar in text mode]] for
+ details. Using this mode, you could [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org#wayland][pipe xmobar's output to, say, swaybar]],
+ and use it in wayland, or, with the [[https://codeberg.org/xmobar/xmobar/src/branch/master/etc/xmobar.el][xmobar.el]] package, show it in Emacs's
tab bar.
* Configuration and further documentation
- If you want to jump straight into running xmobar, head over to the
- [[./doc/quick-start.org][quick start guide]].
+ [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/quick-start.org][quick start guide]].
- If you want to get a detailed overview of all available plugins and
- monitors, visit the [[./doc/plugins.org][plugins index]].
+ monitors, visit the [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/plugins.org][plugins index]].
- For more information on how to use xmobar as a Haskell library see the
- [[file:doc/using-haskell.org][using Haskell guide]].
+ [[https://codeberg.org/xmobar/xmobar/src/branch/master/doc/using-haskell.org][using Haskell guide]].
- If you want to know how to contribute to the xmobar project, check out
- [[contributing.org][contributing]].
+ [[https://codeberg.org/xmobar/xmobar/src/branch/master/contributing.org][contributing]].
* 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, Patrick Günther, 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
- Michał Zielonka.
-
- Andrea wants to thank Robert Manea and Spencer Janssen for their
- help in understanding how X works. They gave him suggestions on how
- to solve many problems with xmobar. He also thanks Claus Reinke for
- making him understand existential types (or at least for letting him
- think he grasps existential types...;-).
+ 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 Kostas Agnantis, Mohammed
+ Alshiekh, Ashesh Ambasta, Alex Ameen, Axel Angel, Enrico Maria De Angelis, 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, Jonathan Grochowski, Patrick Günther, Reto
+ Hablützel, Corey Halpin, Juraj Hercek, Jaroslaw Jantura, Tomáš Janoušek, Ada
+ Joule, Spencer Janssen, Léana 江, 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, Ulrik de
+ Muelenaere, Joan Milev, Marcin Mikołajczyk, Dino Morelli, Tony Morris, Eric
+ Mrak, Thiago Negri, Edward O'Callaghan, Svein Ove, Martin Perner, Alexander
+ Pankoff, 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 Michał Zielonka.
+
+ Andrea wants to thank Robert Manea and Spencer Janssen for their help in
+ understanding how X works. They gave him suggestions on how to solve many
+ problems with xmobar. He also thanks Claus Reinke for making him understand
+ existential types (or at least for letting him think he grasps existential
+ types...;-).
+
+* Contributing
+** Generative AI (LLMs)
+
+Use of generative AI (LLMs, diffusion models and similar technology) is not
+acceptable for contributions to or interactions with the xmobar project.
+
+This includes words, images and code, as well as bug reports, commit
+messages, email (mailing list or private) and IRC messages.
* License
This software is released under a BSD-style license. See [[https://codeberg.org/xmobar/xmobar/src/branch/master/license][license]] for more
details.
- Copyright © 2010-2022 Jose Antonio Ortega Ruiz
+ Copyright © 2010-2026 Jose Antonio Ortega Ruiz
Copyright © 2007-2010 Andrea Rossato
diff --git a/src/Xmobar.hs b/src/Xmobar.hs
index ced40a5..5a31d80 100644
--- a/src/Xmobar.hs
+++ b/src/Xmobar.hs
@@ -3,7 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : Xmobar
--- Copyright : (c) 2011, 2012, 2013, 2014, 2015, 2017, 2018, 2019, 2022 Jose Antonio Ortega Ruiz
+-- Copyright : (c) 2011-2015, 2017-2019, 2022, 2025 Jose Antonio Ortega Ruiz
-- (c) 2007 Andrea Rossato
-- License : BSD-style (see LICENSE)
--
@@ -19,13 +19,13 @@ module Xmobar (xmobar
, xmobarMain
, defaultConfig
, configFromArgs
- , tenthSeconds
, Runnable (..)
- , Exec (..)
, Command (..)
, SignalType (..)
+ , module Xmobar.Run.Exec
, module Xmobar.Config.Types
, module Xmobar.Config.Parse
+ , module Xmobar.Plugins.Accordion
, module Xmobar.Plugins.BufferedPipeReader
, module Xmobar.Plugins.CommandReader
, module Xmobar.Plugins.Date
@@ -43,6 +43,7 @@ module Xmobar (xmobar
#endif
, module Xmobar.Plugins.NotmuchMail
, module Xmobar.Plugins.Monitors
+ , module Xmobar.Plugins.PacmanUpdates
, module Xmobar.Plugins.PipeReader
, module Xmobar.Plugins.MarqueePipeReader
, module Xmobar.Plugins.StdinReader
@@ -53,6 +54,7 @@ import Xmobar.Run.Runnable
import Xmobar.Run.Exec
import Xmobar.Config.Types
import Xmobar.Config.Parse
+import Xmobar.Plugins.Accordion
import Xmobar.Plugins.Command
import Xmobar.Plugins.BufferedPipeReader
import Xmobar.Plugins.CommandReader
@@ -70,6 +72,7 @@ import Xmobar.Plugins.Mail
import Xmobar.Plugins.MBox
#endif
import Xmobar.Plugins.Monitors
+import Xmobar.Plugins.PacmanUpdates
import Xmobar.Plugins.PipeReader
import Xmobar.Plugins.StdinReader
import Xmobar.Plugins.MarqueePipeReader
diff --git a/src/Xmobar/App/Compile.hs b/src/Xmobar/App/Compile.hs
index 80dbac7..e5b08b7 100644
--- a/src/Xmobar/App/Compile.hs
+++ b/src/Xmobar/App/Compile.hs
@@ -3,7 +3,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.App.Compile
--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2026 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -20,20 +20,17 @@
module Xmobar.App.Compile(recompile, trace, xmessage) where
import Control.Monad.IO.Class
-import Control.Monad.Fix (fix)
-import Control.Exception.Extensible (try, bracket, SomeException(..))
-import qualified Control.Exception.Extensible as E
+import Control.Exception (SomeException(..))
+import qualified Control.Exception as E
import Control.Monad (filterM, when)
import Data.List ((\\))
-import Data.Maybe (isJust)
import System.FilePath((</>), takeExtension)
import System.IO
import System.Directory
import System.Process
import System.Exit
-import System.Posix.Process(executeFile, forkProcess, getAnyProcessStatus)
+import System.Posix.Process(executeFile, forkProcess)
import System.Posix.Types(ProcessID)
-import System.Posix.Signals
isExecutable :: FilePath -> IO Bool
isExecutable f =
@@ -144,14 +141,12 @@ recompile confDir dataDir execName force verb = liftIO $ do
else shouldRecompile verb src bin lib
if sc
then do
- uninstallSignalHandlers
- status <- bracket (openFile err WriteMode) hClose $
+ status <- withFile err WriteMode $
\errHandle ->
waitForProcess =<<
if useScript
then runScript script bin confDir errHandle
else runGHC bin confDir errHandle
- installSignalHandlers
if status == ExitSuccess
then trace verb "Xmobar recompilation process exited with success!"
else do
@@ -168,24 +163,9 @@ recompile confDir dataDir execName force verb = liftIO $ do
#ifdef RTSOPTS
++ ["-rtsopts", "-with-rtsopts", "-V0"]
#endif
+#ifdef SHARED_LIBRARIES
+ ++ ["-dynamic"]
+#endif
++ ["-o", bin]
runGHC bin = runProc "ghc" (opts bin)
runScript script bin = runProc script [bin]
-
--- | Ignore SIGPIPE to avoid termination when a pipe is full, and SIGCHLD to
--- avoid zombie processes, and clean up any extant zombie processes.
-installSignalHandlers :: MonadIO m => m ()
-installSignalHandlers = liftIO $ do
- installHandler openEndedPipe Ignore Nothing
- installHandler sigCHLD Ignore Nothing
- (try :: IO a -> IO (Either SomeException a))
- $ fix $ \more -> do
- x <- getAnyProcessStatus False False
- when (isJust x) more
- return ()
-
-uninstallSignalHandlers :: MonadIO m => m ()
-uninstallSignalHandlers = liftIO $ do
- installHandler openEndedPipe Default Nothing
- installHandler sigCHLD Default Nothing
- return ()
diff --git a/src/Xmobar/App/Config.hs b/src/Xmobar/App/Config.hs
index a284973..5c2f362 100644
--- a/src/Xmobar/App/Config.hs
+++ b/src/Xmobar/App/Config.hs
@@ -67,6 +67,7 @@ defaultConfig =
, signal = SignalChan Nothing
, textOutput = False
, textOutputFormat = Plain
+ , dpi = 96.0
}
-- | Return the path to the xmobar data directory. This directory is
diff --git a/src/Xmobar/App/Opts.hs b/src/Xmobar/App/Opts.hs
index 3a6b4e7..5196b3c 100644
--- a/src/Xmobar/App/Opts.hs
+++ b/src/Xmobar/App/Opts.hs
@@ -1,7 +1,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.App.Opts
--- Copyright: (c) 2018, 2019, 2020, 2022 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2019, 2020, 2022, 2023-2026 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -52,6 +52,7 @@ data Opts = Help
| Position String
| WmClass String
| WmName String
+ | Dpi String
deriving (Show, Eq)
options :: [OptDescr Opts]
@@ -60,7 +61,7 @@ options =
, 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")
+ , Option "T" ["text"] (OptArg TextOutput "format")
"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")
@@ -95,6 +96,8 @@ options =
"On which X screen number to start"
, Option "p" ["position"] (ReqArg Position "position")
"Specify position of xmobar. Same syntax as in config file"
+ , Option "D" ["dpi"] (ReqArg Dpi "dpi")
+ "The DPI scaling factor. Default 96.0"
]
getOpts :: [String] -> IO ([Opts], [String])
@@ -113,7 +116,7 @@ usage = usageInfo header options ++ footer
info :: String
info = "xmobar " ++ showVersion version
- ++ "\n (C) 2010 - 2022 Jose A Ortega Ruiz"
+ ++ "\n (C) 2010 - 2026 Jose A Ortega Ruiz"
++ "\n (C) 2007 - 2010 Andrea Rossato\n "
++ mail ++ "\n" ++ license ++ "\n"
@@ -161,6 +164,7 @@ doOpts conf (o:oo) =
Right x -> doOpts' (conf {commands = commands conf ++ x})
Left e -> putStr (e ++ usage) >> exitWith (ExitFailure 1)
Position s -> readPosition s
+ Dpi d -> doOpts' (conf {dpi = read d})
where readCom c str =
case readStr str of
[x] -> Right x
diff --git a/src/Xmobar/Config/Parse.hs b/src/Xmobar/Config/Parse.hs
index 16af3db..0b41267 100644
--- a/src/Xmobar/Config/Parse.hs
+++ b/src/Xmobar/Config/Parse.hs
@@ -19,7 +19,8 @@
module Xmobar.Config.Parse(readConfig
, parseConfig
, indexedFont
- , indexedOffset) where
+ , indexedOffset
+ , colorComponents) where
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Number (int)
@@ -31,6 +32,14 @@ import Xmobar.Config.Types
import qualified System.IO as S (readFile)
+-- | 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)
+
+
stripComments :: String -> String
stripComments =
unlines . map (drop 5 . strip False . (replicate 5 ' '++)) . lines
@@ -63,7 +72,7 @@ parseConfig defaultConfig =
<|?> pAllDesktops <|?> pOverrideRedirect <|?> pPickBroadest
<|?> pLowerOnStart <|?> pPersistent <|?> pIconRoot
<|?> pCommands <|?> pSepChar <|?> pAlignSep <|?> pTemplate
- <|?> pVerbose <|?> pSignal
+ <|?> pVerbose <|?> pSignal <|?> pDpi
fields = [ "font", "additionalFonts", "bgColor", "fgColor"
, "wmClass", "wmName", "sepChar"
@@ -72,7 +81,7 @@ parseConfig defaultConfig =
, "allDesktops", "overrideRedirect", "pickBroadest"
, "hideOnStart", "lowerOnStart", "persistent", "iconRoot"
, "alpha", "commands", "verbose", "signal", "textOutput"
- , "textOutputFormat"
+ , "textOutputFormat", "dpi"
]
pTextOutput = readField textOutput "textOutput"
@@ -103,6 +112,7 @@ parseConfig defaultConfig =
pIconRoot = readField iconRoot "iconRoot"
pAlpha = readField alpha "alpha"
pVerbose = readField verbose "verbose"
+ pDpi = readField dpi "dpi"
pSignal = field signal "signal" $
fail "signal is meant for use with Xmobar as a library.\n It is not meant for use in the configuration file."
diff --git a/src/Xmobar/Config/Template.hs b/src/Xmobar/Config/Template.hs
new file mode 100644
index 0000000..ad30c3d
--- /dev/null
+++ b/src/Xmobar/Config/Template.hs
@@ -0,0 +1,188 @@
+------------------------------------------------------------------------------
+-- |
+-- Module: Xmobar.Config.Template
+-- Copyright: (c) 2022 jao
+-- License: BSD3-style (see LICENSE)
+--
+-- Maintainer: mail@jao.io
+-- Stability: unstable
+-- Portability: portable
+-- Created: Fri Sep 30, 2022 06:33
+--
+--
+-- Parsing template strings
+--
+------------------------------------------------------------------------------
+
+
+module Xmobar.Config.Template (parseString) where
+
+import Data.Maybe (fromMaybe)
+import qualified Control.Monad as CM
+
+import Text.Parsec ((<|>))
+import Text.Read (readMaybe)
+
+import qualified Text.Parsec as P
+import qualified Text.Parsec.Combinator as C
+
+import Text.ParserCombinators.Parsec (Parser)
+
+import qualified Xmobar.Config.Types as T
+
+type Context = (T.TextRenderInfo, T.FontIndex, Maybe [T.Action])
+
+retSegment :: Context -> T.Widget -> Parser [T.Segment]
+retSegment (i, idx, as) widget = return [(widget, i, idx, as)]
+
+-- | Run the template string parser for the given config, producing a list of
+-- drawable segment specifications.
+parseString :: T.Config -> String -> [T.Segment]
+parseString c s =
+ case P.parse (stringParser ci) "" s of
+ Left _ -> [(T.Text $ "Could not parse string: " ++ s, ti, 0, Nothing)]
+ Right x -> concat x
+ where ci = (ti , 0, Nothing)
+ ti = T.TextRenderInfo (T.fgColor c) 0 0 []
+
+-- Top level parser reading the full template string
+stringParser :: Context -> Parser [[T.Segment]]
+stringParser c = C.manyTill (allParsers c) C.eof
+
+allParsers :: Context -> Parser [T.Segment]
+allParsers c = C.choice (textParser c:map (\f -> P.try (f c)) parsers)
+ where parsers = [ iconParser, hspaceParser, rawParser, actionParser
+ , fontParser, boxParser, colorParser ]
+
+-- 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
+ C.notFollowedBy $ P.try (e >> return '*')
+ return x
+
+-- Parse a maximal string without markup
+textParser :: Context -> Parser [T.Segment]
+textParser c =
+ C.many1 (P.noneOf "<" <|> P.try (notFollowedBy' (P.char '<') suffixes))
+ >>= retSegment c . T.Text
+ where suffixes = C.choice $ map (P.try . P.string)
+ [ "icon=" , "hspace=", "raw="
+ , "action=", "/action>", "fn=", "/fn>"
+ , "box", "/box>", "fc=", "/fc>" ]
+
+-- 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 :: Context -> Parser [T.Segment]
+rawParser c = do
+ P.string "<raw="
+ lenstr <- C.many1 P.digit
+ P.char ':'
+ case reads lenstr of
+ [(len,[])] -> do
+ CM.guard ((len :: Integer) <= fromIntegral (maxBound :: Int))
+ s <- C.count (fromIntegral len) P.anyChar
+ P.string "/>"
+ retSegment c (T.Text s)
+ _ -> CM.mzero
+
+iconParser :: Context -> Parser [T.Segment]
+iconParser c = do
+ P.string "<icon="
+ i <- C.manyTill (P.noneOf ">") (P.try (P.string "/>"))
+ retSegment c (T.Icon i)
+
+hspaceParser :: Context -> Parser [T.Segment]
+hspaceParser c = do
+ P.string "<hspace="
+ pVal <- C.manyTill P.digit (P.try (P.string "/>"))
+ retSegment c (T.Hspace (fromMaybe 0 $ readMaybe pVal))
+
+actionParser :: Context -> Parser [T.Segment]
+actionParser (ti, fi, act) = do
+ P.string "<action="
+ command <- C.between (P.char '`') (P.char '`') (C.many1 (P.noneOf "`"))
+ <|> C.many1 (P.noneOf ">")
+ buttons <- (P.char '>' >> return "1") <|> (P.space >> P.spaces >>
+ C.between (P.string "button=") (P.string ">") (C.many1 (P.oneOf "12345")))
+ let a = T.Spawn (toButtons buttons) command
+ a' = case act of
+ Nothing -> Just [a]
+ Just act' -> Just $ a : act'
+ s <- C.manyTill (allParsers (ti, fi, a')) (P.try $ P.string "</action>")
+ return (concat s)
+
+toButtons :: String -> [T.Button]
+toButtons = map (\x -> read [x])
+
+colorParser :: Context -> Parser [T.Segment]
+colorParser (T.TextRenderInfo _ _ _ bs, fidx, a) = do
+ c <- C.between (P.string "<fc=") (P.string ">") (C.many1 colorc)
+ let colorParts = break (==':') c
+ let (ot,ob) = case break (==',') (drop 1 $ snd colorParts) of
+ (top,',':btm) -> (top, btm)
+ (top, _) -> (top, top)
+ tri = T.TextRenderInfo (fst colorParts)
+ (fromMaybe (-1) $ readMaybe ot)
+ (fromMaybe (-1) $ readMaybe ob)
+ bs
+ s <- C.manyTill (allParsers (tri, fidx, a)) (P.try $ P.string "</fc>")
+ return (concat s)
+ where colorc = P.alphaNum <|> P.oneOf ",:#"
+
+boxParser :: Context -> Parser [T.Segment]
+boxParser (T.TextRenderInfo cs ot ob bs, f, a) = do
+ c <- C.between (P.string "<box") (P.string ">")
+ (C.option "" (C.many1 (P.alphaNum <|> P.oneOf "= #,")))
+ let b = T.Box T.BBFull (T.BoxOffset T.C 0) 1 cs (T.BoxMargins 0 0 0 0)
+ let g = boxReader b (words c)
+ s <- C.manyTill
+ (allParsers (T.TextRenderInfo cs ot ob (g : bs), f, a))
+ (P.try $ P.string "</box>")
+ return (concat s)
+
+boxReader :: T.Box -> [String] -> T.Box
+boxReader b [] = b
+boxReader b (x:xs) = boxReader (boxParamReader b param val) xs
+ where (param,val) = case break (=='=') x of
+ (p,'=':v) -> (p, v)
+ (p, _) -> (p, "")
+
+boxParamReader :: T.Box -> String -> String -> T.Box
+boxParamReader b _ "" = b
+
+boxParamReader (T.Box bb off lw fc mgs) "type" val =
+ T.Box (fromMaybe bb $ readMaybe ("BB" ++ val)) off lw fc mgs
+
+boxParamReader (T.Box bb (T.BoxOffset alg off) lw fc mgs) "offset" (a:o) =
+ T.Box bb (T.BoxOffset align offset) lw fc mgs
+ where offset = fromMaybe off $ readMaybe o
+ align = fromMaybe alg $ readMaybe [a]
+
+boxParamReader (T.Box bb off lw fc mgs) "width" val =
+ T.Box bb off (fromMaybe lw $ readMaybe val) fc mgs
+
+boxParamReader (T.Box bb off lw _ mgs) "color" val =
+ T.Box bb off lw val mgs
+
+boxParamReader (T.Box bb off lw fc mgs@(T.BoxMargins mt mr mb ml)) ('m':pos) v =
+ let mgs' = case pos of
+ "t" -> T.BoxMargins (maybeVal mt) mr mb ml
+ "r" -> T.BoxMargins mt (maybeVal mr) mb ml
+ "b" -> T.BoxMargins mt mr (maybeVal mb) ml
+ "l" -> T.BoxMargins mt mr mb (maybeVal ml)
+ _ -> mgs
+ maybeVal d = fromMaybe d (readMaybe v)
+ in T.Box bb off lw fc mgs'
+
+boxParamReader b _ _ = b
+
+fontParser :: Context -> Parser [T.Segment]
+fontParser (i, _, a) = do
+ f <- C.between (P.string "<fn=") (P.string ">") (C.many1 P.digit)
+ s <- C.manyTill (allParsers (i, fromMaybe 0 $ readMaybe f, a))
+ (P.try $ P.string "</fn>")
+ return (concat s)
diff --git a/src/Xmobar/Config/Types.hs b/src/Xmobar/Config/Types.hs
index 4959aa1..785b55b 100644
--- a/src/Xmobar/Config/Types.hs
+++ b/src/Xmobar/Config/Types.hs
@@ -15,14 +15,28 @@
module Xmobar.Config.Types
( Config (..)
, XPosition (..), Align (..), Border (..), TextOutputFormat (..)
+ , Segment
, FontIndex
+ , Box(..)
+ , BoxBorder(..)
+ , BoxOffset(..)
+ , BoxMargins(..)
+ , TextRenderInfo(..)
+ , Widget(..)
, SignalChan (..)
+ , Action (..)
+ , Button
) where
import qualified Control.Concurrent.STM as STM
import qualified Xmobar.Run.Runnable as R
import qualified Xmobar.System.Signal as S
+import Data.Int (Int32)
+import Foreign.C.Types (CInt)
+
+import Xmobar.Run.Actions (Action (..), Button)
+
-- $config
-- Configuration data type
@@ -71,20 +85,94 @@ data Config =
, template :: String -- ^ The output template
, verbose :: Bool -- ^ Emit additional debug messages
, signal :: SignalChan -- ^ Channel to send signals to xmobar
+ , dpi :: Double -- ^ DPI scaling factor for fonts
} deriving (Read, Show)
-data XPosition = Top
- | TopH Int
- | TopW Align Int
- | TopSize Align Int Int
- | TopP Int Int
+-- | The position datatype
+data XPosition = Top -- ^ Top of the screen, full width, auto height
+
+ | TopH -- ^ Top of the screen, full width with
+ -- specific height
+ Int -- ^ Height (in pixels)
+
+ -- | Top of the screen, full width with
+ -- specific height and margins
+ | TopHM
+ Int -- ^ Height (in pixels)
+ Int -- ^ Left margin (in pixels)
+ Int -- ^ Right margin (in pixels)
+ Int -- ^ Top margin (in pixels)
+ Int -- ^ Bottom margin (in pixels)
+
+ -- | Top of the screen with specific width
+ -- (as screen percentage) and alignment
+ | TopW
+ Align -- ^ Alignement (L|C|R)
+ Int -- ^ Width as screen percentage (0-100)
+
+ -- | Top of the screen with specific width
+ -- (as screen percentage), height and
+ -- alignment
+ | TopSize
+ Align -- ^ Alignement (L|C|R)
+ Int -- ^ Width as screen percentage (0-100)
+ Int -- ^ Height (in pixels)
+
+ -- | Top of the screen with specific left/right
+ -- margins
+ | TopP
+ Int -- ^ Left margin (in pixels)
+ Int -- ^ Right margin (in pixels)
+
+ -- | Bottom of the screen, full width, auto height
| Bottom
- | BottomH Int
- | BottomP Int Int
- | BottomW Align Int
- | BottomSize Align Int Int
- | Static {xpos, ypos, width, height :: Int}
- | OnScreen Int XPosition
+
+ | BottomH -- ^ Bottom of the screen, full width, with
+ -- specific height
+ Int -- ^ Height (in pixels)
+
+ -- | Bottom of the screen with specific height
+ -- and margins
+ | BottomHM
+ Int -- ^ Height (in pixels)
+ Int -- ^ Left margin (in pixels)
+ Int -- ^ Right margin (in pixels)
+ Int -- ^ Top margin (in pixels)
+ Int -- ^ Bottom margin (in pixels)
+
+ -- | Bottom of the screen with specific
+ -- left/right margins
+ | BottomP
+ Int -- ^ Left margin (in pixels)
+ Int -- ^ Bottom margin (in pixels)
+
+ -- | Bottom of the screen with specific width
+ -- (as screen percentage) and alignment
+ -- and alignment
+ | BottomW
+ Align -- ^ Alignement (L|C|R)
+ Int -- ^ Width as screen percentage (0-100)
+
+ -- | Bottom of the screen with specific width
+ -- (as screen percentage), height
+ -- and alignment
+ | BottomSize
+ Align -- ^ Alignement (L|C|R)
+ Int -- ^ Width as screen percentage (0-100)
+ Int -- ^ Height (in pixels)
+
+ -- | Static position and specific size
+ | Static { xpos :: Int -- ^ Position X (in pixels)
+ , ypos :: Int -- ^ Position Y (in pixels)
+ , width :: Int -- ^ Width (in pixels)
+ , height :: Int -- ^ Height (in pixels)
+ }
+
+ -- | Along with the position characteristics
+ -- specify the screen to display the bar
+ | OnScreen
+ Int -- ^ Screen id (primary is 0)
+ XPosition -- ^ Position
deriving ( Read, Show, Eq )
data Align = L | R | C deriving ( Read, Show, Eq )
@@ -110,3 +198,34 @@ instance Read SignalChan where
instance Show SignalChan where
show (SignalChan (Just _)) = "SignalChan (Just <tmvar>)"
show (SignalChan Nothing) = "SignalChan Nothing"
+
+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 { bBorder :: BoxBorder
+ , bOffset :: BoxOffset
+ , bWidth :: CInt
+ , bColor :: String
+ , bMargins :: BoxMargins
+ } deriving (Eq, Show)
+
+data TextRenderInfo = TextRenderInfo { tColorsString :: String
+ , tBgTopOffset :: Int32
+ , tBgBottomOffset :: Int32
+ , tBoxes :: [Box]
+ } deriving Show
+
+type Segment = (Widget, TextRenderInfo, FontIndex, Maybe [Action])
diff --git a/src/Xmobar/Draw/Boxes.hs b/src/Xmobar/Draw/Boxes.hs
index 1358805..ff55ab3 100644
--- a/src/Xmobar/Draw/Boxes.hs
+++ b/src/Xmobar/Draw/Boxes.hs
@@ -1,7 +1,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.X11.Boxes
--- Copyright: (c) 2022 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2022, 2024 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -16,7 +16,6 @@
module Xmobar.Draw.Boxes (Line, boxLines, BoxRect, borderRect) where
import qualified Xmobar.Config.Types as T
-import qualified Xmobar.Run.Parsers as P
type Line = (Double, Double, Double, Double)
type BoxRect = (Double, Double, Double, Double)
@@ -25,30 +24,29 @@ type BoxRect = (Double, Double, Double, Double)
-- The Box is to be positioned between x0 and x1, with height ht, and drawn
-- with line width lw. The returned lists are coordinates of the beginning
-- and end of each line.
-boxLines :: P.Box -> Double -> Double -> Double -> [Line]
-boxLines (P.Box bd offset lw _ margins) ht x0 x1 =
+boxLines :: T.Box -> Double -> Double -> Double -> [Line]
+boxLines (T.Box bd offset lw _ margins) ht x0 x1 =
case bd of
- P.BBTop -> [rtop]
- P.BBBottom -> [rbot]
- P.BBVBoth -> [rtop, rbot]
- P.BBLeft -> [rleft]
- P.BBRight -> [rright]
- P.BBHBoth -> [rleft, rright]
- P.BBFull -> [rtop, rbot, rleft, rright]
+ T.BBTop -> [rtop]
+ T.BBBottom -> [rbot]
+ T.BBVBoth -> [rtop, rbot]
+ T.BBLeft -> [rleft]
+ T.BBRight -> [rright]
+ T.BBHBoth -> [rleft, rright]
+ T.BBFull -> [rtop, rbot, rleft, rright]
where
- (P.BoxMargins top right bot left) = margins
- (P.BoxOffset align m) = offset
+ (T.BoxMargins top right bot left) = margins
+ (T.BoxOffset align m) = offset
ma = fromIntegral m
(p0, p1) = case align of
T.L -> (0, -ma)
T.C -> (ma, -ma)
T.R -> (ma, 0)
lc = fromIntegral lw / 2
- [mt, mr, mb, ml] = map fromIntegral [top, right, bot, left]
- xmin = x0 - ml - lc
- xmax = x1 + mr + lc
- ymin = mt + lc
- ymax = ht - mb - lc
+ xmin = x0 - fromIntegral left - lc
+ xmax = x1 + fromIntegral right + lc
+ ymin = fromIntegral top + lc
+ ymax = ht - fromIntegral bot - lc
rtop = (xmin + p0, ymin, xmax + p1, ymin)
rbot = (xmin + p0, ymax, xmax + p1, ymax)
rleft = (xmin, ymin + p0, xmin, ymax + p1)
diff --git a/src/Xmobar/Draw/Cairo.hs b/src/Xmobar/Draw/Cairo.hs
index 7e22df4..2338b10 100644
--- a/src/Xmobar/Draw/Cairo.hs
+++ b/src/Xmobar/Draw/Cairo.hs
@@ -2,7 +2,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.X11.Cairo
--- Copyright: (c) 2022 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2022, 2023, 2024 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -29,14 +29,13 @@ import Graphics.Rendering.Cairo.Types(Surface)
import qualified Xmobar.Config.Types as C
import qualified Xmobar.Config.Parse as ConfigParse
-import qualified Xmobar.Run.Parsers as P
import qualified Xmobar.Text.Pango as TextPango
import qualified Xmobar.Draw.Boxes as Boxes
import qualified Xmobar.Draw.Types as T
-type Renderinfo = (P.Segment, Surface -> Double -> Double -> IO (), Double)
-type BoundedBox = (Double, Double, [P.Box])
+type Renderinfo = (C.Segment, Surface -> Double -> Double -> IO (), Double)
+type BoundedBox = (Double, Double, [C.Box])
type Acc = (Double, T.Actions, [BoundedBox])
readColourName :: String -> (SRGB.Colour Double, Double)
@@ -63,10 +62,10 @@ renderLines color wd lns = do
mapM_ (\(x0, y0, x1, y1) ->
Cairo.moveTo x0 y0 >> Cairo.lineTo x1 y1 >> Cairo.stroke) lns
-segmentMarkup :: C.Config -> P.Segment -> String
-segmentMarkup conf (P.Text txt, info, idx, _actions) =
+segmentMarkup :: C.Config -> C.Segment -> String
+segmentMarkup conf (C.Text txt, info, idx, _actions) =
let fnt = TextPango.fixXft $ ConfigParse.indexedFont conf idx
- (fg, bg) = P.colorComponents conf (P.tColorsString info)
+ (fg, bg) = ConfigParse.colorComponents conf (C.tColorsString info)
attrs = [Pango.FontDescr fnt, Pango.FontForeground fg]
attrs' = if bg == C.bgColor conf
then attrs
@@ -74,8 +73,8 @@ segmentMarkup conf (P.Text txt, info, idx, _actions) =
in Pango.markSpan attrs' $ Pango.escapeMarkup txt
segmentMarkup _ _ = ""
-withRenderinfo :: Pango.PangoContext -> T.DrawContext -> P.Segment -> IO Renderinfo
-withRenderinfo ctx dctx seg@(P.Text _, inf, idx, a) = do
+withRenderinfo :: Pango.PangoContext -> T.DrawContext -> C.Segment -> IO Renderinfo
+withRenderinfo ctx dctx seg@(C.Text _, inf, idx, a) = do
let conf = T.dcConfig dctx
lyt <- Pango.layoutEmpty ctx
mk <- Pango.layoutSetMarkup lyt (segmentMarkup conf seg) :: IO String
@@ -88,25 +87,28 @@ withRenderinfo ctx dctx seg@(P.Text _, inf, idx, a) = do
Pango.layoutSetEllipsize lyt Pango.EllipsizeEnd
Pango.layoutSetWidth lyt (Just $ mx - off)
Cairo.renderWith s $ Cairo.moveTo off voff >> Pango.showLayout lyt
- return ((P.Text mk, inf, idx, a), slyt, wd)
+ return ((C.Text mk, inf, idx, a), slyt, wd)
-withRenderinfo _ _ seg@(P.Hspace w, _, _, _) =
+withRenderinfo _ _ seg@(C.Hspace w, _, _, _) =
return (seg, \_ _ _ -> return (), fromIntegral w)
-withRenderinfo _ dctx seg@(P.Icon p, _, _, _) = do
+withRenderinfo _ dctx seg@(C.Icon p, info, _, _) = do
let (wd, _) = T.dcIconLookup dctx p
ioff = C.iconOffset (T.dcConfig dctx)
vpos = T.dcHeight dctx / 2 + fromIntegral ioff
- render _ off mx = when (off + wd <= mx) $ T.dcIconDrawer dctx off vpos p
+ conf = T.dcConfig dctx
+ (fg, bg) = ConfigParse.colorComponents conf (C.tColorsString info)
+ render _ off mx = when (off + wd <= mx) $
+ T.dcIconDrawer dctx off vpos p fg bg
return (seg, render, wd)
-drawBox :: T.DrawContext -> Surface -> Double -> Double -> P.Box -> IO ()
-drawBox dctx surf x0 x1 box@(P.Box _ _ w color _) =
+drawBox :: T.DrawContext -> Surface -> Double -> Double -> C.Box -> IO ()
+drawBox dctx surf x0 x1 box@(C.Box _ _ w color _) =
Cairo.renderWith surf $
renderLines color (fromIntegral w) (Boxes.boxLines box (T.dcHeight dctx) x0 x1)
drawSegmentBackground ::
- T.DrawContext -> Surface -> P.TextRenderInfo -> Double -> Double -> IO ()
+ T.DrawContext -> Surface -> C.TextRenderInfo -> Double -> Double -> IO ()
drawSegmentBackground dctx surf info x0 x1 =
when (bg /= C.bgColor conf && (top >= 0 || bot >= 0)) $
Cairo.renderWith surf $ do
@@ -114,19 +116,20 @@ drawSegmentBackground dctx surf info x0 x1 =
Cairo.rectangle x0 top (x1 - x0) (T.dcHeight dctx - bot - top)
Cairo.fillPreserve
where conf = T.dcConfig dctx
- (_, bg) = P.colorComponents conf (P.tColorsString info)
- top = fromIntegral $ P.tBgTopOffset info
- bot = fromIntegral $ P.tBgBottomOffset info
+ (_, bg) = ConfigParse.colorComponents conf (C.tColorsString info)
+ top = fromIntegral $ C.tBgTopOffset info
+ bot = fromIntegral $ C.tBgBottomOffset info
drawSegment :: T.DrawContext -> Surface -> Double -> Acc -> Renderinfo -> IO Acc
drawSegment dctx surface maxoff (off, acts, boxs) (segment, render, lwidth) = do
let end = min maxoff (off + lwidth)
(_, info, _, a) = segment
acts' = case a of Just as -> (as, off, end):acts; _ -> acts
- bs = P.tBoxes info
+ bs = C.tBoxes info
boxs' = if null bs then boxs else (off, end, bs):boxs
- drawSegmentBackground dctx surface info off end
- render surface off maxoff
+ when (end > off) $ do
+ drawSegmentBackground dctx surface info off end
+ render surface off maxoff
return (off + lwidth, acts', boxs')
renderOuterBorder :: C.Config -> Double -> Double -> Cairo.Render ()
@@ -166,25 +169,27 @@ drawCairoBackground dctx surf = do
drawSegments :: T.DrawContext -> Surface -> IO T.Actions
drawSegments dctx surf = do
- let [left, center, right] = take 3 $ T.dcSegments dctx ++ repeat []
+ let segs = take 3 $ T.dcSegments dctx ++ repeat []
dh = T.dcHeight dctx
dw = T.dcWidth dctx
conf = T.dcConfig dctx
sWidth = foldl (\a (_,_,w) -> a + w) 0
ctx <- Pango.cairoCreateContext Nothing
- llyts <- mapM (withRenderinfo ctx dctx) left
- rlyts <- mapM (withRenderinfo ctx dctx) right
- clyts <- mapM (withRenderinfo ctx dctx) center
+ Pango.cairoContextSetResolution ctx $ C.dpi conf
+ llyts <- mapM (withRenderinfo ctx dctx) (head segs)
+ rlyts <- mapM (withRenderinfo ctx dctx) (segs !! 2)
+ clyts <- mapM (withRenderinfo ctx dctx) (segs !! 1)
#ifndef XRENDER
drawCairoBackground dctx surf
#endif
(lend, as, bx) <- foldM (drawSegment dctx surf dw) (0, [], []) llyts
let rw = sWidth rlyts
- rstart = max (lend + 1) (dw - rw - 1)
- cmax = rstart - 1
cw = sWidth clyts
- cstart = lend + 1 + max 0 (dw - rw - lend - cw) / 2.0
- (_, as', bx') <- foldM (drawSegment dctx surf cmax) (cstart, as, bx) clyts
+ rstart = max lend (dw - rw)
+ cstart = if lend > 1 || rw == 0 then max lend ((dw - cw) / 2.0) else lend
+ (_, as', bx') <- if cw > 0
+ then foldM (drawSegment dctx surf rstart) (cstart, as, bx) clyts
+ else return (0, as, bx)
(_, as'', bx'') <- foldM (drawSegment dctx surf dw) (rstart, as', bx') rlyts
drawBoxes dctx surf (reverse bx'')
when (C.borderWidth conf > 0) (drawBorder conf dw dh surf)
diff --git a/src/Xmobar/Draw/Types.hs b/src/Xmobar/Draw/Types.hs
index 75dd714..1a076b3 100644
--- a/src/Xmobar/Draw/Types.hs
+++ b/src/Xmobar/Draw/Types.hs
@@ -17,16 +17,15 @@
module Xmobar.Draw.Types where
-import Xmobar.Config.Types (Config)
+import Xmobar.Config.Types (Config, Segment)
import Xmobar.Run.Actions (Action)
-import Xmobar.Run.Parsers (Segment)
type Position = Double
type ActionPos = ([Action], Position, Position)
type Actions = [ActionPos]
type IconLookup = String -> (Double, Double)
-type IconDrawer = Double -> Double -> String -> IO ()
+type IconDrawer = Double -> Double -> String -> String -> String -> IO ()
data DrawContext = DC { dcIconDrawer :: IconDrawer
, dcIconLookup :: IconLookup
diff --git a/src/Xmobar/Plugins/Accordion.hs b/src/Xmobar/Plugins/Accordion.hs
new file mode 100644
index 0000000..ce15cee
--- /dev/null
+++ b/src/Xmobar/Plugins/Accordion.hs
@@ -0,0 +1,112 @@
+{-# LANGUAGE TupleSections, FlexibleContexts #-}
+{-# LANGUAGE RecordWildCards #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module : Plugins.Monitors.Accordion
+-- Copyright : (c) 2024 Enrico Maria De Angelis
+-- License : BSD-style (see LICENSE)
+--
+-- Maintainer : Enrico Maria De Angelis <enricomaria.dean6elis@gmail.com>
+-- Stability : unstable
+-- Portability : unportable
+--
+-- A plugin to group adjacent plugins and make them, as a whole, shrinkable to
+-- an alternate text upon clicking.
+--
+-----------------------------------------------------------------------------
+
+module Xmobar.Plugins.Accordion (defaultTuning, makeAccordion, makeAccordion', Tuning(..)) where
+
+import Control.Concurrent.Async (concurrently_, mapConcurrently_)
+import Control.Exception (finally)
+import Control.Monad.Extra (whenM)
+import Control.Monad (forever, join)
+import Control.Monad.IO.Class (liftIO, MonadIO)
+import Control.Monad.Reader (MonadReader, runReaderT, ask)
+import Control.Monad.State.Strict (MonadState, evalStateT, get, modify')
+import Data.IORef (atomicModifyIORef', newIORef, readIORef, IORef)
+import GHC.IO.Handle.FD (withFileBlocking)
+import System.Directory (removeFile)
+import System.IO (IOMode(ReadMode), hGetContents')
+import System.Process (readProcessWithExitCode)
+import Xmobar.Run.Exec (Exec(..), tenthSeconds)
+
+-- TODO: Ideally, I'd have just `Accordion`, and not `Tuning`, but since
+-- `Accordion` is polymorphic, I can't have a `defaultAccordion` constructor
+-- with `plugins = []`, because that leaves `a` undetermined.
+-- So I have move all non-polymorphic typed members in `Tuning`, allowing for
+-- default values at least for those members.
+data Accordion a = Accordion {
+ tuning :: Tuning
+ , plugins :: [a]
+ , shortPlugins :: [a]
+} deriving (Show, Read)
+
+makeAccordion :: Exec a => Tuning -> [a] -> Accordion a
+makeAccordion t rs = Accordion { tuning = t, plugins = rs, shortPlugins = [] }
+
+makeAccordion' :: Exec a => Tuning -> [a] -> [a] -> Accordion a
+makeAccordion' t rs rs' = Accordion { tuning = t, plugins = rs, shortPlugins = rs' }
+
+data Tuning = Tuning {
+ alias' :: String
+ , initial :: Bool
+ , expand :: String
+ , shrink :: String
+} deriving (Read, Show)
+
+defaultTuning :: Tuning
+defaultTuning = Tuning {
+ alias' = "accordion"
+ , initial = True
+ , expand = "<>"
+ , shrink = "><"
+}
+
+instance Exec a => Exec (Accordion a) where
+ alias (Accordion Tuning{..} _ _) = alias'
+ start (Accordion Tuning{..} runnables shortRunnables) cb = do
+ clicked <- newIORef False
+ (_, n, _) <- readProcessWithExitCode "uuidgen" [] ""
+ let pipe = "/tmp/accordion-" ++ removeLinebreak n
+ (_, _, _) <- readProcessWithExitCode "mkfifo" [pipe] ""
+ concurrently_ (forever $ do "" <- withFileBlocking pipe ReadMode hGetContents'
+ atomicModifyIORef' clicked (const (True, ())))
+ (do
+ strRefs <- mapM (newIORef . const "") runnables
+ strRefs' <- mapM (newIORef . const "") shortRunnables
+ let processClick = forever (do liftIO (tenthSeconds 1)
+ whenM (liftIO $ readIORef clicked)
+ (do liftIO $ clear clicked
+ modify' not)
+ get >>= loop pipe)
+ `runReaderT` (strRefs, strRefs')
+ `evalStateT` initial
+ let startRunnables = zipWith start
+ (runnables ++ shortRunnables)
+ (map writeToRef $ strRefs ++ strRefs')
+ parallel_ $ processClick:startRunnables)
+ `finally` removeFile pipe
+ where
+ loop :: (MonadIO m,
+ MonadState Bool m,
+ MonadReader ([IORef String], [IORef String]) m)
+ => String -> Bool -> m ()
+ loop pipe bool = do
+ (strRefs, strRefs') <- ask
+ text <- join <$> mapM (liftIO . readIORef) (if bool then strRefs else strRefs')
+ liftIO $ cb $ text ++ attachClick pipe (if bool then shrink else expand)
+ parallel_ = mapConcurrently_ id
+
+writeToRef :: IORef a -> a -> IO ()
+writeToRef strRef = atomicModifyIORef' strRef . const . (,())
+
+clear :: IORef Bool -> IO ()
+clear = (`atomicModifyIORef'` const (False, ()))
+
+removeLinebreak :: [a] -> [a]
+removeLinebreak = init
+
+attachClick :: String -> String -> String
+attachClick file icon = "<action=`echo -n > " ++ file ++ "`>" ++ icon ++ "</action>"
diff --git a/src/Xmobar/Plugins/EWMH.hs b/src/Xmobar/Plugins/EWMH.hs
index 94fd7d7..9b583ea 100644
--- a/src/Xmobar/Plugins/EWMH.hs
+++ b/src/Xmobar/Plugins/EWMH.hs
@@ -19,6 +19,7 @@ module Xmobar.Plugins.EWMH (EWMH(..)) where
import Control.Applicative (Applicative(..))
import Control.Monad.State
+import Control.Monad
import Control.Monad.Reader
import Graphics.X11 hiding (Modifier, Color)
import Graphics.X11.Xlib.Extras
@@ -231,7 +232,7 @@ updateClientList _ = do
where
unmanage w = asks display >>= \d -> liftIO $ selectInput d w 0
listen w = asks display >>= \d -> liftIO $ selectInput d w propertyChangeMask
- update w = mapM_ (($ w) . snd) clientHandlers
+ update w = mapM_ (`snd` w) clientHandlers
modifyClient :: Window -> (Client -> Client) -> M ()
modifyClient w f = modify (\s -> s { clients = Map.alter f' w $ clients s })
diff --git a/src/Xmobar/Plugins/Kraken.hs b/src/Xmobar/Plugins/Kraken.hs
index 2345b3d..5d565e0 100644
--- a/src/Xmobar/Plugins/Kraken.hs
+++ b/src/Xmobar/Plugins/Kraken.hs
@@ -36,7 +36,7 @@ instance Exec Kraken where
cb (display g)
loop mv g
- loop mvar (Map.fromList $ zip ps (repeat 0.0))
+ loop mvar (Map.fromList $ map (, 0.0) ps)
where
display :: Map.Map String Double -> String
diff --git a/src/Xmobar/Plugins/Locks.hs b/src/Xmobar/Plugins/Locks.hs
index 9176312..35a3f97 100644
--- a/src/Xmobar/Plugins/Locks.hs
+++ b/src/Xmobar/Plugins/Locks.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE TupleSections #-}
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Locks
@@ -16,45 +17,70 @@ module Xmobar.Plugins.Locks(Locks(..)) where
import Graphics.X11
import Data.List
+import Data.List.Extra (trim)
import Data.Bits
+import Data.Maybe (fromJust)
import Control.Monad
+import Control.Monad.Extra (ifM)
import Graphics.X11.Xlib.Extras
import Xmobar.Run.Exec
import Xmobar.System.Kbd
import Xmobar.X11.Events (nextEvent')
-data Locks = Locks
+data Locks = Locks | Locks' [(String, (String, String))]
deriving (Read, Show)
locks :: [ ( KeySym, String )]
-locks = [ ( xK_Caps_Lock, "CAPS" )
- , ( xK_Num_Lock, "NUM" )
+locks = [ ( xK_Caps_Lock, "CAPS" )
+ , ( xK_Num_Lock, "NUM" )
, ( xK_Scroll_Lock, "SCROLL" )
]
-run' :: Display -> Window -> IO String
-run' d root = do
+type Labels = [ ( String, (String, String) )]
+defaultLabels :: Labels
+defaultLabels = let nms = map snd locks
+ in zip nms (map (, mempty) nms)
+
+type LabelledLock = (KeySym, String, String, String)
+
+attach :: (KeySym, String) -> Labels -> LabelledLock
+(key, lock) `attach` lbls = let (enb, dis) = fromJust $ lookup lock lbls
+ in (key, lock, enb, dis)
+
+enabled :: (a, b, c, d) -> c
+enabled (_, _, c, _) = c
+disabled :: (a, b, c, d) -> d
+disabled (_, _, _, d) = d
+
+isEnabled :: (Bits a1, Foldable t, Foldable t1, Integral a)
+ => Display -> t (a, t1 KeyCode) -> a1 -> (KeySym, b, c, d) -> IO Bool
+isEnabled d modMap m ( ks, _, _, _ ) = do
+ kc <- keysymToKeycode d ks
+ return $ case find (elem kc . snd) modMap of
+ Nothing -> False
+ Just ( i, _ ) -> testBit m (fromIntegral i)
+
+run' :: Display -> Window -> Labels -> IO String
+run' d root labels = do
modMap <- getModifierMapping d
( _, _, _, _, _, _, _, m ) <- queryPointer d root
- ls <- filterM ( \( ks, _ ) -> do
- kc <- keysymToKeycode d ks
- return $ case find (elem kc . snd) modMap of
- Nothing -> False
- Just ( i, _ ) -> testBit m (fromIntegral i)
- ) locks
-
- return $ unwords $ map snd ls
+ ls' <- forM (map (`attach` labels) locks)
+ (\l -> ifM (isEnabled d modMap m l)
+ (return (enabled l))
+ (return (disabled l)))
+ return $ trim $ unwords ls'
instance Exec Locks where
- alias Locks = "locks"
- start Locks cb = do
+ alias _ = "locks"
+ start Locks cb = start (Locks' defaultLabels) cb
+ start (Locks' labels) cb = do
d <- openDisplay ""
root <- rootWindow d (defaultScreen d)
_ <- xkbSelectEventDetails d xkbUseCoreKbd xkbIndicatorStateNotify m m
allocaXEvent $ \ep -> forever $ do
- cb =<< run' d root
+ cb =<< run' d root labels
nextEvent' d ep
getEvent ep
diff --git a/src/Xmobar/Plugins/MarqueePipeReader.hs b/src/Xmobar/Plugins/MarqueePipeReader.hs
index 075503c..a6d590e 100644
--- a/src/Xmobar/Plugins/MarqueePipeReader.hs
+++ b/src/Xmobar/Plugins/MarqueePipeReader.hs
@@ -60,7 +60,7 @@ writer txt sep len rate chan cb = do
Nothing -> tenthSeconds rate >> writer (drop 1 txt) sep len rate chan cb
toInfTxt :: String -> String -> String
-toInfTxt line sep = concat (repeat $ line ++ " " ++ sep ++ " ")
+toInfTxt line sep = cycle (line ++ " " ++ sep ++ " ")
checkPipe :: FilePath -> IO ()
checkPipe file = handle (\(SomeException _) -> waitForPipe) $ do
diff --git a/src/Xmobar/Plugins/Monitors/Alsa.hs b/src/Xmobar/Plugins/Monitors/Alsa.hs
index dfc7329..8d02931 100644
--- a/src/Xmobar/Plugins/Monitors/Alsa.hs
+++ b/src/Xmobar/Plugins/Monitors/Alsa.hs
@@ -1,7 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.Alsa
--- Copyright : (c) 2018 Daniel Schüssler
+-- Copyright : (c) 2018, 2024 Daniel Schüssler
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Jose A. Ortega Ruiz <jao@gnu.org>
@@ -25,6 +25,7 @@ import Control.Concurrent.Async
import Control.Exception
import Control.Monad
import Data.IORef
+import Data.Maybe (fromJust)
import Data.Time.Clock
import Xmobar.Plugins.Monitors.Common
import qualified Xmobar.Plugins.Monitors.Volume as Volume;
@@ -129,7 +130,8 @@ alsaReaderThread mixerName alsaCtlPath outputCallback mvar =
{std_out = CreatePipe}
runAlsaOnce =
- withCreateProcess createProc $ \_ (Just alsaOut) _ _ -> do
+ withCreateProcess createProc $ \_ out _ _ -> do
+ let alsaOut = fromJust out
hSetBuffering alsaOut LineBuffering
tryPutMVar mvar () -- Refresh immediately after restarting alsactl
diff --git a/src/Xmobar/Plugins/Monitors/Batt/Common.hs b/src/Xmobar/Plugins/Monitors/Batt/Common.hs
index 3262b78..31caabc 100644
--- a/src/Xmobar/Plugins/Monitors/Batt/Common.hs
+++ b/src/Xmobar/Plugins/Monitors/Batt/Common.hs
@@ -1,7 +1,8 @@
+{-# LANGUAGE TypeApplications #-}
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.Batt.Common
--- Copyright : (c) 2010, 2011, 2012, 2013, 2015, 2016, 2018, 2019 Jose A Ortega
+-- Copyright : (c) 2010-2016, 2018, 2019, 2024 Jose A Ortega
-- (c) 2010 Andrea Rossato, Petr Rockai
-- License : BSD-style (see LICENSE)
--
@@ -18,7 +19,8 @@ module Xmobar.Plugins.Monitors.Batt.Common (BattOpts(..)
, Status(..)
, maybeAlert) where
-import System.Process (system)
+import System.Environment
+import System.Process (waitForProcess, withCreateProcess, shell, CreateProcess(env))
import Control.Monad (unless, void)
import Xmobar.Plugins.Monitors.Common
@@ -54,4 +56,11 @@ maybeAlert opts left =
case onLowAction opts of
Nothing -> return ()
Just x -> unless (isNaN left || actionThreshold opts < 100 * left)
- $ void $ system x
+ $ runCmd =<< mkShellCmd x
+ where
+ mkShellCmd command = do
+ selfEnv <- getEnvironment
+ pure (shell command) { env = Just $ ("XMOBAR_BATT_LEFT", show @Int $ round $ 100 * left) : selfEnv
+ }
+ runCmd c = withCreateProcess c $ \_ _ _ ph ->
+ void $ waitForProcess ph
diff --git a/src/Xmobar/Plugins/Monitors/Batt/Linux.hs b/src/Xmobar/Plugins/Monitors/Batt/Linux.hs
index 5389be0..d95b902 100644
--- a/src/Xmobar/Plugins/Monitors/Batt/Linux.hs
+++ b/src/Xmobar/Plugins/Monitors/Batt/Linux.hs
@@ -199,5 +199,5 @@ readBatteries opts bfs =
| time == 0 = Idle
| ac = Charging
| otherwise = Discharging
- unless ac (maybeAlert opts left)
+ unless (racst == Charging || racst == Idle) $ maybeAlert opts left
return $ if isNaN left then NA else Result left watts time racst
diff --git a/src/Xmobar/Plugins/Monitors/Bright.hs b/src/Xmobar/Plugins/Monitors/Bright.hs
index 12790e1..9c61fb2 100644
--- a/src/Xmobar/Plugins/Monitors/Bright.hs
+++ b/src/Xmobar/Plugins/Monitors/Bright.hs
@@ -54,11 +54,12 @@ data Files = Files { fCurr :: String
, fMax :: String
}
| NoFiles
+ deriving Show
brightFiles :: BrightOpts -> IO Files
brightFiles opts = do
is_curr <- fileExist $ fCurr files
- is_max <- fileExist $ fCurr files
+ is_max <- fileExist $ fMax files
return (if is_curr && is_max then files else NoFiles)
where prefix = sysDir </> subDir opts
files = Files { fCurr = prefix </> currBright opts
diff --git a/src/Xmobar/Plugins/Monitors/Common/Output.hs b/src/Xmobar/Plugins/Monitors/Common/Output.hs
index bd60710..c0a00ab 100644
--- a/src/Xmobar/Plugins/Monitors/Common/Output.hs
+++ b/src/Xmobar/Plugins/Monitors/Common/Output.hs
@@ -3,7 +3,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.Plugins.Monitors.Strings
--- Copyright: (c) 2018, 2019, 2020, 2022 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2019, 2020, 2022, 2024 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -88,9 +88,9 @@ pShowWithColors p f x = do
pColorizeString :: (Num a, Ord a, MonadIO m) => MonitorConfig -> a -> String -> m String
pColorizeString p x s = do
let col = pSetColor p s
- [ll,hh] = map fromIntegral $ sort [pLow p, pHigh p] -- consider high < low
- pure $ head $ [col pHighColor | x > hh ] ++
- [col pNormalColor | x > ll ] ++
+ cols = map fromIntegral $ sort [pLow p, pHigh p] -- consider high < low
+ pure $ head $ [col pHighColor | x > (cols !! 1) ] ++
+ [col pNormalColor | x > head cols ] ++
[col pLowColor | True]
pSetColor :: MonitorConfig -> String -> PSelector (Maybe String) -> String
@@ -140,7 +140,7 @@ showWithUnits d n x
padString :: Int -> Int -> String -> Bool -> String -> String -> String
padString mnw mxw pad pr ellipsis s =
let len = length s
- rmin = if mnw < 0 then 0 else mnw
+ rmin = max mnw 0
rmax = if mxw <= 0 then max len rmin else mxw
(rmn, rmx) = if rmin <= rmax then (rmin, rmax) else (rmax, rmin)
rlen = min (max rmn len) rmx
@@ -197,9 +197,9 @@ colorizeString x s = do
h <- getConfigValue high
l <- getConfigValue low
let col = setColor s
- [ll,hh] = map fromIntegral $ sort [l, h] -- consider high < low
- head $ [col highColor | x > hh ] ++
- [col normalColor | x > ll ] ++
+ cols = map fromIntegral $ sort [l, h] -- consider high < low
+ head $ [col highColor | x > cols !! 1 ] ++
+ [col normalColor | x > head cols ] ++
[col lowColor | True]
showWithColors :: (Num a, Ord a) => (a -> String) -> a -> Monitor String
@@ -260,11 +260,11 @@ logScaling f v = do
h <- fromIntegral `fmap` getConfigValue high
l <- fromIntegral `fmap` getConfigValue low
bw <- fromIntegral `fmap` getConfigValue barWidth
- let [ll, hh] = sort [l, h]
+ let ws = sort [l, h]
bw' = if bw > 0 then bw else 10
scaled x | x == 0.0 = 0
- | x <= ll = 1 / bw'
- | otherwise = f + logBase 2 (x / hh) / bw'
+ | x <= head ws = 1 / bw'
+ | otherwise = f + logBase 2 (x / ws !! 1) / bw'
return $ scaled v
showLogBar :: Float -> Float -> Monitor String
diff --git a/src/Xmobar/Plugins/Monitors/Disk.hs b/src/Xmobar/Plugins/Monitors/Disk.hs
index 47d1eac..95bcff6 100644
--- a/src/Xmobar/Plugins/Monitors/Disk.hs
+++ b/src/Xmobar/Plugins/Monitors/Disk.hs
@@ -1,7 +1,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.Disk
--- Copyright : (c) 2010, 2011, 2012, 2014, 2018, 2019 Jose A Ortega Ruiz
+-- Copyright : (c) 2010-2012, 2014, 2018, 2019, 2024 Jose A Ortega Ruiz
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>
@@ -131,10 +131,9 @@ startDiskIO disks args rate cb = do
runM args diskIOConfig (runDiskIO dref disks) rate cb
runDiskU' :: DiskUOpts -> String -> [Integer] -> Monitor String
-runDiskU' opts tmp stat = do
+runDiskU' opts tmp (total:free:diff:_) = do
setConfigValue tmp template
- let [total, free, diff] = stat
- strs = map sizeToStr [free, diff]
+ let strs = map sizeToStr [free, diff]
freep = if total > 0 then free * 100 `div` total else 0
fr = fromIntegral freep / 100
s <- zipWithM showWithColors' strs [freep, 100 - freep]
@@ -146,6 +145,7 @@ runDiskU' opts tmp stat = do
uvb <- showVerticalBar (fromIntegral $ 100 - freep) (1 - fr)
uipat <- showIconPattern (usedIconPattern opts) (1 - fr)
parseTemplate $ [sizeToStr total] ++ s ++ sp ++ [fb,fvb,fipat,ub,uvb,uipat]
+runDiskU' _ _ _ = return ""
runDiskU :: [(String, String)] -> [String] -> Monitor String
runDiskU disks argv = do
diff --git a/src/Xmobar/Plugins/Monitors/Disk/FreeBSD.hsc b/src/Xmobar/Plugins/Monitors/Disk/FreeBSD.hsc
index 296ba6c..b5530f1 100644
--- a/src/Xmobar/Plugins/Monitors/Disk/FreeBSD.hsc
+++ b/src/Xmobar/Plugins/Monitors/Disk/FreeBSD.hsc
@@ -39,7 +39,7 @@ import Xmobar.Plugins.Monitors.Disk.Common (
, Path
)
-import qualified Control.Exception.Extensible as E
+import qualified Control.Exception as E
import qualified Data.List as DL
import qualified Data.Map as DM
import qualified Data.Set as DS
diff --git a/src/Xmobar/Plugins/Monitors/MPD.hs b/src/Xmobar/Plugins/Monitors/MPD.hs
index 7ecbc0c..b091147 100644
--- a/src/Xmobar/Plugins/Monitors/MPD.hs
+++ b/src/Xmobar/Plugins/Monitors/MPD.hs
@@ -109,8 +109,9 @@ parseMPD (Right st) song opts = do
si = stateGlyph s opts
vol = int2str $ fromMaybe 0 (M.stVolume st)
(p, t) = fromMaybe (0, 0) (M.stTime st)
- [lap, len, remain] = map showTime
- [floor p, floor t, max 0 (floor t - floor p)]
+ lap = showTime $ floor p
+ len = showTime $ floor t
+ remain = showTime $ max 0 (floor t - floor p)
b = if t > 0 then realToFrac $ p / t else 0
plen = int2str $ M.stPlaylistLength st
ppos = maybe "" (int2str . (+1)) $ M.stSongPos st
diff --git a/src/Xmobar/Plugins/Monitors/Mem/Linux.hs b/src/Xmobar/Plugins/Monitors/Mem/Linux.hs
index 79dcc9d..7a81c6d 100644
--- a/src/Xmobar/Plugins/Monitors/Mem/Linux.hs
+++ b/src/Xmobar/Plugins/Monitors/Mem/Linux.hs
@@ -25,9 +25,13 @@ parseMEM =
let content = map words $ take 8 $ lines file
info = M.fromList $ map (
\line -> (head line, (read $ line !! 1 :: Float) / 1024)) content
- [total, free, buffer, cache] =
- map (info M.!) ["MemTotal:", "MemFree:", "Buffers:", "Cached:"]
- available = M.findWithDefault (free + buffer + cache) "MemAvailable:" info
+ info' x = info M.! (x ++ ":")
+ total = info' "MemTotal"
+ free = info' "MemFree"
+ buffer = info' "Buffers"
+ cache = info' "Cached"
+ available =
+ M.findWithDefault (free + buffer + cache) "MemAvailable:" info
used = total - available
usedratio = used / total
freeratio = free / total
diff --git a/src/Xmobar/Plugins/Monitors/Mpris.hs b/src/Xmobar/Plugins/Monitors/Mpris.hs
index ee30ad3..eb9595b 100644
--- a/src/Xmobar/Plugins/Monitors/Mpris.hs
+++ b/src/Xmobar/Plugins/Monitors/Mpris.hs
@@ -28,7 +28,7 @@ import qualified DBus.Client as DC
import Control.Arrow ((***))
import Data.Maybe ( fromJust )
import Data.Int ( Int32, Int64 )
-import Data.Word ( Word32 )
+import Data.Word ( Word32, Word64 )
import System.IO.Unsafe ( unsafePerformIO )
import Control.Exception (try)
@@ -136,17 +136,17 @@ makeList version md = map getStr (fieldsList version) where
"xesam:trackNumber" -> printf "%02d" num
_ -> (show::Int32 -> String) num
pw32 v = printf "%02d" (fromVar v::Word32)
- plen str v = let num = fromVar v in
- case str of
+ plen str num = case str of
"mpris:length" -> formatTime (num `div` 1000000)
- _ -> (show::Int64 -> String) num
+ _ -> show num
getStr str = case lookup str md of
Nothing -> ""
Just v -> case variantType v of
TypeString -> fromVar v
TypeInt32 -> pInt str v
TypeWord32 -> pw32 v
- TypeInt64 -> plen str v
+ TypeWord64 -> plen str (fromVar v :: Word64)
+ TypeInt64 -> plen str (fromVar v :: Int64)
TypeArray TypeString ->
let x = arrayItems (fromVar v) in
if null x then "" else fromVar (head x)
diff --git a/src/Xmobar/Plugins/Monitors/Net/Linux.hs b/src/Xmobar/Plugins/Monitors/Net/Linux.hs
index 9306497..f9cbc28 100644
--- a/src/Xmobar/Plugins/Monitors/Net/Linux.hs
+++ b/src/Xmobar/Plugins/Monitors/Net/Linux.hs
@@ -47,7 +47,10 @@ isUp d = flip catchIOError (const $ return False) $ do
return $! (head . B.lines) operstate `elem` ["up", "unknown"]
readNetDev :: [String] -> IO NetDevRawTotal
-readNetDev ~[d, x, y] = do
+readNetDev ds = do
+ let (d, x, y) = case ds of
+ d':x':y':_ -> (d', x', y')
+ _ -> ("", "", "")
up <- unsafeInterleaveIO $ isUp d
return $ N d (if up then ND (r x) (r y) else NI)
where r s | s == "" = 0
diff --git a/src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc b/src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc
index 9c74e36..90c58c1 100644
--- a/src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc
+++ b/src/Xmobar/Plugins/Monitors/Swap/FreeBSD.hsc
@@ -71,11 +71,10 @@ instance Storable SwapData where
poke _ _ = pure ()
-
isEnabled :: IO Bool
isEnabled = do
- enabled <- sysctlReadUInt "vm.swap_enabled"
- return $ enabled == 1
+ nswapdev <- sysctlReadUInt "vm.nswapdev"
+ return $ nswapdev > 0
parseMEM' :: Bool -> IO [Float]
parseMEM' False = return []
diff --git a/src/Xmobar/Plugins/Monitors/Top.hs b/src/Xmobar/Plugins/Monitors/Top.hs
index 3bfe6fd..b2e573b 100644
--- a/src/Xmobar/Plugins/Monitors/Top.hs
+++ b/src/Xmobar/Plugins/Monitors/Top.hs
@@ -3,7 +3,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : Plugins.Monitors.Top
--- Copyright : (c) 2010, 2011, 2012, 2013, 2014, 2018, 2022 Jose A Ortega Ruiz
+-- Copyright : (c) 2010-2014, 2018, 2022, 2025 Jose A Ortega Ruiz
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Jose A Ortega Ruiz <jao@gnu.org>
@@ -20,7 +20,7 @@ import Xmobar.Plugins.Monitors.Common
import Data.IORef (newIORef, readIORef, writeIORef)
import Data.List (sortBy)
-import Data.Ord (comparing)
+import Data.Ord (comparing, Down (..))
import Data.Time.Clock (getCurrentTime, diffUTCTime)
import Xmobar.Plugins.Monitors.Top.Common (
@@ -66,7 +66,7 @@ showInfo nm sms mms = do
sortTop :: [(String, Float)] -> [(String, Float)]
-sortTop = sortBy (flip (comparing snd))
+sortTop = sortBy (comparing (Down . snd))
showMemInfo :: Float -> MemInfo -> Monitor [String]
showMemInfo scale (nm, rss) =
diff --git a/src/Xmobar/Plugins/Monitors/Weather.hs b/src/Xmobar/Plugins/Monitors/Weather.hs
index e71de10..6b5c353 100644
--- a/src/Xmobar/Plugins/Monitors/Weather.hs
+++ b/src/Xmobar/Plugins/Monitors/Weather.hs
@@ -66,6 +66,7 @@ weatherConfig = mkMConfig
, "skyCondition"
, "skyConditionS"
, "weather"
+ , "weatherS"
, "tempC"
, "tempF"
, "dewPointC"
@@ -221,23 +222,23 @@ getData station = CE.catch
errHandler :: CE.SomeException -> IO String
errHandler _ = return "<Could not retrieve data>"
-formatSk :: Eq p => [(p, p)] -> p -> p
-formatSk ((a,b):sks) sk = if a == sk then b else formatSk sks sk
-formatSk [] sk = sk
-
formatWeather
:: WeatherOpts -- ^ Formatting options from the cfg file
-> [(String,String)] -- ^ 'SkyConditionS' for 'WeatherX'
-> [WeatherInfo] -- ^ The actual weather info
-> Monitor String
-formatWeather opts sks [WI st ss y m d h (WindInfo wc wa wm wk wkh wms) v sk we tC tF dC dF r p] =
- do cel <- showWithColors show tC
+formatWeather opts sks [WI st ss y m d h wind v sk we tC tF dC dF r p] =
+ do let WindInfo wc wa wm wk wkh wms = wind
+ cel <- showWithColors show tC
far <- showWithColors show tF
- let sk' = formatSk sks (map toLower sk)
- we' = showWeather (weatherString opts) we
+ let we' = showWeather (weatherString opts) we
+ sk' = findSk sks (map toLower sk) we'
+ we'' = findSk sks (map toLower we') sk'
parseTemplate [st, ss, y, m, d, h, wc, wa, wm, wk, wkh
- , wms, v, sk, sk', we', cel, far
+ , wms, v, sk, sk', we', we'', cel, far
, show dC, show dF, show r , show p ]
+ where findSk ((a,b):xs) x df = if a == x then b else findSk xs x df
+ findSk [] _ df = df
formatWeather _ _ _ = getConfigValue naString
-- | Show the 'weather' field with a default string in case it was empty.
diff --git a/src/Xmobar/Plugins/PacmanUpdates.hs b/src/Xmobar/Plugins/PacmanUpdates.hs
new file mode 100644
index 0000000..ea14454
--- /dev/null
+++ b/src/Xmobar/Plugins/PacmanUpdates.hs
@@ -0,0 +1,165 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilyDependencies #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ViewPatterns #-}
+
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+
+{- |
+Module : Plugins.Monitors.PacmanUpdates
+Copyright : (c) 2024, 2026 Enrico Maria De Angelis
+ , (c) 2025 Alexander Pankoff
+ , (c) 2026 Enrico Maria De Angelis
+License : BSD-style (see LICENSE)
+
+Maintainer : Enrico Maria De Angelis <enricomaria.dean6elis@gmail.com>
+Stability : unstable
+Portability : unportable
+
+A Pacman updates availablility plugin for Xmobar. It also informs whether a kernel update is
+available (provided the name of the kernel package), and whether the running kernel is older
+than the installed one.
+-}
+module Xmobar.Plugins.PacmanUpdates (
+#if __GLASGOW_HASKELL__ >= 908
+ {-# DEPRECATED "This ctor is DEPRECATED; please use `PacmanUpdates` type and `PacmanUpdatesK`, `PacmanUpdatesPredicateK` and `PacmanUpdatesNoK` constructors instead." #-}
+#endif
+ pattern PacmanUpdates
+ , PacmanUpdates ()
+ , PacmanUpdatesKernelCheck (..)
+ , pattern PacmanUpdatesK
+ , pattern PacmanUpdatesPredicateK
+ , pattern PacmanUpdatesNoK) where
+
+import System.Exit (ExitCode (..))
+import System.Process (readProcessWithExitCode)
+import Xmobar.Plugins.Command (Rate)
+import Xmobar.Run.Exec
+import Data.Tuple.Extra (fst3)
+import Data.Kind (Type)
+import Data.Functor ((<&>))
+import Data.Void (Void)
+import Control.Arrow ((&&&))
+import qualified Data.Vector as V
+
+-- | Deprecated plugin ctor (will be deleted in 2027).
+-- Use `PacmanUpdatesK`, `PacmanUpdatesPredicateK`, or `PacmanUpdatesNoK` instead.
+pattern PacmanUpdates :: (String, String, String, String) -- ^ `String`s to be shown for 0, 1, ≥ 2 updates,
+ -- and for error respectively (in the 3rd string, for
+ -- ≥ 2 updates, any occurrence of the '?' character
+ -- is a placeholder for the number of available updates).
+ -> Rate -- ^ `Rate` of update (see [Xmobar doc](https://codeberg.org/xmobar/xmobar/src/commit/39fd70308c3aef5402abe7152ade76ff7bb331bb/src/Xmobar/Plugins/Command.hs#L34)).
+ -> PacmanUpdates NoKernelCheck
+pattern PacmanUpdates irrelevant <- (error "PacmanUpdates: PacmanUpdates is a build-only pattern synonym (a ctor synonym)." -> irrelevant)
+ where PacmanUpdates zome r
+ = let (z, o, m, e) = zome
+ printer = const
+ $ (++ deprecationNote)
+ . \case Left _ -> e
+ Right 0 -> z
+ Right 1 -> o
+ Right n -> m >>= \c -> if c == '?'
+ then show n
+ else pure c
+ deprecationNote = " <fc=#ff0000>(<action=`xdg-open https://codeberg.org/xmobar/xmobar/pulls/765`>"
+ ++ "deprecated plugin, click here</action>)</fc>"
+ in PacmanUpdatesNoK r printer
+
+
+-- | Different types of kernel checks.
+data PacmanUpdatesKernelCheck = NoKernelCheck | PredicateKernelCheck
+
+-- | PacmanUpdates plugin parametrized over the `PacmanUpdatesKernelCheck` kind.
+data PacmanUpdates (b :: PacmanUpdatesKernelCheck)
+ = Make -- ^ Constructor.
+ Rate -- ^ `Rate` of update (see [Xmobar doc](https://codeberg.org/xmobar/xmobar/src/commit/39fd70308c3aef5402abe7152ade76ff7bb331bb/src/Xmobar/Plugins/Command.hs#L34)).
+ (Arg b) -- ^ Optional further argument. See instances of `Updates`.
+ (Printer b) -- ^ Printer. See instances of `Updates` for its signature.
+
+instance Show (PacmanUpdates b) where
+ show = error "PacmanUpdates: Show instance is stub"
+
+instance Read (PacmanUpdates b) where
+ readsPrec = error "PacmanUpdates: Read instance is stub"
+
+instance Updates b => Exec (PacmanUpdates (b :: PacmanUpdatesKernelCheck)) where
+ alias = const "pacman"
+ rate (Make r _ _) = r
+ run = Xmobar.Plugins.PacmanUpdates.run'
+
+class Updates (b :: PacmanUpdatesKernelCheck) where
+ -- | See `Updates`'s instances.
+ type Arg b = (a :: Type) | a -> b
+ -- | See `Updates`'s instances.
+ type Printer b = (p :: Type) | p -> b
+ -- | This is the implementation of `Xmobar.Run.Exec.run`.
+ run' :: PacmanUpdates b -> IO String
+
+-- | No additional argument required for constructing the plugin;
+-- the user-provided printer is fed with a `Bool` telling whether
+-- the system is running an outdated kernel, and an `Int` telling
+-- the number of available updates (or `Left` if an error occurred
+-- when calling `checkupdates`).
+instance Updates NoKernelCheck where
+ type Arg NoKernelCheck = Void
+ type Printer NoKernelCheck = Bool -> Either String Int -> String
+ run' (Make _ _ printer)
+ = printer
+ <$> kernIsOld
+ <*> (fmap V.length <$> checkUpdates)
+
+-- | Constructing the plugin requires an additional `String -> Bool` predicate
+-- that receives each available package name and returns `True` for kernel
+-- packages; the user-provided printer is fed with a `Bool` telling whether the
+-- system is running an outdated kernel, and an `(Int, Bool)` pair telling the
+-- number of available updates and whether one of these is a kernel update (or
+-- `Left` if an error occurred when calling `checkupdates`).
+instance Updates PredicateKernelCheck where
+ type Arg PredicateKernelCheck = String -> Bool
+ type Printer PredicateKernelCheck = Bool -> Either String (Int, Bool) -> String
+ run' (Make _ checkKern printer)
+ = printer
+ <$> kernIsOld
+ <*> (fmap (V.length &&& V.any checkKern) <$> checkUpdates)
+
+-- | Pattern synonym to construct a `PacmanUpdates PredicateKernelCheck` that
+-- detects updates for packages matched by the given @(String -> Bool)@
+-- predicate. This can be used to detect kernel updates for distributions
+-- with versioned kernel package names (e.g. Manjaro's @linux618@)
+pattern PacmanUpdatesPredicateK :: Rate -> Arg PredicateKernelCheck -> Printer PredicateKernelCheck -> PacmanUpdates PredicateKernelCheck
+pattern PacmanUpdatesPredicateK r a p = Make r a p
+
+-- | A convenience wrapper around PacmanUpdatesPredicateK with the predicate @(== kernName)@
+-- Construction only: the kernel name cannot be recovered when matching.
+pattern PacmanUpdatesK :: Rate -> String -> Printer PredicateKernelCheck -> PacmanUpdates PredicateKernelCheck
+pattern PacmanUpdatesK r kernName p <-
+ (error "PacmanUpdatesK: build-only pattern synonym (a ctor synonym)." -> (r, kernName, p))
+ where PacmanUpdatesK r kernName p = PacmanUpdatesPredicateK r (== kernName) p
+
+-- | Pattern synonym used to construct a `PacmanUpdates NoKernelCheck`.
+pattern PacmanUpdatesNoK :: Rate -> Printer NoKernelCheck -> PacmanUpdates NoKernelCheck
+pattern PacmanUpdatesNoK r p <- Make r _ p
+ where PacmanUpdatesNoK r p = Make r undefined p
+
+checkUpdates :: IO (Either String (V.Vector String))
+checkUpdates = readProcessWithExitCode "checkupdates" [] ""
+ <&> \case (ExitFailure 2, "", "") -> Right V.empty
+ (ExitSuccess, stdout, "")
+ -> let pkgName = takeWhile (/= ' ')
+ pkgs = V.fromList $ fmap pkgName $ lines stdout
+ in case V.length pkgs of
+ 0 -> impossible
+ _ -> Right pkgs
+ (ExitFailure 1, _, _) -> Left "checkupdates: unknown cause of failure."
+ _ -> impossible
+
+kernIsOld :: IO Bool
+kernIsOld = (/= ExitSuccess) . exitCode <$> readProcessWithExitCode "modinfo" ["-n", "i915"] ""
+ where exitCode = fst3
+
+impossible :: a
+impossible = error "This is impossible, according to my knowledge."
diff --git a/src/Xmobar/Run/Actions.hs b/src/Xmobar/Run/Actions.hs
index 2a49312..a9afed9 100644
--- a/src/Xmobar/Run/Actions.hs
+++ b/src/Xmobar/Run/Actions.hs
@@ -16,7 +16,7 @@ module Xmobar.Run.Actions ( Button
, runAction'
, stripActions) where
-import System.Process (system)
+import System.Process (shell, withCreateProcess, waitForProcess)
import Control.Monad (void)
import Text.Regex (Regex, subRegex, mkRegex, matchRegex)
import Data.Word (Word32)
@@ -26,11 +26,12 @@ type Button = Word32
data Action = Spawn [Button] String deriving (Eq, Read, Show)
runAction :: Action -> IO ()
-runAction (Spawn _ s) = void $ system (s ++ "&")
+runAction (Spawn _ s) = withCreateProcess (shell s) $ \_ _ _ ph ->
+ void $ waitForProcess ph
-- | Run action with stdout redirected to stderr
runAction' :: Action -> IO ()
-runAction' (Spawn _ s) = void $ system (s ++ " 1>&2 &")
+runAction' (Spawn btn s) = runAction (Spawn btn (s ++ " 1>&2"))
stripActions :: String -> String
stripActions s = case matchRegex actionRegex s of
diff --git a/src/Xmobar/Run/Loop.hs b/src/Xmobar/Run/Loop.hs
index bda41ff..6775961 100644
--- a/src/Xmobar/Run/Loop.hs
+++ b/src/Xmobar/Run/Loop.hs
@@ -57,7 +57,7 @@ type LoopFunction = TMVar SignalType -> TVar [String] -> IO ()
loop :: Config -> LoopFunction -> IO ()
loop conf looper = withDeferSignals $ do
- cls <- mapM (parseTemplate (commands conf) (sepChar conf))
+ let cls = map (parseTemplate (commands conf) (sepChar conf))
(splitTemplate (alignSep conf) (template conf))
let confSig = unSignalChan (signal conf)
sig <- maybe newEmptyTMVarIO pure confSig
diff --git a/src/Xmobar/Run/Parsers.hs b/src/Xmobar/Run/Parsers.hs
deleted file mode 100644
index 9b36786..0000000
--- a/src/Xmobar/Run/Parsers.hs
+++ /dev/null
@@ -1,244 +0,0 @@
-{-# 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 { bBorder :: BoxBorder
- , bOffset :: BoxOffset
- , bWidth :: CInt
- , bColor :: String
- , bMargins :: BoxMargins
- } deriving (Eq, Show)
-
-data TextRenderInfo = TextRenderInfo { tColorsString :: String
- , tBgTopOffset :: Int32
- , tBgBottomOffset :: Int32
- , tBoxes :: [Box]
- } deriving Show
-
-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) fidx 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)
- tri = TextRenderInfo (fst colorParts)
- (fromMaybe (-1) $ readMaybe ot)
- (fromMaybe (-1) $ readMaybe ob)
- bs
- s <- manyTill (allParsers tri fidx 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 align offset) lw fc mgs
- where offset = fromMaybe off $ readMaybe o
- align = fromMaybe alg $ readMaybe [a]
-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 '#')
diff --git a/src/Xmobar/Run/Template.hs b/src/Xmobar/Run/Template.hs
index 87c84d3..0e066dc 100644
--- a/src/Xmobar/Run/Template.hs
+++ b/src/Xmobar/Run/Template.hs
@@ -50,21 +50,20 @@ templateParser s = many $ templateStringParser s
-- | Actually runs the template parsers over a (segment of) a template
-- string, returning a list of runnables with their prefix and suffix.
-parseTemplate :: [Runnable] -> String -> String -> IO [(Runnable,String,String)]
+parseTemplate :: [Runnable] -> String -> String -> [(Runnable,String,String)]
parseTemplate c sepChar s =
- do str <- case parse (templateParser sepChar) "" s of
- Left _ -> return [("", s, "")]
- Right x -> return x
- let cl = map alias c
- m = Map.fromList $ zip cl c
- return $ combine c m str
+ let str = case parse (templateParser sepChar) "" s of
+ Left _ -> [("", s, "")]
+ Right x -> x
+ cl = map alias c
+ m = Map.fromList $ zip cl c
+ in combine m str
-- | Given a finite "Map" and a parsed template produce the resulting
-- output string.
-combine :: [Runnable] -> Map.Map String Runnable -> [(String, String, String)]
- -> [(Runnable,String,String)]
-combine _ _ [] = []
-combine c m ((ts,s,ss):xs) = (com, s, ss) : combine c m xs
+combine :: Map.Map String Runnable -> [(String, String, String)] -> [(Runnable,String,String)]
+combine _ [] = []
+combine m ((ts,s,ss):xs) = (com, s, ss) : combine m xs
where com = Map.findWithDefault dflt ts m
dflt = Run $ Com ts [] [] 10
@@ -77,5 +76,6 @@ splitTemplate alignSep template =
(ce,_:ri) -> [le, ce, ri]
_ -> def
_ -> def
- where [l, r] = if length alignSep == 2 then alignSep else defaultAlign
+ where sep = if length alignSep == 2 then alignSep else defaultAlign
+ (l, r) = (head sep, sep !! 1)
def = [template, "", ""]
diff --git a/src/Xmobar/Run/Types.hs b/src/Xmobar/Run/Types.hs
index 69406bb..8b9caa4 100644
--- a/src/Xmobar/Run/Types.hs
+++ b/src/Xmobar/Run/Types.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE TypeOperators, CPP #-}
+{-# LANGUAGE DataKinds #-}
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.Run.Types
@@ -19,6 +20,7 @@
module Xmobar.Run.Types(runnableTypes) where
import {-# SOURCE #-} Xmobar.Run.Runnable()
+import Xmobar.Plugins.PacmanUpdates
import Xmobar.Plugins.Command
import Xmobar.Plugins.Monitors
import Xmobar.Plugins.Date
diff --git a/src/Xmobar/System/DBus.hs b/src/Xmobar/System/DBus.hs
index 103a5a9..90bee2a 100644
--- a/src/Xmobar/System/DBus.hs
+++ b/src/Xmobar/System/DBus.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : DBus
@@ -17,9 +18,10 @@ module Xmobar.System.DBus (runIPC) where
import DBus
import DBus.Client hiding (interfaceName)
import qualified DBus.Client as DC
+import DBus.Socket
import Data.Maybe (isNothing)
import Control.Concurrent.STM
-import Control.Exception (handle)
+import Control.Exception
import System.IO (stderr, hPutStrLn)
import Control.Monad.IO.Class (liftIO)
@@ -35,10 +37,10 @@ interfaceName :: InterfaceName
interfaceName = interfaceName_ "org.Xmobar.Control"
runIPC :: TMVar SignalType -> IO ()
-runIPC mvst = handle printException exportConnection
+runIPC mvst = exportConnection `catches` [
+ Handler(\ (ex :: ClientError) -> hPutStrLn stderr (clientErrorMessage ex)),
+ Handler(\ (ex :: SocketError) -> hPutStrLn stderr (socketErrorMessage ex))]
where
- printException :: ClientError -> IO ()
- printException = hPutStrLn stderr . clientErrorMessage
exportConnection = do
client <- connectSession
requestName client busName [ nameDoNotQueue ]
diff --git a/src/Xmobar/System/Environment.hs b/src/Xmobar/System/Environment.hs
index 25802fe..0491bcc 100644
--- a/src/Xmobar/System/Environment.hs
+++ b/src/Xmobar/System/Environment.hs
@@ -13,14 +13,14 @@
-----------------------------------------------------------------------------
module Xmobar.System.Environment(expandEnv) where
-import Data.Maybe (fromMaybe)
-import System.Environment (lookupEnv)
+import qualified Data.Maybe as M
+import qualified System.Environment as E
expandEnv :: String -> IO String
expandEnv "" = return ""
expandEnv (c:s) = case c of
'$' -> do
- envVar <- fromMaybe "" <$> lookupEnv e
+ envVar <- M.fromMaybe "" <$> E.lookupEnv e
remainder <- expandEnv s'
return $ envVar ++ remainder
where (e, s') = getVar s
@@ -36,12 +36,13 @@ expandEnv (c:s) = case c of
False -> do
remainder <- expandEnv $ drop 1 s
return $ escString s ++ remainder
- where escString s' = let (cc:_) = s' in
+ where escString (cc:_) =
case cc of
't' -> "\t"
'n' -> "\n"
'$' -> "$"
_ -> [cc]
+ escString [] = ""
_ -> do
remainder <- expandEnv s
diff --git a/src/Xmobar/Text/Loop.hs b/src/Xmobar/Text/Loop.hs
index 05379cd..5d2c43f 100644
--- a/src/Xmobar/Text/Loop.hs
+++ b/src/Xmobar/Text/Loop.hs
@@ -45,4 +45,4 @@ eventLoop cfg signal tv = do
updateString :: Config -> TVar [String] -> IO String
updateString conf v = do
s <- readTVarIO v
- format conf (concat s)
+ return $ format conf (concat s)
diff --git a/src/Xmobar/Text/Output.hs b/src/Xmobar/Text/Output.hs
index 783a5bb..677b6d2 100644
--- a/src/Xmobar/Text/Output.hs
+++ b/src/Xmobar/Text/Output.hs
@@ -15,13 +15,15 @@
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.Config.Types ( Config (..)
+ , TextOutputFormat (..)
+ , Segment
+ , Widget (..)
+ , tColorsString)
+
+
+import Xmobar.Config.Parse (colorComponents)
+import Xmobar.Config.Template (parseString)
import Xmobar.Text.Ansi (withAnsiColor)
import Xmobar.Text.Pango (withPangoMarkup)
@@ -47,9 +49,9 @@ formatWithColor conf (Hspace n, i, x, y) =
formatWithColor conf (Text $ replicate (fromIntegral n) ' ', i, x, y)
formatWithColor _ _ = ""
-format :: Config -> String -> IO String
+format :: Config -> String -> String
format conf s = do
- segments <- parseString conf s
+ let segments = parseString conf s
case textOutputFormat conf of
- Swaybar -> return $ formatSwaybar conf segments
- _ -> return (concatMap (formatWithColor conf) segments)
+ Swaybar -> formatSwaybar conf segments
+ _ -> concatMap (formatWithColor conf) segments
diff --git a/src/Xmobar/Text/Swaybar.hs b/src/Xmobar/Text/Swaybar.hs
index a2fc585..355de06 100644
--- a/src/Xmobar/Text/Swaybar.hs
+++ b/src/Xmobar/Text/Swaybar.hs
@@ -24,16 +24,16 @@ 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.Config.Types ( Config (additionalFonts)
+ , Segment
+ , Widget(..)
+ , Box(..)
+ , BoxBorder(..)
+ , FontIndex
+ , tBoxes
+ , tColorsString)
+
+import Xmobar.Config.Parse (colorComponents)
import Xmobar.Text.SwaybarClicks (startHandler)
import Xmobar.Text.Pango (withPangoFont)
diff --git a/src/Xmobar/X11/Bitmap.hs b/src/Xmobar/X11/Bitmap.hs
index b14356f..c5304d9 100644
--- a/src/Xmobar/X11/Bitmap.hs
+++ b/src/Xmobar/X11/Bitmap.hs
@@ -2,7 +2,7 @@
-----------------------------------------------------------------------------
-- |
-- Module : X11.Bitmap
--- Copyright : (C) 2013, 2015, 2017, 2018, 2022 Alexander Polakov
+-- Copyright : (C) 2013, 2015, 2017, 2018, 2022, 2024 Alexander Polakov
-- License : BSD3
--
-- Maintainer : jao@gnu.org
@@ -116,8 +116,9 @@ loadBitmap d w p = do
drawBitmap :: Display -> Drawable -> GC -> String -> String
-> Position -> Position -> Bitmap -> IO ()
drawBitmap d p gc fc bc x y i =
- withColors d [fc, bc] $ \[fc', bc'] -> do
- let w = width i
+ withColors d [fc, bc] $ \cs -> do
+ let (fc', bc') = (head cs, cs !! 1)
+ w = width i
h = height i
y' = 1 + y - fromIntegral h `div` 2
setForeground d gc fc'
diff --git a/src/Xmobar/X11/Draw.hs b/src/Xmobar/X11/Draw.hs
index a056136..a1ec901 100644
--- a/src/Xmobar/X11/Draw.hs
+++ b/src/Xmobar/X11/Draw.hs
@@ -25,7 +25,6 @@ import Foreign.C.Types as FT
import qualified Graphics.X11.Xlib as X11
import qualified Xmobar.Config.Types as C
-import qualified Xmobar.Run.Parsers as P
import qualified Xmobar.Draw.Types as D
import qualified Xmobar.Draw.Cairo as DC
@@ -38,11 +37,8 @@ import qualified Xmobar.X11.XRender as XRender
#endif
drawXBitmap :: T.XConf -> X11.GC -> X11.Pixmap -> D.IconDrawer
-drawXBitmap xconf gc p h v path = do
+drawXBitmap xconf gc p h v path fc bc = do
let disp = T.display xconf
- conf = T.config xconf
- fc = C.fgColor conf
- bc = C.bgColor conf
case M.lookup path (T.iconCache xconf) of
Just bm -> liftIO $ B.drawBitmap disp p gc fc bc (round h) (round v) bm
Nothing -> return ()
@@ -69,7 +65,7 @@ withPixmap disp win (X11.Rectangle _ _ w h) depth action = do
X11.sync disp True
return res
-draw :: [[P.Segment]] -> T.X [D.ActionPos]
+draw :: [[C.Segment]] -> T.X [D.ActionPos]
draw segments = do
xconf <- ask
let disp = T.display xconf
@@ -89,7 +85,7 @@ draw segments = do
#ifdef XRENDER
color = C.bgColor conf
alph = C.alpha conf
- XRender.drawBackground disp p color alph (X11.Rectangle 0 0 w h)
+ XRender.drawBackground disp p color alph rect
#endif
CS.withXlibSurface disp p vis (fromIntegral w) (fromIntegral h) render
diff --git a/src/Xmobar/X11/Events.hs b/src/Xmobar/X11/Events.hs
index 4334f6b..fbd2bd0 100644
--- a/src/Xmobar/X11/Events.hs
+++ b/src/Xmobar/X11/Events.hs
@@ -1,7 +1,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.X11.Events
--- Copyright: (c) 2018 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2022 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -17,20 +17,19 @@
module Xmobar.X11.Events(nextEvent') where
-import Control.Concurrent
-import System.Posix.Types (Fd(..))
+import qualified Control.Concurrent as C
+import qualified System.Posix.Types as T
-import Graphics.X11.Xlib (
- Display(..), XEventPtr, nextEvent, pending, connectionNumber)
+import qualified Graphics.X11.Xlib as X
-- | A version of nextEvent that does not block in foreign calls.
-nextEvent' :: Display -> XEventPtr -> IO ()
+nextEvent' :: X.Display -> X.XEventPtr -> IO ()
nextEvent' d p = do
- pend <- pending d
+ pend <- X.pending d
if pend /= 0
- then nextEvent d p
+ then X.nextEvent d p
else do
- threadWaitRead (Fd fd)
+ C.threadWaitRead (T.Fd fd)
nextEvent' d p
where
- fd = connectionNumber d
+ fd = X.connectionNumber d
diff --git a/src/Xmobar/X11/Loop.hs b/src/Xmobar/X11/Loop.hs
index 599e680..0425cff 100644
--- a/src/Xmobar/X11/Loop.hs
+++ b/src/Xmobar/X11/Loop.hs
@@ -3,7 +3,7 @@
------------------------------------------------------------------------------
-- |
-- Module: Xmobar.App.X11EventLoop
--- Copyright: (c) 2018, 2020, 2022 Jose Antonio Ortega Ruiz
+-- Copyright: (c) 2018, 2020, 2022, 2023, 2024 Jose Antonio Ortega Ruiz
-- License: BSD3-style (see LICENSE)
--
-- Maintainer: jao@gnu.org
@@ -22,6 +22,7 @@ import Prelude hiding (lookup)
import Control.Concurrent as Concurrent
import Control.Concurrent.STM as STM
+import Control.Monad as MR
import Control.Monad.Reader as MR
import Data.Bits (Bits((.|.)))
@@ -35,10 +36,10 @@ import qualified Graphics.X11.Xinerama as Xinerama
import qualified Graphics.X11.Xrandr as Xrandr
import qualified Xmobar.Config.Types as C
+import qualified Xmobar.Config.Template as CT
import qualified Xmobar.Run.Actions as A
import qualified Xmobar.Run.Loop as L
-import qualified Xmobar.Run.Parsers as P
import qualified Xmobar.System.Utils as U
import qualified Xmobar.System.Signal as S
@@ -145,15 +146,14 @@ signalLoop xc@(T.XConf d r w fs is cfg) actions signalv strs = do
r' <- W.repositionWin d w (NE.head fs) rcfg
signalLoop (T.XConf d r' w fs is rcfg) actions signalv strs
-parseSegments :: C.Config -> STM.TVar [String] -> IO [[P.Segment]]
+parseSegments :: C.Config -> STM.TVar [String] -> IO [[C.Segment]]
parseSegments conf v = do
s <- STM.readTVarIO v
- let l:c:r:_ = s ++ repeat ""
- MR.liftIO $ mapM (P.parseString conf) [l, c, r]
+ return $ map (CT.parseString conf) (take 3 $ s ++ repeat "")
-updateIconCache :: T.XConf -> [[P.Segment]] -> IO T.XConf
+updateIconCache :: T.XConf -> [[C.Segment]] -> IO T.XConf
updateIconCache xc@(T.XConf d _ w _ c cfg) segs = do
- let paths = [p | (P.Icon p, _, _, _) <- concat segs]
+ let paths = [p | (C.Icon p, _, _, _) <- concat segs]
c' <- Bitmap.updateCache d w c (C.iconRoot cfg) paths
return $ xc {T.iconCache = c'}
@@ -170,7 +170,7 @@ updateConfigPosition disp cfg =
runActions :: D.Actions -> A.Button -> X11.Position -> IO ()
runActions actions button pos =
mapM_ A.runAction $
- filter (\(A.Spawn b _) -> button `elem` b) $
- concatMap (\(a,_,_) -> a) $
- filter (\(_, from, to) -> pos' >= from && pos' <= to) actions
+ concatMap
+ (filter (\ (A.Spawn b _) -> button `elem` b) . (\ (a, _, _) -> a))
+ (filter (\ (_, from, to) -> pos' >= from && pos' <= to) actions)
where pos' = fromIntegral pos
diff --git a/src/Xmobar/X11/Window.hs b/src/Xmobar/X11/Window.hs
index ad7ebf7..87d56f4 100644
--- a/src/Xmobar/X11/Window.hs
+++ b/src/Xmobar/X11/Window.hs
@@ -86,10 +86,14 @@ setPosition c p rs ht =
T.Top -> X.Rectangle rx ry rw h
T.TopP l r -> X.Rectangle (rx + fi l) ry (rw - fi l - fi r) h
T.TopH ch -> X.Rectangle rx ry rw (mh ch)
+ T.TopHM ch l r t _ ->
+ X.Rectangle (rx + fi l) (ry + fi t) (rw - fi l - fi r) (mh ch)
T.TopW a i -> X.Rectangle (ax a i) ry (nw i) h
T.TopSize a i ch -> X.Rectangle (ax a i) ry (nw i) (mh ch)
T.Bottom -> X.Rectangle rx ny rw h
T.BottomH ch -> X.Rectangle rx (ny' ch) rw (mh ch)
+ T.BottomHM ch l r _ b ->
+ X.Rectangle (rx + fi l) (ry + fi rh - fi b - fi (mh ch)) (rw - fi l - fi r) (mh ch)
T.BottomW a i -> X.Rectangle (ax a i) ny (nw i) h
T.BottomP l r -> X.Rectangle (rx + fi l) ny (rw - fi l - fi r) h
T.BottomSize a i ch -> X.Rectangle (ax a i) (ny' ch) (nw i) (mh ch)
@@ -160,18 +164,20 @@ getRootWindowHeight srs = maximum (map getMaxScreenYCoord srs)
getStrutValues :: X.Rectangle -> T.XPosition -> Int -> [Int]
getStrutValues r@(X.Rectangle x y w h) p rwh =
case p of
- T.OnScreen _ p' -> getStrutValues r p' rwh
- T.Top -> [0, 0, st, 0, 0, 0, 0, 0, nx, nw, 0, 0]
- T.TopH _ -> [0, 0, st, 0, 0, 0, 0, 0, nx, nw, 0, 0]
- T.TopP _ _ -> [0, 0, st, 0, 0, 0, 0, 0, nx, nw, 0, 0]
- T.TopW _ _ -> [0, 0, st, 0, 0, 0, 0, 0, nx, nw, 0, 0]
- T.TopSize {} -> [0, 0, st, 0, 0, 0, 0, 0, nx, nw, 0, 0]
- T.Bottom -> [0, 0, 0, sb, 0, 0, 0, 0, 0, 0, nx, nw]
- T.BottomH _ -> [0, 0, 0, sb, 0, 0, 0, 0, 0, 0, nx, nw]
- T.BottomP _ _ -> [0, 0, 0, sb, 0, 0, 0, 0, 0, 0, nx, nw]
- T.BottomW _ _ -> [0, 0, 0, sb, 0, 0, 0, 0, 0, 0, nx, nw]
- T.BottomSize {} -> [0, 0, 0, sb, 0, 0, 0, 0, 0, 0, nx, nw]
- T.Static {} -> getStaticStrutValues p rwh
+ T.OnScreen _ p' -> getStrutValues r p' rwh
+ T.Top -> [0, 0, st , 0 , 0, 0, 0, 0, nx, nw, 0 , 0 ]
+ T.TopH _ -> [0, 0, st , 0 , 0, 0, 0, 0, nx, nw, 0 , 0 ]
+ T.TopHM _ _ _ _ b -> [0, 0, st+b, 0 , 0, 0, 0, 0, nx, nw, 0 , 0 ]
+ T.TopP _ _ -> [0, 0, st , 0 , 0, 0, 0, 0, nx, nw, 0 , 0 ]
+ T.TopW _ _ -> [0, 0, st , 0 , 0, 0, 0, 0, nx, nw, 0 , 0 ]
+ T.TopSize {} -> [0, 0, st , 0 , 0, 0, 0, 0, nx, nw, 0 , 0 ]
+ T.Bottom -> [0, 0, 0 , sb , 0, 0, 0, 0, 0 , 0 , nx, nw]
+ T.BottomH _ -> [0, 0, 0 , sb , 0, 0, 0, 0, 0 , 0 , nx, nw]
+ T.BottomHM _ _ _ t _ -> [0, 0, 0 , sb+t, 0, 0, 0, 0, 0 , 0 , nx, nw]
+ T.BottomP _ _ -> [0, 0, 0 , sb , 0, 0, 0, 0, 0 , 0 , nx, nw]
+ T.BottomW _ _ -> [0, 0, 0 , sb , 0, 0, 0, 0, 0 , 0 , nx, nw]
+ T.BottomSize {} -> [0, 0, 0 , sb , 0, 0, 0, 0, 0 , 0 , nx, nw]
+ T.Static {} -> getStaticStrutValues p rwh
where st = fi y + fi h
sb = rwh - fi y
nx = fi x
diff --git a/src/Xmobar/X11/XRender.hsc b/src/Xmobar/X11/XRender.hsc
index 5ad0391..4e4d448 100644
--- a/src/Xmobar/X11/XRender.hsc
+++ b/src/Xmobar/X11/XRender.hsc
@@ -91,22 +91,28 @@ drawBackground d p bgc alpha (Rectangle x y wid ht) = do
withRenderFill d
(XRenderColor 0 0 0 (257 * alpha))
(render pictOpSrc bgfill pic)
- -- Handle transparency
- internAtom d "_XROOTPMAP_ID" False >>= \xid ->
- let xroot = defaultRootWindow d in
- alloca $ \x1 ->
- alloca $ \x2 ->
- alloca $ \x3 ->
- alloca $ \x4 ->
- alloca $ \pprop -> do
- xGetWindowProperty d xroot xid 0 1 False 20 x1 x2 x3 x4 pprop
- prop <- peek pprop
- when (prop /= nullPtr) $ do
- rootbg <- peek (castPtr prop) :: IO Pixmap
- xFree prop
- withRenderPicture d rootbg $ \bgpic ->
- withRenderFill d (XRenderColor 0 0 0 (0xFFFF - 257 * alpha))
- (render pictOpAdd bgpic pic)
+ -- Handle pseudo-transparency by compositing the root pixmap.
+ -- Skip entirely when alpha == 255 (fully opaque) since the blend
+ -- factor would be zero, making this a no-op. More importantly,
+ -- the root pixmap (_XROOTPMAP_ID) can be freed at any time by
+ -- wallpaper setters like feh (via XKillClient), causing a
+ -- BadDrawable crash in XRenderCreatePicture if we touch it.
+ when (alpha < 255) $
+ internAtom d "_XROOTPMAP_ID" False >>= \xid ->
+ let xroot = defaultRootWindow d in
+ alloca $ \x1 ->
+ alloca $ \x2 ->
+ alloca $ \x3 ->
+ alloca $ \x4 ->
+ alloca $ \pprop -> do
+ xGetWindowProperty d xroot xid 0 1 False 20 x1 x2 x3 x4 pprop
+ prop <- peek pprop
+ when (prop /= nullPtr) $ do
+ rootbg <- peek (castPtr prop) :: IO Pixmap
+ xFree prop
+ withRenderPicture d rootbg $ \bgpic ->
+ withRenderFill d (XRenderColor 0 0 0 (0xFFFF - 257 * alpha))
+ (render pictOpAdd bgpic pic)
-- | Parses color into XRender color (allocation not necessary!)
parseRenderColor :: Display -> String -> IO XRenderColor
diff --git a/stack.yaml b/stack.yaml
index 8021bad..439f19f 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,5 +1,5 @@
-# ghc 8.10.7
-resolver: lts-18.20
+# ghc-9.10.3
+resolver: lts-24.45
packages:
- .
@@ -11,7 +11,6 @@ flags:
extra-deps:
- netlink-1.1.1.0
- - libmpd-0.9.2.0
nix:
packages:
- alsaLib
diff --git a/test/Xmobar/Plugins/Monitors/CpuSpec.hs b/test/Xmobar/Plugins/Monitors/CpuSpec.hs
index 3d07dee..b415179 100644
--- a/test/Xmobar/Plugins/Monitors/CpuSpec.hs
+++ b/test/Xmobar/Plugins/Monitors/CpuSpec.hs
@@ -6,24 +6,38 @@ module Xmobar.Plugins.Monitors.CpuSpec
import Test.Hspec
import Xmobar.Plugins.Monitors.Common
import Xmobar.Plugins.Monitors.Cpu
+
import Data.List
+import Text.Regex.TDFA((=~))
main :: IO ()
main = hspec spec
+withFc :: String -> String
+withFc s = "((<fc=(green|red)>)?" ++ s ++ "(</fc>)?)"
+
+withFcDigits :: String -> String -> String
+withFcDigits prefix suffix = prefix ++ digits ++ suffix
+ where digits = withFc "([0-9][0-9]?|-0)" -- in CI computers, -0 is a value
+
spec :: Spec
spec =
describe "CPU Spec" $ do
+ it "uses the correct regexps" $
+ do "Cpu: -0%" `shouldSatisfy` (=~ withFcDigits "Cpu: " "%")
+ "Cpu: 12" `shouldSatisfy` (=~ withFcDigits "Cpu: " "")
+ "Cpu: <fc=red>12</fc>" `shouldSatisfy` (=~ withFcDigits "Cpu: " "")
+ "Cpu: <fc=green>12</fc> -0" `shouldSatisfy` (=~ withFcDigits "Cpu: (" ")+")
it "works with total template" $
do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>%"]
cpuArgs <- getArguments args
cpuValue <- runCpu cpuArgs
- cpuValue `shouldSatisfy` (\item -> "Cpu:" `isPrefixOf` item)
+ cpuValue `shouldSatisfy` (=~ withFcDigits "Cpu: " "%")
it "works with bar template" $
do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar>"]
cpuArgs <- getArguments args
cpuValue <- runCpu cpuArgs
- cpuValue `shouldSatisfy` (all (`elem` ":#") . last . words)
+ cpuValue `shouldSatisfy` ((=~ (withFc "#+" ++ "?:*")) . last . words)
it "works with no icon pattern template" $
do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <total>% <bar>", "--", "--load-icon-pattern", "<icon=bright_%%.xpm/>"]
cpuArgs <- getArguments args
@@ -38,4 +52,5 @@ spec =
do let args = ["-L","3","-H","50","--normal","green","--high","red", "-t", "Cpu: <user> <nice> <iowait>"]
cpuArgs <- getArguments args
cpuValue <- runCpu cpuArgs
- cpuValue `shouldSatisfy` (\item -> "Cpu:" `isPrefixOf` cpuValue)
+ cpuValue `shouldSatisfy` (=~ withFcDigits "Cpu:( " ")+")
+
diff --git a/xmobar.cabal b/xmobar.cabal
index 8b331f5..e7ed69c 100644
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -1,423 +1,471 @@
+cabal-version: >=1.10
name: xmobar
-version: 0.45
-homepage: https://codeberg.org/xmobar/xmobar
-synopsis: A Minimalistic Text Based Status Bar
-description: Xmobar is a minimalistic text based status bar.
- .
- Inspired by the Ion3 status bar, it supports similar
- features, like dynamic color management, output templates,
- and extensibility through plugins.
-category: System
+version: 0.51.1
license: BSD3
license-file: license
-author: Andrea Rossato and Jose A. Ortega Ruiz
maintainer: Jose A. Ortega Ruiz <jao@gnu.org>
+author: Andrea Rossato and Jose A. Ortega Ruiz
+homepage: https://codeberg.org/xmobar/xmobar
bug-reports: https://codeberg.org/xmobar/xmobar/issues
-cabal-version: >= 1.10
-build-type: Simple
+synopsis: A Minimalistic Text Based Status Bar
+description:
+ Xmobar is a minimalistic text based status bar.
+ .
+ Inspired by the Ion3 status bar, it supports similar
+ features, like dynamic color management, output templates,
+ and extensibility through plugins.
-extra-source-files: readme.org, changelog.md,
- doc/quick-start.org,
- doc/plugins.org,
- doc/compiling.org,
- doc/using-haskell.org,
- etc/padding-icon.sh,
- etc/xmobar.config,
- etc/xmobar.hs,
- etc/xmonadpropwrite.hs,
- etc/xmobar.el
+category: System
+build-type: Simple
+extra-source-files:
+ readme.org
+ changelog.md
+ doc/quick-start.org
+ doc/plugins.org
+ doc/compiling.org
+ doc/using-haskell.org
+ etc/padding-icon.sh
+ etc/xmobar.config
+ etc/xmobar.hs
+ etc/xmonadpropwrite.hs
+ etc/xmobar.el
+ etc/notify-once.sh
source-repository head
- type: git
- location: git://codeberg.org/xmobar/xmobar.git
- branch: master
+ type: git
+ location: https://codeberg.org/xmobar/xmobar.git
+ branch: master
flag with_xrender
- description: Use XRender for alpha background pseudo-transparency.
- default: True
+ description: Use XRender for alpha background pseudo-transparency.
flag with_inotify
- description: inotify support (modern Linux only). Required for the Mail and MBox plugins.
- default: False
+ description:
+ inotify support (modern Linux only). Required for the Mail and MBox plugins.
+
+ default: False
flag with_iwlib
- description: Wireless info support via Wext ioctls (deprecated). Required for the Wireless plugin, needs iwlib installed.
- default: False
+ description:
+ Wireless info support via Wext ioctls (deprecated). Required for the Wireless plugin, needs iwlib installed.
+
+ default: False
flag with_nl80211
- description: Wireless info support via nl80211. Required for the Wireless plugin on systems running Linux, the kernel.
- default: False
+ description:
+ Wireless info support via nl80211. Required for the Wireless plugin on systems running Linux, the kernel.
+
+ default: False
flag with_mpd
- description: MPD support. Needs libmpd installed.
- default: False
+ description: MPD support. Needs libmpd installed.
+ default: False
flag all_extensions
- description: Includes all optional extensions.
- default: False
+ description: Includes all optional extensions.
+ default: False
flag with_alsa
- description: Use alsa-mixer to get the volume from soundcards.
- default: False
+ description: Use alsa-mixer to get the volume from soundcards.
+ default: False
flag with_datezone
- description: Enables localized date support.
- default: False
+ description: Enables localized date support.
+ default: False
flag with_mpris
- description: MPRIS v1, v2 support.
- default: False
+ description: MPRIS v1, v2 support.
+ default: False
flag with_dbus
- description: Publish a service on the session bus for controlling xmobar.
- default: False
+ description:
+ Publish a service on the session bus for controlling xmobar.
+
+ default: False
flag with_xpm
- description: Enable usage of xpm for icons.
- default: False
+ description: Enable usage of xpm for icons.
+ default: False
flag with_threaded
- description: Use threaded runtime. Required for timer coalescing (less power usage).
- default: False
+ description:
+ Use threaded runtime. Required for timer coalescing (less power usage).
+
+ default: False
flag with_rtsopts
- description: Use -with-rtsopts=-V0 to reduce wakeups.
- default: True
+ description: Use -with-rtsopts=-V0 to reduce wakeups.
+
+flag with_shared
+ description:
+ Use shared libraries. Required when dependencies are built as shared libraries.
+
+ default: False
flag with_weather
- description: Enable weather plugin.
- default: True
+ description: Enable weather plugin.
flag with_uvmeter
- description: UVMeter only useful to australians.
- default: False
+ description: UVMeter only useful to australians.
+ default: False
flag with_kraken
- description: Enable Kraken plugin.
- default: False
+ description: Enable Kraken plugin.
+ default: False
library
+ exposed-modules:
+ Xmobar
+ Xmobar.Plugins.Accordion
+ Xmobar.Plugins.Monitors.Common.Types
+ Xmobar.Plugins.Monitors.Common.Run
+ Xmobar.Plugins.Monitors.Common
+ Xmobar.Plugins.Monitors.Cpu
+
+ hs-source-dirs: src
+ other-modules:
+ Paths_xmobar
+ Xmobar.Config.Types
+ Xmobar.Config.Parse
+ Xmobar.Config.Template
+ Xmobar.Run.Types
+ Xmobar.Run.Timer
+ Xmobar.Run.Template
+ Xmobar.Run.Exec
+ Xmobar.Run.Runnable
+ Xmobar.Run.Actions
+ Xmobar.Run.Loop
+ Xmobar.Draw.Boxes
+ Xmobar.Draw.Cairo
+ Xmobar.Draw.Types
+ Xmobar.App.Config
+ Xmobar.App.Main
+ Xmobar.App.Opts
+ Xmobar.App.Compile
+ Xmobar.System.Utils
+ Xmobar.System.StatFS
+ Xmobar.System.Environment
+ Xmobar.System.Localize
+ Xmobar.System.Signal
+ Xmobar.System.Kbd
+ Xmobar.Text.Ansi
+ Xmobar.Text.Loop
+ Xmobar.Text.Pango
+ Xmobar.Text.Swaybar
+ Xmobar.Text.SwaybarClicks
+ Xmobar.Text.Output
+ Xmobar.X11.Bitmap
+ Xmobar.X11.CairoSurface
+ Xmobar.X11.ColorCache
+ Xmobar.X11.Draw
+ Xmobar.X11.Events
+ Xmobar.X11.Loop
+ Xmobar.X11.Text
+ Xmobar.X11.Types
+ Xmobar.X11.Window
+ Xmobar.Plugins.Command
+ Xmobar.Plugins.BufferedPipeReader
+ Xmobar.Plugins.CommandReader
+ Xmobar.Plugins.Date
+ Xmobar.Plugins.EWMH
+ Xmobar.Plugins.HandleReader
+ Xmobar.Plugins.QueueReader
+ Xmobar.Plugins.PacmanUpdates
+ Xmobar.Plugins.PipeReader
+ Xmobar.Plugins.MarqueePipeReader
+ Xmobar.Plugins.StdinReader
+ Xmobar.Plugins.XMonadLog
+ Xmobar.Plugins.Kbd
+ Xmobar.Plugins.Locks
+ Xmobar.Plugins.NotmuchMail
+ Xmobar.Plugins.Monitors
+ Xmobar.Plugins.Monitors.Batt
+ Xmobar.Plugins.Monitors.Batt.Common
+ Xmobar.Plugins.Monitors.Common.Output
+ Xmobar.Plugins.Monitors.Common.Parsers
+ Xmobar.Plugins.Monitors.Common.Files
+ Xmobar.Plugins.Monitors.CoreTemp
+ Xmobar.Plugins.Monitors.K10Temp
+ Xmobar.Plugins.Monitors.Cpu.Common
+ Xmobar.Plugins.Monitors.CpuFreq
+ Xmobar.Plugins.Monitors.Disk
+ Xmobar.Plugins.Monitors.Disk.Common
+ Xmobar.Plugins.Monitors.Load
+ Xmobar.Plugins.Monitors.Load.Common
+ Xmobar.Plugins.Monitors.Mem
+ Xmobar.Plugins.Monitors.MultiCoreTemp
+ Xmobar.Plugins.Monitors.MultiCpu
+ Xmobar.Plugins.Monitors.Net
+ Xmobar.Plugins.Monitors.Net.Common
+ Xmobar.Plugins.Monitors.Swap
+ Xmobar.Plugins.Monitors.Thermal
+ Xmobar.Plugins.Monitors.ThermalZone
+ Xmobar.Plugins.Monitors.Top
+ Xmobar.Plugins.Monitors.Top.Common
+ Xmobar.Plugins.Monitors.Uptime
+ Xmobar.Plugins.Monitors.Bright
+ Xmobar.Plugins.Monitors.CatInt
+
default-language: Haskell2010
- hs-source-dirs: src
-
- exposed-modules: Xmobar,
- Xmobar.Plugins.Monitors.Common.Types,
- Xmobar.Plugins.Monitors.Common.Run,
- Xmobar.Plugins.Monitors.Common,
- Xmobar.Plugins.Monitors.Cpu
-
- other-modules: Paths_xmobar,
- Xmobar.Config.Types,
- Xmobar.Config.Parse,
- Xmobar.Run.Types,
- Xmobar.Run.Timer,
- Xmobar.Run.Template,
- Xmobar.Run.Exec,
- Xmobar.Run.Runnable
- Xmobar.Run.Actions,
- Xmobar.Run.Parsers,
- Xmobar.Run.Loop,
- Xmobar.Draw.Boxes,
- Xmobar.Draw.Cairo,
- Xmobar.Draw.Types,
- Xmobar.App.Config,
- Xmobar.App.Main,
- Xmobar.App.Opts,
- Xmobar.App.Compile,
- Xmobar.System.Utils,
- Xmobar.System.StatFS,
- Xmobar.System.Environment,
- Xmobar.System.Localize,
- Xmobar.System.Signal,
- Xmobar.System.Kbd,
- Xmobar.Text.Ansi,
- Xmobar.Text.Loop,
- Xmobar.Text.Pango,
- Xmobar.Text.Swaybar,
- Xmobar.Text.SwaybarClicks,
- Xmobar.Text.Output,
- Xmobar.X11.Bitmap,
- Xmobar.X11.CairoSurface,
- Xmobar.X11.ColorCache,
- Xmobar.X11.Draw,
- Xmobar.X11.Events,
- Xmobar.X11.Loop,
- Xmobar.X11.Text,
- Xmobar.X11.Types,
- Xmobar.X11.Window,
- Xmobar.Plugins.Command,
- Xmobar.Plugins.BufferedPipeReader,
- Xmobar.Plugins.CommandReader,
- Xmobar.Plugins.Date,
- Xmobar.Plugins.EWMH,
- Xmobar.Plugins.HandleReader,
- Xmobar.Plugins.QueueReader,
- Xmobar.Plugins.PipeReader,
- Xmobar.Plugins.MarqueePipeReader,
- Xmobar.Plugins.StdinReader,
- Xmobar.Plugins.XMonadLog,
- Xmobar.Plugins.Kbd,
- Xmobar.Plugins.Locks,
- Xmobar.Plugins.NotmuchMail,
- Xmobar.Plugins.Monitors,
- Xmobar.Plugins.Monitors.Batt,
- Xmobar.Plugins.Monitors.Batt.Common,
- Xmobar.Plugins.Monitors.Common.Output,
- Xmobar.Plugins.Monitors.Common.Parsers,
- Xmobar.Plugins.Monitors.Common.Files,
- Xmobar.Plugins.Monitors.CoreTemp,
- Xmobar.Plugins.Monitors.K10Temp,
- Xmobar.Plugins.Monitors.Cpu.Common,
- Xmobar.Plugins.Monitors.CpuFreq,
- Xmobar.Plugins.Monitors.Disk,
- Xmobar.Plugins.Monitors.Disk.Common,
- Xmobar.Plugins.Monitors.Load,
- Xmobar.Plugins.Monitors.Load.Common,
- Xmobar.Plugins.Monitors.Mem,
- Xmobar.Plugins.Monitors.MultiCoreTemp,
- Xmobar.Plugins.Monitors.MultiCpu,
- Xmobar.Plugins.Monitors.Net,
- Xmobar.Plugins.Monitors.Net.Common,
- Xmobar.Plugins.Monitors.Swap,
- Xmobar.Plugins.Monitors.Thermal,
- Xmobar.Plugins.Monitors.ThermalZone,
- Xmobar.Plugins.Monitors.Top,
- Xmobar.Plugins.Monitors.Top.Common,
- Xmobar.Plugins.Monitors.Uptime,
- Xmobar.Plugins.Monitors.Bright,
- Xmobar.Plugins.Monitors.CatInt
-
- extra-libraries: Xrandr Xrender
-
- ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
+ extra-libraries:
+ Xrandr
+ Xrender
+ ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
build-depends:
- aeson >= 1.4.7.1,
- async,
- base >= 4.11.0 && < 4.17,
- bytestring >= 0.10.8.2,
- cairo >= 0.13,
- colour >= 2.3.6,
- containers,
- directory,
- extensible-exceptions == 0.1.*,
- filepath,
- mtl >= 2.1 && < 2.3,
- old-locale,
- pango >= 0.13,
- parsec == 3.1.*,
- parsec-numbers >= 0.1.0,
- process,
- regex-compat,
- stm >= 2.3 && < 2.6,
- time,
- transformers,
- unix,
- utf8-string >= 0.3 && < 1.1,
- X11 >= 1.6.1
-
- if impl(ghc < 8.0.2)
- -- Disable building with GHC before 8.0.2.
- -- Due to a cabal bug, do not use buildable: False,
- -- but instead give it an impossible constraint.
- -- See: https://github.com/haskell-infra/hackage-trustees/issues/165
- build-depends: unsupported-ghc-version > 1 && < 1
+ aeson >=1.4.7.1 && <2.4,
+ async <2.3,
+ base >=4.18.0 && <4.22,
+ bytestring >=0.10.8.2 && <0.13,
+ cairo >=0.13 && <0.14,
+ colour >=2.3.6 && <2.4,
+ containers <0.9,
+ directory <1.4,
+ extra <1.9,
+ filepath <1.6,
+ mtl >=2.1 && <2.4,
+ old-locale <1.1,
+ pango >=0.13 && <0.14,
+ parsec >=3.1 && <3.2,
+ parsec-numbers >=0.1.0 && <0.2,
+ process <1.7,
+ regex-compat <0.96,
+ stm >=2.3 && <2.6,
+ time <1.17,
+ transformers <0.7,
+ unix <2.9,
+ utf8-string >=0.3 && <1.1,
+ vector <0.14,
+ X11 >=1.6.1 && <1.11
+
+ if impl(ghc <9.6.0)
+ build-depends: unsupported-ghc-version >=1 && <1
if flag(with_threaded)
- -- -threaded is a workaround for 100% CPU busy loop
- -- (http://hackage.haskell.org/trac/ghc/ticket/4934).
- -- See also comments in https://codeberg.org/xmobar/xmobar/pulls/36
- cpp-options: -DTHREADED_RUNTIME
+ cpp-options: -DTHREADED_RUNTIME
if flag(with_rtsopts)
- cpp-options: -DRTSOPTS
+ cpp-options: -DRTSOPTS
+
+ if flag(with_shared)
+ cpp-options: -DSHARED_LIBRARIES
if flag(with_xrender)
- build-depends: X11-xft >= 0.2
- other-modules: Xmobar.X11.XRender
- cpp-options: -DXRENDER
+ cpp-options: -DXRENDER
+ other-modules: Xmobar.X11.XRender
+ build-depends: X11-xft >=0.2 && <0.4
+
+ if (flag(with_inotify) || flag(all_extensions))
+ cpp-options: -DINOTIFY
+ other-modules:
+ Xmobar.Plugins.Mail
+ Xmobar.Plugins.MBox
- if flag(with_inotify) || flag(all_extensions)
- build-depends: hinotify >= 0.3 && < 0.5
- other-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox
- cpp-options: -DINOTIFY
+ build-depends: hinotify >=0.3 && <0.5
- if flag(with_iwlib) || flag(with_nl80211) || flag(all_extensions)
- other-modules: Xmobar.Plugins.Monitors.Wireless
+ if ((flag(with_iwlib) || flag(with_nl80211)) || flag(all_extensions))
+ other-modules: Xmobar.Plugins.Monitors.Wireless
if flag(with_iwlib)
- extra-libraries: iw
- build-depends: iwlib >= 0.1.0 && < 0.2
- cpp-options: -DIWLIB
-
- if !flag(with_iwlib) && (flag(with_nl80211) || flag(all_extensions))
- build-depends: netlink >= 1.1.1.0,
- cereal >= 0.5.8.1
- cpp-options: -DUSE_NL80211
-
- if flag(with_mpd) || flag(all_extensions)
- build-depends: libmpd >= 0.9.2.0
- other-modules: Xmobar.Plugins.Monitors.MPD
- cpp-options: -DLIBMPD
-
- if flag(with_alsa) || flag(all_extensions)
- build-depends: alsa-mixer >= 0.3 && < 0.4
- build-depends: alsa-core == 0.5.*,
- process >= 1.4.3.0
- other-modules: Xmobar.Plugins.Monitors.Volume,
- Xmobar.Plugins.Monitors.Alsa
- cpp-options: -DALSA
-
- if flag(with_datezone) || flag(all_extensions)
- build-depends: timezone-olson >= 0.2 && < 0.3, timezone-series == 0.1.*
- other-modules: Xmobar.Plugins.DateZone
- cpp-options: -DDATEZONE
-
- if flag(with_mpris) || flag(all_extensions)
- build-depends: dbus >= 1
- other-modules: Xmobar.Plugins.Monitors.Mpris
- cpp-options: -DMPRIS
-
- if flag(with_dbus) || flag(all_extensions)
- build-depends: dbus >= 1
- other-modules: Xmobar.System.DBus
- cpp-options: -DDBUS
-
- if flag(with_xpm) || flag(all_extensions)
- extra-libraries: Xpm
- other-modules: Xmobar.X11.XPMFile
- cpp-options: -DXPM
-
- if flag(with_weather) || flag(all_extensions)
- other-modules: Xmobar.Plugins.Monitors.Weather
- cpp-options: -DWEATHER
- build-depends: http-conduit, http-types, http-client-tls
+ cpp-options: -DIWLIB
+ extra-libraries: iw
+ build-depends: iwlib >=0.1.0 && <0.2
+
+ if (!flag(with_iwlib) && (flag(with_nl80211) || flag(all_extensions)))
+ cpp-options: -DUSE_NL80211
+ build-depends:
+ netlink >=1.1.1.0,
+ cereal >=0.5.8.1
+
+ if (flag(with_mpd) || flag(all_extensions))
+ cpp-options: -DLIBMPD
+ other-modules: Xmobar.Plugins.Monitors.MPD
+ build-depends: libmpd >=0.10.0.1 && <0.11
+
+ if (flag(with_alsa) || flag(all_extensions))
+ cpp-options: -DALSA
+ other-modules:
+ Xmobar.Plugins.Monitors.Volume
+ Xmobar.Plugins.Monitors.Alsa
+
+ build-depends:
+ alsa-mixer >=0.3 && <0.4,
+ alsa-core >=0.5 && <0.6,
+ process >=1.4.3.0 && <1.7
+
+ if (flag(with_datezone) || flag(all_extensions))
+ cpp-options: -DDATEZONE
+ other-modules: Xmobar.Plugins.DateZone
+ build-depends:
+ timezone-olson >=0.2 && <0.3,
+ timezone-series >=0.1 && <0.2
+
+ if (flag(with_mpris) || flag(all_extensions))
+ cpp-options: -DMPRIS
+ other-modules: Xmobar.Plugins.Monitors.Mpris
+ build-depends: dbus >=1 && <1.5
+
+ if (flag(with_dbus) || flag(all_extensions))
+ cpp-options: -DDBUS
+ other-modules: Xmobar.System.DBus
+ build-depends: dbus >=1 && <1.5
+
+ if (flag(with_xpm) || flag(all_extensions))
+ cpp-options: -DXPM
+ other-modules: Xmobar.X11.XPMFile
+ extra-libraries: Xpm
+
+ if (flag(with_weather) || flag(all_extensions))
+ cpp-options: -DWEATHER
+ other-modules: Xmobar.Plugins.Monitors.Weather
+ build-depends:
+ http-conduit <2.4,
+ http-types <0.13,
+ http-client-tls <0.5
if flag(with_uvmeter)
- other-modules: Xmobar.Plugins.Monitors.UVMeter
- build-depends: http-conduit, http-types
- cpp-options: -DUVMETER
+ cpp-options: -DUVMETER
+ other-modules: Xmobar.Plugins.Monitors.UVMeter
+ build-depends:
+ http-conduit,
+ http-types
if flag(with_kraken)
- other-modules: Xmobar.Plugins.Kraken
- build-depends: aeson == 1.5.6.*
- , text == 1.2.4.*
- , unordered-containers == 0.2.14.*
- , vector == 0.12.3.*
- , wuss == 1.1.*
- , websockets == 0.12.*
- cpp-options: -DKRAKEN
+ cpp-options: -DKRAKEN
+ other-modules: Xmobar.Plugins.Kraken
+ build-depends:
+ aeson >=1.5.6 && <1.5.7,
+ text >=1.2.4 && <1.2.5,
+ unordered-containers >=0.2.14 && <0.2.15,
+ vector >=0.12.3 && <0.12.4,
+ wuss >=1.1 && <1.2,
+ websockets >=0.12 && <0.13
if os(freebsd)
- -- enables freebsd specific code
- extra-libraries: procstat
- , kvm
- , geom
- build-depends: bsd-sysctl
- other-modules: Xmobar.Plugins.Monitors.Batt.FreeBSD,
- Xmobar.Plugins.Monitors.Cpu.FreeBSD,
- Xmobar.Plugins.Monitors.Disk.FreeBSD,
- Xmobar.Plugins.Monitors.Load.FreeBSD,
- Xmobar.Plugins.Monitors.Mem.FreeBSD,
- Xmobar.Plugins.Monitors.Net.FreeBSD,
- Xmobar.Plugins.Monitors.Swap.FreeBSD,
- Xmobar.Plugins.Monitors.Top.FreeBSD,
- Xmobar.Plugins.Monitors.Uptime.FreeBSD
+ other-modules:
+ Xmobar.Plugins.Monitors.Batt.FreeBSD
+ Xmobar.Plugins.Monitors.Cpu.FreeBSD
+ Xmobar.Plugins.Monitors.Disk.FreeBSD
+ Xmobar.Plugins.Monitors.Load.FreeBSD
+ Xmobar.Plugins.Monitors.Mem.FreeBSD
+ Xmobar.Plugins.Monitors.Net.FreeBSD
+ Xmobar.Plugins.Monitors.Swap.FreeBSD
+ Xmobar.Plugins.Monitors.Top.FreeBSD
+ Xmobar.Plugins.Monitors.Uptime.FreeBSD
+
+ extra-libraries:
+ procstat
+ kvm
+ geom
+
+ build-depends: bsd-sysctl <1.1
+
else
- other-modules: Xmobar.Plugins.Monitors.Batt.Linux,
- Xmobar.Plugins.Monitors.Cpu.Linux,
- Xmobar.Plugins.Monitors.Disk.Linux,
- Xmobar.Plugins.Monitors.Load.Linux,
- Xmobar.Plugins.Monitors.Mem.Linux,
- Xmobar.Plugins.Monitors.Net.Linux,
- Xmobar.Plugins.Monitors.Swap.Linux,
- Xmobar.Plugins.Monitors.Top.Linux,
- Xmobar.Plugins.Monitors.Uptime.Linux
+ other-modules:
+ Xmobar.Plugins.Monitors.Batt.Linux
+ Xmobar.Plugins.Monitors.Cpu.Linux
+ Xmobar.Plugins.Monitors.Disk.Linux
+ Xmobar.Plugins.Monitors.Load.Linux
+ Xmobar.Plugins.Monitors.Mem.Linux
+ Xmobar.Plugins.Monitors.Net.Linux
+ Xmobar.Plugins.Monitors.Swap.Linux
+ Xmobar.Plugins.Monitors.Top.Linux
+ Xmobar.Plugins.Monitors.Uptime.Linux
executable xmobar
- default-language: Haskell2010
- hs-source-dirs: app
- main-is: Main.hs
- build-depends: X11,
- async,
- base,
- containers,
- directory,
- filepath,
- parsec,
- unix,
- xmobar
-
- ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
+ main-is: Main.hs
+ hs-source-dirs: app
+ default-language: Haskell2010
+ ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
+ build-depends:
+ X11 <1.11,
+ async <2.3,
+ base,
+ containers <0.9,
+ directory <1.4,
+ filepath <1.6,
+ parsec,
+ unix <2.9,
+ xmobar
if flag(with_rtsopts)
- ghc-options: -with-rtsopts=-V0
+ ghc-options: -with-rtsopts=-V0
if flag(with_threaded)
- ghc-options: -threaded
- cpp-options: -DTHREADED_RUNTIME
+ cpp-options: -DTHREADED_RUNTIME
+ ghc-options: -threaded
test-suite XmobarTest
- default-language: Haskell2010
- type: exitcode-stdio-1.0
- hs-source-dirs: src, test
- main-is: Spec.hs
- build-depends: X11,
- async,
- base,
- bytestring,
- containers,
- directory,
- filepath,
- hspec == 2.*,
- mtl,
- old-locale,
- parsec,
- parsec-numbers,
- process,
- regex-compat,
- stm,
- temporary,
- time,
- transformers,
- unix,
- xmobar
-
- other-modules: Xmobar.Plugins.Monitors.CommonSpec
- Xmobar.Plugins.Monitors.Common
- Xmobar.Plugins.Monitors.Common.Parsers
- Xmobar.Plugins.Monitors.Common.Types
- Xmobar.Plugins.Monitors.Common.Output
- Xmobar.Plugins.Monitors.Common.Files
- Xmobar.Plugins.Monitors.Cpu
- Xmobar.Plugins.Monitors.Cpu.Common
- Xmobar.Plugins.Monitors.CpuSpec
- Xmobar.Plugins.Monitors.Common.Run
- Xmobar.Run.Exec
- Xmobar.Run.Timer
- Xmobar.System.Signal
-
- if flag(with_alsa) || flag(all_extensions)
- build-depends: alsa-mixer,
- alsa-core,
- process >= 1.4.3.0
- other-modules: Xmobar.Plugins.Monitors.Volume
- Xmobar.Plugins.Monitors.Alsa
- Xmobar.Plugins.Monitors.AlsaSpec
-
- cpp-options: -DALSA
-
- if os(freebsd)
- -- enables freebsd specific code
- build-depends: bsd-sysctl
- other-modules: Xmobar.Plugins.Monitors.Cpu.FreeBSD
- else
- other-modules: Xmobar.Plugins.Monitors.Cpu.Linux
+ type: exitcode-stdio-1.0
+ main-is: Spec.hs
+ hs-source-dirs: src test
+ other-modules:
+ Xmobar.Plugins.Monitors.CommonSpec
+ Xmobar.Plugins.Monitors.Common
+ Xmobar.Plugins.Monitors.Common.Parsers
+ Xmobar.Plugins.Monitors.Common.Types
+ Xmobar.Plugins.Monitors.Common.Output
+ Xmobar.Plugins.Monitors.Common.Files
+ Xmobar.Plugins.Monitors.Cpu
+ Xmobar.Plugins.Monitors.Cpu.Common
+ Xmobar.Plugins.Monitors.CpuSpec
+ Xmobar.Plugins.Monitors.Common.Run
+ Xmobar.Run.Exec
+ Xmobar.Run.Timer
+ Xmobar.System.Signal
+
+ default-language: Haskell2010
+ build-depends:
+ X11 <1.11,
+ async <2.3,
+ base,
+ bytestring <0.13,
+ containers <0.9,
+ directory <1.4,
+ filepath <1.6,
+ hspec >=2 && <3,
+ mtl,
+ old-locale <1.1,
+ parsec,
+ parsec-numbers <0.2,
+ process <1.7,
+ regex-compat <0.96,
+ regex-tdfa <1.4,
+ stm,
+ temporary <1.4,
+ time <1.17,
+ transformers <0.7,
+ unix <2.9,
+ xmobar
+
+ if (flag(with_alsa) || flag(all_extensions))
+ cpp-options: -DALSA
+ other-modules:
+ Xmobar.Plugins.Monitors.Volume
+ Xmobar.Plugins.Monitors.Alsa
+ Xmobar.Plugins.Monitors.AlsaSpec
+
+ build-depends:
+ alsa-mixer,
+ alsa-core,
+ process >=1.4.3.0 && <1.7
+
+ if os(freebsd)
+ other-modules: Xmobar.Plugins.Monitors.Cpu.FreeBSD
+ build-depends: bsd-sysctl
+
+ else
+ other-modules: Xmobar.Plugins.Monitors.Cpu.Linux
benchmark xmobarbench
- type: exitcode-stdio-1.0
- main-is: main.hs
- hs-source-dirs: bench
- ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind -O2
- build-depends: base, gauge, mtl, time, xmobar
- default-language: Haskell2010
+ type: exitcode-stdio-1.0
+ main-is: main.hs
+ hs-source-dirs: bench
+ default-language: Haskell2010
+ ghc-options: -funbox-strict-fields -Wall -fno-warn-unused-do-bind
+ build-depends:
+ base,
+ gauge,
+ mtl,
+ time <1.17,
+ xmobar