X.H.Rescreen: Configurable wait/delay for events to settle

This commit is contained in:
Tomas Janousek 2024-10-16 19:25:41 +01:00
parent b454f1e0be
commit 2f42d2e7b4

View File

@ -16,10 +16,12 @@ module XMonad.Hooks.Rescreen (
addAfterRescreenHook, addAfterRescreenHook,
addRandrChangeHook, addRandrChangeHook,
setRescreenWorkspacesHook, setRescreenWorkspacesHook,
setRescreenDelay,
RescreenConfig(..), RescreenConfig(..),
rescreenHook, rescreenHook,
) where ) where
import Control.Concurrent (threadDelay)
import Graphics.X11.Xrandr import Graphics.X11.Xrandr
import XMonad import XMonad
import XMonad.Prelude import XMonad.Prelude
@ -61,6 +63,7 @@ data RescreenConfig = RescreenConfig
{ afterRescreenHook :: X () -- ^ hook to invoke after 'rescreen' { afterRescreenHook :: X () -- ^ hook to invoke after 'rescreen'
, randrChangeHook :: X () -- ^ hook for other randr changes, e.g. (dis)connects , randrChangeHook :: X () -- ^ hook for other randr changes, e.g. (dis)connects
, rescreenWorkspacesHook :: Last (X ()) -- ^ hook to invoke instead of 'rescreen' , rescreenWorkspacesHook :: Last (X ()) -- ^ hook to invoke instead of 'rescreen'
, rescreenDelay :: Last Int -- ^ delay (in microseconds) to wait for events to settle
} }
instance Default RescreenConfig where instance Default RescreenConfig where
@ -68,10 +71,12 @@ instance Default RescreenConfig where
{ afterRescreenHook = mempty { afterRescreenHook = mempty
, randrChangeHook = mempty , randrChangeHook = mempty
, rescreenWorkspacesHook = mempty , rescreenWorkspacesHook = mempty
, rescreenDelay = mempty
} }
instance Semigroup RescreenConfig where instance Semigroup RescreenConfig where
RescreenConfig arh rch rwh <> RescreenConfig arh' rch' rwh' = RescreenConfig (arh <> arh') (rch <> rch') (rwh <> rwh') RescreenConfig arh rch rwh rd <> RescreenConfig arh' rch' rwh' rd' =
RescreenConfig (arh <> arh') (rch <> rch') (rwh <> rwh') (rd <> rd')
instance Monoid RescreenConfig where instance Monoid RescreenConfig where
mempty = def mempty = def
@ -96,6 +101,10 @@ instance Monoid RescreenConfig where
-- to change the order workspaces are assigned to physical screens for -- to change the order workspaces are assigned to physical screens for
-- example. -- example.
-- --
-- 'rescreenDelay' makes xmonad wait a bit for events to settle (after the
-- first event is received) — useful when multiple @xrandr@ invocations are
-- being used to change the screen layout.
--
-- Note that 'rescreenHook' is safe to use several times, 'rescreen' is still -- Note that 'rescreenHook' is safe to use several times, 'rescreen' is still
-- done just once and hooks are invoked in sequence (except -- done just once and hooks are invoked in sequence (except
-- 'rescreenWorkspacesHook', which has a replace rather than sequence -- 'rescreenWorkspacesHook', which has a replace rather than sequence
@ -124,6 +133,10 @@ addRandrChangeHook h = rescreenHook def{ randrChangeHook = h }
setRescreenWorkspacesHook :: X () -> XConfig l -> XConfig l setRescreenWorkspacesHook :: X () -> XConfig l -> XConfig l
setRescreenWorkspacesHook h = rescreenHook def{ rescreenWorkspacesHook = pure h } setRescreenWorkspacesHook h = rescreenHook def{ rescreenWorkspacesHook = pure h }
-- | Shortcut for 'rescreenHook'.
setRescreenDelay :: Int -> XConfig l -> XConfig l
setRescreenDelay d = rescreenHook def{ rescreenDelay = pure d }
-- | Startup hook to listen for @RRScreenChangeNotify@ events. -- | Startup hook to listen for @RRScreenChangeNotify@ events.
rescreenStartupHook :: X () rescreenStartupHook :: X ()
rescreenStartupHook = do rescreenStartupHook = do
@ -146,6 +159,7 @@ handleEvent :: Event -> X ()
handleEvent e = XC.with $ \RescreenConfig{..} -> do handleEvent e = XC.with $ \RescreenConfig{..} -> do
-- Xorg emits several events after every change, clear them to prevent -- Xorg emits several events after every change, clear them to prevent
-- triggering the hook multiple times. -- triggering the hook multiple times.
whenJust (getLast rescreenDelay) (io . threadDelay)
moreConfigureEvents <- clearTypedWindowEvents (ev_window e) configureNotify moreConfigureEvents <- clearTypedWindowEvents (ev_window e) configureNotify
_ <- clearTypedWindowRREvents (ev_window e) rrScreenChangeNotify _ <- clearTypedWindowRREvents (ev_window e) rrScreenChangeNotify
-- If there were any ConfigureEvents, this is an actual screen -- If there were any ConfigureEvents, this is an actual screen