packages feed

Chitra (empty) → 0.1

raw patch · 9 files changed

+481/−0 lines, 9 filesdep +basedep +binarydep +bytestringsetup-changed

Dependencies added: base, binary, bytestring, mtl, network

Files

+ Chitra.cabal view
@@ -0,0 +1,41 @@+Name:                Chitra+Version:             0.1+Synopsis:            Haskell library for platform independent graphics using VNC.+Homepage:            http://github.com/ckkashyap/Chitra+License:             BSD3+License-file:        LICENSE+Author:              C K Kashyap+Maintainer:          ckkashyap@gmail.com+synopsis:		Simple, VNC based graphics rendering system+description: Chitra in most Indian languages means "Image". This aim of this project is to build an VNC library that can be used to develop interactive graphical application. What I think will be the strength of Chitra would be its "platform independence". So, the idea is, the library would have a "putpixel" function which when called would render a pixel on an image buffer that would be rendered via the vnc server. For viewing and interactive with the aplication, one would use a standard VNC client. Eventually, I might chose to do this using the RDP protocol that even has support for sound.  ++	To try out -++	Just do a make and you should have the executable *Main* created. ++	Run ./Main <width> <height> <port> ++	Now try connecting a vnc client to localhost:5900++Category:            Graphics++Build-type:          Simple++Cabal-version:       >=1.2++Library+  Exposed-modules:     Chitra.Canvas,+                       RFB.ClientToServer,+                       RFB.Handshake,+                       RFB.CommandLoop,+                       RFB.Server+  Hs-source-dirs:      ./+  Build-depends:       base >= 4.2 && < 4.3,+                       binary >= 0.5 && < 0.6,+                       bytestring >= 0.9 && < 1.0,+                       network >= 2.2 && < 2.3,+                       mtl >= 1.1 && < 1.2++Executable Chitra+  Main-is:             Main.hs+  Build-depends:       base >= 4.2 && < 4.3
+ Chitra/Canvas.hs view
@@ -0,0 +1,27 @@+module Chitra.Canvas where++import Control.Monad+import System.IO++import qualified Data.ByteString.Lazy as BS+import qualified Data.ByteString.Lazy.Char8 as B+import Data.Char+import Data.Binary.Get+import Data.Binary.Put+import Data.Word++import qualified RFB.Constants as RFB+import qualified RFB.Server as SERVER+import qualified RFB.Handshake as Handshake+import qualified RFB.CommandLoop as CommandLoop++++start w h p= do+	SERVER.serve w h p doit++doit w h hnd = do+	Handshake.handshake w h hnd+	CommandLoop.commandLoop hnd w h+	+
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright 2002, C.K.Kashyap+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++ * Redistributions of source code must retain the above copyright notice,+   this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.++ * Neither the name of the copyright holder(s) nor the names of+   contributors may be used to endorse or promote products derived from+   this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Main.hs view
@@ -0,0 +1,11 @@+import qualified Chitra.Canvas as C+import System.Environment++main = do+	args <- getArgs+	case args of+		[w,h,port] -> C.start width height port+			where+				width = read w :: Int+				height = read h :: Int+		_ -> putStrLn "Usage: ./Main width height port"
+ RFB/ClientToServer.hs view
@@ -0,0 +1,109 @@+module RFB.ClientToServer (+	Command+	(+		SetPixelFormat ,+		SetEncodings ,+		FramebufferUpdate ,+		KeyEvent ,+		PointerEvent ,+		ClientCutText ,+		BadCommand+	),+	CommandData+	(+		SetPixelFormatData ,+		SetEncodingsData ,+		FramebufferUpdateData ,+		KeyEventData ,+		PointerEventData ,+		ClientCutTextData+	),+	bytesToRead,+	parseCommandByteString,+	getCommandData,+	word8ToCommand,+) where++import Data.Word++import qualified Utilities.ParseByteString as PBS+import qualified Data.ByteString.Lazy as BS+++data Command = SetPixelFormat | SetEncodings | FramebufferUpdate | KeyEvent | PointerEvent | ClientCutText | BadCommand deriving (Show)++data CommandData = SetPixelFormatData {+	bitsPerPixel	:: Int,+	depth		:: Int,+	bigEndian	:: Int,+	trueColor	:: Int,+	redMax		:: Int,+	greenMax	:: Int,+	blueMax		:: Int,+	redShift	:: Int,+	greenShift	:: Int,+	blueShift	:: Int+} | ClientCutTextData {+	length		:: Int+} | SetEncodingsData {+	count		:: Int+} | FramebufferUpdateData {+	incremental	:: Int,+	x		:: Int,+	y		:: Int,+	width		:: Int,+	height		:: Int+} | KeyEventData {+	downFlag	:: Int,+	key		:: Int+} | PointerEventData {+	buttonMask	:: Int,+	x		:: Int,+	y		:: Int+} | BadCommandData deriving (Show)++++bytesToRead :: Command -> Int+bytesToRead c = foldr (+) 0 (map (\x -> if x == 0 then 1 else x) (commandFormat c))++commandFormat :: Command -> [Int] -- 0 for padding bytes+commandFormat c = case c of+		SetPixelFormat		-> [0,0,0,1,1,1,1,2,2,2,1,1,1,0,0,0]+		SetEncodings		-> [0,2]+		FramebufferUpdate	-> [1,2,2,2,2]+		KeyEvent		-> [1,0,0,4]+		PointerEvent		-> [1,2,2]+		ClientCutText		-> [0,0,0,4]+		BadCommand		-> []+++parseCommandByteString :: BS.ByteString -> Command -> [Int]+parseCommandByteString byteString command =+	PBS.parseByteString list byteString+		where +			list = (commandFormat command)++getCommandData	:: BS.ByteString -> Command -> CommandData+getCommandData byteString command = commandDataFromList list+	where+		list = PBS.parseByteString (commandFormat command) byteString+		commandDataFromList xs = case command of+			SetPixelFormat		-> SetPixelFormatData (xs!!0) (xs!!1) (xs!!2) (xs!!3) (xs!!4) (xs!!5) (xs!!6) (xs!!7) (xs!!8) (xs!!9)+			SetEncodings		-> SetEncodingsData (xs!!0)+			FramebufferUpdate	-> FramebufferUpdateData (xs!!0) (xs!!1) (xs!!2) (xs!!3) (xs!!4)+			KeyEvent		-> KeyEventData (xs!!0) (xs!!1)+			PointerEvent		-> PointerEventData (xs!!0) (xs!!1) (xs!!2)+			ClientCutText		-> ClientCutTextData (xs!!0)+			BadCommand		-> BadCommandData+++word8ToCommand :: Word8 -> Command+word8ToCommand w = case w of+	0 -> SetPixelFormat+	2 -> SetEncodings+	3 -> FramebufferUpdate+	4 -> KeyEvent+	5 -> PointerEvent+	6 -> ClientCutText+	_ -> BadCommand
+ RFB/CommandLoop.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE NamedFieldPuns #-}+module RFB.CommandLoop (commandLoop) where++import System.IO+import qualified Data.ByteString.Lazy as BS++import Data.Char+import Data.Binary.Get+import Data.Binary.Put+import Data.Word++import qualified RFB.ClientToServer as RFBClient+import qualified RFB.Encoding as Encoding+import qualified RFB.State as RFBState++import Control.Monad.State+++type MyState a = StateT RFBState.RFBState  IO a++commandLoop :: Handle -> Int -> Int -> IO ()+commandLoop h width height= do+	runStateT (commandLoop1 h) (RFBState.initialState width height)+	return ()+++commandLoop1 :: Handle -> MyState ()+commandLoop1 handle = do+	commandByte <- liftIO$ BS.hGet handle 1+	let command = RFBClient.word8ToCommand $ runGet (do {x<-getWord8;return(x);}) commandByte+	byteStream <- liftIO $ BS.hGet handle (RFBClient.bytesToRead command)+	let commandData = RFBClient.getCommandData byteStream command+	--let commandData = RFBClient.parseCommandByteString byteStream command+	liftIO $ putStrLn $ "Client said -> " ++ (show command)+	liftIO $ putStrLn (show commandData)+	case command of+		RFBClient.SetPixelFormat -> processSetPixelFormat commandData+		RFBClient.SetEncodings -> liftIO $ processSetEncodings handle commandData +		RFBClient.FramebufferUpdate -> processFrameBufferUpdateRequest handle commandData+		RFBClient.PointerEvent -> processPointerEvent handle commandData+		RFBClient.ClientCutText -> processClientCutTextEvent handle commandData+		RFBClient.KeyEvent -> processKeyEvent handle commandData+		RFBClient.BadCommand -> liftIO $ putStrLn (show command)+	commandLoop1 handle++++processClientCutTextEvent handle (RFBClient.ClientCutTextData length) = do+	x <- liftIO $ BS.hGet handle length+	liftIO $ putStrLn (show x)++	++processKeyEvent handle commandData = do+	return ()++processPointerEvent handle (RFBClient.PointerEventData buttonMask x y)= do+	state@(RFBState.RFBState d i p pend u) <- get+	let newState=if buttonMask == 1 then Encoding.putPixel state (x,y) else state+	put newState+	if pend && ((length u) > 0) then do+			liftIO $ putStrLn $ "Updating -> " ++ (show u)+			liftIO $ BS.hPutStr handle (updateRectangles state)+			liftIO $ hFlush handle+			put (RFBState.RFBState d i p False [])+			return ()+		else +			return ()++++processSetPixelFormat (RFBClient.SetPixelFormatData bitsPerPixel depth bigEndian trueColor redMax greenMax blueMax redShift greenShift blueShift)+	= do+		state <- get+		let newState=RFBState.setPixelFormat state bitsPerPixel bigEndian redMax greenMax blueMax redShift greenShift blueShift+		put newState+		return ()++++processSetEncodings handle (RFBClient.SetEncodingsData count) = do+	x <- BS.hGet handle (4*count)+	let e = runGet (do {x<-getWord32le; return x}) x+	putStrLn (show e)+	return ()+++fullScreen :: Int -> Int -> Int -> Int -> RFBState.RFBState -> BS.ByteString+fullScreen x y width height state = runPut $ do+	putWord8 0+	putWord8 0+	putWord16be 1+	putWord16be (fromIntegral x)+	putWord16be (fromIntegral y)+	putWord16be (fromIntegral width)+	putWord16be (fromIntegral height)+	putWord32be 0+	Encoding.getImageByteString state x y width height+	return ()++++updateRectangles state@(RFBState.RFBState _ _ (RFBState.PixelFormat bpp _ _ _ _ _ _ _) pend updateList) = runPut $ do+	putWord8 0+	putWord8 0+	putWord16be (fromIntegral (length updateList))+	Encoding.encodeRectagles bpp updateList+	return ()++empty = runPut $ return ()+++	++processFrameBufferUpdateRequest handle (RFBClient.FramebufferUpdateData incremental x y width height) = do -- this produces black+	state@(RFBState.RFBState d i p pend u) <- get+	let byteString=if incremental == 0 then fullScreen x y width height state else (if (length u > 0) then updateRectangles state else empty)+	--let newState = if incremental == 0 then state else RFBState.RFBState d i p pend []+	let newState = if incremental == 0 then RFBState.RFBState d i p False [] else RFBState.RFBState d i p (if (length u > 0) then False else True) [] +	put newState+ 	(RFBState.RFBState _ _ _ newPend _) <- get+	liftIO $ putStrLn (show pend)+	liftIO $ putStrLn (show newPend)+	--liftIO $ putStrLn (show state)+	--liftIO $ putStrLn (show newState)+	liftIO $ BS.hPutStr handle byteString+	liftIO $ hFlush handle++
+ RFB/Handshake.hs view
@@ -0,0 +1,77 @@+module RFB.Handshake (handshake) where++import System.IO+import qualified Data.ByteString.Lazy as BS+import qualified Data.ByteString.Lazy.Char8 as B+import Data.Char+import Data.Binary.Get+import Data.Binary.Put+import Data.Word++import Control.Monad.State++type MyState a = StateT Int IO a++++handshake :: Int -> Int -> Handle -> IO ()+handshake w h hnd =  do+	runStateT (handshake1 w h hnd) 0+	return ()+			++handshake1 :: Int -> Int -> Handle -> MyState ()+handshake1 width height handle = do+	liftIO $ hPutStrLn handle "RFB 003.003"+	liftIO $ hFlush handle++	byteStream <- liftIO $ hGetLine handle+	liftIO $ putStrLn ("Client Said :: " ++ (show byteStream))+	let majorVersion = read $ (take 3).(drop 4) $ byteStream :: Int+	if majorVersion /= 3 then liftIO (fail ("Expected 3 but the Client sent " ++ (show majorVersion)))+		else liftIO $ return () -- contiue down the function++	-- Send 1 to the client, meaning, no auth required+	liftIO $ BS.hPutStr handle (BS.pack [0,0,0,1])+	liftIO $ hFlush handle++	clientInitMessage <- liftIO $ BS.hGet handle 1++	let sharedOrNot = runGet (do {x<-getWord8;return(x);}) clientInitMessage++	if sharedOrNot==1 then liftIO $ putStrLn "Sharing enabled"+		else liftIO $ putStrLn "Sharing disabled"++	liftIO $ BS.hPutStr handle (serverInitMessage width height)+	liftIO $ hFlush handle+++++serverInitMessage :: Int -> Int -> BS.ByteString+serverInitMessage width height = runPut $ do+				putWord16be (fromIntegral width::Word16) -- width+				putWord16be (fromIntegral height::Word16) -- height+				--pixel format+				putWord8 (32::Word8) -- bits per pixl+				putWord8 (24::Word8) -- depth+				putWord8 (1::Word8) -- big endian+				putWord8 (1::Word8) -- true color+				putWord16be (255::Word16) -- red max+				putWord16be (255::Word16) -- green max+				putWord16be (255::Word16) -- blue max+				putWord8 (16::Word8) -- red shift+				putWord8 (8::Word8)  -- green shift+				putWord8 (0::Word8)  -- blue shift++				--padding+				putWord8 (0::Word8)+				putWord8 (0::Word8)+				putWord8 (0::Word8)++				--name length+				let name = "Haskell Framebuffer"+				putWord32be (((fromIntegral.length) name)::Word32)+				--mapM_ (putWord8.fromIntegral.ord) name --this works+				putLazyByteString (B.pack name)+				--putLazyByteString (stringToByteString name) --this works
+ RFB/Server.hs view
@@ -0,0 +1,56 @@+module RFB.Server (serve) where++import Data.Bits+import Network.Socket+import Network.BSD+import Data.List+import Control.Concurrent+import Control.Concurrent.MVar+import System.IO+++-- HandlerFunc Width Height+type HandlerFunc = Int -> Int -> Handle -> IO ()++serve :: Int -> Int -> String -> HandlerFunc -> IO ()+serve width height port handlerFunc = withSocketsDo $+	do 	-- Look up the port.  Either raises an exception or returns+		-- a nonempty list.  +		addrinfos <- getAddrInfo +			(Just (defaultHints {addrFlags = [AI_PASSIVE]}))+			Nothing (Just port)+		let serveraddr = head addrinfos++		-- Create a socket+		sock <- socket (addrFamily serveraddr) Stream defaultProtocol++		-- Bind it to the address we're listening to+		bindSocket sock (addrAddress serveraddr)++		-- Start listening for connection requests.  Maximum queue size+		-- of 5 connection requests waiting to be accepted.+		listen sock 5++		-- Create a lock to use for synchronizing access to the handler+		lock <- newMVar ()++		-- Loop forever waiting for connections.  Ctrl-C to abort.+		procRequests lock sock+		where+		  -- | Process incoming connection requests+		  procRequests :: MVar () -> Socket -> IO ()+		  procRequests lock mastersock = +		      do (connsock, clientaddr) <- accept mastersock+			 forkIO $ procMessages lock connsock clientaddr+			 procRequests lock mastersock++		  -- | Process incoming messages+		  procMessages :: MVar () -> Socket -> SockAddr -> IO ()+		  procMessages lock connsock clientaddr =+		      do connhdl <- socketToHandle connsock ReadWriteMode+			 --hSetBuffering connhdl LineBuffering+			 --messages <- hGetContents connhdl+			 --mapM_ (handle lock clientaddr) (lines messages)+			 handlerFunc width height connhdl+			 hClose connhdl+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain