home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tk42r2s.zip / tk4.2 / os2 / tkOS2Draw.c < prev    next >
C/C++ Source or Header  |  1999-07-26  |  69KB  |  2,101 lines

  1. /* 
  2.  * tkOS2Draw.c --
  3.  *
  4.  *    This file contains the Xlib emulation functions pertaining to
  5.  *    actually drawing objects on a window.
  6.  *
  7.  * Copyright (c) 1996-1998 Illya Vaes
  8.  * Copyright (c) 1995 Sun Microsystems, Inc.
  9.  * Copyright (c) 1994 Software Research Associates, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  */
  14.  
  15.  
  16. #include "tkOS2Int.h"
  17.  
  18. #define PI 3.14159265358979
  19. #define XAngleToRadians(a) ((double)(a) / 64 * PI / 180)
  20.  
  21. /*
  22.  * Translation tables between X gc values and OS/2 GPI line attributes.
  23.  */
  24.  
  25. static int lineStyles[] = {
  26.     LINETYPE_SOLID,    /* LineSolid */
  27.     LINETYPE_SHORTDASH,    /* LineOnOffDash */
  28.     LINETYPE_SHORTDASH    /* LineDoubleDash EXTRA PROCESSING NECESSARY */
  29. };
  30. static int capStyles[] = {
  31.     LINEEND_FLAT,    /* CapNotLast EXTRA PROCESSING NECESSARY */
  32.     LINEEND_FLAT,    /* CapButt */
  33.     LINEEND_ROUND,    /* CapRound */
  34.     LINEEND_SQUARE    /* CapProjecting */
  35. };
  36. static int joinStyles[] = {
  37.     LINEJOIN_MITRE,    /* JoinMiter */
  38.     LINEJOIN_ROUND,    /* JoinRound */
  39.     LINEJOIN_BEVEL    /* JoinBevel */
  40. };
  41.  
  42. /*
  43.  * Translation table between X gc functions and OS/2 GPI mix attributes.
  44.  */
  45.  
  46. static int mixModes[] = {
  47.     FM_ZERO,            /* GXclear */
  48.     FM_AND,            /* GXand */
  49.     FM_MASKSRCNOT,        /* GXandReverse */
  50.     FM_OVERPAINT,        /* GXcopy */
  51.     FM_SUBTRACT,        /* GXandInverted */
  52.     FM_LEAVEALONE,        /* GXnoop */
  53.     FM_XOR,            /* GXxor */
  54.     FM_OR,            /* GXor */
  55.     FM_NOTMERGESRC,        /* GXnor */
  56.     FM_NOTXORSRC,        /* GXequiv */
  57.     FM_INVERT,            /* GXinvert */
  58.     FM_MERGESRCNOT,        /* GXorReverse */
  59.     FM_NOTCOPYSRC,        /* GXcopyInverted */
  60.     FM_MERGENOTSRC,        /* GXorInverted */
  61.     FM_NOTMASKSRC,        /* GXnand */
  62.     FM_ONE            /* GXset */
  63. };
  64.  
  65.  
  66. /*
  67.  * Translation table between X gc functions and OS/2 GPI BitBlt raster op modes.
  68.  * Some of the operations defined in X don't have names, so we have to construct
  69.  * new opcodes for those functions.  This is arcane and probably not all that
  70.  * useful, but at least it's accurate.
  71.  */
  72.  
  73. #define NOTSRCAND    (LONG)0x0022 /* dest = (NOT source) AND dest */
  74. #define NOTSRCINVERT    (LONG)0x0099 /* dest = (NOT source) XOR dest */
  75. #define SRCORREVERSE    (LONG)0x00dd /* dest = source OR (NOT dest) */
  76. #define SRCNAND        (LONG)0x0077 /* dest = (NOT source) OR (NOT dest) */
  77.  
  78. static int bltModes[] = {
  79.     ROP_ZERO,            /* GXclear */
  80.     ROP_SRCAND,            /* GXand */
  81.     ROP_SRCERASE,        /* GXandReverse */
  82.     ROP_SRCCOPY,        /* GXcopy */
  83.     NOTSRCAND,            /* GXandInverted */
  84.     ROP_PATCOPY,        /* GXnoop */
  85.     ROP_SRCINVERT,        /* GXxor */
  86.     ROP_SRCPAINT,        /* GXor */
  87.     ROP_NOTSRCERASE,        /* GXnor */
  88.     NOTSRCINVERT,        /* GXequiv */
  89.     ROP_DSTINVERT,        /* GXinvert */
  90.     SRCORREVERSE,        /* GXorReverse */
  91.     ROP_NOTSRCCOPY,        /* GXcopyInverted */
  92.     ROP_MERGEPAINT,        /* GXorInverted */
  93.     SRCNAND,            /* GXnand */
  94.     ROP_ONE            /* GXset */
  95. };
  96.  
  97. /*
  98.  * The following raster op uses the source bitmap as a mask for the
  99.  * pattern.  This is used to draw in a foreground color but leave the
  100.  * background color transparent.
  101.  */
  102.  
  103. #define MASKPAT        0x00e2 /* dest = (src & pat) | (!src & dst) */
  104.  
  105. /*
  106.  * The following two raster ops are used to copy the foreground and background
  107.  * bits of a source pattern as defined by a stipple used as the pattern.
  108.  */
  109.  
  110. #define COPYFG        0x00ca /* dest = (pat & src) | (!pat & dst) */
  111. #define COPYBG        0x00ac /* dest = (!pat & src) | (pat & dst) */
  112.  
  113. /*
  114.  * Macros used later in the file.
  115.  */
  116.  
  117. #ifndef MIN
  118. #define MIN(a,b)    ((a>b) ? b : a)
  119. #endif
  120. #ifndef MAX
  121. #define MAX(a,b)    ((a<b) ? b : a)
  122. #endif
  123.  
  124. /*
  125.  * Forward declarations for procedures defined in this file:
  126.  */
  127.  
  128. static POINTL *        ConvertPoints (Drawable d, XPoint *points, int npoints,
  129.                 int mode, RECTL *bbox);
  130. static void        DrawOrFillArc (Display *display,
  131.                 Drawable d, GC gc, int x, int y,
  132.                 unsigned int width, unsigned int height,
  133.                 int angle1, int angle2, int fill);
  134. static void        RenderObject (HPS hps, GC gc, Drawable d,
  135.                             XPoint* points, int npoints, int mode,
  136.                             PLINEBUNDLE lineBundle, int func);
  137. static void        TkOS2SetStipple(HPS destPS, HPS bmpPS, HBITMAP stipple,
  138.                 LONG x, LONG y, LONG *oldPatternSet,
  139.                 PPOINTL oldRefPoint);
  140. static void        TkOS2UnsetStipple(HPS destPS, HPS bmpPS, HBITMAP stipple,
  141.                 LONG oldPatternSet, PPOINTL oldRefPoint);
  142.  
  143. /*
  144.  *----------------------------------------------------------------------
  145.  *
  146.  * TkOS2GetDrawablePS --
  147.  *
  148.  *    Retrieve the Presentation Space from a drawable.
  149.  *
  150.  * Results:
  151.  *    Returns the window PS for windows.  Returns the associated memory PS
  152.  *    for pixmaps.
  153.  *
  154.  * Side effects:
  155.  *    Sets up the palette for the presentation space, and saves the old
  156.  *    presentation space state in the passed in TkOS2PSState structure.
  157.  *
  158.  *----------------------------------------------------------------------
  159.  */
  160.  
  161. HPS
  162. TkOS2GetDrawablePS(display, d, state)
  163.     Display *display;
  164.     Drawable d;
  165.     TkOS2PSState* state;
  166. {
  167.     HPS hps;
  168.     TkOS2Drawable *todPtr = (TkOS2Drawable *)d;
  169.     Colormap cmap;
  170.  
  171.     if (todPtr->type != TOD_BITMAP) {
  172.         TkWindow *winPtr = todPtr->window.winPtr;
  173.  
  174.     hps = WinGetPS(todPtr->window.handle);
  175.         if (winPtr == NULL) {
  176.         cmap = DefaultColormap(display, DefaultScreen(display));
  177.         } else {
  178.         cmap = winPtr->atts.colormap;
  179.         }
  180.         state->palette = TkOS2SelectPalette(hps, todPtr->window.handle, cmap);
  181.     } else {
  182.  
  183.         hps = todPtr->bitmap.hps;
  184.         cmap = todPtr->bitmap.colormap;
  185.         state->palette = TkOS2SelectPalette(hps, todPtr->bitmap.parent, cmap);
  186.     }
  187.     return hps;
  188. }
  189.  
  190. /*
  191.  *----------------------------------------------------------------------
  192.  *
  193.  * TkOS2ReleaseDrawablePS --
  194.  *
  195.  *    Frees the resources associated with a drawable's DC.
  196.  *
  197.  * Results:
  198.  *    None.
  199.  *
  200.  * Side effects:
  201.  *    Restores the old bitmap handle to the memory DC for pixmaps.
  202.  *
  203.  *----------------------------------------------------------------------
  204.  */
  205.  
  206. void
  207. TkOS2ReleaseDrawablePS(d, hps, state)
  208.     Drawable d;
  209.     HPS hps;
  210.     TkOS2PSState *state;
  211. {
  212.     ULONG changed;
  213.     HPAL oldPal;
  214.     TkOS2Drawable *todPtr = (TkOS2Drawable *)d;
  215.  
  216.     oldPal = GpiSelectPalette(hps, state->palette);
  217.     if (todPtr->type != TOD_BITMAP) {
  218.         WinRealizePalette(TkOS2GetHWND(d), hps, &changed);
  219.         WinReleasePS(hps);
  220.     } else {
  221.         WinRealizePalette(todPtr->bitmap.parent, hps, &changed);
  222.     }
  223. }
  224.  
  225. /*
  226.  *----------------------------------------------------------------------
  227.  *
  228.  * ConvertPoints --
  229.  *
  230.  *    Convert an array of X points to an array of OS/2 GPI points.
  231.  *
  232.  * Results:
  233.  *    Returns the converted array of POINTLs.
  234.  *
  235.  * Side effects:
  236.  *    Allocates a block of memory that should not be freed.
  237.  *
  238.  *----------------------------------------------------------------------
  239.  */
  240.  
  241. static POINTL *
  242. ConvertPoints(d, points, npoints, mode, bbox)
  243.     Drawable d;
  244.     XPoint *points;
  245.     int npoints;
  246.     int mode;            /* CoordModeOrigin or CoordModePrevious. */
  247.     RECTL *bbox;            /* Bounding box of points. */
  248. {
  249.     static POINTL *os2Points = NULL; /* Array of points that is reused. */
  250.     static int nOS2Points = -1;        /* Current size of point array. */
  251.     LONG windowHeight;
  252.     int i;
  253.  
  254.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)d);
  255.  
  256.     /*
  257.      * To avoid paying the cost of a malloc on every drawing routine,
  258.      * we reuse the last array if it is large enough.
  259.      */
  260.  
  261.     if (npoints > nOS2Points) {
  262.     if (os2Points != NULL) {
  263.         ckfree((char *) os2Points);
  264.     }
  265.     os2Points = (POINTL *) ckalloc(sizeof(POINTL) * npoints);
  266.     if (os2Points == NULL) {
  267.         nOS2Points = -1;
  268.         return NULL;
  269.     }
  270.     nOS2Points = npoints;
  271.     }
  272.  
  273.     /* Convert to PM Coordinates */
  274.     bbox->xLeft = bbox->xRight = points[0].x;
  275.     bbox->yTop = bbox->yBottom = windowHeight - points[0].y;
  276.     
  277.     if (mode == CoordModeOrigin) {
  278.     for (i = 0; i < npoints; i++) {
  279.         os2Points[i].x = points[i].x;
  280.         /* convert to PM */
  281.         os2Points[i].y = windowHeight - points[i].y;
  282.         bbox->xLeft = MIN(bbox->xLeft, os2Points[i].x);
  283.         /* Since GpiBitBlt excludes top & right, add one */
  284.         bbox->xRight = MAX(bbox->xRight, os2Points[i].x + 1);
  285.         /* y: min and max switched for PM */
  286.         bbox->yTop = MAX(bbox->yTop, os2Points[i].y + 1);
  287.         bbox->yBottom = MIN(bbox->yBottom, os2Points[i].y);
  288.     }
  289.     } else {
  290.     os2Points[0].x = points[0].x;
  291.     os2Points[0].y = windowHeight - points[0].y;
  292.     for (i = 1; i < npoints; i++) {
  293.         os2Points[i].x = os2Points[i-1].x + points[i].x;
  294.         /* convert to PM */
  295.         os2Points[i].y = os2Points[i-1].y -
  296.                          (windowHeight - points[i].y);
  297.         bbox->xLeft = MIN(bbox->xLeft, os2Points[i].x);
  298.         /* Since GpiBitBlt excludes top & right, add one */
  299.         bbox->xRight = MAX(bbox->xRight, os2Points[i].x + 1);
  300.         /* y: min and max switched for PM */
  301.         bbox->yTop = MAX(bbox->yTop, os2Points[i].y + 1);
  302.         bbox->yBottom = MIN(bbox->yBottom, os2Points[i].y);
  303.     }
  304.     }
  305.     return os2Points;
  306. }
  307.  
  308. /*
  309.  *----------------------------------------------------------------------
  310.  *
  311.  * XCopyArea --
  312.  *
  313.  *    Copies data from one drawable to another using block transfer
  314.  *    routines.
  315.  *
  316.  * Results:
  317.  *    None.
  318.  *
  319.  * Side effects:
  320.  *    Data is moved from a window or bitmap to a second window or
  321.  *    bitmap.
  322.  *
  323.  *----------------------------------------------------------------------
  324.  */
  325.  
  326. void
  327. XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y)
  328.     Display* display;
  329.     Drawable src;
  330.     Drawable dest;
  331.     GC gc;
  332.     int src_x, src_y;
  333.     unsigned int width, height;
  334.     int dest_x, dest_y;
  335. {
  336.     HPS srcPS, destPS;
  337.     TkOS2PSState srcState, destState;
  338.     TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
  339.     POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
  340.     BOOL rc;
  341.     LONG windowHeight;
  342.     HRGN oldReg;
  343.  
  344.     /* Translate the Y coordinates to PM coordinates */
  345.     /* Determine height of window */
  346.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)dest);
  347.     aPoints[0].x = dest_x;
  348.     aPoints[0].y = windowHeight - dest_y - height;
  349.     aPoints[1].x = dest_x + width;
  350.     aPoints[1].y = windowHeight - dest_y;
  351.     aPoints[2].x = src_x;
  352.     if (src != dest) {
  353.         windowHeight = TkOS2WindowHeight((TkOS2Drawable *)src);
  354.     }
  355.     aPoints[2].y = windowHeight - src_y - height;
  356.     srcPS = TkOS2GetDrawablePS(display, src, &srcState);
  357.  
  358.     if (src != dest) {
  359.     destPS = TkOS2GetDrawablePS(display, dest, &destState);
  360.     } else {
  361.     destPS = srcPS;
  362.     }
  363.  
  364. /*
  365.     if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  366.         if (GpiSetClipRegion(destPS, (HRGN) clipPtr->value.region, &oldReg)
  367.             != RGN_ERROR) {
  368.             POINTL offset;
  369.             offset.x = gc->clip_x_origin;
  370. */
  371.             /* Reverse Y coordinates */
  372. /*
  373.             offset.y = - gc->clip_y_origin;
  374.             rc = GpiOffsetClipRegion(destPS, &offset);
  375. #ifdef DEBUG
  376.             printf("GpiOffsetClipRegion %dx%d into %x %s\n", offset.x,
  377.                    offset.y, destPS, rc == RGN_NULL ? "RGN_NULL" :
  378.                                      (rc == RGN_RECT ? "RGN_RECT" :
  379.                                      (rc == RGN_COMPLEX ? "RGN_COMPLEX" :
  380.                                      "RGN_ERROR")));
  381. #endif
  382.         }
  383. #ifdef DEBUG
  384.           else {
  385.             printf("GpiSetClipRegion %x into %x RGN_ERROR\n",
  386.                    clipPtr->value.region, destPS);
  387.         }
  388. #endif
  389.     }
  390. */
  391.  
  392.     rc = GpiBitBlt(destPS, srcPS, 3, aPoints, bltModes[gc->function],
  393.                    BBO_IGNORE);
  394.  
  395.     if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  396.         GpiSetClipRegion(destPS, oldReg, &oldReg);
  397.     }
  398.  
  399.     if (src != dest) {
  400.     TkOS2ReleaseDrawablePS(dest, destPS, &destState);
  401.     }
  402.     TkOS2ReleaseDrawablePS(src, srcPS, &srcState);
  403. }
  404.  
  405. /*
  406.  *----------------------------------------------------------------------
  407.  *
  408.  * XCopyPlane --
  409.  *
  410.  *    Copies a bitmap from a source drawable to a destination
  411.  *    drawable.  The plane argument specifies which bit plane of
  412.  *    the source contains the bitmap.  Note that this implementation
  413.  *    ignores the gc->function.
  414.  *
  415.  * Results:
  416.  *    None.
  417.  *
  418.  * Side effects:
  419.  *    Changes the destination drawable.
  420.  *
  421.  *----------------------------------------------------------------------
  422.  */
  423.  
  424. void
  425. XCopyPlane(display, src, dest, gc, src_x, src_y, width, height, dest_x,
  426.     dest_y, plane)
  427.     Display* display;
  428.     Drawable src;
  429.     Drawable dest;
  430.     GC gc;
  431.     int src_x, src_y;
  432.     unsigned int width, height;
  433.     int dest_x, dest_y;
  434.     unsigned long plane;
  435. {
  436.     HPS srcPS, destPS;
  437.     TkOS2PSState srcState, destState;
  438.     TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
  439.     LONG oldPattern;
  440.     LONG oldMix, oldBackMix;
  441.     LONG oldColor, oldBackColor;
  442.     LONG srcWindowHeight, destWindowHeight;
  443.     POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
  444.     LONG rc;
  445.     HRGN oldReg;
  446.  
  447.     /* Translate the Y coordinates to PM coordinates */
  448.     destWindowHeight = TkOS2WindowHeight((TkOS2Drawable *)dest);
  449.     if (src != dest) {
  450.         srcWindowHeight = TkOS2WindowHeight((TkOS2Drawable *)src);
  451.     } else {
  452.         srcWindowHeight = destWindowHeight;
  453.     }
  454.     aPoints[0].x = dest_x;
  455.     aPoints[0].y = destWindowHeight - dest_y - height;
  456.     aPoints[1].x = dest_x + width;
  457.     aPoints[1].y = destWindowHeight - dest_y;
  458.     aPoints[2].x = src_x;
  459.     aPoints[2].y = srcWindowHeight - src_y - height;
  460.     display->request++;
  461.  
  462.     if (plane != 1) {
  463.     panic("Unexpected plane specified for XCopyPlane");
  464.     }
  465.  
  466.     srcPS = TkOS2GetDrawablePS(display, src, &srcState);
  467.  
  468.     if (src != dest) {
  469.     destPS = TkOS2GetDrawablePS(display, dest, &destState);
  470.     } else {
  471.     destPS = srcPS;
  472.     }
  473.  
  474.     if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) {
  475.  
  476.         /*
  477.          * Case 1: opaque bitmaps.  Windows handles the conversion
  478.          * from one bit to multiple bits by setting 0 to the
  479.          * foreground color, and 1 to the background color (seems
  480.          * backwards, but there you are).
  481.          */
  482.  
  483.         if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  484.             if (GpiSetClipRegion(destPS, (HRGN) clipPtr->value.region, &oldReg)
  485.                 != RGN_ERROR) {
  486.                 POINTL offset;
  487.                 offset.x = gc->clip_x_origin;
  488.                 /* Reverse Y coordinates */
  489.                 offset.y = - gc->clip_y_origin;
  490.                 GpiOffsetClipRegion(destPS, &offset);
  491.             }
  492.         }
  493.  
  494.         oldColor = GpiQueryColor(destPS);
  495.         oldBackColor = GpiQueryBackColor(destPS);
  496.         oldMix = GpiQueryMix(destPS);
  497.         oldBackMix = GpiQueryBackMix(destPS);
  498.  
  499.         /*
  500.         rc= GpiSetColor(destPS, gc->foreground);
  501.         */
  502.         rc= GpiSetColor(destPS, gc->background);
  503.         /*
  504.         rc= GpiSetBackColor(destPS, gc->background);
  505.         */
  506.         rc= GpiSetBackColor(destPS, gc->foreground);
  507.  
  508.         rc = GpiBitBlt(destPS, srcPS, 3, aPoints, ROP_SRCCOPY, BBO_IGNORE);
  509.         rc= GpiSetColor(destPS, oldColor);
  510.         rc= GpiSetBackColor(destPS, oldBackColor);
  511.         rc= GpiSetMix(destPS, oldMix);
  512.         rc= GpiSetBackMix(destPS, oldBackMix);
  513.  
  514.         GpiSetClipRegion(destPS, oldReg, &oldReg);
  515.     } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
  516.         if (clipPtr->value.pixmap == src) {
  517.  
  518.             /*
  519.              * Case 2: transparent bitmaps are handled by setting the
  520.              * destination to the foreground color whenever the source
  521.              * pixel is set.
  522.              */
  523.         oldColor = GpiQueryColor(destPS);
  524.             oldBackColor = GpiQueryBackColor(destPS);
  525.         oldPattern = GpiQueryPattern(destPS);
  526.         GpiSetColor(destPS, gc->foreground);
  527.             rc= GpiSetBackColor(destPS, gc->background);
  528.         GpiSetPattern(destPS, PATSYM_SOLID);
  529.             rc = GpiBitBlt(destPS, srcPS, 3, aPoints, MASKPAT, BBO_IGNORE);
  530.         GpiSetPattern(destPS, oldPattern);
  531.             GpiSetBackColor(destPS, oldBackColor);
  532.         GpiSetColor(destPS, oldColor);
  533.         } else {
  534.  
  535.             /*
  536.              * Case 3: two arbitrary bitmaps.  Copy the source rectangle
  537.              * into a color pixmap.  Use the result as a brush when
  538.              * copying the clip mask into the destination.
  539.              */
  540.  
  541.             HPS memPS, maskPS;
  542.             BITMAPINFOHEADER2 bmpInfo;
  543.             HBITMAP bitmap, oldBitmap;
  544.             TkOS2PSState maskState;
  545.     
  546.             oldColor = GpiQueryColor(destPS);
  547.             oldPattern = GpiQueryPattern(destPS);
  548.     
  549.             maskPS = TkOS2GetDrawablePS(display, clipPtr->value.pixmap,
  550.                                         &maskState);
  551.             memPS = WinGetScreenPS(HWND_DESKTOP);
  552.             bmpInfo.cbFix = sizeof(BITMAPINFOHEADER2);
  553.             bmpInfo.cx = width;
  554.             bmpInfo.cy = height;
  555.             bmpInfo.cPlanes = 1;
  556.             bmpInfo.cBitCount = 1;
  557.             bitmap = GpiCreateBitmap(memPS, &bmpInfo, 0L, NULL, NULL);
  558.             oldBitmap = GpiSetBitmap(memPS, bitmap);
  559.     
  560.             /*
  561.              * Set foreground bits.  We create a new bitmap containing
  562.              * (source AND mask), then use it to set the foreground color
  563.              * into the destination.
  564.              */
  565.     
  566.             /* Translate the Y coordinates to PM coordinates */
  567.             aPoints[0].x = 0; /* dest_x = 0 */
  568.             aPoints[0].y = destWindowHeight - height; /* dest_y = 0 */
  569.             aPoints[1].x = width;
  570.             aPoints[1].y = destWindowHeight;
  571.             aPoints[2].x = src_x;
  572.             aPoints[2].y = srcWindowHeight - src_y - height;
  573.             rc = GpiBitBlt(memPS, srcPS, 3, aPoints, ROP_SRCCOPY, BBO_IGNORE);
  574.             /* Translate the Y coordinates to PM coordinates */
  575.             aPoints[0].x = 0; /* dest_x = 0 */
  576.             aPoints[0].y = destWindowHeight - height; /* dest_y = 0 */
  577.             aPoints[1].x = dest_x + width;
  578.             aPoints[1].y = destWindowHeight;
  579.             aPoints[2].x = dest_x - gc->clip_x_origin;
  580.             aPoints[2].y = srcWindowHeight - dest_y + gc->clip_y_origin -
  581.                            height;
  582.             rc = GpiBitBlt(memPS, maskPS, 3, aPoints, ROP_SRCAND, BBO_IGNORE);
  583.             /* Translate the Y coordinates to PM coordinates */
  584.             aPoints[0].x = dest_x;
  585.             aPoints[0].y = destWindowHeight - dest_y - height;
  586.             aPoints[1].x = dest_x + width;
  587.             aPoints[1].y = destWindowHeight - dest_y;
  588.             aPoints[2].x = 0; /* src_x = 0 */
  589.             aPoints[2].y = srcWindowHeight - height; /* src_y = 0 */
  590.             GpiSetColor(destPS, gc->foreground);
  591.             GpiSetPattern(destPS, PATSYM_SOLID);
  592.             rc = GpiBitBlt(destPS, memPS, 3, aPoints, MASKPAT, BBO_IGNORE);
  593.     
  594.             /*
  595.              * Set background bits.  Same as foreground, except we use
  596.              * ((NOT source) AND mask) and the background brush.
  597.              */
  598.     
  599.             /* Translate the Y coordinates to PM coordinates */
  600.             aPoints[0].x = 0; /* dest_x = 0 */
  601.             aPoints[0].y = destWindowHeight - height; /* dest_y = 0 */
  602.             aPoints[1].x = width;
  603.             aPoints[1].y = destWindowHeight;
  604.             aPoints[2].x = src_x;
  605.             aPoints[2].y = srcWindowHeight - src_y - height;
  606.             rc = GpiBitBlt(memPS, srcPS, 3, aPoints, ROP_NOTSRCCOPY,
  607.                            BBO_IGNORE);
  608.             /* Translate the Y coordinates to PM coordinates */
  609.             aPoints[0].x = 0; /* dest_x = 0 */
  610.             aPoints[0].y = destWindowHeight - height; /* dest_y = 0 */
  611.             aPoints[1].x = dest_x + width;
  612.             aPoints[1].y = destWindowHeight;
  613.             aPoints[2].x = dest_x - gc->clip_x_origin;
  614.             aPoints[2].y = destWindowHeight - dest_y + gc->clip_y_origin -
  615.                            height;
  616.             rc = GpiBitBlt(memPS, maskPS, 3, aPoints, ROP_SRCAND, BBO_IGNORE);
  617.             GpiSetColor(destPS, gc->background);
  618.             GpiSetPattern(destPS, PATSYM_SOLID);
  619.             /* Translate the Y coordinates to PM coordinates */
  620.             aPoints[0].x = dest_x;
  621.             aPoints[0].y = destWindowHeight - dest_y - height;
  622.             aPoints[1].x = dest_x + width;
  623.             aPoints[1].y = destWindowHeight - dest_y;
  624.             aPoints[2].x = 0; /* src_x = 0 */
  625.             aPoints[2].y = srcWindowHeight - height; /* src_y = 0 */
  626.             rc = GpiBitBlt(destPS, memPS, 3, aPoints, MASKPAT, BBO_IGNORE);
  627.     
  628.             TkOS2ReleaseDrawablePS(clipPtr->value.pixmap, maskPS, &maskState);
  629.             GpiSetPattern(destPS, oldPattern);
  630.             GpiSetColor(destPS, oldColor);
  631.             GpiSetBitmap(memPS, oldBitmap);
  632.             GpiDeleteBitmap(bitmap);
  633.             WinReleasePS(memPS);
  634.         }
  635.     }
  636.  
  637.     if (src != dest) {
  638.     TkOS2ReleaseDrawablePS(dest, destPS, &destState);
  639.     }
  640.     TkOS2ReleaseDrawablePS(src, srcPS, &srcState);
  641. }
  642.  
  643. /*
  644.  *----------------------------------------------------------------------
  645.  *
  646.  * TkPutImage --
  647.  *
  648.  *    Copies a subimage from an in-memory image to a rectangle of
  649.  *    of the specified drawable.
  650.  *
  651.  * Results:
  652.  *    None.
  653.  *
  654.  * Side effects:
  655.  *    Draws the image on the specified drawable.
  656.  *
  657.  *----------------------------------------------------------------------
  658.  */
  659.  
  660. void
  661. TkPutImage(colors, ncolors, display, d, gc, image, src_x, src_y, dest_x,
  662.     dest_y, width, height)
  663.     unsigned long *colors;        /* Array of pixel values used by this
  664.                      * image.  May be NULL. */
  665.     int ncolors;            /* Number of colors used, or 0. */
  666.     Display* display;
  667.     Drawable d;                /* Destination drawable. */
  668.     GC gc;
  669.     XImage* image;            /* Source image. */
  670.     int src_x, src_y;            /* Offset of subimage. */      
  671.     int dest_x, dest_y;            /* Position of subimage origin in
  672.                      * drawable.  */
  673.     unsigned int width, height;        /* Dimensions of subimage. */
  674. {
  675.     HPS hps;
  676.     LONG rc;
  677.     TkOS2PSState state;
  678.     BITMAPINFOHEADER2 bmpInfo;
  679.     BITMAPINFO2 *infoPtr;
  680.     char *data;
  681.     LONG windowHeight;
  682.  
  683.     /* Translate the Y coordinates to PM coordinates */
  684.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)d);
  685.  
  686.     display->request++;
  687.  
  688.     hps = TkOS2GetDrawablePS(display, d, &state);
  689.  
  690.     rc = GpiSetMix(hps, mixModes[gc->function]);
  691.  
  692.     if (image->bits_per_pixel == 1) {
  693.  
  694.         /* Bitmap must be reversed in OS/2 wrt. the Y direction */
  695.         /* This is done best in a modified version of TkAlignImageData */
  696.     data = TkAlignImageData(image, sizeof(ULONG), MSBFirst);
  697.     bmpInfo.cbFix = 16L;
  698.     bmpInfo.cx = image->width;
  699.     bmpInfo.cy = image->height;
  700.     bmpInfo.cPlanes = 1;
  701.     bmpInfo.cBitCount = 1;
  702.         rc = GpiSetBitmapBits(hps, windowHeight - dest_y - height, height,
  703.                               (PBYTE)data, (BITMAPINFO2*) &bmpInfo);
  704.     ckfree(data);
  705.     } else {
  706.     int usePalette;
  707.  
  708.     /*
  709.      * Do not use a palette for TrueColor images.
  710.      */
  711.     
  712.     usePalette = (image->bits_per_pixel < 24);
  713.  
  714.     if (usePalette) {
  715.         infoPtr = (BITMAPINFO2*) ckalloc(sizeof(BITMAPINFO2)
  716.             + sizeof(RGB2)*ncolors);
  717.     } else {
  718.         infoPtr = (BITMAPINFO2*) ckalloc(sizeof(BITMAPINFO2));
  719.     }
  720.     if (infoPtr == NULL) return;
  721.  
  722.         /* Bitmap must be reversed in OS/2 wrt. the Y direction */
  723.     data = TkOS2ReverseImageLines(image, height);
  724.     
  725.     infoPtr->cbFix = sizeof(BITMAPINFOHEADER2);
  726.     infoPtr->cx = width;
  727.         infoPtr->cy = height;
  728.  
  729.  
  730.     infoPtr->cPlanes = 1;
  731.     infoPtr->cBitCount = image->bits_per_pixel;
  732.     infoPtr->ulCompression = BCA_UNCOMP;
  733.     infoPtr->cbImage = 0;
  734.     infoPtr->cxResolution = aDevCaps[CAPS_HORIZONTAL_RESOLUTION];
  735.     infoPtr->cyResolution = aDevCaps[CAPS_VERTICAL_RESOLUTION];
  736.     infoPtr->cclrUsed = 0;
  737.     infoPtr->cclrImportant = 0;
  738.     infoPtr->usUnits = BRU_METRIC;
  739.     infoPtr->usReserved = 0;
  740.     infoPtr->usRecording = BRA_BOTTOMUP;
  741.     infoPtr->usRendering = BRH_NOTHALFTONED;
  742.     infoPtr->cSize1 = 0L;
  743.     infoPtr->cSize2 = 0L;
  744.     infoPtr->ulColorEncoding = BCE_RGB;
  745.     infoPtr->ulIdentifier = 0L;
  746.  
  747.     if (usePalette) {
  748.         BOOL palManager = FALSE;
  749.  
  750.         if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  751.             palManager = TRUE;
  752.         }
  753.             if (palManager) {
  754.                 rc = GpiQueryPaletteInfo(GpiQueryPalette(hps), hps, 0, 0,
  755.                                          ncolors, (PLONG) &infoPtr->argbColor);
  756.             } else {
  757.                 rc = GpiQueryLogColorTable(hps, 0, 0, ncolors,
  758.                                            (PLONG) &infoPtr->argbColor);
  759.         }
  760.     } else {
  761.         infoPtr->cclrUsed = 0;
  762.     }
  763.  
  764.         rc = GpiSetBitmapBits(hps, windowHeight - dest_y - height, height,
  765.                               (PBYTE)data, infoPtr);
  766.     ckfree((char *)infoPtr);
  767.     ckfree(data);
  768.     }
  769.     TkOS2ReleaseDrawablePS(d, hps, &state);
  770. }
  771.  
  772. /*
  773.  *----------------------------------------------------------------------
  774.  *
  775.  * XDrawString --
  776.  *
  777.  *    Draw a single string in the current font.
  778.  *
  779.  * Results:
  780.  *    None.
  781.  *
  782.  * Side effects:
  783.  *    Renders the specified string in the drawable.
  784.  *
  785.  *----------------------------------------------------------------------
  786.  */
  787.  
  788. void
  789. XDrawString(display, d, gc, x, y, string, length)
  790.     Display* display;
  791.     Drawable d;
  792.     GC gc;
  793.     int x;
  794.     int y;
  795.     _Xconst char* string;
  796.     int length;
  797. {
  798.     HPS hps;
  799.     SIZEF oldCharBox;
  800.     LONG oldFont = 0L;
  801.     LONG oldHorAlign, oldVerAlign;
  802.     LONG oldBackMix;
  803.     LONG oldColor, oldBackColor = 0L;
  804.     POINTL oldRefPoint;
  805.     LONG oldPattern;
  806.     HBITMAP oldBitmap;
  807.     POINTL noShear= {0, 1};
  808.     TkOS2PSState state;
  809.     POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
  810.     CHARBUNDLE cBundle;
  811.     AREABUNDLE aBundle;
  812.     LONG windowHeight, l;
  813.     char *str;
  814.     POINTL refPoint;
  815.     BOOL rc;
  816.  
  817.     display->request++;
  818.  
  819.     if (d == None) {
  820.     return;
  821.     }
  822.  
  823.     hps = TkOS2GetDrawablePS(display, d, &state);
  824.     GpiSetMix(hps, mixModes[gc->function]);
  825.  
  826.     /* If this is an outline font, set the char box */
  827.     if (logfonts[(LONG)gc->font].outline) {
  828.         rc = GpiQueryCharBox(hps, &oldCharBox);
  829.         rc = TkOS2ScaleFont(hps, logfonts[(LONG)gc->font].deciPoints, 0);
  830.     }
  831.  
  832.     /* Translate the Y coordinates to PM coordinates */
  833.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)d);
  834.     y = windowHeight - y;
  835.  
  836.     if ((gc->fill_style == FillStippled || gc->fill_style == FillOpaqueStippled)
  837.         && gc->stipple != None) {
  838.  
  839.     TkOS2Drawable *todPtr = (TkOS2Drawable *)gc->stipple;
  840.     HDC dcMem;
  841.     HPS psMem;
  842.         DEVOPENSTRUC dop = {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
  843.         SIZEL sizl = {0,0}; /* use same page size as device */
  844.     HBITMAP bitmap;
  845.         BITMAPINFOHEADER2 bmpInfo;
  846.         RECTL rect;
  847.         POINTL textBox[TXTBOX_COUNT];
  848.  
  849.     if (todPtr->type != TOD_BITMAP) {
  850.         panic("unexpected drawable type in stipple");
  851.     }
  852.  
  853.     /*
  854.      * Select stipple pattern into destination PS.
  855.      * gc->ts_x_origin and y_origin are relative to origin of the
  856.      * destination drawable, while PatternRefPoint is in world coords.
  857.      */
  858.  
  859.     dcMem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&dop,
  860.                       NULLHANDLE);
  861.     if (dcMem == DEV_ERROR) {
  862.         return;
  863.     }
  864.         psMem = GpiCreatePS(hab, dcMem, &sizl,
  865.                             PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  866.         if (psMem == GPI_ERROR) {
  867.             DevCloseDC(dcMem);
  868.             return;
  869.         }
  870.     /*
  871.      * Compute the bounding box and create a compatible bitmap.
  872.      */
  873.  
  874.     rc = WinQueryWindowRect(((TkOS2Drawable *)d)->bitmap.parent, &rect);
  875.     bmpInfo.cbFix = 16L;
  876.     /*
  877.     bmpInfo.cx = rect.xRight - rect.xLeft;
  878.     bmpInfo.cy = rect.yTop - rect.yBottom;
  879.     */
  880.     bmpInfo.cx = xScreen;
  881.     bmpInfo.cy = yScreen;
  882.     bmpInfo.cPlanes = 1;
  883.     bmpInfo.cBitCount = display->screens[display->default_screen].root_depth;
  884.     bitmap = GpiCreateBitmap(psMem, &bmpInfo, 0L, NULL, NULL);
  885.         oldBitmap = GpiSetBitmap(psMem, bitmap);
  886.  
  887.     refPoint.x = gc->ts_x_origin;
  888.     refPoint.y = windowHeight - gc->ts_y_origin;
  889.  
  890.         /* The bitmap mustn't be selected in the HPS */
  891.         TkOS2SetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  892.                         refPoint.x, refPoint.y, &oldPattern, &oldRefPoint);
  893.  
  894.         GpiQueryTextAlignment(psMem, &oldHorAlign, &oldVerAlign);
  895.         GpiSetTextAlignment(psMem, TA_LEFT, TA_BASE);
  896.  
  897.         GpiQueryAttrs(psMem, PRIM_CHAR, LBB_COLOR, (PBUNDLE)&cBundle);
  898.         oldColor = cBundle.lColor;
  899.         cBundle.lColor = gc->foreground;
  900.         rc = GpiSetAttrs(psMem, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  901.         aBundle.lColor = gc->foreground;
  902.         rc = GpiSetAttrs(hps, PRIM_AREA, LBB_COLOR, 0L, (PBUNDLE)&aBundle);
  903.  
  904.     oldBackMix = GpiQueryBackMix(psMem);
  905.     rc = GpiSetBackMix(psMem, BM_LEAVEALONE);
  906.         oldBackColor = GpiQueryBackColor(psMem);
  907.         GpiSetBackColor(psMem, CLR_FALSE);
  908.  
  909.     if (gc->font != None) {
  910.             rc = GpiCreateLogFont(psMem, NULL, (LONG)gc->font,
  911.                                   &(logfonts[(LONG)gc->font].fattrs));
  912.         oldFont = GpiQueryCharSet(psMem);
  913.         rc = GpiSetCharSet(psMem, (LONG)gc->font);
  914.         /* Set slant if necessary */
  915.         if (logfonts[(LONG)gc->font].setShear) {
  916.             rc = GpiSetCharShear(psMem, &(logfonts[(LONG)gc->font].shear));
  917.         }
  918.             /* If this is an outline font, set the char box */
  919.             if (logfonts[(LONG)gc->font].outline) {
  920.                 rc = TkOS2ScaleFont(psMem, logfonts[(LONG)gc->font].deciPoints,
  921.                                     0);
  922.             }
  923.     }
  924.  
  925.         refPoint.x = x;
  926.         refPoint.y = y;
  927.         rc = GpiSetCurrentPosition(psMem, &refPoint);
  928.     rc = GpiQueryTextBox(psMem, length, (PCH)string, TXTBOX_COUNT, textBox);
  929.  
  930.         aPoints[0].x = refPoint.x + textBox[TXTBOX_BOTTOMLEFT].x;
  931.         aPoints[0].y = refPoint.y + textBox[TXTBOX_BOTTOMLEFT].y;
  932.         aPoints[1].x = refPoint.x + textBox[TXTBOX_TOPRIGHT].x;
  933.     aPoints[1].y = refPoint.y + textBox[TXTBOX_TOPRIGHT].y;
  934.         aPoints[2].x = refPoint.x + textBox[TXTBOX_BOTTOMLEFT].x;
  935.     aPoints[2].y = refPoint.y + textBox[TXTBOX_BOTTOMLEFT].y;
  936.  
  937.     /*
  938.      * The following code is tricky because fonts are rendered in multiple
  939.      * colors.  First we draw onto a black background and copy the white
  940.      * bits.  Then we draw onto a white background and copy the black bits.
  941.      * Both the foreground and background bits of the font are ANDed with
  942.      * the stipple pattern as they are copied.
  943.      */
  944.  
  945.         rc = GpiBitBlt(psMem, (HPS)0, 2, aPoints, ROP_ZERO, BBO_IGNORE);
  946.  
  947.         /* only 512 bytes allowed in string */
  948.         rc = GpiSetCurrentPosition(psMem, &refPoint);
  949.         l = length;
  950.         str = (char *)string;
  951.         while (length>512) {
  952.             rc = GpiCharString(psMem, l, (PCH)str);
  953.             l -= 512;
  954.             str += 512;
  955.         }
  956.         rc = GpiCharString(psMem, l, (PCH)str);
  957.  
  958.         rc = GpiBitBlt(hps, psMem, 3, aPoints, (LONG)0x00ea, BBO_IGNORE);
  959.  
  960.         rc = GpiBitBlt(psMem, (HPS)0, 2, aPoints, ROP_ONE, BBO_IGNORE);
  961.  
  962.         /* only 512 bytes allowed in string */
  963.         rc = GpiSetCurrentPosition(psMem, &refPoint);
  964.         l = length;
  965.         str = (char *)string;
  966.         while (length>512) {
  967.             rc = GpiCharString(psMem, 512, (PCH)str);
  968.             l -= 512;
  969.             str += 512;
  970.         }
  971.         rc = GpiCharString(psMem, l, (PCH)str);
  972.  
  973.         rc = GpiBitBlt(hps, psMem, 3, aPoints, (LONG)0x00ba, BBO_IGNORE);
  974.     /*
  975.      * Destroy the temporary bitmap and restore the device context.
  976.      */
  977.  
  978.     GpiSetBitmap(psMem, oldBitmap);
  979.     GpiDeleteBitmap(bitmap);
  980.     GpiDestroyPS(psMem);
  981.         DevCloseDC(dcMem);
  982.  
  983.     if (gc->font != None) {
  984.         /* Set slant if necessary */
  985.         if (logfonts[(LONG)gc->font].setShear) {
  986.             rc = GpiSetCharShear(hps, &noShear);
  987.         }
  988.         rc = GpiSetCharSet(hps, oldFont);
  989.     }
  990.     rc = GpiSetBackMix(hps, oldBackMix);
  991.     cBundle.lColor = oldColor;
  992.     rc = GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  993.         /* The bitmap must be reselected in the HPS */
  994.         TkOS2UnsetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  995.                           oldPattern, &oldRefPoint);
  996.  
  997.     } else {
  998.  
  999.     GpiQueryTextAlignment(hps, &oldHorAlign, &oldVerAlign);
  1000.     GpiSetTextAlignment(hps, TA_LEFT, TA_BASE);
  1001.  
  1002.     GpiQueryAttrs(hps, PRIM_CHAR, LBB_COLOR, (PBUNDLE)&cBundle);
  1003.     oldColor = cBundle.lColor;
  1004.     cBundle.lColor = gc->foreground;
  1005.     rc = GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  1006.  
  1007.     oldBackMix = GpiQueryBackMix(hps);
  1008.     /* We get a crash in PMMERGE.DLL on anything other than BM_LEAVEALONE */
  1009.     GpiSetBackMix(hps, BM_LEAVEALONE);
  1010.  
  1011.     if (gc->font != None) {
  1012.             rc = GpiCreateLogFont(hps, NULL, (LONG)gc->font,
  1013.                                   &(logfonts[(LONG)gc->font].fattrs));
  1014.         oldFont = GpiQueryCharSet(hps);
  1015.         rc = GpiSetCharSet(hps, (LONG)gc->font);
  1016.         /* Set slant if necessary */
  1017.         if (logfonts[(LONG)gc->font].setShear) {
  1018.             GpiSetCharShear(hps, &(logfonts[(LONG)gc->font].shear));
  1019.         }
  1020.             /* If this is an outline font, set the char box */
  1021.             if (logfonts[(LONG)gc->font].outline) {
  1022.                 rc= TkOS2ScaleFont(hps, logfonts[(LONG)gc->font].deciPoints, 0);
  1023.             }
  1024.     }
  1025.  
  1026.     refPoint.x = x;
  1027.     refPoint.y = y;
  1028.         /* only 512 bytes allowed in string */
  1029.         rc = GpiSetCurrentPosition(hps, &refPoint);
  1030.         l = length;
  1031.         str = (char *)string;
  1032.         while (l>512) {
  1033.             rc = GpiCharString(hps, 512, (PCH)str);
  1034.             l -= 512;
  1035.             str += 512;
  1036.         }
  1037.         rc = GpiCharString(hps, l, (PCH)str);
  1038.  
  1039.         rc = GpiSetCharSet(hps, LCID_DEFAULT);
  1040.         rc = GpiDeleteSetId(hps, (LONG)gc->font);
  1041.  
  1042.     if (gc->font != None) {
  1043.         /* Set slant if necessary */
  1044.         if (logfonts[(LONG)gc->font].setShear) {
  1045.             GpiSetCharShear(hps, &noShear);
  1046.         }
  1047.         GpiSetCharSet(hps, oldFont);
  1048.     }
  1049.     GpiSetBackMix(hps, oldBackMix);
  1050.     GpiSetBackColor(hps, oldBackColor);
  1051.     cBundle.lColor = oldColor;
  1052.     GpiSetAttrs(hps, PRIM_CHAR, LBB_COLOR, 0L, (PBUNDLE)&cBundle);
  1053.     GpiSetTextAlignment(hps, oldHorAlign, oldVerAlign);
  1054.     }
  1055.  
  1056.     TkOS2ReleaseDrawablePS(d, hps, &state);
  1057. }
  1058.  
  1059. /*
  1060.  *----------------------------------------------------------------------
  1061.  *
  1062.  * XFillRectangles --
  1063.  *
  1064.  *    Fill multiple rectangular areas in the given drawable.
  1065.  *
  1066.  * Results:
  1067.  *    None.
  1068.  *
  1069.  * Side effects:
  1070.  *    Draws onto the specified drawable.
  1071.  *
  1072.  *----------------------------------------------------------------------
  1073.  */
  1074.  
  1075. void
  1076. XFillRectangles(display, d, gc, rectangles, nrectangles)
  1077.     Display* display;
  1078.     Drawable d;
  1079.     GC gc;
  1080.     XRectangle* rectangles;
  1081.     int nrectangles;
  1082. {
  1083.     HPS hps;
  1084.     int i;
  1085.     RECTL rect;
  1086.     TkOS2PSState state;
  1087.     LONG windowHeight;
  1088.     POINTL refPoint;
  1089.     LONG oldPattern, oldBitmap;
  1090.     TkOS2Drawable *todPtr = (TkOS2Drawable *)d;
  1091.     LONG rc;
  1092.  
  1093.     if (d == None) {
  1094.     return;
  1095.     }
  1096.  
  1097.     windowHeight = TkOS2WindowHeight(todPtr);
  1098.  
  1099.     hps = TkOS2GetDrawablePS(display, d, &state);
  1100.     GpiSetMix(hps, mixModes[gc->function]);
  1101.  
  1102.     if ((gc->fill_style == FillStippled
  1103.         || gc->fill_style == FillOpaqueStippled)
  1104.         && gc->stipple != None) {
  1105.     HBITMAP bitmap;
  1106.         BITMAPINFOHEADER2 bmpInfo;
  1107.         LONG rc;
  1108.         DEVOPENSTRUC dop = {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
  1109.         SIZEL sizl = {0,0}; /* use same page size as device */
  1110.         HDC dcMem;
  1111.     HPS psMem;
  1112.         POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
  1113.         POINTL oldRefPoint;
  1114.  
  1115.     todPtr = (TkOS2Drawable *)gc->stipple;
  1116.  
  1117.     if (todPtr->type != TOD_BITMAP) {
  1118.         panic("unexpected drawable type in stipple");
  1119.     }
  1120.  
  1121.     /*
  1122.      * Select stipple pattern into destination dc.
  1123.      */
  1124.  
  1125.     refPoint.x = gc->ts_x_origin;
  1126.     /* Translate Xlib y to PM y */
  1127.     refPoint.y = windowHeight - gc->ts_y_origin;
  1128.  
  1129.         /* The bitmap mustn't be selected in the HPS */
  1130.         TkOS2SetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  1131.                         refPoint.x, refPoint.y, &oldPattern, &oldRefPoint);
  1132.  
  1133.     dcMem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&dop,
  1134.                       NULLHANDLE);
  1135.     if (dcMem == DEV_ERROR) {
  1136.         return;
  1137.     }
  1138.         psMem = GpiCreatePS(hab, dcMem, &sizl,
  1139.                             PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  1140.         if (psMem == GPI_ERROR) {
  1141.             DevCloseDC(dcMem);
  1142.             return;
  1143.         }
  1144.  
  1145.     /*
  1146.      * For each rectangle, create a drawing surface which is the size of
  1147.      * the rectangle and fill it with the background color.  Then merge the
  1148.      * result with the stipple pattern.
  1149.      */
  1150.  
  1151.     for (i = 0; i < nrectangles; i++) {
  1152.         bmpInfo.cbFix = 16L;
  1153.         bmpInfo.cx = rectangles[i].width + 1;
  1154.         bmpInfo.cy = rectangles[i].height + 1;
  1155.         bmpInfo.cPlanes = 1;
  1156.         bmpInfo.cBitCount = 1;
  1157.         bitmap = GpiCreateBitmap(psMem, &bmpInfo, 0L, NULL, NULL);
  1158.         oldBitmap = GpiSetBitmap(psMem, bitmap);
  1159.  
  1160.             /* Translate the Y coordinates to PM coordinates */
  1161.  
  1162.         rect.xLeft = 0;
  1163.         rect.xRight = rectangles[i].width + 1;
  1164.         rect.yBottom = 0;
  1165.         rect.yTop = rectangles[i].height + 1;
  1166.  
  1167.         oldPattern = GpiQueryPattern(psMem);
  1168.         GpiSetPattern(psMem, PATSYM_SOLID);
  1169.         rc = WinFillRect(psMem, &rect, gc->foreground);
  1170.             /* Translate the Y coordinates to PM coordinates */
  1171.             aPoints[0].x = rectangles[i].x;
  1172.             aPoints[0].y = windowHeight - rectangles[i].y -
  1173.                            rectangles[i].height;
  1174.             aPoints[1].x = rectangles[i].x + rectangles[i].width + 1;
  1175.             aPoints[1].y = windowHeight - rectangles[i].y + 1;
  1176.         aPoints[2].x = 0;
  1177.         aPoints[2].y = 0;
  1178.             rc = GpiBitBlt(hps, psMem, 3, aPoints, COPYFG, BBO_IGNORE);
  1179.         if (gc->fill_style == FillOpaqueStippled) {
  1180.             rc = WinFillRect(psMem, &rect, gc->background);
  1181.                 rc = GpiBitBlt(hps, psMem, 3, aPoints, COPYBG, BBO_IGNORE);
  1182.         }
  1183.         GpiSetPattern(psMem, oldPattern);
  1184.         GpiDeleteBitmap(bitmap);
  1185.     }
  1186.     GpiDestroyPS(psMem);
  1187.         DevCloseDC(dcMem);
  1188.         /* The bitmap must be reselected in the HPS */
  1189.         TkOS2UnsetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  1190.                           oldPattern, &oldRefPoint);
  1191.     } else {
  1192.  
  1193.         for (i = 0; i < nrectangles; i++) {
  1194.             rect.xLeft = rectangles[i].x;
  1195.             rect.xRight = rect.xLeft + rectangles[i].width;
  1196.             rect.yBottom = windowHeight - rectangles[i].y -
  1197.                            rectangles[i].height;
  1198.             rect.yTop = windowHeight - rectangles[i].y;
  1199.             rc = WinFillRect(hps, &rect, gc->foreground);
  1200.             GpiSetPattern(hps, oldPattern);
  1201.         }
  1202.     }
  1203.  
  1204.     TkOS2ReleaseDrawablePS(d, hps, &state);
  1205. }
  1206.  
  1207. /*
  1208.  *----------------------------------------------------------------------
  1209.  *
  1210.  * RenderObject --
  1211.  *
  1212.  *    This function draws a shape using a list of points, a
  1213.  *    stipple pattern, and the specified drawing function.
  1214.  *
  1215.  * Results:
  1216.  *    None.
  1217.  *
  1218.  * Side effects:
  1219.  *    None.
  1220.  *
  1221.  *----------------------------------------------------------------------
  1222.  */
  1223.  
  1224. static void
  1225. RenderObject(hps, gc, d, points, npoints, mode, pLineBundle, func)
  1226.     HPS hps;
  1227.     GC gc;
  1228.     Drawable d;
  1229.     XPoint* points;
  1230.     int npoints;
  1231.     int mode;
  1232.     PLINEBUNDLE pLineBundle;
  1233.     int func;
  1234. {
  1235.     RECTL rect;
  1236.     LINEBUNDLE oldLineBundle;
  1237.     LONG oldPattern;
  1238.     LONG oldColor;
  1239.     POINTL oldRefPoint;
  1240.     POINTL *os2Points;
  1241.     POINTL refPoint;
  1242.     POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
  1243.     LONG windowHeight;
  1244.     POLYGON polygon;
  1245.  
  1246.     pLineBundle->lColor = gc->foreground;
  1247.     pLineBundle->lGeomWidth = gc->line_width;
  1248.     if ( func == TOP_POLYGONS) {
  1249.         pLineBundle->usType = LINETYPE_INVISIBLE;
  1250.     } else {
  1251.         pLineBundle->usType = lineStyles[gc->line_style];
  1252.     }
  1253.     pLineBundle->usEnd = capStyles[gc->cap_style];
  1254.     pLineBundle->usJoin = joinStyles[gc->join_style];
  1255.  
  1256.     /* os2Points/rect get *PM* coordinates handed to it by ConvertPoints */
  1257.     os2Points = ConvertPoints(d, points, npoints, mode, &rect);
  1258.  
  1259.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)d);
  1260.  
  1261.     if ((gc->fill_style == FillStippled
  1262.         || gc->fill_style == FillOpaqueStippled)
  1263.         && gc->stipple != None) {
  1264.  
  1265.     TkOS2Drawable *todPtr = (TkOS2Drawable *)gc->stipple;
  1266.         DEVOPENSTRUC dop = {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
  1267.         SIZEL sizl = {0,0}; /* use same page size as device */
  1268.         HDC dcMem;
  1269.     HPS psMem;
  1270.     LONG width, height;
  1271.     int i;
  1272.     HBITMAP bitmap, oldBitmap;
  1273.         BITMAPINFOHEADER2 bmpInfo;
  1274.  
  1275.     if (todPtr->type != TOD_BITMAP) {
  1276.         panic("unexpected drawable type in stipple");
  1277.     }
  1278.  
  1279.     
  1280.     width = rect.xRight - rect.xLeft;
  1281.     /* PM coordinates are just reverse: top - bottom */
  1282.     height = rect.yTop - rect.yBottom;
  1283.  
  1284.     /*
  1285.      * Select stipple pattern into destination hps.
  1286.      */
  1287.     
  1288.     refPoint.x = gc->ts_x_origin;
  1289.     /* Translate Xlib y to PM y */
  1290.     refPoint.y = windowHeight - gc->ts_y_origin;
  1291.  
  1292.         TkOS2SetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  1293.                         refPoint.x, refPoint.y, &oldPattern, &oldRefPoint);
  1294.  
  1295.     /*
  1296.      * Create temporary drawing surface containing a copy of the
  1297.      * destination equal in size to the bounding box of the object.
  1298.      */
  1299.     
  1300.     dcMem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&dop,
  1301.                       NULLHANDLE);
  1302.     if (dcMem == DEV_ERROR) {
  1303.         return;
  1304.     }
  1305.         psMem = GpiCreatePS(hab, dcMem, &sizl,
  1306.                             PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  1307.         if (psMem == GPI_ERROR) {
  1308.             DevCloseDC(dcMem);
  1309.             return;
  1310.         }
  1311.  
  1312.     TkOS2SelectPalette(psMem, HWND_DESKTOP, todPtr->bitmap.colormap);
  1313.  
  1314.     /*
  1315.      * X filling includes top and left sides, excludes bottom and right sides.
  1316.      * PM filling (WinFillRect) and BitBlt-ing (GpiBitBlt) includes bottom and
  1317.      * left sides, excludes top and right sides.
  1318.      * NB! X fills a box exactly as wide and high as width and height specify,
  1319.      * while PM cuts one pixel off the right and top.
  1320.      * => decrement y (X Window System) by one / increment y (PM) by one AND
  1321.      *    increment height by one, and increment width by one.
  1322.      */
  1323.  
  1324.     bmpInfo.cbFix = sizeof(BITMAPINFOHEADER2);
  1325.     bmpInfo.cx = width + 1;
  1326.     bmpInfo.cy = height + 1;
  1327.     bitmap = GpiCreateBitmap(psMem, &bmpInfo, 0L, NULL, NULL);
  1328.     oldBitmap = GpiSetBitmap(psMem, bitmap);
  1329.     rc = GpiSetAttrs(psMem, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH
  1330.                      | LBB_TYPE | LBB_END | LBB_JOIN, 0L, pLineBundle);
  1331.         /* Translate the Y coordinates to PM coordinates */
  1332.         aPoints[0].x = 0;    /* dest_x 0 */
  1333.         aPoints[0].y = 0;    /* dest_y 0 */
  1334.         aPoints[1].x = width + 1;    /* dest_x + width */
  1335.         aPoints[1].y = height + 1;    /* dest_y + height */
  1336.         aPoints[2].x = rect.xLeft;
  1337.         aPoints[2].y = rect.yBottom;
  1338.  
  1339.         GpiBitBlt(psMem, hps, 3, aPoints, ROP_SRCCOPY, BBO_IGNORE);
  1340.  
  1341.     /*
  1342.      * Translate the object to 0,0 for rendering in the temporary drawing
  1343.      * surface. 
  1344.      */
  1345.  
  1346.     for (i = 0; i < npoints; i++) {
  1347.         os2Points[i].x -= rect.xLeft;
  1348.         os2Points[i].y -= rect.yBottom;
  1349.     }
  1350.  
  1351.     /*
  1352.      * Draw the object in the foreground color and copy it to the
  1353.      * destination wherever the pattern is set.
  1354.      */
  1355.  
  1356.     rc = GpiSetColor(psMem, gc->foreground);
  1357.     rc = GpiSetPattern(psMem, PATSYM_SOLID);
  1358.     if (func == TOP_POLYGONS) {
  1359.         rc = GpiSetCurrentPosition(psMem, os2Points);
  1360.             polygon.ulPoints = npoints-1;
  1361.             polygon.aPointl = os2Points+1;
  1362.         rc = GpiPolygons(psMem, 1, &polygon, POLYGON_BOUNDARY |
  1363.                          (gc->fill_rule == EvenOddRule) ? POLYGON_ALTERNATE
  1364.                                                         : POLYGON_WINDING,
  1365.                          POLYGON_INCL);
  1366.     } else { /* TOP_POLYLINE */
  1367.         rc = GpiSetCurrentPosition(psMem, os2Points);
  1368.             rc = GpiBeginPath(psMem, 1);
  1369.             rc = GpiPolyLine(psMem, npoints-1, os2Points+1);
  1370.             rc = GpiEndPath(psMem);
  1371.             rc = GpiStrokePath(psMem, 1, 0);
  1372.     }
  1373.         aPoints[0].x = rect.xLeft;    /* dest_x */
  1374.         aPoints[0].y = rect.yBottom;
  1375.         aPoints[1].x = rect.xRight;    /* dest_x + width */
  1376.         aPoints[1].y = rect.yTop;    /* dest_y */
  1377.         aPoints[2].x = 0;    /* src_x 0 */
  1378.         aPoints[2].y = 0;    /* Src_y */
  1379.         rc = GpiBitBlt(hps, psMem, 3, aPoints, COPYFG, BBO_IGNORE);
  1380.  
  1381.     /*
  1382.      * If we are rendering an opaque stipple, then draw the polygon in the
  1383.      * background color and copy it to the destination wherever the pattern
  1384.      * is clear.
  1385.      */
  1386.  
  1387.     if (gc->fill_style == FillOpaqueStippled) {
  1388.         GpiSetColor(psMem, gc->background);
  1389.         if (func == TOP_POLYGONS) {
  1390.                 polygon.ulPoints = npoints;
  1391.                 polygon.aPointl = os2Points;
  1392.             rc = GpiPolygons(psMem, 1, &polygon,
  1393.                           (gc->fill_rule == EvenOddRule) ? POLYGON_ALTERNATE
  1394.                                                          : POLYGON_WINDING,
  1395.                           0);
  1396.             } else { /* TOP_POLYLINE */
  1397.                 rc = GpiBeginPath(psMem, 1);
  1398.                 rc = GpiPolyLine(psMem, npoints, os2Points);
  1399.                 rc = GpiEndPath(psMem);
  1400.                 rc = GpiStrokePath(psMem, 1, 0);
  1401.         }
  1402.             rc = GpiBitBlt(hps, psMem, 3, aPoints, COPYBG, BBO_IGNORE);
  1403.     }
  1404.     /* end of using 254 */
  1405.         TkOS2UnsetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  1406.                           oldPattern, &oldRefPoint);
  1407.     GpiDestroyPS(psMem);
  1408.         DevCloseDC(dcMem);
  1409.     } else {
  1410.  
  1411.     GpiQueryAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE,
  1412.                   &oldLineBundle);
  1413.     rc = GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE
  1414.                      | LBB_END | LBB_JOIN, 0L, pLineBundle);
  1415.         oldColor = GpiQueryColor(hps);
  1416.         oldPattern = GpiQueryPattern(hps);
  1417.     rc = GpiSetColor(hps, gc->foreground);
  1418.     rc = GpiSetPattern(hps, PATSYM_SOLID);
  1419.     rc = GpiSetMix(hps, mixModes[gc->function]);
  1420.  
  1421.         if (func == TOP_POLYGONS) {
  1422.         rc = GpiSetCurrentPosition(hps, os2Points);
  1423.             polygon.ulPoints = npoints-1;
  1424.             polygon.aPointl = os2Points+1;
  1425.             rc = GpiPolygons(hps, 1, &polygon, POLYGON_BOUNDARY |
  1426.                              (gc->fill_rule == EvenOddRule) ? POLYGON_ALTERNATE
  1427.                                                             : POLYGON_WINDING,
  1428.                          POLYGON_INCL);
  1429.         } else { /* TOP_POLYLINE */
  1430.         rc = GpiSetCurrentPosition(hps, os2Points);
  1431.             rc = GpiBeginPath(hps, 1);
  1432.             rc = GpiPolyLine(hps, npoints-1, os2Points+1);
  1433.             rc = GpiEndPath(hps);
  1434.             rc = GpiStrokePath(hps, 1, 0);
  1435.         }
  1436.  
  1437.     GpiSetColor(hps, oldColor);
  1438.     GpiSetPattern(hps, oldPattern);
  1439.     GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE, 0L,
  1440.                 &oldLineBundle);
  1441.     }
  1442. }
  1443.  
  1444. /*
  1445.  *----------------------------------------------------------------------
  1446.  *
  1447.  * XDrawLines --
  1448.  *
  1449.  *    Draw connected lines.
  1450.  *
  1451.  * Results:
  1452.  *    None.
  1453.  *
  1454.  * Side effects:
  1455.  *    Renders a series of connected lines.
  1456.  *
  1457.  *----------------------------------------------------------------------
  1458.  */
  1459.  
  1460. void
  1461. XDrawLines(display, d, gc, points, npoints, mode)
  1462.     Display* display;
  1463.     Drawable d;
  1464.     GC gc;
  1465.     XPoint* points;
  1466.     int npoints;
  1467.     int mode;
  1468. {
  1469.     LINEBUNDLE lineBundle;
  1470.     TkOS2PSState state;
  1471.     HPS hps;
  1472.  
  1473.     if (d == None) {
  1474.     return;
  1475.     }
  1476.  
  1477.     hps = TkOS2GetDrawablePS(display, d, &state);
  1478.  
  1479.     RenderObject(hps, gc, d, points, npoints, mode, &lineBundle, TOP_POLYLINE);
  1480.     
  1481.     TkOS2ReleaseDrawablePS(d, hps, &state);
  1482. }
  1483.  
  1484. /*
  1485.  *----------------------------------------------------------------------
  1486.  *
  1487.  * XFillPolygon --
  1488.  *
  1489.  *    Draws a filled polygon.
  1490.  *
  1491.  * Results:
  1492.  *    None.
  1493.  *
  1494.  * Side effects:
  1495.  *    Draws a filled polygon on the specified drawable.
  1496.  *
  1497.  *----------------------------------------------------------------------
  1498.  */
  1499.  
  1500. void
  1501. XFillPolygon(display, d, gc, points, npoints, shape, mode)
  1502.     Display* display;
  1503.     Drawable d;
  1504.     GC gc;
  1505.     XPoint* points;
  1506.     int npoints;
  1507.     int shape;
  1508.     int mode;
  1509. {
  1510.     LINEBUNDLE lineBundle;
  1511.     TkOS2PSState state;
  1512.     HPS hps;
  1513.  
  1514.     if (d == None) {
  1515.     return;
  1516.     }
  1517.  
  1518.     hps = TkOS2GetDrawablePS(display, d, &state);
  1519.  
  1520.     RenderObject(hps, gc, d, points, npoints, mode, &lineBundle, TOP_POLYGONS);
  1521.  
  1522.     TkOS2ReleaseDrawablePS(d, hps, &state);
  1523. }
  1524.  
  1525. /*
  1526.  *----------------------------------------------------------------------
  1527.  *
  1528.  * XDrawRectangle --
  1529.  *
  1530.  *    Draws a rectangle.
  1531.  *
  1532.  * Results:
  1533.  *    None.
  1534.  *
  1535.  * Side effects:
  1536.  *    Draws a rectangle on the specified drawable.
  1537.  *
  1538.  *----------------------------------------------------------------------
  1539.  */
  1540.  
  1541. void
  1542. XDrawRectangle(display, d, gc, x, y, width, height)
  1543.     Display* display;
  1544.     Drawable d;
  1545.     GC gc;
  1546.     int x;
  1547.     int y;
  1548.     unsigned int width;
  1549.     unsigned int height;
  1550. {
  1551.     LINEBUNDLE lineBundle, oldLineBundle;
  1552.     TkOS2PSState state;
  1553.     LONG oldPattern;
  1554.     HPS hps;
  1555.     POINTL oldCurrent, changePoint;
  1556.     LONG windowHeight;
  1557.  
  1558.     if (d == None) {
  1559.     return;
  1560.     }
  1561.  
  1562.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)d);
  1563.  
  1564.     hps = TkOS2GetDrawablePS(display, d, &state);
  1565.  
  1566.     GpiQueryAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE,
  1567.                   &oldLineBundle);
  1568.     lineBundle.lColor = gc->foreground;
  1569.     lineBundle.lGeomWidth = gc->line_width;
  1570.     lineBundle.usType = LINETYPE_SOLID;
  1571.     GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE, 0L,
  1572.                 &lineBundle);
  1573.     oldPattern = GpiQueryPattern(hps);
  1574.     GpiSetPattern(hps, PATSYM_NOSHADE);
  1575.     GpiSetMix(hps, mixModes[gc->function]);
  1576.  
  1577.     GpiQueryCurrentPosition(hps, &oldCurrent);
  1578.     changePoint.x = x;
  1579.     /* Translate the Y coordinates to PM coordinates */
  1580.     changePoint.y = windowHeight - y;
  1581.     GpiSetCurrentPosition(hps, &changePoint);
  1582.     /*
  1583.      * Now put other point of box in changePoint.
  1584.      */
  1585.     changePoint.x += width;
  1586.     changePoint.y -= height;    /* PM coordinates are reverse */
  1587.     GpiBox(hps, DRO_OUTLINE, &changePoint, 0L, 0L);
  1588.     GpiSetCurrentPosition(hps, &oldCurrent);
  1589.  
  1590.     GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE, 0L,
  1591.                 &oldLineBundle);
  1592.     GpiSetPattern(hps, oldPattern);
  1593.     TkOS2ReleaseDrawablePS(d, hps, &state);
  1594. }
  1595.  
  1596. /*
  1597.  *----------------------------------------------------------------------
  1598.  *
  1599.  * XDrawArc --
  1600.  *
  1601.  *    Draw an arc.
  1602.  *
  1603.  * Results:
  1604.  *    None.
  1605.  *
  1606.  * Side effects:
  1607.  *    Draws an arc on the specified drawable.
  1608.  *
  1609.  *----------------------------------------------------------------------
  1610.  */
  1611.  
  1612. void
  1613. XDrawArc(display, d, gc, x, y, width, height, angle1, angle2)
  1614.     Display* display;
  1615.     Drawable d;
  1616.     GC gc;
  1617.     int x;
  1618.     int y;
  1619.     unsigned int width;
  1620.     unsigned int height;
  1621.     int angle1;
  1622.     int angle2;
  1623. {
  1624.     display->request++;
  1625.  
  1626.     DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, 0);
  1627. }
  1628.  
  1629. /*
  1630.  *----------------------------------------------------------------------
  1631.  *
  1632.  * XFillArc --
  1633.  *
  1634.  *    Draw a filled arc.
  1635.  *
  1636.  * Results:
  1637.  *    None.
  1638.  *
  1639.  * Side effects:
  1640.  *    Draws a filled arc on the specified drawable.
  1641.  *
  1642.  *----------------------------------------------------------------------
  1643.  */
  1644.  
  1645. void
  1646. XFillArc(display, d, gc, x, y, width, height, angle1, angle2)
  1647.     Display* display;
  1648.     Drawable d;
  1649.     GC gc;
  1650.     int x;
  1651.     int y;
  1652.     unsigned int width;
  1653.     unsigned int height;
  1654.     int angle1;
  1655.     int angle2;
  1656. {
  1657.     display->request++;
  1658.  
  1659.     DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, 1);
  1660. }
  1661.  
  1662. /*
  1663.  *----------------------------------------------------------------------
  1664.  *
  1665.  * DrawOrFillArc --
  1666.  *
  1667.  *    This procedure handles the rendering of drawn or filled
  1668.  *    arcs and chords.
  1669.  *
  1670.  * Results:
  1671.  *    None.
  1672.  *
  1673.  * Side effects:
  1674.  *    Renders the requested arc.
  1675.  *
  1676.  *----------------------------------------------------------------------
  1677.  */
  1678.  
  1679. static void
  1680. DrawOrFillArc(display, d, gc, x, y, width, height, angle1, angle2, fill)
  1681.     Display *display;
  1682.     Drawable d;
  1683.     GC gc;
  1684.     int x, y;            /* left top */
  1685.     unsigned int width, height;
  1686.     int angle1;            /* angle1: three-o'clock (deg*64) */
  1687.     int angle2;            /* angle2: relative (deg*64) */
  1688.     int fill;            /* ==0 draw, !=0 fill */
  1689. {
  1690.     HPS hps;
  1691.     LONG oldColor, oldMix, oldPattern;
  1692.     LINEBUNDLE lineBundle, oldLineBundle;
  1693.     AREABUNDLE aBundle;
  1694.     int sign;
  1695.     POINTL center, curPt;
  1696.     TkOS2PSState state;
  1697.     LONG windowHeight;
  1698.     ARCPARAMS arcParams, oldArcParams;
  1699.     double a1sin, a1cos;
  1700.     TkOS2Drawable *todPtr = (TkOS2Drawable *)d;
  1701.     POINTL refPoint;
  1702.  
  1703.     if (d == None) {
  1704.     return;
  1705.     }
  1706.     a1sin = sin(XAngleToRadians(angle1));
  1707.     a1cos = cos(XAngleToRadians(angle1));
  1708.     windowHeight = TkOS2WindowHeight(todPtr);
  1709.  
  1710.     /* Translate the Y coordinates to PM coordinates */
  1711.     y = windowHeight - y;
  1712.     /* Translate angles back to positive degrees */
  1713.     angle1 = abs(angle1 / 64);
  1714.     if (angle2 < 0) {
  1715.         sign = -1;
  1716.         /*
  1717.          * Not only the sweep but also the starting angle gets computed
  1718.          * counter-clockwise when Arc Param Q is negative (p*q actually).
  1719.          */
  1720.         angle1 = 360 - angle1;
  1721.     }
  1722.     else {
  1723.         sign = 1;
  1724.     }
  1725.     angle2 = abs(angle2 / 64);
  1726.  
  1727.     hps = TkOS2GetDrawablePS(display, d, &state);
  1728.  
  1729.     oldColor = GpiQueryColor(hps);
  1730.     oldPattern = GpiQueryPattern(hps);
  1731.     oldMix = GpiQueryMix(hps);
  1732.     GpiSetColor(hps, gc->foreground);
  1733.     GpiSetPattern(hps, PATSYM_SOLID);
  1734.     GpiSetMix(hps, mixModes[gc->function]);
  1735.  
  1736.     /*
  1737.      * Now draw a filled or open figure.
  1738.      */
  1739.  
  1740.     GpiQueryAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE,
  1741.                   &oldLineBundle);
  1742.     if ((gc->fill_style == FillStippled || gc->fill_style == FillOpaqueStippled)
  1743.         && gc->stipple != None) {
  1744.         HBITMAP bitmap, oldBitmap;
  1745.         BITMAPINFOHEADER2 bmpInfo;
  1746.         LONG rc;
  1747.         DEVOPENSTRUC dop = {0L, (PSZ)"DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
  1748.         SIZEL sizl = {0,0}; /* use same page size as device */
  1749.         HDC dcMem;
  1750.         HPS psMem;
  1751.         POINTL aPoints[3]; /* Lower-left, upper-right, lower-left source */
  1752.         POINTL oldRefPoint;
  1753.  
  1754.         todPtr = (TkOS2Drawable *)gc->stipple;
  1755.  
  1756.         if (todPtr->type != TOD_BITMAP) {
  1757.             panic("unexpected drawable type in stipple");
  1758.         }
  1759.  
  1760.         /*
  1761.          * Select stipple pattern into destination dc.
  1762.          */
  1763.         /* Translate Xlib y to PM y */
  1764.         refPoint.x = gc->ts_x_origin;
  1765.         refPoint.y = windowHeight - gc->ts_y_origin;
  1766.  
  1767.         dcMem = DevOpenDC(hab, OD_MEMORY, (PSZ)"*", 5L, (PDEVOPENDATA)&dop,
  1768.                           NULLHANDLE);
  1769.         if (dcMem == DEV_ERROR) {
  1770.             return;
  1771.         }
  1772.         psMem = GpiCreatePS(hab, dcMem, &sizl,
  1773.                             PU_PELS | GPIT_NORMAL | GPIA_ASSOC);
  1774.         if (psMem == GPI_ERROR) {
  1775.             DevCloseDC(dcMem);
  1776.             return;
  1777.         }
  1778.  
  1779.         rc = GpiQueryArcParams(psMem, &oldArcParams);
  1780.         arcParams.lP = width / 2;
  1781.         arcParams.lQ = sign * (height / 2);
  1782.         arcParams.lR = 0;
  1783.         arcParams.lS = 0;
  1784.         rc = GpiSetArcParams(psMem, &arcParams);
  1785.  
  1786.     /*
  1787.      * Draw the object in the foreground color and copy it to the
  1788.      * destination wherever the pattern is set.
  1789.      */
  1790.  
  1791.     rc = GpiSetColor(psMem, gc->foreground);
  1792.  
  1793.     /*
  1794.      * X filling includes top and left sides, excludes bottom and right sides.
  1795.      * PM filling (WinFillRect) and BitBlt-ing (GpiBitBlt) includes bottom and
  1796.      * left sides, excludes top and right sides.
  1797.      * NB! X fills a box exactly as wide and high as width and height specify,
  1798.      * while PM cuts one pixel off the right and top.
  1799.      * => decrement y (X Window System) by one / increment y (PM) by one AND
  1800.      *    increment height by one, and increment width by one.
  1801.      */
  1802.  
  1803.         bmpInfo.cbFix = 16L;
  1804.     /* Bitmap must be able to contain a thicker line! */
  1805.         bmpInfo.cx = width + gc->line_width + 1;
  1806.         bmpInfo.cy = height + gc->line_width + 1;
  1807.         bmpInfo.cPlanes = 1;
  1808.         bmpInfo.cBitCount= display->screens[display->default_screen].root_depth;
  1809.         bitmap = GpiCreateBitmap(psMem, &bmpInfo, 0L, NULL, NULL);
  1810.         oldBitmap = GpiSetBitmap(psMem, bitmap);
  1811.  
  1812.         TkOS2SelectPalette(psMem, HWND_DESKTOP, todPtr->bitmap.colormap);
  1813.  
  1814.         /* Line width! */
  1815.         aPoints[0].x = 0;
  1816.         aPoints[0].y = 0;
  1817.         aPoints[1].x = width + gc->line_width + 1;
  1818.         aPoints[1].y = height + gc->line_width + 1;
  1819.         aPoints[2].x = x - (gc->line_width/2);
  1820.         aPoints[2].y = y - height + 1 - (gc->line_width/2);
  1821.  
  1822.         rc = GpiBitBlt(psMem, hps, 3, aPoints, ROP_SRCCOPY, BBO_IGNORE);
  1823.  
  1824.         /* The bitmap mustn't be selected in the HPS */
  1825.         TkOS2SetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  1826.                         refPoint.x, refPoint.y, &oldPattern, &oldRefPoint);
  1827.         /* Drawing */
  1828.         /* Center of arc is at x+(0.5*width),y-(0.5*height) */
  1829.         /* Translate to 0,0 for rendering in psMem */
  1830.         center.x = (0.5 * width) + (gc->line_width/2);
  1831.         center.y = (0.5 * height) + (gc->line_width/2);
  1832.         lineBundle.lColor = gc->foreground;
  1833.         lineBundle.lGeomWidth = gc->line_width;
  1834.         lineBundle.usType = LINETYPE_SOLID;
  1835.         rc = GpiSetAttrs(psMem, PRIM_LINE,
  1836.                          LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE,
  1837.                          0L, &lineBundle);
  1838.         aBundle.lColor = gc->foreground;
  1839.         rc = GpiSetAttrs(psMem, PRIM_AREA, LBB_COLOR, 0L, (PBUNDLE)&aBundle);
  1840.         if (!fill) {
  1841.             curPt.x = center.x + (int) (0.5 * width * a1cos);
  1842.             curPt.y = center.y + (int) (0.5 * height * a1sin);
  1843.             rc = GpiSetCurrentPosition(psMem, &curPt);
  1844.             rc = GpiBeginPath(psMem, 1);
  1845.             rc= GpiPartialArc(psMem, ¢er, MAKEFIXED(1, 0),
  1846.                               MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1847.             rc = GpiEndPath(psMem);
  1848.             rc = GpiStrokePath(psMem, 1, 0);
  1849.         } else {
  1850.             curPt.x = center.x + (int) (0.5 * width * a1cos);
  1851.             curPt.y = center.y + (int) (0.5 * height * a1sin);
  1852.             rc = GpiSetCurrentPosition(psMem, &curPt);
  1853.             if (gc->arc_mode == ArcChord) {
  1854.                 /* Chord */
  1855.                 /*
  1856.                  * See GPI reference: first do GpiPartialArc with invisible,
  1857.                  * line then again with visible line, in an Area for filling.
  1858.                  */
  1859.                 rc = GpiSetLineType(psMem, LINETYPE_INVISIBLE);
  1860.                 rc = GpiPartialArc(psMem, ¢er, MAKEFIXED(1, 0),
  1861.                                    MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1862.                 rc = GpiSetLineType(psMem, LINETYPE_SOLID);
  1863.                 rc = GpiBeginArea(psMem, BA_NOBOUNDARY|BA_ALTERNATE);
  1864.                 rc = GpiPartialArc(psMem, ¢er, MAKEFIXED(1, 0),
  1865.                                    MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1866.                 rc = GpiEndArea(psMem);
  1867.             } else if ( gc->arc_mode == ArcPieSlice ) {
  1868.                 /* Pie */
  1869.                 rc = GpiSetCurrentPosition(psMem, ¢er);
  1870.                 rc = GpiBeginArea(psMem, BA_NOBOUNDARY|BA_ALTERNATE);
  1871.                 rc = GpiPartialArc(psMem, ¢er, MAKEFIXED(1, 0),
  1872.                                    MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1873.                 rc = GpiLine(psMem, ¢er);
  1874.                 rc = GpiEndArea(psMem);
  1875.             }
  1876.         }
  1877.         /* Translate the Y coordinates to PM coordinates */
  1878.         aPoints[0].x = x - (gc->line_width/2);
  1879.         aPoints[0].y = y - height + 1 - (gc->line_width/2);
  1880.         aPoints[1].x = x + width + 1 + (gc->line_width/2);
  1881.         aPoints[1].y = y + 2 + (gc->line_width/2);
  1882.         aPoints[2].x = 0;
  1883.         aPoints[2].y = 0;
  1884.         rc = GpiBitBlt(hps, psMem, 3, aPoints, COPYFG, BBO_IGNORE);
  1885.         GpiSetAttrs(psMem, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE, 0L,
  1886.                     &oldLineBundle);
  1887.         /*
  1888.          * Destroy the temporary bitmap and restore the device context.
  1889.          */
  1890.  
  1891.         GpiSetBitmap(psMem, oldBitmap);
  1892.         GpiDeleteBitmap(bitmap);
  1893.         GpiDestroyPS(psMem);
  1894.         DevCloseDC(dcMem);
  1895.         /* The bitmap must be reselected in the HPS */
  1896.         TkOS2UnsetStipple(hps, todPtr->bitmap.hps, todPtr->bitmap.handle,
  1897.                           oldPattern, &oldRefPoint);
  1898.     } else {
  1899.  
  1900.         /* Not stippled */
  1901.  
  1902.         rc = GpiQueryArcParams(hps, &oldArcParams);
  1903.         arcParams.lP = width / 2;
  1904.         arcParams.lQ = sign * (height / 2);
  1905.         arcParams.lR = 0;
  1906.         arcParams.lS = 0;
  1907.         rc = GpiSetArcParams(hps, &arcParams);
  1908.  
  1909.         /* Center of arc is at x+(0.5*width),y-(0.5*height) */
  1910.         center.x = x + (0.5 * width);
  1911.         center.y = y - (0.5 * height);    /* PM y coordinate reversed */
  1912.         lineBundle.lColor = gc->foreground;
  1913.         lineBundle.lGeomWidth = gc->line_width;
  1914.         lineBundle.usType = LINETYPE_SOLID;
  1915.         rc = GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE,
  1916.                          0L, &lineBundle);
  1917.         if (!fill) {
  1918.         /* direction of arc is determined by arc parameters, while angles
  1919.          * are always positive
  1920.          * p*q > r*s -> direction counterclockwise
  1921.          * p*q < r*s -> direction clockwise
  1922.          * p*q = r*s -> straight line
  1923.          * When comparing the Remarks for function GpiSetArcParams in the
  1924.          * GPI Guide and Reference with the Xlib Programming Manual
  1925.          * (Fig.6-1), * the 3 o'clock point of the unit arc is defined by
  1926.          * (p,s) and the 12 * o'clock point by (r,q), when measuring from
  1927.          * (0,0) -> (cx+p, cy+s) and * (cx+r, cy+q) from center of arc at
  1928.          * (cx, cy). => p = 0.5 width, q = (sign*)0.5 height, r=s=0
  1929.          * GpiPartialArc draws a line from the current point to the start
  1930.          * of the partial arc, so we have to set the current point to it
  1931.          * first.
  1932.          * this is (cx+0.5*width*cos(angle1), cy+0.5*height*sin(angle1))
  1933.          */
  1934.         curPt.x = center.x + (int) (0.5 * width * a1cos);
  1935.         curPt.y = center.y + (int) (0.5 * height * a1sin);
  1936.         rc = GpiSetCurrentPosition(hps, &curPt);
  1937.             rc = GpiBeginPath(hps, 1);
  1938.         rc= GpiPartialArc(hps, ¢er, MAKEFIXED(1, 0),
  1939.                           MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1940.             rc = GpiEndPath(hps);
  1941.             rc = GpiStrokePath(hps, 1, 0);
  1942.         } else {
  1943.             curPt.x = center.x + (int) (0.5 * width * a1cos);
  1944.             curPt.y = center.y + (int) (0.5 * height * a1sin);
  1945.             rc = GpiSetCurrentPosition(hps, &curPt);
  1946.         if (gc->arc_mode == ArcChord) {
  1947.                 /* Chord */
  1948.                 /*
  1949.                  * See GPI reference: first do GpiPartialArc with invisible
  1950.                  * line, then again with visible line, in an Area for filling.
  1951.                  */
  1952.             GpiSetLineType(hps, LINETYPE_INVISIBLE);
  1953.             GpiPartialArc(hps, ¢er, MAKEFIXED(1, 0),
  1954.                           MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1955.             GpiSetLineType(hps, LINETYPE_SOLID);
  1956.             rc = GpiBeginArea(hps, BA_NOBOUNDARY|BA_ALTERNATE);
  1957.             rc = GpiPartialArc(hps, ¢er, MAKEFIXED(1, 0),
  1958.                                MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1959.             rc = GpiEndArea(hps);
  1960.         } else if ( gc->arc_mode == ArcPieSlice ) {
  1961.                 /* Pie */
  1962.             GpiSetCurrentPosition(hps, ¢er);
  1963.             GpiBeginArea(hps, BA_NOBOUNDARY|BA_ALTERNATE);
  1964.                 rc = GpiPartialArc(hps, ¢er, MAKEFIXED(1, 0),
  1965.                                    MAKEFIXED(angle1, 0), MAKEFIXED(angle2, 0));
  1966.                 GpiLine(hps, ¢er);
  1967.             GpiEndArea(hps);
  1968.         }
  1969.         }
  1970.         GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR | LBB_GEOM_WIDTH | LBB_TYPE, 0L,
  1971.                     &oldLineBundle);
  1972.     } /* not Stippled */
  1973.     GpiSetPattern(hps, oldPattern);
  1974.     GpiSetColor(hps, oldColor);
  1975.     GpiSetMix(hps, oldMix);
  1976.     rc = GpiSetArcParams(hps, &oldArcParams);
  1977.     TkOS2ReleaseDrawablePS(d, hps, &state);
  1978. }
  1979.  
  1980. /*
  1981.  *----------------------------------------------------------------------
  1982.  *
  1983.  * TkScrollWindow --
  1984.  *
  1985.  *    Scroll a rectangle of the specified window and accumulate
  1986.  *    a damage region.
  1987.  *
  1988.  * Results:
  1989.  *    Returns 0 if the scroll genereated no additional damage.
  1990.  *    Otherwise, sets the region that needs to be repainted after
  1991.  *    scrolling and returns 1.
  1992.  *
  1993.  * Side effects:
  1994.  *    Scrolls the bits in the window.
  1995.  *
  1996.  *----------------------------------------------------------------------
  1997.  */
  1998.  
  1999. int
  2000. TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn)
  2001.     Tk_Window tkwin;        /* The window to be scrolled. */
  2002.     GC gc;            /* GC for window to be scrolled. */
  2003.     int x, y, width, height;    /* Position rectangle to be scrolled. */
  2004.     int dx, dy;            /* Distance rectangle should be moved. */
  2005.     TkRegion damageRgn;        /* Region to accumulate damage in. */
  2006. {
  2007.     HWND hwnd = TkOS2GetHWND(Tk_WindowId(tkwin));
  2008.     RECTL scrollRect;
  2009.     LONG lReturn;
  2010.     LONG windowHeight;
  2011.  
  2012.     windowHeight = TkOS2WindowHeight((TkOS2Drawable *)Tk_WindowId(tkwin));
  2013.  
  2014.     /* Translate the Y coordinates to PM coordinates */
  2015.     y = windowHeight - y;
  2016.     dy = -dy;
  2017.     scrollRect.xLeft = x;
  2018.     scrollRect.yTop = y;
  2019.     scrollRect.xRight = x + width;
  2020.     scrollRect.yBottom = y - height;    /* PM coordinate reversed */
  2021.     /* Hide cursor, just in case */
  2022.     WinShowCursor(hwnd, FALSE);
  2023.     lReturn = WinScrollWindow(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn,
  2024.                               NULL, 0);
  2025.     /* Show cursor again */
  2026.     WinShowCursor(hwnd, TRUE);
  2027.     return ( lReturn == RGN_NULL ? 0 : 1);
  2028. }
  2029.  
  2030. /*
  2031.  *----------------------------------------------------------------------
  2032.  *
  2033.  * TkOS2SetStipple --
  2034.  *
  2035.  *    Set the pattern set of a HPS to a "stipple" (bitmap).
  2036.  *
  2037.  * Results:
  2038.  *    Returns the old pattern set and reference point.
  2039.  *
  2040.  * Side effects:
  2041.  *    Unsets the bitmap in/from "its" HPS, appoints a bitmap ID to it,
  2042.  *    sets that ID as the pattern set, with its reference point as given.
  2043.  *
  2044.  *----------------------------------------------------------------------
  2045.  */
  2046.  
  2047. void
  2048. TkOS2SetStipple(destPS, bmpPS, stipple, x, y, oldPatternSet, oldRefPoint)
  2049.     HPS destPS;        /* The HPS to receive the stipple. */
  2050.     HPS bmpPS;        /* The HPS of the stipple-bitmap. */
  2051.     HBITMAP stipple;    /* Stipple-bitmap. */
  2052.     LONG x, y;            /* Reference point for the stipple. */
  2053.     LONG *oldPatternSet;    /* Pattern set that was in effect in the HPS. */
  2054.     PPOINTL oldRefPoint;    /* Reference point that was in effect. */
  2055. {
  2056.     POINTL refPoint;
  2057.  
  2058.     refPoint.x = x;
  2059.     refPoint.y = y;
  2060.     rc = GpiQueryPatternRefPoint(destPS, oldRefPoint);
  2061.     rc = GpiSetPatternRefPoint(destPS, &refPoint);
  2062.     *oldPatternSet = GpiQueryPatternSet(destPS);
  2063.     GpiSetBitmap(bmpPS, NULLHANDLE);
  2064.     rc = GpiSetBitmapId(destPS, stipple, 254L);
  2065.     rc = GpiSetPatternSet(destPS, 254L);
  2066. }
  2067.  
  2068. /*
  2069.  *----------------------------------------------------------------------
  2070.  *
  2071.  * TkOS2UnsetStipple --
  2072.  *
  2073.  *    Unset the "stipple" (bitmap) from a HPS.
  2074.  *
  2075.  * Results:
  2076.  *    None.
  2077.  *
  2078.  * Side effects:
  2079.  *    Resets the pattern set and refpoint of the hps to their original
  2080.  *    (given) values and reassociates the bitmap with its "own" HPS.
  2081.  *
  2082.  *----------------------------------------------------------------------
  2083.  */
  2084.  
  2085. void
  2086. TkOS2UnsetStipple(destPS, bmpPS, stipple, oldPatternSet, oldRefPoint)
  2087.     HPS destPS;        /* The HPS to give up the stipple. */
  2088.     HPS bmpPS;        /* The HPS of the stipple-bitmap. */
  2089.     HBITMAP stipple;    /* Stipple-bitmap. */
  2090.     LONG oldPatternSet;        /* Pattern set to be put back in effect. */
  2091.     PPOINTL oldRefPoint;    /* Reference point to put back in effect. */
  2092. {
  2093.     rc = GpiSetPatternSet(destPS, oldPatternSet);
  2094.     rc = GpiSetPatternRefPoint(destPS, oldRefPoint);
  2095.  
  2096.     rc = GpiDeleteSetId(destPS, 254L);
  2097.     /* end of using 254 */
  2098.     /* The bitmap must be reselected in the HPS */
  2099.     GpiSetBitmap(bmpPS, stipple);
  2100. }
  2101.