sys7.1-doc-wip/Toolbox/NotificationMgr/NotificationMgr.c
2020-04-26 16:46:44 +08:00

926 lines
27 KiB
C

/*
Hacks to match MacOS (most recent first):
<Sys7.1> 8/3/92 Reverted <SM5>/<SM6>: restored the simple SndPlay to DoSound
Reverted <SM4>: removed early-return speedup from NMTask
9/2/94 SuperMario ROM source dump (header preserved below)
*/
/*
File: NotificationMgr.c
Contains: Notification Manager
Written by: Ed Tecot
Copyright: © 1987-1994 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<SM6> 1/8/94 kc Initialize SndChannelPtr before calling SndNewChannel in
DoSound. This fixes bug found in MacWorld Compatability Lab.
<SM5> 12/21/93 SAM Changed DoSound to manually get a new sound channel and set its
volume to the "alert" volume level before calling SndPlay.
<SM4> 5/18/93 RC perfomance/bug fix (seed up WaitNextEvent by 20%)
<SM3> 12/3/92 RB Renamed Call to avoid a conflict.
<14> 5/29/92 DCL Included TextUtils.p. EqualString was moved for the New Inside
Mac.
<13> 10/28/91 SAM/KSM Rolled in Regatta changes.
Regatta Change History:
<3> 6/14/91 SAM (HJR) Added a call to IdleUpdate() on _NMInstall calls to wake
the the system up when NM procs want to run.
<1> 5/22/91 SAM Split off from 7.0 GM sources.
7.0 Change History:
<12> 4/3/91 dba kill all the fun
<11> 3/4/91 dba dty: get rid of SysVers conditional
<10> 1/21/91 DFH (KSM) Process Menu is now called Application Menu.
<9> 10/10/90 JL Add Errors.h to Include List for nmTypErr
<8> 9/21/90 VL Juggled the fields in QHdr because we are patching some routines
in ci and portable ROMs. Preserving the order of the fields in
the original record allows us not to patch all of the routines.
<7> 8/18/90 dba get rid of code that does dialog centering for 7.0, since the
Window Mgr. will do it for us
<6> 7/17/90 dba use Memory.h all the time (MemUtils.h is obsolete); get rid of C
warning from unused parameter
<5> 7/16/90 VL See "Changes for 7.0".
<4> 7/10/90 dba add prototypes to avoid warnings
<3> 7/7/90 dba use standard Memory.h and OSUtils.h for system disk version
<2> 3/20/90 EMT Rewrote HaveCQD() macro to generate less code. Removed
RealMBarHeight stuff - MBarHeight is sufficient.
<1.2> 11/17/89 dba got rid of check for 64K ROMs
<1.1> 11/9/88 CCH Fixed file header.
<1.0> 11/9/88 CCH Adding to EASE.
<1.7> 11/1/88 GGD Added even more type coercions so that it compiles under MPW
3.0b1.
<1.6> 10/10/88 MSH Added type coercions so that it compiles under MPW 3.0b1.
<1.5> 9/16/88 cv Added type coersion so that it compiles with MPW3.0a2
<1.4> 8/4/88 BBM Changed FLUSHAPPLNM to uppercase for numac build
<1.3> 7/13/88 EMT Rolled in S474: Fixed bug so response procedure gets called.
<1.2> 5/23/88 BBM Changed NMInit to uppercase.
<1.1> 5/19/88 BBM Converted to MPW C 3.0.
<1.0> 3/22/88 EMT First time adding Notification Manager sources
*/
/*********************************************************************************************
*
* Changes for 7.0
*
* User-interface changes:
* 1) If a notification is coming from a process which is listed under the Application Menu,
* the blinking icon is put above the Application Menu. Otherwise, the blinking icon will be
* put above the Apple Menu. The latter case applies to DAs and system-level tasks.
* 2) The marks (or the diamonds) are put on the left of the menu items under the Application Menu.
* No mark will be put in the Apple Menu.
* 3) The NM can now blink color icon. The handle to the color icon suite is passed in the
* nmIcon field (previously nmSIcon field). The NM distinguishes the 2 kinds of icons by
* the size of the handle in nmIcon.
*
* Engineering changes:
* 1) In order to deal with blinking icons on both the Apple Menu and the Application Menu, an
* extra queue is added to NMHdr. amIcons and pmIcons will contain IconRec's for the Apple
* Menu and the Application Menu respectively. curAMIconRec and curPMIconRec contain the current
* icons for the Apple Menu and Application Menu.
* 2) An extra boolean is added to NMHdr. It shows whether NM should put up a new icon on the
* Apple Menu or the Application Menu. The icons above the 2 menus blink alternately.
* 3) In order to deal with color icon, a new Boolean iconSuite is added to IconRec so that
* the NM will know which kind of icon to plot.
* 4) GetApplicationMenu now gets the Application Menu for the 7.0 system while it gets the
* Apple menu in the 6.0 system.
* 5) New MBDF messages are added to deal with drawing above the Application Menu and color icon
* suites.
* 6) WaitSThresh is no longer a constant. It becomes a macro and returns the long or short
* wait time according to the state of the icon queues. The long wait time is used when
* icons are only blinking on one side while the short wait time is used when icons are
* blinking on both sides.
*
********************************************************************************************/
#include <Types.h>
#include <Errors.h>
#include <Memory.h>
#include <OSUtils.h>
#include <TextUtils.h>
#include <Devices.h>
#include <Events.h>
#include <Resources.h>
#include <Controls.h>
#include <Dialogs.h>
#include <Menus.h>
#include <Sound.h>
#include <IconUtilsPriv.h>
#include <MenuMgrPriv.h>
#include <MFPrivate.h>
#include <Power.h>
#include "kernel.h"
#include "task.h"
#include "Notification.h"
int disable();
void spl(int level);
#define MoveSDist 0 /* Argument to CallMBarProc message */
#define MoveSThresh 1 /* Number of ticks between moves */
#define AlarmSICN 0xBFFF /* ID of the alarm clock SICN */
#define AppleMark 0x0114 /* Pascal string containing apple character */
#define SICNsize 32 /* Size of (single) SICN */
typedef struct {
MenuHandle menuOH;
short menuLeft;
} MenuRec;
typedef struct {
short lastMenu, lastRight, mbResID;
MenuRec menu[0];
} MenuL, *MenuLPtr, **MenuLHdl;
#define MapTRUE -1
#define BufPtr (*(Ptr *) 0x10C)
#define UnitTable (*(DCtlHandle **) 0x11C)
#define Ticks (*(long *) 0x16A)
#define AlarmState (*(char *) 0x21F)
#define ROM85 (*(unsigned short *) 0x28E)
#define SysZone (*(THz *) 0x2A6)
#define ApplZone (*(THz *) 0x2AA)
#define WMgrPort (*(GrafPtr *) 0x9DE)
#define MenuList (*(MenuLHdl *) 0xA1C)
#define ROMMapInsert (*(short *) 0xB9E)
#define MBarHeight (*(short *) 0xBAA)
#define WMgrCPort (*(GrafPtr *) 0xD2C)
#define HaveCQD() (ROM85 <= 0x3FFF)
/* True iff alarm has gone off */
#define Alarm() (!(AlarmState & 0x3))
/* MBDF Messages */
#define MoveICSToPM 16
#define MoveICSToAM 17
#define MoveSICNToPM 18
#define MoveSICNToAM 13
/* Private NMRec nmFlags */
#define fItemMarked 0x0001
#define fIconinRot 0x0002
#define fSndPlayed 0x0008
#define fDlogDisp 0x0010
#define fDlogCompl 0x0020
#define fRespCompl 0x0040
#define fReqLocked 0x0080
#define fReqDone 0x8000
/* All auxiliary records start with this */
typedef struct AuxRec {
QElemPtr qLink;
short qType;
short aRefCount;
struct AuxRec *aLink;
} AuxRec, *AuxRecPtr;
#define nmMarkChar 0x13
/* Auxiliary record for menu item marks */
typedef struct MarkRec {
AuxRec hdr;
short mPID;
short mMarkID;
} MarkRec, *MarkRecPtr;
/* Auxiliary record for icons */
typedef struct IconRec {
AuxRec hdr;
Handle iSIcon;
Boolean iconSuite;
} IconRec, *IconRecPtr;
/* Notification Manager's globals */
typedef struct NMHdr {
QHdr requests, marks, amIcons; /* amIcons was icons */
NMRecPtr alarmRec;
MenuHandle lastMenuUsed; /* was lastAppleMenu */
IconRecPtr curAMIconRec; /* was curIconRec */
Handle copyIcon;
long lastMoveTime;
Boolean useNewIcon;
/* the following fields were added after the Portable and IIci ROMs */
IconRecPtr curPMIconRec;
QHdr pmIcons;
Boolean appleMenu;
} NMHdr, *NMHdrPtr;
#define NMQHdr (*(NMHdrPtr *) 0xB60)
/* Private NMHdr qFlags */
#define fInDoDlog 0x0001
#define fDlogInval 0x0002
#define NMDialog 1
#define buttonItem 1
#define defButItem 2
#define textItem 3
#define iconItem 4
#define EmptyIconQueue(iconQueue) (((IconRecPtr) iconQueue.qHead)->hdr.qLink == nil)
#define WaitSThresh(amIconQueue, pmIconQueue) ((!EmptyIconQueue(amIconQueue) && !EmptyIconQueue(pmIconQueue)) ? 30 : 60)
/* The MPW GetDCtlEntry has a bug. This is my substitute. It returns a handle
* to the DCE of the driver having the given refnum.
*/
#define MyGetDCtlEntry(refNum) UnitTable[~refNum]
/* Returns true iff theAddr is in the range specified by low & high. Uses StripAddress. */
Boolean
AddrInRange(Ptr theAddr, Ptr low, Ptr high)
{
theAddr = StripAddress(theAddr);
return (StripAddress(low) <= theAddr) && (theAddr <= StripAddress(high));
}
#define InSysZone(theAddr) AddrInRange(theAddr, (Ptr) SysZone, SysZone->bkLim)
#define InApplZone(theAddr) AddrInRange(theAddr, (Ptr) ApplZone, BufPtr)
/* Gets a process ID, or returns -1 if none is available (MultiFinder not active) */
short
GetPID(void)
{
if (NGetTrapAddress(0x8F, ToolTrap) != NGetTrapAddress(0x9F, ToolTrap)) {
/* MultiFinder active */
return TWGetPID();
}
else return -1;
}
/* Given a menu handle and a string, finds the item number, if any. Returns
* zero if it is not in the menu.
*/
short
FindItem(MenuHandle theMenu, StringPtr itemString)
{
register short i = CountMItems(theMenu);
Str255 menuString;
while (i > 0) {
GetItem(theMenu, i, menuString);
if (EqualString(itemString, menuString, false, true)) return i;
i--;
}
return 0;
}
MenuHandle
GetApplicationMenu(void)
{
return ((MenuHandle) GetResource('MENU',kApplicationMenuID));
}
short InApplicationMenu(short thePID, short theMarkID)
{
register MenuHandle theApplicationMenu = GetApplicationMenu();
register DCtlHandle hDCE = (theMarkID < 0) ? MyGetDCtlEntry(theMarkID) : nil;
short theItem = 0;
if (theApplicationMenu) {
if (thePID != -1) {
/* MultiFinder is here */
if (hDCE && !InSysZone((*hDCE)->dCtlDriver) && (thePID != GetPID())) {
/* The driver is not in the system heap and the PID is not mine.
* Therefore, the driver is not to be found, flag the app instead.
*/
hDCE = nil;
}
if (!hDCE) {
/* Mark the application */
struct procinfo procInfoRec;
TWGetProcInfo(thePID, &procInfoRec);
theItem = FindItem(theApplicationMenu, procInfoRec.p_name);
}
}
if (hDCE) {
/* It's a driver */
short dID;
ResType dType;
Str255 dName;
ROMMapInsert = MapTRUE;
GetResInfo(GetResource('DRVR', ~theMarkID), &dID, &dType, dName);
theItem = FindItem(theApplicationMenu, dName);
}
}
return theItem;
}
/* Gets the free auxiliary record, if available */
AuxRecPtr
GetFreeAux(QHdrPtr theQueue)
{
register AuxRecPtr theAuxRec = theQueue->qTail;
if (theAuxRec && !theAuxRec->qType) return theAuxRec;
else return nil;
}
/* Ensures that a free auxiliary record is available */
void
AddAuxRec(Size theSize, QHdrPtr theQueue)
{
if (!GetFreeAux(theQueue)) {
register AuxRecPtr theAuxRec = NewPtrSysClear(theSize);
Enqueue((QElemPtr)theAuxRec, theQueue);
}
}
#define AddMarkRec() AddAuxRec(sizeof(MarkRec), &NMQHdr->marks)
void
AddIconRec(void)
{
AddAuxRec(sizeof(IconRec), &NMQHdr->amIcons);
AddAuxRec(sizeof(IconRec), &NMQHdr->pmIcons);
}
/* Links the auxiliary record to theNMRec */
void
LinkAuxRec(NMRecPtr theNMRec, AuxRecPtr theAuxRec)
{
theAuxRec->qType = -1;
theAuxRec->aRefCount++;
theAuxRec->aLink = (AuxRecPtr) theNMRec->nmPrivate;
(AuxRecPtr) theNMRec->nmPrivate = theAuxRec;
}
/* Removes the auxiliary record links from theNMRec */
void
UnLinkAuxRecs(NMRecPtr theNMRec)
{
register AuxRecPtr theAuxRec = (AuxRecPtr) theNMRec->nmPrivate;
(AuxRecPtr) theNMRec->nmPrivate = nil;
while (theAuxRec) {
theAuxRec->aRefCount--;
theAuxRec = theAuxRec->aLink;
}
}
/* Inserts the MarkRec associated with theNMRec in the queue.
* Note that since MarkRecs have multiple references, it is important that
* these be the first auxiliary records in. (aLink should always be nil)
*/
MarkRecPtr
InsertMarkRec(NMRecPtr theNMRec)
{
register MarkRecPtr theMarkRec = NMQHdr->marks.qHead;
register short thePID = theNMRec->nmReserved;
register short theMarkID = theNMRec->nmMark;
while (theMarkRec &&
((theMarkID != theMarkRec->mMarkID) || (thePID != theMarkRec->mPID)) &&
theMarkRec->hdr.qType) theMarkRec = (MarkRec *) theMarkRec->hdr.qLink; /* 1.5 type coersion */
if (!theMarkRec) theMarkRec = (MarkRec *) GetFreeAux(&NMQHdr->marks); /* 1.5 type coersion */
if (theMarkRec) {
theMarkRec->mPID = thePID;
theMarkRec->mMarkID = theMarkID;
LinkAuxRec(theNMRec, (AuxRecPtr) theMarkRec);
}
return theMarkRec;
}
/* Inserts the IconRec associated with theNMRec in the queue. */
IconRecPtr
InsertIconRec(NMRecPtr theNMRec)
{
register IconRecPtr theIconRec = nil;
if ((GetHandleSize(theNMRec->nmIcon) == sizeof(IconSuite)) ||
(GetHandleSize(theNMRec->nmIcon) == SICNsize)) {
theIconRec = (IconRecPtr) GetFreeAux((InApplicationMenu(theNMRec->nmReserved, theNMRec->nmMark) && (theNMRec->nmMark)) ? &NMQHdr->pmIcons : &NMQHdr->amIcons);
if (theIconRec) {
theIconRec->iSIcon = theNMRec->nmIcon;
theIconRec->iconSuite = (GetHandleSize(theNMRec->nmIcon) == sizeof(IconSuite));
LinkAuxRec(theNMRec, (AuxRecPtr) theIconRec);
}
}
return theIconRec;
}
/* Finds the next valid IconRec in the queue, deleting all unused entries along
* the way, starting with theIconRec.
*/
IconRecPtr
ValidIconRec(IconRecPtr theIconRec, QHdrPtr queue)
{
if (theIconRec)
theIconRec = (IconRecPtr) theIconRec->hdr.qLink;
else
theIconRec = (IconRecPtr) queue->qHead;
while (theIconRec && !theIconRec->hdr.aRefCount) {
register IconRecPtr tempIconRec = theIconRec->hdr.qLink;
if (theIconRec->hdr.qType) {
Dequeue((QElemPtr)theIconRec, queue);
DisposPtr((Ptr)theIconRec);
}
theIconRec = tempIconRec;
}
return theIconRec;
}
/* This is run immediately after the code is installed in the system heap. */
void
NMINIT(void)
{
NMQHdr = (NMHdrPtr) NewPtrSysClear(sizeof(NMHdr));
NMQHdr->useNewIcon = true;
NMQHdr->appleMenu = true;
NMQHdr->copyIcon = NewHandleSys(sizeof(IconSuite));
}
/* This is the NMInstall trap, $A05E. The underscore is because NMInstall() calls
* the trap. This routine installs the request into the queue. It is guaranteed
* to succeed if theNMRec is valid.
*/
OSErr
_NMInstall(NMRecPtr theNMRec)
{
if (theNMRec->qType != nmType) return nmTypErr;
if (NGetTrapAddress(0xA085,OSTrap) != NGetTrapAddress(0xA89F,ToolTrap))
IdleUpdate();
theNMRec->nmFlags = 0;
theNMRec->nmPrivate = 0;
theNMRec->nmReserved = GetPID();
Enqueue((QElemPtr)theNMRec, &NMQHdr->requests);
return noErr;
}
/* This is the NMRemove trap, $A05F. The underscore is because NMRemove() calls
* the trap. This routine removes the request from the queue. It will remove
* the dialog if one is up, and will abort any icon rotation that is in progress.
* It is guaranteed to succeed if theNMRec is valid and in the queue.
*/
OSErr
_NMRemove(NMRecPtr theNMRec)
{
register OSErr rValue;
if (theNMRec->qType != nmType) return nmTypErr;
if ((rValue = Dequeue((QElemPtr)theNMRec, &NMQHdr->requests)) == noErr) {
/* See if we have a dialog up */
if ((theNMRec->nmFlags & (fDlogDisp | fDlogCompl)) == fDlogDisp) NMQHdr->requests.qFlags |= fDlogInval;
UnLinkAuxRecs(theNMRec);
}
return rValue;
}
/* Copies Pascal style strings. */
pascal void
CopyString(StringPtr srcString, StringPtr dstString)
{
BlockMove(srcString, dstString, *srcString + 1);
}
/* Called by InitApplZone via the IAZNotify vector. Removes all requests that
* are in the application zone.
*/
void
FLUSHAPPLNM(void)
{
if (SysZone != ApplZone) {
register int procLevel;
register NMRecPtr theNMRec;
procLevel = disable();
theNMRec = (NMRecPtr) NMQHdr->requests.qHead; /* 1.5 type coersion */
while (theNMRec != nil) {
register NMRecPtr nextNMRec = theNMRec->qLink;
if (InApplZone((Ptr) theNMRec)) NMRemove(theNMRec);
theNMRec = nextNMRec;
}
spl(procLevel);
}
}
/* This dialog filter proc is almost identical to the default, except that it will
* also return if aborted by NMRemove.
*/
pascal Boolean
NMFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
{
if (theEvent->what == keyDown) {
register unsigned char theChar = theEvent->message & 0xFF;
if ((theChar == 3) || (theChar == 0xD)) {
/* It's a return or enter. */
short itemType;
ControlHandle item;
Rect junk;
GetDItem(theDialog, buttonItem, &itemType, (Handle*)&item, &junk);
if (itemType == (ctrlItem+btnCtrl)) {
/* It's an enabled button - highlight it */
HiliteControl(item, inButton);
Delay(8, (long*)&junk);
HiliteControl(item, 0);
}
*itemHit = buttonItem;
return true;
}
}
if (NMQHdr->requests.qFlags & fDlogInval) {
/* The request was removed - punt the dialog */
return true;
}
return false;
}
/* This is the user item procedure which displays the default button roundRect. */
pascal void
DefButProc(DialogPtr theDialog, short itemNo)
{
PenState savePen;
short itemType;
Handle item;
Rect box;
GetPenState(&savePen);
PenSize(3,3);
GetDItem(theDialog, itemNo, &itemType, &item, &box);
FrameRoundRect(&box, 16, 16);
SetPenState(&savePen);
}
typedef pascal long (**MBarProcHandle)(short, short, short, long);
/* This routine calls the Menu Bar Proc. May be replaced by a trap at a later date.
*/
long
NMCallMBarProc(short message, short param1, long param2)
{
register MenuL **menuLHdl, *menuLPtr;
register short mbResID;
register MBarProcHandle MBDFHndl;
/* This mess just forces code optimization */
if ((menuLHdl = MenuList) && (menuLPtr = *menuLHdl)) {
mbResID = menuLPtr->mbResID;
}
else return 0;
ROMMapInsert = MapTRUE;
if (MBDFHndl = (MBarProcHandle) GetResource('MBDF', mbResID)) {
register short flags = HGetState((Handle)MBDFHndl);
register long result;
HLock((Handle)MBDFHndl);
result = (**MBDFHndl)(mbResID & 7, message, param1, param2);
HSetState((Handle)MBDFHndl, flags);
return result;
}
else return 0;
}
/* theItem of theMenu is marked with newMarkChar iff it was previously marked with
* oldMarkChar.
*/
pascal void /* Declared pascal for efficiency */
SwapItemMarks(MenuHandle theMenu, short theItem, short oldMarkChar, short newMarkChar)
{
short theMarkChar;
GetItemMark(theMenu, theItem, &theMarkChar);
if (theMarkChar == oldMarkChar) SetItemMark(theMenu, theItem, newMarkChar);
}
/* Clears out all the Notification Manager marks from theMenu */
void
ClearMarks(MenuHandle theMenu)
{
register short i = CountMItems(theMenu);
while (i > 0) SwapItemMarks(theMenu, i--, nmMarkChar, noMark);
}
/* Exchanges oldMarkChar for newMarkChar in the menu item referred to by
* theMarkRec. If the current mark is not oldMarkChar, nothing happens.
*/
pascal void /* Declared pascal for efficiency */
SwapAppMark(MarkRecPtr theMarkRec, short oldMarkChar, short newMarkChar)
{
register MenuHandle theApplicationMenu = GetApplicationMenu();
if (theApplicationMenu) {
register short thePID = theMarkRec->mPID;
register short theMarkID = theMarkRec->mMarkID;
register short theItem = 0;
theItem = InApplicationMenu(thePID, theMarkID);
if (theItem) SwapItemMarks(theApplicationMenu, theItem, oldMarkChar, newMarkChar);
}
}
#define MarkApp(theMarkRec) SwapAppMark(theMarkRec, noMark, nmMarkChar)
#define UnMarkApp(theMarkRec) SwapAppMark(theMarkRec, nmMarkChar, noMark)
/* Mark an item in the apple or Application Menu */
void
MarkItem(NMRecPtr theNMRec, int procLevel)
{
if (theNMRec->nmMark != 0) {
register MarkRecPtr theMarkRec = InsertMarkRec(theNMRec);
if (theMarkRec) {
theNMRec->nmFlags |= fItemMarked;
spl(procLevel);
MarkApp(theMarkRec);
}
}
else theNMRec->nmFlags |= fItemMarked;
}
/* Start an icon rotating */
void
RotateIcon(NMRecPtr theNMRec, int /*procLevel*/)
{
if (theNMRec->nmIcon != 0) {
if (InsertIconRec(theNMRec)) theNMRec->nmFlags |= fIconinRot;
}
else theNMRec->nmFlags |= fIconinRot;
}
/* Play a sound */
/* ex<SM5> ex<SM6> <Sys7.1> */
void
DoSound(NMRecPtr theNMRec, int procLevel)
{
register Handle theSound = theNMRec->nmSound;
theNMRec->nmFlags |= fSndPlayed;
if (theSound)
{
spl(procLevel);
if (theSound == (Handle) -1)
SysBeep(3);
else
{
SndPlay(NULL, theSound, false);
}
}
}
/* Put up a dialog. Currently, this procedure waits for the user to respond, or
* the request to be removed. This should be fixed in the future.
*/
void
DoDialog(NMRecPtr theNMRec, int procLevel)
{
if (theNMRec->nmStr == nil) theNMRec->nmFlags |= fDlogDisp | fDlogCompl;
/* DoDialog not reentrant, temporarily lock out this request */
else if (NMQHdr->requests.qFlags & fInDoDlog) theNMRec->nmFlags |= fReqLocked;
else {
register DialogPtr theDialog;
register short saveResFile;
GrafPtr savePort;
Str255 alertStr;
short itemType, itemHit;
Handle item;
Rect box;
/* Mark that we're in here for reentrancy test */
NMQHdr->requests.qFlags |= fInDoDlog;
/* Flag that we are going to bring up a dialog */
/* Also lock it until the user responds */
theNMRec->nmFlags |= fDlogDisp | fReqLocked;
/* Copy the string */
CopyString(theNMRec->nmStr, alertStr);
spl(procLevel);
InitCursor();
GetPort(&savePort);
saveResFile = CurResFile();
UseResFile(0);
theDialog = GetNewDialog(NMDialog, nil, (WindowPtr) -1);
UseResFile(saveResFile);
GetDItem(theDialog, defButItem, &itemType, &item, &box);
SetDItem(theDialog, defButItem, itemType, (Handle) DefButProc, &box); /* 1.5 type coersion */
GetDItem(theDialog, textItem, &itemType, &item, &box);
SetIText(item, alertStr);
ShowWindow(theDialog);
ModalDialog((ModalFilterProcPtr) NMFilter, &itemHit); /* 1.5, 1.7 type coersion */
/* If the queue entry is intact, mark the dialog as displayed and unlock the request.
* Disable queue access during this time to prevent removal underneath.
*/
procLevel = disable();
if (!(NMQHdr->requests.qFlags & fDlogInval)) {
/* Queue entry is intact */
theNMRec->nmFlags |= fDlogCompl;
theNMRec->nmFlags &= ~fReqLocked;
}
else NMQHdr->requests.qFlags &= ~fDlogInval;
/* Also unlock the next pending dialog. */
theNMRec = (NMRecPtr) NMQHdr->requests.qHead; /* 1.5 type coersion */
while (theNMRec != nil) {
if ((theNMRec->nmFlags & (fDlogDisp | fReqLocked)) == fReqLocked) {
theNMRec->nmFlags &= ~fReqLocked;
break;
}
theNMRec = (NMRecPtr) theNMRec->qLink; /* 1.5 type coersion */
}
spl(procLevel);
DisposDialog(theDialog);
SetPort(savePort);
NMQHdr->requests.qFlags &= ~fInDoDlog;
}
}
/* Call the response procedure */
void
DoRespProc(NMRecPtr theNMRec, int procLevel)
{
register NMProcPtr respProc = theNMRec->nmResp;
theNMRec->nmFlags |= fRespCompl;
if (respProc) {
if (respProc == (NMProcPtr) -1) NMRemove(theNMRec);
else {
spl(procLevel);
(*respProc)(theNMRec);
}
}
}
/* Called by GetNextEvent. Checks to see if the alarm has gone off. */
pascal void
NMGNEFilter(void)
{
register NMRecPtr theAlarmRec = NMQHdr->alarmRec;
if (Alarm()) {
/* Alarm should be on */
if (!theAlarmRec) {
/* It's not, turn it on */
register Handle theSIcon;
ROMMapInsert = MapTRUE;
if (theSIcon = GetResource('SICN', AlarmSICN)) {
/* Build theAlarmRec and copy the alarm icon into the sys heap */
register Size iconSize = GetHandleSize(theSIcon);
if ((theAlarmRec = (NMRec *) NewPtrSysClear(sizeof(NMRec))) &&
(theAlarmRec->nmIcon = NewHandleSys(iconSize))) {
BlockMove(*theSIcon, *(theAlarmRec->nmIcon), iconSize);
theAlarmRec->qType = nmType;
theAlarmRec->nmSound = (Handle) -1; /* Use SysBeep */
NMInstall(theAlarmRec);
NMQHdr->alarmRec = theAlarmRec;
}
ReleaseResource(theSIcon);
}
}
}
else {
/* Alarm should be off */
if (theAlarmRec) {
/* It's not, turn it off */
NMRemove(theAlarmRec);
DisposHandle(theAlarmRec->nmIcon);
NMQHdr->alarmRec = nil;
}
}
}
/* Called by SystemTask in the topmost layer */
/* ex<SM4> <Sys7.1> */
pascal void
NMTask(void)
{
register int procLevel;
short selector[4];
procLevel = disable();
selector[3] = MoveICSToAM;
selector[2] = MoveSICNToAM;
selector[1] = MoveICSToPM;
selector[0] = MoveSICNToPM;
{
/* Find the first queue element that needs attention.
* Note that the response proc is the last thing done.
*/
register NMRecPtr theNMRec = NMQHdr->requests.qHead;
while ((theNMRec != nil) && (theNMRec->nmFlags & fReqLocked)) theNMRec = (NMRecPtr) theNMRec->qLink; /* 1.5 type coersion */
/* Determine the next thing to be done and call the procedure to do it */
if (theNMRec != nil) {
register short nmFlags = theNMRec->nmFlags;
if (!(nmFlags & fItemMarked)) MarkItem(theNMRec, procLevel);
else if (!(nmFlags & fIconinRot)) RotateIcon(theNMRec, procLevel);
else if (!(nmFlags & fSndPlayed)) DoSound(theNMRec, procLevel);
else if (!(nmFlags & fDlogDisp)) DoDialog(theNMRec, procLevel);
else if (!(nmFlags & fRespCompl)) DoRespProc(theNMRec, procLevel);
else theNMRec->nmFlags |= fReqLocked | fReqDone;
}
}
spl(procLevel);
AddMarkRec();
AddIconRec();
/* Now go through the marks queue, deleting entries and updating menu marks
* as needed.
*/
{
register MenuHandle theApplicationMenu = GetApplicationMenu();
register MarkRecPtr theMarkRec = NMQHdr->marks.qHead;
if (theApplicationMenu && (NMQHdr->lastMenuUsed != theApplicationMenu)) ClearMarks(theApplicationMenu);
while (theMarkRec != nil) {
register MarkRecPtr nextMarkRec = theMarkRec->hdr.qLink;
if (theMarkRec->hdr.qType) {
if (!theMarkRec->hdr.aRefCount) {
/* Remove the mark and delete this record */
UnMarkApp(theMarkRec);
Dequeue((QElemPtr)theMarkRec, &NMQHdr->marks);
DisposPtr((Ptr)theMarkRec);
}
else if (theApplicationMenu && NMQHdr->lastMenuUsed != theApplicationMenu) MarkApp(theMarkRec);
}
theMarkRec = nextMarkRec;
}
NMQHdr->lastMenuUsed = theApplicationMenu;
}
{
/* Get the icon to be displayed for the menu bar defproc */
register long curTime = Ticks, timeSince = curTime - NMQHdr->lastMoveTime;
register IconRecPtr *curIconRec;
curIconRec = (NMQHdr->appleMenu ? &NMQHdr->curAMIconRec : &NMQHdr->curPMIconRec);
if (timeSince >= MoveSThresh) {
register IconRecPtr theIconRec = *curIconRec;
if (NMQHdr->useNewIcon) {
/* Get the next icon from the queue. If not enough time has elapsed,
* or the new icon is the same as the old, get out.
*/
if (timeSince >= WaitSThresh(NMQHdr->amIcons, NMQHdr->pmIcons)) {
register IconRecPtr newIconRec = ValidIconRec(theIconRec, (NMQHdr->appleMenu ? &NMQHdr->amIcons : &NMQHdr->pmIcons));
if (newIconRec == theIconRec) {
NMQHdr->appleMenu = !(NMQHdr->appleMenu);
return;
}
else {
*curIconRec = theIconRec = newIconRec;
if (theIconRec)
BlockMove(*(theIconRec->iSIcon), *(NMQHdr->copyIcon), (theIconRec->iconSuite ? sizeof(IconSuite) : SICNsize));
}
}
else return;
}
NMQHdr->lastMoveTime = curTime;
NMQHdr->useNewIcon = NMCallMBarProc(selector[(NMQHdr->appleMenu << 1) + (theIconRec ? theIconRec->iconSuite : 0)],
MoveSDist,
(long) (theIconRec ? NMQHdr->copyIcon: nil));
NMQHdr->appleMenu = !(NMQHdr->appleMenu);
}
}
}