-- TalkerImpl.mesa
-- Paul Rovner, May 4, 1983 5:09 pm
DIRECTORY
BBSafety
USING [Mother],
CedarSnapshot
USING [Register, AddSpaceProc, After],
Commander
USING [Register, CommandProc],
Containers
USING [ChildXBound, ChildYBound],
Labels
USING [Label, Create, Set],
Icons
USING [IconFlavor, NewIconFromFile],
MBQueue
USING [Queue, Create, CreateMenuEntry, QueueClientAction],
Interpreter
USING [EvaluateToRope],
IO
USING [GetId, PutRope,
STREAM, time, char, Put, EndOfStream, RIS],
Menus
USING[CreateMenu, InsertMenuEntry, Menu, MenuProc],
Process
USING [Detach],
Rope
USING[
ROPE, Concat, Find, Cat, Equal],
RPC
USING[MakeKey],
TalkerOps
USING[],
-- EXPORTS ONLY
TalkerOpsRpcControl
USING[InterfaceRecord, ImportNewInterface, ExportInterface,
UnexportInterface],
TalkerPrivate
USING[Handle, ConversationObject, Conversant, ConversantObject, Puller,
SendOutGoingLines, JoinConversation, ComputeStatus, RemakeStatusLabel,
PaintLine, KillConversation, IsViewer, BlinkOff, FindConversant,
JoinConversationHit, ShowStatusHit, LowerRope,
RemoveConversantFromOtherConversations],
TypeScript
USING [Create,
TS],
UserCredentials
USING [GetUserCredentials],
VFonts
USING [CharWidth, FontHeight],
ViewerClasses
USING [Viewer],
ViewerEvents
USING [EventProc, RegisterEventProc, ViewerEvent],
ViewerIO
USING [CreateViewerStreams],
ViewerOps
USING [CreateViewer],
Volume
USING [GetType, systemID];
TalkerImpl:
CEDAR
MONITOR
-- protects "conversations" list
IMPORTS BBSafety, CedarSnapshot, Commander, Containers, Icons, Interpreter,
IO, Labels,
MBQueue, Menus, Process, Rope,
RPC, TalkerOpsRpcControl, TalkerPrivate, TypeScript,
UserCredentials, VFonts, ViewerEvents, ViewerIO, ViewerOps, Volume
EXPORTS TalkerOps, TalkerPrivate
=
BEGIN
OPEN Rope, TalkerPrivate;
-- VARIABLES
conversations:
LIST
OF Handle ←
NIL;
talkerIcon: Icons.IconFlavor = Icons.NewIconFromFile["Talker.icons", 0];
viewerEventQueue: MBQueue.Queue = MBQueue.Create[];
-- PROCEDURES
-- ******* interface procedures
-- registered with Commander
Talk: Commander.CommandProc = {
--PROC [cmd: Commander.Handle]
h: Handle ←
NIL;
cls:
IO.
STREAM =
IO.
RIS[cmd.commandLine];
DO
{conversantName:
ROPE ←
NIL;
conversantName ← cls.GetId[ !
IO.EndOfStream =>
GOTO endOfStream;
ANY =>
CONTINUE];
IF conversantName #
NIL
THEN {
IF Find[conversantName, "."] = -1
THEN conversantName ← Concat[conversantName, ".pa"];
IF Rope.Equal[conversantName, GetLocalName[],
FALSE]
THEN
GOTO badConversant;
IF h =
NIL
THEN [h, ] ← FindConversation[conversantName
!
ANY =>
GOTO badConversant]
ELSE JoinConversation[h, conversantName
!
ANY =>
GOTO badConversant];
RemoveConversantFromOtherConversations[h, conversantName
!
ANY =>
GOTO badConversant];
EXITS badConversant => cmd.out.PutRope
[Cat[" ***Talker error: no such conversant: ",
conversantName,
"\n"] !
ANY =>
CONTINUE]};
EXITS endOfStream =>
EXIT}
ENDLOOP;
IF h #
NIL
THEN RemakeStatusLabel[h];
};
-- end
Talk
Talkable: Commander.CommandProc = {
--PROC [cmd: Commander.Handle]
cls:
IO.
STREAM =
IO.
RIS[cmd.commandLine];
DO
{conversantName:
ROPE ←
NIL;
conversantName ← cls.GetId[ !
IO.EndOfStream =>
GOTO endOfStream;
ANY =>
CONTINUE];
IF conversantName #
NIL
THEN {
IF Find[conversantName, "."] = -1
THEN conversantName ← Concat[conversantName, ".pa"];
IF Rope.Equal[conversantName, GetLocalName[],
FALSE]
THEN
GOTO badConversant;
[] ← TalkerOpsRpcControl.ImportNewInterface
[interfaceName: [instance: LowerRope[conversantName]]
!
ANY =>
GOTO badConversant];
EXITS badConversant => cmd.out.PutRope
[Cat[" ",
conversantName,
" not registered as a conversant\n"]
!
ANY =>
CONTINUE]};
EXITS endOfStream =>
EXIT}
ENDLOOP;
};
-- end
Talkable
-- RPC magic. These are the only procs called by remote clients.
PutMyLine:
PUBLIC
PROC[myName:
ROPE, line:
ROPE] = {
h: Handle ←
NIL;
rePaintStatus:
BOOL ←
FALSE;
[h, rePaintStatus] ← FindConversation[myName !
ANY =>
CONTINUE];
IF h =
NIL
THEN
RETURN;
PaintLine[h, Cat[myName, ": ", line]];
IF rePaintStatus
THEN RemakeStatusLabel[h];
};
-- end PutMyLine
JoinWith:
PUBLIC
PROC[myName:
ROPE, newConversant:
ROPE] = {
h: Handle ←
NIL;
rePaintStatus:
BOOL ←
FALSE;
IF Equal[newConversant, myName,
FALSE]
THEN
RETURN;
[h, rePaintStatus] ← FindConversation[myName !
ANY =>
CONTINUE];
IF h =
NIL
THEN
RETURN;
JoinConversation[h, newConversant];
RemakeStatusLabel[h];
RemoveConversantFromOtherConversations[h, newConversant];
RemoveConversantFromOtherConversations[h, myName];
};
-- end
JoinWith
DealMeOut:
PUBLIC
PROC[myName:
ROPE] = {
RemoveConversantFromOtherConversations[
NIL, myName];
};
-- end
DealMeOut
Cancel:
PUBLIC
PROC[conversant:
ROPE]
RETURNS[
ROPE] = {
result:
ROPE;
errorRope:
ROPE;
noResult:
BOOL;
motherRope:
ROPE;
inner:
PROC = {
[result, errorRope, noResult] ← Interpreter.EvaluateToRope[conversant];
};
motherRope ← BBSafety.Mother[inner];
IF motherRope #
NIL
THEN
RETURN[Cat["Mother: ", motherRope]]
ELSE
IF errorRope #
NIL
THEN
RETURN[Cat["Error: ", errorRope]]
ELSE
IF noResult
THEN
RETURN["NoResult"]
ELSE
RETURN[result];
};
Horse:
PROC[n, r:
ROPE]
RETURNS[ans:
ROPE ←
NIL] = {
ir: TalkerOpsRpcControl.InterfaceRecord;
IF Find[n, "."] = -1
THEN n ← Cat[n, ".pa"];
ir ← TalkerOpsRpcControl.ImportNewInterface[interfaceName: [instance: LowerRope[n]]];
TRUSTED{ans ← ir.Cancel[r]};
};
-- ******* menu and event procedures
DisconnectHit: Menus.MenuProc = {
-- [parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]
h: Handle ←
NARROW[clientData, Handle];
KillConversation[h];
RemakeStatusLabel[h];
};
-- end DisconnectHit
VEBundle: TYPE = RECORD[viewer: ViewerClasses.Viewer, event: ViewerEvents.ViewerEvent];
ViewerEvent: ViewerEvents.EventProc = {
PROC [viewer: ViewerClasses.Viewer, event: ViewerEvents.ViewerEvent];
MBQueue.QueueClientAction
[viewerEventQueue,
DoViewerEvent,
NEW[VEBundle ← [viewer, event]]];
};