home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Code Resources / Jims CDEFs 1.50 / CDEF Source / source / cdef3D.c next >
Encoding:
Text File  |  1995-11-08  |  36.1 KB  |  1,276 lines  |  [TEXT/KAHL]

  1. //------------------------- © 1994-1995 by James G. Stout --------------------------
  2. // File        : cdef3D.c
  3. // Date        : May 2, 1994
  4. // Author    : Jim Stout
  5. // Purpose    : A CDEF to implement some very subtle 3D pushButtons, checkBoxes & 
  6. //            : radioButtons.  These will even "do 3D" on a white background.
  7. //            :
  8. //            : checkBox & radioButton controls can have an embossed titles if
  9. //            : they are used on a colored background.
  10. //            :
  11. //            : This version uses varCode 4 (undefined in the standard CDEF) to
  12. //            : provide a push button that will use the window background color as
  13. //            : the body color for the button.
  14. //            :
  15. //            : There are several build switches to control this CDEF. See below.
  16. //            :
  17. //            : If you find a use for this, I'd love to know about it.  Bug reports
  18. //            : are always interesting.
  19. //            :
  20. //            : Internet    : JimS@WRQ.COM(work hours, PST)
  21. //            : AppleLink   : WRQ            (daily)
  22. //            : CompuServe  : 73240,2052    (weekly or so)
  23. //            : AOL         : JasG        (weekly or so)
  24. //            : eWorld      : Jim Stout    (weekly or so)
  25. //            :
  26. //----------------------------------------------------------------------------------
  27.  
  28. //#define _DEBUGCDEF 1            // allows inline debugging in a test project
  29.  
  30. //----------------------------------------------------------------------------------
  31. //    The following switches control the appearance of push buttons & check boxes
  32. //----------------------------------------------------------------------------------
  33.  
  34. #define _USETINGE 1            // add window tinge color to button frame (if no 'cctb')
  35. #define _EMBOSS 1            // emboss radioButton & checkBox titles
  36. //#define _REALCHECK 1        // use a checkMark instead of an 'x' in checkBoxes
  37. //#define _RECTPUSH 1        // draw a Rectangular button, not oval
  38.  
  39. //----------------------------------------------------------------------------------
  40. //    The next switch controls the use of offscreen (GWorld) drawing.  There are 2 
  41. //    advantages to using this:
  42. //
  43. //        1. Elimination of "flicker" as the embossed titles are drawn.
  44. //        2. To get '3d' controls in old style GrafPorts (no 'dctb' resources) that
  45. //            are displayed on color devices.
  46. //
  47. //    This does mean performance & memory hits, but hopefully, minor.  Also, the
  48. //    code size for the CDEF will increase.  GWorlds are not used for push buttons. 
  49. //
  50. //    I recommend using this if you want to use this CDEF on non-white backgrounds
  51. //    and you have set the _EMBOSS switch above.
  52. //----------------------------------------------------------------------------------
  53.  
  54. #define _USEOFFSCREEN 1
  55.  
  56. //----------------------------------------------------------------------------------
  57. //    The next 2 switches force push buttons to always use a black frame & body color
  58. //    of _GRAYSHADE. 'cctb' colors are used for the title.
  59. //----------------------------------------------------------------------------------
  60.  
  61. //#define _GRAYBUTTONS 1
  62. #define _GRAYSHADE 0xeeee
  63.  
  64. //----------------------------------------------------------------------------------
  65.  
  66. #include "fatCDEF.h"
  67.  
  68. #include <Controls.h>
  69. #include <LowMem.h>
  70. #include <GestaltEqu.h>
  71. #include <Memory.h>
  72. #include <QDOffscreen.h>
  73. #include <ToolUtils.h>
  74. #include <Traps.h>
  75. #include <Types.h>
  76.  
  77. #include "colorCDEF.h"
  78. #include "grayCDEF.h"
  79. #include "miscCDEF.h"
  80.  
  81. #include "cdef3D.h"
  82.             
  83. #ifdef _DEBUGCDEF
  84. pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param);
  85. pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
  86. #else
  87.  
  88. //==================================================================================
  89. //    CDEF main
  90. //==================================================================================
  91.  
  92. pascal long main (short varCode, ControlHandle theCtl, short message, long param)
  93. #endif
  94. {
  95.     long        ret = 0L;
  96.     short        ctlType;
  97.     Point        p;
  98.     GrafPtr        thisPort;
  99.     CDEFHandle    hCdef;
  100.     SignedByte    cState, dState;
  101.     
  102. #include "fatEntry.c"
  103.     
  104.     cState = HGetState((Handle)theCtl);
  105.     HLock((Handle)theCtl);
  106.     if((**theCtl).contrlData) {
  107.         dState = HGetState((**theCtl).contrlData);
  108.         HLock((**theCtl).contrlData);
  109.     }
  110.  
  111. //----------------------------------------------------------------------------------
  112. // Process messages to control    
  113. //----------------------------------------------------------------------------------
  114.  
  115.     switch(message) {
  116.         
  117.         case initCntl:
  118.         
  119.             GetPort(&thisPort);
  120.             hCdef = (CDEFHandle)NewHandle(sizeof(CDEFData));
  121.             if(hCdef) {
  122.                 (**hCdef).txFont = thisPort->txFont;
  123.                 (**hCdef).txSize = thisPort->txSize;
  124.                 (**hCdef).txFace = thisPort->txFace;
  125.                 (**theCtl).contrlData = (Handle)hCdef;
  126.                 dState = HGetState((**theCtl).contrlData);
  127.                 HLock((**theCtl).contrlData);
  128.             }
  129.         break;
  130.  
  131.         case dispCntl:
  132.             if((**theCtl).contrlData) {
  133.                 hCdef = (CDEFHandle)(**theCtl).contrlData;
  134.                 
  135.                 HUnlock((**theCtl).contrlData);
  136.                 DisposeHandle((**theCtl).contrlData);
  137.                 
  138.                 (**theCtl).contrlData = 0;
  139.             }
  140.         break;
  141.  
  142.         case drawCntl:
  143.             if((**theCtl).contrlVis != 0 &&
  144.                 ((WindowPeek)(**theCtl).contrlOwner)->visible)
  145.                 doDraw(theCtl, varCode);
  146.         break;
  147.  
  148.         case testCntl:
  149.             p.v=HiWord(param);
  150.             p.h=LoWord(param);
  151.             ctlType = varCode;
  152.             if(varCode & useWindFont)
  153.                 ctlType ^= useWindFont;
  154.                 
  155.             if(PtInRect(p,&(*theCtl)->contrlRect)) {
  156.                 switch(ctlType) {
  157.                     case 0:
  158.                     case 4:
  159.                         ret = inButton;
  160.                     break;
  161.                     
  162.                     default:
  163.                         ret = inCheckBox;
  164.                     break;
  165.                 }
  166.             }
  167.         break;
  168.  
  169.         case  calcCRgns:
  170.             RectRgn((RgnHandle)(param & 0x7fffffffL), &(*theCtl)->contrlRect);
  171.         break;
  172.  
  173.         case calcCntlRgn:
  174.         case calcThumbRgn:
  175.             RectRgn((RgnHandle)(param), &(*theCtl)->contrlRect);
  176.         break;
  177.     }
  178.     
  179.     if((**theCtl).contrlData)
  180.         HSetState((**theCtl).contrlData, dState);
  181.     HSetState((Handle)theCtl, cState);
  182.  
  183. #include "fatExit.c"
  184.     
  185.     return (ret);
  186. }
  187.         
  188. //==================================================================================
  189. // If running with System 7, use DeviceLoop to gracefully handle multiple screens.
  190. // Simulate DeviceLoop if using System 6...
  191. //==================================================================================
  192.  
  193. static void doDraw(ControlHandle theCtl, short varCode)
  194. {
  195.     short                    saveMode, txF, txS;
  196.     unsigned char            saveFace;
  197.     GrafPtr                    savePort, thisPort;
  198.     devLoopHandle            hDl;
  199.     RgnHandle                saveClip, hRgn;
  200.     DeviceLoopDrawingUPP    drawControlUPP;
  201.  
  202. //----------------------------------------------------------------------------------
  203. // set window font & size info    
  204. //----------------------------------------------------------------------------------
  205.     GetPort(&savePort);
  206.     SetPort((**theCtl).contrlOwner);
  207.     GetPort(&thisPort);
  208.     
  209.     saveMode = thisPort->txMode;
  210.     saveFace = thisPort->txFace;
  211.     
  212.     if(!(varCode & useWindFont)) {                // use system font
  213.         txF = thisPort->txFont;                    // save current
  214.         txS = thisPort->txSize;
  215.         TextFont(LMGetSysFontFam());            // set system as current
  216.         TextSize(LMGetSysFontSize());
  217.         TextFace(normal);
  218.     }
  219.     TextMode(srcOr);
  220.  
  221. //----------------------------------------------------------------------------------
  222. //    Create our data handle to pass to DeviceLoop
  223. //----------------------------------------------------------------------------------
  224.  
  225.     hDl = (devLoopHandle)NewHandle(sizeof(devLoopData));
  226.     if(hDl) {
  227.         drawControlUPP = NewDeviceLoopDrawingProc(drawControl);
  228.         
  229.         (**hDl).theCtl = theCtl;
  230.         (**hDl).varCode = varCode;
  231.         (**hDl).controlRect = (**theCtl).contrlRect;
  232.  
  233. //----------------------------------------------------------------------------------
  234. //    Do the clip region properly.  Thanks Ari!
  235. //----------------------------------------------------------------------------------
  236.  
  237.         saveClip = NewRgn();
  238.         GetClip(saveClip);
  239.         
  240.         hRgn = NewRgn();
  241.         RectRgn(hRgn, &(**hDl).controlRect);
  242.         SectRgn(saveClip, hRgn, hRgn);
  243.         
  244.         if(EmptyRgn(hRgn)) {                                    // if empty, don't waste
  245.             DisposeRgn(saveClip);                                // time drawing...
  246.             DisposeRgn(hRgn);
  247.             return;
  248.         }        
  249.  
  250. //----------------------------------------------------------------------------------
  251. //    Call DeviceLoop to take care of our drawing
  252. //----------------------------------------------------------------------------------
  253.         
  254.         if(getOSVers() >= 0x0700) {
  255.             DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
  256.         }
  257.         else {
  258.             sys6DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
  259.         }
  260.         
  261.         SetClip(saveClip);        
  262.         DisposeRgn(hRgn);
  263.         DisposeHandle((Handle)hDl);
  264.         DisposeRoutineDescriptor(drawControlUPP);
  265.     }
  266. //----------------------------------------------------------------------------------
  267. // restore window font & size info    
  268. //----------------------------------------------------------------------------------
  269.  
  270.     if(!(varCode & useWindFont)) {
  271.         TextFont(txF);
  272.         TextSize(txS);
  273.     }
  274.     TextMode(saveMode);
  275.     TextFace(saveFace);
  276.     SetPort(savePort);
  277. }
  278.  
  279. //==================================================================================
  280. // main drawing routine for all variations of the control.  Also
  281. // handles setting of colors, inactive control drawing.
  282. //
  283. // This is called by DeviceLoop, but in this case, we just pay attention to the
  284. // "depth" and "userData" parameters.
  285. //==================================================================================
  286.  
  287. pascal void drawControl (short depth, short dFlags, GDHandle theDevice, long userData)
  288. {
  289. #pragma unused (dFlags, theDevice)
  290.     ControlHandle    theCtl;
  291.     short            varCode, xferMode, qdVers, lnHt,lnAdj;
  292.     OSErr            err;
  293.     Rect            ctlRect, offRect;
  294.     RgnHandle        saveClip, ctlClip = 0;
  295.     FontInfo        f;
  296.     PenState        savePen;
  297.     Boolean            grayOK = false, inColor = false, inactive = false, bwPort = true;
  298.     Boolean            bgInColor = false, pushBtn = false, useOffscreen = false;
  299.     RGBColor        saveFore={0,0,0}, saveBack={-1,-1,-1}, rgbGray;
  300. #ifdef _GRAYBUTTONS
  301.     RGBColor        bodyGray = {_GRAYSHADE, _GRAYSHADE, _GRAYSHADE};
  302. #endif
  303.     GrafPtr            thisPort;
  304.     CGrafPtr        savePort, offPort=0;
  305.     GDHandle        saveDevice;
  306.     PixMapHandle    offPix;
  307.     CDEFHandle        hCdef;
  308.     devLoopHandle    hDl;
  309.     
  310. //----------------------------------------------------------------------------------
  311. // Can we draw?
  312. //----------------------------------------------------------------------------------
  313.  
  314.     hDl = (devLoopHandle)userData;                        // need control & varCode
  315.     if(hDl) {
  316.         theCtl = (**hDl).theCtl;
  317.         varCode = (**hDl).varCode;
  318.     }
  319.     else {
  320.         return;
  321.     }
  322.         
  323.     hCdef = (CDEFHandle)(**theCtl).contrlData;
  324.     if(!hCdef) {
  325.         return;
  326.     }
  327.  
  328. //----------------------------------------------------------------------------------
  329. //    Figure out what kind of control we are drawing
  330. //----------------------------------------------------------------------------------
  331.  
  332.     if(varCode & useWindFont)
  333.         varCode ^= useWindFont;
  334.     
  335.     if(varCode != checkBoxProc && varCode != radioButProc) {
  336.         pushBtn = true;
  337.     }
  338.     
  339. //----------------------------------------------------------------------------------
  340. // Initialize for drawing    
  341. //----------------------------------------------------------------------------------
  342.     
  343.     if((*theCtl)->contrlHilite == 255)
  344.         inactive = true;
  345.     
  346.     GetPenState(&savePen);
  347.     GetPort(&thisPort);
  348.     ctlRect = offRect = (*theCtl)->contrlRect;
  349.         
  350.     if((thisPort->txFont != (**hCdef).txFont) ||        // if font changed,
  351.         (thisPort->txSize != (**hCdef).txSize) ||        // clear rect to erase
  352.         (thisPort->txFace != (**hCdef).txFace)) {        // old font
  353.         (**hCdef).txFont = thisPort->txFont;            
  354.         (**hCdef).txSize = thisPort->txSize;
  355.         (**hCdef).txFace = thisPort->txFace;
  356.         EraseRect(&ctlRect);
  357.     }
  358.  
  359.  
  360. //----------------------------------------------------------------------------------
  361. //    Should we draw in color?
  362. //
  363. //    What kind of port are we drawing to ?  DeviceLoop may have called us with a 
  364. //    depth > 1, but for an old-style 1 bit port ( but the GDevice is multi-bit). 
  365. //
  366. //    If so, then set depth to 1 unless we have Color Quickdraw and want to use
  367. //    offscreen drawing to force color controls in the old style grafport.
  368. //----------------------------------------------------------------------------------
  369.  
  370.     if((((CGrafPtr)thisPort)->portVersion & 0x8000))    // have a color grafPort
  371.         bwPort = false;
  372.  
  373. #ifdef _USEOFFSCREEN
  374.         
  375.     qdVers = getQDVers();
  376.     
  377.     if(bwPort && qdVers < gestalt32BitQD12)                // can't force colors
  378.         depth = 1;                                        // in b&w port unless
  379.                                                         // we have ColorQD
  380. #else
  381.  
  382.     if(bwPort)
  383.         depth = 1;
  384.  
  385. #endif
  386.  
  387.     if(depth > 2) {                                        // either color port or
  388.         inColor = true;                                    // color GDevice
  389.         saveColors(&saveFore, &saveBack);
  390.         bgInColor = true;
  391.         if(saveBack.red == 65535 &&                        // is bg white?
  392.             saveBack.green == 65535 &&
  393.             saveBack.blue == 65535)
  394.             bgInColor = false;
  395.     }
  396.  
  397. //----------------------------------------------------------------------------------
  398. //    Figure out how we should draw - offscreen or not...
  399. //----------------------------------------------------------------------------------
  400.  
  401. #ifdef _USEOFFSCREEN
  402.  
  403.     if(inColor && qdVers >= gestalt32BitQD12) {            // can use GWorlds
  404.         if(bwPort)                                        // to get 3D in b&w ports
  405.             useOffscreen = true;
  406.         else
  407.         if(!pushBtn && bgInColor)                        // or to avoid flicker on
  408.             useOffscreen = true;                        // radio/check titles
  409.     }
  410.     
  411. //----------------------------------------------------------------------------------
  412. // Can we draw off screen ?
  413. //----------------------------------------------------------------------------------
  414.  
  415.     if(useOffscreen) {
  416.         err = NewGWorld(&offPort, 0, &offRect, nil, nil, 0L);
  417.         if(err == noErr && offPort) {                    // got offscreen port
  418.             offPix = getLockedPixels(&offPort, qdVers);    // get pixels
  419.             if(offPix) {
  420.                 GetGWorld(&savePort, &saveDevice);        // save old port stuff
  421.                 SetGWorld(offPort, nil);                // set to offscreen port
  422.                 SetOrigin(offRect.left, offRect.top);    // and initialize it...
  423.                 RGBForeColor(&saveFore);            
  424.                 RGBBackColor(&saveBack);
  425.                 TextFont(thisPort->txFont);
  426.                 TextSize(thisPort->txSize);
  427.                 TextFace(thisPort->txFace);
  428.                 TextMode(srcOr);
  429.                 EraseRect(&offRect);
  430.             }
  431.             else {
  432.                 DisposeGWorld(offPort);
  433.                 offPort = 0;
  434.             }
  435.         }
  436.         else
  437.             offPort = 0;
  438.     }
  439.  
  440. #endif    // _USEOFFSCREEN
  441.  
  442. //----------------------------------------------------------------------------------
  443. //    Set the correct colors for drawing the control frames.
  444. //----------------------------------------------------------------------------------
  445.  
  446.     if(inColor) {
  447.         setPartColor(theCtl, cFrameColor, true);        // foreground
  448.         if(pushBtn) {
  449. #ifdef _GRAYBUTTONS
  450.             ForeColor(blackColor);                        // foreground
  451.             if(!(varCode & useWindBG)) {
  452.                 RGBBackColor(&bodyGray);                // background
  453.             }
  454. #else
  455.             if(!(varCode & useWindBG)) {
  456.                 setPartColor(theCtl, cBodyColor, false);// background
  457.             }
  458. #endif
  459.         }
  460.         if(inactive) {                                    // get a gray that is
  461.             if(getGray(&rgbGray))                        // relative to current
  462.                 RGBForeColor(&rgbGray);                    // fore & background colors
  463.         }
  464.     }
  465.     
  466. //----------------------------------------------------------------------------------
  467. //    Finish init of drawing port
  468. //    Set a 1 by 1, solid pattern pen for our drawing.
  469. //----------------------------------------------------------------------------------
  470.  
  471.     PenSize(1,1);
  472.     PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
  473.  
  474. //----------------------------------------------------------------------------------
  475. //    Get font info so the title lines up correctly
  476. //----------------------------------------------------------------------------------
  477.  
  478.     GetFontInfo(&f);                                    // needed for title routine
  479.     lnAdj = f.descent + f.leading;                
  480.     lnHt = f.ascent + lnAdj;
  481.     
  482. //----------------------------------------------------------------------------------
  483. //    Finally, draw controls into GWorld (if set, otherwise to screen).
  484. //----------------------------------------------------------------------------------
  485.  
  486.     if(varCode == checkBoxProc)
  487.         drawCheck(theCtl, &ctlRect, inColor);
  488.     else
  489.     if(varCode == radioButProc)
  490.         drawRadio(theCtl, &ctlRect, inColor, inactive);
  491.     else
  492.     if(pushBtn)
  493.         drawPush(theCtl, &offRect, varCode, inColor, lnHt, lnAdj);
  494.  
  495. //----------------------------------------------------------------------------------
  496. //    Set correct colors and draw the control titles.  Must set the correct fore/back
  497. //    colors so the getGray routine returns the correct gray for dimmed controls.    
  498. //----------------------------------------------------------------------------------
  499.  
  500.     if(inColor) {
  501.  
  502. #ifdef _EMBOSS    
  503.         if( !pushBtn && bgInColor) {
  504.             ForeColor(whiteColor);
  505.             drawTitle (theCtl, &offRect, varCode, lnHt, lnAdj, EMBOSS, !PUSHED);
  506.         }
  507. #endif
  508.  
  509.         setPartColor(theCtl, cTextColor, true);        // title color
  510.         
  511.         if(inactive) {                                // need a grayed title
  512.             if(pushBtn) {
  513. #ifdef _GRAYBUTTONS
  514.                 RGBBackColor(&bodyGray);
  515. #else
  516.                 setPartColor(theCtl, cBodyColor, false);
  517. #endif
  518.             }
  519.             else {
  520.                 RGBBackColor(&saveBack);
  521.             }
  522.             
  523.             grayOK = getGray(&rgbGray);
  524.             if(grayOK) {
  525.                 RGBForeColor(&rgbGray);
  526.             }
  527.         }
  528.     }
  529.     if(!pushBtn || inactive) {
  530.         drawTitle(theCtl, &offRect, varCode, lnHt, lnAdj, NORMAL, !PUSHED);
  531.     }
  532.  
  533. //----------------------------------------------------------------------------------
  534. //    If we drew offscreen, restore the onscreen port and blit the control image.
  535. //----------------------------------------------------------------------------------
  536.  
  537. #ifdef _USEOFFSCREEN
  538.  
  539.     if(offPort) {
  540.         SetGWorld(savePort, saveDevice);
  541.         
  542. //----------------------------------------------------------------------------------
  543. //    Blit the pushButton or titles for the other controls to the screen (avoiding 
  544. //    flicker on embossed titles).
  545. //----------------------------------------------------------------------------------
  546.  
  547.         if(pushBtn) {
  548.             xferMode = srcCopy;                        // cover any pattern completely
  549.             ForeColor(blackColor);
  550.             BackColor(whiteColor);
  551.         }
  552.         else {
  553.             xferMode = transparent;                    // overlay on pattern
  554.             restoreColors(&saveFore, &saveBack);
  555.             offRect.left+=14;
  556.             ctlRect.left+=14;
  557.         }
  558.         if(pushBtn || (**theCtl).contrlTitle[0])
  559.             CopyBits( &WINBITMAP( offPort ), &WINBITMAP( savePort ),
  560.                           &offRect, &ctlRect, xferMode, nil );
  561.                 
  562. //----------------------------------------------------------------------------------
  563. //    Finally, blit the checkBox & radioButton indicators to the screen.  Doing this
  564. //    last & with a proper clip region and srcCopy transfer mode insures that they 
  565. //    will appear correctly on patterned backgrounds or when drawn on top of a picture
  566. //    (as in Web browsers).
  567. //----------------------------------------------------------------------------------  
  568.  
  569.         if(!pushBtn) {
  570.             ForeColor(blackColor);
  571.             BackColor(whiteColor);
  572.             ctlRect.left-=14;
  573.             saveClip = NewRgn();
  574.             GetClip(saveClip);
  575.             ctlClip = NewRgn();
  576.             OpenRgn();
  577.             getIndicatorRect(&ctlRect, &offRect);
  578.             if(varCode == checkBoxProc) {
  579.                 if((offRect.top > ctlRect.top) && (offRect.bottom < ctlRect.bottom))
  580.                     InsetRect(&offRect, -1, -1);
  581.                 FrameRect(&offRect);
  582.             }
  583.             else
  584.                 FrameOval(&offRect);
  585.             CloseRgn(ctlClip);
  586.             SetClip(ctlClip);
  587.  
  588.             CopyBits( &WINBITMAP( offPort ), &WINBITMAP( savePort ),
  589.                       &offRect, &offRect, srcCopy, nil );
  590.  
  591.             SetClip(saveClip);
  592.             DisposeRgn(ctlClip);
  593.         }
  594.         unlockPixels(offPix, qdVers);
  595.         DisposeGWorld(offPort);
  596.     }
  597.  
  598. #endif // _USEOFFSCREEN
  599.     
  600. //----------------------------------------------------------------------------------
  601. // gray inactive controls the System 6 way if needed (couldn't get gray for title)
  602. //----------------------------------------------------------------------------------
  603.         
  604.     if(!grayOK && inactive) {                        // gray out the old way    
  605.         PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
  606.         PenMode(patBic);
  607.         if(pushBtn)
  608.             InsetRect(&ctlRect, 2, 2);                // only interior of button
  609.         else
  610.             ctlRect.left+=18;                        // not the indicator area
  611.         ClipRect(&ctlRect);
  612.         PaintRect(&ctlRect);
  613.     }
  614.  
  615. //----------------------------------------------------------------------------------
  616. // Clean up and leave    
  617. //----------------------------------------------------------------------------------
  618.                   
  619.     if(inColor)
  620.         restoreColors(&saveFore, &saveBack);
  621.     SetPenState(&savePen);
  622. }
  623.  
  624. //==================================================================================
  625. //    The push button drawing routine for a regular oval button
  626. //==================================================================================
  627.  
  628. static void drawPush(ControlHandle theCtl, Rect *r, short varCode, Boolean inColor, 
  629.                         short lnHt, short lnAdj)
  630. {
  631.     short        radius;
  632.     Boolean        pushed=false;
  633.     RGBColor    saveFore, saveBack;
  634.     
  635. //----------------------------------------------------------------------------------        
  636. // At least 1 lazy programmer has used narrow buttons to create 
  637. // simple lines to separate items in a dialog.  Hence this
  638. // funny looking check.
  639.  
  640.     if((r->bottom - r->top) < 5 || (r->right - r->left) < 5) {
  641.         FrameRect(r);
  642.         return;
  643.     }
  644.  
  645. //----------------------------------------------------------------------------------
  646.     
  647.     if((*theCtl)->contrlHilite == inButton ||
  648.             (**theCtl).contrlHilite == 1)
  649.         pushed = true;
  650.  
  651. //----------------------------------------------------------------------------------
  652. //    Set our colors for drawing the button.  ForeColor has been set to cFrameColor.
  653. //----------------------------------------------------------------------------------
  654.  
  655.  
  656.     if(inColor) {                                        // 3D button
  657.         saveColors(&saveFore, &saveBack);    
  658.  
  659. //----------------------------------------------------------------------------------
  660. //    Draw the button and title
  661. //----------------------------------------------------------------------------------
  662.  
  663.         do3DPush(theCtl, varCode, r, pushed);            // draw button
  664.         
  665.         drawTitle(theCtl, r, varCode, lnHt, lnAdj, EMBOSS, pushed);
  666.         
  667.         if((**theCtl).contrlHilite != 0xFF) {    
  668.             setPartColor(theCtl, cTextColor, true);
  669.             drawTitle(theCtl, r, varCode, lnHt, lnAdj, !EMBOSS, pushed);
  670.         }
  671.         restoreColors(&saveFore, &saveBack);
  672.     }
  673.  
  674. //----------------------------------------------------------------------------------
  675. //    If not in color, draw a button that is identical to the standard Mac button.
  676. //----------------------------------------------------------------------------------
  677.  
  678.     else {                                                // normal button
  679.         radius = (r->bottom - r->top)/2;
  680.         FillRoundRect(r, radius, radius, 
  681.                     (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00"); 
  682.         drawTitle(theCtl, r, varCode, lnHt, lnAdj, !EMBOSS, !PUSHED);
  683.         if(pushed)
  684.             InvertRoundRect(r, radius, radius);
  685.         FrameRoundRect(r, radius, radius);
  686.     }
  687. }
  688.  
  689. //==================================================================================
  690. //    A little utility routine to return that portion of the controlRect that the
  691. //    CheckBox or RadioButton should occupy.
  692. //==================================================================================
  693.  
  694. static void getIndicatorRect(Rect *ctlRect, Rect *r)
  695. {
  696.     Point    p;
  697.     
  698.     *r = *ctlRect;                                
  699.     p.h = r->left;
  700.     p.v = r->bottom - (r->bottom - r->top)/2 - 1;    // get pen loc for drawing
  701.     
  702.     r->left+=2;                                        // calculate the destination
  703.     r->bottom = p.v+7;                                // rect for a check/radio
  704.     r->right = r->left+12;                            // indicator
  705.     r->top = r->bottom-12;
  706. }
  707.  
  708. //==================================================================================
  709. //    The check box drawing routine
  710. //==================================================================================
  711.  
  712. static void drawCheck(ControlHandle theCtl, Rect *ctlRect, Boolean inColor)
  713. {    
  714.     Rect        r;
  715.     RGBColor    saveFore, saveBack, rgbA = {0xAAAA,0xAAAA,0xAAAA};
  716.     
  717.     getIndicatorRect(ctlRect, &r);
  718.     
  719.     if(inColor) {
  720.         saveColors(&saveFore, &saveBack);
  721.         BackColor(whiteColor);
  722.     }
  723.     
  724.     FillRect(&r, (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
  725.     FrameRect(&r);
  726.     
  727.     if(inColor) {                                    // a VERY slight
  728.         RGBForeColor(&rgbA);                        // 3D effect.
  729.         MoveTo(r.left-1,r.bottom);
  730.         LineTo(r.left-1,r.top-1);
  731.         LineTo(r.right,r.top-1);
  732.         
  733.         ForeColor(whiteColor);
  734.         Move(0,1);
  735.         LineTo(r.right,r.bottom);
  736.         LineTo(r.left,r.bottom);
  737.         
  738.         restoreColors(&saveFore, &saveBack);
  739.     }
  740.     
  741.     if((*theCtl)->contrlHilite == inCheckBox ||
  742.             (**theCtl).contrlHilite == 1) {            // hilited button
  743.         InsetRect(&r, 1, 1);
  744.         FrameRect(&r);
  745.         InsetRect(&r, -1, -1);
  746.     }
  747.     
  748.     if((*theCtl)->contrlValue != OFF) {                // button center
  749. #ifdef _REALCHECK
  750.         MoveTo(r.left+2,r.top+5);
  751.         Line(0,2);
  752.         Move(1,-1);
  753.         Line(0,2);
  754.         Move(1,-1);
  755.         Line(0,2);
  756.         Move(1,-1);
  757.         Line(0,-2);
  758.         Move(1,1);
  759.         Line(0,-2);
  760.         Move(1,1);
  761.         Line(0,-2);
  762.         Move(1,1);
  763.         Line(0,-2);
  764.         Move(1,1);
  765.         Line(0,-2);
  766. #else
  767.         MoveTo(r.right-2, r.top+1);
  768.         LineTo(r.left+1,  r.bottom-2);
  769.         MoveTo(r.left,  r.top);
  770.         LineTo(r.right-2, r.bottom-2);
  771. #endif        
  772.     }
  773. }
  774.  
  775. //==================================================================================
  776. //    The radio button drawing routine
  777. //==================================================================================
  778.  
  779. static void drawRadio(ControlHandle theCtl, Rect *ctlRect, Boolean inColor,
  780.                                      Boolean inactive)
  781. {    
  782.     Rect        r;
  783.     RGBColor    saveBack;
  784.  
  785.     getIndicatorRect(ctlRect, &r);
  786.         
  787.     if(inColor) {
  788.         GetBackColor(&saveBack);
  789.         BackColor(whiteColor);
  790.     }
  791.     
  792.     FillOval(&r, (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
  793.     FrameOval(&r);
  794.     
  795.     if(inColor && !inactive)
  796.         do3DRadio(theCtl, &r);                        // button shading
  797.     
  798.     if((*theCtl)->contrlHilite == inCheckBox ||
  799.             (**theCtl).contrlHilite == 1) {            // hilited button
  800.         InsetRect(&r, 1, 1);
  801.         FrameOval(&r);
  802.         InsetRect(&r, -1, -1);
  803.     }
  804.     if((*theCtl)->contrlValue != OFF) {                // button center
  805.         InsetRect(&r, 3, 3);    
  806.         PaintOval(&r);
  807.     }
  808.     if(inColor) 
  809.         RGBBackColor(&saveBack);
  810. }
  811.  
  812. //==================================================================================
  813. // Draw a shaded 3D radioButton with a "squishy" look.
  814. //==================================================================================
  815.  
  816. static void do3DRadio(ControlHandle theCtl, Rect *r)
  817. {
  818.     RGBColor    rgbA = {0xAAAA, 0xAAAA, 0xAAAA};
  819.     RGBColor    rgbB = {0xBBBB, 0xBBBB, 0xBBBB};
  820.     RGBColor    rgbD = {0xDDDD, 0xDDDD, 0xDDDD};
  821.     RGBColor    rgbE = {0xEEEE, 0xEEEE, 0xEEEE};
  822.     RGBColor    saveFore;
  823.     
  824.     GetForeColor(&saveFore);
  825.     
  826.     if((**theCtl).contrlValue) {                // button is ON, draw it so that
  827.         RGBForeColor(&rgbA);                    // it appears depressed.
  828.         MoveTo(r->right-5, r->top+1);
  829.         Line(-3,0);
  830.         Move(0,1);
  831.         Line(-2,0);
  832.         Move(1,1);
  833.         Line(-1,0);
  834.         Line(0,1);
  835.         Line(-1,0);
  836.         Line(0,3);
  837.         
  838.         RGBForeColor(&rgbB);
  839.         Move(1,2);
  840.         Line(0,-4);
  841.         Move(3,-3);
  842.         Line(3,0);
  843.         
  844.         RGBForeColor(&rgbD);
  845.         Move(0,1);
  846.         Line(0,0);
  847.         Move(-5,5);
  848.         Line(0,1);
  849.     }
  850.     else {                                        // button is OFF, draw so that
  851.         RGBForeColor(&rgbA);                    // it appears raised.
  852.         MoveTo(r->left+4, r->bottom-2);
  853.         Line(3,0);
  854.         Move(0,-1);
  855.         Line(2,0);
  856.         Move(-1,-1);
  857.         Line(1,0);
  858.         Line(0,-1);
  859.         Line(1,0);
  860.         Line(0,-3);
  861.         
  862.         RGBForeColor(&rgbB);
  863.         Move(-1,-2);
  864.         Line(0,4);
  865.         Line(-3,3);
  866.         Line(-1,0);
  867.         Move(1,-1);
  868.         Line(2,-2);
  869.         
  870.         RGBForeColor(&rgbD);
  871.         
  872.         Move(0,-1);
  873.         Line(0,-3);
  874.         Move(-1,4);
  875.         Line(-3,3);
  876.         Line(-1,0);
  877.         
  878.         RGBForeColor(&rgbE);
  879.         Move(0,-1);
  880.         Line(1,0);
  881.         Move(1,-1);
  882.         Line(2,-2);
  883.         Line(0,-4);
  884.         Move(-1,4);
  885.         Line(-2,2);
  886.     }
  887.     RGBForeColor(&saveFore);
  888. }
  889.  
  890. //==================================================================================
  891. // Draw the control titles - handles multiple lines and 3D embossing
  892. //==================================================================================
  893.  
  894. static void drawTitle (ControlHandle theCtl, Rect *ctlRect, short varCode, short lnHt, 
  895.                         short lnAdj, Boolean emboss, Boolean pushed)
  896. {
  897.     Rect            r;
  898.     short             inx=1,lnCnt=1,lnSpace,ctlSpace,v,h,adj=0;
  899.     Str255            s;
  900.     
  901.     if((*theCtl)->contrlTitle[0] == 0)
  902.         return;
  903.     r = *ctlRect;
  904.         
  905.     do {                                            // count number of lines
  906.         if((*theCtl)->contrlTitle[inx++] == 0x0d)    
  907.             lnCnt++;
  908.     }while (inx <= (*theCtl)->contrlTitle[0]);
  909.     
  910.     lnSpace = lnCnt * lnHt;                            // required space
  911.     ctlSpace = r.bottom - r.top;                    // available height
  912.     v = r.bottom;                                    // baseline
  913.     v-=(ctlSpace - lnSpace)/2;                        // minus free space
  914.     v-=lnAdj;                                        // minus descent+leading
  915.     v-=((lnCnt-1)*lnHt);                            // minus other lines
  916.                                                     // v is now base for line 1
  917.     for(inx=1;inx<=lnCnt;inx++) {
  918.         getNextLine((*theCtl)->contrlTitle, s, inx);
  919.         if(s[0]) {
  920.             if(varCode == radioButProc || varCode == checkBoxProc)
  921.                 h = r.left + 18;
  922.             else
  923.                 h = r.left + (r.right - r.left - StringWidth(s))/2;
  924.             
  925.             if(emboss & pushed)
  926.                 adj = -1;
  927.             else
  928.             if(emboss) 
  929.                 adj = 1;
  930.     
  931.             MoveTo(h+adj, v+adj);
  932.             DrawString(s);
  933.         }
  934.         v+=lnHt;
  935.     }
  936. }
  937.  
  938. //==================================================================================
  939. // Grab the next line of a control title (assumes lines separated by CR)
  940. //==================================================================================
  941.  
  942. static void getNextLine(Str255 t, Str255 s, short line)
  943. {
  944.     short    inx=1,len=0,lnCnt=1;
  945.     
  946.     s[0] = 0;                        // always default to null string
  947.     
  948.     do {
  949.         if(t[inx] == 0x0d)            // next line
  950.             lnCnt++;
  951.         else
  952.         if(lnCnt == line) {            // return this line
  953.             len++;
  954.             s[0] = len;
  955.             s[len] = t[inx];
  956.         }
  957.         inx++;
  958.     }while (inx <= t[0]);
  959. }
  960.  
  961. #ifdef _RECTPUSH
  962. //==================================================================================
  963. //    Utility routines for the Rectangular 3D push button
  964. //==================================================================================
  965. static void topLeftInner(Rect *r)
  966. {
  967.     MoveTo(r->right-3,r->top+2);
  968.     LineTo(r->left+2, r->top+2);
  969.     LineTo(r->left+2, r->bottom-3);
  970. }
  971. static void topLeftOuter(Rect *r)
  972. {
  973.     MoveTo(r->right-2,r->top+1);
  974.     LineTo(r->left+1, r->top+1);
  975.     LineTo(r->left+1, r->bottom-2);
  976. }
  977. static void bottomRightOuter(Rect *r)
  978. {
  979.     MoveTo(r->left+2, r->bottom-2);
  980.     LineTo(r->right-2,r->bottom-2);
  981.     LineTo(r->right-2,r->top+2);
  982. }
  983. static void bottomRightInner(Rect *r)
  984. {
  985.     MoveTo(r->left+3, r->bottom-3);
  986.     LineTo(r->right-3, r->bottom-3);
  987.     LineTo(r->right-3, r->top+3);
  988. }
  989.  
  990. //==================================================================================
  991. // Draw a Rectangular 3D pushButton
  992. //==================================================================================
  993.  
  994. static void do3DPush(ControlHandle theCtl, short varCode, Rect *r, Boolean pushed)
  995. {    
  996.     RGBColor    tingeColor[6];
  997.     Boolean        okToTinge=false;
  998.  
  999.     GetForeColor(&tingeColor[vDark]);
  1000.     GetBackColor(&tingeColor[vLight]);
  1001.     
  1002. #ifndef _GRAYBUTTONS
  1003.  
  1004.     if(tingeColor[vDark].red == 0 &&        // only use system tinge on b&w buttons
  1005.         tingeColor[vDark].green == 0 &&        // (i.e. without a custom 'cctb')
  1006.         tingeColor[vDark].blue  == 0 &&
  1007.         tingeColor[vLight].red == 65535 &&
  1008.         tingeColor[vLight].green == 65535 &&
  1009.         tingeColor[vLight].blue == 65535) {
  1010.         
  1011.         okToTinge = true;
  1012.     }
  1013.     
  1014.     if(!(varCode & useWindBG) && okToTinge) {
  1015.         setPartColor(theCtl, cBodyColor, false);    // set bgColor
  1016.         GetBackColor(&tingeColor[vLight]);
  1017.     }
  1018.  
  1019. #endif
  1020.         
  1021.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0xc, &tingeColor[dark]);
  1022.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x9, &tingeColor[medDark]);
  1023.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x7, &tingeColor[medLight]);
  1024.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x3, &tingeColor[light]);
  1025.     
  1026.     if(pushed) {
  1027.         RGBBackColor(&tingeColor[medLight]);
  1028.         RGBForeColor(&tingeColor[light]);
  1029.     }
  1030.     
  1031.     FillRect(r, (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00"); 
  1032.     
  1033.     RGBForeColor(&tingeColor[vDark]);
  1034.     FrameRect(r);
  1035.     
  1036.     if(pushed) {
  1037.         RGBForeColor(&tingeColor[dark]);
  1038.         topLeftOuter(r);
  1039.         
  1040.         RGBForeColor(&tingeColor[medDark]);
  1041.         topLeftInner(r);
  1042.         
  1043.         RGBForeColor(&tingeColor[light]);
  1044.         bottomRightInner(r);
  1045.         
  1046.         RGBForeColor(&tingeColor[vLight]);
  1047.         bottomRightOuter(r);
  1048.         RGBForeColor(&tingeColor[light]);
  1049.     }
  1050.     else {
  1051.         RGBForeColor(&tingeColor[vLight]);
  1052. #ifdef _USETINGE
  1053.         if(okToTinge) {
  1054.             setSysColor(cTingeLight, true);
  1055.         }
  1056. #endif
  1057.         topLeftOuter(r);
  1058.         
  1059.         ForeColor(whiteColor);
  1060.         topLeftInner(r);
  1061.         
  1062.         RGBForeColor(&tingeColor[light]);
  1063. #ifdef _USETINGE
  1064.         if(okToTinge) {
  1065.             setSysColor(cTingeLight, true);
  1066.         }
  1067. #endif
  1068.         bottomRightInner(r);
  1069.         
  1070.         RGBForeColor(&tingeColor[medLight]);
  1071.         bottomRightOuter(r);
  1072.         ForeColor(whiteColor);
  1073.     }
  1074. }
  1075. #else
  1076.  
  1077. //==================================================================================
  1078. //    Utility routines for the Oval 3D push button
  1079. //==================================================================================
  1080.  
  1081. static void topLeftInner(Rect *r)
  1082. {
  1083.     MoveTo(r->right-4, r->top+2);
  1084.     LineTo(r->left+3, r->top+2);
  1085.     Move(0,1);
  1086.     LineTo(r->left+2, r->top+3);
  1087.     LineTo(r->left+2, r->bottom-4);
  1088. }
  1089. static void topLeftOuter(Rect *r)
  1090. {
  1091.     MoveTo(r->right-4,r->top+1);
  1092.     LineTo(r->left+3,r->top+1);
  1093.     Move(-1,1);
  1094.     LineTo(r->left+2,r->top+2);
  1095.     Move(-1,1);
  1096.     LineTo(r->left+1,r->bottom-4);
  1097. }
  1098. static void bottomRightOuter(Rect *r)
  1099. {
  1100.     MoveTo(r->left+3, r->bottom-2);
  1101.     LineTo(r->right-4,r->bottom-2);
  1102.     Move(1,-1);
  1103.     LineTo(r->right-2,r->bottom-4);
  1104.     LineTo(r->right-2,r->top+3);
  1105. }
  1106. static void bottomRightInner(Rect *r)
  1107. {
  1108.     MoveTo(r->left+2, r->bottom-3);
  1109.     LineTo(r->right-4, r->bottom-3);
  1110.     Move(0,-1);
  1111.     LineTo(r->right-3, r->bottom-4);
  1112.     LineTo(r->right-3, r->top+2);
  1113. }
  1114.  
  1115. //==================================================================================
  1116. // Draw an Oval 3D pushButton
  1117. //==================================================================================
  1118. static void do3DPush(ControlHandle theCtl, short varCode, Rect *r, Boolean pushed)
  1119. {
  1120.     RGBColor    tingeColor[6];
  1121.     Boolean        okToTinge=false;
  1122.  
  1123.     GetForeColor(&tingeColor[vDark]);
  1124.     GetBackColor(&tingeColor[vLight]);
  1125.     
  1126. #ifndef _GRAYBUTTONS
  1127.  
  1128.     if(tingeColor[vDark].red == 0 &&        // only use system tinge on b&w buttons
  1129.         tingeColor[vDark].green == 0 &&        // (i.e. without a custom 'cctb')
  1130.         tingeColor[vDark].blue  == 0 &&
  1131.         tingeColor[vLight].red == 65535 &&
  1132.         tingeColor[vLight].green == 65535 &&
  1133.         tingeColor[vLight].blue == 65535) {
  1134.         
  1135.         okToTinge = true;
  1136.     }
  1137.     
  1138.     if(!(varCode & useWindBG) && okToTinge) {
  1139.         setPartColor(theCtl, cBodyColor, false);    // set bgColor
  1140.         GetBackColor(&tingeColor[vLight]);
  1141.     }
  1142.  
  1143. #endif
  1144.     
  1145.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0xc, &tingeColor[dark]);
  1146.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x9, &tingeColor[medDark]);
  1147.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x7, &tingeColor[medLight]);
  1148.     mixColor(&tingeColor[vLight], &tingeColor[vDark], 0x3, &tingeColor[light]);
  1149.     
  1150.     if(pushed) {
  1151.         RGBBackColor(&tingeColor[medLight]);
  1152.         RGBForeColor(&tingeColor[light]);
  1153.     }
  1154.     
  1155.     FillRoundRect(r, 10, 10, 
  1156.                     (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00"); 
  1157.         
  1158.     RGBForeColor(&tingeColor[vDark]);
  1159.     FrameRoundRect(r, 10, 10);
  1160.     
  1161.     if(pushed) {
  1162.         RGBForeColor(&tingeColor[dark]);
  1163.         topLeftOuter(r);
  1164.         
  1165.         RGBForeColor(&tingeColor[medDark]);
  1166.         topLeftInner(r);
  1167.         
  1168.         RGBForeColor(&tingeColor[light]);
  1169.         bottomRightInner(r);
  1170.         
  1171.         RGBForeColor(&tingeColor[vLight]);
  1172.         bottomRightOuter(r);
  1173.         RGBForeColor(&tingeColor[light]);
  1174.     }
  1175.     else {
  1176.     
  1177.         RGBForeColor(&tingeColor[vLight]);
  1178. #ifdef _USETINGE
  1179.         if(okToTinge) {
  1180.             setSysColor(cTingeLight, true);
  1181.         }
  1182. #endif
  1183.         topLeftOuter(r);
  1184.         
  1185.         ForeColor(whiteColor);
  1186.         topLeftInner(r);
  1187.         
  1188.         RGBForeColor(&tingeColor[light]);
  1189. #ifdef _USETINGE
  1190.         if(okToTinge) {
  1191.             setSysColor(cTingeLight, true);
  1192.         }
  1193. #endif
  1194.         bottomRightInner(r);
  1195.         
  1196.         RGBForeColor(&tingeColor[medLight]);
  1197.         bottomRightOuter(r);
  1198.         ForeColor(whiteColor);
  1199.     }
  1200. }
  1201. #endif
  1202.  
  1203. //==================================================================================
  1204. //    NOTICE: This routine stolen from Troy Gaul & the Infinity Windoid.
  1205. //    Thanks, Troy!
  1206. //==================================================================================
  1207.  
  1208. static void mixColor(RGBColor *light, RGBColor *dark, short shade, 
  1209.                         RGBColor *result) 
  1210. {
  1211.     shade = 0x0F - shade;
  1212.         // This is necessary because we give shades between light and
  1213.         // dark (0% is light), but for colors, $0000 is black and $FFFF 
  1214.         // is dark.
  1215.  
  1216.     result->red      = (long) (light->red   - dark->red)   * shade / 15 + dark->red;
  1217.     result->green = (long) (light->green - dark->green) * shade / 15 + dark->green;
  1218.     result->blue  = (long) (light->blue  - dark->blue)  * shade / 15 + dark->blue;
  1219. }
  1220.  
  1221. #ifdef _USEOFFSCREEN
  1222.  
  1223. //==================================================================================
  1224. // Lock down the offPort pixels and return a locked handle to the locked pixels
  1225. //==================================================================================
  1226.  
  1227. static PixMapHandle getLockedPixels(CGrafPtr * offPort, short qdVers)
  1228. {
  1229.     PixMapHandle    pmHdl;
  1230.     
  1231.     if(qdVers >= gestalt32BitQD13) {                    // no bug in the
  1232.         pmHdl = GetGWorldPixMap(*offPort);                // GetGWorldPixMap routine
  1233.         if(!LockPixels(pmHdl)) {
  1234.                 pmHdl = 0;
  1235.         }
  1236.     }
  1237.     else
  1238.         pmHdl = (*offPort)->portPixMap;
  1239.     
  1240.     if(pmHdl)
  1241.         HLock((Handle)pmHdl);
  1242.     return(pmHdl);
  1243. }
  1244.  
  1245. //==================================================================================
  1246. //    Unlock PixMapHandle & pixels
  1247. //==================================================================================
  1248.  
  1249. static void unlockPixels(PixMapHandle pmHdl, short qdVers)
  1250. {    
  1251.     if(pmHdl) {
  1252.         HUnlock((Handle)pmHdl);
  1253.         if(qdVers >= gestalt32BitQD13) {                // no bug in the
  1254.             UnlockPixels(pmHdl);                        // GetGWorldPixMap routine
  1255.         }
  1256.     }
  1257. }
  1258.  
  1259. //==================================================================================
  1260. //    Return QD version number from Gestalt 
  1261. //==================================================================================
  1262.  
  1263. static short getQDVers()        
  1264. {
  1265.     OSErr        err;
  1266.     long        gResult;
  1267.     
  1268.     if(trapAvailable(_Gestalt)) {        
  1269.         err = Gestalt(gestaltQuickdrawVersion,&gResult);
  1270.         if(err == noErr)
  1271.             return(LoWord(gResult));
  1272.     }
  1273.     return(gestaltOriginalQD);
  1274. }
  1275.  
  1276. #endif // _USEOFFSCREEN