X.H.ManageDocks: Avoid unnecessary refresh (loop) for decorations

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
This commit is contained in:
Tomas Janousek 2022-02-18 12:21:32 +00:00
parent ee3ea2402d
commit 6a6e4bcce8

View File

@ -148,15 +148,20 @@ requestDockEvents w = whenX (not <$> isClient w) $ withDisplay $ \dpy ->
withWindowAttributes dpy w $ \attrs -> io $ selectInput dpy w $
wa_your_event_mask attrs .|. propertyChangeMask .|. structureNotifyMask
-- | Checks if a window is a DOCK or DESKTOP window
-- | Checks if a window is a DOCK or DESKTOP window.
-- Ignores xmonad's own windows (usually _NET_WM_WINDOW_TYPE_DESKTOP) to avoid
-- unnecessary refreshes.
checkDock :: Query Bool
checkDock = ask >>= \w -> liftX $ do
checkDock = isDockOrDesktop <&&> (not <$> isXMonad)
where
isDockOrDesktop = ask >>= \w -> liftX $ do
dock <- getAtom "_NET_WM_WINDOW_TYPE_DOCK"
desk <- getAtom "_NET_WM_WINDOW_TYPE_DESKTOP"
mbr <- getProp32s "_NET_WM_WINDOW_TYPE" w
case mbr of
Just rs -> return $ any ((`elem` [dock,desk]) . fromIntegral) rs
_ -> return False
isXMonad = className =? "xmonad"
-- | Whenever a new dock appears, refresh the layout immediately to avoid the
-- new dock.