{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.X11.Xlib.Region
-- Copyright   :  (c) Alastair Reid, 1999-2003
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  portable
--
-- A collection of FFI declarations for interfacing with Xlib Regions.
--
-----------------------------------------------------------------------------

module Graphics.X11.Xlib.Region(
        Region,

        RectInRegionResult,
        rectangleOut,
        rectangleIn,
        rectanglePart,

        createRegion,
        polygonRegion,
        intersectRegion,
        subtractRegion,
        unionRectWithRegion,
        unionRegion,
        xorRegion,
        emptyRegion,
        equalRegion,
        pointInRegion,
        rectInRegion,
        clipBox,
        offsetRegion,
        shrinkRegion,
        setRegion,

        ) where

import Graphics.X11.Types
import Graphics.X11.Xlib.Types

import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.C.Types
import Foreign.Storable
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Marshal.Utils

#if __GLASGOW_HASKELL__
import Data.Data
#endif

----------------------------------------------------------------
-- Regions
----------------------------------------------------------------

newtype Region = Region (ForeignPtr Region)
#if __GLASGOW_HASKELL__
        deriving (Eq, Ord, Show, Typeable, Data)
#else
        deriving (Eq, Ord, Show)
#endif

withRegion :: Region -> (Ptr Region -> IO a) -> IO a
withRegion (Region r) = withForeignPtr r

type RectInRegionResult = CInt

-- Return values from XRectInRegion()
rectangleOut, rectangleIn, rectanglePart :: RectInRegionResult
rectangleOut  = 0
rectangleIn   = 1
rectanglePart = 2

----------------------------------------------------------------
-- Creating regions
----------------------------------------------------------------

-- regions deallocation is handled by the GC (ForeignPtr magic)
-- so we don't provide XDestroyRegion explicitly
-- no idea what the int is for
-- %fun XDestroyRegion :: Region -> IO Int
foreign import ccall unsafe "HsXlib.h &XDestroyRegion"
        xDestroyRegionPtr :: FunPtr (Ptr Region -> IO ())

makeRegion :: Ptr Region -> IO Region
makeRegion rp = do
        r <- newForeignPtr xDestroyRegionPtr rp
        return (Region r)

-- an empty region
-- (often used as "out argument" to binary operators which return regions)

-- | interface to the X11 library function @XCreateRegion()@.
createRegion :: IO Region
createRegion = do
        rp <- xCreateRegion
        makeRegion rp
foreign import ccall unsafe "HsXlib.h XCreateRegion"
        xCreateRegion :: IO (Ptr Region)

-- | interface to the X11 library function @XPolygonRegion()@.
polygonRegion :: [Point] -> FillRule -> IO Region
polygonRegion points fill_rule =
        withArrayLen points $ \ n point_arr -> do
        rp <- xPolygonRegion point_arr (fromIntegral n) fill_rule
        makeRegion rp
foreign import ccall unsafe "HsXlib.h XPolygonRegion"
        xPolygonRegion :: Ptr Point -> CInt -> FillRule -> IO (Ptr Region)

----------------------------------------------------------------
-- Combining Regions
--
-- The usual shoddy state of Xlib documentation fails to mention
-- what the Int is for.
--
-- All operations overwrite the region in their third argument
-- which is usually a freshly created region.
----------------------------------------------------------------

-- | interface to the X11 library function @XIntersectRegion()@.
intersectRegion     :: Region -> Region -> Region -> IO CInt
intersectRegion src1 src2 dest =
        withRegion src1 $ \ src1_ptr ->
        withRegion src2 $ \ src2_ptr ->
        withRegion dest $ \ dest_ptr ->
        xIntersectRegion src1_ptr src2_ptr dest_ptr
foreign import ccall unsafe
        "HsXlib.h XIntersectRegion" xIntersectRegion ::
        Ptr Region -> Ptr Region -> Ptr Region -> IO CInt

-- | interface to the X11 library function @XSubtractRegion()@.
subtractRegion     :: Region -> Region -> Region -> IO CInt
subtractRegion src1 src2 dest =
        withRegion src1 $ \ src1_ptr ->
        withRegion src2 $ \ src2_ptr ->
        withRegion dest $ \ dest_ptr ->
        xSubtractRegion src1_ptr src2_ptr dest_ptr
foreign import ccall unsafe
        "HsXlib.h XSubtractRegion" xSubtractRegion ::
        Ptr Region -> Ptr Region -> Ptr Region -> IO CInt

-- | interface to the X11 library function @XUnionRectWithRegion()@.
unionRectWithRegion     :: Rectangle -> Region -> Region -> IO CInt
unionRectWithRegion rect src dest =
        with rect $ \ rect_ptr ->
        withRegion src $ \ src_ptr ->
        withRegion dest $ \ dest_ptr ->
        xUnionRectWithRegion rect_ptr src_ptr dest_ptr
foreign import ccall unsafe
        "HsXlib.h XUnionRectWithRegion" xUnionRectWithRegion ::
        Ptr Rectangle -> Ptr Region -> Ptr Region -> IO CInt

-- | interface to the X11 library function @XUnionRegion()@.
unionRegion     :: Region -> Region -> Region -> IO CInt
unionRegion src1 src2 dest =
        withRegion src1 $ \ src1_ptr ->
        withRegion src2 $ \ src2_ptr ->
        withRegion dest $ \ dest_ptr ->
        xUnionRegion src1_ptr src2_ptr dest_ptr
foreign import ccall unsafe
        "HsXlib.h XUnionRegion" xUnionRegion ::
        Ptr Region -> Ptr Region -> Ptr Region -> IO CInt

-- | interface to the X11 library function @XXorRegion()@.
xorRegion     :: Region -> Region -> Region -> IO CInt
xorRegion src1 src2 dest =
        withRegion src1 $ \ src1_ptr ->
        withRegion src2 $ \ src2_ptr ->
        withRegion dest $ \ dest_ptr ->
        xXorRegion src1_ptr src2_ptr dest_ptr
foreign import ccall unsafe
        "HsXlib.h XXorRegion" xXorRegion ::
        Ptr Region -> Ptr Region -> Ptr Region -> IO CInt

----------------------------------------------------------------
-- Examining regions (tests, bounding boxes, etc)
----------------------------------------------------------------

-- | interface to the X11 library function @XEmptyRegion()@.
emptyRegion :: Region -> IO Bool
emptyRegion r = withRegion r xEmptyRegion
foreign import ccall unsafe "HsXlib.h XEmptyRegion"
        xEmptyRegion :: Ptr Region -> IO Bool

-- | interface to the X11 library function @XEqualRegion()@.
equalRegion :: Region -> Region -> IO Bool
equalRegion r1 r2 =
        withRegion r1 $ \ rp1 ->
        withRegion r2 $ \ rp2 ->
        xEqualRegion rp1 rp2
foreign import ccall unsafe "HsXlib.h XEqualRegion"
        xEqualRegion :: Ptr Region -> Ptr Region -> IO Bool

-- | interface to the X11 library function @XPointInRegion()@.
pointInRegion :: Region -> Point -> IO Bool
pointInRegion r (Point x y) =
        withRegion r $ \ rp ->
        xPointInRegion rp x y
foreign import ccall unsafe "HsXlib.h XPointInRegion"
        xPointInRegion :: Ptr Region -> Position -> Position -> IO Bool

-- | interface to the X11 library function @XRectInRegion()@.
rectInRegion :: Region -> Rectangle -> IO RectInRegionResult
rectInRegion r (Rectangle x y w h) =
        withRegion r $ \ rp ->
        xRectInRegion rp x y w h
foreign import ccall unsafe "HsXlib.h XRectInRegion"
        xRectInRegion :: Ptr Region -> Position -> Position ->
                Dimension -> Dimension -> IO RectInRegionResult

-- I have no idea what the int is for

-- | interface to the X11 library function @XClipBox()@.
clipBox :: Region -> IO (Rectangle,CInt)
clipBox r =
        withRegion r $ \ rp ->
        alloca $ \ rect_ptr -> do
        res <- xClipBox rp rect_ptr
        rect <- peek rect_ptr
        return (rect, res)
foreign import ccall unsafe "HsXlib.h XClipBox"
        xClipBox :: Ptr Region -> Ptr Rectangle -> IO CInt

----------------------------------------------------------------
-- Modifying regions
-- (If you use any of these, you can't make regions look like
--  first class data structures.)
----------------------------------------------------------------

-- translate region

-- | interface to the X11 library function @XOffsetRegion()@.
offsetRegion :: Region -> Point -> IO CInt
offsetRegion r (Point x y) =
        withRegion r $ \ rp ->
        xOffsetRegion rp x y
foreign import ccall unsafe "HsXlib.h XOffsetRegion"
        xOffsetRegion :: Ptr Region -> Position -> Position -> IO CInt

-- increase size of region by +ve or -ve number of pixels
-- while preserving the centre of the region (ie half the pixels
-- come off the left, and half off the right)

-- | interface to the X11 library function @XShrinkRegion()@.
shrinkRegion :: Region -> Point -> IO CInt
shrinkRegion r (Point x y) =
        withRegion r $ \ rp ->
        xShrinkRegion rp x y
foreign import ccall unsafe "HsXlib.h XShrinkRegion"
        xShrinkRegion :: Ptr Region -> Position -> Position -> IO CInt

----------------------------------------------------------------
-- Graphics Context
----------------------------------------------------------------

-- set clip mask of GC

-- | interface to the X11 library function @XSetRegion()@.
setRegion :: Display -> GC -> Region -> IO CInt
setRegion disp gc r =
        withRegion r $ \ rp ->
        xSetRegion disp gc rp
foreign import ccall unsafe "HsXlib.h XSetRegion"
        xSetRegion :: Display -> GC -> Ptr Region -> IO CInt

----------------------------------------------------------------
-- End
----------------------------------------------------------------