mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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;
|
|
|
|
{--------------------------------------------------------------------------------}
|