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