module talk // ************************************************************************************************** // // This program creates two interactive processes that communicate via message passing. // In a future distributed version this program can be used as a graphical talk application. // // The program has been written in Clean 2.0 and uses the Clean Standard Object I/O library 1.2.2 // // ************************************************************************************************** import StdEnv, StdIO // The message type of talk processes: :: Message = NewLine String // Transmit a line of text | Quit // Request termination // Start creates two talk processes A and B that communicate by means of message passing. Start :: *World -> *World Start world # (a, world) = openRId world # (b, world) = openRId world # (talkA,world) = talk "A" a b world # (talkB,world) = talk "B" b a world = startProcesses [talkA,talkB] world /* talk name me you defines a talk process named name, to which messages can be sent of type Message via me, and that sends messages of type Message to a receiver you. */ talk :: String (RId Message) (RId Message) *World -> (Process,*World) talk name me you world # (wId, world) = openId world # (outId,world) = openId world # (inId, world) = openId world = ( Process SDI Void (initialise wId outId inId) [ProcessClose (quit you)] , world ) where initialise wId outId inId pst # (size,pst) = controlSize (input wId inId you :+: output outId inId) True Nothing Nothing Nothing pst talkwindow = Window ("Talk "+++name) (input wId inId you :+: output outId inId) [ WindowId wId , WindowViewSize size ] menu = Menu ("&Talk "+++name) ( MenuItem "&Quit" [MenuShortKey 'q',MenuFunction (noLS (quit you))] ) [] receiver = Receiver me (noLS1 (receive wId outId)) [] # (_,pst) = openWindow undef talkwindow pst # (_,pst) = openMenu undef menu pst # (_,pst) = openReceiver undef receiver pst = pst input wId inId you = EditControl "" (PixelWidth (hmm 50.0)) 5 [ ControlId inId , ControlKeyboard inputfilter Able (noLS1 (keyinput wId inId you)) , ControlResize editResize , ControlTip "Type your message here" ] output outId inId = EditControl "" (PixelWidth (hmm 50.0)) 5 [ ControlId outId , ControlPos (Below inId,NoOffset) , ControlSelectState Unable , ControlResize editResize , ControlTip "Received messages appear here" ] /* editResize handles the resize of the two input fields. */ editResize :: Size Size Size -> Size editResize _ _ newWindowSize=:{h} = {newWindowSize & h=h/2} /* keyinput handles keyboard input in the input EditControl: for every KeyDown keyboard input that has been accepted by the input EditControl, input sends the current content text of the input EditControl to the other talk process with (NewLine text). */ inputfilter :: KeyboardState -> Bool inputfilter keystate = getKeyboardStateKeyState keystate<>KeyUp keyinput :: Id Id (RId Message) KeyboardState (PSt .l) -> PSt .l keyinput wId inId you _ pst # (Just window,pst) = accPIO (getWindow wId) pst text = fromJust (snd (getControlText inId window)) = snd (asyncSend you (NewLine text) pst) /* The message passing protocol of a talk process. On receipt of: (1) NewLine text:set the new text to the output control field of the talk dialog. (2) Quit: this is always the last message of the other talk process when termination is requested. The process should terminate itself. */ receive :: Id Id Message (PSt .l) -> PSt .l receive wId outId (NewLine text) pst=:{io} = {pst & io=setEditControlCursor outId (size text) (setControlText outId text io)} receive _ _ Quit pst = closeProcess pst /* The quit command first sends the Quit message to the other talk process and then quits itself. */ quit :: (RId Message) (PSt .l) -> PSt .l quit you pst = closeProcess (snd (syncSend you Quit pst))