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.
GetZoneList.c
/* ------------------------------------------------------------------------------ |
# |
# Apple Macintosh Developer Technical Support |
# |
# AppleTalk GetZoneList Sample Application |
# |
# GetZoneList |
# |
# GetZoneList.c - C Source |
# |
# Copyright © 1988-90 Apple Computer, Inc. |
# All rights reserved. |
# |
# Versions: 1.00 November 1988 |
# 1.01 October 1989 |
# 1.02 May 1990 |
# 1.03 June 1992 |
# 1.04 July 1992 |
# |
# Components: GetZoneList.c May 1, 1990 |
# GetZoneList.p May 1, 1990 |
# GetZoneList.r May 1, 1990 |
# MakeFile May 1, 1990 |
# UFailure.a November 1, 1988 |
# UFailure.h November 1, 1988 |
# UFailure.inc1.p November 1, 1988 |
# UFailure.p November 1, 1988 |
# |
# GetZoneList is a sample application that uses |
# AppleTalk ATP and ZIP to obtain a list of zones |
# on an AppleTalk internet. |
# |
# GetZoneList also demonstrates using a signal, or |
# failure-catching mechanism to recover from error |
# situations. Since C does not allow nested procedures |
# a la Pascal, a few modifications were made to incorporate |
# the failure handling and keep this sample fairly close in |
# design to the Pascal sample. |
# (Gee, thanks a lot M2 for using nested procs. - pvh) |
# |
# GetZoneList is based on DTS Sample.c. For more |
# description and explanation of the non-example |
# specific areas of this application, please refer to |
# either Sample.p or TESample.c. |
# |
------------------------------------------------------------------------------ */ |
#include <Limits.h> |
#include <Types.h> |
#include <QuickDraw.h> |
#include <Fonts.h> |
#include <Events.h> |
#include <Controls.h> |
#include <Windows.h> |
#include <Menus.h> |
#include <TextEdit.h> |
#include <Dialogs.h> |
#include <Packages.h> |
#include <Menus.h> |
#include <Devices.h> |
#include <Events.h> |
#include <Scrap.h> |
#include <Lists.h> |
#include <ToolUtils.h> |
#include <Memory.h> |
#include <SegLoad.h> |
#include <Errors.h> |
#include <Files.h> |
#include <OSUtils.h> |
#include <AppleTalk.h> |
#include <Traps.h> |
#include <DiskInit.h> |
#include <Script.h> |
#include <UFailure.h> |
typedef XCallParam *XCallParamPtr; |
#define kSysEnvironsVersion 1 |
#define kOSEvent app4Evt /* event used by Multifinder */ |
#define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */ |
#define kResumeMask 1 /* bit of message field for resume vs. suspend */ |
#define kCR 13 /* carriage return character */ |
#define kENTER 3 /* enter character */ |
#define kScrollBarWidth 15 /* the width of the scrollbar in the list */ |
#define kListInset -1 /* adjustment for list frame */ |
#define kATPTimeOutVal 3 /* re-try ATP SendRequest every 3 seconds */ |
#define kATPRetryCount 5 /* for five times */ |
#define kZonesSize 578 /* size of buffer for zone names */ |
#define kGZLCall 0x08000000 /* GetZoneList indicator */ |
#define kZIPSocket 6 /* the Zone Information Protocol socket */ |
#define kMoreZones 0xFF000000 /* mask to see if more zones to come */ |
#define kZoneCount 0x0000FFFF /* mask to count zones in buffer */ |
#define kHilite 1 /* hilite value for button control */ |
#define kDeHilite 0 /* dehilite value for button control */ |
#define kHiliteDelay 8 /* time in ticks to leave button hilited */ |
#define kMinHeap (29 * 1024) |
#define kMinSpace (20 * 1024) |
#define sErrStrings 128 /* error string STR# */ |
#define eStandardErr 1 |
#define eWrongMachine 2 |
#define eSmallSize 3 |
#define eNoMemory 4 |
#define eAppleTalk 5 |
#define eNoZones 6 |
#define rAboutAlert 128 /* about alert */ |
#define rZoneDialog 129 /* zone list dialog */ |
#define dZoneList 2 /* user item that is zone list */ |
#define dDefault 3 /* user item that is default indicator */ |
#define rUserAlert 130 /* error alert */ |
#define rMenuBar 128 /* application's menu bar */ |
#define mApple 128 /* Apple menu */ |
#define iAbout 1 |
#define mFile 129 /* File menu */ |
#define iNew 1 |
#define iClose 4 |
#define iQuit 12 |
#define mEdit 130 /* Edit menu */ |
#define iUndo 1 |
#define iCut 3 |
#define iCopy 4 |
#define iPaste 5 |
#define iClear 6 |
/* kDITop and kDILeft are used to locate the Disk Initialization dialogs. */ |
#define kDITop 0x0050 |
#define kDILeft 0x0070 |
/* Globs */ |
SysEnvRec gMac; /* set up by Initialize */ |
Boolean gHasWaitNextEvent; /* set up by Initialize */ |
Boolean gInBackground; /* maintained by Initialize and DoEvent */ |
XCallParamPtr gXPBPBPtr; /* structure for Phase 2 NBP lookups */ |
/* needs to be global for failure handling */ |
ListHandle gList; /* the list to be filled with zone names */ |
extern void _DataInit(); |
/* globals added for C sample use as the Pascal |
example used those horrid :-) nested procedures! */ |
ATPPBPtr gATPPBPtr; /* the parameter block for GetZoneList call */ |
Ptr gZones; /* the data buffer for GetZoneList call */ |
DialogPtr gErrDlg; /* Dialog used for displaying zone list */ |
/* 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. */ |
/* 1.02 - Needs to be called after call to SysEnvirons so that it can check |
if a ToolTrap is out of range of a pre-MacII ROM. */ |
#pragma segment Initialize |
Boolean TrapAvailable(tNumber,tType) |
short tNumber; |
TrapType tType; |
{ |
if ( ( tType == (unsigned char) 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) != NGetTrapAddress(_Unimplemented, ToolTrap); |
} /*TrapAvailable*/ |
#pragma segment Main |
void FailOSErrMsg(result, message) |
short result; |
short message; |
{ |
if (result != noErr) |
Failure(result, message); |
} /* SignalOSErrMsg */ |
#pragma segment Main |
void FailnilMsg(p, message) |
Ptr p; |
short message; |
{ |
if (p == nil) |
Failure(memFullErr, message); |
} /* FailNILMsg */ |
#pragma segment Main |
void AlertUser(error, message) |
/* Display an alert to inform the user of an error. Message acts as an |
index into a STR# resource of error messages. if no message is given, |
i.e. = 0, then use a standard message. if error is not noErr then |
display it as well. */ |
short error; |
long message; |
{ |
Str255 msg1, msg2; |
short itemHit; |
if (message <= 0L) message = eStandardErr; |
GetIndString(msg1, sErrStrings, message); |
if (error == noErr) |
msg2[0] = ''; |
else |
NumToString(error, msg2); |
ParamText(msg1, msg2, "\p", "\p"); |
itemHit = Alert(rUserAlert, nil); |
} /* AlertUser */ |
#pragma segment Main |
Boolean IsDAWindow(window) |
WindowPtr window; |
{ |
if (window == nil) |
return (false); |
else /* DA windows have negative windowKinds */ |
return ((WindowPeek) window)->windowKind < 0; |
} /* IsDAWindow */ |
#pragma segment Main |
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 */ |
#pragma segment Main |
void ZoneListCleanUp() |
{ |
if (gATPPBPtr != nil) |
DisposePtr((Ptr)gATPPBPtr); /* get rid of pb block */ |
if (gZones != nil) |
DisposePtr(gZones); /* and buffer */ |
} /* ZoneListCleanUp */ |
#pragma segment Main |
pascal void HandleZoneListErr(short error, long message) |
{ |
#pragma unused (error, message) |
ZoneListCleanUp(); /* get rid of allocated junk */ |
} /* HandleZoneListErr */ |
#pragma segment Main |
void BuildZoneList() |
/* |
* Create the list of zones on the network. Find a bridge to talk to , if one is |
* present, then ask it for zone names. Add the names to the list in the dialog. |
*/ |
{ |
BDSElement dBDS; /* the BDS for GetZoneList call */ |
Ptr dCurr; /* the data buffer for GetZoneList call */ |
short dIndex, dCount; |
short ignore; |
Cell cSize; |
FailInfo fi; |
short nodeNetAddress, bridgeNode; |
gATPPBPtr = nil; /* init some important variables*/ |
gZones = nil; |
CatchCFailures(&fi, HandleZoneListErr); |
gATPPBPtr = (ATPPBPtr)NewPtr(sizeof(ATPParamBlock)); |
FailnilMsg(gATPPBPtr, eNoMemory); |
gZones = NewPtr(kZonesSize); |
FailnilMsg(gZones, eNoMemory); |
dBDS.buffSize = kZonesSize; /* set up BDS */ |
dBDS.buffPtr = gZones; |
gATPPBPtr->ATPatpFlags = 0; |
/* |
* get network address of node & node ID of bridge (if any) |
*/ |
FailOSErrMsg(GetNodeAddress(&ignore, &nodeNetAddress), eAppleTalk); |
bridgeNode = GetBridgeAddress(); |
/* |
* test to see if bridge node fails. If so, no internet. |
*/ |
if (bridgeNode == 0) |
Failure(0, eNoZones); /* bail if no zones present */ |
gATPPBPtr->ATPaddrBlock.aNet = nodeNetAddress; |
gATPPBPtr->ATPaddrBlock.aNode = bridgeNode; /* get node of bridge */ |
gATPPBPtr->ATPaddrBlock.aSocket = kZIPSocket; /* the socket we want */ |
gATPPBPtr->ATPreqLength = 0; |
gATPPBPtr->ATPreqPointer = nil; |
gATPPBPtr->ATPbdsPointer = (Ptr) &dBDS; |
gATPPBPtr->ATPnumOfBuffs = 1; |
gATPPBPtr->ATPtimeOutVal = kATPTimeOutVal; |
gATPPBPtr->ATPretryCount = kATPRetryCount; |
dIndex = 1; |
dCount = 0; |
SetPt(&cSize, 0, 0); /* we always stuff into first */ |
do { |
gATPPBPtr->ATPuserData = kGZLCall + dIndex; /* indicate GetZoneList request */ |
FailOSErrMsg(PSendRequest(gATPPBPtr, false), eAppleTalk); /* send sync request */ |
dCount = dCount + dBDS.userBytes & kZoneCount; /* find out how many returned */ |
dCurr = gZones; /* put current pointer at start */ |
do { /* get each zone */ |
ignore = LAddRow(1, 0, gList); /* create new cell at start */ |
LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList); /* stuff in zone */ |
dCurr = (Ptr)(dCurr + *dCurr + 1 ); /* bump up current pointer */ |
dIndex = dIndex + 1; /* increment which zone */ |
} while(! (dIndex > dCount)); |
} while ((dBDS.userBytes & kMoreZones) == 0); /* keep going until none left */ |
ZoneListCleanUp(); |
Success(&fi); |
} /* BuildZoneList */ |
#pragma segment Main |
void ZoneListCleanUpPhase2() |
{ |
if (gXPBPBPtr != nil) |
DisposePtr((Ptr)gXPBPBPtr); /* get rid of pb block */ |
if (gZones != nil) |
DisposePtr(gZones); /* and buffer */ |
} /* ZoneListCleanUpPhase2 */ |
#pragma segment Main |
void BuildZoneListPhase2() |
/* Create the list of zones on the network. Find a bridge to talk to , if one is |
present, then ask it for zone names. Add the names to the list in the dialog. */ |
{ |
Ptr dCurr; /* the data buffer for GetZoneList call */ |
short dIndex, dCount; |
short ignore; |
Cell cSize; |
FailInfo fi; |
short xppDriverRefNum; |
gXPBPBPtr = nil; /* init some important variables*/ |
gZones = nil; |
CatchCFailures(&fi, HandleZoneListErr); |
/* Get network address of bridge. If zero, no internet. */ |
if (GetBridgeAddress() == 0) |
Failure(0, eNoZones); /* bail if no zones present */ |
/* get a hold of the XPP driver reference number-this is the safest way */ |
FailOSErrMsg(OpenDriver("\p.XPP", &xppDriverRefNum), eAppleTalk); |
gXPBPBPtr = (XCallParamPtr)NewPtr(sizeof(XCallParam)); |
FailnilMsg(gXPBPBPtr, eNoMemory); |
gZones = NewPtr(kZonesSize); |
FailnilMsg(gZones, eNoMemory); |
gXPBPBPtr->zipInfoField[0] = 0; /* ALWAYS 0 on first call. has state info on subsequent calls */ |
gXPBPBPtr->zipInfoField[1] = 0; /* ALWAYS 0 on first call. has state info on subsequent calls */ |
gXPBPBPtr->zipLastFlag = 0; |
gXPBPBPtr->ioRefNum = xppDriverRefNum; |
gXPBPBPtr->csCode = xCall; |
gXPBPBPtr->xppSubCode = zipGetZoneList; |
gXPBPBPtr->xppTimeout = kATPTimeOutVal; |
gXPBPBPtr->xppRetry = kATPRetryCount; |
gXPBPBPtr->zipBuffPtr = (Ptr) gZones; |
dIndex = 1; |
dCount = 0; |
SetPt(&cSize, 0, 0); /* we always stuff into first */ |
do { |
FailOSErrMsg(PBControl((ParmBlkPtr) gXPBPBPtr, false), eAppleTalk); /* send sync control call */ |
dCount = dCount + gXPBPBPtr->zipNumZones; /* find out how many returned */ |
dCurr = gZones; /* put current pointer at start */ |
do { /* get each zone */ |
ignore = LAddRow(1, 0, gList); /* create new cell at start */ |
LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList); /* stuff in zone */ |
dCurr = (Ptr)(dCurr + *dCurr + 1 ); /* bump up current pointer */ |
dIndex = dIndex + 1; /* increment which zone */ |
} while(! (dIndex > dCount)); |
} while (gXPBPBPtr->zipLastFlag == 0); /* keep going until none left */ |
ZoneListCleanUpPhase2(); |
Success(&fi); |
} /* BuildZoneList */ |
#pragma segment Main |
pascal void ZoneListDraw(dlg, item) |
DialogPtr dlg; |
short item; |
{ |
/* The user item void for the zone list user item and default |
box user item in the dialog. Draw the list and the frame that goes with it. |
Draw the default box around the OK button */ |
GrafPtr port; |
short kind; |
Handle h; |
Rect r; |
PenState ps; |
GetPort(&port); /* save old port */ |
SetPort(dlg); /* make dialog port */ |
switch (item) { |
case dZoneList: |
LUpdate(dlg->visRgn, gList); /* re-draw list */ |
GetDialogItem(dlg, dZoneList, &kind, &h, &r); |
InsetRect(&r, kListInset, kListInset); |
FrameRect(&r); /* re-draw frame */ |
break; |
case dDefault: |
GetDialogItem(dlg, dDefault, &kind, &h, &r); |
GetPenState(&ps); |
PenNormal(); /* always be on the defensive */ |
PenSize(3, 3); |
InsetRect(&r, -4, -4); |
FrameRoundRect(&r, 16, 16); /* draw default box */ |
SetPenState(&ps); |
break; |
} |
SetPort(port); /* restore old port */ |
} /* ZoneListDraw */ |
#pragma segment Main |
pascal Boolean ListFilter (dlg, event, item) |
DialogPtr dlg; |
EventRecord *event; |
short *item; |
{ |
/* Passed as parameter to ModalDialog. Handle key presses and mouse clicks |
from the user. Do all the right default actions since we override them |
by virtue of our existence. */ |
GrafPtr port; |
Point loc; |
short kind; |
Handle h; |
Rect r; |
Boolean ignore; |
char key; |
long finalTicks; |
Boolean returnValue; |
returnValue = false; /* always default false */ |
switch (event->what) { |
case keyDown: /* check for <cr> or <enter> */ |
case autoKey: |
key = (char) event->message; |
if (key == kCR || key == kENTER) { /* it was a <cr> or <enter> */ |
GetDialogItem(dlg, ok, &kind, &h, &r); |
HiliteControl((ControlHandle)h, kHilite); |
Delay(kHiliteDelay, &finalTicks); |
HiliteControl((ControlHandle)h, kDeHilite); |
returnValue = true; /* so we handle it */ |
*item = 1; /* and make the first item hit */ |
} |
break; |
case mouseDown: /* we want mouseDowns */ |
GetPort(&port); |
SetPort(dlg); |
loc = event->where; |
GlobalToLocal(&loc); /* find where clicked */ |
GetDialogItem(dlg, dZoneList, &kind, &h, &r); /* get rect for list */ |
if (PtInRect(loc, &r)) { /* if clicked insideÉ */ |
returnValue = true; /* we take care of it */ |
ignore = LClick(loc, event->modifiers, gList); /* by passing click to list */ |
} |
SetPort(port); |
break; |
} |
return (returnValue); |
} /* ListFilter */ |
#pragma segment Main |
void CleanUp_DoZoneList() |
{ |
if (gList != nil) |
LDispose(gList); /* get rid of list */ |
if (gErrDlg != nil) |
DisposeDialog(gErrDlg); /* get rid of dialog */ |
} /* CleanUp_DoZoneList */ |
#pragma segment Main |
pascal void HandleErr_DoZoneList(short error, long message) |
{ |
#pragma unused (error, message) |
CleanUp_DoZoneList(); /* release junk */ |
} /* HandleErr_DoZoneList */ |
#pragma segment Main |
void DoZoneList() |
/* Put up a modal dialog that shows a list of the zones on the net. Create the dialog |
and list, call BuildZoneList to fill it, then wait for the user to click OK. */ |
{ |
DialogPtr dlg; |
short item, kind; |
Handle h; |
Rect r, rView, dataBounds; |
Cell cSize; |
FailInfo fi; |
short hor, ver; |
ModalFilterUPP mfUPP; |
gList = nil; /* init some important variables */ |
dlg = nil; |
CatchCFailures(&fi, HandleErr_DoZoneList); |
dlg = GetNewDialog(rZoneDialog, nil, (WindowPtr)-1); /* create dialog */ |
SetPort(dlg); |
gErrDlg = dlg; |
FailnilMsg(dlg, eNoMemory); |
/* We center the dialog horizontally and position it vertically one-third the |
distance from the menu bar to the bottom of the main device. We do not |
check for the dialog extending past the bottom of the device because we |
know the dialog is not that big. You may wish to make that check. */ |
hor = dlg->portRect.right - dlg->portRect.left; |
ver = dlg->portRect.bottom - dlg->portRect.top; |
hor = ((qd.screenBits.bounds.right - qd.screenBits.bounds.left) - hor) / 2; |
ver = (((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - ver - GetMBarHeight()) / 3) + GetMBarHeight(); |
MoveWindow(dlg, hor, ver, false); |
GetDialogItem(dlg, dDefault, &kind, &h, &r); |
SetDialogItem(dlg, dDefault, kind, (Handle) ZoneListDraw, &r); |
GetDialogItem(dlg, dZoneList, &kind, &h, &r); |
SetDialogItem(dlg, dZoneList, kind, (Handle) ZoneListDraw, &r); /* connect drawing void */ |
rView = r; |
rView.right -= kScrollBarWidth; /* adjust rectangle for scroll */ |
SetRect(&dataBounds, 0, 0, 1, 0); /* init to one-wide list */ |
SetPt(&cSize, 0, 0); |
gList = LNew(&rView, &dataBounds, cSize, 0, (WindowPtr)dlg, |
false, false, false, true); /* create with vertical scroll */ |
FailnilMsg(gList, eNoMemory); |
/* changes for Phase 2 - pvh 8/6/89 */ |
/* this is the easiest check for Phase 2's existence */ |
if(gMac.atDrvrVersNum >= 53) |
BuildZoneListPhase2(); /* put the stuff into the list */ |
else |
BuildZoneList(); /* put the stuff into the list */ |
SetPt(&cSize, 0, 0); |
LSetSelect(true, cSize, gList); /* select the first guy */ |
LSetDrawingMode(true, gList); /* turn on the list */ |
ShowWindow(dlg); /* turn on the dialog */ |
mfUPP = NewModalFilterProc(ListFilter); |
do { |
ModalDialog(mfUPP, &item); /* accept events */ |
} while (item != ok); /* until he presses 'ok' */ |
DisposeRoutineDescriptor(mfUPP); |
CleanUp_DoZoneList(); |
Success(&fi); |
} /* DoZoneList */ |
#pragma segment Main |
Boolean DoCloseWindow(window) |
WindowPtr window; |
{ |
Boolean functionValue = true; |
if (IsDAWindow(window)) |
CloseDeskAcc((short) ((WindowPeek)window)->windowKind); |
if (IsAppWindow(window)) |
CloseWindow(window); |
return(functionValue); |
} /* DoCloseWindow */ |
#pragma segment Initialize |
pascal void HandleErr_Initialize(error, message) |
short error; |
long message; |
{ |
if (error > 0) |
AlertUser(0, error); |
else |
AlertUser(error, message); |
ExitToShell(); |
} /* HandleErr_Initialize */ |
#pragma segment Initialize |
void Initialize() |
{ |
Handle menuBar; |
OSErr ignoreError; |
long total, contig; |
Boolean ignoreResult; |
EventRecord event; |
short count; |
FailInfo fi; |
gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap); |
gInBackground = false; |
InitGraf(&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
InitCursor(); |
/* get MultiFinder started */ |
for (count=1;count<3;count++) |
ignoreResult = EventAvail(everyEvent, &event); |
CatchCFailures(&fi, HandleErr_Initialize); |
FailOSErrMsg(MPPOpen(), eAppleTalk); |
FailOSErrMsg(ATPLoad(), eAppleTalk); |
ignoreError = SysEnvirons(kSysEnvironsVersion, &gMac); |
if (gMac.machineType < 0) |
Failure(0, eWrongMachine); |
if (GetApplLimit() - ApplicationZone() < kMinHeap) |
Failure(0, eSmallSize); |
PurgeSpace(&total, &contig); |
if (total < kMinSpace) |
Failure(0, eNoMemory); |
menuBar = GetNewMBar(rMenuBar); /* read menus into menu bar */ |
FailnilMsg(menuBar, eNoMemory); |
SetMenuBar(menuBar); /* install menus */ |
DisposeHandle(menuBar); |
AppendResMenu(GetMenuHandle(mApple), 'DRVR'); /* add DA names to Apple menu */ |
DrawMenuBar(); |
Success(&fi); |
} /* Initialize */ |
#pragma segment Main |
void Terminate() |
{ |
WindowPtr aWindow; |
Boolean closed; |
closed = true; |
do { |
aWindow = FrontWindow(); /* get the current front window */ |
if (aWindow != nil) |
closed = DoCloseWindow(aWindow); /* close this window */ |
} while ((closed) && (aWindow != nil)); /* do all windows */ |
if (closed) |
ExitToShell(); /* exit if no cancellation */ |
} /* Terminate */ |
#pragma segment Main |
void AdjustMenus() |
{ |
WindowPtr window; |
MenuHandle menu; |
window = FrontWindow(); |
menu = GetMenuHandle(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 = GetMenuHandle(mEdit); |
if (IsDAWindow(window)) { /* a desk accessory might need the edit menu */ |
EnableItem(menu, iUndo); |
EnableItem(menu, iCut); |
EnableItem(menu, iCopy); |
EnableItem(menu, iPaste); |
EnableItem(menu, iClear); |
} |
else { /* but we know we do not */ |
DisableItem(menu, iUndo); |
DisableItem(menu, iCut); |
DisableItem(menu, iCopy); |
DisableItem(menu, iClear); |
DisableItem(menu, iPaste); |
} |
} /* AdjustMenus */ |
pascal void HandleMenu(short error, long message) |
{ |
#pragma unused (error, message) |
HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */ |
} /* HandleMenu */ |
#pragma segment Main |
void DoMenuCommand(menuResult) |
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 ; |
Boolean ignore; |
FailInfo fi; |
CatchCFailures(&fi, (HandlerFuncPtr) HandleMenu); |
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(rAboutAlert, nil); |
break; |
default: /* all non-About items in this menu are DAs */ |
GetMenuItemText(GetMenuHandle(mApple), menuItem, daName); |
daRefNum = OpenDeskAcc(daName); |
break; |
} |
break; |
case mFile: |
switch (menuItem) { |
case iNew: |
DoZoneList(); |
break; |
case iClose: |
ignore = DoCloseWindow(FrontWindow()); |
break; |
case iQuit: |
Terminate(); |
break; |
} |
break; |
case mEdit: /* call SystemEdit for DA editing & Multifinder */ |
handledByDA = SystemEdit(menuItem-1); /* since we don't do any editing */ |
break; |
} |
HiliteMenu(0); /* cleanup */ |
Success(&fi); |
} /* DoMenuCommand */ |
#pragma segment Main |
pascal void HandleErr_DoEvent(error, message) |
short error; |
long message; |
{ |
if (error > 0) |
AlertUser(0, error); |
else |
AlertUser(error, message); |
ExitToShell(); |
} /* HandleErr_DoEvent */ |
#pragma segment Main |
void DoEvent(event) |
EventRecord event; |
{ |
short part; |
WindowPtr window; |
char key; |
FailInfo fi; |
Point aPoint; |
OSErr err; |
CatchCFailures(&fi, (HandlerFuncPtr) HandleErr_DoEvent); |
switch (event.what) { |
case mouseDown: |
part = FindWindow(event.where, &window); |
switch (part) { |
case inMenuBar: /* process the menu command */ |
AdjustMenus(); |
DoMenuCommand(MenuSelect(event.where)); |
break; |
case inSysWindow: /* let the system handle the mouseDown */ |
SystemClick(&event, window); |
break; |
case inContent: |
break; |
case inDrag: |
break; |
case inGrow: |
break; |
case inZoomIn: |
case inZoomOut: |
break; |
} |
break; |
case keyDown: /* check for menukey equivalents */ |
case autoKey: |
key = event.message & charCodeMask; |
if (event.modifiers & cmdKey) { /* Command key down */ |
if (event.what == keyDown) { |
AdjustMenus(); /* enable/disable/check menu items properly */ |
DoMenuCommand(MenuKey(key)); |
} |
} |
break; |
/* call DoActivate with the window and... */ |
case activateEvt: |
break; |
case updateEvt: |
break; |
/* It is not a bad idea to at least call DIBadMount in response |
to a diskEvt, so that the user can format a floppy. */ |
case diskEvt: |
if (HiWord(event.message) != noErr) { |
SetPt(&aPoint, kDILeft, kDITop); |
err = DIBadMount(aPoint, event.message); |
} |
case kOSEvent: |
switch ((event.message >> 24) & 0x0FF) { /* high byte of message */ |
case kSuspendResumeMessage: |
gInBackground = event.message & kResumeMask; |
break; |
} |
break; |
} |
Success(&fi); |
} /* DoEvent */ |
#pragma segment Main |
void EventLoop() |
{ |
RgnHandle cursorRgn; |
Boolean gotEvent; |
EventRecord event; |
cursorRgn = NewRgn(); /* weÕll pass WNE an empty region the 1st time thru */ |
do { |
if (gHasWaitNextEvent) /* put us 'asleep' forever under Multifinder */ |
gotEvent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursorRgn); |
else { |
SystemTask(); /* must be called if using GetNextEvent */ |
gotEvent = GetNextEvent(everyEvent, &event); |
} |
if (gotEvent) { |
DoEvent(event); |
} |
} while (true); /* loop forever; we quit through an ExitToShell */ |
} /* EventLoop */ |
#pragma segment Main |
void main() |
{ |
UnloadSeg(_DataInit); /* note that _DataInit must not be in Main! */ |
MaxApplZone(); /* expand the heap so code segments load at the top */ |
InitUFailure(); |
Initialize(); /* initialize the program */ |
UnloadSeg(Initialize); /* note that Initialize must not be in Main! */ |
EventLoop(); /* call the main event loop */ |
} /* main */ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14