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