-----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Actions.FlexibleResize
-- Description :  Resize floating windows from any corner.
-- 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 XMonad.Prelude (fi)
import Foreign.C.Types

-- $usage
-- To use, first import this module into your @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 :: Window -> X ()
mouseResizeWindow = Rational -> Window -> X ()
mouseResizeEdgeWindow Rational
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 :: Rational -> Window -> X ()
mouseResizeEdgeWindow Rational
edge Window
w = X Bool -> X () -> X ()
whenX (Window -> X Bool
isClient Window
w) forall a b. (a -> b) -> a -> b
$ forall a. (Display -> X a) -> X a
withDisplay forall a b. (a -> b) -> a -> b
$ \Display
d ->
  Display -> Window -> (WindowAttributes -> X ()) -> X ()
withWindowAttributes Display
d Window
w forall a b. (a -> b) -> a -> b
$ \WindowAttributes
wa -> do
    SizeHints
sh <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display -> Window -> IO SizeHints
getWMNormalHints Display
d Window
w
    (Bool
_, Window
_, Window
_, CInt
_, CInt
_, CInt
ix, CInt
iy, Modifier
_) <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display
-> Window
-> IO (Bool, Window, Window, CInt, CInt, CInt, CInt, Modifier)
queryPointer Display
d Window
w
    let
        pos_x :: Position
pos_x  = forall a b. (Integral a, Num b) => a -> b
fi forall a b. (a -> b) -> a -> b
$ WindowAttributes -> CInt
wa_x WindowAttributes
wa
        pos_y :: Position
pos_y  = forall a b. (Integral a, Num b) => a -> b
fi forall a b. (a -> b) -> a -> b
$ WindowAttributes -> CInt
wa_y WindowAttributes
wa
        width :: Position
width  = forall a b. (Integral a, Num b) => a -> b
fi forall a b. (a -> b) -> a -> b
$ WindowAttributes -> CInt
wa_width WindowAttributes
wa
        height :: Position
height = forall a b. (Integral a, Num b) => a -> b
fi forall a b. (a -> b) -> a -> b
$ WindowAttributes -> CInt
wa_height WindowAttributes
wa
        west :: Maybe Bool
west  = CInt -> Position -> Maybe Bool
findPos CInt
ix Position
width
        north :: Maybe Bool
north = CInt -> Position -> Maybe Bool
findPos CInt
iy Position
height
        (Position
cx, Dimension -> Position
fx, Position -> Dimension
gx) = Maybe Bool
-> Position
-> Position
-> (Position, Dimension -> Position, Position -> Dimension)
mkSel Maybe Bool
west  Position
width  Position
pos_x
        (Position
cy, Dimension -> Position
fy, Position -> Dimension
gy) = Maybe Bool
-> Position
-> Position
-> (Position, Dimension -> Position, Position -> Dimension)
mkSel Maybe Bool
north Position
height Position
pos_y
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display
-> Window
-> Window
-> Position
-> Position
-> Dimension
-> Dimension
-> Position
-> Position
-> IO ()
warpPointer Display
d Window
none Window
w Position
0 Position
0 Dimension
0 Dimension
0 Position
cx Position
cy
    (Position -> Position -> X ()) -> X () -> X ()
mouseDrag (\Position
ex Position
ey -> do let (Dimension
nw,Dimension
nh) = forall a.
Integral a =>
SizeHints -> (a, a) -> (Dimension, Dimension)
applySizeHintsContents SizeHints
sh (Position -> Dimension
gx Position
ex, Position -> Dimension
gy Position
ey)
                            forall (m :: * -> *) a. MonadIO m => IO a -> m a
io forall a b. (a -> b) -> a -> b
$ Display
-> Window
-> Position
-> Position
-> Dimension
-> Dimension
-> IO ()
moveResizeWindow Display
d Window
w (Dimension -> Position
fx Dimension
nw) (Dimension -> Position
fy Dimension
nh) Dimension
nw Dimension
nh
                            Window -> X ()
float Window
w)
              (Window -> X ()
float Window
w)
    where
    findPos :: CInt -> Position -> Maybe Bool
    findPos :: CInt -> Position -> Maybe Bool
findPos CInt
m Position
s
      | Rational
p forall a. Ord a => a -> a -> Bool
< Rational
0.5 forall a. Num a => a -> a -> a
- Rational
edgeforall a. Fractional a => a -> a -> a
/Rational
2 = forall a. a -> Maybe a
Just Bool
True
      | Rational
p forall a. Ord a => a -> a -> Bool
< Rational
0.5 forall a. Num a => a -> a -> a
+ Rational
edgeforall a. Fractional a => a -> a -> a
/Rational
2 = forall a. Maybe a
Nothing
      | Bool
otherwise = forall a. a -> Maybe a
Just Bool
False
      where
          p :: Rational
p = forall a b. (Integral a, Num b) => a -> b
fi CInt
m forall a. Fractional a => a -> a -> a
/ forall a b. (Integral a, Num b) => a -> b
fi Position
s
    mkSel :: Maybe Bool -> Position -> Position -> (Position, Dimension -> Position, Position -> Dimension)
    mkSel :: Maybe Bool
-> Position
-> Position
-> (Position, Dimension -> Position, Position -> Dimension)
mkSel Maybe Bool
b Position
k Position
p = case Maybe Bool
b of
                      Just Bool
True ->  (Position
0, (forall a b. (Integral a, Num b) => a -> b
fi Position
k forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fi Position
p forall a. Num a => a -> a -> a
-)forall b c a. (b -> c) -> (a -> b) -> a -> c
.forall a b. (Integral a, Num b) => a -> b
fi, (forall a b. (Integral a, Num b) => a -> b
fi Position
k forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fi Position
p forall a. Num a => a -> a -> a
-)forall b c a. (b -> c) -> (a -> b) -> a -> c
.forall a b. (Integral a, Num b) => a -> b
fi)
                      Maybe Bool
Nothing ->    (Position
k forall a. Integral a => a -> a -> a
`div` Position
2, forall a b. a -> b -> a
const Position
p, forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fi Position
k)
                      Just Bool
False -> (Position
k, forall a b. a -> b -> a
const Position
p, forall a. Num a => a -> a -> a
subtract (forall a b. (Integral a, Num b) => a -> b
fi Position
p) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fi)