4 * This file contains the Xlib emulation functions pertaining to
5 * actually drawing objects on a window.
7 * Copyright (c) 1995 Sun Microsystems, Inc.
8 * Copyright (c) 1994 Software Research Associates, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 * These macros convert between X's bizarre angle units to radians.
22 #define PI 3.14159265358979
23 #define XAngleToRadians(a) ((double)(a) / 64 * PI / 180);
26 * Translation table between X gc functions and Win32 raster op modes.
29 int tkpWinRopModes[] = {
30 R2_BLACK, /* GXclear */
31 R2_MASKPEN, /* GXand */
32 R2_MASKPENNOT, /* GXandReverse */
33 R2_COPYPEN, /* GXcopy */
34 R2_MASKNOTPEN, /* GXandInverted */
36 R2_XORPEN, /* GXxor */
37 R2_MERGEPEN, /* GXor */
38 R2_NOTMERGEPEN, /* GXnor */
39 R2_NOTXORPEN, /* GXequiv */
40 R2_NOT, /* GXinvert */
41 R2_MERGEPENNOT, /* GXorReverse */
42 R2_NOTCOPYPEN, /* GXcopyInverted */
43 R2_MERGENOTPEN, /* GXorInverted */
44 R2_NOTMASKPEN, /* GXnand */
49 * Translation table between X gc functions and Win32 BitBlt op modes. Some
50 * of the operations defined in X don't have names, so we have to construct
51 * new opcodes for those functions. This is arcane and probably not all that
52 * useful, but at least it's accurate.
55 #define NOTSRCAND (DWORD)0x00220326 /* dest = (NOT source) AND dest */
56 #define NOTSRCINVERT (DWORD)0x00990066 /* dest = (NOT source) XOR dest */
57 #define SRCORREVERSE (DWORD)0x00DD0228 /* dest = source OR (NOT dest) */
58 #define SRCNAND (DWORD)0x007700E6 /* dest = NOT (source AND dest) */
60 static int bltModes[] = {
61 BLACKNESS, /* GXclear */
63 SRCERASE, /* GXandReverse */
65 NOTSRCAND, /* GXandInverted */
67 SRCINVERT, /* GXxor */
69 NOTSRCERASE, /* GXnor */
70 NOTSRCINVERT, /* GXequiv */
71 DSTINVERT, /* GXinvert */
72 SRCORREVERSE, /* GXorReverse */
73 NOTSRCCOPY, /* GXcopyInverted */
74 MERGEPAINT, /* GXorInverted */
80 * The following raster op uses the source bitmap as a mask for the
81 * pattern. This is used to draw in a foreground color but leave the
82 * background color transparent.
85 #define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */
88 * The following two raster ops are used to copy the foreground and background
89 * bits of a source pattern as defined by a stipple used as the pattern.
92 #define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
93 #define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
96 * Macros used later in the file.
99 #define MIN(a,b) ((a>b) ? b : a)
100 #define MAX(a,b) ((a<b) ? b : a)
103 * The followng typedef is used to pass Windows GDI drawing functions.
106 typedef BOOL (CALLBACK *WinDrawFunc) _ANSI_ARGS_((HDC dc,
107 CONST POINT* points, int npoints));
109 typedef struct ThreadSpecificData {
110 POINT *winPoints; /* Array of points that is reused. */
111 int nWinPoints; /* Current size of point array. */
112 } ThreadSpecificData;
113 static Tcl_ThreadDataKey dataKey;
116 * Forward declarations for procedures defined in this file:
119 static POINT * ConvertPoints _ANSI_ARGS_((XPoint *points, int npoints,
120 int mode, RECT *bbox));
121 static void DrawOrFillArc _ANSI_ARGS_((Display *display,
122 Drawable d, GC gc, int x, int y,
123 unsigned int width, unsigned int height,
124 int start, int extent, int fill));
125 static void RenderObject _ANSI_ARGS_((HDC dc, GC gc,
126 XPoint* points, int npoints, int mode, HPEN pen,
128 static HPEN SetUpGraphicsPort _ANSI_ARGS_((GC gc));
131 *----------------------------------------------------------------------
133 * TkWinGetDrawableDC --
135 * Retrieve the DC from a drawable.
138 * Returns the window DC for windows. Returns a new memory DC
142 * Sets up the palette for the device context, and saves the old
143 * device context state in the passed in TkWinDCState structure.
145 *----------------------------------------------------------------------
149 TkWinGetDrawableDC(display, d, state)
155 TkWinDrawable *twdPtr = (TkWinDrawable *)d;
158 if (twdPtr->type == TWD_WINDOW) {
159 TkWindow *winPtr = twdPtr->window.winPtr;
161 dc = GetDC(twdPtr->window.handle);
162 if (winPtr == NULL) {
163 cmap = DefaultColormap(display, DefaultScreen(display));
165 cmap = winPtr->atts.colormap;
167 } else if (twdPtr->type == TWD_WINDC) {
168 dc = twdPtr->winDC.hdc;
169 cmap = DefaultColormap(display, DefaultScreen(display));
171 dc = CreateCompatibleDC(NULL);
172 SelectObject(dc, twdPtr->bitmap.handle);
173 cmap = twdPtr->bitmap.colormap;
175 state->palette = TkWinSelectPalette(dc, cmap);
176 state->bkmode = GetBkMode(dc);
181 *----------------------------------------------------------------------
183 * TkWinReleaseDrawableDC --
185 * Frees the resources associated with a drawable's DC.
191 * Restores the old bitmap handle to the memory DC for pixmaps.
193 *----------------------------------------------------------------------
197 TkWinReleaseDrawableDC(d, dc, state)
202 TkWinDrawable *twdPtr = (TkWinDrawable *)d;
203 SetBkMode(dc, state->bkmode);
204 SelectPalette(dc, state->palette, TRUE);
206 if (twdPtr->type == TWD_WINDOW) {
207 ReleaseDC(TkWinGetHWND(d), dc);
208 } else if (twdPtr->type == TWD_BITMAP) {
214 *----------------------------------------------------------------------
218 * Convert an array of X points to an array of Win32 points.
221 * Returns the converted array of POINTs.
224 * Allocates a block of memory in thread local storage that
225 * should not be freed.
227 *----------------------------------------------------------------------
231 ConvertPoints(points, npoints, mode, bbox)
234 int mode; /* CoordModeOrigin or CoordModePrevious. */
235 RECT *bbox; /* Bounding box of points. */
237 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
238 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
242 * To avoid paying the cost of a malloc on every drawing routine,
243 * we reuse the last array if it is large enough.
246 if (npoints > tsdPtr->nWinPoints) {
247 if (tsdPtr->winPoints != NULL) {
248 ckfree((char *) tsdPtr->winPoints);
250 tsdPtr->winPoints = (POINT *) ckalloc(sizeof(POINT) * npoints);
251 if (tsdPtr->winPoints == NULL) {
252 tsdPtr->nWinPoints = -1;
255 tsdPtr->nWinPoints = npoints;
258 bbox->left = bbox->right = points[0].x;
259 bbox->top = bbox->bottom = points[0].y;
261 if (mode == CoordModeOrigin) {
262 for (i = 0; i < npoints; i++) {
263 tsdPtr->winPoints[i].x = points[i].x;
264 tsdPtr->winPoints[i].y = points[i].y;
265 bbox->left = MIN(bbox->left, tsdPtr->winPoints[i].x);
266 bbox->right = MAX(bbox->right, tsdPtr->winPoints[i].x);
267 bbox->top = MIN(bbox->top, tsdPtr->winPoints[i].y);
268 bbox->bottom = MAX(bbox->bottom, tsdPtr->winPoints[i].y);
271 tsdPtr->winPoints[0].x = points[0].x;
272 tsdPtr->winPoints[0].y = points[0].y;
273 for (i = 1; i < npoints; i++) {
274 tsdPtr->winPoints[i].x = tsdPtr->winPoints[i-1].x + points[i].x;
275 tsdPtr->winPoints[i].y = tsdPtr->winPoints[i-1].y + points[i].y;
276 bbox->left = MIN(bbox->left, tsdPtr->winPoints[i].x);
277 bbox->right = MAX(bbox->right, tsdPtr->winPoints[i].x);
278 bbox->top = MIN(bbox->top, tsdPtr->winPoints[i].y);
279 bbox->bottom = MAX(bbox->bottom, tsdPtr->winPoints[i].y);
282 return tsdPtr->winPoints;
286 *----------------------------------------------------------------------
290 * Copies data from one drawable to another using block transfer
297 * Data is moved from a window or bitmap to a second window or
300 *----------------------------------------------------------------------
304 XCopyArea(display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y)
310 unsigned int width, height;
314 TkWinDCState srcState, destState;
315 TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
317 srcDC = TkWinGetDrawableDC(display, src, &srcState);
320 destDC = TkWinGetDrawableDC(display, dest, &destState);
325 if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
326 SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
327 OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
330 BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
331 bltModes[gc->function]);
333 SelectClipRgn(destDC, NULL);
336 TkWinReleaseDrawableDC(dest, destDC, &destState);
338 TkWinReleaseDrawableDC(src, srcDC, &srcState);
342 *----------------------------------------------------------------------
346 * Copies a bitmap from a source drawable to a destination
347 * drawable. The plane argument specifies which bit plane of
348 * the source contains the bitmap. Note that this implementation
349 * ignores the gc->function.
355 * Changes the destination drawable.
357 *----------------------------------------------------------------------
361 XCopyPlane(display, src, dest, gc, src_x, src_y, width, height, dest_x,
368 unsigned int width, height;
373 TkWinDCState srcState, destState;
374 HBRUSH bgBrush, fgBrush, oldBrush;
375 TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask;
380 panic("Unexpected plane specified for XCopyPlane");
383 srcDC = TkWinGetDrawableDC(display, src, &srcState);
386 destDC = TkWinGetDrawableDC(display, dest, &destState);
391 if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) {
394 * Case 1: opaque bitmaps. Windows handles the conversion
395 * from one bit to multiple bits by setting 0 to the
396 * foreground color, and 1 to the background color (seems
397 * backwards, but there you are).
400 if (clipPtr && clipPtr->type == TKP_CLIP_REGION) {
401 SelectClipRgn(destDC, (HRGN) clipPtr->value.region);
402 OffsetClipRgn(destDC, gc->clip_x_origin, gc->clip_y_origin);
405 SetBkMode(destDC, OPAQUE);
406 SetBkColor(destDC, gc->foreground);
407 SetTextColor(destDC, gc->background);
408 BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
411 SelectClipRgn(destDC, NULL);
412 } else if (clipPtr->type == TKP_CLIP_PIXMAP) {
413 if (clipPtr->value.pixmap == src) {
416 * Case 2: transparent bitmaps are handled by setting the
417 * destination to the foreground color whenever the source
421 fgBrush = CreateSolidBrush(gc->foreground);
422 oldBrush = SelectObject(destDC, fgBrush);
423 BitBlt(destDC, dest_x, dest_y, width, height, srcDC, src_x, src_y,
425 SelectObject(destDC, oldBrush);
426 DeleteObject(fgBrush);
430 * Case 3: two arbitrary bitmaps. Copy the source rectangle
431 * into a color pixmap. Use the result as a brush when
432 * copying the clip mask into the destination.
437 TkWinDCState maskState;
439 fgBrush = CreateSolidBrush(gc->foreground);
440 bgBrush = CreateSolidBrush(gc->background);
441 maskDC = TkWinGetDrawableDC(display, clipPtr->value.pixmap,
443 memDC = CreateCompatibleDC(destDC);
444 bitmap = CreateBitmap(width, height, 1, 1, NULL);
445 SelectObject(memDC, bitmap);
448 * Set foreground bits. We create a new bitmap containing
449 * (source AND mask), then use it to set the foreground color
450 * into the destination.
453 BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y, SRCCOPY);
454 BitBlt(memDC, 0, 0, width, height, maskDC,
455 dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin,
457 oldBrush = SelectObject(destDC, fgBrush);
458 BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0,
462 * Set background bits. Same as foreground, except we use
463 * ((NOT source) AND mask) and the background brush.
466 BitBlt(memDC, 0, 0, width, height, srcDC, src_x, src_y,
468 BitBlt(memDC, 0, 0, width, height, maskDC,
469 dest_x - gc->clip_x_origin, dest_y - gc->clip_y_origin,
471 SelectObject(destDC, bgBrush);
472 BitBlt(destDC, dest_x, dest_y, width, height, memDC, 0, 0,
475 TkWinReleaseDrawableDC(clipPtr->value.pixmap, maskDC, &maskState);
476 SelectObject(destDC, oldBrush);
478 DeleteObject(bitmap);
479 DeleteObject(fgBrush);
480 DeleteObject(bgBrush);
484 TkWinReleaseDrawableDC(dest, destDC, &destState);
486 TkWinReleaseDrawableDC(src, srcDC, &srcState);
490 *----------------------------------------------------------------------
494 * Copies a subimage from an in-memory image to a rectangle of
495 * of the specified drawable.
501 * Draws the image on the specified drawable.
503 *----------------------------------------------------------------------
507 TkPutImage(colors, ncolors, display, d, gc, image, src_x, src_y, dest_x,
508 dest_y, width, height)
509 unsigned long *colors; /* Array of pixel values used by this
510 * image. May be NULL. */
511 int ncolors; /* Number of colors used, or 0. */
513 Drawable d; /* Destination drawable. */
515 XImage* image; /* Source image. */
516 int src_x, src_y; /* Offset of subimage. */
517 int dest_x, dest_y; /* Position of subimage origin in
519 unsigned int width, height; /* Dimensions of subimage. */
529 dc = TkWinGetDrawableDC(display, d, &state);
530 SetROP2(dc, tkpWinRopModes[gc->function]);
531 dcMem = CreateCompatibleDC(dc);
533 if (image->bits_per_pixel == 1) {
535 * If the image isn't in the right format, we have to copy
536 * it into a new buffer in MSBFirst and word-aligned format.
539 if ((image->bitmap_bit_order != MSBFirst)
540 || (image->bitmap_pad != sizeof(WORD))) {
541 data = TkAlignImageData(image, sizeof(WORD), MSBFirst);
542 bitmap = CreateBitmap(image->width, image->height, 1, 1, data);
545 bitmap = CreateBitmap(image->width, image->height, 1, 1,
548 SetTextColor(dc, gc->foreground);
549 SetBkColor(dc, gc->background);
554 * Do not use a palette for TrueColor images.
557 usePalette = (image->bits_per_pixel < 16);
560 infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER)
561 + sizeof(RGBQUAD)*ncolors);
563 infoPtr = (BITMAPINFO*) ckalloc(sizeof(BITMAPINFOHEADER));
566 infoPtr->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
567 infoPtr->bmiHeader.biWidth = image->width;
568 infoPtr->bmiHeader.biHeight = -image->height; /* Top-down order */
569 infoPtr->bmiHeader.biPlanes = 1;
570 infoPtr->bmiHeader.biBitCount = image->bits_per_pixel;
571 infoPtr->bmiHeader.biCompression = BI_RGB;
572 infoPtr->bmiHeader.biSizeImage = 0;
573 infoPtr->bmiHeader.biXPelsPerMeter = 0;
574 infoPtr->bmiHeader.biYPelsPerMeter = 0;
575 infoPtr->bmiHeader.biClrImportant = 0;
578 infoPtr->bmiHeader.biClrUsed = ncolors;
579 for (i = 0; i < ncolors; i++) {
580 infoPtr->bmiColors[i].rgbBlue = GetBValue(colors[i]);
581 infoPtr->bmiColors[i].rgbGreen = GetGValue(colors[i]);
582 infoPtr->bmiColors[i].rgbRed = GetRValue(colors[i]);
583 infoPtr->bmiColors[i].rgbReserved = 0;
586 infoPtr->bmiHeader.biClrUsed = 0;
588 bitmap = CreateDIBitmap(dc, &infoPtr->bmiHeader, CBM_INIT,
589 image->data, infoPtr, DIB_RGB_COLORS);
590 ckfree((char *) infoPtr);
592 bitmap = SelectObject(dcMem, bitmap);
593 BitBlt(dc, dest_x, dest_y, width, height, dcMem, src_x, src_y, SRCCOPY);
594 DeleteObject(SelectObject(dcMem, bitmap));
596 TkWinReleaseDrawableDC(d, dc, &state);
600 *----------------------------------------------------------------------
604 * Fill multiple rectangular areas in the given drawable.
610 * Draws onto the specified drawable.
612 *----------------------------------------------------------------------
616 XFillRectangles(display, d, gc, rectangles, nrectangles)
620 XRectangle* rectangles;
633 dc = TkWinGetDrawableDC(display, d, &state);
634 SetROP2(dc, tkpWinRopModes[gc->function]);
635 brush = CreateSolidBrush(gc->foreground);
637 if ((gc->fill_style == FillStippled
638 || gc->fill_style == FillOpaqueStippled)
639 && gc->stipple != None) {
640 TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
641 HBRUSH oldBrush, stipple;
642 HBITMAP oldBitmap, bitmap;
644 HBRUSH bgBrush = CreateSolidBrush(gc->background);
646 if (twdPtr->type != TWD_BITMAP) {
647 panic("unexpected drawable type in stipple");
651 * Select stipple pattern into destination dc.
654 stipple = CreatePatternBrush(twdPtr->bitmap.handle);
655 SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
656 oldBrush = SelectObject(dc, stipple);
657 dcMem = CreateCompatibleDC(dc);
660 * For each rectangle, create a drawing surface which is the size of
661 * the rectangle and fill it with the background color. Then merge the
662 * result with the stipple pattern.
665 for (i = 0; i < nrectangles; i++) {
666 bitmap = CreateCompatibleBitmap(dc, rectangles[i].width,
667 rectangles[i].height);
668 oldBitmap = SelectObject(dcMem, bitmap);
671 rect.right = rectangles[i].width;
672 rect.bottom = rectangles[i].height;
673 FillRect(dcMem, &rect, brush);
674 BitBlt(dc, rectangles[i].x, rectangles[i].y, rectangles[i].width,
675 rectangles[i].height, dcMem, 0, 0, COPYFG);
676 if (gc->fill_style == FillOpaqueStippled) {
677 FillRect(dcMem, &rect, bgBrush);
678 BitBlt(dc, rectangles[i].x, rectangles[i].y,
679 rectangles[i].width, rectangles[i].height, dcMem,
682 SelectObject(dcMem, oldBitmap);
683 DeleteObject(bitmap);
687 SelectObject(dc, oldBrush);
688 DeleteObject(stipple);
689 DeleteObject(bgBrush);
691 for (i = 0; i < nrectangles; i++) {
692 TkWinFillRect(dc, rectangles[i].x, rectangles[i].y,
693 rectangles[i].width, rectangles[i].height, gc->foreground);
697 TkWinReleaseDrawableDC(d, dc, &state);
701 *----------------------------------------------------------------------
705 * This function draws a shape using a list of points, a
706 * stipple pattern, and the specified drawing function.
714 *----------------------------------------------------------------------
718 RenderObject(dc, gc, points, npoints, mode, pen, func)
730 POINT *winPoints = ConvertPoints(points, npoints, mode, &rect);
732 if ((gc->fill_style == FillStippled
733 || gc->fill_style == FillOpaqueStippled)
734 && gc->stipple != None) {
736 TkWinDrawable *twdPtr = (TkWinDrawable *)gc->stipple;
743 if (twdPtr->type != TWD_BITMAP) {
744 panic("unexpected drawable type in stipple");
748 * Grow the bounding box enough to account for wide lines.
751 if (gc->line_width > 1) {
752 rect.left -= gc->line_width;
753 rect.top -= gc->line_width;
754 rect.right += gc->line_width;
755 rect.bottom += gc->line_width;
758 width = rect.right - rect.left;
759 height = rect.bottom - rect.top;
762 * Select stipple pattern into destination dc.
765 SetBrushOrgEx(dc, gc->ts_x_origin, gc->ts_y_origin, NULL);
766 oldBrush = SelectObject(dc, CreatePatternBrush(twdPtr->bitmap.handle));
769 * Create temporary drawing surface containing a copy of the
770 * destination equal in size to the bounding box of the object.
773 dcMem = CreateCompatibleDC(dc);
774 oldBitmap = SelectObject(dcMem, CreateCompatibleBitmap(dc, width,
776 oldPen = SelectObject(dcMem, pen);
777 BitBlt(dcMem, 0, 0, width, height, dc, rect.left, rect.top, SRCCOPY);
780 * Translate the object for rendering in the temporary drawing
784 for (i = 0; i < npoints; i++) {
785 winPoints[i].x -= rect.left;
786 winPoints[i].y -= rect.top;
790 * Draw the object in the foreground color and copy it to the
791 * destination wherever the pattern is set.
794 SetPolyFillMode(dcMem, (gc->fill_rule == EvenOddRule) ? ALTERNATE
796 oldMemBrush = SelectObject(dcMem, CreateSolidBrush(gc->foreground));
797 (*func)(dcMem, winPoints, npoints);
798 BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0, COPYFG);
801 * If we are rendering an opaque stipple, then draw the polygon in the
802 * background color and copy it to the destination wherever the pattern
806 if (gc->fill_style == FillOpaqueStippled) {
807 DeleteObject(SelectObject(dcMem,
808 CreateSolidBrush(gc->background)));
809 (*func)(dcMem, winPoints, npoints);
810 BitBlt(dc, rect.left, rect.top, width, height, dcMem, 0, 0,
814 SelectObject(dcMem, oldPen);
815 DeleteObject(SelectObject(dcMem, oldMemBrush));
816 DeleteObject(SelectObject(dcMem, oldBitmap));
819 oldPen = SelectObject(dc, pen);
820 oldBrush = SelectObject(dc, CreateSolidBrush(gc->foreground));
821 SetROP2(dc, tkpWinRopModes[gc->function]);
823 SetPolyFillMode(dc, (gc->fill_rule == EvenOddRule) ? ALTERNATE
826 (*func)(dc, winPoints, npoints);
828 SelectObject(dc, oldPen);
830 DeleteObject(SelectObject(dc, oldBrush));
834 *----------------------------------------------------------------------
838 * Draw connected lines.
844 * Renders a series of connected lines.
846 *----------------------------------------------------------------------
850 XDrawLines(display, d, gc, points, npoints, mode)
866 dc = TkWinGetDrawableDC(display, d, &state);
868 pen = SetUpGraphicsPort(gc);
869 SetBkMode(dc, TRANSPARENT);
870 RenderObject(dc, gc, points, npoints, mode, pen, Polyline);
873 TkWinReleaseDrawableDC(d, dc, &state);
877 *----------------------------------------------------------------------
881 * Draws a filled polygon.
887 * Draws a filled polygon on the specified drawable.
889 *----------------------------------------------------------------------
893 XFillPolygon(display, d, gc, points, npoints, shape, mode)
910 dc = TkWinGetDrawableDC(display, d, &state);
912 pen = GetStockObject(NULL_PEN);
913 RenderObject(dc, gc, points, npoints, mode, pen, Polygon);
915 TkWinReleaseDrawableDC(d, dc, &state);
919 *----------------------------------------------------------------------
929 * Draws a rectangle on the specified drawable.
931 *----------------------------------------------------------------------
935 XDrawRectangle(display, d, gc, x, y, width, height)
953 dc = TkWinGetDrawableDC(display, d, &state);
955 pen = SetUpGraphicsPort(gc);
956 SetBkMode(dc, TRANSPARENT);
957 oldPen = SelectObject(dc, pen);
958 oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
959 SetROP2(dc, tkpWinRopModes[gc->function]);
961 Rectangle(dc, x, y, x+width+1, y+height+1);
963 DeleteObject(SelectObject(dc, oldPen));
964 SelectObject(dc, oldBrush);
965 TkWinReleaseDrawableDC(d, dc, &state);
969 *----------------------------------------------------------------------
979 * Draws an arc on the specified drawable.
981 *----------------------------------------------------------------------
985 XDrawArc(display, d, gc, x, y, width, height, start, extent)
998 DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 0);
1002 *----------------------------------------------------------------------
1006 * Draw a filled arc.
1012 * Draws a filled arc on the specified drawable.
1014 *----------------------------------------------------------------------
1018 XFillArc(display, d, gc, x, y, width, height, start, extent)
1025 unsigned int height;
1031 DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, 1);
1035 *----------------------------------------------------------------------
1039 * This procedure handles the rendering of drawn or filled
1046 * Renders the requested arc.
1048 *----------------------------------------------------------------------
1052 DrawOrFillArc(display, d, gc, x, y, width, height, start, extent, fill)
1056 int x, y; /* left top */
1057 unsigned int width, height;
1058 int start; /* start: three-o'clock (deg*64) */
1059 int extent; /* extent: relative (deg*64) */
1060 int fill; /* ==0 draw, !=0 fill */
1063 HBRUSH brush, oldBrush;
1066 int clockwise = (extent < 0); /* non-zero if clockwise */
1067 int xstart, ystart, xend, yend;
1068 double radian_start, radian_end, xr, yr;
1074 dc = TkWinGetDrawableDC(display, d, &state);
1076 SetROP2(dc, tkpWinRopModes[gc->function]);
1079 * Compute the absolute starting and ending angles in normalized radians.
1080 * Swap the start and end if drawing clockwise.
1083 start = start % (64*360);
1087 extent = (start+extent) % (64*360);
1096 radian_start = XAngleToRadians(start);
1097 radian_end = XAngleToRadians(extent);
1100 * Now compute points on the radial lines that define the starting and
1101 * ending angles. Be sure to take into account that the y-coordinate
1102 * system is inverted.
1105 xr = x + width / 2.0;
1106 yr = y + height / 2.0;
1107 xstart = (int)((xr + cos(radian_start)*width/2.0) + 0.5);
1108 ystart = (int)((yr + sin(-radian_start)*height/2.0) + 0.5);
1109 xend = (int)((xr + cos(radian_end)*width/2.0) + 0.5);
1110 yend = (int)((yr + sin(-radian_end)*height/2.0) + 0.5);
1113 * Now draw a filled or open figure. Note that we have to
1114 * increase the size of the bounding box by one to account for the
1115 * difference in pixel definitions between X and Windows.
1118 pen = SetUpGraphicsPort(gc);
1119 oldPen = SelectObject(dc, pen);
1122 * Note that this call will leave a gap of one pixel at the
1123 * end of the arc for thin arcs. We can't use ArcTo because
1124 * it's only supported under Windows NT.
1127 SetBkMode(dc, TRANSPARENT);
1128 Arc(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
1130 brush = CreateSolidBrush(gc->foreground);
1131 oldBrush = SelectObject(dc, brush);
1132 if (gc->arc_mode == ArcChord) {
1133 Chord(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
1134 } else if ( gc->arc_mode == ArcPieSlice ) {
1135 Pie(dc, x, y, x+width+1, y+height+1, xstart, ystart, xend, yend);
1137 DeleteObject(SelectObject(dc, oldBrush));
1139 DeleteObject(SelectObject(dc, oldPen));
1140 TkWinReleaseDrawableDC(d, dc, &state);
1144 *----------------------------------------------------------------------
1146 * SetUpGraphicsPort --
1148 * Set up the graphics port from the given GC.
1154 * The current port is adjusted.
1156 *----------------------------------------------------------------------
1160 SetUpGraphicsPort(gc)
1165 if (gc->line_style == LineOnOffDash) {
1166 unsigned char *p = (unsigned char *) &(gc->dashes);
1167 /* pointer to the dash-list */
1170 * Below is a simple translation of serveral dash patterns
1171 * to valid windows pen types. Far from complete,
1172 * but I don't know how to do it better.
1173 * Any ideas: <mailto:j.nijtmans@chello.nl>
1177 if (!p[3] || p[4]) {
1178 style = PS_DASHDOTDOT; /* -.. */
1180 style = PS_DASHDOT; /* -. */
1183 if (p[0] > (4 * gc->line_width)) {
1184 style = PS_DASH; /* - */
1186 style = PS_DOT; /* . */
1192 if (gc->line_width < 2) {
1193 return CreatePen(style, gc->line_width, gc->foreground);
1197 lb.lbStyle = BS_SOLID;
1198 lb.lbColor = gc->foreground;
1201 style |= PS_GEOMETRIC;
1202 switch (gc->cap_style) {
1205 style |= PS_ENDCAP_FLAT;
1208 style |= PS_ENDCAP_ROUND;
1211 style |= PS_ENDCAP_SQUARE;
1214 switch (gc->join_style) {
1216 style |= PS_JOIN_MITER;
1219 style |= PS_JOIN_ROUND;
1222 style |= PS_JOIN_BEVEL;
1225 return ExtCreatePen(style, gc->line_width, &lb, 0, NULL);
1230 *----------------------------------------------------------------------
1234 * Scroll a rectangle of the specified window and accumulate
1238 * Returns 0 if the scroll genereated no additional damage.
1239 * Otherwise, sets the region that needs to be repainted after
1240 * scrolling and returns 1.
1243 * Scrolls the bits in the window.
1245 *----------------------------------------------------------------------
1249 TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn)
1250 Tk_Window tkwin; /* The window to be scrolled. */
1251 GC gc; /* GC for window to be scrolled. */
1252 int x, y, width, height; /* Position rectangle to be scrolled. */
1253 int dx, dy; /* Distance rectangle should be moved. */
1254 TkRegion damageRgn; /* Region to accumulate damage in. */
1256 HWND hwnd = TkWinGetHWND(Tk_WindowId(tkwin));
1259 scrollRect.left = x;
1261 scrollRect.right = x + width;
1262 scrollRect.bottom = y + height;
1263 return (ScrollWindowEx(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn,
1264 NULL, 0) == NULLREGION) ? 0 : 1;
1268 *----------------------------------------------------------------------
1272 * This routine fills a rectangle with the foreground color
1273 * from the specified GC ignoring all other GC values. This
1274 * is the fastest way to fill a drawable with a solid color.
1280 * Modifies the contents of the DC drawing surface.
1282 *----------------------------------------------------------------------
1286 TkWinFillRect(dc, x, y, width, height, pixel)
1288 int x, y, width, height;
1296 rect.right = x + width;
1297 rect.bottom = y + height;
1298 oldColor = SetBkColor(dc, (COLORREF)pixel);
1299 SetBkMode(dc, OPAQUE);
1300 ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
1301 SetBkColor(dc, oldColor);
1305 *----------------------------------------------------------------------
1307 * TkpDrawHighlightBorder --
1309 * This procedure draws a rectangular ring around the outside of
1310 * a widget to indicate that it has received the input focus.
1312 * On Windows, we just draw the simple inset ring. On other sytems,
1313 * e.g. the Mac, the focus ring is a little more complicated, so we
1314 * need this abstraction.
1320 * A rectangle "width" pixels wide is drawn in "drawable",
1321 * corresponding to the outer area of "tkwin".
1323 *----------------------------------------------------------------------
1327 TkpDrawHighlightBorder(tkwin, fgGC, bgGC, highlightWidth, drawable)
1334 TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0);