pvd-1.1.0: XUtils.hs
module XUtils (
initX,
drawImg,
sendExposeEvent,
loadXImg,
XImg
) where
import Control.Monad.Error
import Data.Array.Storable
import Data.Foldable (for_)
import Data.Word (Word8)
import Foreign hiding (newArray)
import qualified Codec.Image.DevIL.Extras as IL
import qualified Graphics.X11.Xlib as X
import qualified Graphics.X11.Xlib.Extras as X
data XImg = XImg {
xImg :: X.Image,
xImgData :: StorableArray (Int,Int,Int) Word8,
xImgH :: Int,
xImgW :: Int
}
initX = do
dpy <- X.openDisplay ""
rootw <- X.rootWindow dpy (X.defaultScreen dpy)
win <- mkWin dpy rootw
X.selectInput dpy win X.exposureMask
X.mapWindow dpy win
return (dpy,win)
where
mkWin dpy rootw = do
attr <- X.getWindowAttributes dpy rootw
col <- initColor dpy "#000000"
X.createSimpleWindow dpy rootw 0 0 (fromIntegral $ X.wa_width attr) (fromIntegral $ X.wa_height attr) 1 col col
drawImg :: X.Display -> X.Window -> XImg -> IO ()
drawImg dpy win ximg = do
bgcolor <- initColor dpy "#000000"
gc <- X.createGC dpy win
(_,_,_,winWidth,winHeight,_,_) <- X.getGeometry dpy win
let depth = X.defaultDepthOfScreen (X.defaultScreenOfDisplay dpy)
pixmap <- X.createPixmap dpy win winWidth winHeight depth
X.setForeground dpy gc bgcolor
X.fillRectangle dpy pixmap gc 0 0 winWidth winHeight
let portWidth = fromIntegral (xImgW ximg)
portHeight = fromIntegral (xImgH ximg)
portX = fromIntegral ((winWidth-portWidth) `div` 2)
portY = fromIntegral ((winHeight-portHeight) `div` 2)
X.putImage dpy pixmap gc (xImg ximg) 0 0 portX portY portWidth portHeight
X.copyArea dpy pixmap win gc 0 0 winWidth winHeight 0 0
X.freeGC dpy gc
X.freePixmap dpy pixmap
X.sync dpy True
initColor :: X.Display -> String -> IO X.Pixel
initColor dpy color = do
let colormap = X.defaultColormap dpy (X.defaultScreen dpy)
(apros,real) <- X.allocNamedColor dpy colormap color
return $ X.color_pixel apros
makeXImage :: X.Display -> IL.Image -> IO XImg
makeXImage dpy img = do
xImgData <- mapIndices bs mapIdx (IL.imgData img)
withStorableArray xImgData (ci xImgData . castPtr)
where
w = fromIntegral (IL.imgWidth img)
h = fromIntegral (IL.imgHeight img)
ci imgdata p = do
ximg <- X.createImage dpy vis depth X.zPixmap 0 p w h 32 0
return XImg { xImgData = imgdata, xImg = ximg, xImgH = IL.imgHeight img,
xImgW = IL.imgWidth img }
depth = X.defaultDepthOfScreen (X.defaultScreenOfDisplay dpy)
vis = X.defaultVisual dpy (X.defaultScreen dpy)
bs = ((0,0,0), (IL.imgHeight img - 1, IL.imgWidth img - 1, 3))
mapIdx (y,x,c) = (IL.imgHeight img - y - 1, x, c' c)
where
c' 0 = 2
c' 1 = 1
c' 2 = 0
c' 3 = 0
loadXImg :: X.Display -> String -> IO (Maybe XImg)
loadXImg dpy path = do
img <- IL.loadImage path
flip (maybe (return Nothing)) img $ \i -> do
ximg <- makeXImage dpy i
IL.unloadImage i
return $ Just ximg
sendExposeEvent dpy win = X.allocaXEvent $ \e -> do
X.setEventType e X.expose
X.sendEvent dpy win False X.noEventMask e
X.flush dpy