home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1995 January
/
macformat-020.iso
/
Shareware City
/
Developers
/
apps.to.go
/
DTS.Lib
/
GWLayers.c
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1994-05-17
|
34.1 KB
|
1,266 lines
|
[
TEXT/MPS
]
/*
** Apple Macintosh Developer Technical Support
**
** Program: DTS.Lib
** File: GWLayers.c
** Written by: Eric Soldan and Forrest Tanaka
**
** Copyright © 1989-1993 Apple Computer, Inc.
** All rights reserved.
*/
/* You may incorporate this sample code into your applications without
** restriction, though the sample code has been provided "AS IS" and the
** responsibility for its operation is 100% yours. However, what you are
** not permitted to do is to redistribute the source as "DSC Sample 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 Code, but that you've made changes. */
/* This is an implementation of off-screen GWorld handling. This particular
** implementation uses GWorlds in a hierarchical manner, with each layer in
** the hierarchy having its own tasks to handle at its specific level.
** The advantage to this is that it can conform to many applications. Each
** application may need a different number of layers, and each layer may
** need to perform a different kind of operation. By having an unlimited
** number of layers, and by having each layer handle its own application
** specific tasks, off-screen GWorld handling can be standardized.
**
** A common use for off-screen stuff is to move an object around in a
** window over a background. To accomplish this, we need 3 layers.
** These are:
**
** 1) The window layer. This layer transfers a rectangle of pixels from
** the middle layer into the window layer, once the middle layer is ready.
** The rectangle transferred would be large enough to cover the old
** location and the new location, thus moving the piece without having
** to turn it off in the old location as a separate step. This gives a
** very smooth appearance when moving an object.
** 2) A middle layer that is used to apply the object being moved to the
** background plus removing the object from the old location. Once these
** two tasks are done, the off-screen work area is ready to be transferred
** to the window layer.
** 3) A background image against which the object moves. This is used to
** restore the middle layer at the location where the object being moved
** was last at.
**
** The top layer object relates to the window, and therefore we don't need an
** off-screen GWorld for it. A call to create this layer might look like the below:
**
** err = NewLayer(&windowLayer, Layer object handle is returned here.
** nil, Top layer, so there is no above layer.
** nil, Uses default layer procedure.
** window, Window used by the layer object.
** 0, Desired depth (0 for screen depth).
** 0); Custom layer init data, if any.
**
** If NewLayer succeeds, the layer object handle is returned in windowLayer.
** If it fails, nil is returned in windowLayer, plus an error is returned.
** If windowLayer is successfully created, then we can proceed to create the
** next two layers. In the case below, we are creating an off-screen layer
** that has a pixmap the same size and depth as windowLayer. If this is
** what we want for the middle layer, then we can again use the default
** LayerProc for the kLayerInit message. All we need to do is to call the
** default layerProc with a kLayerInit message. We want the standard
** action for initialization, but we want our own update action. That's
** why we have a custom layerProc for the middle layer. The call would look
** something like the below:
**
** err = NewLayer(&middleLayer, Layer object handle is returned here.
** windowLayer, Layer above this layer.
** MiddleLayerProc, Custom layerProc.
** nil, Create a pixmap for layer.
** 0, Pixmap created as same size/depth as above layer.
** 0);
**
** The background layer would be created similarly. When you are finished with
** the layers, you can dispose of them one at a time with DisposeLayer, or you
** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
**
** Inserting a layer is done by position, and not by which layer it goes above
** or below. The reason for this is that the layer positions are most likely
** absolute, and therefore it is better to indicate their position with an
** absolute number instead of always relating it to some other layer. If it
** is necessary to insert a layer specifically above or below some other layer,
** it would be done as follows:
** InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
** InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
**
** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
*/
/*****************************************************************************/
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
#ifndef __GWLAYERS__
#include "GWLayers.h"
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __STRINGUTILS__
#include <StringUtils.h>
#endif
#ifndef __TRAPS__
#include <Traps.h>
#endif
#ifndef __WINDOWS__
#include <Windows.h>
#endif
#define kQDOriginal 0
static OSErr DefaultLayerInit(LayerObj theLayer);
static OSErr DefaultLayerUpdate(LayerObj theLayer);
static OSErr DefaultLayerDispose(LayerObj theLayer);
static OSErr MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
static void KillLayerWorld(LayerObj theLayer);
static void SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
static void SmartSetGWorld(CGrafPtr port, GDHandle gdh);
static short GetQDVersion(void);
static short GetSystemVersion(void);
static short NumToolboxTraps(void);
static Boolean TrapExists(short theTrap);
static TrapType GetTrapType(short theTrap);
/*****************************************************************************/
/*****************************************************************************/
#pragma segment GWLayers
OSErr NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
GrafPtr basePort, short depth, unsigned long theData)
{
OSErr err;
LayerRecPtr lptr;
CGrafPtr scratchPort;
GDHandle baseGDevice;
*newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
err = MemError();
if (err) return(err);
/* If not enough memory for layer object, return nil and error. */
SmartGetGWorld(&scratchPort, &baseGDevice);
if (!theProc)
theProc = DefaultLayerProc;
/* If layer proc is nil, then they want the default behavior. */
lptr = **newLayer;
lptr->layerPort = basePort;
lptr->layerGDevice = baseGDevice;
lptr->layerDepth = depth;
lptr->xferMode = srcCopy;
lptr->layerProc = theProc;
lptr->layerData = theData;
/* Layer object is now initialized, except for layers that need a GWorld
** created. This will occur when the layer proc is called with an
** initialization message. (All fields not explicitly set are 0.) */
InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
/* Connect the layer to the layer chain. The default initialization
** behavior may need this, as it may create a GWorld of the same size
** as the above layer. If it isn't connected to the layer chain, then
** there is no above layer. */
err = (*theProc)(*newLayer, kLayerInit);
if (err) {
DisposeLayer(*newLayer);
*newLayer = nil;
/* There wasn't enough memory to create the off-screen GWorld, so
** dispose of the layer object. Since we failed, we need to return
** nil and the error. */
}
return(err);
}
/*****************************************************************************/
#pragma segment GWLayers
void DetachLayer(LayerObj theLayer)
{
LayerObj aboveLayer, belowLayer;
if (theLayer) {
aboveLayer = (*theLayer)->aboveLayer;
belowLayer = (*theLayer)->belowLayer;
if (aboveLayer)
(*aboveLayer)->belowLayer = belowLayer;
if (belowLayer)
(*belowLayer)->aboveLayer = aboveLayer;
(*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
}
}
/*****************************************************************************/
#pragma segment GWLayers
OSErr DisposeLayer(LayerObj theLayer)
{
OSErr err;
err = noErr;
if (theLayer) {
err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
DetachLayer(theLayer);
DisposeHandle((Handle)theLayer);
}
return(err);
}
/*****************************************************************************/
#pragma segment GWLayers
OSErr DisposeThisAndBelowLayers(LayerObj theLayer)
{
OSErr err, err2;
err = noErr;
if (theLayer) {
err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
err = DisposeLayer(theLayer);
if (!err)
err = err2;
}
return(err);
}
/*****************************************************************************/
#pragma segment GWLayers
short GetLayerPosition(LayerObj theLayer)
{
short pos;
if (!theLayer) return(0);
for (pos = 0; (theLayer = (*theLayer)->aboveLayer) != nil; ++pos) {};
return(pos);
}
/*****************************************************************************/
#pragma segment GWLayers
LayerObj GetTopLayer(LayerObj theLayer)
{
for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer) {};
return(theLayer);
}
/*****************************************************************************/
#pragma segment GWLayers
LayerObj GetBottomLayer(LayerObj theLayer)
{
for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer) {};
return(theLayer);
}
/*****************************************************************************/
#pragma segment GWLayers
void InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
{
LayerObj aboveLayer, belowLayer;
short i;
if (theLayer) {
if (theLayer == referenceLayer) {
/* If theLayer layer is the same as referenceLayer... */
belowLayer = (*theLayer)->belowLayer;
if (belowLayer)
referenceLayer = belowLayer;
aboveLayer = (*theLayer)->aboveLayer;
if (aboveLayer)
referenceLayer = aboveLayer;
/* Try to make the reference layer not the same as theLayer.
** If it is the same as theLayer, then when theLayer is
** removed from the old hierarchy, we lose the ability to re-add
** it to the hierarchy in a new location. */
}
DetachLayer(theLayer);
/* Remove layer from its old hierarchy, if any. */
if (!referenceLayer) return;
/* If there isn't a valid alternative reference, then theLayer
** IS the hierarchy and no action is taken. */
aboveLayer = nil;
belowLayer = GetTopLayer(referenceLayer);
/* aboveLayer now nil. belowLayer now is top layer. These
** are the correct values if the layer being added is to be
** the new top layer. This will be the case if pos is 0.
** We now walk the linked list pos number of times to get the
** correct position. We also terminate if we reach the end
** of the linked list, no matter what pos is. This will allow
** values of pos that are too big to insert the layer at the
** end of the linked list. */
for (i = 0; ((belowLayer) && (i != pos)); ++i) {
aboveLayer = belowLayer;
belowLayer = (*belowLayer)->belowLayer;
}
/* We now have correct values for aboveLayer and belowLayer. Note that
** these values may be nil, which would be correct. */
(*theLayer)->aboveLayer = aboveLayer;
if (aboveLayer)
(*aboveLayer)->belowLayer = theLayer;
(*theLayer)->belowLayer = belowLayer;
if (belowLayer)
(*belowLayer)->aboveLayer = theLayer;
}
}
/*****************************************************************************/
/*****************************************************************************/
#pragma segment GWLayers
OSErr UpdateLayer(LayerObj theLayer)
{
OSErr err;
err = noErr;
if (theLayer) {
err = UpdateLayer((*theLayer)->belowLayer);
/* Handle the updates from the bottom up. */
if (!err)
err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
/* Chain possible errors through each level of recursion. */
}
return(err);
}
/*****************************************************************************/
#pragma segment GWLayers
Rect GetEffectiveSrcRect(LayerObj theLayer)
{
Rect srcRect;
if (!theLayer)
SetRect(&srcRect, 0, 0, 0, 0);
else {
srcRect = (*theLayer)->srcRect;
if (EmptyRect(&srcRect))
srcRect = ((*theLayer)->layerPort)->portRect;
}
return(srcRect);
}
/*****************************************************************************/
#pragma segment GWLayers
Rect GetEffectiveDstRect(LayerObj theLayer)
{
Rect dstRect;
if (!theLayer)
SetRect(&dstRect, 0, 0, 0, 0);
else {
dstRect = (*theLayer)->dstRect;
if (EmptyRect(&dstRect))
dstRect = ((*theLayer)->layerPort)->portRect;
}
return(dstRect);
}
/*****************************************************************************/
#pragma segment GWLayers
OSErr DefaultLayerProc(LayerObj theLayer, short message)
{
OSErr err;
err = noErr;
if (theLayer) {
switch (message) { /* Dispatch to the correct default behavior. */
case kLayerInit:
err = DefaultLayerInit(theLayer);
break;
case kLayerDispose:
err = DefaultLayerDispose(theLayer);
break;
case kLayerUpdate:
err = DefaultLayerUpdate(theLayer);
break;
default:
break;
}
}
return(err);
}
/*****************************************************************************/
#pragma segment GWLayers
Rect UpdateUpdateRects(LayerObj theLayer)
{
Rect lastUpdate, thisUpdate, dstRect;
if (theLayer) {
lastUpdate = (*theLayer)->lastUpdate;
(*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
if ((*theLayer)->includeLastUpdate) {
(*theLayer)->includeLastUpdate = false;
if (EmptyRect(&lastUpdate))
lastUpdate = thisUpdate;
if (EmptyRect(&thisUpdate))
thisUpdate = lastUpdate;
UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
/* We are going to update the last and current update rects.
** This will allow the appearance of movement for a foreground
** object. The old location is cleared, plus the new location
** is updated. */
dstRect = GetEffectiveDstRect(theLayer);
SectRect(&thisUpdate, &dstRect, &thisUpdate);
}
}
else SetRect(&thisUpdate, 0, 0, 0, 0);
return(thisUpdate);
}
/*****************************************************************************/
#pragma segment GWLayers
void InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
{
Rect thisUpdate, srcRect, dstRect;
LayerObj belowLayer;
short ow, oh;
long dw, dh, sw, sh;
if (theLayer) {
belowLayer = (*theLayer)->belowLayer;
dstRect = GetEffectiveDstRect(theLayer);
SectRect(&dstRect, &invalRect, &invalRect);
if (!EmptyRect(&invalRect)) { /* If there is something to invalidate... */
thisUpdate = (*theLayer)->thisUpdate; /* There may be a prior unhandled update... */
if (EmptyRect(&thisUpdate))
thisUpdate = invalRect; /* UnionRect doesn't */
UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate); /* like empty rects. */
if (belowLayer) {
/* If we have a below layer, then pass the update down. The effectiveSrcRct
** rect for the below layer may be a different size than the effectiveDstRct.
** If this is the case, we want to scale invalRect to invalidate a proportional
** area in the below layer. */
srcRect = GetEffectiveSrcRect(belowLayer);
dw = dstRect.right - dstRect.left; /* Calculate widths and heights for */
dh = dstRect.bottom - dstRect.top; /* srcRect and dstRect. */
sw = srcRect.right - srcRect.left;
sh = srcRect.bottom - srcRect.top;
OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
/* We want to align the upper-left corner of the srcRect and dstRect
** so that the scaling also aligns the invalRect into the correct
** place in the below layer's effectiveSrcRect. invalRect is now
** positioned relative to a dstRect with a upper-left corner of 0,0. */
if (dw != sw) { /* Width dstRect different than srcRect. */
ow = invalRect.right - invalRect.left;
invalRect.left = (short)((invalRect.left * sw) / dw);
invalRect.right = (short)((invalRect.right * sw) / dw);
if ((((invalRect.right - invalRect.left) * dw) / sw) != ow)
++invalRect.right;
/* We can possibly lose a fraction of a pixel on the right edge when
** scaling the invalRect. It won't hurt if we inval just a bit too
** much, whereas invalidating too little is a bad thing. */
}
if (dh != sh) { /* Height dstRect different than srcRect. */
oh = invalRect.bottom - invalRect.top;
invalRect.top = (short)((invalRect.top * sh) / dh);
invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
++invalRect.bottom;
}
OffsetRect(&invalRect, srcRect.left, srcRect.top);
/* Displace the new invalRect correctly relative to the srcRect. */
}
}
if (includeLastUpdate)
(*theLayer)->includeLastUpdate = true;
/* If requested to update last position as well, flag it. */
InvalLayer(belowLayer, invalRect, includeLastUpdate);
/* Invalidate the below layer with the new (possibly scaled) invalRect. */
}
}
/*****************************************************************************/
#pragma segment GWLayers
void SetLayerWorld(LayerObj theLayer)
{
CGrafPtr keepPort;
GDHandle keepGDevice;
/* This is a convenient call for setting a GWorld, while remembering what
** the previous GWorld was. This should be balanced with a call to
** ResetLayerWorld. A count of how many times this is called is kept
** so that the old GWorld is cached only if SetLayerWorld is currently
** in balance with ResetLayerWorld. This keeps the oldest kept GWorld
** from being overwritten by subsequent calls. */
if (theLayer) {
if (!(*theLayer)->cachedCount++) {
SmartGetGWorld(&keepPort, &keepGDevice);
(*theLayer)->cachedPort = keepPort;
(*theLayer)->cachedGDevice = keepGDevice;
}
SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
LockLayerWorld(theLayer);
}
}
/*****************************************************************************/
#pragma segment GWLayers
void ResetLayerWorld(LayerObj theLayer)
{
/* This is used to undo a call to SetLayerWorld. Calls to ResetLayerWorld
** should be balanced with previous calls to SetLayerWorld. */
if (theLayer) {
UnlockLayerWorld(theLayer);
if (!--(*theLayer)->cachedCount)
SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
}
}
/*****************************************************************************/
#pragma segment GWLayers
void LockLayerWorld(LayerObj theLayer)
{
Handle bitmap;
/* This is a convenient way to lock down the pixels for a layer's GWorld.
** A locked count is kept to make sure that the GWorld is locked only the
** first time this is called. Calls to LockLayerWorld will most likely
** be balanced by calls to UnlockLayerWorld, but not necessarily. It may
** be desirable to keep a GWorld call locked. In this case, right after
** creating the layer (and indirectly its GWorld), call LockLayerWorld.
** This will initially lock it. Subsequent calls would be balanced, and
** therefore there will always be one more LockLayerWorld call than
** UnlockLayerWorld calls. This will keep it locked. */
if (theLayer) {
if ((*theLayer)->layerOwnsPort) {
if (!(*theLayer)->lockedCount++) {
bitmap = (*theLayer)->layerBitmap;
if (bitmap) {
HLock(bitmap);
(*theLayer)->layerPort->portBits.baseAddr = *bitmap;
}
else
LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
}
}
}
}
/*****************************************************************************/
#pragma segment GWLayers
void UnlockLayerWorld(LayerObj theLayer)
{
/* This undoes what LockLayerWorld does. Calls to UnlockLayerWorld will
** generally be balanced with calls to LockLayerWorld. */
if (theLayer) {
if ((*theLayer)->layerOwnsPort) {
if (!--(*theLayer)->lockedCount) {
if ((*theLayer)->layerBitmap)
HUnlock((*theLayer)->layerBitmap);
else
UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
}
}
}
}
/*****************************************************************************/
#pragma segment GWLayers
RgnHandle ScreenDepthRegion(short depth)
{
RgnHandle retRgn, tmpRgn;
GDHandle device;
PixMapHandle pmap;
Rect rct;
GrafPtr mainPort;
retRgn = NewRgn();
if (GetQDVersion() == kQDOriginal) {
if (depth == 1) {
GetWMgrPort(&mainPort);
rct = mainPort->portRect;
RectRgn(retRgn, &rct);
}
}
else {
tmpRgn = NewRgn();
for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
if (
(TestDeviceAttribute(device, screenDevice)) &&
(TestDeviceAttribute(device, screenActive))
) {
pmap = (*device)->gdPMap;
if ((*pmap)->pixelSize >= depth) {
rct = (*device)->gdRect;
RectRgn(tmpRgn, &rct);
UnionRgn(retRgn, tmpRgn, retRgn);
}
}
}
DisposeRgn(tmpRgn);
}
return(retRgn);
}
/*****************************************************************************/
#pragma segment GWLayers
CIconHandle ReadCIcon(short iconID)
{
Handle hndl;
if (TrapExists(_PlotCIcon))
return(GetCIcon(iconID));
hndl = GetResource('cicn', iconID);
DetachResource(hndl);
return((CIconHandle)hndl);
}
/*****************************************************************************/
#pragma segment GWLayers
void KillCIcon(CIconHandle icon)
{
if (!icon) return;
if (TrapExists(_PlotCIcon))
DisposeCIcon(icon);
else
DisposeHandle((Handle)icon);
}
/*****************************************************************************/
#pragma segment GWLayers
void DrawCIcon(CIconHandle icon, Rect destRect)
{
WindowPtr curPort;
short depth;
if (!icon) return;
if (TrapExists(_PlotCIcon)) {
depth = 8;
if (GetSystemVersion() < 0x0700) {
depth = 1;
GetPort(&curPort);
if (curPort->portBits.rowBytes & 0x8000)
depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
}
}
else depth = 1;
if (depth > 1)
PlotCIcon(&destRect, icon);
else
DrawCIconByDepth(icon, destRect, 1, true);
}
/*****************************************************************************/
#pragma segment GWLayers
void DrawCIconNoMask(CIconHandle icon, Rect destRect)
{
Rect iconRect;
char oldMask[128], *mptr;
short maskSize, i;
if (!icon) return;
mptr = (Ptr)(*icon)->iconMaskData;
iconRect = (*icon)->iconPMap.bounds;
maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
for (i = 0; i < maskSize; ++i) {
oldMask[i] = mptr[i];
mptr[i] = 0xFF;
}
DrawCIcon(icon, destRect);
mptr = (Ptr)(*icon)->iconMaskData;
for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
}
/*****************************************************************************/
#pragma segment GWLayers
void DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
{
GrafPtr curPort;
char savedIconState;
char savedDataState;
short offset;
BitMapPtr bmap;
Rect iconRect;
if (!icon) return;
GetPort(&curPort);
if (!depth) {
if (!(curPort->portBits.rowBytes & 0x8000))
depth = 1;
else
depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
}
savedIconState = HGetState((Handle)icon); /* Lock down things. */
HLock((Handle)icon);
if (depth > 1) {
savedDataState = HGetState((*icon)->iconData);
HLock((*icon)->iconData);
(*icon)->iconPMap.baseAddr = *((*icon)->iconData);
/* Point the icon's pixMap at the color icon data. */
}
iconRect = (*icon)->iconPMap.bounds;
/* Find out the dimensions of the icon. */
(*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
/* Point the mask's bitMap at the mask data. */
offset = iconRect.bottom - iconRect.top;
offset *= (*icon)->iconMask.rowBytes;
(*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
/* Point the icon's bitMap at the b/w icon data. */
bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
if (useMask)
CopyMask(bmap, &((*icon)->iconMask), &curPort->portBits, &iconRect, &iconRect, &destRect);
else
CopyBits(bmap, &curPort->portBits, &iconRect, &destRect, srcCopy, nil);
HSetState((Handle)icon, savedIconState); /* Unlock things. */
if (depth > 1)
HSetState((*icon)->iconData, savedDataState);
}
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
#pragma segment GWLayers
static OSErr DefaultLayerInit(LayerObj theLayer)
{
LayerObj aboveLayer;
GWorldPtr layerWorld; /* GWorld for this layer. */
Rect parentRect; /* Rectangle of parent in global coordinates. */
GrafPtr parentPort; /* Parent layer's GrafPort. */
GDHandle parentGDevice; /* Parent layer's GDevice. */
CGrafPtr keepPort; /* Saved GrafPort. */
GDHandle keepGDevice; /* Saved GDevice. */
Point org;
OSErr err;
short depth;
err = noErr;
if (theLayer) {
if (!(*theLayer)->layerPort) {
aboveLayer = (*theLayer)->aboveLayer;
if (aboveLayer) {
/* The default behavior is to create a GWorld the same size
** as the above layer, if there is one. If there isn't an above
** layer and we were expected to create a GWorld, we have problems.
** This situation can't be resolved and is handled as a paramErr. */
if (!((*theLayer)->layerDepth))
(*theLayer)->layerDepth = (*aboveLayer)->layerDepth;
SmartGetGWorld(&keepPort, &keepGDevice); /* Keep the GWorld. */
parentPort = (*aboveLayer)->layerPort;
parentGDevice = (*aboveLayer)->layerGDevice;
/* Grab the parent layer's GrafPort and GDevice. */
SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
parentRect = GetEffectiveDstRect(aboveLayer);
/* The default behavior is to use the portRect of the above
** port. This behavior can be overridden if desired by setting
** dstRect. dstRect is initialized to be empty, but if
** it is specifically set, then this layer should map into
** just the dstRect and not the portRect. This is useful if
** the off-screen image is to be displayed in only a portion
** of a window. */
org.h = parentRect.left;
org.v = parentRect.top;
LocalToGlobal(((Point *)&parentRect) + 0);
LocalToGlobal(((Point *)&parentRect) + 1);
/* Put the parent layer's destination rect in global coordinates. */
if (GetQDVersion())
err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
/* Create the GWorld for this layer. It will be created with the
** requested depth. If the requested depth is 0, then it will be
** created with a depth great enough for the deepest monitor the
** parentRect intersects. */
else
err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
/* Create a bitmap for those systems without GWorlds. */
if (err == noErr) {
(*theLayer)->layerOwnsPort = true;
SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
/* Save the new GWorld in the layer object. */
SetOrigin(org.h, org.v);
/* Set the origin so that this GWorld maps directly into the
** area to be copied into (dstRect or portRect) for the
** above layer. */
if (!((*theLayer)->layerDepth)) {
if (((GrafPtr)layerWorld)->portBits.rowBytes & 0x8000)
depth = (*(((CGrafPtr)layerWorld)->portPixMap))->pixelSize;
else
depth = 1;
(*theLayer)->layerDepth = depth;
}
}
SmartSetGWorld(keepPort, keepGDevice); /* Restore the kept GWorld. */
}
else {
err = paramErr;
/* We were expected to create an off-screen GWorld of the
** same size as the above layer, but we didn't have an above
** layer. This is an error. The parameters passed to NewLayer
** were inappropriate for the situation, so return a paramErr. */
}
}
}
return(err);
}
/*****************************************************************************/
#pragma segment GWLayers
static OSErr DefaultLayerUpdate(LayerObj theLayer)
{
LayerObj belowLayer;
GrafPtr belowPort, thisPort;
GDHandle thisGDevice;
CGrafPtr keepPort;
GDHandle keepGDevice;
Rect thisUpdate, belowRect, thisRect;
short xfer;
RgnHandle rgn;
/* The default update behavior is to copy the area to be updated from the
** below layer into the indicated layer. We only need to update layer if
** there is a below layer. The bottom-most layer update doesn't do anything.
** As a default, the bottom-most layer is considered background and does not
** get updated. */
if (theLayer) {
belowLayer = (*theLayer)->belowLayer;
if (belowLayer) {
/* Get this layer's GWorld and below layer's port. */
thisPort = (*theLayer)->layerPort;
thisGDevice = (*theLayer)->layerGDevice;
belowPort = (*belowLayer)->layerPort;
/* Save current GWorld and set the parent's GWorld. */
SmartGetGWorld(&keepPort, &keepGDevice);
SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
thisUpdate = UpdateUpdateRects(theLayer);
rgn = NewRgn();
RectRgn(rgn, &thisUpdate);
belowRect = GetEffectiveSrcRect(belowLayer);
thisRect = GetEffectiveDstRect(theLayer);
/* As a default behavior, we CopyBits the below layer into this layer. */
LockLayerWorld(belowLayer);
LockLayerWorld(theLayer);
xfer = (*theLayer)->xferMode;
CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
UnlockLayerWorld(theLayer);
UnlockLayerWorld(belowLayer);
DisposeRgn(rgn);
SmartSetGWorld(keepPort, keepGDevice); /* Restore to the kept GWorld. */
}
}
return(noErr);
}
/*****************************************************************************/
#pragma segment GWLayers
static OSErr DefaultLayerDispose(LayerObj theLayer)
{
GWorldPtr theWorld;
if (theLayer) {
if ((*theLayer)->layerOwnsPort) {
theWorld = (GWorldPtr)(*theLayer)->layerPort;
if (theWorld) {
if ((*theLayer)->layerBitmap)
KillLayerWorld(theLayer);
else
DisposeGWorld(theWorld);
}
}
}
return(noErr);
}
/*****************************************************************************/
#pragma segment GWLayers
static OSErr MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
{
GrafPtr oldPort;
GrafPtr newPort;
Handle bitmap;
OSErr err;
OffsetRect(&bnds, -bnds.left, -bnds.top); /* Make sure upper-left is 0,0. */
GetPort(&oldPort); /* Need this to restore the port after OpenPort. */
newPort = (GrafPtr)NewPtr(sizeof(GrafPort)); /* Allocate the grafPort. */
err = MemError();
if (err)
return(err); /* Failed to allocate the off-screen port. */
/* The call to OpenPort does the following:
** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
** 2) sets portBits to screenBits
** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
** 4) side effect: does a SetPort(&offScreen) */
OpenPort(newPort);
SetPort(oldPort);
/* Now make bitmap the size of the bounds that caller supplied. */
newPort->portRect = bnds;
newPort->portBits.bounds = bnds;
RectRgn(newPort->visRgn, &bnds);
SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
/* Avoid wide-open clipRgn, to be safe. */
/* rowBytes is size of row, it must be rounded up to an even number of bytes. */
newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
err = MemError();
if (err) {
ClosePort(newPort); /* Dump the visRgn and clipRgn. */
DisposePtr((Ptr)newPort); /* Dump the GrafPort. */
return(err);
}
(*theLayer)->layerBitmap = bitmap;
*layerWorld = (GWorldPtr)newPort;
return(noErr);
}
/*****************************************************************************/
#pragma segment GWLayers
static void KillLayerWorld(LayerObj theLayer)
{
DisposeHandle((*theLayer)->layerBitmap);
(*theLayer)->layerBitmap = nil;
ClosePort((*theLayer)->layerPort);
DisposePtr((Ptr)(*theLayer)->layerPort);
(*theLayer)->layerPort = nil;
}
/*****************************************************************************/
#pragma segment GWLayers
static void SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
{
if (GetQDVersion())
GetGWorld(port, gdh);
else {
*gdh = nil;
GetPort((GrafPtr *)port);
}
}
/*****************************************************************************/
#pragma segment GWLayers
static void SmartSetGWorld(CGrafPtr port, GDHandle gdh)
{
if (GetQDVersion())
SetGWorld(port, gdh);
else
SetPort((GrafPtr)port);
}
/*****************************************************************************/
#pragma segment GWLayers
static short GetQDVersion()
{
static long gestaltResult = -1;
if (gestaltResult == -1) {
if (Gestalt(gestaltQuickdrawVersion, &gestaltResult))
gestaltResult = 0;
}
return((gestaltResult >> 8) & 0xFF);
}
/*****************************************************************************/
#pragma segment GWLayers
static short GetSystemVersion()
{
static long gestaltResult;
if (!gestaltResult) {
if (Gestalt(gestaltSystemVersion, &gestaltResult))
gestaltResult = 0;
}
return(gestaltResult);
}
/*****************************************************************************/
#pragma segment GWLayers
static Boolean TrapExists(short theTrap)
{
TrapType theTrapType;
theTrapType = GetTrapType(theTrap);
if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
theTrap = _Unimplemented;
return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
}
/*****************************************************************************/
#pragma segment GWLayers
static short NumToolboxTraps(void)
{
if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
return(0x200);
else
return(0x400);
}
/*****************************************************************************/
#pragma segment GWLayers
static 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);
}