mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-07-31 12:11:52 -07:00
X.A.WindowNavigation: fix currentPosition
Now properly deals with an unitialized state (e.g. from a restart) or an inconsistent state (e.g. from using mod-j/k). Deserves cleanup.
This commit is contained in:
@@ -45,25 +45,19 @@ import Graphics.X11.Xlib
|
|||||||
-- - documentation :)
|
-- - documentation :)
|
||||||
-- - tests? (esp. for edge cases in currentPosition)
|
-- - tests? (esp. for edge cases in currentPosition)
|
||||||
-- - solve the 2+3, middle right to bottom left problem
|
-- - solve the 2+3, middle right to bottom left problem
|
||||||
|
-- - manageHook to draw window decos?
|
||||||
|
|
||||||
|
|
||||||
|
type WNState = Map WorkspaceId Point
|
||||||
|
|
||||||
-- go:
|
-- go:
|
||||||
-- 1. get current position, verifying it matches the current window
|
-- 1. get current position, verifying it matches the current window
|
||||||
-- 2. get target windowrect
|
-- 2. get target windowrect
|
||||||
-- 3. focus window
|
-- 3. focus window
|
||||||
-- 4. set new position
|
-- 4. set new position
|
||||||
|
|
||||||
-- key bindings to do the important stuff
|
|
||||||
|
|
||||||
type WNState = Map WorkspaceId Point
|
|
||||||
|
|
||||||
-- 1. Get current position, window
|
|
||||||
-- 2. Determine list of windows in dir from pos, except window
|
|
||||||
-- 3. Grab closest one
|
|
||||||
|
|
||||||
go :: IORef WNState -> Direction -> X ()
|
go :: IORef WNState -> Direction -> X ()
|
||||||
go posRef dir = fromCurrentPoint $ \win pos -> do
|
go posRef dir = fromCurrentPoint $ \win pos -> do
|
||||||
targets <- filter ((/= win) . fst) <$> navigableTargets pos dir
|
targets <- filter ((/= win) . fst) <$> navigableTargets pos dir
|
||||||
io $ putStrLn $ "pos: " ++ show pos ++ "; tgts: " ++ show targets
|
|
||||||
whenJust (listToMaybe targets) $ \(tw, tr) -> do
|
whenJust (listToMaybe targets) $ \(tw, tr) -> do
|
||||||
windows (W.focusWindow tw)
|
windows (W.focusWindow tw)
|
||||||
setPosition posRef pos tr
|
setPosition posRef pos tr
|
||||||
@@ -77,16 +71,27 @@ swap _ _ = return ()
|
|||||||
-- a restart), derives the current position from the current window. Also,
|
-- a restart), derives the current position from the current window. Also,
|
||||||
-- verifies that the position is congruent with the current window (say, if you
|
-- verifies that the position is congruent with the current window (say, if you
|
||||||
-- used mod-j/k or mouse or something).
|
-- used mod-j/k or mouse or something).
|
||||||
-- TODO: replace 0 0 0 0 with 'middle of current window'
|
-- TODO: worry about off-by-one issues with inside definition
|
||||||
-- TODO: correct if not in window, or add logHook
|
|
||||||
currentPosition :: IORef WNState -> X Point
|
currentPosition :: IORef WNState -> X Point
|
||||||
currentPosition posRef = do
|
currentPosition posRef = do
|
||||||
|
root <- asks theRoot
|
||||||
|
currentWindow <- gets (W.peek . windowset)
|
||||||
|
currentRect <- maybe (Rectangle 0 0 0 0) snd <$> windowRect (fromMaybe root currentWindow)
|
||||||
|
|
||||||
wsid <- gets (W.tag . W.workspace . W.current . windowset)
|
wsid <- gets (W.tag . W.workspace . W.current . windowset)
|
||||||
mp <- M.lookup wsid <$> io (readIORef posRef)
|
mp <- M.lookup wsid <$> io (readIORef posRef)
|
||||||
return $ fromMaybe (Point 0 0) mp
|
|
||||||
|
|
||||||
navigableTargets :: Point -> Direction -> X [(Window, Rectangle)]
|
case mp of
|
||||||
navigableTargets point dir = navigable dir point <$> windowRects
|
Just p | p `inside` currentRect -> return p
|
||||||
|
_ -> return (middleOf currentRect)
|
||||||
|
|
||||||
|
where Point px py `inside` Rectangle rx ry rw rh =
|
||||||
|
px >= rx && px < rx + fromIntegral rw &&
|
||||||
|
py >= rx && py < ry + fromIntegral rh
|
||||||
|
|
||||||
|
middleOf (Rectangle x y w h) =
|
||||||
|
Point (x + fromIntegral w `div` 2) (y + fromIntegral h `div` 2)
|
||||||
|
-- return $ fromMaybe (Point 0 0) mp
|
||||||
|
|
||||||
-- TODO: use a smarter algorithm (with memory of last position)
|
-- TODO: use a smarter algorithm (with memory of last position)
|
||||||
setPosition :: IORef WNState -> Point -> Rectangle -> X ()
|
setPosition :: IORef WNState -> Point -> Rectangle -> X ()
|
||||||
@@ -95,6 +100,9 @@ setPosition posRef _ (Rectangle x y w h) = do
|
|||||||
let position = Point (x + (fromIntegral w `div` 2)) (y + (fromIntegral h `div` 2))
|
let position = Point (x + (fromIntegral w `div` 2)) (y + (fromIntegral h `div` 2))
|
||||||
io $ modifyIORef posRef $ M.insert wsid position
|
io $ modifyIORef posRef $ M.insert wsid position
|
||||||
|
|
||||||
|
navigableTargets :: Point -> Direction -> X [(Window, Rectangle)]
|
||||||
|
navigableTargets point dir = navigable dir point <$> windowRects
|
||||||
|
|
||||||
-- Filters and sorts the windows in terms of what is closest from the Point in
|
-- Filters and sorts the windows in terms of what is closest from the Point in
|
||||||
-- the Direction.
|
-- the Direction.
|
||||||
navigable :: Direction -> Point -> [(Window, Rectangle)] -> [(Window, Rectangle)]
|
navigable :: Direction -> Point -> [(Window, Rectangle)] -> [(Window, Rectangle)]
|
||||||
@@ -107,25 +115,22 @@ navigable d pt = sortby d . filter (inr d (fromPoint pt) . snd)
|
|||||||
-- TODO: adjust rectangles based on screen position? (perhaps this is already handled)
|
-- TODO: adjust rectangles based on screen position? (perhaps this is already handled)
|
||||||
windowRects :: X [(Window, Rectangle)]
|
windowRects :: X [(Window, Rectangle)]
|
||||||
windowRects = do
|
windowRects = do
|
||||||
dpy <- asks display
|
|
||||||
wins <- gets (visibleWindows . windowset)
|
wins <- gets (visibleWindows . windowset)
|
||||||
catMaybes <$> mapM (windowRect dpy) wins
|
catMaybes <$> mapM windowRect wins
|
||||||
where visibleWindows wset = concatMap (W.integrate' . W.stack . W.workspace)
|
where visibleWindows wset = concatMap (W.integrate' . W.stack . W.workspace)
|
||||||
(W.current wset : W.visible wset)
|
(W.current wset : W.visible wset)
|
||||||
|
|
||||||
windowRect :: Display -> Window -> X (Maybe (Window, Rectangle))
|
windowRect :: Window -> X (Maybe (Window, Rectangle))
|
||||||
windowRect dpy win = do
|
windowRect win = withDisplay $ \dpy -> do
|
||||||
(_, x, y, w, h, _, _) <- io $ getGeometry dpy win
|
(_, x, y, w, h, _, _) <- io $ getGeometry dpy win
|
||||||
return $ Just $ (win, Rectangle x y w h)
|
return $ Just $ (win, Rectangle x y w h)
|
||||||
`catchX` return Nothing
|
`catchX` return Nothing
|
||||||
|
|
||||||
-- manageHook to draw window decos?
|
|
||||||
|
|
||||||
fromPoint :: Point -> FPoint
|
fromPoint :: Point -> FPoint
|
||||||
fromPoint p = P (fromIntegral $ pt_x p) (fromIntegral $ pt_y p)
|
fromPoint p = P (fromIntegral $ pt_x p) (fromIntegral $ pt_y p)
|
||||||
|
|
||||||
-- Stolen from droundy's implementation of WindowNavigation. I should probably take the time
|
-- Stolen from droundy's implementation of WindowNavigation.
|
||||||
-- to understand the black magic below at some point.
|
-- TODO: refactor, perhaps
|
||||||
|
|
||||||
data FPoint = P Double Double
|
data FPoint = P Double Double
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user