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.
Utilities.c
/* |
File: Utilities.c |
Contains: Collection of Utilities for DTS Sample code |
Written by: |
Copyright: Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/18/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#ifndef __CONTROLS__ |
#include <Controls.h> |
#endif |
#ifndef __DEVICES__ |
#include <Devices.h> |
#endif |
#ifndef __EVENTS__ |
#include <Events.h> |
#endif |
#ifndef __FIXMATH__ |
#include <FixMath.h> |
#endif |
#ifndef __FONTS__ |
#include <Fonts.h> |
#endif |
#ifndef __MENUS__ |
#include <Menus.h> |
#endif |
#ifndef __PACKAGES__ |
#include <Packages.h> |
#endif |
#ifndef __RESOURCES__ |
#include <Resources.h> |
#endif |
#ifndef __SCRIPT__ |
#include <Script.h> |
#endif |
#ifndef __SEGLOAD__ |
#include <SegLoad.h> |
#endif |
#ifndef __STRING__ |
#include <String.h> |
#endif |
#ifndef __LOWMEM__ |
#include <LowMem.h> |
#endif |
#ifndef __TEXTEDIT__ |
#include <TextEdit.h> |
#endif |
#ifndef __TOOLUTILS__ |
#include <ToolUtils.h> |
#endif |
#ifndef __TRAPS__ |
#include <Traps.h> |
#endif |
#ifndef __ERRORS__ |
#include <Errors.h> |
#endif |
#include "Utilities.h" |
#include <TextUtils.h> |
/*----------------------------------------------------------------------------------------- |
Private Functions |
-----------------------------------------------------------------------------------------*/ |
/*----------------------------------------------------------------------------------------- |
Global variables -- See Utilities.h for more explanation |
-----------------------------------------------------------------------------------------*/ |
short gMachineType; /* which machine this is */ |
short gSystemVersion; /* System version number */ |
short gProcessorType; /* which CPU this is */ |
Boolean gHasFPU; /* true if machine has an FPU */ |
short gQDVersion; /* major QD version #; 0 for original, |
1 for color QD, 2 for 32-bit QD */ |
short gKeyboardType; /* which type of keyboard is present */ |
short gAppleTalkVersion; /* AppleTalk version number */ |
Boolean gHasPMMU; /* true if machine has a PMMU or equivalent */ |
short gAUXVersion; /* major A/UX version number (0 if not present) */ |
Boolean gHasWaitNextEvent; |
short gAppResRef; |
Boolean gInBackground; |
Str255 gAppName; |
OSType gSignature = '????'; |
Boolean gUtilitiesInited; |
/*****************************************************************************/ |
/* Given an alert ID and a window pointer the alert relates to, this function |
** will center the alertÕs rectangle before showing it on the proper screen. |
** This follows the Apple Human Interface Guidelines for where to place a |
** centered window on the screen. If the alert is not closely associated with |
** another window, pass a NULL for the window pointer of the related window. If |
** you pass a NULL, the alert is simply displayed where the resource |
** would indicate. Note that if an error occurs when getting the resource for |
** the alert, then the alert is not displayed, and the returned value is not |
** the item hit, but is the error that occured when reading the resource. */ |
#pragma segment UtilMain |
short CenteredAlert(short alertID, WindowPtr relatedWindow) |
{ |
AlertTHndl alertHandle; |
WindowPtr tempWindow; |
Rect alertRect; |
short itemHit; |
char hstate; |
OSErr err; |
alertHandle = (AlertTHndl)GetAppResource('ALRT', alertID, &err); |
if (err) return((short)err); |
hstate = LockHandleHigh((Handle)alertHandle); |
/* Do our part to help prevent fragmentation. */ |
alertRect = (*alertHandle)->boundsRect; |
/* Preserve the real alert bounding rectangle. */ |
if (tempWindow = NewWindow(NULL, &alertRect, "\p", false, dBoxProc, |
(WindowPtr)NULL, false, 0)) { |
/* Use an invisible temporary window to calculate where the alert will go. */ |
(*alertHandle)->boundsRect = CenterWindow(tempWindow, relatedWindow); |
DisposeWindow(tempWindow); |
} |
itemHit = Alert(alertID, NULL); |
(*alertHandle)->boundsRect = alertRect; |
/* Restore the resource's bounding rect, so if this resource is ever used |
** not through this function, it will open where the resource indicates. */ |
HSetState((Handle)alertHandle, hstate); |
return(itemHit); |
} |
/*****************************************************************************/ |
/* Given two rects, this function centers the second one within the first. */ |
#pragma segment UtilMain |
void CenterRectInRect(Rect outerRect, Rect *innerRect) |
{ |
PositionRectInRect(outerRect, innerRect, FixRatio(1, 2), FixRatio(1, 2)); |
} |
/*****************************************************************************/ |
/* Center a window within a particular device. The device to center the window |
** within is determined by passing a related window. This allows related |
** windows to be kept on the same device. This is useful if an alert related |
** to a specific window, for example. */ |
#pragma segment UtilMain |
Rect CenterWindow(WindowPtr window, WindowPtr relatedWindow) |
{ |
WindowPtr whichDevice; |
Rect deviceRect, oldWindowRect, newWindowRect, contentRect; |
if (!(whichDevice = relatedWindow)) whichDevice = window; |
/* If we have a window to center against, use the device for that window, |
** else use the device for the window that is getting centered. */ |
deviceRect = GetWindowDeviceRectNMB(whichDevice); |
/* We now have the rectangle of the device we want to center within. */ |
oldWindowRect = newWindowRect = GetWindowStructureRect(window); |
PositionRectInRect(deviceRect, &newWindowRect, FixRatio (1, 2), |
FixRatio (1, 3)); |
/* Figure out the new window strucRect so we can compare it against |
** the old strucRect. This will tell us how much to move the window. */ |
contentRect = GetWindowContentRect(window); |
/* Get where the window is now. */ |
OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left, |
newWindowRect.top - oldWindowRect.top); |
/* Calculate the new content rect. */ |
MoveWindow(window, contentRect.left, contentRect.top, false); |
/* Move the window to the new location. */ |
return(contentRect); |
} |
/*****************************************************************************/ |
/* Close a window. This handles desk accessory and application windows. Use |
** this call (instead of DisposeAnyWindow) if the memory for the window was |
** allocated by you. (Same as CloseWindow v.s. DisposeWindow.) */ |
#pragma segment UtilMain |
void CloseAnyWindow(WindowPtr window) |
{ |
if (IsDAWindow(window)) |
CloseDeskAcc(((WindowPeek)window)->windowKind); |
else { |
if (IsAppWindow(window)) |
CloseWindow(window); |
else if (((WindowPeek)window)->windowKind >= dialogKind) |
CloseDialog((DialogPtr)window); |
} |
} |
/*****************************************************************************/ |
/* Dispose a window. This handles desk accessory and application windows. Use |
** this call (instead of CloseAnyWindow) if you want the memory for the window |
** record to be disposed of. (Same as CloseWindow v.s. DisposeWindow.) */ |
#pragma segment UtilMain |
void DisposeAnyWindow(WindowPtr window) |
{ |
if (IsDAWindow(window)) |
CloseDeskAcc(((WindowPeek)window)->windowKind); |
else { |
if (IsAppWindow(window)) |
DisposeWindow(window); |
else if (((WindowPeek)window)->windowKind >= dialogKind) |
DisposeDialog((DialogPtr)window); |
} |
} |
/*****************************************************************************/ |
/* Display an alert that tells the user an error occurred, then exit the |
** program. This function is used as an ultimate bail-out for serious errors |
** that prohibit the continuation of the application. Errors that do not |
** require the termination of the application should be handled in a different |
** manner. */ |
#pragma segment UtilMain |
void DeathAlert(short errResID, short errStringIndex) |
{ |
ErrorAlert(errResID, errStringIndex); |
ExitToShell(); |
} |
/*****************************************************************************/ |
/* Display an alert that tells the user an error occurred, then exit the |
** program. This function is used as an ultimate bail-out for serious errors |
** that prohibit the continuation of the application. Errors that do not |
** require the termination of the application should be handled in a different |
** manner. The message parameter is an error code that is to be displayed. */ |
#pragma segment UtilMain |
void DeathAlertMessage(short errResID, short errStringIndex, short message) |
{ |
ErrorAlertMessage(errResID, errStringIndex, message); |
ExitToShell(); |
} |
/*****************************************************************************/ |
/* Display an alert that tells the user an error occurred. */ |
#pragma segment UtilMain |
void ErrorAlert(short errResID, short errStringIndex) |
{ |
ErrorAlertMessage(errResID, errStringIndex, 0); |
} |
/*****************************************************************************/ |
/* Display an alert to inform the user of an error. errStringIndex acts as an |
** index into a STR# resource of error messages. If no errStringIndex is |
** given, i.e. = 0, then use a standard message. If message is not noErr then |
** display it as well. |
** |
** BUG NOTE: GetIndString returns a bogus String if the index is |
** not positive. */ |
#pragma segment UtilMain |
void ErrorAlertMessage(short errResID, short errStringIndex, short message) |
{ |
Str255 msg1, msg2; |
SetCursor(&QD(arrow)); |
if (errStringIndex <= 0) { |
errStringIndex = eStandardErr; |
errResID = rUtilStrings; |
} |
GetIndString(msg1, errResID, errStringIndex); |
if (message == noErr) { |
ParamText(msg1, "\p", "\p", "\p"); |
CenteredAlert(rUtilErrorAlert, NULL); |
} else { |
NumToString(message, msg2); |
ParamText(msg1, msg2, "\p", "\p"); |
CenteredAlert(rUtilErrorMessageAlert, NULL); |
} |
} |
/*****************************************************************************/ |
/* FindSysFolder returns the (real) vRefNum, and the DirID of the current |
** system folder. It uses the Folder Manager if present, otherwise it falls |
** back to SysEnvirons. It returns zero on success, otherwise a standard |
** system error. */ |
#pragma segment UtilMain |
OSErr FindSysFolder(short *foundVRefNum, long *foundDirID) |
{ |
long gesResponse; |
SysEnvRec envRec; |
WDPBRec myWDPB; |
unsigned char volName[34]; |
OSErr err; |
*foundVRefNum = 0; |
*foundDirID = 0; |
if (!Gestalt (gestaltFindFolderAttr, &gesResponse) && |
BTstQ (gesResponse, gestaltFindFolderPresent)) { /* Does Folder Manager exist? */ |
err = FindFolder (kOnSystemDisk, kSystemFolderType, kDontCreateFolder, |
foundVRefNum, foundDirID); |
} else { |
/* Gestalt can't give us the answer, so we resort to SysEnvirons */ |
if (!(err = SysEnvirons (curSysEnvVers, &envRec))) { |
myWDPB.ioVRefNum = envRec.sysVRefNum; |
volName[0] = '\000'; /* Zero volume name */ |
myWDPB.ioNamePtr = volName; |
myWDPB.ioWDIndex = 0; |
myWDPB.ioWDProcID = 0; |
if (!(err = PBGetWDInfo (&myWDPB, 0))) { |
*foundVRefNum = myWDPB.ioWDVRefNum; |
*foundDirID = myWDPB.ioWDDirID; |
} |
} |
} |
return (err); |
} |
/*****************************************************************************/ |
/* GetAppIndResource gets a resource from the application's resource file |
** by index. */ |
#pragma segment UtilMain |
Handle GetAppIndResource(ResType theType, short index, OSErr *err) |
{ |
#pragma unused (err) |
short savedResFile; |
Handle returnHandle; |
savedResFile = CurResFile (); |
UseResFile (gAppResRef); |
returnHandle = Get1IndResource(theType, index); |
UseResFile (savedResFile); |
return (returnHandle); |
} |
/*****************************************************************************/ |
/* GetAppNamedResource gets a resource from the application's resource file |
** by name. */ |
#pragma segment UtilMain |
Handle GetAppNamedResource(ResType theType, Str255 name, OSErr *err) |
{ |
short savedResFile; |
Handle returnHandle; |
savedResFile = CurResFile (); |
UseResFile (gAppResRef); |
returnHandle = Get1NamedResource(theType, name); |
*err = ResError(); |
UseResFile (savedResFile); |
return (returnHandle); |
} |
/*****************************************************************************/ |
/* GetAppResource gets a resource from the application's resource file by |
** resource ID. */ |
#pragma segment UtilMain |
Handle GetAppResource(ResType theType,short theID, OSErr *err) |
{ |
short savedResFile; |
Handle returnHandle; |
savedResFile = CurResFile (); |
UseResFile (gAppResRef); |
returnHandle = Get1Resource(theType, theID); |
*err = ResError(); |
UseResFile (savedResFile); |
return (returnHandle); |
} |
/*****************************************************************************/ |
/* Checks for the presence of A/UX by whatever means is appropriate. Returns |
** the major version number of A/UX (i.e. 0 if A/UX is not present, 1 for |
** any 1.x.x version 2 for any 2.x version, etc. |
** |
** This code should work for all past, present and future A/UX systems. */ |
#pragma segment UtilMain |
short GetAUXVersion(void) |
{ |
long auxVersion; |
short err; |
/* |
* This code assumes the Gestalt glue checks for the presence of the _Gestalt |
* trap and does something intelligent if the trap is unavailable, i.e. |
* return unknown selector. |
*/ |
auxVersion = 0; |
err = Gestalt(gestaltAUXVersion, &auxVersion); |
/* |
* If gestaltUnknownErr or gestaltUndefSelectorErr was returned, then either |
* we weren't running on A/UX, or the _Gestalt trap is unavailable so use |
* HWCfgFlags instead. |
* All other errors are ignored (implies A/UX not present). |
*/ |
if (err == gestaltUnknownErr || err == gestaltUndefSelectorErr) { /* Use HWCfgFlags */ |
if (BTstQ(LMGetHWCfgFlags(), 9)) |
auxVersion = 0x100; /* Do Have A/UX, so assume version 1.x.x */ |
} |
/* |
* Now right shift auxVersion by 8 bits to get major version number |
*/ |
auxVersion >>= 8; |
return((short)auxVersion); |
} |
/*****************************************************************************/ |
/* Given a dialog ID and a window pointer the dialog relates to, this function |
** will center the dialogÕs rectangle before showing it on the proper screen. |
** This follows the Apple Human Interface Guidelines for where to place a |
** centered window on the screen. If the dialog is not closely associated with |
** another window, pass a NULL for the window pointer of the related window. If |
** you pass a NULL, the dialog is simply displayed where the resource |
** would indicate. */ |
#pragma segment UtilMain |
DialogPtr GetCenteredDialog(short id, DialogPtr storage, WindowPtr relatedWindow, WindowPtr behind) |
{ |
DialogTHndl dlogResource; |
DialogPtr dialog; |
Boolean oldVis; |
char hstate; |
OSErr err; |
dialog = NULL; |
if (dlogResource = (DialogTHndl)GetAppResource('DLOG', id, &err)) { |
hstate = LockHandleHigh((Handle)dlogResource); |
oldVis = (*dlogResource)->visible; |
(*dlogResource)->visible = false; |
if (dialog = GetNewDialog(id, storage, behind)) { |
CenterWindow(dialog, relatedWindow); |
if (oldVis) ShowWindow(dialog); |
} |
(*dlogResource)->visible = oldVis; |
HSetState((Handle)dlogResource, hstate); |
} |
return(dialog); |
} |
/*****************************************************************************/ |
/* Given a window ID and a window pointer the window relates to, this function |
** will center the windowÕs rectangle before showing it on the proper screen. |
** This follows the Apple Human Interface Guidelines for where to place a |
** centered window on the screen. If the window is not closely associated with |
** another window, pass a NULL for the window pointer of the related window. If |
** you pass a NULL, the window is simply displayed where the resource |
** would indicate. */ |
#pragma segment UtilMain |
WindowPtr GetCenteredWindow(short id, Ptr storage, WindowPtr relatedWindow, |
WindowPtr behind, Boolean inColor) |
{ |
return(GetSomeKindOfWindow(CenterWindow, id, storage, relatedWindow, behind, inColor)); |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
Boolean GetCheckOrRadio(DialogPtr dlgPtr, short itemNo) |
{ |
short iKind; |
Handle iHandle; |
Rect iRect; |
GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect); |
return(GetControlValue((ControlHandle)iHandle) != 0); |
} |
/*****************************************************************************/ |
/* GetGestaltResult returns the result value from Gestalt for the specified |
** selector. If Gestalt returned an error GetGestaltResult returns zero. |
** Use of this function is only cool if we don't care whether Gestalt returned |
** an error. In many cases you may need to know the exact Gestalt error code |
** so then this function would be inappropriate. |
** See GetAUXVersion for an example. */ |
#pragma segment UtilMain |
long GetGestaltResult(OSType gestaltSelector) |
{ |
long gestaltResult; |
if (Gestalt(gestaltSelector, &gestaltResult) == noErr) |
return(gestaltResult); |
else |
return(0); |
} |
/*****************************************************************************/ |
/* Get the global coordinates of the mouse. When you call OSEventAvail it will |
** return either a pending event or a null event. In either case, the where |
** field of the event record will contain the current position of the mouse in |
** global coordinates and the modifiers field will reflect the current state of |
** the modifiers. Another way to get the global coordinates is to call |
** GetMouse and LocalToGlobal, but that requires being sure that thePort is set |
** to a valid port. */ |
#pragma segment UtilMain |
Point GetGlobalMouse(void) |
{ |
EventRecord event; |
OSEventAvail(kNoEvents, &event); /* we arenÕt interested in any events */ |
return(event.where); /* just the mouse position */ |
} |
/*****************************************************************************/ |
/* Given a window, this will return the top left point of the windowÕs port in |
** global coordinates. Something this doesnÕt include is the windowÕs drag |
** region (or title bar). This returns the top left point of the windowÕs |
** content area only. */ |
#pragma segment UtilMain |
Point GetGlobalTopLeft(WindowPtr window) |
{ |
GrafPtr oldPort; |
Point globalPt; |
GetPort(&oldPort); |
SetPort(window); |
globalPt = TopLeft(window->portRect); |
LocalToGlobal(&globalPt); |
SetPort(oldPort); |
return(globalPt); |
} |
/*****************************************************************************/ |
/* Return the amount of free space on the volume in KBytes. -1 is returned as |
** the size if there is an error. */ |
#pragma segment UtilInit |
long GetKFreeSpace(short vRefNum) |
{ |
HParamBlockRec pb; |
OSErr err; |
pb.volumeParam.ioNamePtr = NULL; /* we don't care about the name */ |
pb.volumeParam.ioVRefNum = vRefNum; |
pb.volumeParam.ioVolIndex = 0; /* use ioVRefNum only */ |
err = PBHGetVInfo(&pb, false); |
if (err == noErr) |
return((pb.volumeParam.ioVFrBlk * pb.volumeParam.ioVAlBlkSiz) / 1024); |
else |
return(-1); |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
Rect GetMainScreenRect(void) |
{ |
GDHandle mainDevice; |
GrafPtr mainPort; |
if (gQDVersion > kQDOriginal) { |
mainDevice = GetMainDevice(); |
return((*mainDevice)->gdRect); |
} else { |
GetWMgrPort(&mainPort); |
return(mainPort->portRect); |
} |
} |
/*****************************************************************************/ |
/* Find the greatest overlap device for the given global rectangle. */ |
#pragma segment UtilInit |
GDHandle GetRectDevice(Rect globalRect) |
{ |
long area; |
long maxArea; |
GDHandle device; |
GDHandle deviceToReturn; |
Rect intersection; |
deviceToReturn = GetMainDevice(); /* Use as default choice. */ |
maxArea = 0; |
for (device = GetDeviceList(); device; device = GetNextDevice(device)) { |
if (TestDeviceAttribute(device, screenDevice) |
&& TestDeviceAttribute(device, screenActive) |
&& SectRect(&globalRect, &((*device)->gdRect), &intersection)) { |
area = (intersection.right - intersection.left) * |
(intersection.bottom - intersection.top); |
if (area > maxArea) { |
deviceToReturn = device; |
maxArea = area; |
} |
} |
} |
return(deviceToReturn); |
} |
/*****************************************************************************/ |
/* Find the rect of the greatest overlap device for the given global rect. */ |
#pragma segment UtilInit |
Rect GetRectDeviceRect(Rect globalRect) |
{ |
if (gQDVersion > kQDOriginal) |
return((*GetRectDevice(globalRect))->gdRect); |
else |
return(GetMainScreenRect()); |
} |
/*****************************************************************************/ |
/* Given a window positioning procedure pointer, a window ID and a window |
** pointer the window relates to, this function open a new window by either |
** a NewCWindow or a NewWindow call, depending on the value of inColor. The |
** window will be opened invisible, independent of what the resource says. |
** Once the window is opened successfully, the positioning procedure is |
** called. The positioning procedure is passed a pointer to the just-opened |
** invisible window and a pointer to the related window. It is up to the |
** positioning procedure to move the invisible window to the correct location |
** on the correct device. Once the positioning procedure returns, the window |
** will be made visible if so indicated by the resource. */ |
#pragma segment UtilMain |
WindowPtr GetSomeKindOfWindow(PositionWndProcPtr whatKind, short windID, |
Ptr storage, WindowPtr relatedWindow, |
WindowPtr behind, Boolean inColor) |
{ |
WindowTHndl windowResource; |
WindowTemplate wt; /* Window template. */ |
WindowPtr aWindow; |
OSErr err; |
if (!gQDVersion) inColor = false; |
aWindow = NULL; /* Assume we will fail. (Good attitude.) */ |
if (!storage) storage = NewPtr(sizeof(WindowRecord)); |
if (storage) { /* If we have memory for the window record... */ |
if (windowResource = (WindowTHndl)GetAppResource('WIND', windID, &err)) { |
/* If we can load the window resource... */ |
wt = **windowResource; /* Make local copy of resource. */ |
aWindow = (inColor ? NewCWindow(storage, &wt.boundsRect, |
wt.title, false, wt.procID, |
behind, wt.goAwayFlag, wt.refCon) |
: NewWindow(storage, &wt.boundsRect, wt.title, |
false, wt.procID, |
behind, wt.goAwayFlag, wt.refCon)); |
/* Open either a regular or color window. */ |
if (aWindow) { /* If we were able to open a window... */ |
(*whatKind)(aWindow, relatedWindow); |
/* Call the designated window positioning procedure. */ |
if (wt.visible) ShowWindow(aWindow); |
/* If resource says window should be visible, do it. */ |
} |
} |
if (!aWindow) DisposePtr(storage); |
/* If we failed, then get rid of window record memory. */ |
} |
return(aWindow); |
} |
/*****************************************************************************/ |
/* Given a window ID and a window pointer the window relates to, this function |
** will stagger the windowÕs rectangle before showing it on the proper screen. |
** This follows the Apple Human Interface Guidelines for where to place a |
** staggered window on the screen. If the window is not closely associated |
** with another window, pass a NULL for the window pointer of the related |
** window. If you pass a NULL, the window is simply displayed where the |
** resource would indicate. */ |
#pragma segment UtilMain |
WindowPtr GetStaggeredWindow(short id, Ptr storage, WindowPtr relatedWindow, |
WindowPtr behind, Boolean inColor) |
{ |
return(GetSomeKindOfWindow(StaggerWindow, id, storage, relatedWindow, behind, inColor)); |
} |
/*****************************************************************************/ |
/* Check the bits of a trap number to determine its type. */ |
#pragma segment UtilInit |
TrapType GetTrapType(short theTrap) |
{ |
/* OS traps start with A0, Tool with A8 or AA. */ |
if ((theTrap & 0x0800) == 0) /* per D.A. */ |
return (OSTrap); |
else |
return (ToolTrap); |
} |
/*****************************************************************************/ |
/* Given a window pointer, return the global rectangle that encloses the |
** content area of the window. */ |
#pragma segment UtilMain |
Rect GetWindowContentRect(WindowPtr window) |
{ |
WindowPtr oldPort; |
Rect contentRect; |
GetPort(&oldPort); |
SetPort(window); |
contentRect = window->portRect; |
LocalToGlobalRect(&contentRect); |
SetPort(oldPort); |
return(contentRect); |
} |
/*****************************************************************************/ |
/* This procedure counts the number of windows in the application plane. |
** You have the choices of also including DAs and invisible windows in |
** this count. */ |
#pragma segment UtilMain |
short GetWindowCount(Boolean includeDAs, Boolean includeInvisibles) |
{ |
WindowPeek window; |
short count; |
for (count = 0, window = (WindowPeek)LMGetWindowList(); |
(window != NULL); window = window->nextWindow) { |
if ((window->windowKind < 0) && (!includeDAs)) continue; |
if ((window->visible) || (includeInvisibles)) count++; |
} |
return (count); |
} |
/*****************************************************************************/ |
/* Find the greatest overlap device for the given window. */ |
#pragma segment UtilInit |
GDHandle GetWindowDevice(WindowPtr window) |
{ |
return(GetRectDevice(GetWindowStructureRect(window))); |
} |
/*****************************************************************************/ |
/* Given a window pointer, find the device that contains most of the window |
** and return the device's bounding rectangle. */ |
#pragma segment UtilMain |
Rect GetWindowDeviceRect(WindowPtr window) |
{ |
if (gQDVersion > kQDOriginal) |
return((*GetWindowDevice(window))->gdRect); |
else |
return(GetMainScreenRect()); |
} |
/*****************************************************************************/ |
/* Given a window pointer, find the device that contains most of the window |
** and return the device's bounding rectangle. If this device is the main |
** device, then remove the menubar area from the rectangle. */ |
#pragma segment UtilMain |
Rect GetWindowDeviceRectNMB(WindowPtr window) |
{ |
Rect deviceRect, tempRect; |
deviceRect = GetWindowDeviceRect(window); |
tempRect = GetMainScreenRect(); |
if (EqualRect(&deviceRect, &tempRect)) deviceRect.top += GetMBarHeight(); |
return(deviceRect); |
} |
/*****************************************************************************/ |
/* This procedure is used to get the rectangle that surrounds the entire |
** structure of a window. This is true whether or not the window is visible. |
** If the window is visible, then it is a simple matter of using the bounding |
** rectangle of the structure region. If the window is invisible, then the |
** strucRgn is not correct. To make it correct, then window has to be moved |
** way off the screen and then made visible. This generates a valid strucRgn, |
** although it is valid for the position that is way off the screen. It still |
** needs to be offset back into the original position. Once the bounding |
** rectangle for the strucRgn is obtained, the window can then be hidden again |
** and moved back to its correct location. Note that ShowHide is used, |
** instead of ShowWindow and HideWindow. HideWindow can change the plane of |
** the window. Also, ShowHide does not affect the hiliting of windows. */ |
#pragma segment UtilMain |
Rect GetWindowStructureRect(WindowPtr window) |
{ |
#define kOffscreenLoc 0x4000 |
GrafPtr oldPort; |
Rect structureRect; |
Point windowLoc; |
if (((WindowPeek)window)->visible) |
structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox; |
else { |
GetPort(&oldPort); |
SetPort(window); |
windowLoc = GetGlobalTopLeft(window); |
MoveWindow(window, windowLoc.h, kOffscreenLoc, false); |
ShowHide(window, true); |
structureRect = (*(((WindowPeek)window)->strucRgn))->rgnBBox; |
ShowHide(window, false); |
MoveWindow(window, windowLoc.h, windowLoc.v, false); |
SetPort(oldPort); |
OffsetRect(&structureRect, 0, windowLoc.v - kOffscreenLoc); |
} |
return(structureRect); |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
void GlobalToLocalRect(Rect *aRect) |
{ |
GlobalToLocal(&TopLeft(*aRect)); |
GlobalToLocal(&BotRight(*aRect)); |
} |
/*****************************************************************************/ |
#pragma segment UtilInit |
void InitToolBox(void) |
{ |
InitGraf((Ptr) &QD(thePort)); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(NULL); |
InitCursor(); |
} |
/*****************************************************************************/ |
/* InitUtilities sets up some global variables for use by the utilities |
** package. If you call StandardInitialization, you don't need to call this, |
** as it will do it for you. */ |
#pragma segment UtilInit |
void InitUtilities(void) |
{ |
//Handle apParam; |
Handle bndlResource; |
OSErr err; |
gUtilitiesInited = false; |
/* Init all the Gestalt variables */ |
gMachineType = GetGestaltResult (gestaltMachineType); |
gSystemVersion = GetGestaltResult (gestaltSystemVersion); |
gProcessorType = GetGestaltResult (gestaltProcessorType); |
/* We only concern ourselves with there being an FPU, not which type it is */ |
gHasFPU = (GetGestaltResult (gestaltFPUType) != gestaltNoFPU); |
/* |
* We only concern ourselves with the major QD version number |
* 0 for original QD, 1 for 8-bit color QD, and 2 for 32-bit QD |
*/ |
gQDVersion = (GetGestaltResult (gestaltQuickdrawVersion) >> 8) & 0xFF; |
gKeyboardType = GetGestaltResult (gestaltKeyboardType); |
gAppleTalkVersion = GetGestaltResult (gestaltAppleTalkVersion); |
/* We only concern ourselves with there being an PMMU, not which type it is */ |
gHasPMMU = GetGestaltResult (gestaltMMUType) >= gestalt68851; |
gAUXVersion = GetAUXVersion (); |
gHasWaitNextEvent = TrapExists(_WaitNextEvent); |
gInBackground = false; |
/* |
10/16/90 pvh/MacDTS |
With GetAppParams(), THINK C in project mode returns the project resource file AND NOT |
the .rsrc file, which is what one really wants (trust me). If THINK is present we will |
return CurResFile() which will be the .rsrc file instead. The name will still be the |
project name in project mode, so be aware of that. |
*/ |
//GetAppParms(gAppName, &gAppResRef, &apParam); |
gAppResRef = CurResFile(); /* returns refNum of .rsrc file */ |
bndlResource = GetAppIndResource('BNDL', 1, &err); |
if (bndlResource) |
gSignature = *(OSType *) (*bndlResource); |
gUtilitiesInited = true; |
} |
/*****************************************************************************/ |
/* Check to see if a window belongs to the application. If the window pointer |
** passed was NULL, then it could not be an application window. WindowKinds |
** that are negative belong to the system and windowKinds less than userKind |
** are reserved by Apple except for windowKinds equal to dialogKind, which |
** mean it is a dialog. */ |
#pragma segment UtilMain |
Boolean IsAppWindow(WindowPtr window) |
{ |
if (window) |
return (((WindowPeek)window)->windowKind >= userKind); |
else |
return false; |
} |
/*****************************************************************************/ |
/* Check to see if a window belongs to a desk accessory. */ |
#pragma segment UtilMain |
Boolean IsDAWindow(WindowPtr window) |
{ |
if (window) /* DA windows have negative windowKinds */ |
return (((WindowPeek) window)->windowKind < 0); |
else |
return false; |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
void LocalToGlobalRect(Rect *aRect) |
{ |
LocalToGlobal(&TopLeft(*aRect)); |
LocalToGlobal(&BotRight(*aRect)); |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
char LockHandleHigh(Handle theHandle) |
{ |
char hstate; |
hstate = HGetState(theHandle); |
MoveHHi(theHandle); |
HLock(theHandle); |
return(hstate); |
} |
/*****************************************************************************/ |
/* InitGraf is always implemented (trap $A86E). If the trap table is big |
** enough, trap $AA6E will always point to either Unimplemented or some other |
** trap, but will never be the same as InitGraf. Thus, you can check the size |
** of the trap table by asking if the address of trap $A86E is the same as |
** $AA6E. */ |
#pragma segment UtilInit |
short NumToolboxTraps(void) |
{ |
if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap)) |
return (0x200); |
else |
return (0x400); |
} |
/*****************************************************************************/ |
/* Given any control handle, this will draw an outline around it. This is used |
** for the default button of a window. The extra nice feature here is that |
** IÕll erase the outline for buttons that are inactive. Seems like there |
** should be a Toolbox call for getting a controlÕs hilite state. Since there |
** isnÕt, I have to look into the control record myself. This should be called |
** for update and activate events. |
** |
** The method for determining the oval diameters for the roundrect is a little |
** different than that recommended by Inside Mac. IM I-407 suggests that you |
** use a hardcoded (16,16) for the diameters. However, this only looks good |
** for small roundrects. For larger ones, the outline doesnÕt follow the inner |
** roundrect because the CDEF for simple buttons doesnÕt use (16,16). Instead, |
** it uses half the height of the button as the diameter. By using this |
** formula, too, our outlines look better. |
** |
** WARNING: This will set the current port to the controlÕs window. */ |
#pragma segment UtilMain |
void OutlineControl(ControlHandle button) |
{ |
Rect theRect; |
PenState curPen; |
short buttonOval; |
if (button) { |
SetPort((*button)->contrlOwner); |
GetPenState(&curPen); |
PenNormal(); |
theRect = (*button)->contrlRect; |
InsetRect(&theRect, kButtonFrameInset, kButtonFrameInset); |
buttonOval = (theRect.bottom - theRect.top) / 2 + 2; |
PenPat((*button)->contrlHilite == kCntlActivate ? &QD(black) : &QD(gray)); |
PenSize(kButtonFrameSize, kButtonFrameSize); |
FrameRoundRect(&theRect, buttonOval, buttonOval); |
SetPenState(&curPen); |
} |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
void OutlineDialogItem(DialogPtr dlgPtr, short item) |
{ |
short iKind; |
Handle iHandle; |
Rect iRect; |
GetDialogItem (dlgPtr, item, &iKind, &iHandle, &iRect); |
OutlineControl((ControlHandle) iHandle); |
} |
/*****************************************************************************/ |
/* Given two rectangles, this function positions the second within the first |
** one so that it maintains the spacing specified by the horzRatio and |
** vertRatio parameters. In other words, to center an inner rectangle |
** hoizontally, but have its center be 1/3 from the top of the outer rectangle, |
** call this function with horzRatio = FixRatio (1, 2), vertRatio = |
** FixRatio(1, 3). We use Fixed rather than floating point to avoid |
** complications when mixing MC68881/non-MC68881 versions of Utilities. */ |
#pragma segment UtilMain |
void PositionRectInRect(Rect outerRect, Rect *innerRect, Fixed horzRatio, Fixed vertRatio) |
{ |
short outerRectHeight; |
short outerRectWidth; |
short innerRectHeight; |
short innerRectWidth; |
short yLocation; |
short xLocation; |
outerRectHeight = outerRect.bottom - outerRect.top; |
outerRectWidth = outerRect.right - outerRect.left; |
innerRectHeight = innerRect->bottom - innerRect->top; |
innerRectWidth = innerRect->right - innerRect->left; |
yLocation = Fix2Long(FixMul(Long2Fix(outerRectHeight - innerRectHeight), vertRatio)) |
+ outerRect.top; |
xLocation = Fix2Long(FixMul(Long2Fix(outerRectWidth - innerRectWidth), horzRatio)) |
+ outerRect.left; |
innerRect->top = yLocation; |
innerRect->left = xLocation; |
innerRect->bottom = yLocation + innerRectHeight; |
innerRect->right = xLocation + innerRectWidth; |
} |
/*****************************************************************************/ |
/* Concatenate a Pascal string onto another. */ |
#pragma segment UtilMain |
void PStrConcat(Str255 targetStr, Str255 appendStr) |
{ |
long appendLen; |
/* Figure out number of bytes to copy, up to 255 */ |
if ((StrLength (targetStr) + StrLength (appendStr)) > 255) |
appendLen = 255 - StrLength (targetStr); |
else |
appendLen = StrLength (appendStr); |
if (appendLen > 0) { |
BlockMove (appendStr + 1, targetStr + StrLength (targetStr) + 1, appendLen); |
targetStr [0] += appendLen; |
} |
} |
/*****************************************************************************/ |
#pragma segment UtilInit |
void PullApplicationToFront(void) |
{ |
#define kBroughtToFront 3 |
EventRecord event; |
short count; |
for (count = 1; count <= kBroughtToFront; count++) |
EventAvail(everyEvent, &event); |
} |
/*****************************************************************************/ |
/* Given the button control handle, this will cause the button to look as if it |
** has been clicked in. This is nice to do for the user if they type return or |
** enter to select the default item. */ |
#pragma segment UtilMain |
void SelectButton(ControlHandle button) |
{ |
unsigned long finalTicks; |
HiliteControl(button, kSelect); |
Delay(kDelayTime, &finalTicks); |
HiliteControl(button, kDeselect); |
} |
/*****************************************************************************/ |
/* Handy function for setting the value of a radio button. Given a dialog |
** pointer, and item number, and a state, this function will take care of the |
** rest. */ |
#pragma segment UtilMain |
void SetCheckOrRadioButton(DialogPtr dlgPtr, short itemNo, short state) |
{ |
short iKind; |
Handle iHandle; |
Rect iRect; |
GetDialogItem(dlgPtr, itemNo, &iKind, &iHandle, &iRect); |
SetControlValue((ControlHandle) iHandle, state); |
} |
/*****************************************************************************/ |
/* This algorithm for staggering windows does quite a good job. It also is |
** quite gnarly. Here's the deal: |
** There are pre-designated positions that we will try when positioning a |
** window. These slots will be tried from the upper-left corner towards the |
** lower-right corner. If there are other windows in that slot, then we will |
** consider that slot taken, and proceed to the next slot. A slot is |
** determined to be taken by checking a point with a slop area. This slop |
** area is diamond-shaped, not simply rectangular. If there is no other |
** visible window with an upper-left corner within the slopt diamond, then |
** we are allowed to position our window there. |
** The above rule holds true unless this forces the window to be partly |
** off the screen. If the window ends up partly off the screen, then we try |
** a new diagonal just below the first diagonal we tried. We keep trying |
** lower and lower diagonals until we find a spot for the window, or the |
** diagonal doesn't fit on the screen at all. If the diagonal doesn't fit, |
** then we try diagonals to the right of the first diagonal. If even this |
** doesn't work, then we give up and put the window in the original spot |
** we tried. */ |
#pragma segment UtilMain |
Rect StaggerWindow(WindowPtr window, WindowPtr relatedWindow) |
{ |
WindowPtr whichDevice, staggerFromWindow; |
Rect deviceRect, oldWindowRect, newWindowRect, slot1; |
Rect testRect, contentRect, staggerFromRect; |
Point delta, absdelta; |
Boolean contained, vertTry; |
short diamondSize, diagNum, tryNum; |
if (!(whichDevice = relatedWindow)) whichDevice = window; |
/* If we have a window to stagger from, use the device for that window, |
** else use the device for the window that is getting staggered. */ |
deviceRect = GetWindowDeviceRectNMB(whichDevice); |
/* We now have the rect of the device we want to stagger within. */ |
oldWindowRect = GetWindowStructureRect(window); |
newWindowRect.top = deviceRect.top + kStartPtV; |
newWindowRect.left = deviceRect.left + kStartPtH; |
newWindowRect.bottom = newWindowRect.top + oldWindowRect.bottom - oldWindowRect.top; |
newWindowRect.right = newWindowRect.left + oldWindowRect.right - oldWindowRect.left; |
/* We now have a new rect for the first window position slot. */ |
slot1 = newWindowRect; |
/* We keep this slot in case we find no acceptable slots. If we |
** don't find an acceptable one, we will use this one anyway. */ |
diamondSize = (kStaggerH < kStaggerV) ? kStaggerH : kStaggerV; |
for (diagNum = 0, vertTry = true;;) { |
for (tryNum = 0;; ++tryNum) { |
SectRect(&newWindowRect, &deviceRect, &testRect); |
if (!(contained = EqualRect(&newWindowRect, &testRect))) break; |
/* Break if the slot we are testing went off the device. */ |
for (staggerFromWindow = FrontWindow(); |
staggerFromWindow; |
staggerFromWindow = |
(WindowPtr)((WindowPeek)staggerFromWindow)->nextWindow |
) { |
if (!((WindowPeek)staggerFromWindow)->visible) continue; |
/* This window is invisible. Staggering from an invisible |
** window is going to confuse the user, so don't do it. */ |
testRect = GetWindowDeviceRectNMB(staggerFromWindow); |
if (!EqualRect(&testRect, &deviceRect)) continue; |
/* This window doesn't belong to the device we are trying to |
** stagger on, so skip it and go to the next window. */ |
staggerFromRect = GetWindowStructureRect(staggerFromWindow); |
delta.v = staggerFromRect.top - newWindowRect.top; |
delta.h = staggerFromRect.left - newWindowRect.left; |
if ((absdelta.v = delta.v) < 0) absdelta.v = -delta.v; |
if ((absdelta.h = delta.h) < 0) absdelta.h = -delta.h; |
if ((absdelta.h + absdelta.v) < diamondSize) { |
if ((delta.h + delta.v) > 0) |
OffsetRect(&newWindowRect, delta.h, delta.v); |
/* If the window that took our slot is closer to |
** the lower-right corner than we are, then use |
** this window's location as the basis for the |
** slots from now on. This will align new windows |
** with previous windows that are not gridded to |
** the default slot positions. The check for > 0 |
** is necessary to prevent bouncing between two |
** existing windows. This check guarantees that |
** we are progressing with the evaluation. */ |
break; |
/* Break because this slot is already used. */ |
} |
} |
if (!staggerFromWindow) break; |
/* If the window pointer is NULL, then we tried all the windows |
** and none of them occupied this slot. This means that the |
** slot is available for the new window. */ |
OffsetRect(&newWindowRect, kStaggerH, kStaggerV); |
/* Since this slot was taken, try the next slot and go through |
** the window list again. */ |
} |
if (contained) break; |
newWindowRect = slot1; |
if (!tryNum) { |
if (!vertTry) break; /* Nothing works. No spots at all. */ |
vertTry = false; /* Try across for the next pass. */ |
diagNum = 0; |
} |
++diagNum; |
if (vertTry) OffsetRect(&newWindowRect, 0, diagNum * kStaggerV); |
else OffsetRect(&newWindowRect, diagNum * kStaggerH, 0); |
} |
contentRect = GetWindowContentRect(window); |
/* Get where the window is now. */ |
OffsetRect(&contentRect, newWindowRect.left - oldWindowRect.left, |
newWindowRect.top - oldWindowRect.top); |
/* Calculate the new content rect. */ |
MoveWindow(window, contentRect.left, contentRect.top, false); |
/* Move the window to the new location. */ |
return(contentRect); |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
void StandardAbout(short appNameStringID) |
{ |
StringHandle apNameHndl; |
VersRecHndl curVersion; |
Str255 apName; |
Str255 verNum = "\p????"; |
Ptr verNumLocation; |
OSErr err; |
if (!gUtilitiesInited) /* Make sure we were initialized */ |
InitUtilities(); |
apNameHndl = (StringHandle)NULL; |
if (appNameStringID != kUseRealAppName) { |
if (appNameStringID != kUseCreatorString) |
apNameHndl = GetString(appNameStringID); |
if (!apNameHndl) |
apNameHndl = (StringHandle) GetAppResource(gSignature, 0, &err); |
} |
if ((!apNameHndl) || (appNameStringID == kUseRealAppName)) |
PStrCopy(apName, gAppName); |
else |
PStrCopy(apName, *apNameHndl); |
curVersion = (VersRecHndl) GetAppResource('vers', 1, &err); |
if (curVersion) { |
verNumLocation = (Ptr) ((long)(*curVersion)->shortVersion |
+ (long)*(*curVersion)->shortVersion + 1); |
PStrCopy(verNum, verNumLocation); |
} |
ParamText(apName, verNum, "\p", "\p"); |
CenteredAlert(rStdAboutAlert, NULL); |
} |
/*****************************************************************************/ |
#pragma segment UtilInit |
void StandardInitialization(short callsToMoreMasters) |
{ |
InitToolBox(); |
while (callsToMoreMasters--) |
MoreMasters(); |
PullApplicationToFront(); |
InitUtilities(); |
} |
/*****************************************************************************/ |
#pragma segment UtilInit |
void StandardMenuSetup(short MBARID, short AppleMenuID) |
{ |
Handle menuBar = GetNewMBar(MBARID); /* read menus into menu bar */ |
if (!menuBar) |
DeathAlert(rUtilStrings, eNoMenuBar); |
SetMenuBar(menuBar); /* install menus */ |
DisposeHandle(menuBar); |
AppendResMenu(GetMenuHandle(AppleMenuID), 'DRVR'); /* add DA names to Apple menu */ |
DrawMenuBar(); |
} |
/*****************************************************************************/ |
#pragma segment UtilMain |
void ToggleCheck(DialogPtr dlgPtr, short chkItem) |
{ |
short iKind; |
Handle iHandle; |
Rect iRect; |
GetDialogItem (dlgPtr, chkItem, &iKind, &iHandle, &iRect); |
SetControlValue((ControlHandle) iHandle, !GetControlValue((ControlHandle)iHandle)); |
} |
/*****************************************************************************/ |
/* Check to see if a given trap is implemented. This is only used by the |
** Initialize function in this program, so we put it in the |
** Initialize segment. */ |
#pragma segment UtilInit |
Boolean TrapExists(short theTrap) |
{ |
TrapType theTrapType; |
theTrapType = GetTrapType(theTrap); |
if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps())) |
theTrap = _Unimplemented; |
return (NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, |
theTrapType)); |
} |
/*****************************************************************************/ |
/* Zoom the window to the size appropriate for the device that contains the |
** most of the window. An additional feature is that you can state the |
** maximum that a window should be zoomed, either horizontally or vertically. |
** If you pass in a maximum of 0 for the zoom for either direction, then that |
** direction will be zoomed to fit the device. */ |
#pragma segment UtilMain |
void ZoomToWindowDevice(WindowPtr window, short maxWidth, short maxHeight, |
short zoomDir, Boolean front) |
{ |
GrafPtr oldPort; |
Rect contentRect, structureRect, deviceRect, newRect; |
short width, height, dx, dy; |
GetPort(&oldPort); |
SetPort(window); |
EraseRect(&window->portRect); /* Recommended for cosmetic reasons. */ |
/* If there is the possibility of multiple gDevices, then we must check them to |
** make sure we are zooming onto the right display device when zooming out. */ |
if ((zoomDir == inZoomOut) && (gQDVersion > kQDOriginal)) { |
contentRect = GetWindowContentRect(window); |
structureRect = GetWindowStructureRect(window); |
deviceRect = GetWindowDeviceRectNMB(window); |
deviceRect.left += (contentRect.left - structureRect.left + 2); |
deviceRect.top += (contentRect.top - structureRect.top + 2); |
deviceRect.right -= (structureRect.right - contentRect.right + 2); |
deviceRect.bottom -= (structureRect.bottom - contentRect.bottom + 2); |
newRect = deviceRect; |
if (maxWidth) |
if ((width = deviceRect.right - deviceRect.left) > maxWidth) |
newRect.right = (newRect.left = contentRect.left) + maxWidth; |
if (maxHeight) |
if ((height = deviceRect.bottom - deviceRect.top) > maxHeight) |
newRect.bottom = (newRect.top = contentRect.top) + maxHeight; |
if ((dx = deviceRect.left - newRect.left) < 0) |
if ((dx = deviceRect.right - newRect.right) > 0) |
dx = 0; |
if ((dy = deviceRect.top - newRect.top) < 0) |
if ((dy = deviceRect.bottom - newRect.bottom) > 0) |
dy = 0; |
OffsetRect(&newRect, dx, dy); |
(*(WStateDataHandle)(((WindowPeek)window)->dataHandle))->stdState = newRect; |
/* Set up the WStateData record for this window. */ |
} |
ZoomWindow(window, zoomDir, front); |
SetPort(oldPort); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-17