<commit_before>-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Layout.FloatSnap
-- Copyright   :  (c) 2009 <NAME> <<EMAIL>>
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  none
-- Stability   :  unstable
-- Portability :  unportable
--
-- Move and resize floating windows using other windows and the edge of the
-- screen as guidelines.
-----------------------------------------------------------------------------

module XMonad.Actions.FloatSnap (
                -- * Usage
                -- $usage
                Direction(..),
                snapMove,
                snapGrow,
                snapShrink,
                snapMagicMove,
                snapMagicResize) where

import XMonad
import Data.List (sort)
import Data.Maybe (listToMaybe,fromJust,isNothing)
import qualified XMonad.StackSet as W

import XMonad.Hooks.ManageDocks (Direction(..))

-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- >    import XMonad.Actions.FloatSnap
--
-- Then add appropriate key bindings, for example:
--
-- >        , ((modMask x,               xK_Left),  withFocused $ snapMove L Nothing)
-- >        , ((modMask x,               xK_Right), withFocused $ snapMove R Nothing)
-- >        , ((modMask x,               xK_Up),    withFocused $ snapMove U Nothing)
-- >        , ((modMask x,               xK_Down),  withFocused $ snapMove D Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Left),  withFocused $ snapShrink R Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Right), withFocused $ snapGrow R Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Up),    withFocused $ snapShrink D Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Down),  withFocused $ snapGrow D Nothing)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
--
-- And possibly add an appropriate mouse binding, for example:
--
-- >        , ((modMask x, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicMove (Just 50) (Just 50) w))
-- >        , ((modMask x, button3), (\w -> focus w >> mouseResizeWindow w >> snapMagicResize (Just 50) (Just 50) w))
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
--
-- Using these mouse bindings, it will not snap while moving, but allow you to click the window once after it has been moved or resized to snap it into place.
-- Note that the order in which the commands are applied in the mouse bindings are important.
--
-- Interesting values for the distance to look for window in the orthogonal axis are Nothing (to snap against every window), Just 0 (to only snap
-- against windows that we should collide with geometrically while moving) and Just 1 (to also snap against windows we brush against).
--
-- For 'snapMagicMove' and 'snapMagicResize', try instead setting it to the same as the maximum snapping distance.
--
-- When a value is specified it can be geometrically conceived as adding a border with the specified width around the window and then checking which
-- windows it should collide with.

-- | Resize the window by each edge independently to snap against the closest part of other windows or the edge of the screen.
snapMagicResize ::
       Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
    -> Window    -- ^ The window to move and resize.
    -> X ()
snapMagicResize collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w

    (nx,nw) <- handleAxis True d wa
    (ny,nh) <- handleAxis False d wa

    io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
    io $ resizeWindow d w (fromIntegral nw) (fromIntegral nh)
    float w
    where
        handleAxis horiz d wa = do
            ((mbl,mbr,bs),(mfl,mfr,fs)) <- getSnap horiz collidedist d w
            let begin = if bs
                        then wpos wa
                        else case (mbl,mbr) of
                            (Just bl,Just br) -> if wpos wa - bl < br - wpos wa then bl else br
                            (Just bl,Nothing) -> bl
                            (Nothing,Just br) -> br
                            (Nothing,Nothing) -> wpos wa
                end = if fs
                      then wpos wa + wdim wa
                      else case (if mfl==(Just begin) then Nothing else mfl,mfr) of
                          (Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
                          (Just fl,Nothing) -> fl
                          (Nothing,Just fr) -> fr
                          (Nothing,Nothing) -> wpos wa + wdim wa
                begin' = if isNothing snapdist || abs (begin - wpos wa) <= fromJust snapdist then begin else (wpos wa)
                end' = if isNothing snapdist || abs (end - wpos wa - wdim wa) <= fromJust snapdist then end else (wpos wa + wdim wa)
            return (begin',end'-begin')
            where
                (wpos, wdim, _, _) = constructors horiz


-- | Move a window by both axises in any direction to snap against the closest part of other windows or the edge of the screen.
snapMagicMove ::
       Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
    -> Window    -- ^ The window to move.
    -> X ()
snapMagicMove collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w

    nx <- handleAxis True d wa
    ny <- handleAxis False d wa

    io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
    float w
    where
        handleAxis horiz d wa = do
            ((mbl,mbr,bs),(mfl,mfr,fs)) <- getSnap horiz collidedist d w
            return $ if bs || fs
                     then wpos wa
                     else let b = case (mbl,mbr) of
                                    (Just bl,Just br) -> if wpos wa - bl < br - wpos wa then bl else br
                                    (Just bl,Nothing) -> bl
                                    (Nothing,Just br) -> br
                                    (Nothing,Nothing) -> wpos wa
                              f = case (mfl,mfr) of
                                    (Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
                                    (Just fl,Nothing) -> fl
                                    (Nothing,Just fr) -> fr
                                    (Nothing,Nothing) -> wpos wa
                              newpos = if abs (b - wpos wa) <= abs (f - wpos wa - wdim wa) then b else (f - wdim wa)
                          in if isNothing snapdist || abs (newpos - wpos wa) <= fromJust snapdist then newpos else (wpos wa)
            where
                (wpos, wdim, _, _) = constructors horiz

-- | Move a window in the specified direction until it snaps against another window or the edge of the screen.
snapMove ::
       Direction -- ^ What direction to move the window in.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Window    -- ^ The window to move.
    -> X ()
snapMove L = doSnapMove True True
snapMove R = doSnapMove True False
snapMove U = doSnapMove False True
snapMove D = doSnapMove False False

doSnapMove :: Bool -> Bool -> Maybe Int -> Window -> X ()
doSnapMove horiz rev collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w
    ((bl,br,_),(fl,fr,_)) <- getSnap horiz collidedist d w

    let (mb,mf) = if rev then (bl,fl)
                         else (br,fr)

        newpos = fromIntegral $ case (mb,mf) of
                                    (Just b,Nothing) -> b
                                    (Nothing,Just f) -> f - wdim wa
                                    (Just b,Just f) -> if rev /= (b < f - wdim wa)
                                                       then b
                                                       else f - wdim wa
                                    _ -> wpos wa

    if horiz then io $ moveWindow d w newpos (fromIntegral $ wa_y wa)
             else io $ moveWindow d w (fromIntegral $ wa_x wa) newpos
    float w

    where
        (wpos, wdim, _, _) = constructors horiz

-- | Grow the specified edge of a window until it snaps against another window or the edge of the screen.
snapGrow ::
       Direction -- ^ What edge of the window to grow.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Window    -- ^ The window to grow.
    -> X ()
snapGrow = snapResize True

-- | Shrink the specified edge of a window until it snaps against another window or the edge of the screen.
snapShrink ::
       Direction -- ^ What edge of the window to shrink.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Window    -- ^ The window to grow.
    -> X ()
snapShrink = snapResize False

snapResize :: Bool -> Direction -> Maybe Int -> Window -> X ()
snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w<commit_msg>X.A.FloatSnap - More configuration for magic resize, adaption for mouse bindings and some minor fixes<commit_after>-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Layout.FloatSnap
-- Copyright   :  (c) 2009 <NAME> <<EMAIL>>
-- License     :  BSD3-style (see LICENSE)
--
-- Maintainer  :  none
-- Stability   :  unstable
-- Portability :  unportable
--
-- Move and resize floating windows using other windows and the edge of the
-- screen as guidelines.
-----------------------------------------------------------------------------

module XMonad.Actions.FloatSnap (
                -- * Usage
                -- $usage
                Direction(..),
                snapMove,
                snapGrow,
                snapShrink,
                snapMagicMove,
                snapMagicResize,
                snapMagicMouseResize) where

import XMonad
import Data.List (sort)
import Data.Maybe (listToMaybe,fromJust,isNothing)
import qualified XMonad.StackSet as W

import XMonad.Hooks.ManageDocks (Direction(..))

-- $usage
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
--
-- >    import XMonad.Actions.FloatSnap
--
-- Then add appropriate key bindings, for example:
--
-- >        , ((modMask x,               xK_Left),  withFocused $ snapMove L Nothing)
-- >        , ((modMask x,               xK_Right), withFocused $ snapMove R Nothing)
-- >        , ((modMask x,               xK_Up),    withFocused $ snapMove U Nothing)
-- >        , ((modMask x,               xK_Down),  withFocused $ snapMove D Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Left),  withFocused $ snapShrink R Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Right), withFocused $ snapGrow R Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Up),    withFocused $ snapShrink D Nothing)
-- >        , ((modMask x .|. shiftMask, xK_Down),  withFocused $ snapGrow D Nothing)
--
-- For detailed instructions on editing your key bindings, see
-- "XMonad.Doc.Extending#Editing_key_bindings".
--
-- And possibly add an appropriate mouse binding, for example:
--
-- >        , ((modMask x,               button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicMove (Just 50) (Just 50) w))
-- >        , ((modMask x .|. shiftMask, button1), (\w -> focus w >> mouseMoveWindow w >> snapMagicResize [L,R,U,D] (Just 50) (Just 50) w))
-- >        , ((modMask x,               button3), (\w -> focus w >> mouseResizeWindow w >> snapMagicResize [R,D] (Just 50) (Just 50) w))
--
-- For detailed instructions on editing your mouse bindings, see
-- "XMonad.Doc.Extending#Editing_mouse_bindings".
--
-- Using these mouse bindings, it will not snap while moving, but allow you to click the window once after it has been moved or resized to snap it into place.
-- Note that the order in which the commands are applied in the mouse bindings are important.
--
-- Interesting values for the distance to look for window in the orthogonal axis are Nothing (to snap against every window), Just 0 (to only snap
-- against windows that we should collide with geometrically while moving) and Just 1 (to also snap against windows we brush against).
--
-- For 'snapMagicMove', 'snapMagicResize' and 'snapMagicMouseResize', try instead setting it to the same as the maximum snapping distance.
--
-- When a value is specified it can be geometrically conceived as adding a border with the specified width around the window and then checking which
-- windows it should collide with.

-- | Resize the window by each edge independently to snap against the closest part of other windows or the edge of the screen. Use the location of the
--   mouse over the window to decide which edges to snap. In corners, the two adjoining edges will be snapped, along the middle of an edge only that edge
--   will be snapped. In the center of the window all edges will snap. Intended to be used together with "XMonad.Actions.FlexibleResize" or
--   "XMonad.Actions.FlexibleManipulate".
snapMagicMouseResize
    :: Rational  -- ^ How big the middle snap area of each axis should be.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
    -> Window    -- ^ The window to move and resize.
    -> X ()
snapMagicMouseResize middle collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
    wa <- io $ getWindowAttributes d w
    (_, _, _, px, py, _, _, _) <- io $ queryPointer d w
    let x = (fromIntegral px - wx wa)/(ww wa)
        y = (fromIntegral py - wy wa)/(wh wa)
        ml = if x <= (0.5 - middle/2) then [L] else []
        mr = if x >  (0.5 + middle/2) then [R] else []
        mu = if y <= (0.5 - middle/2) then [U] else []
        md = if y >  (0.5 + middle/2) then [D] else []
        mdir = ml++mr++mu++md
        dir = if mdir == []
              then [L,R,U,D]
              else mdir
    snapMagicResize dir collidedist snapdist w
    where
        wx = fromIntegral.wa_x
        wy = fromIntegral.wa_y
        ww = fromIntegral.wa_width
        wh = fromIntegral.wa_height

-- | Resize the window by each edge independently to snap against the closest part of other windows or the edge of the screen.
snapMagicResize
    :: [Direction] -- ^ The edges to snap.
    -> Maybe Int   -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Maybe Int   -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
    -> Window      -- ^ The window to move and resize.
    -> X ()
snapMagicResize dir collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w

    (xbegin,xend) <- handleAxis True d wa
    (ybegin,yend) <- handleAxis False d wa

    let xbegin' = if L `elem` dir then xbegin else (wx wa)
        xend'   = if R `elem` dir then xend   else (wx wa + ww wa)
        ybegin' = if U `elem` dir then ybegin else (wy wa)
        yend'   = if D `elem` dir then yend   else (wy wa + wh wa)

    io $ moveWindow d w (fromIntegral $ xbegin') (fromIntegral $ ybegin')
    io $ resizeWindow d w (fromIntegral $ xend' - xbegin') (fromIntegral $ yend' - ybegin')
    float w
    where
        wx = fromIntegral.wa_x
        wy = fromIntegral.wa_y
        ww = fromIntegral.wa_width
        wh = fromIntegral.wa_height

        handleAxis horiz d wa = do
            ((mbl,mbr,bs),(mfl,mfr,fs)) <- getSnap horiz collidedist d w
            let begin = if bs
                        then wpos wa
                        else case (mbl,mbr) of
                            (Just bl,Just br) -> if wpos wa - bl < br - wpos wa then bl else br
                            (Just bl,Nothing) -> bl
                            (Nothing,Just br) -> br
                            (Nothing,Nothing) -> wpos wa
                end = if fs
                      then wpos wa + wdim wa
                      else case (if mfl==(Just begin) then Nothing else mfl,mfr) of
                          (Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
                          (Just fl,Nothing) -> fl
                          (Nothing,Just fr) -> fr
                          (Nothing,Nothing) -> wpos wa + wdim wa
                begin' = if isNothing snapdist || abs (begin - wpos wa) <= fromJust snapdist then begin else (wpos wa)
                end' = if isNothing snapdist || abs (end - wpos wa - wdim wa) <= fromJust snapdist then end else (wpos wa + wdim wa)
            return (begin',end')
            where
                (wpos, wdim, _, _) = constructors horiz


-- | Move a window by both axises in any direction to snap against the closest part of other windows or the edge of the screen.
snapMagicMove
    :: Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Maybe Int -- ^ The maximum distance to snap. Use Nothing to not impose any boundary.
    -> Window    -- ^ The window to move.
    -> X ()
snapMagicMove collidedist snapdist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w

    nx <- handleAxis True d wa
    ny <- handleAxis False d wa

    io $ moveWindow d w (fromIntegral nx) (fromIntegral ny)
    float w
    where
        handleAxis horiz d wa = do
            ((mbl,mbr,bs),(mfl,mfr,fs)) <- getSnap horiz collidedist d w
            return $ if bs || fs
                     then wpos wa
                     else let b = case (mbl,mbr) of
                                    (Just bl,Just br) -> if wpos wa - bl < br - wpos wa then bl else br
                                    (Just bl,Nothing) -> bl
                                    (Nothing,Just br) -> br
                                    (Nothing,Nothing) -> wpos wa
                              f = case (mfl,mfr) of
                                    (Just fl,Just fr) -> if wpos wa + wdim wa - fl < fr - wpos wa - wdim wa then fl else fr
                                    (Just fl,Nothing) -> fl
                                    (Nothing,Just fr) -> fr
                                    (Nothing,Nothing) -> wpos wa
                              newpos = if abs (b - wpos wa) <= abs (f - wpos wa - wdim wa) then b else (f - wdim wa)
                          in if isNothing snapdist || abs (newpos - wpos wa) <= fromJust snapdist then newpos else (wpos wa)
            where
                (wpos, wdim, _, _) = constructors horiz

-- | Move a window in the specified direction until it snaps against another window or the edge of the screen.
snapMove
    :: Direction -- ^ What direction to move the window in.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Window    -- ^ The window to move.
    -> X ()
snapMove L = doSnapMove True True
snapMove R = doSnapMove True False
snapMove U = doSnapMove False True
snapMove D = doSnapMove False False

doSnapMove :: Bool -> Bool -> Maybe Int -> Window -> X ()
doSnapMove horiz rev collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
    wa <- io $ getWindowAttributes d w
    ((bl,br,_),(fl,fr,_)) <- getSnap horiz collidedist d w

    let (mb,mf) = if rev then (bl,fl)
                         else (br,fr)

        newpos = fromIntegral $ case (mb,mf) of
                                    (Just b,Nothing) -> b
                                    (Nothing,Just f) -> f - wdim wa
                                    (Just b,Just f) -> if rev /= (b < f - wdim wa)
                                                       then b
                                                       else f - wdim wa
                                    _ -> wpos wa

    if horiz then io $ moveWindow d w newpos (fromIntegral $ wa_y wa)
             else io $ moveWindow d w (fromIntegral $ wa_x wa) newpos
    float w

    where
        (wpos, wdim, _, _) = constructors horiz

-- | Grow the specified edge of a window until it snaps against another window or the edge of the screen.
snapGrow
    :: Direction -- ^ What edge of the window to grow.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Window    -- ^ The window to grow.
    -> X ()
snapGrow = snapResize True

-- | Shrink the specified edge of a window until it snaps against another window or the edge of the screen.
snapShrink
    :: Direction -- ^ What edge of the window to shrink.
    -> Maybe Int -- ^ The distance in the orthogonal axis to look for windows to snap against. Use Nothing to snap against every window.
    -> Window    -- ^ The window to shrink.
    -> X ()
snapShrink = snapResize False

snapResize :: Bool -> Direction -> Maybe Int -> Window -> X ()
snapResize grow dir collidedist w = whenX (isClient w) $ withDisplay $ \d -> do
    io $ raiseWindow d w
{'fraction_non_alphanumeric': 0.10405893927607193, 'fraction_numerical': 0.0023337756829725897, 'mean_word_length': 1.7447877417734237, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3190980', 'n_tokens_mistral': 6161, 'n_tokens_neox': 5901, 'n_words': 2560}