Pointer follows focus (with patch)

I sometimes get annoyed at having to get my mouse from several screens over to my current window to click on things I'm working on. I hacked around this by binding a key to Warp.warpToWindow but I'm starting to think there should be the following invariant: the pointer should always be over the focused window. So not only does the focused window follow the pointer as it does now, but the pointer will also follow any window focus.Using the Warp module I got this close to working in my config file. I had lots of keybindings which are modified to look like this: windows W.swapUp >> warpToWindow (1%2) (1%2) What prevents me from getting the invariant I'm aiming for is new or destroyed windows. By adding a new warpToWindow function which takes a window to warp to, and using a ManageHook I got quite close to getting it working for new windows. I had something that looked like this: manageWarp = ask >>= \w -> liftX (warpToWindow w (1%2) (1%2)) >> doF id It worked great for floating windows but not for tiled windows. I think the reason is because the hook management code is done before the layout code, so the pointer just warps to wherever the window asks to be put which becomes wrong as soon as xmonad puts the window into it's proper location. So anyway, I'm starting to think this isn't going to be possible to do in my config. But I think it's possibly closer to the right way to handle the pointer than what exists now. I've included a patch which adds support for a mouseFocusWarpPos config flag to XMonad. It's disabled by default but that could be changed if others like it. Currently it moves the mouse pointer to a relative position within the window the user configures. I'm not entirely happy with this. What might be better is for each window to keep track of where the mouse was and go back there whenever the window regains focus. But that may be too complicated. Feedback appreciated.

On Sun, Feb 03, 2008 at 07:06:50PM +0900, Robert wrote:
I sometimes get annoyed at having to get my mouse from several screens over to my current window to click on things I'm working on.
I hacked around this by binding a key to Warp.warpToWindow but I'm starting to think there should be the following invariant: the pointer should always be over the focused window. So not only does the focused window follow the pointer as it does now, but the pointer will also follow any window focus.Using the Warp module I got this close to working in my config file.
I had lots of keybindings which are modified to look like this:
windows W.swapUp >> warpToWindow (1%2) (1%2)
What prevents me from getting the invariant I'm aiming for is new or destroyed windows.
By adding a new warpToWindow function which takes a window to warp to, and using a ManageHook I got quite close to getting it working for new windows. I had something that looked like this:
manageWarp = ask >>= \w -> liftX (warpToWindow w (1%2) (1%2)) >> doF id
It worked great for floating windows but not for tiled windows. I think the reason is because the hook management code is done before the layout code, so the pointer just warps to wherever the window asks to be put which becomes wrong as soon as xmonad puts the window into it's proper location.
So anyway, I'm starting to think this isn't going to be possible to do in my config. But I think it's possibly closer to the right way to handle the pointer than what exists now. I've included a patch which adds support for a mouseFocusWarpPos config flag to XMonad. It's disabled by default but that could be changed if others like it.
Currently it moves the mouse pointer to a relative position within the window the user configures. I'm not entirely happy with this. What might be better is for each window to keep track of where the mouse was and go back there whenever the window regains focus. But that may be too complicated.
Feedback appreciated.
Have you considered using logHook? It is executed after each windowset change, which should be sufficient. I'd rather not add this feature to the core. Cheers, Spencer Janssen

On Thu, 2008/02/07 15:35:48 -0600, Spencer Janssen wrote:
Have you considered using logHook? It is executed after each windowset change, which should be sufficient.
I tried this, but the pointer warps too often: any time the pointer enters a window, it immediately warps to the specified position in the window. Also, the pointer warps any time the window title changes.

On Sat, Feb 16, 2008 at 12:26:18PM -1000, lithis wrote:
On Thu, 2008/02/07 15:35:48 -0600, Spencer Janssen wrote:
Have you considered using logHook? It is executed after each windowset change, which should be sufficient.
I tried this, but the pointer warps too often: any time the pointer enters a window, it immediately warps to the specified position in the window. Also, the pointer warps any time the window title changes.
So check the pointer position first, if it is contained in the focused window, do nothing, otherwise warp to whichever position.

On Sat, 2008/02/16 17:31:11 -0600, Spencer Janssen wrote:
On Sat, Feb 16, 2008 at 12:26:18PM -1000, lithis wrote:
On Thu, 2008/02/07 15:35:48 -0600, Spencer Janssen wrote:
Have you considered using logHook? It is executed after each windowset change, which should be sufficient.
I tried this, but the pointer warps too often: any time the pointer enters a window, it immediately warps to the specified position in the window. Also, the pointer warps any time the window title changes.
So check the pointer position first, if it is contained in the focused window, do nothing, otherwise warp to whichever position.
I could’t figure out how to do this. Could anyone who knows Haskell and X11 write a function that does this?

lithis wrote:
On Sat, 2008/02/16 17:31:11 -0600, Spencer Janssen wrote:
On Sat, Feb 16, 2008 at 12:26:18PM -1000, lithis wrote:
On Thu, 2008/02/07 15:35:48 -0600, Spencer Janssen wrote:
Have you considered using logHook? It is executed after each windowset change, which should be sufficient.
I tried this, but the pointer warps too often: any time the pointer enters a window, it immediately warps to the specified position in the window. Also, the pointer warps any time the window title changes.
So check the pointer position first, if it is contained in the focused window, do nothing, otherwise warp to whichever position.
I couldâÂÂt figure out how to do this. Could anyone who knows Haskell and X11 write a function that does this?
This is what my previous patch did. I don't know how feasible it is in the context of loghook but the original patch may give you some idea. I'm away on holiday right now so I'll have a look when I get back if you don't get it working first. Spencer: thanks for the suggestion; ideally I'd prefer it in contrib too. If impossible in the current state I suppose I'll see how to make it possible with minimal changes to the base code.

On Fri, Feb 22, 2008 at 10:12:08AM +0900, Robert wrote:
lithis wrote:
On Sat, 2008/02/16 17:31:11 -0600, Spencer Janssen wrote:
On Sat, Feb 16, 2008 at 12:26:18PM -1000, lithis wrote:
On Thu, 2008/02/07 15:35:48 -0600, Spencer Janssen wrote:
Have you considered using logHook? It is executed after each windowset change, which should be sufficient.
I tried this, but the pointer warps too often: any time the pointer enters a window, it immediately warps to the specified position in the window. Also, the pointer warps any time the window title changes.
So check the pointer position first, if it is contained in the focused window, do nothing, otherwise warp to whichever position.
I couldâÂÂt figure out how to do this. Could anyone who knows Haskell and X11 write a function that does this?
This is what my previous patch did. I don't know how feasible it is in the context of loghook but the original patch may give you some idea. I'm away on holiday right now so I'll have a look when I get back if you don't get it working first.
Spencer: thanks for the suggestion; ideally I'd prefer it in contrib too. If impossible in the current state I suppose I'll see how to make it possible with minimal changes to the base code.
Yes, this should be very easy with the code you've already written, I'd forgotten about it! Something like: logHook = withFocused warp With the defn. of warp from your patch. Cheers, Spencer Janssen

Spencer Janssen wrote:
Yes, this should be very easy with the code you've already written, I'd forgotten about it! Something like:
logHook = withFocused warp
With the defn. of warp from your patch.
Thanks, it really was about that easy. logHook is awesome. I've created patch for an UpdateFocus module which I've attached. It does basically what you suggest. It's also documented and updated to only move the mouse to the nearest point of the newly focused window minimising the distance it travels. Thanks also to lithis for looking at this while I was away.

robreim:
Spencer Janssen wrote:
Yes, this should be very easy with the code you've already written, I'd forgotten about it! Something like:
logHook = withFocused warp
With the defn. of warp from your patch.
Thanks, it really was about that easy. logHook is awesome.
I've created patch for an UpdateFocus module which I've attached. It does basically what you suggest. It's also documented and updated to only move the mouse to the nearest point of the newly focused window minimising the distance it travels.
Thanks also to lithis for looking at this while I was away.
Applied, thanks!

Thanks Robert! I got your code to work in my Config.hs without any modifications to xmonad. Here's what I have: pointerFollowsFocus :: Rational -> Rational -> X () pointerFollowsFocus h v = do dpy <- asks display root <- asks theRoot withFocused $ \w -> do wa <- io $ getWindowAttributes dpy w (sameRoot,_,w',_,_,_,_,_) <- io $ queryPointer dpy root if (sameRoot && w == w') then return () else io $ warpPointer dpy none w 0 0 0 0 (fraction h (wa_width wa)) (fraction v (wa_height wa)) where fraction x y = floor (x * fromIntegral y) [...] logHook = dynamicLogWithPP hethraelPP {ppOutput = hPutStrLn xmobar } >> pointerFollowsFocus 1 1 'unless' was not in scope, so I changed it to an if statement. I have found a couple of issues with it, but otherwise it's great. First, the pointer warps when tabs are clicked. The second is a little more complicated. When using a full or tabbed layout, calling focusDown (mod+J) to move from the last window to the first window causes the pointer to warp even if the pointer is in the window. When calling focusUp (mod+K), the pointer always warps unless moving from the master window to the last window.

xmonad:
Thanks Robert! I got your code to work in my Config.hs without any modifications to xmonad. Here's what I have:
pointerFollowsFocus :: Rational -> Rational -> X () pointerFollowsFocus h v = do dpy <- asks display root <- asks theRoot withFocused $ \w -> do wa <- io $ getWindowAttributes dpy w (sameRoot,_,w',_,_,_,_,_) <- io $ queryPointer dpy root if (sameRoot && w == w') then return () else io $ warpPointer dpy none w 0 0 0 0 (fraction h (wa_width wa)) (fraction v (wa_height wa)) where fraction x y = floor (x * fromIntegral y) [...] logHook = dynamicLogWithPP hethraelPP {ppOutput = hPutStrLn xmobar } >> pointerFollowsFocus 1 1
'unless' was not in scope, so I changed it to an if statement.
I have found a couple of issues with it, but otherwise it's great. First, the pointer warps when tabs are clicked. The second is a little more complicated. When using a full or tabbed layout, calling focusDown (mod+J) to move from the last window to the first window causes the pointer to warp even if the pointer is in the window. When calling focusUp (mod+K), the pointer always warps unless moving from the master window to the last window.
Once this is finalised, can we get it as an extension module for mouse/pointer stuff. Saves people reimplementing this functionality
participants (4)
-
Don Stewart
-
lithis
-
Robert
-
Spencer Janssen