tkWinDraw.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:35k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkWinDraw.c --
  3.  *
  4.  * This file contains the Xlib emulation functions pertaining to
  5.  * actually drawing objects on a window.
  6.  *
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  * Copyright (c) 1994 Software Research Associates, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * RCS: @(#) $Id: tkWinDraw.c,v 1.12.2.3 2007/12/05 19:17:32 hobbs Exp $
  14.  */
  15. #include "tkWinInt.h"
  16. /*
  17.  * These macros convert between X's bizarre angle units to radians.
  18.  */
  19. #define PI 3.14159265358979
  20. #define XAngleToRadians(a) ((double)(a) / 64 * PI / 180);
  21. /*
  22.  * Translation table between X gc functions and Win32 raster op modes.
  23.  */
  24. int tkpWinRopModes[] = {
  25.     R2_BLACK, /* GXclear */
  26.     R2_MASKPEN, /* GXand */
  27.     R2_MASKPENNOT, /* GXandReverse */
  28.     R2_COPYPEN, /* GXcopy */
  29.     R2_MASKNOTPEN, /* GXandInverted */
  30.     R2_NOT, /* GXnoop */
  31.     R2_XORPEN, /* GXxor */
  32.     R2_MERGEPEN, /* GXor */
  33.     R2_NOTMERGEPEN, /* GXnor */
  34.     R2_NOTXORPEN, /* GXequiv */
  35.     R2_NOT, /* GXinvert */
  36.     R2_MERGEPENNOT, /* GXorReverse */
  37.     R2_NOTCOPYPEN, /* GXcopyInverted */
  38.     R2_MERGENOTPEN, /* GXorInverted */
  39.     R2_NOTMASKPEN, /* GXnand */
  40.     R2_WHITE /* GXset */
  41. };
  42. /*
  43.  * Translation table between X gc functions and Win32 BitBlt op modes.  Some
  44.  * of the operations defined in X don't have names, so we have to construct
  45.  * new opcodes for those functions.  This is arcane and probably not all that
  46.  * useful, but at least it's accurate.
  47.  */
  48. #define NOTSRCAND (DWORD)0x00220326 /* dest = (NOT source) AND dest */
  49. #define NOTSRCINVERT (DWORD)0x00990066 /* dest = (NOT source) XOR dest */
  50. #define SRCORREVERSE (DWORD)0x00DD0228 /* dest = source OR (NOT dest) */
  51. #define SRCNAND (DWORD)0x007700E6 /* dest = NOT (source AND dest) */
  52. int tkpWinBltModes[] = {
  53.     BLACKNESS, /* GXclear */
  54.     SRCAND, /* GXand */
  55.     SRCERASE, /* GXandReverse */
  56.     SRCCOPY, /* GXcopy */
  57.     NOTSRCAND, /* GXandInverted */
  58.     PATCOPY, /* GXnoop */
  59.     SRCINVERT, /* GXxor */
  60.     SRCPAINT, /* GXor */
  61.     NOTSRCERASE, /* GXnor */
  62.     NOTSRCINVERT, /* GXequiv */
  63.     DSTINVERT, /* GXinvert */
  64.     SRCORREVERSE, /* GXorReverse */
  65.     NOTSRCCOPY, /* GXcopyInverted */
  66.     MERGEPAINT, /* GXorInverted */
  67.     SRCNAND, /* GXnand */
  68.     WHITENESS /* GXset */
  69. };
  70. /*
  71.  * The following raster op uses the source bitmap as a mask for the
  72.  * pattern.  This is used to draw in a foreground color but leave the
  73.  * background color transparent.
  74.  */
  75. #define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */
  76. /*
  77.  * The following two raster ops are used to copy the foreground and background
  78.  * bits of a source pattern as defined by a stipple used as the pattern.
  79.  */
  80. #define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
  81. #define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
  82. /*
  83.  * Macros used later in the file.
  84.  */
  85. #define MIN(a,b) ((a>b) ? b : a)
  86. #define MAX(a,b) ((a<b) ? b : a)
  87. /*
  88.  * The followng typedef is used to pass Windows GDI drawing functions.
  89.  */
  90. typedef BOOL (CALLBACK *WinDrawFunc) _ANSI_ARGS_((HDC dc,
  91.     CONST POINT* points, int npoints));
  92. typedef struct ThreadSpecificData {
  93.     POINT *winPoints;    /* Array of points that is reused. */
  94.     int nWinPoints; /* Current size of point array. */
  95. } ThreadSpecificData;
  96. static Tcl_ThreadDataKey dataKey;
  97. /*
  98.  * Forward declarations for procedures defined in this file:
  99.  */
  100. static POINT * ConvertPoints _ANSI_ARGS_((XPoint *points, int npoints,
  101.     int mode, RECT *bbox));
  102. static void DrawOrFillArc _ANSI_ARGS_((Display *display,
  103.     Drawable d, GC gc, int x, int y,
  104.     unsigned int width, unsigned int height,
  105.     int start, int extent, int fill));
  106. static void RenderObject _ANSI_ARGS_((HDC dc, GC gc,
  107.     XPoint* points, int npoints, int mode, HPEN pen,
  108.     WinDrawFunc func));
  109. static HPEN SetUpGraphicsPort _ANSI_ARGS_((GC gc));
  110. /*
  111.  *----------------------------------------------------------------------
  112.  *
  113.  * TkWinGetDrawableDC --
  114.  *
  115.  * Retrieve the DC from a drawable.
  116.  *
  117.  * Results:
  118.  * Returns the window DC for windows.  Returns a new memory DC
  119.  * for pixmaps.
  120.  *
  121.  * Side effects:
  122.  * Sets up the palette for the device context, and saves the old
  123.  * device context state in the passed in TkWinDCState structure.
  124.  *
  125.  *----------------------------------------------------------------------
  126.  */
  127. HDC
  128. TkWinGetDrawableDC(display, d, state)
  129.     Display *display;
  130.     Drawable d;
  131.     TkWinDCState* state;
  132. {
  133.     HDC dc;
  134.     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
  135.     Colormap cmap;
  136.     if (twdPtr->type == TWD_WINDOW) {
  137. TkWindow *winPtr = twdPtr->window.winPtr;
  138.     
  139.   dc = GetDC(twdPtr->window.handle);
  140. if (winPtr == NULL) {
  141.     cmap = DefaultColormap(display, DefaultScreen(display));
  142. } else {
  143.     cmap = winPtr->atts.colormap;
  144. }
  145.     } else if (twdPtr->type == TWD_WINDC) {
  146. dc = twdPtr->winDC.hdc;
  147. cmap = DefaultColormap(display, DefaultScreen(display));
  148.     } else {
  149. dc = CreateCompatibleDC(NULL);
  150. SelectObject(dc, twdPtr->bitmap.handle);
  151. cmap = twdPtr->bitmap.colormap;
  152.     }
  153.     state->palette = TkWinSelectPalette(dc, cmap);
  154.     state->bkmode  = GetBkMode(dc);
  155.     return dc;
  156. }
  157. /*
  158.  *----------------------------------------------------------------------
  159.  *
  160.  * TkWinReleaseDrawableDC --
  161.  *
  162.  * Frees the resources associated with a drawable's DC.
  163.  *
  164.  * Results:
  165.  * None.
  166.  *
  167.  * Side effects:
  168.  * Restores the old bitmap handle to the memory DC for pixmaps.
  169.  *
  170.  *----------------------------------------------------------------------
  171.  */
  172. void
  173. TkWinReleaseDrawableDC(d, dc, state)
  174.     Drawable d;
  175.     HDC dc;
  176.     TkWinDCState *state;
  177. {
  178.     TkWinDrawable *twdPtr = (TkWinDrawable *)d;
  179.     SetBkMode(dc, state->bkmode);
  180.     SelectPalette(dc, state->palette, TRUE);
  181.     RealizePalette(dc);
  182.     if (twdPtr->type == TWD_WINDOW) {
  183. ReleaseDC(TkWinGetHWND(d), dc);
  184.     } else if (twdPtr->type == TWD_BITMAP) {
  185. DeleteDC(dc);
  186.     }
  187. }
  188. /*
  189.  *----------------------------------------------------------------------
  190.  *
  191.  * ConvertPoints --
  192.  *
  193.  * Convert an array of X points to an array of Win32 points.
  194.  *
  195.  * Results:
  196.  * Returns the converted array of POINTs.
  197.  *
  198.  * Side effects:
  199.  * Allocates a block of memory in thread local storage that 
  200.  *      should not be freed.
  201.  *
  202.  *----------------------------------------------------------------------
  203.  */
  204. static POINT *
  205. ConvertPoints(points, npoints, mode, bbox)
  206.     XPoint *points;
  207.     int npoints;
  208.     int mode; /* CoordModeOrigin or CoordModePrevious. */
  209.     RECT *bbox; /* Bounding box of points. */
  210. {
  211.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
  212.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  213.     int i;
  214.     /*
  215.      * To avoid paying the cost of a malloc on every drawing routine,
  216.      * we reuse the last array if it is large enough.
  217.      */
  218.     if (npoints > tsdPtr->nWinPoints) {
  219. if (tsdPtr->winPoints != NULL) {
  220.     ckfree((char *) tsdPtr->winPoints);
  221. }
  222. tsdPtr->winPoints = (POINT *) ckalloc(sizeof(POINT) * npoints);
  223. if (tsdPtr->winPoints == NULL) {
  224.     tsdPtr->nWinPoints = -1;
  225.     return NULL;
  226. }
  227. tsdPtr->nWinPoints = npoints;
  228.     }
  229.     bbox->left = bbox->right = points[0].x;
  230.     bbox->top = bbox->bottom = points[0].y;
  231.     
  232.     if (mode == CoordModeOrigin) {
  233. for (i = 0; i < npoints; i++) {
  234.     tsdPtr->winPoints[i].x = points[i].x;
  235.     tsdPtr->winPoints[i].y = points[i].y;
  236.     bbox->left = MIN(bbox->left, tsdPtr->winPoints[i].x);
  237.     bbox->right = MAX(bbox->right, tsdPtr->winPoints[i].x);
  238.     bbox->top = MIN(bbox->top, tsdPtr->winPoints[i].y);
  239.     bbox->bottom = MAX(bbox->bottom, tsdPtr->winPoints[i].y);
  240. }
  241.     } else {
  242. tsdPtr->winPoints[0].x = points[0].x;
  243. tsdPtr->winPoints[0].y = points[0].y;
  244. for (i = 1; i < npoints; i++) {
  245.     tsdPtr->winPoints[i].x = tsdPtr->winPoints[i-1].x + points[i].x;
  246.     tsdPtr->winPoints[i].y = tsdPtr->winPoints[i-1].y + points[i].y;
  247.     bbox->left = MIN(bbox->left, tsdPtr->winPoints[i].x);
  248.     bbox->right = MAX(bbox->right, tsdPtr->winPoints[i].x);
  249.     bbox->top = MIN(bbox->top, tsdPtr->winPoints[i].y);
  250.     bbox->bottom = MAX(bbox->bottom, tsdPtr->winPoints[i].y);
  251. }
  252.     }
  253.     return tsdPtr->winPoints;
  254. }
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * XCopyArea --
  259.  *
  260.  * Copies data from one drawable to another using block transfer
  261.  * routines.
  262.  *
  263.  * Results:
  264.  * None.
  265.  *
  266.  * Side effects:
  267.  * Data is moved from a window or bitmap to a second window or
  268.  * bitmap.
  269.  *
  270.  *----------------------------------------------------------------------
  271.  */
  272. void
  273. XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y)
  274.     Display* display;
  275.     Drawable src;
  276.     Drawable dest;
  277.     GC gc;
  278.     int src_x, src_y;
  279.     unsigned int width, height;
  280.     int dest_x, dest_y;
  281. {
  282.     HDC srcDC, destDC;
  283.     TkWinDCState srcState, destState;
  284.     TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
  285.     srcDC = TkWinGetDrawableDC(display, src, &srcState);
  286.     if (src != dest) {
  287. destDC = TkWinGetDrawableDC(display, dest, &destState);
  288.     } else {
  289. destDC = srcDC;
  290.     }
  291.     if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  292. SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
  293. OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
  294.     }
  295.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  296.     tkpWinBltModes[gc->function]);
  297.     SelectClipRgn(destDC, NULL);
  298.     if (src != dest) {
  299. TkWinReleaseDrawableDC(dest, destDC, &destState);
  300.     }
  301.     TkWinReleaseDrawableDC(src, srcDC, &srcState);
  302. }
  303. /*
  304.  *----------------------------------------------------------------------
  305.  *
  306.  * XCopyPlane --
  307.  *
  308.  * Copies a bitmap from a source drawable to a destination
  309.  * drawable.  The plane argument specifies which bit plane of
  310.  * the source contains the bitmap.  Note that this implementation
  311.  * ignores the gc->function.
  312.  *
  313.  * Results:
  314.  * None.
  315.  *
  316.  * Side effects:
  317.  * Changes the destination drawable.
  318.  *
  319.  *----------------------------------------------------------------------
  320.  */
  321. void
  322. XCopyPlane(display, src, dest, gc, src_x, src_y, width, height, dest_x,
  323. dest_y, plane)
  324.     Display* display;
  325.     Drawable src;
  326.     Drawable dest;
  327.     GC gc;
  328.     int src_x, src_y;
  329.     unsigned int width, height;
  330.     int dest_x, dest_y;
  331.     unsigned long plane;
  332. {
  333.     HDC srcDC, destDC;
  334.     TkWinDCState srcState, destState;
  335.     HBRUSH bgBrush, fgBrush, oldBrush;
  336.     TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
  337.     display->request++;
  338.     if (plane != 1) {
  339. panic("Unexpected plane specified for XCopyPlane");
  340.     }
  341.     srcDC = TkWinGetDrawableDC(display, src, &srcState);
  342.     if (src != dest) {
  343. destDC = TkWinGetDrawableDC(display, dest, &destState);
  344.     } else {
  345. destDC = srcDC;
  346.     }
  347.     if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) {
  348. /*
  349.  * Case 1: opaque bitmaps.  Windows handles the conversion
  350.  * from one bit to multiple bits by setting 0 to the
  351.  * foreground color, and 1 to the background color (seems
  352.  * backwards, but there you are).
  353.  */
  354. if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
  355.     SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
  356.     OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
  357. }
  358. SetBkMode(destDC, OPAQUE);
  359. SetBkColor(destDC, gc->foreground);
  360. SetTextColor(destDC, gc->background);
  361. BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  362. SRCCOPY);
  363. SelectClipRgn(destDC, NULL);
  364.     } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
  365. if (clipPtr->value.pixmap == src) {
  366.     /*
  367.      * Case 2: transparent bitmaps are handled by setting the
  368.      * destination to the foreground color whenever the source
  369.      * pixel is set.  We need to reset the BkColor and TextColor,
  370.      * because they affect bitmap color mapping.
  371.      */
  372.     fgBrush = CreateSolidBrush(gc->foreground);
  373.     oldBrush = SelectObject(destDC, fgBrush);
  374.     SetBkColor(destDC, RGB(255,255,255));
  375.     SetTextColor(destDC, RGB(0,0,0));
  376.     BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
  377.     MASKPAT);
  378.     SelectObject(destDC, oldBrush);
  379.     DeleteObject(fgBrush);
  380. } else {
  381.     /*
  382.      * Case 3: two arbitrary bitmaps.  Copy the source rectangle
  383.      * into a color pixmap.  Use the result as a brush when
  384.      * copying the clip mask into the destination.
  385.      */
  386.     HDC memDC, maskDC;
  387.     HBITMAP bitmap;
  388.     TkWinDCState maskState;
  389.     fgBrush = CreateSolidBrush(gc->foreground);
  390.     bgBrush = CreateSolidBrush(gc->background);
  391.     maskDC = TkWinGetDrawableDC(display, clipPtr->value.pixmap,
  392.     &maskState);
  393.     memDC = CreateCompatibleDC(destDC);
  394.     bitmap = CreateBitmap(width, height, 1, 1, NULL);
  395.     SelectObject(memDC, bitmap);
  396.     /*
  397.      * Set foreground bits.  We create a new bitmap containing
  398.      * (source AND mask), then use it to set the foreground color
  399.      * into the destination.
  400.      */
  401.     BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, SRCCOPY);
  402.     BitBlt(memDC, 0, 0, width, height, maskDC,
  403.     dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin,
  404.     SRCAND);
  405.     oldBrush = SelectObject(destDC, fgBrush);
  406.     BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0,
  407.     MASKPAT);
  408.     /*
  409.      * Set background bits.  Same as foreground, except we use
  410.      * ((NOT source) AND mask) and the background brush.
  411.      */
  412.     BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y,
  413.     NOTSRCCOPY);
  414.     BitBlt(memDC, 0, 0, width, height, maskDC,
  415.     dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin,
  416.     SRCAND);
  417.     SelectObject(destDC, bgBrush);
  418.     BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0,
  419.     MASKPAT);
  420.     TkWinReleaseDrawableDC(clipPtr->value.pixmap, maskDC, &maskState);
  421.     SelectObject(destDC, oldBrush);
  422.     DeleteDC(memDC);
  423.     DeleteObject(bitmap);
  424.     DeleteObject(fgBrush);
  425.     DeleteObject(bgBrush);
  426. }
  427.     }
  428.     if (src != dest) {
  429. TkWinReleaseDrawableDC(dest, destDC, &destState);
  430.     }
  431.     TkWinReleaseDrawableDC(src, srcDC, &srcState);
  432. }
  433. /*
  434.  *----------------------------------------------------------------------
  435.  *
  436.  * TkPutImage --
  437.  *
  438.  * Copies a subimage from an in-memory image to a rectangle of
  439.  * of the specified drawable.
  440.  *
  441.  * Results:
  442.  * None.
  443.  *
  444.  * Side effects:
  445.  * Draws the image on the specified drawable.
  446.  *
  447.  *----------------------------------------------------------------------
  448.  */
  449. void
  450. TkPutImage(colors, ncolors, display, d, gc, image, src_x, src_y, dest_x,
  451. dest_y, width, height)
  452.     unsigned long *colors; /* Array of pixel values used by this
  453.  * image.  May be NULL. */
  454.     int ncolors; /* Number of colors used, or 0. */
  455.     Display* display;
  456.     Drawable d; /* Destination drawable. */
  457.     GC gc;
  458.     XImage* image; /* Source image. */
  459.     int src_x, src_y; /* Offset of subimage. */      
  460.     int dest_x, dest_y; /* Position of subimage origin in
  461.  * drawable.  */
  462.     unsigned int width, height; /* Dimensions of subimage. */
  463. {
  464.     HDC dc, dcMem;
  465.     TkWinDCState state;
  466.     BITMAPINFO *infoPtr;
  467.     HBITMAP bitmap;
  468.     char *data;
  469.     display->request++;
  470.     dc = TkWinGetDrawableDC(display, d, &state);
  471.     SetROP2(dc, tkpWinRopModes[gc->function]);
  472.     dcMem = CreateCompatibleDC(dc);
  473.     if (image->bits_per_pixel == 1) {
  474. /*
  475.  * If the image isn't in the right format, we have to copy
  476.  * it into a new buffer in MSBFirst and word-aligned format.
  477.  */
  478. if ((image->bitmap_bit_order != MSBFirst)
  479. || (image->bitmap_pad != sizeof(WORD))) {
  480.     data = TkAlignImageData(image, sizeof(WORD), MSBFirst);
  481.     bitmap = CreateBitmap(image->width, image->height, 1, 1, data);
  482.     ckfree(data);
  483. } else {
  484.     bitmap = CreateBitmap(image->width, image->height, 1, 1,
  485.     image->data);
  486. }
  487. SetTextColor(dc, gc->foreground);
  488. SetBkColor(dc, gc->background);
  489.     } else {    
  490. int i, usePalette;
  491. /*
  492.  * Do not use a palette for TrueColor images.
  493.  */
  494. usePalette = (image->bits_per_pixel < 16);
  495. if (usePalette) {
  496.     infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER)
  497.     + sizeof(RGBQUAD)*ncolors);
  498. } else {
  499.     infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER));
  500. }
  501. infoPtr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  502. infoPtr->bmiHeader.biWidth = image->width;
  503. infoPtr->bmiHeader.biHeight = -image->height; /* Top-down order */
  504. infoPtr->bmiHeader.biPlanes = 1;
  505. infoPtr->bmiHeader.biBitCount = image->bits_per_pixel;
  506. infoPtr->bmiHeader.biCompression = BI_RGB;
  507. infoPtr->bmiHeader.biSizeImage = 0;
  508. infoPtr->bmiHeader.biXPelsPerMeter = 0;
  509. infoPtr->bmiHeader.biYPelsPerMeter = 0;
  510. infoPtr->bmiHeader.biClrImportant = 0;
  511. if (usePalette) {
  512.     infoPtr->bmiHeader.biClrUsed = ncolors;
  513.     for (i = 0; i < ncolors; i++) {
  514. infoPtr->bmiColors[i].rgbBlue = GetBValue(colors[i]);
  515. infoPtr->bmiColors[i].rgbGreen = GetGValue(colors[i]);
  516. infoPtr->bmiColors[i].rgbRed = GetRValue(colors[i]);
  517. infoPtr->bmiColors[i].rgbReserved = 0;
  518.     }
  519. } else {
  520.     infoPtr->bmiHeader.biClrUsed = 0;
  521. }
  522. bitmap = CreateDIBitmap(dc, &infoPtr->bmiHeader, CBM_INIT,
  523. image->data, infoPtr, DIB_RGB_COLORS);
  524. ckfree((char *) infoPtr);
  525.     }
  526.     if(!bitmap) {
  527. panic("Fail to allocate bitmapn");
  528. DeleteDC(dcMem);
  529.      TkWinReleaseDrawableDC(d, dc, &state);
  530. return;
  531.     }
  532.     bitmap = SelectObject(dcMem, bitmap);
  533.     BitBlt(dc, dest_x, dest_y, width, height, dcMem, src_x, src_y, SRCCOPY);
  534.     DeleteObject(SelectObject(dcMem, bitmap));
  535.     DeleteDC(dcMem);
  536.     TkWinReleaseDrawableDC(d, dc, &state);
  537. }
  538. /*
  539.  *----------------------------------------------------------------------
  540.  *
  541.  * XFillRectangles --
  542.  *
  543.  * Fill multiple rectangular areas in the given drawable.
  544.  *
  545.  * Results:
  546.  * None.
  547.  *
  548.  * Side effects:
  549.  * Draws onto the specified drawable.
  550.  *
  551.  *----------------------------------------------------------------------
  552.  */
  553. void
  554. XFillRectangles(display, d, gc, rectangles, nrectangles)
  555.     Display* display;
  556.     Drawable d;
  557.     GC gc;
  558.     XRectangle* rectangles;
  559.     int nrectangles;
  560. {
  561.     HDC dc;
  562.     int i;
  563.     RECT rect;
  564.     TkWinDCState state;
  565.     HBRUSH brush, oldBrush;
  566.     if (d == None) {
  567. return;
  568.     }
  569.     dc = TkWinGetDrawableDC(display, d, &state);
  570.     SetROP2(dc, tkpWinRopModes[gc->function]);
  571.     brush = CreateSolidBrush(gc->foreground);
  572.     if ((gc->fill_style == FillStippled
  573.     || gc->fill_style == FillOpaqueStippled)
  574.     && gc->stipple != None) {
  575. TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  576. HBRUSH stipple;
  577. HBITMAP oldBitmap, bitmap;
  578. HDC dcMem;
  579. HBRUSH bgBrush = CreateSolidBrush(gc->background);
  580. if (twdPtr->type != TWD_BITMAP) {
  581.     panic("unexpected drawable type in stipple");
  582. }
  583. /*
  584.  * Select stipple pattern into destination dc.
  585.  */
  586. stipple = CreatePatternBrush(twdPtr->bitmap.handle);
  587. SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  588. oldBrush = SelectObject(dc, stipple);
  589. dcMem = CreateCompatibleDC(dc);
  590. /*
  591.  * For each rectangle, create a drawing surface which is the size of
  592.  * the rectangle and fill it with the background color.  Then merge the
  593.  * result with the stipple pattern.
  594.  */
  595. for (i = 0; i < nrectangles; i++) {
  596.     bitmap = CreateCompatibleBitmap(dc, rectangles[i].width,
  597.     rectangles[i].height);
  598.     oldBitmap = SelectObject(dcMem, bitmap);
  599.     rect.left = 0;
  600.     rect.top = 0;
  601.     rect.right = rectangles[i].width;
  602.     rect.bottom = rectangles[i].height;
  603.     FillRect(dcMem, &rect, brush);
  604.     BitBlt(dc, rectangles[i].x, rectangles[i].y, rectangles[i].width,
  605.     rectangles[i].height, dcMem, 0, 0, COPYFG);
  606.     if (gc->fill_style == FillOpaqueStippled) {
  607. FillRect(dcMem, &rect, bgBrush);
  608. BitBlt(dc, rectangles[i].x, rectangles[i].y,
  609. rectangles[i].width, rectangles[i].height, dcMem,
  610. 0, 0, COPYBG);
  611.     }
  612.     SelectObject(dcMem, oldBitmap);
  613.     DeleteObject(bitmap);
  614. }
  615. DeleteDC(dcMem);
  616. SelectObject(dc, oldBrush);
  617. DeleteObject(stipple);
  618. DeleteObject(bgBrush);
  619.     } else {
  620. if (gc->function == GXcopy) {
  621.     for (i = 0; i < nrectangles; i++) {
  622. rect.left = rectangles[i].x;
  623. rect.right = rect.left + rectangles[i].width;
  624. rect.top = rectangles[i].y;
  625. rect.bottom = rect.top + rectangles[i].height;
  626. FillRect(dc, &rect, brush);
  627.     }
  628. } else {
  629.     HPEN newPen = CreatePen(PS_NULL, 0, gc->foreground);
  630.     HPEN oldPen = SelectObject(dc, newPen);
  631.     oldBrush = SelectObject(dc, brush);
  632.     
  633.     for (i = 0; i < nrectangles; i++) {
  634. Rectangle(dc, rectangles[i].x, rectangles[i].y,
  635.     rectangles[i].x + rectangles[i].width + 1,
  636.     rectangles[i].y + rectangles[i].height + 1);
  637.     }
  638.     SelectObject(dc, oldBrush);
  639.     SelectObject(dc, oldPen);
  640.     DeleteObject(newPen);
  641. }
  642.     }
  643.     DeleteObject(brush);
  644.     TkWinReleaseDrawableDC(d, dc, &state);
  645. }
  646. /*
  647.  *----------------------------------------------------------------------
  648.  *
  649.  * RenderObject --
  650.  *
  651.  * This function draws a shape using a list of points, a
  652.  * stipple pattern, and the specified drawing function.
  653.  *
  654.  * Results:
  655.  * None.
  656.  *
  657.  * Side effects:
  658.  * None.
  659.  *
  660.  *----------------------------------------------------------------------
  661.  */
  662. static void
  663. RenderObject(dc, gc, points, npoints, mode, pen, func)
  664.     HDC dc;
  665.     GC gc;
  666.     XPoint* points;
  667.     int npoints;
  668.     int mode;
  669.     HPEN pen;
  670.     WinDrawFunc func;
  671. {
  672.     RECT rect;
  673.     HPEN oldPen;
  674.     HBRUSH oldBrush;
  675.     POINT *winPoints = ConvertPoints(points, npoints, mode, &rect);
  676.     
  677.     if ((gc->fill_style == FillStippled
  678.     || gc->fill_style == FillOpaqueStippled)
  679.     && gc->stipple != None) {
  680. TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
  681. HDC dcMem;
  682. LONG width, height;
  683. HBITMAP oldBitmap;
  684. int i;
  685. HBRUSH oldMemBrush;
  686. if (twdPtr->type != TWD_BITMAP) {
  687.     panic("unexpected drawable type in stipple");
  688. }
  689. /*
  690.  * Grow the bounding box enough to account for line width.
  691.  */
  692. rect.left -= gc->line_width;
  693. rect.top -= gc->line_width;
  694. rect.right += gc->line_width;
  695. rect.bottom += gc->line_width;
  696. width = rect.right - rect.left;
  697. height = rect.bottom - rect.top;
  698. /*
  699.  * Select stipple pattern into destination dc.
  700.  */
  701. SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
  702. oldBrush = SelectObject(dc, CreatePatternBrush(twdPtr->bitmap.handle));
  703. /*
  704.  * Create temporary drawing surface containing a copy of the
  705.  * destination equal in size to the bounding box of the object.
  706.  */
  707. dcMem = CreateCompatibleDC(dc);
  708. oldBitmap = SelectObject(dcMem, CreateCompatibleBitmap(dc, width,
  709. height));
  710. oldPen = SelectObject(dcMem, pen);
  711. BitBlt(dcMem, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY);
  712. /*
  713.  * Translate the object for rendering in the temporary drawing
  714.  * surface. 
  715.  */
  716. for (i = 0; i < npoints; i++) {
  717.     winPoints[i].x -= rect.left;
  718.     winPoints[i].y -= rect.top;
  719. }
  720. /*
  721.  * Draw the object in the foreground color and copy it to the
  722.  * destination wherever the pattern is set.
  723.  */
  724. SetPolyFillMode(dcMem, (gc->fill_rule == EvenOddRule) ? ALTERNATE
  725. : WINDING);
  726. oldMemBrush = SelectObject(dcMem, CreateSolidBrush(gc->foreground));
  727. (*func)(dcMem, winPoints, npoints);
  728. BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0, COPYFG);
  729. /*
  730.  * If we are rendering an opaque stipple, then draw the polygon in the
  731.  * background color and copy it to the destination wherever the pattern
  732.  * is clear.
  733.  */
  734. if (gc->fill_style == FillOpaqueStippled) {
  735.     DeleteObject(SelectObject(dcMem,
  736.     CreateSolidBrush(gc->background)));
  737.     (*func)(dcMem, winPoints, npoints);
  738.     BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0,
  739.     COPYBG);
  740. }
  741. SelectObject(dcMem, oldPen);
  742. DeleteObject(SelectObject(dcMem, oldMemBrush));
  743. DeleteObject(SelectObject(dcMem, oldBitmap));
  744. DeleteDC(dcMem);
  745.     } else {
  746. oldPen = SelectObject(dc, pen);
  747. oldBrush = SelectObject(dc, CreateSolidBrush(gc->foreground));
  748. SetROP2(dc, tkpWinRopModes[gc->function]);
  749. SetPolyFillMode(dc, (gc->fill_rule == EvenOddRule) ? ALTERNATE
  750. : WINDING);
  751. (*func)(dc, winPoints, npoints);
  752. SelectObject(dc, oldPen);
  753.     }
  754.     DeleteObject(SelectObject(dc, oldBrush));
  755. }
  756. /*
  757.  *----------------------------------------------------------------------
  758.  *
  759.  * XDrawLines --
  760.  *
  761.  * Draw connected lines.
  762.  *
  763.  * Results:
  764.  * None.
  765.  *
  766.  * Side effects:
  767.  * Renders a series of connected lines.
  768.  *
  769.  *----------------------------------------------------------------------
  770.  */
  771. void
  772. XDrawLines(display, d, gc, points, npoints, mode)
  773.     Display* display;
  774.     Drawable d;
  775.     GC gc;
  776.     XPoint* points;
  777.     int npoints;
  778.     int mode;
  779. {
  780.     HPEN pen;
  781.     TkWinDCState state;
  782.     HDC dc;
  783.     
  784.     if (d == None) {
  785. return;
  786.     }
  787.     dc = TkWinGetDrawableDC(display, d, &state);
  788.     pen = SetUpGraphicsPort(gc);
  789.     SetBkMode(dc, TRANSPARENT);
  790.     RenderObject(dc, gc, points, npoints, mode, pen, Polyline);
  791.     DeleteObject(pen);
  792.     
  793.     TkWinReleaseDrawableDC(d, dc, &state);
  794. }
  795. /*
  796.  *----------------------------------------------------------------------
  797.  *
  798.  * XFillPolygon --
  799.  *
  800.  * Draws a filled polygon.
  801.  *
  802.  * Results:
  803.  * None.
  804.  *
  805.  * Side effects:
  806.  * Draws a filled polygon on the specified drawable.
  807.  *
  808.  *----------------------------------------------------------------------
  809.  */
  810. void
  811. XFillPolygon(display, d, gc, points, npoints, shape, mode)
  812.     Display* display;
  813.     Drawable d;
  814.     GC gc;
  815.     XPoint* points;
  816.     int npoints;
  817.     int shape;
  818.     int mode;
  819. {
  820.     HPEN pen;
  821.     TkWinDCState state;
  822.     HDC dc;
  823.     if (d == None) {
  824. return;
  825.     }
  826.     dc = TkWinGetDrawableDC(display, d, &state);
  827.     pen = GetStockObject(NULL_PEN);
  828.     RenderObject(dc, gc, points, npoints, mode, pen, Polygon);
  829.     TkWinReleaseDrawableDC(d, dc, &state);
  830. }
  831. /*
  832.  *----------------------------------------------------------------------
  833.  *
  834.  * XDrawRectangle --
  835.  *
  836.  * Draws a rectangle.
  837.  *
  838.  * Results:
  839.  * None.
  840.  *
  841.  * Side effects:
  842.  * Draws a rectangle on the specified drawable.
  843.  *
  844.  *----------------------------------------------------------------------
  845.  */
  846. void
  847. XDrawRectangle(display, d, gc, x, y, width, height)
  848.     Display* display;
  849.     Drawable d;
  850.     GC gc;
  851.     int x;
  852.     int y;
  853.     unsigned int width;
  854.     unsigned int height;
  855. {
  856.     HPEN pen, oldPen;
  857.     TkWinDCState state;
  858.     HBRUSH oldBrush;
  859.     HDC dc;
  860.     if (d == None) {
  861. return;
  862.     }
  863.     dc = TkWinGetDrawableDC(display, d, &state);
  864.     pen = SetUpGraphicsPort(gc);
  865.     SetBkMode(dc, TRANSPARENT);
  866.     oldPen = SelectObject(dc, pen);
  867.     oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
  868.     SetROP2(dc, tkpWinRopModes[gc->function]);
  869.     Rectangle(dc, x, y, x+width+1, y+height+1);
  870.     DeleteObject(SelectObject(dc, oldPen));
  871.     SelectObject(dc, oldBrush);
  872.     TkWinReleaseDrawableDC(d, dc, &state);
  873. }
  874. /*
  875.  *----------------------------------------------------------------------
  876.  *
  877.  * XDrawArc --
  878.  *
  879.  * Draw an arc.
  880.  *
  881.  * Results:
  882.  * None.
  883.  *
  884.  * Side effects:
  885.  * Draws an arc on the specified drawable.
  886.  *
  887.  *----------------------------------------------------------------------
  888.  */
  889. void
  890. XDrawArc(display, d, gc, x, y, width, height, start, extent)
  891.     Display* display;
  892.     Drawable d;
  893.     GC gc;
  894.     int x;
  895.     int y;
  896.     unsigned int width;
  897.     unsigned int height;
  898.     int start;
  899.     int extent;
  900. {
  901.     display->request++;
  902.     DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 0);
  903. }
  904. /*
  905.  *----------------------------------------------------------------------
  906.  *
  907.  * XFillArc --
  908.  *
  909.  * Draw a filled arc.
  910.  *
  911.  * Results:
  912.  * None.
  913.  *
  914.  * Side effects:
  915.  * Draws a filled arc on the specified drawable.
  916.  *
  917.  *----------------------------------------------------------------------
  918.  */
  919. void
  920. XFillArc(display, d, gc, x, y, width, height, start, extent)
  921.     Display* display;
  922.     Drawable d;
  923.     GC gc;
  924.     int x;
  925.     int y;
  926.     unsigned int width;
  927.     unsigned int height;
  928.     int start;
  929.     int extent;
  930. {
  931.     display->request++;
  932.     DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 1);
  933. }
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * DrawOrFillArc --
  938.  *
  939.  * This procedure handles the rendering of drawn or filled
  940.  * arcs and chords.
  941.  *
  942.  * Results:
  943.  * None.
  944.  *
  945.  * Side effects:
  946.  * Renders the requested arc.
  947.  *
  948.  *----------------------------------------------------------------------
  949.  */
  950. static void
  951. DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, fill)
  952.     Display *display;
  953.     Drawable d;
  954.     GC gc;
  955.     int x, y; /* left top */
  956.     unsigned int width, height;
  957.     int start; /* start: three-o'clock (deg*64) */
  958.     int extent; /* extent: relative (deg*64) */
  959.     int fill; /* ==0 draw, !=0 fill */
  960. {
  961.     HDC dc;
  962.     HBRUSH brush, oldBrush;
  963.     HPEN pen, oldPen;
  964.     TkWinDCState state;
  965.     int clockwise = (extent < 0); /* non-zero if clockwise */
  966.     int xstart, ystart, xend, yend;
  967.     double radian_start, radian_end, xr, yr;
  968.     if (d == None) {
  969. return;
  970.     }
  971.     dc = TkWinGetDrawableDC(display, d, &state);
  972.     SetROP2(dc, tkpWinRopModes[gc->function]);
  973.     /*
  974.      * Compute the absolute starting and ending angles in normalized radians.
  975.      * Swap the start and end if drawing clockwise.
  976.      */
  977.     start = start % (64*360);
  978.     if (start < 0) {
  979. start += (64*360);
  980.     }
  981.     extent = (start+extent) % (64*360);
  982.     if (extent < 0) {
  983. extent += (64*360);
  984.     }
  985.     if (clockwise) {
  986. int tmp = start;
  987. start = extent;
  988. extent = tmp;
  989.     }
  990.     radian_start = XAngleToRadians(start);
  991.     radian_end = XAngleToRadians(extent);
  992.     /*
  993.      * Now compute points on the radial lines that define the starting and
  994.      * ending angles.  Be sure to take into account that the y-coordinate
  995.      * system is inverted.
  996.      */
  997.     xr = x + width / 2.0;
  998.     yr = y + height / 2.0;
  999.     xstart = (int)((xr + cos(radian_start)*width/2.0) + 0.5);
  1000.     ystart = (int)((yr + sin(-radian_start)*height/2.0) + 0.5);
  1001.     xend = (int)((xr + cos(radian_end)*width/2.0) + 0.5);
  1002.     yend = (int)((yr + sin(-radian_end)*height/2.0) + 0.5);
  1003.     /*
  1004.      * Now draw a filled or open figure.  Note that we have to
  1005.      * increase the size of the bounding box by one to account for the
  1006.      * difference in pixel definitions between X and Windows.
  1007.      */
  1008.     pen = SetUpGraphicsPort(gc);
  1009.     oldPen = SelectObject(dc, pen);
  1010.     if (!fill) {
  1011. /*
  1012.  * Note that this call will leave a gap of one pixel at the
  1013.  * end of the arc for thin arcs.  We can't use ArcTo because
  1014.  * it's only supported under Windows NT.
  1015.  */
  1016. SetBkMode(dc, TRANSPARENT);
  1017. Arc(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
  1018.     } else {
  1019. brush = CreateSolidBrush(gc->foreground);
  1020. oldBrush = SelectObject(dc, brush);
  1021. if (gc->arc_mode == ArcChord) {
  1022.     Chord(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
  1023. } else if ( gc->arc_mode == ArcPieSlice ) {
  1024.     Pie(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
  1025. }
  1026. DeleteObject(SelectObject(dc, oldBrush));
  1027.     }
  1028.     DeleteObject(SelectObject(dc, oldPen));
  1029.     TkWinReleaseDrawableDC(d, dc, &state);
  1030. }
  1031. /*
  1032.  *----------------------------------------------------------------------
  1033.  *
  1034.  * SetUpGraphicsPort --
  1035.  *
  1036.  * Set up the graphics port from the given GC.
  1037.  *
  1038.  * Results:
  1039.  * None.
  1040.  *
  1041.  * Side effects:
  1042.  * The current port is adjusted.
  1043.  *
  1044.  *----------------------------------------------------------------------
  1045.  */
  1046. static HPEN
  1047. SetUpGraphicsPort(gc)
  1048.     GC gc;
  1049. {
  1050.     DWORD style;
  1051.     if (gc->line_style == LineOnOffDash) {
  1052. unsigned char *p = (unsigned char *) &(gc->dashes);
  1053. /* pointer to the dash-list */
  1054. /*
  1055.  * Below is a simple translation of serveral dash patterns
  1056.  * to valid windows pen types. Far from complete,
  1057.  * but I don't know how to do it better.
  1058.  * Any ideas: <mailto:j.nijtmans@chello.nl>
  1059.  */
  1060. if (p[1] && p[2]) {
  1061.     if (!p[3] || p[4]) {
  1062. style = PS_DASHDOTDOT; /* -.. */
  1063.     } else {
  1064. style = PS_DASHDOT; /* -. */
  1065.     }
  1066. } else {
  1067.     if (p[0] > (4 * gc->line_width)) {
  1068. style = PS_DASH; /* - */
  1069.     } else {
  1070. style = PS_DOT; /* . */
  1071.     }
  1072. }
  1073.     } else {
  1074. style = PS_SOLID;
  1075.     }
  1076.     if (gc->line_width < 2) {
  1077. return CreatePen(style, gc->line_width, gc->foreground);
  1078.     } else {
  1079. LOGBRUSH lb;
  1080. lb.lbStyle = BS_SOLID;
  1081. lb.lbColor = gc->foreground;
  1082. lb.lbHatch = 0;
  1083. style |= PS_GEOMETRIC;
  1084. switch (gc->cap_style) {
  1085.     case CapNotLast:
  1086.     case CapButt:
  1087. style |= PS_ENDCAP_FLAT; 
  1088. break;
  1089.     case CapRound:
  1090. style |= PS_ENDCAP_ROUND; 
  1091. break;
  1092.     default:
  1093. style |= PS_ENDCAP_SQUARE; 
  1094. break;
  1095. }
  1096. switch (gc->join_style) {
  1097.     case JoinMiter: 
  1098. style |= PS_JOIN_MITER; 
  1099. break;
  1100.     case JoinRound:
  1101. style |= PS_JOIN_ROUND; 
  1102. break;
  1103.     default:
  1104. style |= PS_JOIN_BEVEL; 
  1105. break;
  1106. }
  1107. return ExtCreatePen(style, gc->line_width, &lb, 0, NULL);
  1108.     }
  1109. }
  1110. /*
  1111.  *----------------------------------------------------------------------
  1112.  *
  1113.  * TkScrollWindow --
  1114.  *
  1115.  * Scroll a rectangle of the specified window and accumulate
  1116.  * a damage region.
  1117.  *
  1118.  * Results:
  1119.  * Returns 0 if the scroll genereated no additional damage.
  1120.  * Otherwise, sets the region that needs to be repainted after
  1121.  * scrolling and returns 1.
  1122.  *
  1123.  * Side effects:
  1124.  * Scrolls the bits in the window.
  1125.  *
  1126.  *----------------------------------------------------------------------
  1127.  */
  1128. int
  1129. TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn)
  1130.     Tk_Window tkwin; /* The window to be scrolled. */
  1131.     GC gc; /* GC for window to be scrolled. */
  1132.     int x, y, width, height; /* Position rectangle to be scrolled. */
  1133.     int dx, dy; /* Distance rectangle should be moved. */
  1134.     TkRegion damageRgn; /* Region to accumulate damage in. */
  1135. {
  1136.     HWND hwnd = TkWinGetHWND(Tk_WindowId(tkwin));
  1137.     RECT scrollRect;
  1138.     scrollRect.left = x;
  1139.     scrollRect.top = y;
  1140.     scrollRect.right = x + width;
  1141.     scrollRect.bottom = y + height;
  1142.     return (ScrollWindowEx(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn,
  1143.     NULL, 0) == NULLREGION) ? 0 : 1;
  1144. }
  1145. /*
  1146.  *----------------------------------------------------------------------
  1147.  *
  1148.  * TkWinFillRect --
  1149.  *
  1150.  * This routine fills a rectangle with the foreground color
  1151.  * from the specified GC ignoring all other GC values.  This
  1152.  * is the fastest way to fill a drawable with a solid color.
  1153.  *
  1154.  * Results:
  1155.  * None.
  1156.  *
  1157.  * Side effects:
  1158.  * Modifies the contents of the DC drawing surface.
  1159.  *
  1160.  *----------------------------------------------------------------------
  1161.  */
  1162. void
  1163. TkWinFillRect(dc, x, y, width, height, pixel)
  1164.     HDC dc;
  1165.     int x, y, width, height;
  1166.     int pixel;
  1167. {
  1168.     RECT rect;
  1169.     COLORREF oldColor;
  1170.     rect.left = x;
  1171.     rect.top = y;
  1172.     rect.right = x + width;
  1173.     rect.bottom = y + height;
  1174.     oldColor = SetBkColor(dc, (COLORREF)pixel);
  1175.     SetBkMode(dc, OPAQUE);
  1176.     ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  1177.     SetBkColor(dc, oldColor);
  1178. }
  1179. /*
  1180.  *----------------------------------------------------------------------
  1181.  *
  1182.  * TkpDrawHighlightBorder --
  1183.  *
  1184.  * This procedure draws a rectangular ring around the outside of
  1185.  * a widget to indicate that it has received the input focus.
  1186.  *
  1187.  *      On Windows, we just draw the simple inset ring.  On other sytems,
  1188.  *      e.g. the Mac, the focus ring is a little more complicated, so we
  1189.  *      need this abstraction.
  1190.  *
  1191.  * Results:
  1192.  * None.
  1193.  *
  1194.  * Side effects:
  1195.  * A rectangle "width" pixels wide is drawn in "drawable",
  1196.  * corresponding to the outer area of "tkwin".
  1197.  *
  1198.  *----------------------------------------------------------------------
  1199.  */
  1200. void 
  1201. TkpDrawHighlightBorder(tkwin, fgGC, bgGC, highlightWidth, drawable)
  1202.     Tk_Window tkwin;
  1203.     GC fgGC;
  1204.     GC bgGC;
  1205.     int highlightWidth;
  1206.     Drawable drawable;
  1207. {
  1208.     TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0);
  1209. }
  1210. /*
  1211.  *----------------------------------------------------------------------
  1212.  *
  1213.  * TkpDrawFrame --
  1214.  *
  1215.  * This procedure draws the rectangular frame area.
  1216.  *
  1217.  * Results:
  1218.  * None.
  1219.  *
  1220.  * Side effects:
  1221.  * Draws inside the tkwin area.
  1222.  *
  1223.  *----------------------------------------------------------------------
  1224.  */
  1225. void
  1226. TkpDrawFrame (Tk_Window tkwin, Tk_3DBorder border,
  1227. int highlightWidth, int borderWidth, int relief)
  1228. {
  1229.     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
  1230.     border, highlightWidth, highlightWidth,
  1231.     Tk_Width(tkwin) - 2 * highlightWidth,
  1232.     Tk_Height(tkwin) - 2 * highlightWidth,
  1233.     borderWidth, relief);
  1234. }