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:
Text File  |  1994-05-17  |  34.1 KB  |  1,266 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        GWLayers.c
  6. ** Written by:  Eric Soldan and Forrest Tanaka
  7. **
  8. ** Copyright © 1989-1993 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* You may incorporate this sample code into your applications without
  13. ** restriction, though the sample code has been provided "AS IS" and the
  14. ** responsibility for its operation is 100% yours.  However, what you are
  15. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  16. ** after having made changes. If you're going to re-distribute the source,
  17. ** we require that you make it clear in the source that the code was
  18. ** descended from Apple Sample Code, but that you've made changes. */
  19.  
  20. /* This is an implementation of off-screen GWorld handling.  This particular
  21. ** implementation uses GWorlds in a hierarchical manner, with each layer in
  22. ** the hierarchy having its own tasks to handle at its specific level.
  23. ** The advantage to this is that it can conform to many applications.  Each
  24. ** application may need a different number of layers, and each layer may
  25. ** need to perform a different kind of operation.  By having an unlimited
  26. ** number of layers, and by having each layer handle its own application
  27. ** specific tasks, off-screen GWorld handling can be standardized.
  28. **
  29. ** A common use for off-screen stuff is to move an object around in a 
  30. ** window over a background.  To accomplish this, we need 3 layers.
  31. ** These are:
  32. **
  33. ** 1) The window layer.  This layer transfers a rectangle of pixels from
  34. **    the middle layer into the window layer, once the middle layer is ready.
  35. **    The rectangle transferred would be large enough to cover the old
  36. **    location and the new location, thus moving the piece without having
  37. **    to turn it off in the old location as a separate step.  This gives a
  38. **    very smooth appearance when moving an object.
  39. ** 2) A middle layer that is used to apply the object being moved to the
  40. **    background plus removing the object from the old location.  Once these
  41. **    two tasks are done, the off-screen work area is ready to be transferred
  42. **    to the window layer.
  43. ** 3) A background image against which the object moves.  This is used to
  44. **    restore the middle layer at the location where the object being moved
  45. **    was last at.
  46. **
  47. ** The top layer object relates to the window, and therefore we don't need an
  48. ** off-screen GWorld for it.  A call to create this layer might look like the below:
  49. **
  50. ** err = NewLayer(&windowLayer,   Layer object handle is returned here.
  51. **                nil,            Top layer, so there is no above layer.
  52. **                nil,            Uses default layer procedure.
  53. **                window,         Window used by the layer object.
  54. **                0,              Desired depth (0 for screen depth).
  55. **                0);             Custom layer init data, if any.
  56. **
  57. ** If NewLayer succeeds, the layer object handle is returned in windowLayer.
  58. ** If it fails, nil is returned in windowLayer, plus an error is returned.
  59. ** If windowLayer is successfully created, then we can proceed to create the
  60. ** next two layers.  In the case below, we are creating an off-screen layer
  61. ** that has a pixmap the same size and depth as windowLayer.  If this is
  62. ** what we want for the middle layer, then we can again use the default
  63. ** LayerProc for the kLayerInit message.  All we need to do is to call the
  64. ** default layerProc with a kLayerInit message.  We want the standard
  65. ** action for initialization, but we want our own update action.  That's
  66. ** why we have a custom layerProc for the middle layer.  The call would look
  67. ** something like the below:
  68. **
  69. ** err = NewLayer(&middleLayer,     Layer object handle is returned here.
  70. **                windowLayer,      Layer above this layer.
  71. **                MiddleLayerProc,  Custom layerProc.
  72. **                nil,              Create a pixmap for layer.
  73. **                0,                Pixmap created as same size/depth as above layer.
  74. **                0);
  75. **
  76. ** The background layer would be created similarly.  When you are finished with
  77. ** the layers, you can dispose of them one at a time with DisposeLayer, or you
  78. ** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
  79. **
  80. ** Inserting a layer is done by position, and not by which layer it goes above
  81. ** or below.  The reason for this is that the layer positions are most likely
  82. ** absolute, and therefore it is better to indicate their position with an
  83. ** absolute number instead of always relating it to some other layer.  If it
  84. ** is necessary to insert a layer specifically above or below some other layer,
  85. ** it would be done as follows:
  86. **         InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  87. **         InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
  88. **
  89. ** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
  90. ** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
  91. */
  92.  
  93.  
  94.  
  95. /*****************************************************************************/
  96.  
  97.  
  98.  
  99. #ifndef __ERRORS__
  100. #include <Errors.h>
  101. #endif
  102.  
  103. #ifndef __GESTALTEQU__
  104. #include <GestaltEqu.h>
  105. #endif
  106.  
  107. #ifndef __GWLAYERS__
  108. #include "GWLayers.h"
  109. #endif
  110.  
  111. #ifndef __RESOURCES__
  112. #include <Resources.h>
  113. #endif
  114.  
  115. #ifndef __STRINGUTILS__
  116. #include <StringUtils.h>
  117. #endif
  118.  
  119. #ifndef __TRAPS__
  120. #include <Traps.h>
  121. #endif
  122.  
  123. #ifndef __WINDOWS__
  124. #include <Windows.h>
  125. #endif
  126.  
  127. #define kQDOriginal 0
  128.  
  129. static OSErr    DefaultLayerInit(LayerObj theLayer);
  130. static OSErr    DefaultLayerUpdate(LayerObj theLayer);
  131. static OSErr    DefaultLayerDispose(LayerObj theLayer);
  132.  
  133. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
  134. static void        KillLayerWorld(LayerObj theLayer);
  135. static void        SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
  136. static void        SmartSetGWorld(CGrafPtr port, GDHandle gdh);
  137. static short    GetQDVersion(void);
  138. static short    GetSystemVersion(void);
  139. static short    NumToolboxTraps(void);
  140. static Boolean    TrapExists(short theTrap);
  141. static TrapType    GetTrapType(short theTrap);
  142.  
  143.  
  144.  
  145. /*****************************************************************************/
  146. /*****************************************************************************/
  147.  
  148.  
  149.  
  150. #pragma segment GWLayers
  151. OSErr    NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
  152.                  GrafPtr basePort, short depth, unsigned long theData)
  153. {
  154.     OSErr        err;
  155.     LayerRecPtr    lptr;
  156.     CGrafPtr    scratchPort;
  157.     GDHandle    baseGDevice;
  158.  
  159.     *newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
  160.     err = MemError();
  161.     if (err) return(err);
  162.         /* If not enough memory for layer object, return nil and error. */
  163.  
  164.     SmartGetGWorld(&scratchPort, &baseGDevice);
  165.     if (!theProc)
  166.         theProc = DefaultLayerProc;
  167.             /* If layer proc is nil, then they want the default behavior. */
  168.  
  169.     lptr = **newLayer;
  170.     lptr->layerPort     = basePort;
  171.     lptr->layerGDevice  = baseGDevice;
  172.     lptr->layerDepth    = depth;
  173.     lptr->xferMode      = srcCopy;
  174.     lptr->layerProc     = theProc;
  175.     lptr->layerData     = theData;
  176.         /* Layer object is now initialized, except for layers that need a GWorld
  177.         ** created.  This will occur when the layer proc is called with an
  178.         ** initialization message.  (All fields not explicitly set are 0.) */
  179.  
  180.     InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  181.         /* Connect the layer to the layer chain.  The default initialization
  182.         ** behavior may need this, as it may create a GWorld of the same size
  183.         ** as the above layer.  If it isn't connected to the layer chain, then
  184.         ** there is no above layer. */
  185.  
  186.     err = (*theProc)(*newLayer, kLayerInit);
  187.     if (err) {
  188.         DisposeLayer(*newLayer);
  189.         *newLayer = nil;
  190.             /* There wasn't enough memory to create the off-screen GWorld, so
  191.             ** dispose of the layer object.  Since we failed, we need to return
  192.             ** nil and the error. */
  193.     }
  194.  
  195.     return(err);
  196. }
  197.  
  198.  
  199.  
  200. /*****************************************************************************/
  201.  
  202.  
  203.  
  204. #pragma segment GWLayers
  205. void    DetachLayer(LayerObj theLayer)
  206. {
  207.     LayerObj    aboveLayer, belowLayer;
  208.  
  209.     if (theLayer) {
  210.         aboveLayer = (*theLayer)->aboveLayer;
  211.         belowLayer = (*theLayer)->belowLayer;
  212.         if (aboveLayer)
  213.             (*aboveLayer)->belowLayer = belowLayer;
  214.         if (belowLayer)
  215.             (*belowLayer)->aboveLayer = aboveLayer;
  216.         (*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
  217.     }
  218. }
  219.  
  220.  
  221.  
  222. /*****************************************************************************/
  223.  
  224.  
  225.  
  226. #pragma segment GWLayers
  227. OSErr    DisposeLayer(LayerObj theLayer)
  228. {
  229.     OSErr    err;
  230.  
  231.     err = noErr;
  232.     if (theLayer) {
  233.         err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
  234.         DetachLayer(theLayer);
  235.         DisposeHandle((Handle)theLayer);
  236.     }
  237.  
  238.     return(err);
  239. }
  240.  
  241.  
  242.  
  243. /*****************************************************************************/
  244.  
  245.  
  246.  
  247. #pragma segment GWLayers
  248. OSErr    DisposeThisAndBelowLayers(LayerObj theLayer)
  249. {
  250.     OSErr    err, err2;
  251.  
  252.     err = noErr;
  253.     if (theLayer) {
  254.         err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
  255.         err  = DisposeLayer(theLayer);
  256.         if (!err)
  257.             err = err2;
  258.     }
  259.     return(err);
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************/
  265.  
  266.  
  267.  
  268. #pragma segment GWLayers
  269. short    GetLayerPosition(LayerObj theLayer)
  270. {
  271.     short    pos;
  272.  
  273.     if (!theLayer) return(0);
  274.  
  275.     for (pos = 0; (theLayer = (*theLayer)->aboveLayer) != nil; ++pos) {};
  276.     return(pos);
  277. }
  278.  
  279.  
  280.  
  281. /*****************************************************************************/
  282.  
  283.  
  284.  
  285. #pragma segment GWLayers
  286. LayerObj    GetTopLayer(LayerObj theLayer)
  287. {
  288.     for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer) {};
  289.     return(theLayer);
  290. }
  291.  
  292.  
  293.  
  294. /*****************************************************************************/
  295.  
  296.  
  297.  
  298. #pragma segment GWLayers
  299. LayerObj    GetBottomLayer(LayerObj theLayer)
  300. {
  301.     for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer) {};
  302.     return(theLayer);
  303. }
  304.  
  305.  
  306.  
  307. /*****************************************************************************/
  308.  
  309.  
  310.  
  311. #pragma segment GWLayers
  312. void    InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
  313. {
  314.     LayerObj    aboveLayer, belowLayer;
  315.     short        i;
  316.  
  317.     if (theLayer) {
  318.         if (theLayer == referenceLayer) {
  319.             /* If theLayer layer is the same as referenceLayer... */
  320.  
  321.             belowLayer = (*theLayer)->belowLayer;
  322.             if (belowLayer)
  323.                 referenceLayer = belowLayer;
  324.             aboveLayer = (*theLayer)->aboveLayer;
  325.             if (aboveLayer)
  326.                 referenceLayer = aboveLayer;
  327.                     /* Try to make the reference layer not the same as theLayer.
  328.                     ** If it is the same as theLayer, then when theLayer is
  329.                     ** removed from the old hierarchy, we lose the ability to re-add
  330.                     ** it to the hierarchy in a new location. */
  331.         }
  332.  
  333.         DetachLayer(theLayer);
  334.             /* Remove layer from its old hierarchy, if any. */
  335.  
  336.         if (!referenceLayer) return;
  337.             /* If there isn't a valid alternative reference, then theLayer
  338.             ** IS the hierarchy and no action is taken. */
  339.  
  340.         aboveLayer = nil;
  341.         belowLayer = GetTopLayer(referenceLayer);
  342.             /* aboveLayer now nil.  belowLayer now is top layer.  These
  343.             ** are the correct values if the layer being added is to be
  344.             ** the new top layer.  This will be the case if pos is 0.
  345.             ** We now walk the linked list pos number of times to get the
  346.             ** correct position.  We also terminate if we reach the end
  347.             ** of the linked list, no matter what pos is.  This will allow
  348.             ** values of pos that are too big to insert the layer at the
  349.             ** end of the linked list. */
  350.  
  351.         for (i = 0; ((belowLayer) && (i != pos)); ++i) {
  352.             aboveLayer = belowLayer;
  353.             belowLayer = (*belowLayer)->belowLayer;
  354.         }
  355.             /* We now have correct values for aboveLayer and belowLayer.  Note that
  356.             ** these values may be nil, which would be correct. */
  357.         (*theLayer)->aboveLayer = aboveLayer;
  358.         if (aboveLayer)
  359.             (*aboveLayer)->belowLayer = theLayer;
  360.         (*theLayer)->belowLayer = belowLayer;
  361.         if (belowLayer)
  362.             (*belowLayer)->aboveLayer = theLayer;
  363.     }
  364. }
  365.  
  366.  
  367.  
  368. /*****************************************************************************/
  369.  
  370.  
  371.  
  372. /*****************************************************************************/
  373.  
  374.  
  375.  
  376. #pragma segment GWLayers
  377. OSErr    UpdateLayer(LayerObj theLayer)
  378. {
  379.     OSErr    err;
  380.  
  381.     err = noErr;
  382.     if (theLayer) {
  383.         err = UpdateLayer((*theLayer)->belowLayer);
  384.             /* Handle the updates from the bottom up. */
  385.         if (!err)
  386.             err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
  387.                 /* Chain possible errors through each level of recursion. */
  388.     }
  389.     return(err);
  390. }
  391.  
  392.  
  393.  
  394. /*****************************************************************************/
  395.  
  396.  
  397.  
  398. #pragma segment GWLayers
  399. Rect    GetEffectiveSrcRect(LayerObj theLayer)
  400. {
  401.     Rect    srcRect;
  402.  
  403.     if (!theLayer)
  404.         SetRect(&srcRect, 0, 0, 0, 0);
  405.     else {
  406.         srcRect = (*theLayer)->srcRect;
  407.         if (EmptyRect(&srcRect))
  408.             srcRect = ((*theLayer)->layerPort)->portRect;
  409.     }
  410.     return(srcRect);
  411. }
  412.  
  413.  
  414.  
  415. /*****************************************************************************/
  416.  
  417.  
  418.  
  419. #pragma segment GWLayers
  420. Rect    GetEffectiveDstRect(LayerObj theLayer)
  421. {
  422.     Rect    dstRect;
  423.  
  424.     if (!theLayer)
  425.         SetRect(&dstRect, 0, 0, 0, 0);
  426.     else {
  427.         dstRect = (*theLayer)->dstRect;
  428.         if (EmptyRect(&dstRect))
  429.             dstRect = ((*theLayer)->layerPort)->portRect;
  430.     }
  431.     return(dstRect);
  432. }
  433.  
  434.  
  435.  
  436. /*****************************************************************************/
  437.  
  438.  
  439.  
  440. #pragma segment GWLayers
  441. OSErr    DefaultLayerProc(LayerObj theLayer, short message)
  442. {
  443.     OSErr    err;
  444.  
  445.     err = noErr;
  446.     if (theLayer) {
  447.         switch (message) {        /* Dispatch to the correct default behavior. */
  448.             case kLayerInit:
  449.                 err = DefaultLayerInit(theLayer);
  450.                 break;
  451.             case kLayerDispose:
  452.                 err = DefaultLayerDispose(theLayer);
  453.                 break;
  454.             case kLayerUpdate:
  455.                 err = DefaultLayerUpdate(theLayer);
  456.                 break;
  457.             default:
  458.                 break;
  459.         }
  460.     }
  461.     return(err);
  462. }
  463.  
  464.  
  465.  
  466. /*****************************************************************************/
  467.  
  468.  
  469.  
  470. #pragma segment GWLayers
  471. Rect    UpdateUpdateRects(LayerObj theLayer)
  472. {
  473.     Rect    lastUpdate, thisUpdate, dstRect;
  474.  
  475.     if (theLayer) {
  476.         lastUpdate = (*theLayer)->lastUpdate;
  477.         (*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
  478.         SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
  479.  
  480.         if ((*theLayer)->includeLastUpdate) {
  481.             (*theLayer)->includeLastUpdate = false;
  482.             if (EmptyRect(&lastUpdate))
  483.                 lastUpdate = thisUpdate;
  484.             if (EmptyRect(&thisUpdate))
  485.                 thisUpdate = lastUpdate;
  486.             UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
  487.                 /* We are going to update the last and current update rects.
  488.                 ** This will allow the appearance of movement for a foreground
  489.                 ** object.  The old location is cleared, plus the new location
  490.                 ** is updated. */
  491.             dstRect = GetEffectiveDstRect(theLayer);
  492.             SectRect(&thisUpdate, &dstRect, &thisUpdate);
  493.         }
  494.     }
  495.     else SetRect(&thisUpdate, 0, 0, 0, 0);
  496.  
  497.     return(thisUpdate);
  498. }
  499.  
  500.  
  501.  
  502. /*****************************************************************************/
  503.  
  504.  
  505.  
  506. #pragma segment GWLayers
  507. void    InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
  508. {
  509.     Rect        thisUpdate, srcRect, dstRect;
  510.     LayerObj    belowLayer;
  511.     short        ow, oh;
  512.     long        dw, dh, sw, sh;
  513.  
  514.     if (theLayer) {
  515.         belowLayer = (*theLayer)->belowLayer;
  516.         dstRect    = GetEffectiveDstRect(theLayer);
  517.  
  518.         SectRect(&dstRect, &invalRect, &invalRect);
  519.         if (!EmptyRect(&invalRect)) {                /* If there is something to invalidate... */
  520.             thisUpdate = (*theLayer)->thisUpdate;    /* There may be a prior unhandled update... */
  521.             if (EmptyRect(&thisUpdate))
  522.                 thisUpdate = invalRect;                /* UnionRect doesn't */
  523.             UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate);    /* like empty rects. */
  524.  
  525.             if (belowLayer) {
  526.                 /* If we have a below layer, then pass the update down.  The effectiveSrcRct
  527.                 ** rect for the below layer may be a different size than the effectiveDstRct.
  528.                 ** If this is the case, we want to scale invalRect to invalidate a proportional
  529.                 ** area in the below layer. */
  530.  
  531.                 srcRect = GetEffectiveSrcRect(belowLayer);
  532.  
  533.                 dw = dstRect.right  - dstRect.left;        /* Calculate widths and heights for */
  534.                 dh = dstRect.bottom - dstRect.top;        /* srcRect and dstRect. */
  535.                 sw = srcRect.right  - srcRect.left;
  536.                 sh = srcRect.bottom - srcRect.top;
  537.  
  538.                 OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
  539.                     /* We want to align the upper-left corner of the srcRect and dstRect
  540.                     ** so that the scaling also aligns the invalRect into the correct
  541.                     ** place in the below layer's effectiveSrcRect.  invalRect is now
  542.                     ** positioned relative to a dstRect with a upper-left corner of 0,0. */
  543.  
  544.                 if (dw != sw) {        /* Width dstRect different than srcRect. */
  545.                     ow = invalRect.right  - invalRect.left;
  546.                     invalRect.left  = (short)((invalRect.left  * sw) / dw);
  547.                     invalRect.right = (short)((invalRect.right * sw) / dw);
  548.                     if ((((invalRect.right  - invalRect.left) * dw) / sw) != ow)
  549.                         ++invalRect.right;
  550.                             /* We can possibly lose a fraction of a pixel on the right edge when
  551.                             ** scaling the invalRect.  It won't hurt if we inval just a bit too
  552.                             ** much, whereas invalidating too little is a bad thing. */
  553.                 }
  554.  
  555.                 if (dh != sh) {        /* Height dstRect different than srcRect. */
  556.                     oh = invalRect.bottom - invalRect.top;
  557.                     invalRect.top    = (short)((invalRect.top    * sh) / dh);
  558.                     invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
  559.                     if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
  560.                         ++invalRect.bottom;
  561.                 }
  562.  
  563.                 OffsetRect(&invalRect, srcRect.left, srcRect.top);
  564.                     /* Displace the new invalRect correctly relative to the srcRect. */
  565.             }
  566.         }
  567.  
  568.         if (includeLastUpdate)
  569.             (*theLayer)->includeLastUpdate = true;
  570.                 /* If requested to update last position as well, flag it. */
  571.  
  572.         InvalLayer(belowLayer, invalRect, includeLastUpdate);
  573.             /* Invalidate the below layer with the new (possibly scaled) invalRect. */
  574.     }
  575. }
  576.  
  577.  
  578. /*****************************************************************************/
  579.  
  580.  
  581.  
  582. #pragma segment GWLayers
  583. void    SetLayerWorld(LayerObj theLayer)
  584. {
  585.     CGrafPtr    keepPort;
  586.     GDHandle    keepGDevice;
  587.  
  588.     /* This is a convenient call for setting a GWorld, while remembering what
  589.     ** the previous GWorld was.  This should be balanced with a call to
  590.     ** ResetLayerWorld.  A count of how many times this is called is kept
  591.     ** so that the old GWorld is cached only if SetLayerWorld is currently
  592.     ** in balance with ResetLayerWorld.  This keeps the oldest kept GWorld
  593.     ** from being overwritten by subsequent calls. */
  594.  
  595.     if (theLayer) {
  596.         if (!(*theLayer)->cachedCount++) {
  597.             SmartGetGWorld(&keepPort, &keepGDevice);
  598.             (*theLayer)->cachedPort    = keepPort;
  599.             (*theLayer)->cachedGDevice = keepGDevice;
  600.         }
  601.         SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
  602.         LockLayerWorld(theLayer);
  603.     }
  604. }
  605.  
  606.  
  607.  
  608. /*****************************************************************************/
  609.  
  610.  
  611.  
  612. #pragma segment GWLayers
  613. void    ResetLayerWorld(LayerObj theLayer)
  614. {
  615.     /* This is used to undo a call to SetLayerWorld.  Calls to ResetLayerWorld
  616.     ** should be balanced with previous calls to SetLayerWorld. */
  617.  
  618.     if (theLayer) {
  619.         UnlockLayerWorld(theLayer);
  620.         if (!--(*theLayer)->cachedCount)
  621.             SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
  622.     }
  623. }
  624.  
  625.  
  626.  
  627. /*****************************************************************************/
  628.  
  629.  
  630.  
  631. #pragma segment GWLayers
  632. void    LockLayerWorld(LayerObj theLayer)
  633. {
  634.     Handle    bitmap;
  635.  
  636.     /* This is a convenient way to lock down the pixels for a layer's GWorld.
  637.     ** A locked count is kept to make sure that the GWorld is locked only the
  638.     ** first time this is called.  Calls to LockLayerWorld will most likely
  639.     ** be balanced by calls to UnlockLayerWorld, but not necessarily.  It may
  640.     ** be desirable to keep a GWorld call locked.  In this case, right after
  641.     ** creating the layer (and indirectly its GWorld), call LockLayerWorld.
  642.     ** This will initially lock it.  Subsequent calls would be balanced, and
  643.     ** therefore there will always be one more LockLayerWorld call than
  644.     ** UnlockLayerWorld calls.  This will keep it locked. */
  645.  
  646.     if (theLayer) {
  647.         if ((*theLayer)->layerOwnsPort) {
  648.             if (!(*theLayer)->lockedCount++) {
  649.                 bitmap = (*theLayer)->layerBitmap;
  650.                 if (bitmap) {
  651.                     HLock(bitmap);
  652.                     (*theLayer)->layerPort->portBits.baseAddr = *bitmap;
  653.                 }
  654.                 else
  655.                     LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  656.             }
  657.         }
  658.     }
  659. }
  660.  
  661.  
  662.  
  663. /*****************************************************************************/
  664.  
  665.  
  666.  
  667. #pragma segment GWLayers
  668. void    UnlockLayerWorld(LayerObj theLayer)
  669. {
  670.     /* This undoes what LockLayerWorld does.  Calls to UnlockLayerWorld will
  671.     ** generally be balanced with calls to LockLayerWorld. */
  672.  
  673.     if (theLayer) {
  674.         if ((*theLayer)->layerOwnsPort) {
  675.             if (!--(*theLayer)->lockedCount) {
  676.                 if ((*theLayer)->layerBitmap)
  677.                     HUnlock((*theLayer)->layerBitmap);
  678.                 else
  679.                     UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  680.             }
  681.         }
  682.     }
  683. }
  684.  
  685.  
  686.  
  687. /*****************************************************************************/
  688.  
  689.  
  690.  
  691. #pragma segment GWLayers
  692. RgnHandle    ScreenDepthRegion(short depth)
  693. {
  694.     RgnHandle        retRgn, tmpRgn;
  695.     GDHandle        device;
  696.     PixMapHandle    pmap;
  697.     Rect            rct;
  698.     GrafPtr            mainPort;
  699.  
  700.     retRgn = NewRgn();
  701.  
  702.     if (GetQDVersion() == kQDOriginal) {
  703.         if (depth == 1) {
  704.             GetWMgrPort(&mainPort);
  705.             rct = mainPort->portRect;
  706.             RectRgn(retRgn, &rct);
  707.         }
  708.     }
  709.     else {
  710.         tmpRgn = NewRgn();
  711.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  712.             if (
  713.                 (TestDeviceAttribute(device, screenDevice)) &&
  714.                 (TestDeviceAttribute(device, screenActive))
  715.             ) {
  716.                 pmap = (*device)->gdPMap;
  717.                 if ((*pmap)->pixelSize >= depth) {
  718.                     rct = (*device)->gdRect;
  719.                     RectRgn(tmpRgn, &rct);
  720.                     UnionRgn(retRgn, tmpRgn, retRgn);
  721.                 }
  722.             }
  723.         }
  724.         DisposeRgn(tmpRgn);
  725.     }
  726.  
  727.     return(retRgn);
  728. }
  729.  
  730.  
  731.  
  732. /*****************************************************************************/
  733.  
  734.  
  735.  
  736. #pragma segment GWLayers
  737. CIconHandle    ReadCIcon(short iconID)
  738. {
  739.     Handle    hndl;
  740.  
  741.     if (TrapExists(_PlotCIcon))
  742.         return(GetCIcon(iconID));
  743.  
  744.     hndl = GetResource('cicn', iconID);
  745.     DetachResource(hndl);
  746.     return((CIconHandle)hndl);
  747. }
  748.  
  749.  
  750.  
  751. /*****************************************************************************/
  752.  
  753.  
  754.  
  755. #pragma segment GWLayers
  756. void    KillCIcon(CIconHandle icon)
  757. {
  758.     if (!icon) return;
  759.  
  760.     if (TrapExists(_PlotCIcon))
  761.         DisposeCIcon(icon);
  762.     else
  763.         DisposeHandle((Handle)icon);
  764. }
  765.  
  766.  
  767.  
  768. /*****************************************************************************/
  769.  
  770.  
  771.  
  772. #pragma segment GWLayers
  773. void    DrawCIcon(CIconHandle icon, Rect destRect)
  774. {
  775.     WindowPtr    curPort;
  776.     short        depth;
  777.  
  778.     if (!icon) return;
  779.  
  780.     if (TrapExists(_PlotCIcon)) {
  781.         depth = 8;
  782.         if (GetSystemVersion() < 0x0700) {
  783.             depth = 1;
  784.             GetPort(&curPort);
  785.             if (curPort->portBits.rowBytes & 0x8000)
  786.                 depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  787.         }
  788.     }
  789.     else depth = 1;
  790.  
  791.     if (depth > 1)
  792.         PlotCIcon(&destRect, icon);
  793.     else
  794.         DrawCIconByDepth(icon, destRect, 1, true);
  795. }
  796.  
  797.  
  798.  
  799. /*****************************************************************************/
  800.  
  801.  
  802.  
  803. #pragma segment GWLayers
  804. void    DrawCIconNoMask(CIconHandle icon, Rect destRect)
  805. {
  806.     Rect    iconRect;
  807.     char    oldMask[128], *mptr;
  808.     short    maskSize, i;
  809.  
  810.     if (!icon) return;
  811.  
  812.     mptr = (Ptr)(*icon)->iconMaskData;
  813.     iconRect = (*icon)->iconPMap.bounds;
  814.     maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  815.     for (i = 0; i < maskSize; ++i) {
  816.         oldMask[i] = mptr[i];
  817.         mptr[i] = 0xFF;
  818.     }
  819.     DrawCIcon(icon, destRect);
  820.     mptr = (Ptr)(*icon)->iconMaskData;
  821.     for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
  822. }
  823.  
  824.  
  825.  
  826. /*****************************************************************************/
  827.  
  828.  
  829.  
  830. #pragma segment GWLayers
  831. void    DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
  832. {
  833.     GrafPtr        curPort;
  834.     char        savedIconState;
  835.     char        savedDataState;
  836.     short        offset;
  837.     BitMapPtr    bmap;
  838.     Rect        iconRect;
  839.  
  840.     if (!icon) return;
  841.  
  842.     GetPort(&curPort);
  843.  
  844.     if (!depth) {
  845.         if (!(curPort->portBits.rowBytes & 0x8000))
  846.             depth = 1;
  847.         else
  848.             depth = (*(((CGrafPtr)curPort)->portPixMap))->pixelSize;
  849.     }
  850.  
  851.     savedIconState = HGetState((Handle)icon);        /* Lock down things. */
  852.     HLock((Handle)icon);
  853.     if (depth > 1) {
  854.         savedDataState = HGetState((*icon)->iconData);
  855.         HLock((*icon)->iconData);
  856.         (*icon)->iconPMap.baseAddr = *((*icon)->iconData);
  857.             /* Point the icon's pixMap at the color icon data. */
  858.     }
  859.  
  860.     iconRect = (*icon)->iconPMap.bounds;
  861.         /* Find out the dimensions of the icon. */
  862.  
  863.     (*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
  864.         /* Point the mask's bitMap at the mask data. */
  865.  
  866.     offset  = iconRect.bottom - iconRect.top;
  867.     offset *= (*icon)->iconMask.rowBytes;
  868.     (*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
  869.         /* Point the icon's bitMap at the b/w icon data. */
  870.  
  871.     bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
  872.     if (useMask)
  873.         CopyMask(bmap, &((*icon)->iconMask), &curPort->portBits, &iconRect, &iconRect, &destRect);
  874.     else
  875.         CopyBits(bmap, &curPort->portBits, &iconRect, &destRect, srcCopy, nil);
  876.  
  877.     HSetState((Handle)icon, savedIconState);        /* Unlock things. */
  878.     if (depth > 1)
  879.         HSetState((*icon)->iconData, savedDataState);
  880. }
  881.  
  882.  
  883.  
  884. /*****************************************************************************/
  885. /*****************************************************************************/
  886. /*****************************************************************************/
  887.  
  888.  
  889.  
  890. #pragma segment GWLayers
  891. static OSErr    DefaultLayerInit(LayerObj theLayer)
  892. {
  893.     LayerObj    aboveLayer;
  894.     GWorldPtr    layerWorld;        /* GWorld for this layer. */
  895.     Rect        parentRect;        /* Rectangle of parent in global coordinates. */
  896.     GrafPtr        parentPort;        /* Parent layer's GrafPort. */
  897.     GDHandle    parentGDevice;    /* Parent layer's GDevice. */
  898.     CGrafPtr    keepPort;        /* Saved GrafPort. */
  899.     GDHandle    keepGDevice;    /* Saved GDevice. */
  900.     Point        org;
  901.     OSErr        err;
  902.     short        depth;
  903.  
  904.     err = noErr;
  905.     if (theLayer) {
  906.         if (!(*theLayer)->layerPort) {
  907.  
  908.             aboveLayer = (*theLayer)->aboveLayer;
  909.             if (aboveLayer) {
  910.                 /* The default behavior is to create a GWorld the same size
  911.                 ** as the above layer, if there is one.  If there isn't an above
  912.                 ** layer and we were expected to create a GWorld, we have problems.
  913.                 ** This situation can't be resolved and is handled as a paramErr. */
  914.  
  915.                 if (!((*theLayer)->layerDepth))
  916.                     (*theLayer)->layerDepth = (*aboveLayer)->layerDepth;
  917.  
  918.                 SmartGetGWorld(&keepPort, &keepGDevice);        /* Keep the GWorld. */
  919.  
  920.                 parentPort    = (*aboveLayer)->layerPort;
  921.                 parentGDevice = (*aboveLayer)->layerGDevice;
  922.                     /* Grab the parent layer's GrafPort and GDevice. */
  923.     
  924.                 SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
  925.                 parentRect = GetEffectiveDstRect(aboveLayer);
  926.                     /* The default behavior is to use the portRect of the above
  927.                     ** port.  This behavior can be overridden if desired by setting
  928.                     ** dstRect.  dstRect is initialized to be empty, but if
  929.                     ** it is specifically set, then this layer should map into
  930.                     ** just the dstRect and not the portRect.  This is useful if
  931.                     ** the off-screen image is to be displayed in only a portion
  932.                     ** of a window. */
  933.  
  934.                 org.h = parentRect.left;
  935.                 org.v = parentRect.top;
  936.  
  937.                 LocalToGlobal(((Point *)&parentRect) + 0);
  938.                 LocalToGlobal(((Point *)&parentRect) + 1);
  939.                     /* Put the parent layer's destination rect in global coordinates. */
  940.     
  941.                 if (GetQDVersion())
  942.                     err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
  943.                         /* Create the GWorld for this layer.  It will be created with the
  944.                         ** requested depth.  If the requested depth is 0, then it will be
  945.                         ** created with a depth great enough for the deepest monitor the
  946.                         ** parentRect intersects. */
  947.                 else
  948.                     err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
  949.                         /* Create a bitmap for those systems without GWorlds. */
  950.  
  951.                 if (err == noErr) {
  952.                     (*theLayer)->layerOwnsPort = true;
  953.                     SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
  954.                         /* Save the new GWorld in the layer object. */
  955.                     SetOrigin(org.h, org.v);
  956.                         /* Set the origin so that this GWorld maps directly into the
  957.                         ** area to be copied into (dstRect or portRect) for the
  958.                         ** above layer. */
  959.  
  960.                     if (!((*theLayer)->layerDepth)) {
  961.                         if (((GrafPtr)layerWorld)->portBits.rowBytes & 0x8000)
  962.                             depth = (*(((CGrafPtr)layerWorld)->portPixMap))->pixelSize;
  963.                         else
  964.                             depth = 1;
  965.                         (*theLayer)->layerDepth = depth;
  966.                     }
  967.                 }
  968.  
  969.                 SmartSetGWorld(keepPort, keepGDevice);        /* Restore the kept GWorld. */
  970.             }
  971.             else {
  972.                 err = paramErr;
  973.                     /* We were expected to create an off-screen GWorld of the
  974.                     ** same size as the above layer, but we didn't have an above
  975.                     ** layer.  This is an error.  The parameters passed to NewLayer
  976.                     ** were inappropriate for the situation, so return a paramErr. */
  977.             }
  978.         }
  979.     }
  980.  
  981.     return(err);
  982. }
  983.  
  984.  
  985.  
  986. /*****************************************************************************/
  987.  
  988.  
  989.  
  990. #pragma segment GWLayers
  991. static OSErr    DefaultLayerUpdate(LayerObj theLayer)
  992. {
  993.     LayerObj    belowLayer;
  994.     GrafPtr        belowPort, thisPort;
  995.     GDHandle    thisGDevice;
  996.     CGrafPtr    keepPort;
  997.     GDHandle    keepGDevice;
  998.     Rect        thisUpdate, belowRect, thisRect;
  999.     short        xfer;
  1000.     RgnHandle    rgn;
  1001.  
  1002.     /* The default update behavior is to copy the area to be updated from the
  1003.     ** below layer into the indicated layer.  We only need to update layer if
  1004.     ** there is a below layer.  The bottom-most layer update doesn't do anything.
  1005.     ** As a default, the bottom-most layer is considered background and does not
  1006.     ** get updated. */
  1007.  
  1008.     if (theLayer) {
  1009.         belowLayer = (*theLayer)->belowLayer;
  1010.         if (belowLayer) {
  1011.             /* Get this layer's GWorld and below layer's port. */
  1012.             thisPort    = (*theLayer)->layerPort;
  1013.             thisGDevice = (*theLayer)->layerGDevice;
  1014.             belowPort   = (*belowLayer)->layerPort;
  1015.  
  1016.             /* Save current GWorld and set the parent's GWorld. */
  1017.             SmartGetGWorld(&keepPort, &keepGDevice);
  1018.             SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
  1019.  
  1020.             thisUpdate = UpdateUpdateRects(theLayer);
  1021.  
  1022.             rgn = NewRgn();
  1023.             RectRgn(rgn, &thisUpdate);
  1024.  
  1025.             belowRect = GetEffectiveSrcRect(belowLayer);
  1026.             thisRect  = GetEffectiveDstRect(theLayer);
  1027.  
  1028.                 /* As a default behavior, we CopyBits the below layer into this layer. */
  1029.             LockLayerWorld(belowLayer);
  1030.             LockLayerWorld(theLayer);
  1031.             xfer = (*theLayer)->xferMode;
  1032.             CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
  1033.             UnlockLayerWorld(theLayer);
  1034.             UnlockLayerWorld(belowLayer);
  1035.             DisposeRgn(rgn);
  1036.  
  1037.             SmartSetGWorld(keepPort, keepGDevice);        /* Restore to the kept GWorld. */
  1038.         }
  1039.     }
  1040.     return(noErr);
  1041. }
  1042.  
  1043.  
  1044.  
  1045. /*****************************************************************************/
  1046.  
  1047.  
  1048.  
  1049. #pragma segment GWLayers
  1050. static OSErr    DefaultLayerDispose(LayerObj theLayer)
  1051. {
  1052.     GWorldPtr    theWorld;
  1053.  
  1054.     if (theLayer) {
  1055.         if ((*theLayer)->layerOwnsPort) {
  1056.             theWorld = (GWorldPtr)(*theLayer)->layerPort;
  1057.             if (theWorld) {
  1058.                 if ((*theLayer)->layerBitmap)
  1059.                     KillLayerWorld(theLayer);
  1060.                 else
  1061.                     DisposeGWorld(theWorld);
  1062.             }
  1063.         }
  1064.     }
  1065.  
  1066.     return(noErr);
  1067. }
  1068.  
  1069.  
  1070.  
  1071. /*****************************************************************************/
  1072.  
  1073.  
  1074.  
  1075. #pragma segment GWLayers
  1076. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
  1077. {
  1078.     GrafPtr    oldPort;
  1079.     GrafPtr    newPort;
  1080.     Handle    bitmap;
  1081.     OSErr    err;
  1082.  
  1083.     OffsetRect(&bnds, -bnds.left, -bnds.top);    /* Make sure upper-left is 0,0. */
  1084.  
  1085.     GetPort(&oldPort);        /* Need this to restore the port after OpenPort. */
  1086.  
  1087.     newPort = (GrafPtr)NewPtr(sizeof(GrafPort));        /* Allocate the grafPort. */
  1088.     err = MemError();
  1089.     if (err)
  1090.         return(err);        /* Failed to allocate the off-screen port. */
  1091.  
  1092.     /* The call to OpenPort does the following:
  1093.     ** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  1094.     ** 2) sets portBits to screenBits
  1095.     ** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
  1096.     ** 4) side effect: does a SetPort(&offScreen) */
  1097.  
  1098.     OpenPort(newPort);
  1099.     SetPort(oldPort);
  1100.  
  1101.         /* Now make bitmap the size of the bounds that caller supplied. */
  1102.  
  1103.     newPort->portRect = bnds;
  1104.     newPort->portBits.bounds = bnds;
  1105.     RectRgn(newPort->visRgn, &bnds);
  1106.  
  1107.     SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
  1108.         /* Avoid wide-open clipRgn, to be safe.    */
  1109.  
  1110.     /* rowBytes is size of row, it must be rounded up to an even number of bytes. */
  1111.     newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
  1112.  
  1113.     bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
  1114.     err = MemError();
  1115.     if (err) {
  1116.         ClosePort(newPort);            /* Dump the visRgn and clipRgn. */
  1117.         DisposePtr((Ptr)newPort);    /* Dump the GrafPort. */
  1118.         return(err);
  1119.     }
  1120.  
  1121.     (*theLayer)->layerBitmap = bitmap;
  1122.     *layerWorld              = (GWorldPtr)newPort;
  1123.  
  1124.     return(noErr);
  1125. }
  1126.  
  1127.  
  1128.  
  1129. /*****************************************************************************/
  1130.  
  1131.  
  1132.  
  1133. #pragma segment GWLayers
  1134. static void    KillLayerWorld(LayerObj theLayer)
  1135. {
  1136.     DisposeHandle((*theLayer)->layerBitmap);
  1137.     (*theLayer)->layerBitmap = nil;
  1138.  
  1139.     ClosePort((*theLayer)->layerPort);
  1140.     DisposePtr((Ptr)(*theLayer)->layerPort);
  1141.     (*theLayer)->layerPort = nil;
  1142. }
  1143.  
  1144.  
  1145.  
  1146.  
  1147. /*****************************************************************************/
  1148.  
  1149.  
  1150.  
  1151. #pragma segment GWLayers
  1152. static void    SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
  1153. {
  1154.     if (GetQDVersion())
  1155.         GetGWorld(port, gdh);
  1156.     else {
  1157.         *gdh = nil;
  1158.         GetPort((GrafPtr *)port);
  1159.     }
  1160. }
  1161.  
  1162.  
  1163.  
  1164. /*****************************************************************************/
  1165.  
  1166.  
  1167.  
  1168. #pragma segment GWLayers
  1169. static void    SmartSetGWorld(CGrafPtr port, GDHandle gdh)
  1170. {
  1171.     if (GetQDVersion())
  1172.         SetGWorld(port, gdh);
  1173.     else
  1174.         SetPort((GrafPtr)port);
  1175. }
  1176.  
  1177.  
  1178.  
  1179. /*****************************************************************************/
  1180.  
  1181.  
  1182.  
  1183. #pragma segment GWLayers
  1184. static short    GetQDVersion()
  1185. {
  1186.     static long    gestaltResult = -1;
  1187.  
  1188.     if (gestaltResult == -1) {
  1189.         if (Gestalt(gestaltQuickdrawVersion, &gestaltResult))
  1190.             gestaltResult = 0;
  1191.     }
  1192.  
  1193.     return((gestaltResult >> 8) & 0xFF);
  1194. }
  1195.  
  1196.  
  1197.  
  1198. /*****************************************************************************/
  1199.  
  1200.  
  1201.  
  1202. #pragma segment GWLayers
  1203. static short    GetSystemVersion()
  1204. {
  1205.     static long    gestaltResult;
  1206.  
  1207.     if (!gestaltResult) {
  1208.         if (Gestalt(gestaltSystemVersion, &gestaltResult))
  1209.             gestaltResult = 0;
  1210.     }
  1211.  
  1212.     return(gestaltResult);
  1213. }
  1214.  
  1215.  
  1216.  
  1217. /*****************************************************************************/
  1218.  
  1219.  
  1220.  
  1221. #pragma segment GWLayers
  1222. static Boolean    TrapExists(short theTrap)
  1223. {
  1224.     TrapType    theTrapType;
  1225.  
  1226.     theTrapType = GetTrapType(theTrap);
  1227.     if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  1228.         theTrap = _Unimplemented;
  1229.  
  1230.     return(NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  1231. }
  1232.  
  1233.  
  1234.  
  1235. /*****************************************************************************/
  1236.  
  1237.  
  1238.  
  1239. #pragma segment GWLayers
  1240. static short    NumToolboxTraps(void)
  1241. {
  1242.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  1243.         return(0x200);
  1244.     else
  1245.         return(0x400);
  1246. }
  1247.  
  1248.  
  1249.  
  1250. /*****************************************************************************/
  1251.  
  1252.  
  1253.  
  1254. #pragma segment GWLayers
  1255. static TrapType    GetTrapType(short theTrap)
  1256. {
  1257.     /* OS traps start with A0, Tool with A8 or AA. */
  1258.     if ((theTrap & 0x0800) == 0)                    /* per D.A. */
  1259.         return(OSTrap);
  1260.     else
  1261.         return(ToolTrap);
  1262. }
  1263.  
  1264.  
  1265.  
  1266.