Merge pull request #886 from liskin/steam-fixes

Fixes/workarounds for Steam client menus/flickering
This commit is contained in:
Tomáš Janoušek 2024-04-28 19:39:21 +02:00 committed by GitHub
commit 700507fcd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 162 additions and 10 deletions

View File

@ -7,11 +7,11 @@
* `XMonad.Hooks.StatusBars` * `XMonad.Hooks.StatusBars`
- Move status bar functions from the `IO` to the `X` monad to - Move status bar functions from the `IO` to the `X` monad to
allow them to look up information from `X`, like the screen allow them to look up information from `X`, like the screen
width. Existing configurations may need to use `io` from width. Existing configurations may need to use `io` from
`XMonad.Core` or `liftIO` from `Control.Monad.IO.Class` in `XMonad.Core` or `liftIO` from `Control.Monad.IO.Class` in
order to lift any existing `IO StatusBarConfig` values into order to lift any existing `IO StatusBarConfig` values into
`X StatusBarConfig` values. `X StatusBarConfig` values.
* `XMonad.Prompt` * `XMonad.Prompt`
@ -22,10 +22,17 @@
### New Modules ### New Modules
* `XMonad.Actions.Profiles`. * `XMonad.Actions.Profiles`
- Group workspaces by similarity. Useful when one has lots - 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.
* `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 ### Bug Fixes and Minor Changes
@ -49,6 +56,15 @@
- The history file is not extraneously read and written anymore if - The history file is not extraneously read and written anymore if
the `historySize` is set to 0. 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 ### Other changes
## 0.18.0 (February 3, 2024) ## 0.18.0 (February 3, 2024)

View File

@ -459,7 +459,14 @@ ewmhDesktopsEventHook'
a_aw <- getAtom "_NET_ACTIVE_WINDOW" a_aw <- getAtom "_NET_ACTIVE_WINDOW"
a_cw <- getAtom "_NET_CLOSE_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) if W.currentTag s == W.tag ww then mempty else windows $ W.view (W.tag ww)
| mt == a_cd -> | mt == a_cd ->
trace $ "Bad _NET_CURRENT_DESKTOP with data=" ++ show d 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 if W.peek s == Just w then mempty else windows $ W.focusWindow w
| mt == a_aw -> do | mt == a_aw -> do
if W.peek s == Just w then mempty else windows . appEndo =<< runQuery activateHook w if W.peek s == Just w then mempty else windows . appEndo =<< runQuery activateHook w
| mt == a_cw ->
killWindow w
| otherwise -> | otherwise ->
-- The Message is unknown to us, but that is ok, not all are meant -- The Message is unknown to us, but that is ok, not all are meant
-- to be handled by the window manager -- to be handled by the window manager

View File

@ -0,0 +1,126 @@
{-# LANGUAGE LambdaCase #-}
-- |
-- Module : XMonad.Hooks.FloatConfigureReq
-- Description : Customize handling of floating windows' move\/resize\/restack requests (ConfigureRequest).
-- Copyright : (c) 2024 Tomáš Janoušek <tomi@nomi.cz>
-- License : BSD3
-- Maintainer : Tomáš Janoušek <tomi@nomi.cz>
--
-- 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,
-- * Known workarounds
fixSteamFlicker,
fixSteamFlickerMMMH,
) 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
--
-- (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'.
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
-- | 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

View File

@ -40,10 +40,14 @@ module XMonad.Util.Hacks (
trayerPaddingXmobarEventHook, trayerPaddingXmobarEventHook,
trayPaddingXmobarEventHook, trayPaddingXmobarEventHook,
trayPaddingEventHook, trayPaddingEventHook,
-- * Steam flickering fix
fixSteamFlicker,
) where ) where
import XMonad import XMonad
import XMonad.Hooks.FloatConfigureReq (fixSteamFlicker)
import XMonad.Hooks.StatusBar (xmonadPropLog') import XMonad.Hooks.StatusBar (xmonadPropLog')
import XMonad.Prelude (All (All), fi, filterM, when) import XMonad.Prelude (All (All), fi, filterM, when)
import System.Posix.Env (putEnv) import System.Posix.Env (putEnv)

View File

@ -192,6 +192,7 @@ library
XMonad.Hooks.EwmhDesktops XMonad.Hooks.EwmhDesktops
XMonad.Hooks.FadeInactive XMonad.Hooks.FadeInactive
XMonad.Hooks.FadeWindows XMonad.Hooks.FadeWindows
XMonad.Hooks.FloatConfigureReq
XMonad.Hooks.FloatNext XMonad.Hooks.FloatNext
XMonad.Hooks.Focus XMonad.Hooks.Focus
XMonad.Hooks.InsertPosition XMonad.Hooks.InsertPosition