mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-05-19 11:30:22 -07:00
XMonad.Actions.UpdatePointer: generalise updatePointer
This commit is contained in:
parent
2fe30c6730
commit
fd23bd692b
@ -19,12 +19,12 @@ module XMonad.Actions.UpdatePointer
|
|||||||
-- * Usage
|
-- * Usage
|
||||||
-- $usage
|
-- $usage
|
||||||
updatePointer
|
updatePointer
|
||||||
, PointerPosition (..)
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import XMonad
|
import XMonad
|
||||||
import XMonad.Util.XUtils (fi)
|
import XMonad.Util.XUtils (fi)
|
||||||
|
import Control.Arrow
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import XMonad.StackSet (member, peek, screenDetail, current)
|
import XMonad.StackSet (member, peek, screenDetail, current)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
@ -35,36 +35,32 @@ import Data.Maybe
|
|||||||
-- > import XMonad
|
-- > import XMonad
|
||||||
-- > import XMonad.Actions.UpdatePointer
|
-- > import XMonad.Actions.UpdatePointer
|
||||||
--
|
--
|
||||||
-- Enable it by including it in your logHook definition. Eg:
|
-- Enable it by including it in your logHook definition, e.g.:
|
||||||
--
|
--
|
||||||
-- > logHook = updatePointer Nearest
|
-- > logHook = updatePointer (0.5, 0.5) (1, 1)
|
||||||
--
|
--
|
||||||
-- which will move the pointer to the nearest point of a newly focused window, or
|
-- which will move the pointer to the nearest point of a newly focused
|
||||||
|
-- window. The first argument establishes a reference point within the
|
||||||
|
-- newly-focused window, while the second argument linearly interpolates
|
||||||
|
-- between said reference point and the edges of the newly-focused window to
|
||||||
|
-- obtain a bounding box for the pointer.
|
||||||
--
|
--
|
||||||
-- > logHook = updatePointer (Relative 0.5 0.5)
|
-- > logHook = updatePointer (0.5, 0.5) (0, 0) -- exact centre of window
|
||||||
--
|
-- > logHook = updatePointer (0.25, 0.25) (0.25, 0.25) -- near the top-left
|
||||||
-- which will move the pointer to the center of a newly focused window, or
|
-- > logHook = updatePointer (0.5, 0.5) (1.1, 1.1) -- within 110% of the edge
|
||||||
--
|
|
||||||
-- > logHook = updatePointer (TowardsCentre 0.75 0.75)
|
|
||||||
--
|
|
||||||
-- which will linearly interpolate the pointer between 'Nearest' and ¾ of
|
|
||||||
-- the way towards the centre of the window.
|
|
||||||
--
|
--
|
||||||
-- To use this with an existing logHook, use >> :
|
-- To use this with an existing logHook, use >> :
|
||||||
--
|
--
|
||||||
-- > logHook = dynamicLog
|
-- > logHook = dynamicLog
|
||||||
-- > >> updatePointer (Relative 1 1)
|
-- > >> updatePointer (1, 1) (0, 0)
|
||||||
--
|
--
|
||||||
-- which moves the pointer to the bottom-right corner of the focused window.
|
-- which moves the pointer to the bottom-right corner of the focused window.
|
||||||
|
|
||||||
data PointerPosition = Nearest | Relative Rational Rational | TowardsCentre Rational Rational
|
|
||||||
deriving (Read,Show)
|
|
||||||
|
|
||||||
-- | Update the pointer's location to the currently focused
|
-- | Update the pointer's location to the currently focused
|
||||||
-- window or empty screen unless it's already there, or unless the user was changing
|
-- window or empty screen unless it's already there, or unless the user was changing
|
||||||
-- focus with the mouse
|
-- focus with the mouse
|
||||||
updatePointer :: PointerPosition -> X ()
|
updatePointer :: (Rational, Rational) -> (Rational, Rational) -> X ()
|
||||||
updatePointer p = do
|
updatePointer refPos ratio = do
|
||||||
ws <- gets windowset
|
ws <- gets windowset
|
||||||
dpy <- asks display
|
dpy <- asks display
|
||||||
rect <- case peek ws of
|
rect <- case peek ws of
|
||||||
@ -72,39 +68,37 @@ updatePointer p = do
|
|||||||
Just w -> windowAttributesToRectangle `fmap` io (getWindowAttributes dpy w)
|
Just w -> windowAttributesToRectangle `fmap` io (getWindowAttributes dpy w)
|
||||||
root <- asks theRoot
|
root <- asks theRoot
|
||||||
mouseIsMoving <- asks mouseFocused
|
mouseIsMoving <- asks mouseFocused
|
||||||
(_sameRoot,_,currentWindow,rootx,rooty,_,_,_) <- io $ queryPointer dpy root
|
(_sameRoot,_,currentWindow,rootX,rootY,_,_,_) <- io $ queryPointer dpy root
|
||||||
drag <- gets dragging
|
drag <- gets dragging
|
||||||
unless (pointWithin (fi rootx) (fi rooty) rect
|
unless (pointWithin (fi rootX) (fi rootY) rect
|
||||||
|| mouseIsMoving
|
|| mouseIsMoving
|
||||||
|| isJust drag
|
|| isJust drag
|
||||||
|| not (currentWindow `member` ws || currentWindow == none)) $
|
|| not (currentWindow `member` ws || currentWindow == none)) $ let
|
||||||
case p of
|
-- focused rectangle
|
||||||
Nearest -> do
|
(rectX, rectY) = (rect_x &&& rect_y) rect
|
||||||
let x = moveWithin (fi rootx) (rect_x rect) (fi (rect_x rect) + fi (rect_width rect))
|
(rectW, rectH) = (fi . rect_width &&& fi . rect_height) rect
|
||||||
y = moveWithin (fi rooty) (rect_y rect) (fi (rect_y rect) + fi (rect_height rect))
|
-- reference position, with (0,0) and (1,1) being top-left and bottom-right
|
||||||
io $ warpPointer dpy none root 0 0 0 0 x y
|
refX = lerp (fst refPos) rectX (rectX + rectW)
|
||||||
TowardsCentre xfrc yfrc -> do
|
refY = lerp (snd refPos) rectY (rectY + rectH)
|
||||||
let cx = fi (rect_width rect) / 2 + fi (rect_x rect)
|
-- final pointer bounds, lerped *outwards* from reference position
|
||||||
cy = fi (rect_height rect) / 2 + fi (rect_y rect)
|
boundsX = join (***) (lerp (fst ratio) refX) (rectX, rectX + rectW)
|
||||||
x,y,cx,cy :: Rational
|
boundsY = join (***) (lerp (snd ratio) refY) (rectY, rectY + rectH)
|
||||||
x = moveWithin (fi rootx) (fi $ rect_x rect) (fi (rect_x rect) + fi (rect_width rect))
|
-- ideally we ought to move the pointer in a straight line towards the
|
||||||
y = moveWithin (fi rooty) (fi $ rect_y rect) (fi (rect_y rect) + fi (rect_height rect))
|
-- reference point until it is within the above bounds, but…
|
||||||
io $ warpPointer dpy none root 0 0 0 0 (round $ x + xfrc*(cx-x)) (round $ y + yfrc*(cy-y))
|
in io $ warpPointer dpy none root 0 0 0 0
|
||||||
Relative h v ->
|
(round . clip boundsX $ fi rootX)
|
||||||
io $ warpPointer dpy none root 0 0 0 0
|
(round . clip boundsY $ fi rootY)
|
||||||
(rect_x rect + fraction h (rect_width rect))
|
|
||||||
(rect_y rect + fraction v (rect_height rect))
|
|
||||||
where fraction x y = floor (x * fromIntegral y)
|
|
||||||
|
|
||||||
windowAttributesToRectangle :: WindowAttributes -> Rectangle
|
windowAttributesToRectangle :: WindowAttributes -> Rectangle
|
||||||
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa))
|
windowAttributesToRectangle wa = Rectangle (fi (wa_x wa))
|
||||||
(fi (wa_y wa))
|
(fi (wa_y wa))
|
||||||
(fi (wa_width wa + 2 * wa_border_width wa))
|
(fi (wa_width wa + 2 * wa_border_width wa))
|
||||||
(fi (wa_height wa + 2 * wa_border_width wa))
|
(fi (wa_height wa + 2 * wa_border_width wa))
|
||||||
moveWithin :: Ord a => a -> a -> a -> a
|
|
||||||
moveWithin now lower upper =
|
lerp :: (RealFrac r, Real a, Real b) => r -> a -> b -> r
|
||||||
if now < lower
|
lerp r a b = (1 - r) * realToFrac a + r * realToFrac b
|
||||||
then lower
|
|
||||||
else if now > upper
|
clip :: Ord a => (a, a) -> a -> a
|
||||||
then upper
|
clip (lower, upper) x = if x < lower then lower
|
||||||
else now
|
else if x > upper then upper else x
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import XMonad
|
|||||||
import qualified XMonad.StackSet as W
|
import qualified XMonad.StackSet as W
|
||||||
import XMonad.Layout.LayoutModifier
|
import XMonad.Layout.LayoutModifier
|
||||||
|
|
||||||
import XMonad.Actions.UpdatePointer(updatePointer, PointerPosition(TowardsCentre))
|
import XMonad.Actions.UpdatePointer (updatePointer)
|
||||||
import Data.Monoid(All(..))
|
import Data.Monoid(All(..))
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
@ -75,12 +75,12 @@ swap (W.Stack f u d) focused
|
|||||||
-- This eventHook does nothing when there are floating windows on the current
|
-- This eventHook does nothing when there are floating windows on the current
|
||||||
-- workspace.
|
-- workspace.
|
||||||
promoteWarp :: Event -> X All
|
promoteWarp :: Event -> X All
|
||||||
promoteWarp = promoteWarp' (TowardsCentre 0.15 0.15)
|
promoteWarp = promoteWarp' (0.5, 0.5) (0.85, 0.85)
|
||||||
|
|
||||||
-- | promoteWarp' allows you to specify an arbitrary PointerPosition to apply
|
-- | promoteWarp' allows you to specify an arbitrary pair of arguments to
|
||||||
-- when the mouse enters another window.
|
-- pass to 'updatePointer' when the mouse enters another window.
|
||||||
promoteWarp' :: PointerPosition -> Event -> X All
|
promoteWarp' :: (Rational, Rational) -> (Rational, Rational) -> Event -> X All
|
||||||
promoteWarp' pos e@(CrossingEvent {ev_window = w, ev_event_type = t})
|
promoteWarp' refPos ratio e@(CrossingEvent {ev_window = w, ev_event_type = t})
|
||||||
| t == enterNotify && ev_mode e == notifyNormal = do
|
| t == enterNotify && ev_mode e == notifyNormal = do
|
||||||
ws <- gets windowset
|
ws <- gets windowset
|
||||||
let foc = W.peek ws
|
let foc = W.peek ws
|
||||||
@ -88,10 +88,10 @@ promoteWarp' pos e@(CrossingEvent {ev_window = w, ev_event_type = t})
|
|||||||
wsFloats = M.filterWithKey (\k _ -> k `elem` st) $ W.floating ws
|
wsFloats = M.filterWithKey (\k _ -> k `elem` st) $ W.floating ws
|
||||||
if Just w /= foc && M.null wsFloats then do
|
if Just w /= foc && M.null wsFloats then do
|
||||||
windows (W.swapMaster . W.focusWindow w)
|
windows (W.swapMaster . W.focusWindow w)
|
||||||
updatePointer pos
|
updatePointer refPos ratio
|
||||||
return $ All False
|
return $ All False
|
||||||
else return $ All True
|
else return $ All True
|
||||||
promoteWarp' _ _ = return $ All True
|
promoteWarp' _ _ _ = return $ All True
|
||||||
|
|
||||||
-- | Another event hook to override the focusFollowsMouse and make the pointer
|
-- | Another event hook to override the focusFollowsMouse and make the pointer
|
||||||
-- only follow if a given condition is satisfied. This could be used to disable
|
-- only follow if a given condition is satisfied. This could be used to disable
|
||||||
|
Loading…
x
Reference in New Issue
Block a user