module Graphics.X11.Turtle.XTools(
Display,
Window,
Pixmap,
Atom,
Point(..),
Position,
Dimension,
XEventPtr,
XIC,
Bufs,
undoBuf,
bgBuf,
topBuf,
GCs,
gcForeground,
gcBackground,
Event(..),
forkIOX,
openWindow,
destroyWindow,
closeDisplay,
windowSize,
flush,
getColorPixel,
setForeground,
copyArea,
fillRectangle,
fillPolygon,
drawLineXT,
writeStringXT,
allocaXEvent,
waitEvent,
pending,
nextEvent,
getEvent,
filterEvent,
utf8LookupString,
buttonPress,
buttonRelease,
xK_VoidSymbol,
) where
import Text.XML.YJSVG(Color(..))
import Graphics.X11(
Display, Drawable, Window, Pixmap, Visual, Colormap, GC, Pixel, Atom,
Point(..), Position, Dimension, XEventPtr,
initThreads, flush, supportsLocale, setLocaleModifiers,
connectionNumber, openDisplay, closeDisplay, internAtom,
createSimpleWindow, destroyWindow, mapWindow, createGC, createPixmap,
rootWindow, defaultScreen, defaultScreenOfDisplay, defaultVisual,
defaultColormap, defaultDepth, whitePixel, blackPixel,
copyArea, fillRectangle, drawLine, nonconvex, coordModeOrigin,
setLineAttributes, lineSolid, capRound, joinRound, setForeground,
allocNamedColor, color_pixel,
allocaXEvent, pending, nextEvent,
setWMProtocols, selectInput, button1MotionMask, buttonReleaseMask,
buttonPressMask, keyPressMask, exposureMask,
buttonPress, buttonRelease, xK_VoidSymbol, getGeometry)
import qualified Graphics.X11 as X(fillPolygon)
import Graphics.X11.Xlib.Extras(Event(..), getEvent)
import Graphics.X11.Xft(
XftColor, xftDrawCreate, xftFontOpen, withXftColorValue,
withXftColorName, xftDrawString)
import Graphics.X11.Xrender(XRenderColor(..))
import Graphics.X11.Xim(
XIC, XNInputStyle(..), openIM, createIC, getICValue, filterEvent,
utf8LookupString)
import Control.Monad(forM_, replicateM)
import Control.Monad.Tools(unlessM)
import Control.Concurrent(ThreadId, forkIO, threadWaitRead)
import Data.Bits((.|.), shift)
import System.Locale.SetLocale(setLocale, Category(..))
import System.Posix.Types(Fd(..))
import Numeric(showFFloat)
data Bufs = Bufs{
undoBuf :: Pixmap,
bgBuf :: Pixmap,
topBuf :: Pixmap}
data GCs = GCs{
gcForeground :: GC,
gcBackground :: GC}
forkIOX :: IO () -> IO ThreadId
forkIOX = (initThreads >>) . forkIO
openWindow :: IO (Display, Window, Bufs, GCs, XIC, Atom, (Dimension, Dimension))
openWindow = do
_ <- setLocale LC_CTYPE Nothing >>= maybe (error "setLocale") return
_ <- initThreads
unlessM supportsLocale $ error "Current locale is not supported."
_ <- setLocaleModifiers ""
dpy <- openDisplay ""
del <- internAtom dpy "WM_DELETE_WINDOW" True
let scr = defaultScreen dpy
root <- rootWindow dpy scr
(rWidth, rHeight) <- windowSize dpy root
bufs@[ub, bb, tb] <- replicateM 3 $
createPixmap dpy root rWidth rHeight $ defaultDepth dpy scr
win <- createSimpleWindow dpy root 0 0 rWidth rHeight 1
(blackPixel dpy scr) (whitePixel dpy scr)
im <- openIM dpy Nothing Nothing Nothing
ic <- createIC im [XIMPreeditNothing, XIMStatusNothing] win
fevent <- getICValue ic "filterEvents"
[gc, gcBG] <- replicateM 2 $ createGC dpy win
setForeground dpy gcBG 0xffffff
forM_ bufs $ \bf -> fillRectangle dpy bf gcBG 0 0 rWidth rHeight
setWMProtocols dpy win [del]
selectInput dpy win $ fevent .|. exposureMask .|. keyPressMask .|.
buttonPressMask .|. buttonReleaseMask .|. button1MotionMask
size <- mapWindow dpy win >> windowSize dpy win
return (dpy, win, Bufs ub bb tb, GCs gc gcBG, ic, del, size)
windowSize :: Display -> Window -> IO (Dimension, Dimension)
windowSize dpy win = do
(_, _, _, width, height, _, _) <- getGeometry dpy win
return (width, height)
getColorPixel :: Display -> Color -> IO (Maybe Pixel)
getColorPixel _ (RGB r g b) = return $ Just $ shift (fromIntegral r) 16 .|.
shift (fromIntegral g) 8 .|. fromIntegral b
getColorPixel dpy (ColorName cn) = fmap (Just . color_pixel . fst)
(allocNamedColor dpy (defaultColormap dpy $ defaultScreen dpy) cn) `catch`
const (putStrLn "no such color" >> return Nothing)
fillPolygon :: Display -> Drawable -> GC -> [Point] -> IO ()
fillPolygon d w gc ps = X.fillPolygon d w gc ps nonconvex coordModeOrigin
drawLineXT :: Display -> GC -> Drawable -> Int -> Color ->
Position -> Position -> Position -> Position -> IO ()
drawLineXT dpy gc bf lw c x1 y1 x2 y2 = do
getColorPixel dpy c >>= maybe (return ()) (setForeground dpy gc)
setLineAttributes dpy gc (fromIntegral lw) lineSolid capRound joinRound
drawLine dpy bf gc x1 y1 x2 y2
writeStringXT :: Display -> Drawable -> String -> Double -> Color ->
Position -> Position -> String -> IO ()
writeStringXT dpy buf fname size clr x y str = do
let scrN = defaultScreenOfDisplay dpy
visual = defaultVisual dpy $ defaultScreen dpy
colormap = defaultColormap dpy $ defaultScreen dpy
xftDraw <- xftDrawCreate dpy buf visual colormap
xftFont <- xftFontOpen dpy scrN $
fname ++ "-" ++ showFFloat (Just 0) size ""
withXftColor dpy visual colormap clr $ \c ->
xftDrawString xftDraw c xftFont x y str
withXftColor ::
Display -> Visual -> Colormap -> Color -> (XftColor -> IO a) -> IO a
withXftColor dpy visual colormap (RGB r g b) action =
withXftColorValue dpy visual colormap color action
where
color = XRenderColor {
xrendercolor_red = fromIntegral r * 0x100,
xrendercolor_green = fromIntegral b * 0x100,
xrendercolor_blue = fromIntegral g * 0x100,
xrendercolor_alpha = 0xffff}
withXftColor dpy visual colormap (ColorName cn) action =
withXftColorName dpy visual colormap cn action
waitEvent :: Display -> IO ()
waitEvent = threadWaitRead . Fd . connectionNumber