packages feed

fudgets-0.18.3: hsrc/ghc-dialogue/DoXRequest.hs

{-# LANGUAGE CPP #-}
{- Obsolete OPTIONS -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/extensions/Xdbe.h> -fvia-C -}
--  -optc-I/usr/X11R6/include
module DoXRequest(doXRequest,getGCValues,translateCoordinates) where

--import P_IO_data(Request(..),Response(..))
import Geometry
import Command
import Event
import Xtypes
import Font
--import ResourceIds
import Visual
import HbcWord(intToWord) -- for Visual
import IOUtil(getEnvi)
--import CmdLineEnv(argFlag)

import XCallTypes
import StructFuns
import Xlib
import Marshall
import MyForeign -- debugging
import CString16

--import Ap

{-
#include "newstructfuns.h"
-}

newXID = newPtr :: IO CXID
newLong = newPtr :: IO CLong
newLongs n = sequence (replicate n newLong)
readLong = readCVar :: CLong -> IO Int
newInt32 = newPtr :: IO CInt32
newInt32s n = sequence (replicate n newInt32)
readInt32 = readCVar :: CInt32 -> IO Int32
freePtrs xs = mapM_ freePtr xs

--synchronize = argFlag "synchronize" False

{-
doXRequest req@(display,_,_) =
  do r <- doXRequest' req
     if synchronize && display/=noDisplay then xSync display False else return ()
     return r
-}
{-
doXRequest req@(display,_,_) | display/=noDisplay =
    withLockedDisplay display $ doXRequest' req
doXRequest req = doXRequest' req
-}
doXRequest (d@display,wi,req) =
 case req of
   OpenDisplay optname ->
      do name <- if null optname
		 then case getEnvi "DISPLAY" of
		        Just n -> return n
	                Nothing -> failu "DISPLAY variable is not set"
		 else return optname
         d <- xOpenDisplay name
	 --xSynchronize d synchronize -- has no effect?!
	 return (DisplayOpened d)
   CreateSimpleWindow p r -> WindowCreated <$> createWindow wi r
   CreateRootWindow r resname -> WindowCreated <$> do
       dr <- xDefaultRootWindow display
       this <- createWindow dr r
       setClassHint display this resname "Fudgets"
	  /* This is a hack that solves a focus problem with twm.
	     The twm option NoTitleFocus also solves the problem. */
       -- xSetWMHints display this InputHint True
       return this
   CreateGC dr oldgc gcattrs -> GCCreated <$> do
     wi' <- if wi == noWindow then xDefaultRootWindow display else return wi
     gcvals <- getGCValues gcattrs
     gc <- createGC display (getdrawable wi' dr)
     if oldgc == rootGC then do
        screen <- xDefaultScreen display
        xSetForeground display gc =<< xBlackPixel display screen
	xSetBackground display gc =<< xWhitePixel display screen
      else copyGC display oldgc gc
     changeGC display gc gcvals
     return gc
   LoadFont fn -> FontLoaded <$> xLoadFont display fn
   CreateFontCursor shp -> CursorCreated <$> xCreateFontCursor display shp
   GrabPointer b evm ->
     PointerGrabbed <$> xGrabPointer display wi b (toC evm)
	  grabModeAsync grabModeAsync windowNone cursorNone currentTime
   AllocNamedColor cm cn ->
      ColorAllocated <$> (allocNamedColor display cn =<< dcm cm)
   AllocColor cm rgb ->
       ColorAllocated <$> (allocColor display rgb =<< dcm cm)
   CreatePixmap (Point w h) depth -> PixmapCreated <$> do
     depth' <- if depth == copyFromParent
		  then xDefaultDepth display =<< xDefaultScreen display
		  else return depth
     WindowId wi' <- if wi == noWindow then xDefaultRootWindow display else return wi
     xCreatePixmap display (DrawableId wi') w h depth'
   ReadBitmapFile filename -> do
      bm <- newXID
      ints@[w,h,xhot,yhot] <- newInt32s 4
      WindowId root <- xDefaultRootWindow display
      cfilename <- marshallString filename -- GHC gives faulty code for marshallM?
      --putStrLn "about to call xReadBitmapFile"
      --writeCVar xhot 0
      --putStrLn filename
      --putStrLn =<< unmarshall cfilename
      --print =<< readLong xhot
      r <- xReadBitmapFile display (DrawableId root) cfilename w h bm xhot yhot
      --putStrLn "returned from call to xReadBitmapFile"
      freePtr cfilename -- crash?!!
      --putStrLn "about to read xhot"
      x <- fromIntegral <$> readInt32 xhot
      --putStr "xhot =";print x
      ret <-
        if (r::Int) == CCONST(BitmapSuccess) then do
	    hot <- if x == -1 then return Nothing 
			      else Just . Point x . fromIntegral <$> readInt32 yhot
	    BitmapReturn
	      <$> (Point <$> (fromIntegral <$> readInt32 w) <*> (fromIntegral <$> readInt32 h))
	     <*> return hot 
	     <*> (PixmapId <$> readCVar bm)
        else return BitmapBad
      --putStrLn "about to free int parameters"
      freePtrs ints
      freePtr bm
      return (BitmapRead ret)
   CreateBitmapFromData (BitmapData size@(Point w h) hot bytes) ->
     do cbytes <- marshallString' (map toEnum bytes) (((w+7) `div` 8)*h)
        WindowId wi' <- if wi == noWindow then xDefaultRootWindow display else return wi
        let cw = fromIntegral w
            ch = fromIntegral h
        pm <- xCreateBitmapFromData display (DrawableId wi') cbytes cw ch
        freePtr cbytes
        return (BitmapRead (BitmapReturn size hot pm))
   --RmGetStringDatabase str ->
   --RmGetResource rmd s1 s2 ->
   TranslateCoordinates ->
     do rootwin <- xDefaultRootWindow display
        CoordinatesTranslated . maybe origin id
          <$> translateCoordinates display wi rootwin
   InternAtom str b -> GotAtom <$> xInternAtom display str b

   GetAtomName a -> 
     do at_ret <- xGetAtomName display a
        if (at_ret == nullStr)
           then return (GotAtomName Nothing)
           else
             do at_name <- unmarshallString at_ret
                xFree at_ret
                -- putStrLn at_name
                case (length at_name) of
                   0 -> return (GotAtomName Nothing)
                   _ -> return (GotAtomName $ Just at_name)

   GetWindowProperty offset property delete req_type ->
     do let length = 1000 
	actual_type <- newPtr
	actual_format <- newPtr
	nitems <- newLong
	bytes_after <- newLong
	prop_return <- newCString
	xGetWindowProperty display wi property offset
			   (length `div` (4::Int)) delete req_type
	       actual_type actual_format nitems bytes_after prop_return
	at <- readCVar actual_type
	af <- readCVar actual_format
	n <- readLong nitems
	ba <- readLong bytes_after
	str <- if (af::Int) == CCONST(None) then return "" else
	    do let got = af*n `div` 8
	       cstr <- readCVar prop_return
	       str <- unmarshallString' cstr got
	       xFree cstr
	       return str
	freePtr actual_type
	freePtr actual_format
	freePtr nitems
	freePtr bytes_after
	freePtr prop_return
	return $ GotWindowProperty at af n ba str
   QueryPointer -> do
     ints@[root,child,root_x,root_y,win_x,win_y,mask] <- newLongs 7
     same <- xQueryPointer display wi root child root_x root_y win_x win_y mask
     ret <- PointerQueried same
	      <$> mkPoint (readLong root_x) (readLong root_y)
	     <*> mkPoint (readLong win_x) (readLong win_y)
	     <*> (fromC <$> readLong mask)
     freePtrs ints
     return ret

   QueryFont fid -> FontQueried <$> queryFont display fid
   LoadQueryFont fn -> FontQueried <$> loadQueryFont display fn

   QueryColor cmid (Pixel px) -> do
      c <- newXColor
      SET(XColor,Word,c,pixel,px)
      cm <- dcm cmid
      xQueryColor display cm c
      r <- mkColor c
      freePtr c
      return (ColorQueried r)

   ListFonts pattern maxnames ->
     do cnt <- newLong
	fnarr <- xListFonts display pattern maxnames cnt
	fns <- unmarshallArray fnarr =<< readLong cnt
	xFreeFontNames fnarr
	freePtr cnt
	return (GotFontList fns)
   --QueryTree ->
   DefaultRootWindow -> GotDefaultRootWindow <$> xDefaultRootWindow display
   --GetGeometry ->
   --GetResource rms ->
   DefaultVisual ->
     GotVisual <$> (mkVisual =<< xDefaultVisual d =<< xDefaultScreen d)
   Sync b -> xSync display b >> return Synced
   QueryTextExtents16 fid s ->
     do let n = length s
	cs <- marshallString16' s n
        ints@[dir,ascent,descent,overall] <- newLongs 4
        overall <- newPtr
	xQueryTextExtents16 display fid cs n dir ascent descent overall
        [asc,desc] <- mapM readLong [ascent,descent]
        ov <- mkCharStruct overall
        freePtrs ints
	freePtr overall
        return $ TextExtents16Queried asc desc ov
   ListFontsWithInfo pattern maxnames ->
     GotFontListWithInfo <$> listFontsWithInfo d pattern maxnames
   DbeQueryExtension ->
     do ints@[major,minor] <- newLongs 2
        status <- xdbeQueryExtension display major minor
	ma <- readLong major
	mi <- readLong minor
	freePtrs ints
	return (DbeExtensionQueried status ma mi)
   DbeAllocateBackBufferName swapAction ->
       DbeBackBufferNameAllocated <$> xdbeAllocateBackBufferName d wi swapAction
   DbeSwapBuffers swapAction -> -- applies only to the fudget's own window.
       do (swapinfo,cnt) <- storeSwapAction [(wi,swapAction)]
          status <- xdbeSwapBuffers display swapinfo cnt
	  freePtr swapinfo
	  return (DbeBuffersSwapped status)
   _ -> error (notImplemented req)
 where
  createWindow parent (Rect (Point x y) (Point w h)) = do
    screen <- xDefaultScreen display
    blackP <- xBlackPixel display screen
    whiteP <- xWhitePixel display screen
    let border_width = 0 -- should agree with border_width in WindowF.hs !!
    this <- xCreateSimpleWindow display parent x y w h border_width blackP whiteP
    xStoreName display this "Fudgets"
    return this
  dcm = dcmap display

{-
type BorderWidth = Int
type FontShape = Int
-}

setClassHint :: Display -> Window -> String -> String -> IO ()
setClassHint d w resName resClass =
  do class_hints <- newPtr
     rn<-marshallString resName
     SET(XClassHint,CString,class_hints,res_name,rn)
     rc<-marshallString resClass
     SET(XClassHint,CString,class_hints,res_class,rc)
     xSetClassHint d w class_hints
     freePtr rn
     freePtr rc

createGC :: Display -> DrawableId -> IO GCId
createGC d w = xCreateGC d w 0 nullPtr
--    _casm_ ``%r=XCreateGC(%0,%1,0,NULL);'' d w

copyGC :: Display -> GCId -> GCId -> IO ()
copyGC d oldgc gc = 
  --xCopyGC d oldgc ``(1<<(GCLastBit+1))-1)''gc
  xCopyGC d oldgc 8388607  gc
--   _casm_ ``XCopyGC(%0,%1,(1<<(GCLastBit+1))-1,%2);'' d oldgc gc

changeGC d gc (gcvals,mask) = xChangeGC d gc mask gcvals

allocNamedColor :: Display -> String -> ColormapId -> IO (Maybe Color)
allocNamedColor d colname cm = do
   exact <- newPtr
   screen <- newPtr
   status <- xAllocNamedColor d cm colname screen exact
   r <- returnColor status screen
   freePtr exact
   freePtr screen
   return r

returnColor status c = 
 if status /= (0::Int)
    then Just <$> mkColor c
    else return Nothing

mkColor xcol = 
 Color . Pixel
  <$> GET(XColor,Word,xcol,pixel)
  <*> (RGB
	 <$> GET(XColor,Int,xcol,red)
	 <*> GET(XColor,Int,xcol,green)
	 <*> GET(XColor,Int,xcol,blue)
      )

allocColor :: Display -> RGB -> ColormapId -> IO (Maybe Color)
allocColor d rgb cm = do
  color <- newXColor
  setRGB rgb color
  status <- xAllocColor d cm color
  r <- returnColor status color
  freePtr color
  return r

setRGB (RGB red green blue) color = do
  SET(XColor,Int,color,red,red)
  SET(XColor,Int,color,green,green)
  SET(XColor,Int,color,blue,blue)

type XGCValuesMask = (CXGCValues,Bitmask)

getGCValues :: GCAttributeList -> IO XGCValuesMask
getGCValues = getValues newPtr getGCValue where
  getGCValue gcv ga = case ga of
    GCFunction f           -> (SET(XGCValues,Int,gcv,function,fromEnum f),CWORD32(GCFunction)::Bitmask)
    GCForeground p         -> (SET(XGCValues,Int,gcv,foreground,toC p),CWORD32(GCForeground))
    GCBackground p         -> (SET(XGCValues,Int,gcv,background,toC p),CWORD32(GCBackground))
    GCLineWidth w          -> (SET(XGCValues,Int,gcv,line_width,w),CWORD32(GCLineWidth))
    GCLineStyle s          -> (SET(XGCValues,Int,gcv,line_style,fromEnum s),CWORD32(GCLineStyle))
    GCFont f               -> (SET(XGCValues,XID,gcv,font,toXID f),CWORD32(GCFont))
    GCCapStyle s           -> (SET(XGCValues,Int,gcv,cap_style,fromEnum s),CWORD32(GCCapStyle))
    GCJoinStyle s          -> (SET(XGCValues,Int,gcv,join_style,fromEnum s),CWORD32(GCJoinStyle))
    GCSubwindowMode m      -> (SET(XGCValues,Int,gcv,subwindow_mode,fromEnum m),CWORD32(GCSubwindowMode))
    GCGraphicsExposures g  -> (SET(XGCValues,Int,gcv,graphics_exposures, fromEnum g),CWORD32(GCGraphicsExposures))
    GCFillStyle f          -> (SET(XGCValues,Int,gcv,fill_style,fromEnum f),CWORD32(GCFillStyle))
    GCTile p               -> (SET(XGCValues,XID,gcv,tile,toXID p),CWORD32(GCTile))
    GCStipple p            -> (SET(XGCValues,XID,gcv,stipple,toXID p),CWORD32(GCStipple) :: Bitmask)
    -- _ -> (return (),0)


loadQueryFont :: Display -> FontName -> IO (Maybe FontStructList)
loadQueryFont d fn = mkFontStructList =<< xLoadQueryFont d fn

queryFont :: Display -> FontId -> IO (Maybe FontStructList)
queryFont d fi = mkFontStructList =<< xQueryFont d fi

listFontsWithInfo :: Display -> FontName -> Int -> IO [(FontName,FontStructList)]
listFontsWithInfo d pattern maxnames =
  do cnt <- newInt32
     fsarrp <- newCXFontStruct
     --putStrLn "About to call xListFontsWithInfo"
     fnarr <- xListFontsWithInfo d pattern (fromIntegral maxnames) cnt fsarrp
     --putStrLn "Returned from call xListFontsWithInfo"
     n <- readInt32 cnt
     --putStr "Number of fonts: " ; print n
     freePtr cnt
     fsarr <- readCVar fsarrp
     freePtr fsarrp
     --putStrLn "After free fsarrp"
     if fnarr==nullStr then return []
      else do
       --putStrLn "Non-null name array"
       fns <- unmarshallArray fnarr (fromIntegral n)
       --putStrLn "Got name list";print fns
       fss <- readArray fsarr (fromIntegral n)
       --putStrLn "Got fontstruct list"
       xFreeFontInfo fnarr fsarr n
       --putStrLn "Freed fontinfo, returning"
       return (zip fns fss)

instance CVar CXFontStruct FontStructList
instance Storable FontStructList where -- just for readArray...
--sizeOf _ = sizeOf (undefined::CXFontStruct) -- Wrong size!!!
  sizeOf _ = SIZEOF(XFontStruct)
  alignment _ = alignment (undefined::CXFontStruct)
  peek = mkFontStructList' . CXFontStruct

mkFontStructList :: CXFontStruct -> IO (Maybe FontStructList)
mkFontStructList fs =
   if fs == CXFontStruct nullAddr
   then return Nothing
   else do fsl <- mkFontStructList' fs
           --_casm_ ``XFreeFontInfo(NULL, %0, 1); '' fs
	   xFreeFontInfo nullStr fs 1
	   return (Just fsl)

#if 0
#define DEBUG(cmd) (putStrLn "cmd before">>(cmd)>>= \r->putStrLn "after">>return r)
#else
#define DEBUG(cmd) (cmd)
#endif

mkFontStructList' :: CXFontStruct -> IO FontStructList
mkFontStructList' fs =
  do --putStrLn "Enter mkFontStructList'"
     min_char_or_byte2 <- GET(XFontStruct,Int,fs,min_char_or_byte2)
     min_byte1 <-GET(XFontStruct,Int,fs,min_byte1)
     max_char_or_byte2 <- GET(XFontStruct,Int,fs,max_char_or_byte2)
     max_byte1 <-GET(XFontStruct,Int,fs,max_byte1)
     n_prop <-GET(XFontStruct,Int,fs,n_properties)
     -- putStrLn $ "font properties: " ++ (show n_prop)
     --putStrLn "after min max"
     let min = min_char_or_byte2 + 256*min_byte1
         max = max_char_or_byte2 + 256*max_byte1
         arrsize = (max_char_or_byte2 - min_char_or_byte2 + 1) *
		   (max_byte1 - min_byte1 + 1)
         --arrsize = max - min  :: Int -- This is wrong!
     --print ("min max arrsize",min,max,arrsize)
     per_char <- GET(XFontStruct,HT(XCharStruct),fs,per_char)
     --putStrLn "after per_char"
     elem9 <- if per_char /= nullPtr -- CCONST(NULL) 
       then Just <$> mapM (\i -> INDEX(XCharStruct) per_char i >>= mkCharStruct) [0..arrsize-1] 
       else return Nothing
     --putStrLn "after elem9"
     f_prop <- GET(XFontStruct,HT(XFontProp),fs,properties)
     elemprop <- if f_prop /= nullPtr
       then mapM (\i -> INDEX(XFontProp) f_prop i >>= mkFontProp) [0..n_prop-1]
       else return []
     -- putStrLn $ show elemprop
     fsl <- FontStruct . FontId
	<$> DEBUG(GET(XFontStruct,XID,fs,fid))
	<*> fmap toEnum DEBUG(GET(XFontStruct,Int,fs,direction))
	<*> return (toEnum min)
	<*> return (toEnum max)
	<*> fmap toEnum DEBUG(GET(XFontStruct,Int,fs,all_chars_exist))
	<*> DEBUG(GET(XFontStruct,Char,fs,default_char))
	<*> return elemprop
	<*> (mkCharStruct =<< DEBUG(AGET(XFontStruct,HT(XCharStruct),fs,min_bounds)))
	<*> (mkCharStruct =<< DEBUG(AGET(XFontStruct,HT(XCharStruct),fs,max_bounds)))
	<*> return elem9
	<*> DEBUG(GET(XFontStruct,Int,fs,ascent))
	<*> DEBUG(GET(XFontStruct,Int,fs,descent))
     -- putStrLn $ "Returning from mkFontStructList'" ++ (show fsl)
     return fsl

-- Intermediate data for FontProp, containing just two integers:
-- atom values will (hopefully) be retrieved lazily.

mkFontProp :: CXFontProp -> IO FontProp

mkFontProp fp = 
  FontProp
   <$> GET(XFontProp,Atom,fp,name)
  <*> GET(XFontProp,Int,fp,card32)

mkCharStruct :: CXCharStruct -> IO CharStruct
mkCharStruct cs = 
    CharStruct
     <$> GET(XCharStruct,Int,cs,lbearing)
     <*> GET(XCharStruct,Int,cs,rbearing)
     <*> GET(XCharStruct,Int,cs,width)
     <*> GET(XCharStruct,Int,cs,ascent)
     <*> GET(XCharStruct,Int,cs,descent)

mkVisual :: CVisual -> IO Visual
mkVisual cv =
  Visual
   <$> GET(Visual,VisualID,cv,visualid)
   <*> fmap toEnum GET(Visual,Int,cv,class)
   <*> fmap intToWord GET(Visual,Int,cv,red_mask)
   <*> fmap intToWord GET(Visual,Int,cv,green_mask)
   <*> fmap intToWord GET(Visual,Int,cv,blue_mask)
   <*> GET(Visual,Int,cv,bits_per_rgb)
   <*> GET(Visual,Int,cv,map_entries)

storeSwapAction :: [(WindowId,SwapAction)] -> IO (CXdbeSwapInfoArray,Int)
storeSwapAction =
  getArray newXdbeSwapInfoArray
	   (\si (i,(wi,sa)) ->
              do SETI(XdbeSwapInfo,WindowId,si,i,swap_window,wi)
		 SETI(XdbeSwapInfo,Int,si,i,swap_action,fromEnum sa))

translateCoordinates display window dstwindow =
  do dx <- newPtr
     dy <- newPtr
     child <- newPtr
     ok <- xTranslateCoordinates display window dstwindow 0 0 dx dy child
     p <- if ok
          then Just <$> (Point <$> (fromEnum <$> readInt32 dx)
                               <*> (fromEnum <$> readInt32 dy))
          else return Nothing
     freePtrs [dx,dy]
     freePtr child
     return p