From 3839c8bce99b6f07bf7074da79110e29e5038ff8 Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Sat, 27 Apr 2024 14:24:45 +0200 Subject: [PATCH 1/5] X.H.EwmhDesktops: Fix menus in Steam client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More specifically, ignore ClientMessageEvents for unmanaged windows. Steam likes to send _NET_ACTIVE_WINDOW requests for all its windows, including override-redirect ones, which used to result in an invocation of `windows` with a no-op Endo—equivalent to a call to `refresh`. But this refresh makes Steam close its menus immediately. Fixes: https://github.com/ValveSoftware/steam-for-linux/issues/9376 Fixes: https://github.com/xmonad/xmonad/issues/451 --- XMonad/Hooks/EwmhDesktops.hs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/XMonad/Hooks/EwmhDesktops.hs b/XMonad/Hooks/EwmhDesktops.hs index cfb1b91df..337de252c 100644 --- a/XMonad/Hooks/EwmhDesktops.hs +++ b/XMonad/Hooks/EwmhDesktops.hs @@ -459,7 +459,14 @@ ewmhDesktopsEventHook' a_aw <- getAtom "_NET_ACTIVE_WINDOW" a_cw <- getAtom "_NET_CLOSE_WINDOW" - if | mt == a_cd, n : _ <- d, Just ww <- ws !? fi n -> + if | mt == a_cw -> + killWindow w + | not (w `W.member` s) -> + -- do nothing for unmanaged windows; it'd be just a useless + -- refresh which breaks menus/popups of misbehaving apps that + -- send _NET_ACTIVE_WINDOW requests for override-redirect wins + mempty + | mt == a_cd, n : _ <- d, Just ww <- ws !? fi n -> if W.currentTag s == W.tag ww then mempty else windows $ W.view (W.tag ww) | mt == a_cd -> trace $ "Bad _NET_CURRENT_DESKTOP with data=" ++ show d @@ -473,8 +480,6 @@ ewmhDesktopsEventHook' if W.peek s == Just w then mempty else windows $ W.focusWindow w | mt == a_aw -> do if W.peek s == Just w then mempty else windows . appEndo =<< runQuery activateHook w - | mt == a_cw -> - killWindow w | otherwise -> -- The Message is unknown to us, but that is ok, not all are meant -- to be handled by the window manager From 2b77997259fab3ea665cadaa8c249d8d0818f622 Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Sat, 27 Apr 2024 23:26:02 +0200 Subject: [PATCH 2/5] X.H.FloatConfigureReq: New module to customize ConfigureRequest handling Implements a replacement event handler for 'ConfigureRequestEvent' to work around misbehaving client applications such as Steam, URxvt and others that try to restore their absolute window positions. Primarily motivated by the Steam client being almost completely unusable in xmonad lately. (I've been running this code in my xmonad.hs for other purposes for years.) --- XMonad/Hooks/FloatConfigureReq.hs | 109 ++++++++++++++++++++++++++++++ xmonad-contrib.cabal | 1 + 2 files changed, 110 insertions(+) create mode 100644 XMonad/Hooks/FloatConfigureReq.hs diff --git a/XMonad/Hooks/FloatConfigureReq.hs b/XMonad/Hooks/FloatConfigureReq.hs new file mode 100644 index 000000000..0aeeee608 --- /dev/null +++ b/XMonad/Hooks/FloatConfigureReq.hs @@ -0,0 +1,109 @@ +{-# LANGUAGE LambdaCase #-} +-- | +-- Module : XMonad.Hooks.FloatConfigureReq +-- Description : Customize handling of floating windows' move\/resize\/restack requests (ConfigureRequest). +-- Copyright : (c) 2024 Tomáš Janoušek +-- License : BSD3 +-- Maintainer : Tomáš Janoušek +-- +-- xmonad normally honours those requests by doing exactly what the client +-- application asked, and refreshing. There are some misbehaving clients, +-- however, that: +-- +-- * try to move their window to the last known absolute position regardless +-- of the current xrandr/xinerama layout +-- +-- * move their window to 0, 0 for no particular reason (e.g. rxvt-unicode) +-- +-- * issue lots of no-op requests causing flickering (e.g. Steam) +-- +-- This module provides a replacement handler for 'ConfigureRequestEvent' to +-- work around such misbehaviours. +-- +module XMonad.Hooks.FloatConfigureReq ( + -- * Usage + -- $usage + MaybeMaybeManageHook, + floatConfReqHook, + ) where + +import qualified Data.Map.Strict as M +import XMonad +import XMonad.Hooks.ManageHelpers +import XMonad.Prelude +import qualified XMonad.StackSet as W + +-- $usage +-- To use this, include the following in your @xmonad.hs@: +-- +-- > import XMonad.Hooks.FloatConfigureReq +-- > import XMonad.Hooks.ManageHelpers +-- +-- > myFloatConfReqHook :: MaybeMaybeManageHook +-- > myFloatConfReqHook = composeAll +-- > [ … ] +-- +-- > myEventHook :: Event -> X All +-- > myEventHook = mconcat +-- > [ … +-- > , floatConfReqHook myFloatConfReqHook +-- > , … ] +-- +-- > main = xmonad $ … +-- > $ def{ handleEventHook = myEventHook +-- > , … } +-- +-- Then fill the @myFloatConfReqHook@ with whatever custom rules you need. +-- +-- As an example, the following will prevent rxvt-unicode from moving its +-- (floating) window to 0, 0 after a font change but still ensure its size +-- increment hints are respected: +-- +-- > className =? "URxvt" -?> pure <$> doFloat +-- +-- Another example that avoids flickering and xmonad slowdowns caused by the +-- Steam client (completely ignore all its requests, none of which are +-- meaningful in the context of a tiling WM): +-- +-- > map toLower `fmap` className =? "steam" -?> mempty + +-- | A variant of 'MaybeManageHook' that additionally may or may not make +-- changes to the 'WindowSet'. +type MaybeMaybeManageHook = Query (Maybe (Maybe (Endo WindowSet))) + +-- | Customizable handler for a 'ConfigureRequestEvent'. If the event's +-- 'ev_window' is a managed floating window, the provided +-- 'MaybeMaybeManageHook' is consulted and its result interpreted as follows: +-- +-- * @Nothing@ - no match, fall back to the default handler +-- +-- * @Just Nothing@ - match but ignore, no refresh, just send ConfigureNotify +-- +-- * @Just (Just a)@ - match, modify 'WindowSet', refresh, send ConfigureNotify +floatConfReqHook :: MaybeMaybeManageHook -> Event -> X All +floatConfReqHook mh ConfigureRequestEvent{ev_window = w} = + runQuery (join <$> (isFloatQ -?> mh)) w >>= \case + Nothing -> mempty + Just e -> do + whenJust e (windows . appEndo) + sendConfEvent + pure (All False) + where + sendConfEvent = withDisplay $ \dpy -> + withWindowAttributes dpy w $ \wa -> do + io . allocaXEvent $ \ev -> do + -- We may have made no changes to the window size/position + -- and thus the X server didn't emit any ConfigureNotify, + -- so we need to send the ConfigureNotify ourselves to make + -- sure there is a reply to this ConfigureRequestEvent and the + -- window knows we (possibly) ignored its request. + setEventType ev configureNotify + setConfigureEvent ev w w + (wa_x wa) (wa_y wa) (wa_width wa) + (wa_height wa) (wa_border_width wa) none (wa_override_redirect wa) + sendEvent dpy w False 0 ev +floatConfReqHook _ _ = mempty + +-- | A 'Query' to determine if a window is floating. +isFloatQ :: Query Bool +isFloatQ = ask >>= \w -> liftX . gets $ M.member w . W.floating . windowset diff --git a/xmonad-contrib.cabal b/xmonad-contrib.cabal index 354aaca8b..1882eb9db 100644 --- a/xmonad-contrib.cabal +++ b/xmonad-contrib.cabal @@ -192,6 +192,7 @@ library XMonad.Hooks.EwmhDesktops XMonad.Hooks.FadeInactive XMonad.Hooks.FadeWindows + XMonad.Hooks.FloatConfigureReq XMonad.Hooks.FloatNext XMonad.Hooks.Focus XMonad.Hooks.InsertPosition From c33efbbefde892de12c31967ec09c8abca927574 Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Sat, 27 Apr 2024 23:45:52 +0200 Subject: [PATCH 3/5] X.H.FloatConfigureReq: Add fixSteamFlicker For ease of use, provide `fixSteamFlicker` as a pre-packaged `floatConfReqHook` that can easily be added directly to a `handleEventHook`. Also, for discoverability, re-export it from X.U.Hacks. --- XMonad/Hooks/FloatConfigureReq.hs | 17 +++++++++++++++++ XMonad/Util/Hacks.hs | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/XMonad/Hooks/FloatConfigureReq.hs b/XMonad/Hooks/FloatConfigureReq.hs index 0aeeee608..7b255a7f4 100644 --- a/XMonad/Hooks/FloatConfigureReq.hs +++ b/XMonad/Hooks/FloatConfigureReq.hs @@ -25,6 +25,10 @@ module XMonad.Hooks.FloatConfigureReq ( -- $usage MaybeMaybeManageHook, floatConfReqHook, + + -- * Known workarounds + fixSteamFlicker, + fixSteamFlickerMMMH, ) where import qualified Data.Map.Strict as M @@ -66,6 +70,10 @@ import qualified XMonad.StackSet as W -- meaningful in the context of a tiling WM): -- -- > map toLower `fmap` className =? "steam" -?> mempty +-- +-- (this example is also available as 'fixSteamFlickerMMMH' to be added to +-- one's @myFloatConfReqHook@ and also 'fixSteamFlicker' to be added directly +-- to one's 'handleEventHook') -- | A variant of 'MaybeManageHook' that additionally may or may not make -- changes to the 'WindowSet'. @@ -107,3 +115,12 @@ floatConfReqHook _ _ = mempty -- | A 'Query' to determine if a window is floating. isFloatQ :: Query Bool isFloatQ = ask >>= \w -> liftX . gets $ M.member w . W.floating . windowset + +-- | A pre-packaged 'floatConfReqHook' that fixes flickering of the Steam client by ignoring 'ConfigureRequestEvent's on any of its floating windows. +-- +-- To use this, add 'fixSteamFlicker' to your 'handleEventHook'. +fixSteamFlicker :: Event -> X All +fixSteamFlicker = floatConfReqHook fixSteamFlickerMMMH + +fixSteamFlickerMMMH :: MaybeMaybeManageHook +fixSteamFlickerMMMH = map toLower `fmap` className =? "steam" -?> mempty diff --git a/XMonad/Util/Hacks.hs b/XMonad/Util/Hacks.hs index 749d81bb6..6b00ead44 100644 --- a/XMonad/Util/Hacks.hs +++ b/XMonad/Util/Hacks.hs @@ -40,10 +40,14 @@ module XMonad.Util.Hacks ( trayerPaddingXmobarEventHook, trayPaddingXmobarEventHook, trayPaddingEventHook, + + -- * Steam flickering fix + fixSteamFlicker, ) where import XMonad +import XMonad.Hooks.FloatConfigureReq (fixSteamFlicker) import XMonad.Hooks.StatusBar (xmonadPropLog') import XMonad.Prelude (All (All), fi, filterM, when) import System.Posix.Env (putEnv) From 67472aa307b673ef88df2df656afc2ad5660a129 Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Sat, 27 Apr 2024 23:49:24 +0200 Subject: [PATCH 4/5] CHANGES: Whitespace/punctuation fixes --- CHANGES.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 569daea02..868fe5230 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,11 +7,11 @@ * `XMonad.Hooks.StatusBars` - Move status bar functions from the `IO` to the `X` monad to - allow them to look up information from `X`, like the screen - width. Existing configurations may need to use `io` from - `XMonad.Core` or `liftIO` from `Control.Monad.IO.Class` in - order to lift any existing `IO StatusBarConfig` values into - `X StatusBarConfig` values. + allow them to look up information from `X`, like the screen + width. Existing configurations may need to use `io` from + `XMonad.Core` or `liftIO` from `Control.Monad.IO.Class` in + order to lift any existing `IO StatusBarConfig` values into + `X StatusBarConfig` values. * `XMonad.Prompt` @@ -22,10 +22,10 @@ ### New Modules - * `XMonad.Actions.Profiles`. + * `XMonad.Actions.Profiles` - Group workspaces by similarity. Useful when one has lots - of workspaces and uses only a couple per unit of work. + of workspaces and uses only a couple per unit of work. ### Bug Fixes and Minor Changes From ca5e70ffc4a7eaf4528dc860d672cbe2793ddb4d Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Sat, 27 Apr 2024 23:55:52 +0200 Subject: [PATCH 5/5] CHANGES: Document this branch's additions/fixes --- CHANGES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 868fe5230..2d3983dbc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,13 @@ - Group workspaces by similarity. Useful when one has lots of workspaces and uses only a couple per unit of work. + * `XMonad.Hooks.FloatConfigureReq` + + - Customize handling of floating windows' move/resize/restack requests + (ConfigureRequest). Useful as a workaround for some misbehaving client + applications (Steam, rxvt-unicode, anything that tries to restore + absolute position of floats). + ### Bug Fixes and Minor Changes * Fix build-with-cabal.sh when XDG_CONFIG_HOME is defined. @@ -49,6 +56,15 @@ - The history file is not extraneously read and written anymore if the `historySize` is set to 0. + * `XMonad.Hooks.EwmhDesktops` + + - Requests for unmanaged windows no longer cause a refresh. This avoids + flicker and also fixes disappearing menus in the Steam client and + possibly a few other client applications. + + (See also `XMonad.Hooks.FloatConfigureReq` and/or `XMonad.Util.Hacks` + for additional Steam client workarounds.) + ### Other changes ## 0.18.0 (February 3, 2024)