Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Main.c
/***************************************************************** |
Program: < ADSP Chat > |
File: < Main.c > |
Written by Pete Helm, Scott Kuechle |
of <Apple Macintosh Developer Technical Support> |
modified by Scott Kuechle |
10/92 SRK Converted from Pascal to C |
8/94 SRK Modified to use a queue of parameter |
blocks. |
Copyright © 1992, 1994 Apple Computer, Inc. |
All rights reserved. |
*****************************************************************/ |
/*****************************************************************/ |
/* I N C L U D E S |
/*****************************************************************/ |
#include "ADSP Chat.h" |
/*****************************************************************/ |
/* G L O B A L V A R I A B L E D E C L A R A T I O N S |
/*****************************************************************/ |
DialogPtr myDialog; |
Boolean gHasWaitNextEvent,gInBackground,gGrowRect,gStopped,gStopRect,gGoRect,gHasSystem7; |
Boolean gMoofEntityFilter; |
MenuHandle ZoneMenu,ObjectMenu,TypeMenu; |
short LastZoneMenuChoice,LastTypeMenuChoice,LastObjectMenuChoice; |
SysEnvRec gMac; |
short gMenuItem; |
/*****************************************************************/ |
/* |
/* E X T E R N A L S |
/* |
/*****************************************************************/ |
extern myFillRoundRectAnimationRtn (Rect r, PatPtr pat); |
extern void connectToPeer(); |
extern void removeADSP(); |
extern void initializeADSP(); |
extern removeMyName(); |
extern void ADSPLoop(); |
extern OSErr InitAppleTalk(); |
extern Boolean ATPZoneRequest (MenuHandle zoneMenu); |
extern LookupNames (MenuHandle lookupMenu,Boolean doObjects); |
extern GetZones(); |
extern GetOurZone(); |
extern void writeOutgoing(DSPPBPtr dspPBPtr, |
short ccbRefNum, |
Ptr dataPtr, |
short reqCount); |
extern void removeConnectionEnd(); |
extern void removeADSPBuffers(); |
extern Str255 gZoneString,gTypeStr,gObjStr; |
extern Boolean gConnectionWasJustMade; |
extern TRCCB gMyCCB; /* our ccb */ |
extern QHdr gAvailQueue,gReadQueue,gDoneQueue; |
extern short gCCBRefNum; /* ccb reference number returned by adsp on a dspInit */ |
extern Ptr outgoingDataBuffer; |
extern DSPPBPtr GetQElement(QHdrPtr qHdrPtr); |
#pragma segment Main |
// ***************************************************************** |
// * CopyPstr |
// * |
// * copies a pascal string |
// ***************************************************************** |
void CopyPstr(Ptr pSource, Ptr pDest) |
{ |
BlockMove(pSource, pDest, pSource[0]+1); |
} |
// ***************************************************************** |
// * PStrCat |
// * |
// * appends pascal string sourceStr, to pascal string destinationStr. |
// * Overflow is checked, and the copy halts if the destination |
// * string is filled. |
// ***************************************************************** |
void PStrCat(Ptr sourceStr, Ptr destinationStr) |
{ |
unsigned int srcIndex, dstIndex; |
unsigned int bytesToCopy; |
srcIndex = 1; |
dstIndex = destinationStr[0] + 1; |
bytesToCopy = sourceStr[0]; |
while(bytesToCopy > 0 && dstIndex < 255) |
{ |
destinationStr[dstIndex] = sourceStr[srcIndex]; |
dstIndex++; |
srcIndex++; |
bytesToCopy--; |
} |
destinationStr[0] = dstIndex - 1; |
} |
// ***************************************************************** |
// * DoActivate |
// * |
// * This is called when a window is activated or deactivated. |
// * In Sample, the Window Manager's handling of activate and |
// * deactivate events is sufficient. Other applications may have |
// * TextEdit records, controls, lists, etc., to activate/deactivate. |
// ***************************************************************** |
void DoActivate (WindowPtr window, Boolean becomingActive) |
{ |
#pragma unused (window,becomingActive) |
} /*DoActivate*/ |
// ***************************************************************** |
// * ShowError |
// * |
// * Our routine for displaying an error message in a dialog box. |
// ***************************************************************** |
void ShowError(short index) |
{ |
short itemHit; |
switch (index) |
{ |
case atalkErr: |
ParamText("\perror loading AppleTalk drivers!","\p","\p","\p"); |
break; |
case memErr: |
ParamText("\pmemory error.","\p","\p","\p"); |
break; |
case menuErr: |
ParamText("\perror initializing menus.","\p","\p","\p"); |
break; |
case nbpErr: |
ParamText("\pCouldn't register our name on the network (duplicate already exists).","\p","\p","\p"); |
break; |
case noTargetErr: |
ParamText("\pTarget not found.","\p","\p","\p"); |
break; |
case noConnErr: |
ParamText("\pNo connection has been made.","\p","\p","\p"); |
break; |
case writeNotDoneErr: |
ParamText("\pPrevious write has not completed yet.","\p","\p","\p"); |
break; |
case badROMsErr: |
ParamText("\pYour machine does not have at least 128K ROMs.","\p","\p","\p"); |
break; |
case heapErr: |
ParamText("\pNot enough heap space.","\p","\p","\p"); |
break; |
case noMemErr: |
ParamText("\pNot enough memory available for our application.","\p","\p","\p"); |
break; |
case DrvrErr: |
ParamText("\pFatal Device Manager error.","\p","\p","\p"); |
break; |
case ListenErr: |
ParamText("\pCould not setup connection listener.","\p","\p","\p"); |
break; |
case dspInitErr: |
ParamText("\pADSP Initialization failed.","\p","\p","\p"); |
break; |
case dspOpenErr: |
ParamText("\pAttempt to open connection failed.","\p","\p","\p"); |
break; |
case dspRemoveErr: |
ParamText("\pError returned while eliminating the connection end.","\p","\p","\p"); |
break; |
default: |
ParamText("\pdefault error displayed here.","\p","\p","\p"); |
break; |
} |
itemHit = Alert(rErrorDialog, nil); |
} |
// ***************************************************************** |
// * FatalError |
// * |
// * This is called when we detect that we cannot operate in the |
// * current environment. |
// ***************************************************************** |
void FatalError(error) |
short error; |
{ |
ShowError(error); |
ExitToShell(); |
} |
// ***************************************************************** |
// * IsAppWindow |
// * |
// * Tells us whether or not a window is an application window |
// * |
// ***************************************************************** |
Boolean IsAppWindow(window) |
WindowPtr window; |
{ |
short windowKind; |
if ( window == nil ) |
return false; |
else { /* application windows have windowKinds >= userKind (8) or dialogKind (2) */ |
windowKind = ((WindowPeek) window)->windowKind; |
return (windowKind >= userKind) || (windowKind == dialogKind); |
} |
} /* IsAppWindow */ |
// ***************************************************************** |
// * DialogEditing |
// * |
// * handles the standard editing operations (cut, copy, paste) |
// * for our dialog. |
// ***************************************************************** |
void DialogEditing (short menuItem) |
{ |
/* handles Edit menu */ |
DialogPeek dp; |
short ignore; |
long evenBiggerIgnore; |
dp = (DialogPeek)myDialog; |
switch(menuItem) |
{ |
case iCut: |
evenBiggerIgnore = ZeroScrap(); /* you really shouldn't ignore this error. see TESample for details */ |
TECut(dp->textH); |
ignore = TEToScrap; /* you really shouldn't ignore this error. see TESample for details */ |
break; |
case iCopy: |
evenBiggerIgnore = ZeroScrap(); /* you really shouldn't ignore this error. see TESample for details */ |
TECopy(dp->textH); |
ignore = TEToScrap; /* you really shouldn't ignore this error. see TESample for details */ |
break; |
case iPaste: |
/* you really shouldn't ignore this either. */ |
/* one should be checking the length of the incoming scrap to see if it */ |
/* will fit in our remaining text edit space. but since we have a weenine 255 */ |
/* char dialog text edit item in any case we'll blow it off...see TESample for */ |
/* details on "doing the right thing" */ |
ignore = TEFromScrap; |
TEPaste(dp->textH); |
break; |
case iClear: |
TEDelete(dp->textH); |
} |
} |
// ***************************************************************** |
// * IsDAWindow |
// * |
// * Check if a window belongs to a desk accessory. |
// ***************************************************************** |
Boolean IsDAWindow(WindowPtr window) |
{ |
if (window == nil) |
return false; |
else /* DA windows have negative windowKinds */ |
return((((WindowPeek)window)->windowKind < 0) ? true : false); |
} /*IsDAWindow*/ |
// ***************************************************************** |
// * DoCloseWindow |
// * |
// * Close a window. This handles only desk accessory windows because we do not |
// * allow our window to be closed. TESample provides an example of how to handle |
// * the closing of application windows. |
// ***************************************************************** |
void DoCloseWindow (WindowPtr window) |
{ |
/* Close a window. This handles only desk accessory windows because we do not*/ |
/* allow our window to be closed. TESample provides an example of how to handle*/ |
/* the closing of application windows.*/ |
if (IsDAWindow(window)) |
CloseDeskAcc(((WindowPeek)window)->windowKind); |
} /*DoCloseWindow*/ |
// ***************************************************************** |
// * HiliteConnectButton |
// * |
// * sets our connect button to the desired state (active or inactive) |
// ***************************************************************** |
void HiliteConnectButton (short mode) |
{ |
Rect r; |
short kind; |
Handle h; |
GetDItem(myDialog, kConnectButtonID, &kind, &h, &r); |
HiliteControl((ControlHandle)h, mode); |
} |
// ***************************************************************** |
// * outlinePopUpMenus |
// * |
// * this is a group routine for drawing the popup menu outlines |
// * compleat with drop shadow. the menu title is draw to the left |
// * of the popUp item itself by this routine. |
// ***************************************************************** |
void outlinePopUpMenus (WindowPtr whichWindow, Rect r, Str255 itemString) |
{ |
FrameRect(&r); |
MoveTo(r.left + 2, r.bottom); |
LineTo(r.right, r.bottom); |
MoveTo(r.right, r.bottom); |
LineTo(r.right, r.top + 2); |
InsetRect(&r, 1, 1); |
EraseRect(&r); |
InsetRect(&r, -1, -1); |
MoveTo(r.left + 5, r.top + 11); |
TextFont(geneva); |
TextSize(9); |
DrawString(itemString); |
drawPopUpTri(whichWindow, r); |
} |
// ***************************************************************** |
// * UpdateUserItems |
// * |
// * update procedure for the user items in our dialog. |
// ***************************************************************** |
pascal void UpdateUserItems (WindowPtr whichWindow, |
short theItem) |
{ |
GrafPtr savedPort; |
Rect r; |
short kind; |
Handle h; |
GetPort(&savedPort); |
SetPort(whichWindow); |
GetDItem(whichWindow, theItem, &kind, &h, &r); |
switch(theItem) |
{ |
case kzoneItemID: |
outlinePopUpMenus(whichWindow, r, gZoneString); |
break; |
case ktypeItemID: |
outlinePopUpMenus(whichWindow, r, gTypeStr); |
break; |
case kobjectItemID: |
outlinePopUpMenus(whichWindow, r, gObjStr); |
break; |
case kRemoteMacsTimeBorderID: |
UpdateItemBorder(theItem, r); |
break; |
case kIncomingMessageBorderID: |
UpdateItemBorder(theItem, r); |
break; |
case kConnectStatusBorder: |
UpdateItemBorder(theItem, r); |
break; |
case kPopupBorderID: |
UpdateItemBorder(theItem, r); |
break; |
} |
SetPort(savedPort); |
} |
// ***************************************************************** |
// * DoModeless |
// * |
// * this handles mouse clicks inside our main dialog |
// ***************************************************************** |
void DoModeless (DialogPtr whichDialog, short whichItem) |
{ |
Rect r; |
short kind; |
Handle h; |
MenuHandle allPurposeMenu; |
long menuResult; |
Point pt; |
if (whichDialog == myDialog) |
{ |
GetDItem(whichDialog, whichItem, &kind, &h, &r); |
switch(whichItem) |
{ |
case kQuitButtonID: |
Terminate(); |
break; |
case kzoneItemID: |
pt.v = r.top; |
pt.h = r.left + 1; |
LocalToGlobal(&pt); |
SetCursor(*(GetCursor(watchCursor))); |
allPurposeMenu = NewMenu(ZoneMenuID, ""); |
InsertMenu(allPurposeMenu, -1); |
GetZones(allPurposeMenu); |
InitCursor(); |
menuResult = PopUpMenuSelect(allPurposeMenu, pt.v, pt.h, 1); |
if (menuResult != 0) |
{ |
GetItem(allPurposeMenu, LoWord(menuResult), gZoneString); |
gMenuItem = LoWord(menuResult); |
CopyPstr("\p", gObjStr); |
InvalRect(&r); |
} |
InitCursor(); |
DeleteMenu(ZoneMenuID); |
DisposeMenu(allPurposeMenu); |
break; |
case ktypeItemID: |
if (gMoofEntityFilter == false) |
{ |
pt.v = r.top - 2; |
pt.h = r.left + 1; |
LocalToGlobal(&pt); |
allPurposeMenu = NewMenu(TypeMenuID, ""); |
InsertMenu(allPurposeMenu, -1); |
SetCursor(*(GetCursor(watchCursor))); |
LookupNames(allPurposeMenu, false); |
InitCursor(); |
menuResult = PopUpMenuSelect(allPurposeMenu, pt.v, pt.h, 1); |
if (menuResult != 0) |
{ |
GetItem(allPurposeMenu, LoWord(menuResult), gTypeStr); |
if (strcmp(gTypeStr,"Moof") == 0) |
HiliteConnectButton(0); |
else |
HiliteConnectButton(255); |
gMenuItem = LoWord(menuResult); |
InvalRect(&r); |
} |
DeleteMenu(TypeMenuID); |
DisposeMenu(allPurposeMenu); |
} |
else |
SysBeep(1); |
break; |
case kobjectItemID: |
pt.v = r.top - 2; |
pt.h = r.left + 1; |
LocalToGlobal(&pt); |
allPurposeMenu = NewMenu(ObjectMenuID, ""); |
InsertMenu(allPurposeMenu, -1); |
SetCursor(*(GetCursor(watchCursor))); |
LookupNames(allPurposeMenu, true); |
InitCursor(); |
menuResult = PopUpMenuSelect(allPurposeMenu, pt.v, pt.h, 1); |
if (menuResult != 0) |
{ |
GetItem(allPurposeMenu, LoWord(menuResult), gObjStr); |
gMenuItem = LoWord(menuResult); |
InvalRect(&r); |
} |
DeleteMenu(ObjectMenuID); |
DisposeMenu(allPurposeMenu); |
break; |
case kConnectButtonID: /* connect button */ |
connectToPeer(); |
break; |
case kMoofFilterCheckBox: |
if (gMoofEntityFilter == false) |
{ |
SetCtlValue((ControlHandle)h,1); |
gMoofEntityFilter = true; |
CopyPstr("\pMoof", gTypeStr); |
HiliteConnectButton(0); |
} |
else |
{ |
SetCtlValue((ControlHandle)h,0); |
gMoofEntityFilter = false; |
CopyPstr("\p", gTypeStr); |
if (gMyCCB.state == sClosed) |
HiliteConnectButton(255); |
} |
gObjStr[0] = 0; |
InvalRect(&myDialog->portRect); |
break; /* iMoofFilter */ |
} /* of case */ |
} |
} |
// ***************************************************************** |
// * setEachUserItem |
// * |
// * sets the update routine for our dialogs user items |
// ***************************************************************** |
void setEachUserItem (short item) |
{ |
Rect r; |
short kind; |
Handle h; |
GetDItem(myDialog, item, &kind, &h, &r); |
SetDItem(myDialog, item, userItem, (Handle)UpdateUserItems, &r); |
} |
// ***************************************************************** |
// * DoMenuCommand |
// * |
// *This is called when an item is chosen from the menu bar (after calling |
// * MenuSelect or MenuKey). It performs the right operation for each command. |
// * It is good to have both the result of MenuSelect and MenuKey go to |
// * one routine like this to keep everything organized. |
// ***************************************************************** |
void DoMenuCommand (long menuResult) |
{ |
short menuID; /*the resource ID of the selected menu*/ |
short menuItem; /*the item number of the selected menu*/ |
short itemHit; |
Str255 daName; |
short daRefNum; |
Boolean handledByDA; |
menuID = HiWord(menuResult); /* use built-ins (for efficiency)...*/ |
menuItem = LoWord(menuResult); /*to get menu item number and menu number*/ |
switch (menuID) |
{ |
case mApple: |
switch(menuItem) |
{ |
case iAbout: /*bring up alert for About*/ |
itemHit = Alert(rAboutDialog, nil); |
break; |
default: |
/*all non-About items in this menu are DAs*/ |
GetItem(GetMHandle(mApple), menuItem, daName); |
daRefNum = OpenDeskAcc(daName); |
break; |
} |
break; |
case mFile: |
switch(menuItem) |
{ |
case iClose: |
DoCloseWindow(FrontWindow()); |
break; |
case iQuit: |
Terminate(); |
break; |
} |
break; |
case mEdit: /*call SystemEdit for DA editing & MultiFinder*/ |
{ |
if (IsDAWindow(FrontWindow())) |
handledByDA = SystemEdit(menuItem - 1); |
else |
DialogEditing(menuItem); |
} |
break; |
} |
HiliteMenu(0); /*unhighlight what MenuSelect (or MenuKey) hilited*/ |
} /*DoMenuCommand*/ |
// ***************************************************************** |
// * AdjustMenus |
// * |
// * Enable and disable menus based on the current state. |
// * The user can only select enabled menu items. We set up all the menu items |
// * before calling MenuSelect or MenuKey, since these are the only times that |
// * a menu item can be selected. Note that MenuSelect is also the only time |
// * the user will see menu items. This approach to deciding what enable |
// * disable state a menu item has the advantage of concentrating all the decision- |
// * making in one routine, as opposed to being spread throughout the application. |
// * Other application designs may take a different approach that is just as valid. |
// ***************************************************************** |
void AdjustMenus() |
{ |
WindowPtr window; |
MenuHandle menu; |
window = FrontWindow(); |
menu = GetMHandle(mFile); |
if (IsDAWindow(window)) /*we can allow desk accessories to be closed from the menu*/ |
EnableItem(menu, iClose); |
else |
DisableItem(menu, iClose); /*but not our traffic light window*/ |
menu = GetMHandle(mEdit); |
if (IsDAWindow(window)) |
{ /*a desk accessory might need the undo item */ |
EnableItem(menu, iUndo); |
EnableItem(menu, iCut); |
EnableItem(menu, iCopy); |
EnableItem(menu, iPaste); |
EnableItem(menu, iClear); |
} |
else |
{ /* but we do not support undo!!! */ |
DisableItem(menu, iUndo); |
EnableItem(menu, iCut); |
EnableItem(menu, iCopy); |
EnableItem(menu, iPaste); |
EnableItem(menu, iClear); |
} |
} /*AdjustMenus*/ |
// ***************************************************************** |
// * DisplayCurrentStatus |
// * |
// * updates our connection status string. |
// ***************************************************************** |
void DisplayCurrentStatus(Ptr displayStr) |
{ |
Rect r; |
short kind; |
Handle h; |
Str255 current; |
GetDItem(myDialog, kConnectionStatusString, &kind, &h, &r); |
GetIText(h,¤t); |
if (IUCompString(current,displayStr) != 0) |
SetIText(h, displayStr); |
} |
// ***************************************************************** |
// * DisposeQueueMemory |
// * |
// * deallocate the memory we used for our error queue |
// ***************************************************************** |
void DisposeQueueMemory(QHdrPtr qHdrPtr) |
{ |
QElemPtr QElem; |
OSErr err; |
/* if free queue has any items, dispose of them */ |
while (qHdrPtr->qHead != nil) |
{ |
QElem = qHdrPtr->qHead; |
err = Dequeue(QElem,qHdrPtr); |
DisposePtr((Ptr)QElem); |
} |
} |
// ***************************************************************** |
// * Terminate |
// * |
// * if we need to quit the program, we remove the connection |
// * end (if any), deallocate any memory we used, remove our |
// * nbp name from the network and exit. |
// ***************************************************************** |
void Terminate() |
{ |
/* did we establish a connection end? */ |
if (gCCBRefNum != 0) |
/* do a dspRemove to close the connection end */ |
removeConnectionEnd(gCCBRefNum); |
/* deallocate the memory we used for our adsp buffers */ |
removeADSPBuffers(); |
/* remove our nbp name "moof" */ |
removeMyName(); |
/* dispose of memory we allocated |
for our queues */ |
DisposeQueueMemory(&gAvailQueue); |
DisposeQueueMemory(&gDoneQueue); |
DisposeQueueMemory(&gReadQueue); |
ExitToShell(); |
} |
// ***************************************************************** |
// * Exit |
// * |
// * this routine is called for fatal control call errors. We exit |
// * the program in this situation. |
// ***************************************************************** |
void Exit(short message) |
{ |
ShowError(message); |
Terminate(); |
} |
// ***************************************************************** |
// * DoIdleProc |
// * |
// * this routine is called each time through our event loop. We |
// * process any adsp errors that were returned and check for connections |
// * coming and going. |
// ***************************************************************** |
void DoIdleProc() |
{ |
ADSPLoop(); |
} |
// ***************************************************************** |
// * AdjustCursor |
// * |
// *Change the cursor's shape, depending on its position. This also calculates the region |
// * where the current cursor resides (for WaitNextEvent). If the mouse is ever outside of |
// * that region, an event would be generated, causing this routine to be called, |
// * allowing us to change the region to the region the mouse is currently in. If |
// * there is more to the event than just Òthe mouse movedÓ, we get called before the |
// * event is processed to make sure the cursor is the right one. In any (ahem) event, |
// * this is called again before we fall back into WNE. |
// ***************************************************************** |
void AdjustCursor (Point mouse, RgnHandle region) |
{ |
WindowPtr window; |
RgnHandle arrowRgn; |
RgnHandle ourRgn; |
Rect globalPortRect; |
Rect r; |
short kind; |
Handle h; |
window = FrontWindow(); /*we only adjust the cursor when we are in front*/ |
if ((!gInBackground) && (!IsDAWindow(window))) |
{ |
/*calculate regions for different cursor shapes*/ |
arrowRgn = NewRgn(); |
ourRgn = NewRgn(); |
/*start with a big, big rectangular region*/ |
SetRectRgn(arrowRgn, extremeNeg, extremeNeg, extremePos, extremePos); |
/*calculate ourRgn*/ |
if (IsAppWindow(window)) |
{ |
SetPort(window); /*make a global version of the portRect*/ |
SetOrigin(-window->portBits.bounds.left, -window->portBits.bounds.top); |
globalPortRect = window->portRect; |
RectRgn(ourRgn, &globalPortRect); |
SectRgn(ourRgn, window->visRgn, ourRgn); |
SetOrigin(0, 0); |
} |
/*subtract other regions from arrowRgn*/ |
DiffRgn(arrowRgn, ourRgn, arrowRgn); |
/*change the cursor and the region parameter*/ |
if (PtInRgn(mouse, ourRgn)) |
{ |
GetDItem(myDialog, kOutgoingTextID, &kind, &h, &r); |
GlobalToLocal(&mouse); |
if (PtInRect(mouse, &r)) |
SetCursor(*GetCursor(iBeamCursor)); |
else |
SetCursor(&qd.arrow); |
CopyRgn(ourRgn, region); |
} |
else |
{ |
SetCursor(&qd.arrow); |
CopyRgn(arrowRgn, region); |
} |
/*get rid of our local regions*/ |
DisposeRgn(arrowRgn); |
DisposeRgn(ourRgn); |
} |
} /*AdjustCursor*/ |
// ***************************************************************** |
// * UpdateItemBorder |
// * |
// * re-draws the borders around our items |
// ***************************************************************** |
void UpdateItemBorder (short item, Rect r) |
{ |
FontInfo fInfo; |
Rect tRect; |
Str255 theBorderString; |
switch(item) |
{ |
case kRemoteMacsTimeBorderID: |
strcpy(&theBorderString,"Time from remote Mac"); |
break; |
case kIncomingMessageBorderID: |
strcpy(&theBorderString,"Incoming message"); |
break; |
case kPopupBorderID: |
strcpy(&theBorderString,"Select A Target Machine"); |
break; |
case kOutgoingMessageBorderID: |
strcpy(&theBorderString,"Outgoing message"); |
break; |
case kConnectStatusBorder: |
strcpy(&theBorderString,"Connection Status"); |
break; |
default: |
break; |
} |
c2pstr(theBorderString); |
GetFontInfo(&fInfo); |
FrameRect(&r); |
MoveTo(r.left + 5, r.top + fInfo.ascent / 2 - 1); |
tRect.left = r.left + 4; |
tRect.right = tRect.left + StringWidth(theBorderString) + 1; |
tRect.top = r.top; |
tRect.bottom = r.top + 1; |
EraseRect(&tRect); |
DrawString(&theBorderString); |
} |
// ***************************************************************** |
// * PlotSICN |
// * |
// * this is the PlotSICN code stolen from Tech Note # |
// ***************************************************************** |
void PlotSICN (Rect theRect,SICNHand theSICN, short theIndex) |
{ |
SignedByte state; /* we want a chance to restore original state */ |
BitMap srcBits; /* built up around 'SICN' data so we can _CopyBits */ |
/* check the index for a valid value */ |
if ((GetHandleSize((Handle)theSICN) / sizeof(SICN)) > theIndex) |
{ |
/* store the resource's current locked/unlocked condition */ |
state = HGetState((Handle)theSICN); |
/* lock the resource so it won't move during the _CopyBits call */ |
HLock((Handle)theSICN); |
/* set up the small icon's bitmap */ |
/*$PUSH*/ |
/*$R-*/ |
/* turn off range checking */ |
srcBits.baseAddr = (Ptr)(&(**theSICN[theIndex])); |
/*$POP*/ |
srcBits.rowBytes = 2; |
SetRect(&srcBits.bounds, 0, 0, 16, 16); |
/* draw the small icon in the current grafport */ |
CopyBits(&srcBits, &qd.thePort->portBits, &srcBits.bounds, &theRect, srcCopy, nil); |
/* restore the resource's locked/unlocked condition */ |
HSetState((Handle)theSICN, state); |
} |
} |
// ***************************************************************** |
// * drawPopUpTri |
// * |
// * this procedure draws the new "standard" SICN triangle now used |
// * in popup menus I guess the drop shadow was not enough of an |
// * indiciation to the users of the presence of the pop-up. |
// * standard in 7.0 and up systems |
// ***************************************************************** |
void drawPopUpTri (WindowPtr whichWindow, Rect r) |
{ |
#pragma unused (whichWindow) |
Handle popUpTri; |
Rect popUpTriRect; |
popUpTri = GetResource('SICN', kStandardTriSICN); |
if (popUpTri) |
{ |
popUpTriRect = r; |
popUpTriRect.right = popUpTriRect.right - 1; |
popUpTriRect.left = popUpTriRect.right - 16; |
popUpTriRect.top = popUpTriRect.top + 1; |
popUpTriRect.bottom = popUpTriRect.top + 16; |
PlotSICN(popUpTriRect, (SICNHand)popUpTri, 0); |
ReleaseResource(popUpTri); |
} |
} |
// ***************************************************************** |
// * DoEvent |
// * |
// * Do the right thing for an event. Determine what kind of event it is, and call |
// * the appropriate routines. |
// ***************************************************************** |
void DoEvent (EventRecord event) |
{ |
short part; |
char key; |
WindowPtr whichWindow; |
DialogPeek dp; |
short teLength; |
DSPPBPtr dspPBPtr; |
whichWindow = FrontWindow(); |
switch(event.what) |
{ |
case nullEvent: |
break; |
case mouseDown: |
part = FindWindow(event.where, &whichWindow); |
if (part != 0) |
{ |
switch(part) |
{ |
case inMenuBar: |
/*process the menu command*/ |
AdjustMenus(); |
DoMenuCommand(MenuSelect(event.where)); |
break; |
case inSysWindow: /*let the system handle the mouseDown*/ |
SystemClick(&event, whichWindow); |
break; |
case inContent: |
if (whichWindow != FrontWindow()) |
SelectWindow(whichWindow); |
break; |
case inDrag: /*pass screenBits.bounds to get all gDevices*/ |
DragWindow(whichWindow, event.where, &qd.screenBits.bounds); |
break; |
case inGrow: |
break; |
case inZoomIn: |
case inZoomOut: |
break; |
} |
} |
break; |
case keyDown: |
case autoKey: |
/*check for menukey equivalents*/ |
key = (char)(event.message & charCodeMask); |
if ((event.modifiers & cmdKey) != 0) /*Command key down*/ |
{ |
if ((event.what == keyDown) || (event.what == autoKey)) |
{ |
AdjustMenus(); /*enable/disable/check menu items properly*/ |
DoMenuCommand(MenuKey(key)); |
} |
} |
else if (key == (char)kEnterKey) /* enter key */ |
{ |
if ( (gMyCCB.state == sClosed) || |
(gMyCCB.state == sPassive)) |
ShowError(noConnErr); |
else |
{ |
dp = (DialogPeek)myDialog; |
/* we'll take a maximum of 255 characters from the edit box */ |
teLength = ((**(*dp).textH).teLength < 255) ? (**(*dp).textH).teLength : 255; |
/* grab the text from our edit text box */ |
BlockMove( *((**(*dp).textH).hText), outgoingDataBuffer, teLength); |
/* we'll make sure we get a parameter block |
so we can send our data */ |
do |
{ |
/* get QElement for the write call */ |
dspPBPtr = GetQElement(&gAvailQueue); |
} |
while ( (dspPBPtr == NULL) ); |
writeOutgoing(dspPBPtr, |
gCCBRefNum, |
outgoingDataBuffer, |
teLength); |
/* Change selection to outgoing text TERecord */ |
SelIText(myDialog, kOutgoingTextID, 0, 32767); |
} |
} |
break; /*call DoActivate with the window and...*/ |
case activateEvt: /*true for activate, false for deactivate*/ |
DoActivate((WindowPtr)event.message, (event.modifiers & activeFlag) != 0); |
break; |
case updateEvt: |
break; |
case osEvent: |
switch(event.message >> 24) /*high byte of message*/ |
{ |
case suspendResumeMessage: |
gInBackground = (event.message & resumeMask) == 0; |
DoActivate(FrontWindow(), !gInBackground); |
break; |
} |
} |
} /*DoEvent*/ |
// ***************************************************************** |
// * EventLoop |
// * |
// * Get events forever, and handle them by calling DoEvent. |
// * Get the events by calling WaitNextEvent, if it's available, otherwise |
// * by calling GetNextEvent. Also call AdjustCursor each time through the loop. |
// ***************************************************************** |
void EventLoop() |
{ |
RgnHandle cursorRgn; |
Boolean gotEvent; |
EventRecord event; |
long sleepTime; |
WindowPtr whichDialog; |
short whichItem; |
cursorRgn = NewRgn(); /*weÕll pass WNE an empty region the 1st time thru*/ |
sleepTime = 2; |
do |
{ |
if (gHasWaitNextEvent) /*put us 'asleep' forever under MultiFinder*/ |
{ |
gotEvent = WaitNextEvent(everyEvent, &event, sleepTime, cursorRgn); |
} |
else |
{ |
SystemTask(); /*must be called if using GetNextEvent*/ |
gotEvent = GetNextEvent(everyEvent, &event); |
} |
DoIdleProc(); |
AdjustCursor(event.where, cursorRgn); /*make sure we have the right cursor*/ |
whichDialog = FrontWindow(); |
/* don't pass command keys or <enter> keys to our dialog */ |
if (!((event.what==keyDown)&&(event.modifiers & cmdKey)) |
&& (IsDialogEvent(&event)) |
&& !((event.what==keyDown)&&((event.message & charCodeMask) == (char)kEnterKey))) |
{ |
if (DialogSelect(&event, &whichDialog, &whichItem)) |
DoModeless(whichDialog, whichItem); |
} |
else |
DoEvent(event); |
} |
while (true); /*loop forever; we quit through an ExitToShell*/ |
} |
// ***************************************************************** |
// * TrapAvailable |
// * |
// * Check to see if a given trap is implemented. This is only used by the |
// * Initialize routine in this program, so we put it in the Initialize segment. |
// * The recommended approach to see if a trap is implemented is to see if |
// * the address of the trap routine is the same as the address of the |
// * Unimplemented trap. |
// ***************************************************************** |
#pragma segment Initialize |
Boolean TrapAvailable(tNumber,tType) |
short tNumber; |
TrapType tType; |
{ |
if ( ( tType == ToolTrap ) && |
( gMac.machineType > envMachUnknown ) && |
( gMac.machineType < envMacII ) ) |
{ /* it's a 512KE, Plus, or SE */ |
tNumber = tNumber & 0x03FF; |
if ( tNumber > 0x01FF ) /* which means the tool traps */ |
tNumber = _Unimplemented; /* only go to 0x01FF */ |
} |
return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented); |
} /*TrapAvailable*/ |
// ***************************************************************** |
// * zeroOutStrings |
// * |
// * clears out the name, time and incoming text strings |
// ***************************************************************** |
void zeroOutStrings() |
{ |
/* this procedure emptys all connection oriented strings in the main dialog */ |
Rect r; |
short kind; |
Handle h; |
GetDItem(myDialog, kRemoteMacsNameID, &kind, &h, &r); |
SetIText(h, "\p"); |
GetDItem(myDialog, kRemoteMacsTimeID, &kind, &h, &r); |
SetIText(h, "\p"); |
GetDItem(myDialog, kIncomingTextID, &kind, &h, &r); |
SetIText(h, "\p"); |
} |
// ***************************************************************** |
// * SetupUserItems |
// * |
// ***************************************************************** |
void SetupUserItems() |
{ |
setEachUserItem(kzoneItemID); |
setEachUserItem(ktypeItemID); |
setEachUserItem(kobjectItemID); |
setEachUserItem(kRemoteMacsTimeBorderID); |
setEachUserItem(kIncomingMessageBorderID); |
setEachUserItem(kConnectStatusBorder); |
setEachUserItem(kPopupBorderID); |
/* set connect button to unhilited */ |
HiliteConnectButton(255); |
} |
// ***************************************************************** |
// * Initialize |
// * |
// * program initialization |
// ***************************************************************** |
void Initialize() |
{ |
Rect r; |
short kind; |
Handle h; |
Handle menuBar; |
DialogPeek dp; |
gInBackground = false; |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
InitCursor(); |
if (InitAppleTalk() != noErr) |
Exit(atalkErr); |
gZoneString[0] = 0;gTypeStr[0] = 0;gObjStr[0] = 0; |
GetOurZone(); |
/* we will allocate our own window storage instead of letting the Window */ |
/* Manager do it because GetNewWindow may load in temp. resources before */ |
/* making the NewPtr call, and this can lead to heap fragmentation. */ |
myDialog = (DialogPtr)(NewPtr(sizeof(DialogRecord))); |
if (myDialog == nil) |
Exit(memErr); |
myDialog = GetNewDialog(rDialog, (Ptr)myDialog, (DialogPtr)-1); |
SetPort(myDialog); |
dp = (DialogPeek)myDialog; |
TextFont(geneva); |
TextSize(9); |
(**(dp->textH)).txFont = geneva; |
(**(dp->textH)).txSize = 9; |
SetWTitle(myDialog, "\pADSP"); |
ShowWindow(myDialog); |
LastZoneMenuChoice = 0; |
LastTypeMenuChoice = 0; |
LastObjectMenuChoice = 0; |
SetupUserItems(); |
/* show blinking cursor in outgoing text box */ |
SelIText(myDialog, kOutgoingTextID, 0, 32767); |
/* turn on "Moof" entity filter (check box) initially */ |
GetDItem(myDialog, kMoofFilterCheckBox, &kind, &h, &r); |
SetCtlValue((ControlHandle)h,1); |
gMoofEntityFilter = true; |
CopyPstr("\pMoof", gTypeStr); |
gObjStr[0] = 0; |
HiliteConnectButton(0); |
menuBar = GetNewMBar(rMenuBar); /*read menus into menu bar*/ |
if (menuBar == nil) |
Exit(menuErr); |
SetMenuBar(menuBar); /*install menus*/ |
DisposHandle(menuBar); |
AddResMenu(GetMHandle(mApple), 'DRVR'); /*add DA names to Apple menu*/ |
DrawMenuBar(); |
gStopped = true; |
zeroOutStrings(); |
initializeADSP(); |
} /*Initialize*/ |
// ***************************************************************** |
// * CheckEnvirons |
// * |
// * check the current operating environment |
// ***************************************************************** |
void CheckEnvirons() |
{ |
long total, contig, response; |
OSErr ignoreError; |
/* ignore the error returned from SysEnvirons; even if an error occurred,*/ |
/* the SysEnvirons glue will fill in the SysEnvRec*/ |
ignoreError = SysEnvirons(sysEnvironsVersion, &gMac); |
/* Make sure that the machine has at least 128K ROMs. If it doesn't, exit. */ |
if (gMac.machineType < 0) FatalError(9); |
if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap) FatalError(10); |
PurgeSpace(&total, &contig); |
if (total < kMinSpace) |
if (UnloadScrap() != noErr) |
FatalError(11); |
else |
{ |
PurgeSpace(&total, &contig); |
if (total < kMinSpace) |
FatalError(11); |
} |
/* verify if WaitNextEvent, Gestalt and PPCToolbox are available */ |
gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap); |
if (TrapAvailable(_Gestalt, ToolTrap)) |
{ /* verify if system 7.0 */ |
Gestalt(gestaltSystemVersion,&response ); |
if (response >= 0x0700) |
gHasSystem7 = true; |
else gHasSystem7 = false; |
} |
else |
{ |
SysBeep(20); |
gHasSystem7 = false; |
} |
} |
// ***************************************************************** |
// * Main |
// * |
// ***************************************************************** |
#pragma segment Main |
main() |
{ |
MaxApplZone(); /*expand the heap so code segments load at the top*/ |
CheckEnvirons(); /*check for some basic requirements; exits if not met*/ |
Initialize(); /*initialize the program*/ |
UnloadSeg(&Initialize); /*note that Initialize must not be in Main!*/ |
EventLoop(); /*call the main event loop*/ |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14