    -----------------------------------------------------------------------------
    -- |
    -- Module      :  XMonad.Actions.FlexibleResize
    -- Copyright   :  (c) Lukas Mai
    -- License     :  BSD3-style (see LICENSE)
    --
    -- Maintainer  :  <l.mai@web.de>
    -- Stability   :  unstable
    -- Portability :  unportable
    --
    -- Resize floating windows from any corner.
    --
    -----------------------------------------------------------------------------

    module XMonad.Actions.FlexibleResize (
            -- * Usage
            -- $usage
            XMonad.Actions.FlexibleResize.mouseResizeWindow,
            XMonad.Actions.FlexibleResize.mouseResizeEdgeWindow
    ) where

    import XMonad
    import Foreign.C.Types

    -- $usage
    -- To use, first import this module into your @~\/.xmonad\/xmonad.hs@ file:
    --
    -- > import qualified XMonad.Actions.FlexibleResize as Flex
    --
    -- Then add an appropriate mouse binding:
    --
    -- >     , ((modm, button3), (\w -> focus w >> Flex.mouseResizeWindow w))
    --
    -- For detailed instructions on editing your mouse bindings, see
    -- "XMonad.Doc.Extending#Editing_mouse_bindings".

    -- | Resize a floating window from whichever corner the mouse is
    --   closest to.
    mouseResizeWindow
      :: Window -- ^ The window to resize.
      -> X ()
    mouseResizeWindow = mouseResizeEdgeWindow 0

    -- | Resize a floating window from whichever corner or edge the mouse is
    --   closest to.
    mouseResizeEdgeWindow
      :: Rational -- ^ The size of the area where only one edge is resized.
      -> Window   -- ^ The window to resize.
      -> X ()
    mouseResizeEdgeWindow edge w = whenX (isClient w) $ withDisplay $ \d -> do
        io $ raiseWindow d w
        wa <- io $ getWindowAttributes d w
        sh <- io $ getWMNormalHints d w
        (_, _, _, _, _, ix, iy, _) <- io $ queryPointer d w
        let
            [pos_x, pos_y, width, height] = map (fi . ($ wa)) [wa_x, wa_y, wa_width, wa_height]
            west  = findPos ix width
            north = findPos iy height
            (cx, fx, gx) = mkSel west  width  pos_x
            (cy, fy, gy) = mkSel north height pos_y
        io $ warpPointer d none w 0 0 0 0 cx cy
        mouseDrag (\ex ey -> do let (nw,nh) = applySizeHintsContents sh (gx ex, gy ey)
                                io $ moveResizeWindow d w (fx nw) (fy nh) nw nh)
                  (float w)
        where
        findPos :: CInt -> Position -> Maybe Bool
        findPos m s = if p < 0.5 - edge/2
                      then Just True
                      else if p < 0.5 + edge/2
                           then Nothing
                           else Just False
                      where p = fi m / fi s
        mkSel :: Maybe Bool -> Position -> Position -> (Position, Dimension -> Position, Position -> Dimension)
        mkSel b k p = case b of
                          Just True ->  (0, (fi k + fi p -).fi, (fi k + fi p -).fi)
                          Nothing ->    (k `div` 2, const p, const $ fi k)
                          Just False -> (k, const p, subtract (fi p) . fi)

    fi :: (Num b, Integral a) => a -> b
    fi = fromIntegral