diff --git a/CHANGES.md b/CHANGES.md index 87cbf400..2ca3ff68 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -686,6 +686,13 @@ - Fixed issue with keyboard/pointer staying grabbed when a blocking action like `runProcessWithInput` was invoked. + - `XMonad.Actions.UpdateFocus` + + - Added `focusUnderPointer`, that updates the focus based on pointer + position, an inverse of `X.A.UpdatePointer`, which moves the mouse + pointer to match the focused window). Together these can be used to + ensure focus stays in sync with mouse. + ## 0.16 ### Breaking Changes diff --git a/XMonad/Actions/UpdateFocus.hs b/XMonad/Actions/UpdateFocus.hs index 628163d1..45dd0318 100644 --- a/XMonad/Actions/UpdateFocus.hs +++ b/XMonad/Actions/UpdateFocus.hs @@ -16,7 +16,8 @@ module XMonad.Actions.UpdateFocus ( -- * Usage -- $usage focusOnMouseMove, - adjustEventInput + adjustEventInput, + focusUnderPointer, ) where import XMonad @@ -57,3 +58,25 @@ adjustEventInput = withDisplay $ \dpy -> do io $ selectInput dpy rootw $ substructureRedirectMask .|. substructureNotifyMask .|. enterWindowMask .|. leaveWindowMask .|. structureNotifyMask .|. buttonPressMask .|. pointerMotionMask + +-- | Focus the window under the mouse pointer, unless we're currently changing +-- focus with the mouse or dragging. This is the inverse to +-- "XMonad.Actions.UpdatePointer": instead of moving the mouse pointer to +-- match the focus, we change the focus to match the mouse pointer. +-- +-- This is meant to be used together with +-- 'XMonad.Actions.UpdatePointer.updatePointer' in individual key bindings. +-- Bindings that change focus should invoke +-- 'XMonad.Actions.UpdatePointer.updatePointer' at the end, bindings that +-- switch workspaces or change layouts should call 'focusUnderPointer' at the +-- end. Neither should go to 'logHook', as that would override the other. +-- +-- This is more finicky to set up than 'focusOnMouseMove', but ensures that +-- focus is updated immediately, without having to touch the mouse. +focusUnderPointer :: X () +focusUnderPointer = whenX (not <$> (asks mouseFocused <||> gets (isJust . dragging))) $ do + dpy <- asks display + root <- asks theRoot + (_, _, w', _, _, _, _, _) <- io $ queryPointer dpy root + w <- gets (W.peek . windowset) + when (w' /= none && Just w' /= w) (focus w') diff --git a/XMonad/Actions/UpdatePointer.hs b/XMonad/Actions/UpdatePointer.hs index dd923bde..2547b7b7 100644 --- a/XMonad/Actions/UpdatePointer.hs +++ b/XMonad/Actions/UpdatePointer.hs @@ -60,6 +60,11 @@ import Control.Arrow ((&&&), (***)) -- | Update the pointer's location to the currently focused -- window or empty screen unless it's already there, or unless the user was changing -- focus with the mouse +-- +-- See also 'XMonad.Actions.UpdateFocus.focusUnderPointer' for an inverse +-- operation that updates the focus instead. The two can be combined in a +-- single config if neither goes into 'logHook' but are invoked explicitly in +-- individual key bindings. updatePointer :: (Rational, Rational) -> (Rational, Rational) -> X () updatePointer refPos ratio = do ws <- gets windowset