home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 August / August CD.bin / Shareware / Programming / Infinity Windoid WDEF 2.6 / WindoidUtil.c < prev    next >
Encoding:
Text File  |  1994-04-01  |  15.1 KB  |  535 lines  |  [TEXT/MPS ]

  1. // *****************************************************************************
  2. //
  3. //    FILE:
  4. //        WindoidUtil.c
  5. //
  6. //    WRITTEN BY:
  7. //        Troy Gaul
  8. //        Infinity Systems
  9. //
  10. //        © 1991-94 Infinity Systems
  11. //        All rights reserved.
  12. //
  13. //    DESCRIPTION:
  14. //        This file contains utility routines that the Infinity Windoid
  15. //        WDEF uses in order to get its job done.
  16. //
  17. //    HOW TO CONTACT THE AUTHOR:
  18. //        Send e-mail to: t-gaul@i-link.com
  19. //
  20. // *****************************************************************************
  21.  
  22. // *****************************************************************************
  23. //    Headers
  24. // -----------------------------------------------------------------------------
  25.  
  26. #include "WindoidDefines.h"            // must be included before Apple interfaces
  27.  
  28. #include <Types.h>
  29. #include <Memory.h>
  30. #include <QuickDraw.h>
  31. #include <OSUtils.h>
  32. #include <Windows.h>
  33. #include <Palettes.h>
  34. #include <ToolUtils.h>
  35. #include <GestaltEqu.h>
  36.  
  37. #include "WindoidTypes.h"
  38. #include "WindoidUtil.h"
  39.  
  40. // *****************************************************************************
  41. //    Environment-determining Routines                                                                             
  42. // -----------------------------------------------------------------------------
  43.     //    These use SysEnvirons by default so we don't have to rely on Gestalt 
  44.     //    being available and so MPW won't include that code in our resource. 
  45.     //    This can be changed by defining USE_GESTALT
  46.  
  47. Boolean 
  48. HasSystem7(void) {
  49. #ifndef USE_GESTALT
  50.     SysEnvRec theWorld;
  51.     
  52.     return (SysEnvirons(1, &theWorld) == noErr 
  53.             && theWorld.systemVersion >= 0x0700);
  54. #else   
  55.     long vers = 0;
  56.     
  57.     return (Gestalt(gestaltSystemVersion, &vers) == noErr 
  58.             && ((vers & 0xFFFF) >= 0x0700));
  59. #endif
  60. }
  61.  
  62. // -----------------------------------------------------------------------------
  63.  
  64. Boolean 
  65. HasCQDraw(void) {
  66. #ifndef USE_GESTALT
  67.     SysEnvRec theWorld;
  68.     
  69.     return ((SysEnvirons(1, &theWorld) == noErr) && 
  70.             theWorld.hasColorQD);
  71. #else
  72.      long vers = 0;
  73.     
  74.     return (Gestalt(gestaltQuickdrawVersion, &vers) == noErr 
  75.             && (vers & 0xFF00));
  76. #endif  
  77. }
  78.  
  79. // *****************************************************************************
  80. //    SyncPorts
  81. // -----------------------------------------------------------------------------
  82.     //    Straight from the pages of _Macintosh Programming Secrets_, Second 
  83.     //    Edition by Scott Knaster and Keith Rollin (page 425). (except that this
  84.     //    version doesn't check Gestalt, it will only be called if CQD is running)
  85.     //    This routines was added to 2.3. It makes sure the drawing environment 
  86.     //    is set correctly if the system has color. This is not needed for the 
  87.     //    code in this WDEF as it is, but if a DoWDrawGIcon handler is implemented, 
  88.     //    this is needed to make sure the drawing environment is set as Apple 
  89.     //    tells us it will be for drawing the gray, xor'ed border.
  90.  
  91. void 
  92. SyncPorts(void) {
  93.     GrafPtr bwPort;
  94.     CGrafPtr colorPort;
  95.     
  96.     GetWMgrPort(&bwPort);
  97.     GetCWMgrPort(&colorPort);
  98.     SetPort((GrafPtr) colorPort);
  99.     
  100.     BlockMove(&bwPort->pnLoc, &colorPort->pnLoc, 10);
  101.     BlockMove(&bwPort->pnVis, &colorPort->pnVis, 14);
  102.     PenPat((ConstPatternParam) &bwPort->pnPat);
  103.     BackPat((ConstPatternParam) &bwPort->bkPat);
  104. }
  105.  
  106. // *****************************************************************************
  107. //    OurDeviceLoop
  108. // -----------------------------------------------------------------------------
  109. #ifndef SYS7_OR_LATER
  110.  
  111. #ifdef UNIV_HEADERS
  112.  
  113. void 
  114. OurDeviceLoop(RgnHandle drawingRgn, DeviceLoopDrawingUPP drawingProc,
  115.               long userData, DeviceLoopFlags flags) {
  116. #else
  117.  
  118. void 
  119. OurDeviceLoop(RgnHandle drawingRgn, DeviceLoopDrawingProcPtr drawingProc,
  120.               long userData, DeviceLoopFlags flags) {
  121. #endif
  122.  
  123.     if (HasSystem7()) {
  124.         DeviceLoop(drawingRgn, drawingProc, userData, flags);
  125.             // this works with or without Color Quickdraw
  126.     } else if (HasCQDraw()) {
  127.         short depth;
  128.         Rect deviceRect;
  129.         GDHandle theDevice;
  130.         RgnHandle saveClip = NewRgn();
  131.         RgnHandle deviceRgn = NewRgn();
  132.         RgnHandle intersectingRgn = NewRgn();
  133.         
  134.         GetClip(saveClip);
  135.         
  136.         
  137.         //    Get the handle to the first device in the list.
  138.         
  139.         theDevice = GetDeviceList();
  140.         
  141.         
  142.         //    Loop through all the devices in the list.
  143.         
  144.         while (theDevice) {
  145.             
  146.             // Get the device's gdRect and convert it to local coordinates.
  147.             
  148.             deviceRect = (**theDevice).gdRect;
  149.             depth = (**(**theDevice).gdPMap).pixelSize;
  150.             
  151.             GlobalToLocal((Point*)&deviceRect.top);
  152.             GlobalToLocal((Point*)&deviceRect.bottom);
  153.             
  154.             
  155.             //    Check if the app's window rect intersects the device's, and if it
  156.             //    does, set the clip region's rect to the intersection, then DRAW!
  157.             
  158.             RectRgn(deviceRgn, &deviceRect);
  159.             SectRgn(drawingRgn, deviceRgn, intersectingRgn);
  160.             SectRgn(intersectingRgn, saveClip, intersectingRgn);
  161.             
  162.             if (!EmptyRgn(intersectingRgn)) {
  163.                 SetClip(intersectingRgn);
  164.  
  165. #ifdef UNIV_HEADERS
  166.                 CallDeviceLoopDrawingProc(drawingProc, depth, 
  167.                                           (**theDevice).gdFlags, theDevice, 
  168.                                           userData);
  169. #else
  170.                 (*drawingProc)(depth, (**theDevice).gdFlags, theDevice, userData);
  171. #endif
  172.             }
  173.             
  174.             
  175.             //    Get the next device in the list.
  176.             
  177.             theDevice = GetNextDevice(theDevice);
  178.         }
  179.         
  180.         SetClip(saveClip);
  181.         DisposeRgn(saveClip);
  182.         DisposeRgn(deviceRgn);
  183.         DisposeRgn(intersectingRgn);
  184.     } else {
  185.  
  186.         //    68000 machine, original QuickDraw, punt
  187.  
  188. #ifdef UNIV_HEADERS
  189.         CallDeviceLoopDrawingProc(drawingProc, 1, 0, nil, userData);
  190. #else
  191.         (*drawingProc)(1, 0, nil, userData);
  192. #endif
  193.     }
  194. }
  195.  
  196. #endif
  197. // *****************************************************************************
  198. //    Color Mixing Routines                                                                     
  199. // -----------------------------------------------------------------------------
  200.  
  201. //    This routine will return some defaults in case neither the window's color
  202. //    table nor the System's is long enough to contain the color requested
  203. //    It was provided by Jim Petrick as part of a fix for a bug in version 2.3
  204. //    of the Infinity Windoid. This problem would be seen if a custom WCTB was
  205. //    being used which was not as long as the default System one (or if the
  206. //    System one had been changed to a shorter size). The rest of Jim's fix
  207. //    can be found in GetWctbColor.
  208.  
  209. static void 
  210. UseDefaultColor(short index, RGBColor *theColor) {
  211.     switch (index) {
  212.         case wContentColor:            //     0
  213.         case wTitleBarColor:        //     4
  214.         case wHiliteColorLight:        //     5
  215.         case wTitleBarLight:        //     7
  216.             theColor->red = theColor->green = theColor->blue = 0xFFFF;
  217.             break;
  218.                 
  219.         case wDialogLight:            //     9
  220.         case wTingeLight:            //    11
  221.             theColor->red = theColor->green = 0xCCCC;
  222.             theColor->blue = 0xFFFF;
  223.             break;
  224.         
  225.         case wTingeDark:            //    12
  226.             theColor->red = theColor->green = 0x3333;
  227.             theColor->blue = 0x6666;
  228.             break;
  229.  
  230.         default:
  231.             theColor->red = theColor->green = theColor->blue = 0;
  232.             break;
  233.     }
  234. }
  235.  
  236. // -----------------------------------------------------------------------------
  237.  
  238. static void 
  239. GetWctbColor(WindowPeek window, short partCode, RGBColor *theColor) {
  240.     
  241.     //    Given a partCode, return the RGBColor associated with it. (Using the
  242.     //    default window color table.)
  243.     
  244.     AuxWinHandle awHndl;
  245.     short count;
  246.     
  247.     
  248.     //    Get the Color table for the window if it has one.
  249.  
  250.     (void) GetAuxWin((WindowPtr) window, &awHndl); 
  251.     count = (**(WCTabHandle) ((**awHndl).awCTable)).ctSize;
  252.     
  253.  
  254.     //    If the table didn't contain the entry of interest, look to the 
  255.     //    default table.
  256.     
  257.     if (count < partCode) {
  258.         GetAuxWin(nil, &awHndl); 
  259.         count = (**(WCTabHandle) ((**awHndl).awCTable)).ctSize;
  260.     }
  261.             
  262.  
  263.     //    If the entry is there, use it, if not make a best guess at a default value.
  264.  
  265.     if (count < partCode)
  266.         UseDefaultColor(partCode, theColor);
  267.     else
  268.         *theColor = (**(WCTabHandle) ((**awHndl).awCTable)).ctTable[partCode].rgb;
  269. }
  270.  
  271. // -----------------------------------------------------------------------------
  272.  
  273. void 
  274. WctbForeColor(WindowPeek window, short partCode) {
  275.     RGBColor theColor;
  276.  
  277.     GetWctbColor(window, partCode, &theColor);
  278.     RGBForeColor(&theColor);
  279. }
  280.  
  281. // -----------------------------------------------------------------------------
  282.  
  283. void
  284. WctbBackColor(WindowPeek window, short partCode) {
  285.     RGBColor theColor;
  286.  
  287.     GetWctbColor(window, partCode, &theColor);
  288.     RGBBackColor(&theColor);
  289. }
  290.  
  291. // -----------------------------------------------------------------------------
  292. #pragma processor 68020
  293.     //    Note: this is okay because this will only be called if we are
  294.     //    doing System 7 color, which requires Color Quickdraw, which is only
  295.     //    available on systems with 68020's or better. This is done to reduce
  296.     //    code size. If it isn't compiled this way, several routines will be
  297.     //    added to the code WDEF resource to handle the long integer arithmetic.
  298.  
  299. static void 
  300. MixColor(const RGBColor *light, const RGBColor *dark, 
  301.          short shade, RGBColor *result) {
  302.     shade = 0x0F - shade;
  303.         //    This is necessary because we give shades between light and
  304.         //    dark (0% is light), but for colors, $0000 is black and $FFFF 
  305.         //    is dark.
  306.  
  307.     result->red      = (long) (light->red   - dark->red)   * shade / 15 + dark->red;
  308.     result->green = (long) (light->green - dark->green) * shade / 15 + dark->green;
  309.     result->blue  = (long) (light->blue  - dark->blue)  * shade / 15 + dark->blue;
  310. }
  311.  
  312. #pragma processor 68000
  313. // -----------------------------------------------------------------------------
  314.  
  315. static void 
  316. AvgWctbColor(WindowPeek window, short light, short dark, short shade, 
  317.              RGBColor *theColor) {
  318.  
  319.     // Mix two parts by the given shade, which is actually a value
  320.     // between 0 (0%) and 15 (100%), return the RGBColor.
  321.  
  322.     RGBColor lightColor;
  323.     RGBColor darkColor;
  324.  
  325.     GetWctbColor(window, light, &lightColor);
  326.     GetWctbColor(window, dark, &darkColor);
  327.     MixColor(&lightColor, &darkColor, shade, theColor);
  328. }
  329.  
  330. // -----------------------------------------------------------------------------
  331.  
  332. void 
  333. AvgWctbForeColor(WindowPeek window, short light, short dark, short shade) {
  334.     RGBColor theColor;
  335.     
  336.     AvgWctbColor(window, light, dark, shade, &theColor);
  337.     RGBForeColor(&theColor);
  338. }
  339.  
  340. // -----------------------------------------------------------------------------
  341.  
  342. void 
  343. AvgWctbBackColor(WindowPeek window, short light, short dark, short shade) {
  344.     RGBColor theColor;
  345.     
  346.     AvgWctbColor(window, light, dark, shade, &theColor);
  347.     RGBBackColor(&theColor);
  348. }
  349.  
  350. // *****************************************************************************
  351. //    CheckDisplay -- Check to see if we are using color title bars
  352. // -----------------------------------------------------------------------------
  353.  
  354. static Boolean 
  355. CheckAvailable(WindowPeek window, short light, short dark, 
  356.                short count, short *ramp) {
  357.  
  358.     //    Given a light and dark index value, a count, and and an array of
  359.     //    'percentage' values (0x0 to 0xF, or 0 to 15), see if each of the
  360.     //    values in the ramp maps to a different color on the screen. If not,
  361.     //    we need to use black-and-white.
  362.     
  363.     RGBColor theColor;
  364.     short i;
  365.     short colorIndex = 0;
  366.     short lastIndex;
  367.     
  368.     for (i = 0 ; i < count ; i++) {
  369.         AvgWctbColor(window, light, dark, ramp[i], &theColor);    
  370.         
  371.         lastIndex = colorIndex;
  372.         colorIndex = Color2Index(&theColor);
  373.         
  374.         if (i > 0 && colorIndex == lastIndex)    // return false if two entries
  375.             return false;                        // have the same index value
  376.     }
  377.     return true;
  378. }
  379.  
  380. // -----------------------------------------------------------------------------
  381.  
  382. short 
  383. CheckDisplay(short theDepth, short deviceFlags, 
  384.              GDHandle targetDevice, WindowPeek window) {
  385.     Boolean        inColor;
  386.     short        result;
  387.     RGBColor    testColor;
  388.     GDHandle    saveDevice;
  389.         
  390.     inColor = HasCQDraw() && (deviceFlags & (0x0001 << gdDevType));
  391.     
  392.     result = blackandwhite;                    // assume Black and White
  393.  
  394. #ifdef NOT_PBOOK_AWARE
  395.     if (theDepth >= 4) {
  396. #else
  397.     if (theDepth >= 4 && (**targetDevice).gdType != fixedType) {
  398. #endif
  399.  
  400. #ifndef SYS7_OR_LATER
  401.         if (!HasSystem7()) {
  402.             result = sys6color;                // System 6.0.x Color
  403.         } else {
  404. #endif
  405.             GetWctbColor(window, wTingeLight, &testColor);
  406.             if (testColor.red != 0 || testColor.green != 0 || testColor.blue != 0) 
  407.                 // check for B&W control panel setting, otherwise:
  408.                 result = sys7color;            // System 7.0 Color
  409. #ifndef SYS7_OR_LATER
  410.         }
  411. #endif
  412.     }
  413.     //    Note: Since I didn't find another way to see if the user had changed
  414.     //    the settings in the Color control panel to the Black-and-white setting,
  415.     //    I actually check to see if the rgb components of the light tinge color
  416.     //    are non-zero (which seemed to be the case with that setting). 
  417.     
  418.     
  419.     //    This part checks to see if there are 'enough' colors to draw the 
  420.     //    title bar in color under System 7. It is supposed to do so in the
  421.     //    same way that Apple's system WDEF does. I essentially took the 
  422.     //    assembly code that Apple released and tried to make this use the
  423.     //    same algorithm.
  424.  
  425.     if (result == sys7color && inColor && theDepth <= 8) {
  426.         short ramp[5];
  427.             // Make sure this array is allocated big enough for the largest ramp.
  428.         
  429.         result = blackandwhite;
  430.         saveDevice = GetGDevice();
  431.         SetGDevice(targetDevice);
  432.  
  433.         ramp[0] = 0x00;
  434.         ramp[1] = 0x07;
  435.         ramp[2] = 0x08;
  436.         ramp[3] = 0x0A;
  437.         ramp[4] = 0x0D;
  438.         if (CheckAvailable(window, wHiliteColorLight, wHiliteColorDark, 5, ramp)) {
  439.             ramp[0] = 0x00;
  440.             ramp[1] = 0x01;
  441.             ramp[2] = 0x04;
  442.             if (CheckAvailable(window, wTitleBarLight, wTitleBarDark, 3, ramp)) {
  443.                 ramp[0] = 0x00;
  444.                 ramp[1] = 0x04;
  445.                 ramp[2] = 0x0F;
  446.                 if (CheckAvailable(window, wTingeLight, wTingeDark, 3, ramp))
  447.                     result = sys7color;
  448.             }
  449.         }
  450.         SetGDevice(saveDevice);
  451.     }
  452.     
  453.  
  454.     return result;
  455. }
  456.  
  457. // *****************************************************************************
  458. //    Color Utility routines
  459. // -----------------------------------------------------------------------------
  460.  
  461. void
  462. ColorsNormal(void) {
  463.     ForeColor(blackColor);
  464.     BackColor(whiteColor);
  465. }
  466.  
  467. // *****************************************************************************
  468. //    General Helper Functions
  469. // -----------------------------------------------------------------------------
  470.  
  471. void 
  472. FrameBox(const Rect *theRect) {
  473.     Rect tempRect = *theRect;
  474.     
  475.     FrameRect(theRect);
  476.     InsetRect(&tempRect, 1, 1);
  477.     EraseRect(&tempRect);
  478. }
  479.  
  480. // -----------------------------------------------------------------------------
  481.  
  482. void
  483. FrameTopLeftShading(Rect theRect) {
  484.     theRect.right--;        // compensate for the way the rectangle hangs
  485.     theRect.bottom--;
  486.  
  487.     MoveTo(theRect.left,  theRect.bottom);            //    •••••
  488.     LineTo(theRect.left,  theRect.top   );            //    •
  489.     LineTo(theRect.right, theRect.top   );            //    •
  490. }
  491.  
  492. // -----------------------------------------------------------------------------
  493.  
  494. void
  495. FrameBottomRightShading(Rect theRect) {
  496.     theRect.right--;        // compensate for the way the rectangle hangs
  497.     theRect.bottom--;
  498.  
  499.     MoveTo(theRect.left,  theRect.bottom);            //        •
  500.     LineTo(theRect.right, theRect.bottom);            //        •
  501.     LineTo(theRect.right, theRect.top   );            //    •••••
  502. }
  503.  
  504. // *****************************************************************************
  505.  
  506. void
  507. GetGlobalMappingPoint(WindowPeek window, Point *thePoint) {
  508.  
  509.     //    This routine returns a point that gives the horizontal and vertical
  510.     //  offsets needed to map something into global coordinates.
  511.  
  512.     GrafPtr savePort;
  513.     
  514.     GetPort(&savePort);
  515.     SetPort((GrafPtr) window);
  516.     
  517.     SetPt(thePoint, 0, 0);
  518.     LocalToGlobal(thePoint);
  519.     
  520.     SetPort(savePort);
  521. }
  522.  
  523. // -----------------------------------------------------------------------------
  524.  
  525. void 
  526. GetGlobalContentRect(WindowPeek window, Rect *contentRect) {
  527.     Point mappingPoint;
  528.  
  529.     *contentRect = window->port.portRect;
  530.     GetGlobalMappingPoint(window, &mappingPoint);
  531.     OffsetRect(contentRect, mappingPoint.h, mappingPoint.v);
  532. }
  533.  
  534. // *****************************************************************************
  535.