X.H.ManageDocks: Avoid unnecessary refresh (loop) for decorations
This started as an investigation of the root cause of
<https://github.com/xmonad/xmonad-contrib/issues/565>, which was
addressed by <https://github.com/xmonad/xmonad-contrib/pull/621> without
having a full understanding of why xmonad ends up in a busy loop.
What was going on:
* X.L.SubLayouts group update algorithm assumes no duplicities in the
Stack, and results in multiplying those duplicities otherwise. Note
that this is a reasonable assumption—duplicities in a Stack have no
defined behaviour in xmonad (X11 can't place a window on a screen
twice), so "fixing" this algorithm is a waste of time.
* X.L.Decoration creates windows which X.H.ManageDocks treats as
possible docks, resulting in extra refresh whenever they appear.
* The extra refresh causes X.L.SubLayouts to multiply the duplicities,
X.L.Decoration to create new decoration windows, and these invalidate
the X.H.ManageDocks strut cache, leading to yet another refresh, and
an endless loop of these.
Having concluded that the no-duplicities assumption is a reasonable one,
there's nothing really to fix here after
<https://github.com/xmonad/xmonad-contrib/pull/621>. Still, the extra
refresh might be causing extra flicker in decorated layouts, and we can
easily avoid it, so I do that here. Plus a bit of documentation for
X.L.SubLayouts.
This started as an investigation/fix of xmonad freezing when a bug in
X.A.DynamicWorkspaces caused duplicate Windows in a single Workspace
Stack, but I soon(-ish) realized that trying to make SubLayouts robust
enough to handle duplicities in a Stack is futile. Any code that creates
duplicities in a Stack is buggy, and must be fixed; the rest can assume
there aren't any.
Instead, let's just document that this is a pre-condition, and that (and
how) stuff will misbehave.
Related: https://github.com/xmonad/xmonad-contrib/issues/565
Windows created by X.U.XUtils.createNewWindow have _NET_WM_WINDOW_TYPE =
_NET_WM_WINDOW_TYPE_DESKTOP, which caused checkDock to match them and an
UpdateDocks event to be sent, causing an additional layout refresh
whenever a decoration window appeared.
This could in theory lead to a refresh loop with a layout (modifier)
that dropped and recreated its decoration windows on every
runLayout—which isn't entirely unreasonable, X.L.MouseResizableTile does
it, just luckily happens to not mark its windows as
_NET_WM_WINDOW_TYPE_DESKTOP.
In practice, such a refresh loop could be triggered when buggy
X.A.DynamicWorkspaces (before 929a6a3f6f) duplicated a Window in a
single workspace's Stack, and buggy X.L.SubLayouts then kept duplicating
the duplication (2 → 4 → 8 → …), triggering the creation of new
decoration window in each iteration.
Fixes: https://github.com/xmonad/xmonad-contrib/issues/565
Adds property tests in both directions for the parser in X.U.EZConfig.
As with the tests for X.P.OrgMode, these (modulo `Maybe` noise) take the
shape of the operation of an inverse semigroup:
pp ∘ p ∘ pp ≡ pp and p ∘ pp ∘ p = p,
where pp is pretty-printing and p is parsing.
The keysymToString function prints the key names in pure ASCII; e.g.,
`keysymToString 250` returns "uacute" instead of "ú". This is
undesirable when printing these keysyms in places like visualSubmap.
Thus, move all of the key infrastructure (heh) from X.U.EZConfig to
X.Prelude and look up the name of the key if possible. For better
composability, slightly change the signature for `regularKeys` and the
associated parser.
This changes KeyPress handling in these modules to behave much closer to
how xmonad core itself handles keypresses. The primary difference lies
in that xmonad reads raw KeyCode and then converts it to unmodified
KeySym, while these modules used `lookupString` to find the actual
keysyms. As a consequence, key definitions like `(shiftMap, xK_Tab)`
didn't work on many layouts because an actual KeySym for `Shift-Tab` is
commonly `ISO_LEFT_TAB`, and not `Tab`.
Closes: https://github.com/xmonad/xmonad-contrib/pull/590
Co-authored-by: Tomas Janousek <tomi@nomi.cz>
This replaces the custom `cleanMask` extension in these modules—which
only filtered out XKB group bits and Button5Mask¹—with the new
`cleanKeyMask` which additionally filters out all mouse buttons, as
these aren't relevant for key bindings.
¹) Filtering out Button5Mask was probably an off-by-one mistake.
Fixes: https://github.com/xmonad/xmonad-contrib/issues/290
Related: https://github.com/xmonad/xmonad-contrib/pull/590
We didn't clean XKB group bits out of the KeyPress events' state so key
bindings only worked in the primary keyboard layout (first XKB group).
To fix this, this adds a `cleanKeyMask` function to X.Prelude which is
analogous to `cleanMask` but aimed at cleaning regular KeyPress states
(as opposed to just KeyPresses from passive key grabs), and this is then
used instead of `cleanMask`.
Related: https://github.com/xmonad/xmonad-contrib/issues/290
Related: https://github.com/xmonad/xmonad-contrib/pull/590
There's no reason (other than me forgetting to update the docs when
these add-Hooks were added) to steer users towards the ugly record-based
low-level API.
Add a `visualSubmap` function, which works much like the regular
`submap` one, except that it visualises the available choices in a
pop-up window.
Related: https://github.com/xmonad/xmonad-contrib/issues/472
Adds several new functions and type for manipulating "simple windows".
There are several ways to draw windows in X.U.XUtils and other places
already, but they are all quite manual. Most of the time one does not
want to think about dimensions much and assumes that the code is smart
enough to "figure it out"; this is an attempt to do exactly that.
There is a less-managed version `showSimpleWindow`, which just creates
and shows the windows, as well as a wrapper-like `withSimpleWindow` that
also destroys the window once some action finishes executing.
With these functions it should be possible to refactor some contrib
modules that currently draw windows manually, like X.U.EasyMotion.
This technically introduces a regression with regards to the way that
modifier masks are printed in X.U.NamedActions and X.H.DebugEvents.
However, since this way of printing masks is move in line with
X.U.EZConfig, I personally don't think that this is noteworthy.
Adds event hooks to communicate with trayer or, more generally, with
other tray programs. For convenience, a standard query for trayer is
also provided.
This one isn't actually a personal configuration, it's more like
X.C.Desktop and the other desktop-specific configs. As I happen to
sometimes use it for testing whether everything still works with
decorated layouts, it shouldn't be considered abandoned.
Related: https://github.com/xmonad/xmonad-contrib/pull/679
When users specify non-existent keys, it seems most intuitive to just
abort the parse and not try to take the "longest" input that still
works. For example, given the "key" `M-10` we should signal a parse
error (by returning `Nothing`) instead of parsing `M-1` and ignoring
the rest of the input. The old EZConfig parser accounted for this but
when the module was rewritten to use X.U.Parser in [1], this was
forgotten about.
Fixes: https://github.com/xmonad/xmonad/issues/361
[1]: 8abeb81fd0