{-# LINE 1 "Graphics/X11/Xim.hsc" #-}

{-# LINE 2 "Graphics/X11/Xim.hsc" #-}

{-# LINE 3 "Graphics/X11/Xim.hsc" #-}

module Graphics.X11.Xim (

  XIM(..)
, XIC(..)
, XNInputStyle(..)
, XrmDatabase(..)

, openIM
, closeIM
, createIC
, destroyIC
, getICValue
, filterEvent
, utf8LookupString
, utf8DrawString
, utf8TextExtents
, utf8TextEscapement

) where

import Graphics.X11.XimTypes


{-# LINE 27 "Graphics/X11/Xim.hsc" #-}
import Codec.Binary.UTF8.String ( encode )

{-# LINE 31 "Graphics/X11/Xim.hsc" #-}

import Graphics.X11	( Window, XEventPtr, GC, KeySym, Rectangle )
import Graphics.X11.Xlib.Extras	( FontSet(..) )
import Graphics.X11.Xlib.Types	( Display(..) )
import Foreign		( Int32, nullPtr, Ptr, Word8, alloca, peek, Int64,
				Word64, Word32,
				allocaBytes, throwIfNull, withArray0 )
import Foreign.C.Types	( CInt, CChar )
import Foreign.C.String	( CString, peekCStringLen, withCString )

import System.IO.Unsafe

-- DATA TYPE

data XIM = XIM { ximPtr :: Ptr XIM }
data XIC = XIC { xicPtr :: Ptr XIC }

data XrmDatabase = XrmDatabase ( Ptr XrmDatabase )

-- FUNCTIONS

foreign import ccall "X11/Xlib.h XOpenIM"	c_XOpenIM	::
	Ptr Display -> Ptr XrmDatabase -> CString -> CString -> IO ( Ptr XIM )
openIM :: Display -> Maybe XrmDatabase -> Maybe String -> Maybe String
							-> IO XIM
openIM ( Display pdpy ) mxd rn rc =
	let pxd = case mxd of
			Nothing                -> nullPtr
			Just ( XrmDatabase p ) -> p
	 in fmap XIM $ withMaybeCString rn $ \crn ->
					withMaybeCString rc $ \crc -> do
		throwIfNull "openIM" $ c_XOpenIM pdpy pxd crn crc

foreign import ccall "X11/Xlib.h XCloseIM"	c_XCloseIM	::
	Ptr XIM -> IO ()
closeIM :: XIM -> IO ()
closeIM = c_XCloseIM . ximPtr

foreign import ccall "X11/Xlib.h XCreateIC"	c_XCreateIC2	::
	Ptr XIM -> CString -> Int32 -> CString
{-# LINE 71 "Graphics/X11/Xim.hsc" #-}
		-> Window -> Ptr () -> IO ( Ptr XIC )
createIC :: XIM -> [ XNInputStyle ] -> Window -> IO XIC
createIC ( XIM pim ) xniss win = do
	fmap XIC $ throwIfNull "createIC" $ withCString "inputStyle" $ \is ->
		withCString "clientWindow" $ \cw ->
			c_XCreateIC2 pim is ( getCXNInputStyle xniss )
				cw win nullPtr

foreign import ccall "X11/Xlib.h XDestroyIC"	c_XDestroyIC	::
	Ptr XIC -> IO ()
destroyIC :: XIC -> IO ()
destroyIC = c_XDestroyIC . xicPtr

foreign import ccall "X11/Xlib.h XGetICValues"	c_XGetICValues1	::
	Ptr XIC -> CString -> Ptr Word32
{-# LINE 86 "Graphics/X11/Xim.hsc" #-}
                -> Ptr () -> IO CString
getICValue :: XIC -> String -> IO Word32
{-# LINE 88 "Graphics/X11/Xim.hsc" #-}
getICValue ( XIC pic ) fn = withCString fn $ \cfn ->
	alloca $ \p -> do
		r <- c_XGetICValues1 pic cfn p nullPtr
		if r == nullPtr
			then peek p
			else error "bad"

foreign import ccall "X11/Xlib.h XFilterEvent" c_XFilterEvent ::
	XEventPtr -> Window -> IO Int32
{-# LINE 97 "Graphics/X11/Xim.hsc" #-}
filterEvent :: XEventPtr -> Window -> IO Bool
filterEvent e w = do
  ret <- c_XFilterEvent e w
  return $ ret == 1
{-# LINE 101 "Graphics/X11/Xim.hsc" #-}

foreign import ccall "X11/Xlib.h Xutf8LookupString"	c_Xutf8LookupString
	:: Ptr XIC -> XEventPtr -> Ptr CChar -> CInt -> Ptr Word32
{-# LINE 104 "Graphics/X11/Xim.hsc" #-}
		-> Ptr Int32 -> IO CInt
{-# LINE 105 "Graphics/X11/Xim.hsc" #-}
utf8LookupString :: XIC -> XEventPtr -> IO ( Maybe String, Maybe KeySym )
utf8LookupString xic pev = utf8LookupStringGen xic pev 8
utf8LookupStringGen :: XIC -> XEventPtr -> Int -> IO ( Maybe String, Maybe KeySym )
utf8LookupStringGen ( XIC pic ) pev bs = allocaBytes bs $ \buf ->
	alloca $ \ks -> alloca $ \stat -> do
		cnt <- fmap fromIntegral $ c_Xutf8LookupString pic pev buf
						( fromIntegral bs ) ks stat
		cStat <- peek stat
		case fromCXLookupStatus cStat of
			XLookupBoth   -> do
				str <- peekCStringLen ( buf, cnt )
				cks <- peek ks

{-# LINE 118 "Graphics/X11/Xim.hsc" #-}
                                return ( Just str, Just cks )

{-# LINE 122 "Graphics/X11/Xim.hsc" #-}
			XLookupChars   -> do
				str <- peekCStringLen ( buf, cnt )

{-# LINE 125 "Graphics/X11/Xim.hsc" #-}
				return ( Just str, Nothing )

{-# LINE 129 "Graphics/X11/Xim.hsc" #-}
			XLookupKeySym   -> do
				cks <- peek ks
				return ( Nothing, Just cks )
			XLookupNone     -> return ( Nothing, Nothing )
			XBufferOverflow -> utf8LookupStringGen
						( XIC pic ) pev ( 2 * bs )


foreign import ccall "X11/Xlib.h Xutf8DrawString"		c_Xutf8DrawString	::
	Ptr Display -> Window -> Ptr FontSet -> GC -> CInt -> CInt
		-> Ptr Word8 -> CInt -> IO ()
utf8DrawString :: Display -> Window -> FontSet -> GC -> Int -> Int -> String ->
	IO ()
utf8DrawString ( Display pdpy ) win ( FontSet pfs ) gc x y str =
	let	utf8Str = encode str
	 in withArray0 0 utf8Str $ \cstr ->
		c_Xutf8DrawString pdpy win pfs gc ( fromIntegral x )
			( fromIntegral y ) cstr
			( fromIntegral $ length utf8Str )

foreign import ccall "X11/Xlib.h Xutf8TextExtents"		c_Xutf8TextExtents	::
	Ptr FontSet -> Ptr Word8 -> CInt -> Ptr Rectangle -> Ptr Rectangle -> IO ()
utf8TextExtents :: FontSet -> String -> (Rectangle, Rectangle)
utf8TextExtents ( FontSet pfs ) str =
	let	utf8Str = encode str
        -- unsafePerformIO is safe here as Xutf8TextExtents does not
        -- involve a server round trip, and has no side effects as
        -- long as the FontSet has not been freed before the thunk is
        -- forced.
	 in unsafePerformIO $ withArray0 0 utf8Str $ \cstr -> alloca $ \r1 -> alloca $ \r2 -> do
		c_Xutf8TextExtents pfs cstr ( fromIntegral $ length utf8Str ) r1 r2
                r1' <- peek r1
                r2' <- peek r2   
                return (r1', r2')

foreign import ccall "X11/Xlib.h Xutf8TextEscapement"		c_Xutf8TextEscapement	::
	Ptr FontSet -> Ptr Word8 -> CInt -> IO CInt
utf8TextEscapement :: FontSet -> String -> CInt
utf8TextEscapement ( FontSet pfs ) str =
	let	utf8Str = encode str
        -- unsafePerformIO is safe like in utf8TextExtents.
	 in unsafePerformIO $ withArray0 0 utf8Str $ \cstr ->
		c_Xutf8TextEscapement pfs cstr ( fromIntegral $ length utf8Str )

withMaybeCString :: Maybe String -> ( CString -> IO a ) -> IO a
withMaybeCString Nothing      f = f nullPtr
withMaybeCString ( Just str ) f = withCString str f