mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-26 01:49:19 +00:00
387 lines
17 KiB
OpenEdge ABL
387 lines
17 KiB
OpenEdge ABL
{
|
|
File: AEInteract.inc1.p
|
|
|
|
Contains: xxx put contents here xxx
|
|
|
|
Written by: xxx put writers here xxx
|
|
|
|
Copyright: © 1990 by Apple Computer, Inc., all rights reserved.
|
|
|
|
This file is used in these builds: BigBang
|
|
|
|
Change History (most recent first):
|
|
|
|
<4> 3/15/91 Lai BM,#83128: Remove notification when interacting with event from
|
|
another process.
|
|
<3> 2/13/91 Lai BM,#82759: In AE_InteractWithUser, timeOutInTicks are not
|
|
translated to actual value before attempting to switch layer,
|
|
now this is fixed by calling CalculateTimeOut in the front of
|
|
the procedure.
|
|
<2> 1/11/91 Lai change msgAddrTargetID to match change in AEUtil.p
|
|
<1> 12/13/90 Lai first checked in
|
|
|
|
To Do:
|
|
}
|
|
|
|
{--------------------------------------------------------------------------------}
|
|
|
|
{ ask the front application to take me to the front by sending an AppleEvent }
|
|
{ later write to use AEM calls to see if it is shorter }
|
|
|
|
PROCEDURE AskToComeToFront(theMsg: MsgHdrHdl;
|
|
waitTillTime: LONGINT);
|
|
|
|
TYPE
|
|
CansBuffer = RECORD
|
|
aevtMarker: AEKeyWord;
|
|
version: LONGINT;
|
|
timeOutKeyword: AEKeyWord;
|
|
timeOutType: DescType;
|
|
timeOutSize: LONGINT;
|
|
timeOutValue: LONGINT;
|
|
metaTerminator: AEKeyWord;
|
|
END;
|
|
|
|
VAR
|
|
theEvent: EventRecord;
|
|
aCansBuffer: CansBuffer;
|
|
|
|
BEGIN
|
|
WITH theEvent DO
|
|
BEGIN
|
|
theEvent.message := LONGINT(kCoreEventClass);
|
|
LONGINT(where) := LONGINT(kCanSwitchIfInteract);
|
|
modifiers := 0;
|
|
END;
|
|
WITH aCansBuffer DO
|
|
BEGIN
|
|
aevtMarker := kCoreEventClass;
|
|
version := kVersionOne;
|
|
metaTerminator := aeEndOfMetaDataKeyword;
|
|
timeOutKeyword := keyBeforeTime;
|
|
timeOutType := typeLongInteger;
|
|
timeOutSize := SizeOf(LONGINT);
|
|
timeOutValue := waitTillTime;
|
|
END;
|
|
WITH theMsg^^ DO
|
|
IgnoreOSErr(PostHighLevelEvent(theEvent, Ptr(msgAddrTarget.asTargetID.sessionID), returnID,
|
|
@aCansBuffer, SizeOf(aCansBuffer),
|
|
receiverIDisSessionID));
|
|
END;
|
|
|
|
{--------------------------------------------------------------------------------}
|
|
|
|
|
|
{ we try to determine if we can interact with the user }
|
|
{ may be no interaction is allowed either because the client don't want it or the
|
|
server machine don't want to have any interaction }
|
|
{ if interaction is allowed, we still need to have get a change to do it }
|
|
{ if the server is the front application, you get it immediately }
|
|
{ if the server is not in front, switch to front if the client is in front and
|
|
grant you the permission to go to the front, otherwise post a notification and
|
|
wait until your application is in the front }
|
|
|
|
FUNCTION AE_InteractWithUser(timeOutInTicks: LONGINT; { how long are you willing to wait }
|
|
nmReqPtr: NMRecPtr; { your own custom notification }
|
|
idleProc: IdleProcPtr { your own idle procedure }
|
|
): OSErr; { return the error }
|
|
|
|
LABEL 999, 1000;
|
|
|
|
VAR
|
|
myPSN, frontPSN, fromPSN: ProcessSerialNumber;
|
|
err: OSErr;
|
|
myNMRec: NMRec;
|
|
nowInFront, localProcess, switchDirectly: Boolean;
|
|
interactType: OSType;
|
|
dummyType: DescType;
|
|
actualSize: LONGINT;
|
|
waitSetFrontProcess: LONGINT;
|
|
curInteract: AEInteractAllowed;
|
|
flag: SignedByte;
|
|
scaled: Boolean;
|
|
aevtSource: AEEventSource;
|
|
currentDesc: AppleEvent;
|
|
|
|
{ this may be nested procedure but actual compiled code show it is shorter }
|
|
|
|
FUNCTION GetDefaultID(VAR theID: integer): Boolean;
|
|
{ get the ID of the application ICON }
|
|
|
|
VAR
|
|
tempHandle: Handle;
|
|
i, j, k, localID: integer;
|
|
count1: integer;
|
|
count2: integer;
|
|
countFREF: integer;
|
|
countBNDL: integer;
|
|
aPtr: IntegerPtr;
|
|
hasID: Boolean;
|
|
aProcessInfoRec: ProcessInfoRec;
|
|
|
|
BEGIN
|
|
GetDefaultID := FALSE;
|
|
WITH aProcessInfoRec DO
|
|
BEGIN
|
|
processInfoLength := SizeOf(ProcessInfoRec); { we only need processSignature }
|
|
processName := NIL; { who cares }
|
|
processAppSpec := NIL;
|
|
END;
|
|
IF GetProcessInformation(myPSN, aProcessInfoRec) = noErr THEN
|
|
BEGIN
|
|
countFREF := CountResources('FREF');
|
|
{ we first try to find the resource ID, by first looking at FREF resource and find the local ID
|
|
of APPL, then we look at the BNDL resource to find the ID corresponding to the local ID }
|
|
FOR i := 1 TO countFREF DO
|
|
BEGIN
|
|
{ look through all 'FREF' resources }
|
|
tempHandle := GetIndResource('FREF', i);
|
|
IF (tempHandle <> NIL) & (LONGINTPtr(tempHandle^)^ = LONGINT('APPL')) THEN
|
|
BEGIN
|
|
localID := IntegerPtr(ord(tempHandle^) + 4)^;
|
|
countBNDL := CountResources('BNDL');
|
|
FOR j := 1 TO countBNDL DO
|
|
BEGIN { we try to find the BNDL from this application }
|
|
tempHandle := GetIndResource('BNDL', j);
|
|
IF (tempHandle <> NIL) & (LONGINTPtr(tempHandle^)^ =
|
|
LONGINT(aProcessInfoRec.processSignature)) THEN
|
|
BEGIN { this is the right BNDL }
|
|
aPtr := IntegerPtr(ord(tempHandle^) + 6);
|
|
count1 := aPtr^;
|
|
aPtr := IntegerPtr(ord(aPtr) + 2);
|
|
FOR j := 0 TO count1 DO
|
|
BEGIN
|
|
IF LONGINTPtr(aPtr)^ = LONGINT('FREF') THEN
|
|
BEGIN
|
|
aPtr := IntegerPtr(ord(aPtr) + 4); { skip over FREF }
|
|
count2 := aPtr^;
|
|
aPtr := IntegerPtr(ord(aPtr) + 2); { skip over count }
|
|
FOR k := 0 TO count2 DO
|
|
BEGIN
|
|
IF aPtr^ = localID THEN
|
|
BEGIN
|
|
GetDefaultID := TRUE;
|
|
theID := IntegerPtr(ord(aPtr) + 2)^;
|
|
Exit(GetDefaultID);
|
|
END;
|
|
aPtr := IntegerPtr(ord(aPtr) + 4); { skip to next one }
|
|
END;
|
|
Exit(GetDefaultID);
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
aPtr := IntegerPtr(ord(aPtr) + 4); { skip over type name }
|
|
aPtr := IntegerPtr(ord(aPtr) + 4 * aPtr^ + 6); { skip over
|
|
this type }
|
|
END;
|
|
END; { look for FREF }
|
|
END; { is the right BNDL }
|
|
END; { search all BNDL loop }
|
|
END; { is FREF for APPL }
|
|
END; { search all FREF loop }
|
|
END; { no err in GetProcessInformation }
|
|
END;
|
|
|
|
FUNCTION GetDefaultSICN: Handle;
|
|
{ get a default SICN from the application }
|
|
|
|
VAR
|
|
tempHandle: Handle;
|
|
tryICN: Handle;
|
|
srcBits, dstBits: BitMap;
|
|
theID: integer;
|
|
|
|
BEGIN
|
|
tempHandle := NIL;
|
|
IF GetDefaultID(theID) THEN
|
|
BEGIN
|
|
{ we find out the default ID, use it to get the resource }
|
|
tempHandle := GetResource('SICN', theID);
|
|
IF tempHandle <> NIL THEN
|
|
BEGIN
|
|
{ we have a SICN, use it }
|
|
flag := HGetState(tempHandle);
|
|
HNoPurge(tempHandle);
|
|
scaled := FALSE;
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
{ we do not have a small icon, then try to scale it down from the icon }
|
|
tryICN := GetResource('ICN#', theID); { first we try to read it in }
|
|
IF tryICN <> NIL THEN { yes, we have one }
|
|
BEGIN
|
|
flag := HGetState(tryICN);
|
|
HLock(tryICN); { lock it down first }
|
|
tempHandle := NewHandle(32); { create a handle for a small icon }
|
|
IF tempHandle <> NIL THEN
|
|
BEGIN { copy it in }
|
|
HLock(tempHandle);
|
|
WITH srcBits DO
|
|
BEGIN
|
|
SetRect(bounds, 0, 0, 32, 32);
|
|
rowBytes := 4;
|
|
baseAddr := tryICN^
|
|
END;
|
|
WITH dstBits DO
|
|
BEGIN
|
|
SetRect(bounds, 0, 0, 16, 16);
|
|
rowBytes := 2;
|
|
baseAddr := tempHandle^
|
|
END;
|
|
{ scale it down }
|
|
CopyBits(srcBits, dstBits, srcBits.bounds, dstBits.bounds, srcCopy,
|
|
NIL);
|
|
HUnLock(tempHandle);
|
|
scaled := TRUE;
|
|
END;
|
|
HSetState(tryICN, flag);
|
|
END;
|
|
END;
|
|
END;
|
|
GetDefaultSICN := tempHandle;
|
|
END;
|
|
|
|
BEGIN
|
|
err := noErr;
|
|
CalculateTimeOut(timeOutInTicks);
|
|
IgnoreOSErr(GetFrontProcess(frontPSN));
|
|
IgnoreOSErr(GetCurrentProcess(myPSN));
|
|
IgnoreOSErr(SameProcess(frontPSN, myPSN, nowInFront)); { are we already in front? }
|
|
interactType := kCanInteract; { this is the default if it is not specified in the message }
|
|
switchDirectly := FALSE;
|
|
IgnoreOSErr(AE_GetTheCurrentEvent(currentDesc));
|
|
EventSource(MsgHdrHdl(currentDesc.dataHandle), aevtSource, fromPSN); { where is it from? }
|
|
IF aevtSource <> kAEUnknownSource THEN
|
|
BEGIN { we have a message }
|
|
IgnoreOSErr(AE_GetInteractionAllowed(curInteract));
|
|
{ find the interact level specified by the message }
|
|
IgnoreOSErr(AE_GetKeyPtr(MakeMeta(currentDesc), keyInteractLevelAttr, typeEnumerated,
|
|
dummyType, @interactType, 4, actualSize));
|
|
IF LONGINT(interactType) = LONGINT(kNeverInteract) THEN { the message specified no
|
|
interact }
|
|
GOTO 999;
|
|
WITH MsgHdrHdl(currentDesc.dataHandle)^^ DO
|
|
BEGIN
|
|
IF (aevtSource = kAELocalProcess) OR (aevtSource = kAERemoteProcess) THEN
|
|
BEGIN
|
|
{ now we know it is not send-to-self }
|
|
IF (curInteract = kAEInteractWithSelf) THEN GOTO 999; { the server don't want to
|
|
interact with others }
|
|
IF aevtSource = kAELocalProcess THEN
|
|
BEGIN
|
|
{ if msg came from front process, we can switch directly }
|
|
IF (interactType[4] = 's') THEN { and they give us permission }
|
|
IgnoreOSErr(SameProcess(frontPSN, fromPSN, switchDirectly));
|
|
END
|
|
ELSE
|
|
BEGIN
|
|
{ this comes from another machine }
|
|
IF curInteract <> kAEInteractWithAll THEN GOTO 999;
|
|
END;
|
|
END;
|
|
END
|
|
END;
|
|
IF NOT nowInFront THEN { only need to do something if nor already in front }
|
|
BEGIN { not the front process, try to get to the front }
|
|
IF timeOutInTicks = 0 THEN
|
|
err := errAETimeOut
|
|
ELSE
|
|
BEGIN
|
|
IF switchDirectly THEN
|
|
BEGIN
|
|
waitSetFrontProcess := 15; { we can wait this long for it to switch }
|
|
{ but we don't have that much time we have to make do with less }
|
|
IF timeOutInTicks < waitSetFrontProcess THEN
|
|
waitSetFrontProcess := timeOutInTicks;
|
|
{ this is the amount left over }
|
|
timeOutInTicks := timeOutInTicks - waitSetFrontProcess;
|
|
AskToComeToFront(MsgHdrHdl(currentDesc.dataHandle), TickCount + waitSetFrontProcess);
|
|
err := GeneralWait(waitSetFrontProcess, idleProc, NIL, NIL);
|
|
IF err = errAETimeOut THEN
|
|
switchDirectly := FALSE { we fail to switch before time is up }
|
|
ELSE { we did not use it all up, so add it back }
|
|
timeOutInTicks := timeOutInTicks + waitSetFrontProcess;
|
|
END;
|
|
|
|
IF switchDirectly THEN { remember it so we can go back }
|
|
MsgHdrHdl(currentDesc.dataHandle)^^.switchFromPSN := fromPSN
|
|
ELSE
|
|
BEGIN
|
|
{ otherwise we just use notification }
|
|
IF nmReqPtr = NIL THEN
|
|
BEGIN { if no notification record is provided, we make our own }
|
|
WITH myNMRec DO
|
|
BEGIN
|
|
qType := nmType;
|
|
nmMark := 1;
|
|
nmIcon := GetDefaultSICN;
|
|
IF nmIcon = NIL THEN
|
|
nmSound := Handle( - 1)
|
|
ELSE
|
|
nmSound := NIL;
|
|
nmStr := NIL;
|
|
nmResp := NIL;
|
|
END;
|
|
nmReqPtr := @myNMRec;
|
|
END;
|
|
IgnoreOSErr(NMInstall(nmReqPtr));
|
|
{ now we call the general wait routine, last two parameter are nil means wait to come to front }
|
|
err := GeneralWait(timeOutInTicks, idleProc, NIL, NIL);
|
|
IgnoreOSErr(NMRemove(nmReqPtr));
|
|
IF ord(nmReqPtr) = ord(@myNMRec) THEN
|
|
WITH myNMRec DO { it is our own, and it was installed, we have to take care
|
|
of it }
|
|
IF nmIcon <> NIL THEN
|
|
BEGIN { we have a small icon }
|
|
IF scaled THEN
|
|
DisposHandle(nmIcon) { we created it, so we free it }
|
|
ELSE
|
|
HSetState(nmIcon, flag); { it is from resource, just restore its
|
|
state }
|
|
END;
|
|
END;
|
|
END;
|
|
END;
|
|
|
|
GOTO 1000;
|
|
999:
|
|
err := errAENoUserInteraction;
|
|
1000:
|
|
AE_InteractWithUser := err;
|
|
END;
|
|
|
|
{--------------------------------------------------------------------------------}
|
|
|
|
{ Used by the server if the command received is going to take some time to process. }
|
|
{ Use the reply to get the necessary information to send a 'wait' back to the client }
|
|
{ This will cause the client to reset its timeout loop and wait longer }
|
|
|
|
FUNCTION AE_ResetTimer(VAR reply: AppleEvent): OSErr;
|
|
|
|
VAR
|
|
theEvent: EventRecord;
|
|
|
|
BEGIN
|
|
AE_ResetTimer := errAEReplyNotValid;
|
|
IF reply.dataHandle <> NIL THEN
|
|
BEGIN
|
|
WITH MsgHdrHdl(reply.dataHandle)^^ DO
|
|
BEGIN
|
|
IF LONGINT(thisAEEventClass) = LONGINT(kCoreEventClass) THEN
|
|
IF LONGINT(thisAEEventID) = LONGINT(kAEAnswer) THEN
|
|
IF LONGINT(msgAddrType) = LONGINT(typeSessionID) THEN
|
|
BEGIN
|
|
theEvent.message := LONGINT(kCoreEventClass);
|
|
LONGINT(theEvent.where) := LONGINT(kAEWaitLonger);
|
|
theEvent.modifiers := 0;
|
|
AE_ResetTimer := PostHighLevelEvent(theEvent,
|
|
Ptr(msgAddrTarget.asTargetID.sessionID),
|
|
returnID, NIL, 0,
|
|
receiverIDisSessionID);
|
|
END;
|
|
END;
|
|
END;
|
|
END;
|
|
|
|
{--------------------------------------------------------------------------------}
|