[xmonad] `Status' Package [xmonad-contrib]

Matt Walker matt.g.d.walker at gmail.com
Sun Dec 13 17:49:59 UTC 2015


Hello everyone,

I've been using xmonad for a couple of months now, and there is something
that has always bothered me, so I'm writing a package to fix it.

[Problem Statement]

Many people who use dzen2 do so with the help of Conky or other external
programs.  While nice, if would be better to be able to control it with
XMonad in a nice way without them.  This would require two things: more
control over how information is outputted to dzen2 from xmonad than that
afforded by DynamicLog, and ways of retrieving system information for
xmonad to use.  Specifically, we would want a flexible, extensible, and
elegant solution, and one that works for more than just Dzen.  I argue no
such solution currently exists, and why this is a problem.

[Evidence of Problem]

People with advanced XMonad/Dzen2 setups often resort to using two
different Dzen2 bars -- one for XMonad stuff that XMonad controls, and one
that is piped output from something like Conky.  Here are just a few
examples I've found around the web:

https://wiki.haskell.org/Xmonad/Config_archive/And1's_xmonad.hs (note the
hacky (but effective) use of the DynamicLog PP facilities)
https://wiki.haskell.org/Xmonad/Config_archive/Regalia's_xmonad.hs
https://wiki.haskell.org/Xmonad/Config_archive/Thayer_Williams'_xmonad.hs
https://wiki.haskell.org/Xmonad/Config_archive/avendael's_xmonad.hs
http://thinkingeek.com/2011/11/21/simple-guide-configure-xmonad-dzen2-conky/
https://github.com/davidbeckingsale/xmonad-config/blob/master/xmonad.hs

In each of these cases, the status bar has two parts: one part controlled
by XMonad that deals with the WM state, and another part controlled by
Conky that contains the system state.  The premise of my argument is
basically that this is undesirable, and all information should be available
from, and outputted from, xmonad.  We have a Haskell environment, and we
are completely by-passing it!

[Probable Cause of Problem]

DynamicLog's PP facility is extremely useful if you want to quickly get a
statusbar up quickly and with minimal customization.  But it quickly
becomes too weak to do anything fancy with, without getting very hacky.

For example, say I wanted my current layout and window-name information
printed in the middle of the bar, and my list of workspaces printed on the
left side of the bar.  This is difficult to achieve with the current tools
-- one must be aware of the formatting characters when performing the
translation if one wants the text to be correctly justified/centred.  One
must be quite familiar with which parts of the PP get outputted when and
how they are put together (since we want two fields to be output to the
same region, but centring them both would make them overlap.)  This makes
for a brittle and non-general solution to the problem.

The problem is that DynamicLog's PP facility is not extensible in any
elegant way.  You have to know how the whole thing works to be able to
extend it, even in minor ways.  Modifications to it are neither composable,
nor factorable -- I can't just add or remove customizations without it
probably breaking.

[Proposed Solution]

I propose a new solution.  The code for this solution is located here:
https://github.com/Fizzixnerd/xmonad-config/tree/master/site-haskell/src/XMonad/Hooks/DynamicLog/Status
.  I haven't yet spun off the code in that subdirectory into its own repo.
Right now, the whole repo is an unholy Frankenstein's monster of personal
configuration, failed attempts, and worthwhile work.  Most of the good
stuff is in XMonad.Hooks.DynamicLog.Status though.

The main idea is that we defined a new type, StatusText which has three
bits: a prefix, a suffix, and some content.  The actual stuff you want to
display goes in the content section, while the prefix and suffix hold the
markup information.

Here is a brief summary of the type:

type Status b a = Writer (b, Dual b) a
type StatusText = Status [T.Text] T.Text

where Dual is defined in Data.Monoid.  And that's it!  We get a Functor and
Writer Monad for free out of this definition, clearly.  The Dual is there
so that if you have something like <bold><italics>hello
there!</italics></bold>, then the wrapping happens in the correct order.
That is, you don't end up with <bold><italics>hello there!</bold></italics>.

We define the `length' of a StatusText to be the length of the content.
This allows us to calculate offsets within the status bar without having to
strip away all the markup.

I have a library included in Status.DZen2 (name change is coming to get rid
of the capital Z).  It contains combinators and so on for marking up
StatusText using all the dzen2 commands, all from within XMonad.
Exciting!  I plan to make a universal interface and a fancy interface: the
universal interface will contain all commands common to dzen2, xmobar, and
possibly taffybar.  In this way, it will be possible to swap out your
statusbar without everything breaking.  Maybe I'll abandon this part, but
let me know if it sounds cool to you.

There are also facilities similar to those found in XMonad.Util.Logger for
making StatusTexts from shell commands.  These are found in
Status.StatusText.Dynamic.  The point of this is so that the formatting of
the information can be cleanly separated from the retrieval of the
information.  This makes things more composable, and doesn't have use
relying on brittle solutions.  However, you can still just plug in your
conky stuff and pipe it through xmonad if you want to just get it up and
running to see what it's like.  I will be adding a few `standard'
StatusTexts in Status.System.

I have replicated the facilities found in XMonad.Hooks.DynamicLog's PP's by
factoring out the different parts of the PP and then wrapping those in
StatusTexts in Status.X.  Big ups to the creator of DynamicLog's PPs.  They
are a fantastic idea within the domain of their applicability, and I used a
lot of the code from them.

I will be spending the coming days cleaning up the codebase and getting it
ready to be submitted for possible inclusion in xmonad-contrib.  I don't
think it even compiles right now, but past versions of it have worked so
I'm not super worried about there being a fundamental flaw in it or
whatever.  There are some examples using battery in Status.System of
composing a StatusText to format content using the monadic interface in
Status.DZen2.Fancy.

Finally, you take your StatusTexts, stick them in a list (one for the left,
middle, and right side of the bar respectively), and then render them to a
string.  This is the part that isn't quite done yet, but it's also probably
the most straightforward.  More on that later.

Obviously, this package is best used with XMonad.Util.Timer, since you
probably want your uptime and stuff to actually update properly with time,
and not just on X events.

[License]

Its currently GPLv3, but I have no qualms about changing it once its ready.

[Conclusion]

I'd love to hear some feedback on this.  Does anyone even care?  Maybe this
is better left as just a personal package for myself.  I have no idea.  I
just felt it solved a rather general problem, and so could possibly be of
use to other people.  If it helps reduce the (in my opinion) ugly hacky use
of Conky and 2+ dzen bars, then I think that's pretty good.  Let me know!

Sincerely,
Matt
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/xmonad/attachments/20151213/f6218bc9/attachment.html>


More information about the xmonad mailing list