-- BBFocusImpl.mesa
-- Russ Atkinson, November 4, 1982 10:49 am

DIRECTORY
AMBridge USING
[FHFromTV, RemoteFHFromTV, RemoteFrameHandle, TVForFrame,
TVForGFHReferent,GetWorld, TVForRemoteFrame, TVForRemoteGFHReferent],
AMTypes USING [DynamicParent, Error, TVType, TypeClass],
BBAction USING [Action, NextPendingAction],
BBContext USING
[Context, ContextForGlobalFrame, ContextForLocalFrame, GetContents],
BBFocus USING [],
BBSafety USING [IsValidAddr],
Rope USING [Equal, ROPE],
RTBasic USING [TV],
WorldVM USING [Address, CurrentIncarnation, LocalWorld, Long, World, WorldName];

BBFocusImpl: CEDAR MONITOR
IMPORTS AMBridge, AMTypes, BBAction, BBContext, BBSafety, Rope, WorldVM
EXPORTS BBFocus
= BEGIN OPEN BBAction, BBContext, Rope, RTBasic, WorldVM;

defaultAction: Action ← NIL;
defaultContext: Context ← NIL;

-- Focus routines

GetDefaultActionAndContext: PUBLIC ENTRY PROC
RETURNS [action: Action, ctx: Context] = {
-- gives the current "place" for the user
action ← defaultAction;
ctx ← defaultContext;
};

SetDefaultActionAndContext: PUBLIC ENTRY PROC [action: Action, ctx: Context] = {
-- sets the default action and context
defaultAction ← action;
defaultContext ← ctx;
};

SetOctalContextFromGF: PUBLIC PROC
[gf: CARDINAL, world: World ← NIL] RETURNS [tv: TVNIL] = TRUSTED {
-- set the context to the given global frame in the current world
-- the frame also must be under some action
-- if anyAction = FALSE, must be under current action
-- returns NIL if given frame not valid in any way
addr: Address ← 0;
IF world = NIL THEN world ← GetCurrentWorld[];
addr ← WorldVM.Long[world, gf];
IF addr = 0 THEN {SetDefaultActionAndContext[NIL, NIL]; RETURN};
IF NOT BBSafety.IsValidAddr[world, addr] THEN RETURN;
IF world = WorldVM.LocalWorld[]
THEN
tv ← AMBridge.TVForGFHReferent
[LOOPHOLE[gf]
! AMTypes.Error => CONTINUE]
ELSE
tv ← AMBridge.TVForRemoteGFHReferent
[[world, world.CurrentIncarnation[], gf]
! AMTypes.Error => CONTINUE];
IF tv # NIL THEN
SetDefaultActionAndContext[NIL, BBContext.ContextForGlobalFrame[tv]];
};

SetOctalContextFromLF: PUBLIC PROC
[lf: CARDINAL, world: World ← NIL, anyAction: BOOLTRUE]
RETURNS [tv: TVNIL] = TRUSTED {
-- set the context to the given global frame in the current world
-- the frame also must be under some action
-- if anyAction = FALSE, must be under current action
-- returns NIL if given frame not valid in any way
addr: Address ← 0;
IF world = NIL THEN world ← GetCurrentWorld[];
addr ← WorldVM.Long[world, lf];
IF addr = 0 THEN {SetDefaultActionAndContext[NIL, NIL]; RETURN};
IF NOT BBSafety.IsValidAddr[world, addr] THEN RETURN;
IF world = WorldVM.LocalWorld[]
THEN
tv ← AMBridge.TVForFrame
[LOOPHOLE[lf]
! AMTypes.Error => CONTINUE]
ELSE
tv ← AMBridge.TVForRemoteFrame
[[world, world.CurrentIncarnation[], lf]
! AMTypes.Error => CONTINUE];
IF tv = NIL THEN RETURN;
FOR action: Action ← NextPendingAction[NIL], NextPendingAction[action]
UNTIL action = NIL DO
frame: TVNIL;
IF action.status # pendingOut THEN LOOP;
IF NOT anyAction AND action # defaultAction THEN LOOP;
frame ← FrameTVFromAction[action];
WHILE frame # NIL DO
-- try to find the given local frame in some pending action
IF SameLocalFrame[tv, frame] THEN
{-- we win!
SetDefaultActionAndContext[action, BBContext.ContextForLocalFrame[tv]];
RETURN;
};
frame ← AMTypes.DynamicParent[frame ! AMTypes.Error => EXIT];
ENDLOOP;
ENDLOOP;
};

GetCurrentWorld: PUBLIC ENTRY PROC RETURNS [world: World] = TRUSTED {
-- inherits world from current action OR context
ENABLE UNWIND => NULL;
IF defaultAction = NIL OR defaultAction.status = dead OR defaultAction.event = NIL THEN
{-- try to get it through the default context
world ← defaultContext.GetContents[].world;
IF world = NIL THEN world ← WorldVM.LocalWorld[];
RETURN;
};
world ← IF defaultAction.event = NIL THEN NIL ELSE defaultAction.event.world;
IF world = NIL THEN world ← WorldVM.LocalWorld[];
};

-- a couple of minor uilities

FrameTVFromAction: PUBLIC PROC [action: Action] RETURNS [lf: TVNIL] = {
-- get the local frame for the given action
-- can be NIL if the action is no longer valid
IF action # NIL AND action.status # dead AND action.event # NIL THEN
lf ← action.event.frame;
};

SameLocalFrame: PUBLIC PROC [lf1,lf2: TV] RETURNS [BOOL] = TRUSTED {
-- tests two local frame TVs for equality
IF lf1 = lf2 THEN RETURN [TRUE];
IF AMTypes.TVType[lf1] # AMTypes.TVType[lf2] THEN RETURN [FALSE];
IF AMTypes.TypeClass[AMTypes.TVType[lf1]] # localFrame THEN RETURN [FALSE];
{world1: WorldVM.World ← AMBridge.GetWorld[lf1];
world2: WorldVM.World ← AMBridge.GetWorld[lf2];
IF world1 = NIL THEN world1 ← WorldVM.LocalWorld[];
IF world2 = NIL THEN world2 ← WorldVM.LocalWorld[];
IF world1 # world2 AND
NOT Rope.Equal[world1.WorldName[], world2.WorldName[], FALSE]
THEN RETURN [FALSE];
IF world1 = WorldVM.LocalWorld[]
THEN
RETURN [AMBridge.FHFromTV[lf1] = AMBridge.FHFromTV[lf2]]
ELSE
{RETURN [AMBridge.RemoteFHFromTV[lf1].fh =
AMBridge.RemoteFHFromTV[lf2].fh]};
};
};

END.