1 | /*
|
---|
2 | * bltTile.c --
|
---|
3 | *
|
---|
4 | * This module manages images for tiled backgrounds for the BLT toolkit.
|
---|
5 | *
|
---|
6 | * Copyright 1995-1998 Lucent Technologies, Inc.
|
---|
7 | *
|
---|
8 | * Permission to use, copy, modify, and distribute this software and
|
---|
9 | * its documentation for any purpose and without fee is hereby
|
---|
10 | * granted, provided that the above copyright notice appear in all
|
---|
11 | * copies and that both that the copyright notice and warranty
|
---|
12 | * disclaimer appear in supporting documentation, and that the names
|
---|
13 | * of Lucent Technologies any of their entities not be used in
|
---|
14 | * advertising or publicity pertaining to distribution of the software
|
---|
15 | * without specific, written prior permission.
|
---|
16 | *
|
---|
17 | * Lucent Technologies disclaims all warranties with regard to this
|
---|
18 | * software, including all implied warranties of merchantability and
|
---|
19 | * fitness. In no event shall Lucent Technologies be liable for any
|
---|
20 | * special, indirect or consequential damages or any damages
|
---|
21 | * whatsoever resulting from loss of use, data or profits, whether in
|
---|
22 | * an action of contract, negligence or other tortuous action, arising
|
---|
23 | * out of or in connection with the use or performance of this
|
---|
24 | * software.
|
---|
25 | */
|
---|
26 |
|
---|
27 | #include "bltInt.h"
|
---|
28 | #include "bltChain.h"
|
---|
29 | #include "bltHash.h"
|
---|
30 | #include "bltImage.h"
|
---|
31 | #include <X11/Xutil.h>
|
---|
32 |
|
---|
33 | #include "bltTile.h"
|
---|
34 |
|
---|
35 | #define TILE_THREAD_KEY "BLT Tile Data"
|
---|
36 | #define TILE_MAGIC ((unsigned int) 0x46170277)
|
---|
37 |
|
---|
38 | typedef struct {
|
---|
39 | Blt_HashTable tileTable; /* Hash table of tile structures keyed by
|
---|
40 | * the name of the image. */
|
---|
41 | Tcl_Interp *interp;
|
---|
42 | } TileInterpData;
|
---|
43 |
|
---|
44 | typedef struct {
|
---|
45 | char *name; /* Name of image used to generate the pixmap.*/
|
---|
46 | Display *display; /* Display where pixmap was created. */
|
---|
47 | int flags; /* See definitions below. */
|
---|
48 | Tcl_Interp *interp;
|
---|
49 | Blt_HashEntry *hashPtr; /* Pointer to hash table location */
|
---|
50 | Blt_HashTable *tablePtr;
|
---|
51 |
|
---|
52 | Pixmap pixmap; /* Pixmap generated from image. */
|
---|
53 | Pixmap mask; /* Monochrome pixmap used as
|
---|
54 | * transparency mask. */
|
---|
55 | GC gc; /* GC */
|
---|
56 | Tk_Image tkImage; /* Tk image token. */
|
---|
57 | Blt_Chain *clients; /* Chain of clients sharing this tile. */
|
---|
58 | int width, height;
|
---|
59 | } Tile;
|
---|
60 |
|
---|
61 | #define NOTIFY_PENDING 1 /* If set, indicates that the image
|
---|
62 | * associated with the tile has been
|
---|
63 | * updated or deleted. The tile pixmap
|
---|
64 | * will be changed and the clients of the
|
---|
65 | * tile will be notified (if they supplied
|
---|
66 | * a TileChangedProc routine. */
|
---|
67 |
|
---|
68 | typedef struct Blt_TileClientStruct {
|
---|
69 | unsigned int magic;
|
---|
70 | Tk_Window tkwin; /* Client window. */
|
---|
71 | int xOrigin, yOrigin; /* Tiling origin in relation to the
|
---|
72 | * client window. */
|
---|
73 | Blt_TileChangedProc *notifyProc; /* If non-NULL, routine to
|
---|
74 | * call to when tile image changes. */
|
---|
75 | ClientData clientData; /* Data to pass to when calling the above
|
---|
76 | * routine. */
|
---|
77 | Tile *tilePtr; /* Pointer to actual tile information */
|
---|
78 | Blt_ChainLink *linkPtr; /* Pointer to client entry in the server's
|
---|
79 | * client list. Used to delete the client */
|
---|
80 | } TileClient;
|
---|
81 |
|
---|
82 | typedef struct {
|
---|
83 | Display *display;
|
---|
84 | Tk_Uid nameId;
|
---|
85 | int depth;
|
---|
86 | } TileKey;
|
---|
87 |
|
---|
88 | static TileInterpData *GetTileInterpData _ANSI_ARGS_((Tcl_Interp *interp));
|
---|
89 |
|
---|
90 | static Tcl_IdleProc UpdateTile;
|
---|
91 | static Tk_ImageChangedProc ImageChangedProc;
|
---|
92 | static Tcl_InterpDeleteProc TileInterpDeleteProc;
|
---|
93 |
|
---|
94 | static void DestroyClient _ANSI_ARGS_((TileClient *clientPtr));
|
---|
95 | static void DestroyTile _ANSI_ARGS_((Tile *tilePtr));
|
---|
96 |
|
---|
97 |
|
---|
98 | /*
|
---|
99 | *----------------------------------------------------------------------
|
---|
100 | *
|
---|
101 | * RedrawTile --
|
---|
102 | *
|
---|
103 | * Generates a pixmap and draws the tile image into it. Also
|
---|
104 | * a tranparency mask is possibly generated from the image.
|
---|
105 | *
|
---|
106 | * Results:
|
---|
107 | * None.
|
---|
108 | *
|
---|
109 | *----------------------------------------------------------------------
|
---|
110 | */
|
---|
111 | static void
|
---|
112 | RedrawTile(tkwin, tilePtr)
|
---|
113 | Tk_Window tkwin;
|
---|
114 | Tile *tilePtr;
|
---|
115 | {
|
---|
116 | GC newGC;
|
---|
117 | Tk_PhotoHandle photo;
|
---|
118 | XGCValues gcValues;
|
---|
119 | int width, height;
|
---|
120 | unsigned int gcMask;
|
---|
121 |
|
---|
122 | Tk_SizeOfImage(tilePtr->tkImage, &width, &height);
|
---|
123 |
|
---|
124 | Tk_MakeWindowExist(tkwin);
|
---|
125 | if ((width != tilePtr->width) || (height != tilePtr->height)) {
|
---|
126 | Pixmap pixmap;
|
---|
127 |
|
---|
128 | /*
|
---|
129 | * Create the new pixmap *before* destroying the old one. I don't
|
---|
130 | * why this happens, but if you delete the old pixmap first, the
|
---|
131 | * old pixmap sometimes gets used in the client's GCs. I suspect
|
---|
132 | * it has something to do with the way Tk reallocates X resource
|
---|
133 | * identifiers.
|
---|
134 | */
|
---|
135 | pixmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), width,
|
---|
136 | height, Tk_Depth(tkwin));
|
---|
137 | if (tilePtr->pixmap != None) {
|
---|
138 | Tk_FreePixmap(Tk_Display(tkwin), tilePtr->pixmap);
|
---|
139 | }
|
---|
140 | tilePtr->pixmap = pixmap;
|
---|
141 | }
|
---|
142 | Tk_RedrawImage(tilePtr->tkImage, 0, 0, width, height, tilePtr->pixmap,
|
---|
143 | 0, 0);
|
---|
144 |
|
---|
145 | gcMask = (GCTile | GCFillStyle);
|
---|
146 | gcValues.fill_style = FillTiled;
|
---|
147 | gcValues.tile = tilePtr->pixmap;
|
---|
148 | newGC = Tk_GetGC(tkwin, gcMask, &gcValues);
|
---|
149 | if (tilePtr->gc != NULL) {
|
---|
150 | Tk_FreeGC(Tk_Display(tkwin), tilePtr->gc);
|
---|
151 | }
|
---|
152 | tilePtr->gc = newGC;
|
---|
153 | tilePtr->width = width;
|
---|
154 | tilePtr->height = height;
|
---|
155 |
|
---|
156 | if (tilePtr->mask != None) {
|
---|
157 | #ifdef WIN32
|
---|
158 | Tk_FreePixmap(Tk_Display(tkwin), tilePtr->mask);
|
---|
159 | #else
|
---|
160 | XFreePixmap(Tk_Display(tkwin), tilePtr->mask);
|
---|
161 | #endif /* WIN32 */
|
---|
162 | tilePtr->mask = None;
|
---|
163 | }
|
---|
164 | photo = Blt_FindPhoto(tilePtr->interp,
|
---|
165 | Blt_NameOfImage(tilePtr->tkImage));
|
---|
166 | if (photo != NULL) {
|
---|
167 | Tk_PhotoImageBlock src;
|
---|
168 |
|
---|
169 | Tk_PhotoGetImage(photo, &src);
|
---|
170 | if ((src.offset[3] < src.pixelSize) && (src.offset[3] >= 0)) {
|
---|
171 | tilePtr->mask = Blt_PhotoImageMask(tkwin, src);
|
---|
172 | }
|
---|
173 | }
|
---|
174 | }
|
---|
175 |
|
---|
176 | /*
|
---|
177 | *----------------------------------------------------------------------
|
---|
178 | *
|
---|
179 | * UpdateTile --
|
---|
180 | *
|
---|
181 | * It would be better if Tk checked for NULL proc pointers.
|
---|
182 | *
|
---|
183 | * Results:
|
---|
184 | * None.
|
---|
185 | *
|
---|
186 | *----------------------------------------------------------------------
|
---|
187 | */
|
---|
188 | static void
|
---|
189 | UpdateTile(clientData)
|
---|
190 | ClientData clientData;
|
---|
191 | {
|
---|
192 | Tile *tilePtr = (Tile *)clientData;
|
---|
193 | TileClient *clientPtr;
|
---|
194 | Blt_ChainLink *linkPtr;
|
---|
195 |
|
---|
196 | tilePtr->flags &= ~NOTIFY_PENDING;
|
---|
197 | if (Tk_ImageIsDeleted(tilePtr->tkImage)) {
|
---|
198 | if (tilePtr->pixmap != None) {
|
---|
199 | Tk_FreePixmap(tilePtr->display, tilePtr->pixmap);
|
---|
200 | }
|
---|
201 | tilePtr->pixmap = None;
|
---|
202 | } else {
|
---|
203 | /* Pick any client window to generate the new pixmap. */
|
---|
204 | linkPtr = Blt_ChainFirstLink(tilePtr->clients);
|
---|
205 | clientPtr = Blt_ChainGetValue(linkPtr);
|
---|
206 | RedrawTile(clientPtr->tkwin, tilePtr);
|
---|
207 | }
|
---|
208 |
|
---|
209 | /* Notify each of the tile's clients that the pixmap has changed. */
|
---|
210 |
|
---|
211 | for (linkPtr = Blt_ChainFirstLink(tilePtr->clients); linkPtr != NULL;
|
---|
212 | linkPtr = Blt_ChainNextLink(linkPtr)) {
|
---|
213 | clientPtr = Blt_ChainGetValue(linkPtr);
|
---|
214 | if (clientPtr->notifyProc != NULL) {
|
---|
215 | (*clientPtr->notifyProc) (clientPtr->clientData, clientPtr);
|
---|
216 | }
|
---|
217 | }
|
---|
218 | }
|
---|
219 |
|
---|
220 | /*
|
---|
221 | *----------------------------------------------------------------------
|
---|
222 | *
|
---|
223 | * ImageChangedProc
|
---|
224 | *
|
---|
225 | * The Tk image has changed or been deleted, redraw the pixmap
|
---|
226 | * tile.
|
---|
227 | *
|
---|
228 | * Note: As of Tk 4.2 (rechecked in 8.3), if you redraw Tk
|
---|
229 | * images from a Tk_ImageChangedProc you'll get a
|
---|
230 | * coredump. As a workaround, we have to simulate
|
---|
231 | * how the Tk widgets use images and redraw within
|
---|
232 | * an idle event.
|
---|
233 | *
|
---|
234 | * Results:
|
---|
235 | * None.
|
---|
236 | *
|
---|
237 | *----------------------------------------------------------------------
|
---|
238 | */
|
---|
239 | /* ARGSUSED */
|
---|
240 | static void
|
---|
241 | ImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight)
|
---|
242 | ClientData clientData;
|
---|
243 | int x, y, width, height; /* Not used. */
|
---|
244 | int imageWidth, imageHeight; /* Not used. */
|
---|
245 | {
|
---|
246 | Tile *tilePtr = (Tile *) clientData;
|
---|
247 |
|
---|
248 | if (!(tilePtr->flags & NOTIFY_PENDING)) {
|
---|
249 | Tcl_DoWhenIdle(UpdateTile, tilePtr);
|
---|
250 | tilePtr->flags |= NOTIFY_PENDING;
|
---|
251 | }
|
---|
252 | }
|
---|
253 |
|
---|
254 | /*
|
---|
255 | *----------------------------------------------------------------------
|
---|
256 | *
|
---|
257 | * DestroyTile --
|
---|
258 | *
|
---|
259 | * Deletes the core tile structure, including the pixmap
|
---|
260 | * representing the tile.
|
---|
261 | *
|
---|
262 | * Results:
|
---|
263 | * None.
|
---|
264 | *
|
---|
265 | *----------------------------------------------------------------------
|
---|
266 | */
|
---|
267 | static void
|
---|
268 | DestroyTile(Tile *tilePtr)
|
---|
269 | {
|
---|
270 | Blt_ChainLink *linkPtr;
|
---|
271 | TileClient *clientPtr;
|
---|
272 |
|
---|
273 | if (tilePtr->flags & NOTIFY_PENDING) {
|
---|
274 | Tcl_CancelIdleCall(UpdateTile, tilePtr);
|
---|
275 | }
|
---|
276 | for (linkPtr = Blt_ChainFirstLink(tilePtr->clients); linkPtr != NULL;
|
---|
277 | linkPtr = Blt_ChainNextLink(linkPtr)) {
|
---|
278 | clientPtr = Blt_ChainGetValue(linkPtr);
|
---|
279 | Blt_Free(clientPtr);
|
---|
280 | }
|
---|
281 | Blt_ChainDestroy(tilePtr->clients);
|
---|
282 |
|
---|
283 | if (tilePtr->hashPtr != NULL) {
|
---|
284 | Blt_DeleteHashEntry(tilePtr->tablePtr, tilePtr->hashPtr);
|
---|
285 | }
|
---|
286 | if (tilePtr->pixmap != None) {
|
---|
287 | Tk_FreePixmap(tilePtr->display, tilePtr->pixmap);
|
---|
288 | }
|
---|
289 | Tk_FreeImage(tilePtr->tkImage);
|
---|
290 |
|
---|
291 | if (tilePtr->gc != NULL) {
|
---|
292 | Tk_FreeGC(tilePtr->display, tilePtr->gc);
|
---|
293 | }
|
---|
294 | if (tilePtr->name != NULL) {
|
---|
295 | Blt_Free(tilePtr->name);
|
---|
296 | }
|
---|
297 | Blt_Free(tilePtr);
|
---|
298 | }
|
---|
299 |
|
---|
300 | /*
|
---|
301 | *----------------------------------------------------------------------
|
---|
302 | *
|
---|
303 | * CreateTile --
|
---|
304 | *
|
---|
305 | * Creates a tile server. A tile server manages a single image,
|
---|
306 | * possibly shared by several clients. Clients will be updated
|
---|
307 | * (if requested) by the server if the image changes, so they
|
---|
308 | * know to redraw themselves. For X11 the image is drawn into a
|
---|
309 | * pixmap that is used in a new GC as its tile. For Windows we
|
---|
310 | * have to do the tiling ourselves by redrawing the image across
|
---|
311 | * the drawing area (see Blt_TileRectangle and Blt_TilePolygon).
|
---|
312 | *
|
---|
313 | * Results:
|
---|
314 | * Returns a pointer to the new tile server. If the image name
|
---|
315 | * does not represent a Tk image, NULL is returned.
|
---|
316 | *
|
---|
317 | *----------------------------------------------------------------------
|
---|
318 | */
|
---|
319 | static Tile *
|
---|
320 | CreateTile(
|
---|
321 | Tcl_Interp *interp,
|
---|
322 | Tk_Window tkwin,
|
---|
323 | char *imageName)
|
---|
324 | {
|
---|
325 | Tile *tilePtr;
|
---|
326 | Tk_Image tkImage;
|
---|
327 |
|
---|
328 | tilePtr = Blt_Calloc(1, sizeof(Tile));
|
---|
329 | assert(tilePtr);
|
---|
330 | /*
|
---|
331 | * Get the image. Funnel all change notifications to a single routine.
|
---|
332 | */
|
---|
333 | tkImage = Tk_GetImage(interp, tkwin, imageName, ImageChangedProc,
|
---|
334 | tilePtr);
|
---|
335 | if (tkImage == NULL) {
|
---|
336 | Blt_Free(tilePtr);
|
---|
337 | return NULL;
|
---|
338 | }
|
---|
339 |
|
---|
340 | /*
|
---|
341 | * Initialize the tile server.
|
---|
342 | */
|
---|
343 | tilePtr->display = Tk_Display(tkwin);
|
---|
344 | tilePtr->interp = interp;
|
---|
345 | tilePtr->name = Blt_Strdup(imageName);
|
---|
346 | tilePtr->clients = Blt_ChainCreate();
|
---|
347 | tilePtr->tkImage = tkImage;
|
---|
348 | RedrawTile(tkwin, tilePtr);
|
---|
349 | return tilePtr;
|
---|
350 | }
|
---|
351 |
|
---|
352 | /*
|
---|
353 | *----------------------------------------------------------------------
|
---|
354 | *
|
---|
355 | * DestroyClient --
|
---|
356 | *
|
---|
357 | * Removes the client from the servers's list of clients and
|
---|
358 | * memory used by the client token is released. When the last
|
---|
359 | * client is deleted, the server is also removed.
|
---|
360 | *
|
---|
361 | * Results:
|
---|
362 | * None.
|
---|
363 | *
|
---|
364 | *----------------------------------------------------------------------
|
---|
365 | */
|
---|
366 | static void
|
---|
367 | DestroyClient(TileClient *clientPtr)
|
---|
368 | {
|
---|
369 | Tile *tilePtr;
|
---|
370 | tilePtr = clientPtr->tilePtr;
|
---|
371 |
|
---|
372 | /* Remove the client from the server's list */
|
---|
373 | if (clientPtr->linkPtr != NULL) {
|
---|
374 | Blt_ChainDeleteLink(tilePtr->clients, clientPtr->linkPtr);
|
---|
375 | }
|
---|
376 | if (Blt_ChainGetLength(tilePtr->clients) == 0) {
|
---|
377 | /*
|
---|
378 | * If there are no more clients of the tile, then remove the
|
---|
379 | * pixmap, image, and the server record.
|
---|
380 | */
|
---|
381 | DestroyTile(tilePtr);
|
---|
382 | }
|
---|
383 | Blt_Free(clientPtr);
|
---|
384 | }
|
---|
385 |
|
---|
386 | /*
|
---|
387 | *----------------------------------------------------------------------
|
---|
388 | *
|
---|
389 | * CreateClient --
|
---|
390 | *
|
---|
391 | * Returns a token to a tile (possibly shared by many clients).
|
---|
392 | * A client uses the token to query or display the tile. Clients
|
---|
393 | * request tiles by their image names. Each tile is known by its
|
---|
394 | * display, screen depth, and image name. The tile server tracks
|
---|
395 | * what clients are using the tile and notifies them (via a
|
---|
396 | * callback) whenever the tile changes. If no server exists
|
---|
397 | * already, one is created on-the-fly.
|
---|
398 | *
|
---|
399 | * Results:
|
---|
400 | * A pointer to the newly created client (i.e. tile).
|
---|
401 | *
|
---|
402 | *----------------------------------------------------------------------
|
---|
403 | */
|
---|
404 | static TileClient *
|
---|
405 | CreateClient(
|
---|
406 | Tcl_Interp *interp,
|
---|
407 | Tk_Window tkwin,
|
---|
408 | char *name)
|
---|
409 | {
|
---|
410 | TileClient *clientPtr;
|
---|
411 | Tile *tilePtr;
|
---|
412 | TileInterpData *dataPtr;
|
---|
413 | Blt_HashEntry *hPtr;
|
---|
414 | int isNew;
|
---|
415 | TileKey key;
|
---|
416 |
|
---|
417 | dataPtr = GetTileInterpData(interp);
|
---|
418 |
|
---|
419 | key.nameId = Tk_GetUid(name);
|
---|
420 | key.display = Tk_Display(tkwin);
|
---|
421 | key.depth = Tk_Depth(tkwin);
|
---|
422 | hPtr = Blt_CreateHashEntry(&dataPtr->tileTable, (char *)&key, &isNew);
|
---|
423 | if (isNew) {
|
---|
424 | tilePtr = CreateTile(interp, tkwin, name);
|
---|
425 | if (tilePtr == NULL) {
|
---|
426 | Blt_DeleteHashEntry(&(dataPtr->tileTable), hPtr);
|
---|
427 | return NULL;
|
---|
428 | }
|
---|
429 | tilePtr->hashPtr = hPtr;
|
---|
430 | tilePtr->tablePtr = &(dataPtr->tileTable);
|
---|
431 | Blt_SetHashValue(hPtr, tilePtr);
|
---|
432 | } else {
|
---|
433 | tilePtr = Blt_GetHashValue(hPtr);
|
---|
434 | }
|
---|
435 | clientPtr = Blt_Calloc(1, sizeof(TileClient));
|
---|
436 | assert(clientPtr);
|
---|
437 |
|
---|
438 | /* Initialize client information. */
|
---|
439 | clientPtr->magic = TILE_MAGIC;
|
---|
440 | clientPtr->tkwin = tkwin;
|
---|
441 | clientPtr->linkPtr = Blt_ChainAppend(tilePtr->clients, clientPtr);
|
---|
442 | clientPtr->tilePtr = tilePtr;
|
---|
443 | return clientPtr;
|
---|
444 | }
|
---|
445 |
|
---|
446 | /*
|
---|
447 | * -----------------------------------------------------------------------
|
---|
448 | *
|
---|
449 | * TileInterpDeleteProc --
|
---|
450 | *
|
---|
451 | * This is called when the interpreter is deleted. All the tiles
|
---|
452 | * are specific to that interpreter are destroyed.
|
---|
453 | *
|
---|
454 | * Results:
|
---|
455 | * None.
|
---|
456 | *
|
---|
457 | * Side effects:
|
---|
458 | * Destroys the tile table.
|
---|
459 | *
|
---|
460 | * ------------------------------------------------------------------------
|
---|
461 | */
|
---|
462 | /* ARGSUSED */
|
---|
463 | static void
|
---|
464 | TileInterpDeleteProc(
|
---|
465 | ClientData clientData, /* Thread-specific data. */
|
---|
466 | Tcl_Interp *interp)
|
---|
467 | {
|
---|
468 | TileInterpData *dataPtr = clientData;
|
---|
469 | Blt_HashEntry *hPtr;
|
---|
470 | Blt_HashSearch cursor;
|
---|
471 | Tile *tilePtr;
|
---|
472 |
|
---|
473 | for (hPtr = Blt_FirstHashEntry(&(dataPtr->tileTable), &cursor);
|
---|
474 | hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
|
---|
475 | tilePtr = Blt_GetHashValue(hPtr);
|
---|
476 | tilePtr->hashPtr = NULL;
|
---|
477 | DestroyTile(tilePtr);
|
---|
478 | }
|
---|
479 | Blt_DeleteHashTable(&(dataPtr->tileTable));
|
---|
480 | Tcl_DeleteAssocData(interp, TILE_THREAD_KEY);
|
---|
481 | Blt_Free(dataPtr);
|
---|
482 | }
|
---|
483 |
|
---|
484 | static TileInterpData *
|
---|
485 | GetTileInterpData(interp)
|
---|
486 | Tcl_Interp *interp;
|
---|
487 | {
|
---|
488 | TileInterpData *dataPtr;
|
---|
489 | Tcl_InterpDeleteProc *proc;
|
---|
490 |
|
---|
491 | dataPtr = (TileInterpData *)
|
---|
492 | Tcl_GetAssocData(interp, TILE_THREAD_KEY, &proc);
|
---|
493 | if (dataPtr == NULL) {
|
---|
494 | dataPtr = Blt_Malloc(sizeof(TileInterpData));
|
---|
495 | assert(dataPtr);
|
---|
496 | dataPtr->interp = interp;
|
---|
497 | Tcl_SetAssocData(interp, TILE_THREAD_KEY, TileInterpDeleteProc,
|
---|
498 | dataPtr);
|
---|
499 | Blt_InitHashTable(&(dataPtr->tileTable), sizeof(TileKey)/sizeof(int));
|
---|
500 | }
|
---|
501 | return dataPtr;
|
---|
502 | }
|
---|
503 |
|
---|
504 | |
---|
505 |
|
---|
506 | /* Public API for tiles. */
|
---|
507 |
|
---|
508 | /*
|
---|
509 | *----------------------------------------------------------------------
|
---|
510 | *
|
---|
511 | * Blt_GetTile
|
---|
512 | *
|
---|
513 | * Convert the named image into a tile.
|
---|
514 | *
|
---|
515 | * Results:
|
---|
516 | * If the image is valid, a new tile is returned. If the name
|
---|
517 | * does not represent a proper image, an error message is left in
|
---|
518 | * interp->result.
|
---|
519 | *
|
---|
520 | *----------------------------------------------------------------------
|
---|
521 | */
|
---|
522 | /*LINTLIBRARY*/
|
---|
523 | int
|
---|
524 | Blt_GetTile(
|
---|
525 | Tcl_Interp *interp, /* Interpreter to report results back to */
|
---|
526 | Tk_Window tkwin, /* Window on the same display as tile */
|
---|
527 | char *imageName, /* Name of image */
|
---|
528 | Blt_Tile *tokenPtr) /* (out) Returns the allocated tile token. */
|
---|
529 | {
|
---|
530 | TileClient *clientPtr;
|
---|
531 |
|
---|
532 | clientPtr = CreateClient(interp, tkwin, imageName);
|
---|
533 | if (clientPtr == NULL) {
|
---|
534 | return TCL_ERROR;
|
---|
535 | }
|
---|
536 | *tokenPtr = clientPtr;
|
---|
537 | return TCL_OK;
|
---|
538 | }
|
---|
539 |
|
---|
540 | /*
|
---|
541 | *----------------------------------------------------------------------
|
---|
542 | *
|
---|
543 | * Blt_FreeTile
|
---|
544 | *
|
---|
545 | * Release the resources associated with the tile.
|
---|
546 | *
|
---|
547 | * Results:
|
---|
548 | * None.
|
---|
549 | *
|
---|
550 | * Side Effects:
|
---|
551 | * Memory and X resources are freed. Bookkeeping information
|
---|
552 | * about the tile (i.e. width, height, and name) is discarded.
|
---|
553 | *
|
---|
554 | *----------------------------------------------------------------------
|
---|
555 | */
|
---|
556 | /*LINTLIBRARY*/
|
---|
557 | void
|
---|
558 | Blt_FreeTile(TileClient *clientPtr) /* Tile to be deleted */
|
---|
559 | {
|
---|
560 | if ((clientPtr == NULL) || (clientPtr->magic != TILE_MAGIC)) {
|
---|
561 | return; /* No tile */
|
---|
562 | }
|
---|
563 | DestroyClient(clientPtr);
|
---|
564 | }
|
---|
565 |
|
---|
566 | /*
|
---|
567 | *----------------------------------------------------------------------
|
---|
568 | *
|
---|
569 | * Blt_NameOfTile
|
---|
570 | *
|
---|
571 | * Returns the name of the image from which the tile was
|
---|
572 | * generated.
|
---|
573 | *
|
---|
574 | * Results:
|
---|
575 | * The name of the image is returned. The name is not unique.
|
---|
576 | * Many tiles may use the same image.
|
---|
577 | *
|
---|
578 | *----------------------------------------------------------------------
|
---|
579 | */
|
---|
580 | /*LINTLIBRARY*/
|
---|
581 | char *
|
---|
582 | Blt_NameOfTile(TileClient *clientPtr) /* Tile to query */
|
---|
583 | {
|
---|
584 | if (clientPtr == NULL) {
|
---|
585 | return "";
|
---|
586 | }
|
---|
587 | if (clientPtr->magic != TILE_MAGIC) {
|
---|
588 | return "not a tile";
|
---|
589 | }
|
---|
590 | return clientPtr->tilePtr->name;
|
---|
591 | }
|
---|
592 |
|
---|
593 | /*
|
---|
594 | *----------------------------------------------------------------------
|
---|
595 | *
|
---|
596 | * Blt_PixmapOfTile
|
---|
597 | *
|
---|
598 | * Returns the pixmap of the tile.
|
---|
599 | *
|
---|
600 | * Results:
|
---|
601 | * The X pixmap used as the tile is returned.
|
---|
602 | *
|
---|
603 | *----------------------------------------------------------------------
|
---|
604 | */
|
---|
605 | /*LINTLIBRARY*/
|
---|
606 | Pixmap
|
---|
607 | Blt_PixmapOfTile(TileClient *clientPtr) /* Tile to query */
|
---|
608 | {
|
---|
609 | if ((clientPtr == NULL) || (clientPtr->magic != TILE_MAGIC)) {
|
---|
610 | return None;
|
---|
611 | }
|
---|
612 | return clientPtr->tilePtr->pixmap;
|
---|
613 | }
|
---|
614 |
|
---|
615 | /*
|
---|
616 | *----------------------------------------------------------------------
|
---|
617 | *
|
---|
618 | * Blt_SizeOfTile
|
---|
619 | *
|
---|
620 | * Returns the width and height of the tile.
|
---|
621 | *
|
---|
622 | * Results:
|
---|
623 | * The width and height of the tile are returned.
|
---|
624 | *
|
---|
625 | *----------------------------------------------------------------------
|
---|
626 | */
|
---|
627 | /*LINTLIBRARY*/
|
---|
628 | void
|
---|
629 | Blt_SizeOfTile(
|
---|
630 | TileClient *clientPtr, /* Tile to query */
|
---|
631 | int *widthPtr,
|
---|
632 | int *heightPtr) /* Returned dimensions of the tile (out) */
|
---|
633 | {
|
---|
634 | if ((clientPtr == NULL) || (clientPtr->magic != TILE_MAGIC)) {
|
---|
635 | *widthPtr = *heightPtr = 0;
|
---|
636 | return; /* No tile given. */
|
---|
637 | }
|
---|
638 | *widthPtr = clientPtr->tilePtr->width;
|
---|
639 | *heightPtr = clientPtr->tilePtr->height;
|
---|
640 | }
|
---|
641 |
|
---|
642 | /*
|
---|
643 | *----------------------------------------------------------------------
|
---|
644 | *
|
---|
645 | * Blt_SetTileChangedProc
|
---|
646 | *
|
---|
647 | * Sets the routine to called when an image changes.
|
---|
648 | *
|
---|
649 | * Results:
|
---|
650 | * None.
|
---|
651 | *
|
---|
652 | * Side Effects:
|
---|
653 | * The designated routine will be called the next time the
|
---|
654 | * image associated with the tile changes.
|
---|
655 | *
|
---|
656 | *----------------------------------------------------------------------
|
---|
657 | */
|
---|
658 | /*LINTLIBRARY*/
|
---|
659 | void
|
---|
660 | Blt_SetTileChangedProc(
|
---|
661 | TileClient *clientPtr, /* Tile to query */
|
---|
662 | Blt_TileChangedProc *notifyProc,
|
---|
663 | ClientData clientData)
|
---|
664 | {
|
---|
665 | if ((clientPtr != NULL) && (clientPtr->magic == TILE_MAGIC)) {
|
---|
666 | clientPtr->notifyProc = notifyProc;
|
---|
667 | clientPtr->clientData = clientData;
|
---|
668 | }
|
---|
669 | }
|
---|
670 |
|
---|
671 | /*
|
---|
672 | *----------------------------------------------------------------------
|
---|
673 | *
|
---|
674 | * Blt_SetTileOrigin --
|
---|
675 | *
|
---|
676 | * Set the pattern origin of the tile to a common point (i.e. the
|
---|
677 | * origin (0,0) of the top level window) so that tiles from two
|
---|
678 | * different widgets will match up. This done by setting the
|
---|
679 | * GCTileStipOrigin field is set to the translated origin of the
|
---|
680 | * toplevel window in the hierarchy.
|
---|
681 | *
|
---|
682 | * Results:
|
---|
683 | * None.
|
---|
684 | *
|
---|
685 | * Side Effects:
|
---|
686 | * The GCTileStipOrigin is reset in the GC. This will cause the
|
---|
687 | * tile origin to change when the GC is used for drawing.
|
---|
688 | *
|
---|
689 | *----------------------------------------------------------------------
|
---|
690 | */
|
---|
691 | /*ARGSUSED*/
|
---|
692 | void
|
---|
693 | Blt_SetTileOrigin(
|
---|
694 | Tk_Window tkwin,
|
---|
695 | TileClient *clientPtr,
|
---|
696 | int x, int y)
|
---|
697 | {
|
---|
698 | while (!Tk_IsTopLevel(tkwin)) {
|
---|
699 | x += Tk_X(tkwin) + Tk_Changes(tkwin)->border_width;
|
---|
700 | y += Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width;
|
---|
701 | tkwin = Tk_Parent(tkwin);
|
---|
702 | }
|
---|
703 | XSetTSOrigin(Tk_Display(tkwin), clientPtr->tilePtr->gc, -x, -y);
|
---|
704 | clientPtr->xOrigin = -x;
|
---|
705 | clientPtr->yOrigin = -y;
|
---|
706 | }
|
---|
707 |
|
---|
708 | void
|
---|
709 | Blt_SetTSOrigin(
|
---|
710 | Tk_Window tkwin,
|
---|
711 | TileClient *clientPtr,
|
---|
712 | int x, int y)
|
---|
713 | {
|
---|
714 | XSetTSOrigin(Tk_Display(tkwin), clientPtr->tilePtr->gc, x, y);
|
---|
715 | clientPtr->xOrigin = x;
|
---|
716 | clientPtr->yOrigin = y;
|
---|
717 | }
|
---|
718 |
|
---|
719 | #ifdef WIN32
|
---|
720 | static int tkpWinRopModes[] =
|
---|
721 | {
|
---|
722 | R2_BLACK, /* GXclear */
|
---|
723 | R2_MASKPEN, /* GXand */
|
---|
724 | R2_MASKPENNOT, /* GXandReverse */
|
---|
725 | R2_COPYPEN, /* GXcopy */
|
---|
726 | R2_MASKNOTPEN, /* GXandInverted */
|
---|
727 | R2_NOT, /* GXnoop */
|
---|
728 | R2_XORPEN, /* GXxor */
|
---|
729 | R2_MERGEPEN, /* GXor */
|
---|
730 | R2_NOTMERGEPEN, /* GXnor */
|
---|
731 | R2_NOTXORPEN, /* GXequiv */
|
---|
732 | R2_NOT, /* GXinvert */
|
---|
733 | R2_MERGEPENNOT, /* GXorReverse */
|
---|
734 | R2_NOTCOPYPEN, /* GXcopyInverted */
|
---|
735 | R2_MERGENOTPEN, /* GXorInverted */
|
---|
736 | R2_NOTMASKPEN, /* GXnand */
|
---|
737 | R2_WHITE /* GXset */
|
---|
738 | };
|
---|
739 | #define MASKPAT 0x00E20746 /* dest = (src & pat) | (!src & dst) */
|
---|
740 | #define COPYFG 0x00CA0749 /* dest = (pat & src) | (!pat & dst) */
|
---|
741 | #define COPYBG 0x00AC0744 /* dest = (!pat & src) | (pat & dst) */
|
---|
742 |
|
---|
743 | static void
|
---|
744 | TileRegion(
|
---|
745 | HDC srcDC, /* Source device context. */
|
---|
746 | HDC destDC, /* Destination device context. */
|
---|
747 | HDC maskDC, /* If non-NULL, device context of the
|
---|
748 | * mask tile mask. */
|
---|
749 | TileClient *clientPtr,
|
---|
750 | int x, int y,
|
---|
751 | int width, int height)
|
---|
752 | {
|
---|
753 | Tile *tilePtr = clientPtr->tilePtr;
|
---|
754 | int destX, destY;
|
---|
755 | int destWidth, destHeight;
|
---|
756 | int srcX, srcY;
|
---|
757 | int startX, startY; /* Starting upper left corner of region. */
|
---|
758 | int delta;
|
---|
759 | int left, top, right, bottom;
|
---|
760 |
|
---|
761 | startX = x;
|
---|
762 | if (x < clientPtr->xOrigin) {
|
---|
763 | delta = (clientPtr->xOrigin - x) % tilePtr->width;
|
---|
764 | if (delta > 0) {
|
---|
765 | startX -= (tilePtr->width - delta);
|
---|
766 | }
|
---|
767 | } else if (x > clientPtr->xOrigin) {
|
---|
768 | delta = (x - clientPtr->xOrigin) % tilePtr->width;
|
---|
769 | if (delta > 0) {
|
---|
770 | startX -= delta;
|
---|
771 | }
|
---|
772 | }
|
---|
773 | startY = y;
|
---|
774 | if (y < clientPtr->yOrigin) {
|
---|
775 | delta = (clientPtr->yOrigin - y) % tilePtr->height;
|
---|
776 | if (delta > 0) {
|
---|
777 | startY -= (tilePtr->height - delta);
|
---|
778 | }
|
---|
779 | } else if (y >= clientPtr->yOrigin) {
|
---|
780 | delta = (y - clientPtr->yOrigin) % tilePtr->height;
|
---|
781 | if (delta > 0) {
|
---|
782 | startY -= delta;
|
---|
783 | }
|
---|
784 | }
|
---|
785 | #ifdef notdef
|
---|
786 | PurifyPrintf("tile is (%d,%d,%d,%d)\n",
|
---|
787 | clientPtr->xOrigin, clientPtr->yOrigin,
|
---|
788 | tilePtr->width, tilePtr->height);
|
---|
789 | PurifyPrintf("region is (%d,%d,%d,%d)\n", x, y, width, height);
|
---|
790 | PurifyPrintf("starting at %d,%d\n", startX, startY);
|
---|
791 | #endif
|
---|
792 | left = x;
|
---|
793 | right = x + width;
|
---|
794 | top = y;
|
---|
795 | bottom = y + height;
|
---|
796 | for (y = startY; y < bottom; y += tilePtr->height) {
|
---|
797 | srcY = 0;
|
---|
798 | destY = y;
|
---|
799 | destHeight = tilePtr->height;
|
---|
800 | if (y < top) {
|
---|
801 | srcY = (top - y);
|
---|
802 | destHeight = tilePtr->height - srcY;
|
---|
803 | destY = top;
|
---|
804 | }
|
---|
805 | if ((destY + destHeight) > bottom) {
|
---|
806 | destHeight = (bottom - destY);
|
---|
807 | }
|
---|
808 | for (x = startX; x < right; x += tilePtr->width) {
|
---|
809 | srcX = 0;
|
---|
810 | destX = x;
|
---|
811 | destWidth = tilePtr->width;
|
---|
812 | if (x < left) {
|
---|
813 | srcX = (left - x);
|
---|
814 | destWidth = tilePtr->width - srcX;
|
---|
815 | destX = left;
|
---|
816 | }
|
---|
817 | if ((destX + destWidth) > right) {
|
---|
818 | destWidth = (right - destX);
|
---|
819 | }
|
---|
820 | #ifdef notdef
|
---|
821 | PurifyPrintf("drawing pattern (%d,%d,%d,%d) at %d,%d\n",
|
---|
822 | srcX , srcY, destWidth, destHeight, destX, destY);
|
---|
823 | #endif
|
---|
824 | if (tilePtr->mask != None) { /* With transparency. */
|
---|
825 | #ifdef notdef
|
---|
826 | HDC maskDC;
|
---|
827 | TkWinDCState maskState;
|
---|
828 |
|
---|
829 | maskDC = TkWinGetDrawableDC(tilePtr->display,
|
---|
830 | tilePtr->mask, &maskState);
|
---|
831 | SetBkColor(destDC, RGB(255, 255, 255));
|
---|
832 | SetTextColor(destDC, RGB(0, 0, 0));
|
---|
833 | #endif
|
---|
834 | BitBlt(destDC, destX, destY, destWidth, destHeight, maskDC,
|
---|
835 | 0, 0, SRCAND);
|
---|
836 | BitBlt(destDC, destX, destY, destWidth, destHeight, srcDC,
|
---|
837 | srcX, srcY, SRCPAINT);
|
---|
838 | #ifdef notdef
|
---|
839 | TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState);
|
---|
840 | #endif
|
---|
841 | } else { /* Opaque tile. */
|
---|
842 | BitBlt(destDC, destX, destY, destWidth, destHeight,
|
---|
843 | srcDC, srcX, srcY, SRCCOPY);
|
---|
844 | }
|
---|
845 | }
|
---|
846 | }
|
---|
847 | }
|
---|
848 |
|
---|
849 | void
|
---|
850 | Blt_TilePolygon(
|
---|
851 | Tk_Window tkwin,
|
---|
852 | Drawable drawable,
|
---|
853 | TileClient *clientPtr,
|
---|
854 | XPoint pointArr[],
|
---|
855 | int nPoints)
|
---|
856 | {
|
---|
857 | HBITMAP oldBitmap;
|
---|
858 | HDC hDC, memDC;
|
---|
859 | HRGN hRgn;
|
---|
860 | POINT *p, *winPts;
|
---|
861 | Region2D bbox;
|
---|
862 | Tile *tilePtr;
|
---|
863 | TkWinDCState state;
|
---|
864 | TkWinDrawable *twdPtr;
|
---|
865 | XPoint *endPtr, *pointPtr;
|
---|
866 | int fillMode;
|
---|
867 | int width, height;
|
---|
868 |
|
---|
869 | if (drawable == None) {
|
---|
870 | return;
|
---|
871 | }
|
---|
872 | tilePtr = clientPtr->tilePtr;
|
---|
873 |
|
---|
874 | /* Determine the bounding box of the polygon. */
|
---|
875 | bbox.left = bbox.right = pointArr[0].x;
|
---|
876 | bbox.top = bbox.bottom = pointArr[0].y;
|
---|
877 |
|
---|
878 | endPtr = pointArr + nPoints;
|
---|
879 | for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) {
|
---|
880 | if (pointPtr->x < bbox.left) {
|
---|
881 | bbox.left = pointPtr->x;
|
---|
882 | }
|
---|
883 | if (pointPtr->x > bbox.right) {
|
---|
884 | bbox.right = pointPtr->x;
|
---|
885 | }
|
---|
886 | if (pointPtr->y < bbox.top) {
|
---|
887 | bbox.top = pointPtr->y;
|
---|
888 | }
|
---|
889 | if (pointPtr->y > bbox.bottom) {
|
---|
890 | bbox.bottom = pointPtr->y;
|
---|
891 | }
|
---|
892 | }
|
---|
893 | width = bbox.right - bbox.left + 1;
|
---|
894 | height = bbox.bottom - bbox.top + 1;
|
---|
895 |
|
---|
896 |
|
---|
897 | /* Allocate and fill an array of POINTS to create the polygon path. */
|
---|
898 | p = winPts = Blt_Malloc(sizeof(POINT) * nPoints);
|
---|
899 | for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) {
|
---|
900 | p->x = pointPtr->x - bbox.left;
|
---|
901 | p->y = pointPtr->y - bbox.top;
|
---|
902 | p++;
|
---|
903 | }
|
---|
904 |
|
---|
905 | hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state);
|
---|
906 | SetROP2(hDC, tkpWinRopModes[tilePtr->gc->function]);
|
---|
907 | fillMode = (tilePtr->gc->fill_rule == EvenOddRule) ? ALTERNATE : WINDING;
|
---|
908 | /* Use the polygon as a clip path. */
|
---|
909 | LPtoDP(hDC, winPts, nPoints);
|
---|
910 | hRgn = CreatePolygonRgn(winPts, nPoints, fillMode);
|
---|
911 | SelectClipRgn(hDC, hRgn);
|
---|
912 | OffsetClipRgn(hDC, bbox.left, bbox.top);
|
---|
913 | Blt_Free(winPts);
|
---|
914 |
|
---|
915 | twdPtr = (TkWinDrawable *)tilePtr->pixmap;
|
---|
916 | memDC = CreateCompatibleDC(hDC);
|
---|
917 | oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
|
---|
918 |
|
---|
919 | /* Tile the bounding box. */
|
---|
920 | if (tilePtr->mask != None) {
|
---|
921 | TkWinDCState maskState;
|
---|
922 | HDC maskDC;
|
---|
923 |
|
---|
924 | maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask,
|
---|
925 | &maskState);
|
---|
926 | SetBkColor(hDC, RGB(255, 255, 255));
|
---|
927 | SetTextColor(hDC, RGB(0, 0, 0));
|
---|
928 | TileRegion(memDC, hDC, maskDC, clientPtr, bbox.left, bbox.top, width,
|
---|
929 | height);
|
---|
930 | TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState);
|
---|
931 | } else {
|
---|
932 | TileRegion(memDC, hDC, NULL, clientPtr, bbox.left, bbox.top, width,
|
---|
933 | height);
|
---|
934 | }
|
---|
935 | SelectBitmap(memDC, oldBitmap);
|
---|
936 | DeleteDC(memDC);
|
---|
937 | SelectClipRgn(hDC, NULL);
|
---|
938 | DeleteRgn(hRgn);
|
---|
939 | TkWinReleaseDrawableDC(drawable, hDC, &state);
|
---|
940 | }
|
---|
941 |
|
---|
942 | void
|
---|
943 | Blt_TileRectangle(
|
---|
944 | Tk_Window tkwin,
|
---|
945 | Drawable drawable,
|
---|
946 | TileClient *clientPtr,
|
---|
947 | int x, int y,
|
---|
948 | unsigned int width,
|
---|
949 | unsigned int height)
|
---|
950 | {
|
---|
951 | HBITMAP oldBitmap;
|
---|
952 | HDC hDC, memDC;
|
---|
953 | Tile *tilePtr;
|
---|
954 | TkWinDCState state;
|
---|
955 | TkWinDrawable *twdPtr;
|
---|
956 |
|
---|
957 | if (drawable == None) {
|
---|
958 | return;
|
---|
959 | }
|
---|
960 | tilePtr = clientPtr->tilePtr;
|
---|
961 | hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state);
|
---|
962 | SetROP2(hDC, tkpWinRopModes[tilePtr->gc->function]);
|
---|
963 |
|
---|
964 | twdPtr = (TkWinDrawable *)tilePtr->pixmap;
|
---|
965 | memDC = CreateCompatibleDC(hDC);
|
---|
966 | oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
|
---|
967 |
|
---|
968 | /* Tile the bounding box. */
|
---|
969 | if (tilePtr->mask != None) {
|
---|
970 | TkWinDCState maskState;
|
---|
971 | HDC maskDC;
|
---|
972 |
|
---|
973 | maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask,
|
---|
974 | &maskState);
|
---|
975 | SetBkColor(hDC, RGB(255, 255, 255));
|
---|
976 | SetTextColor(hDC, RGB(0, 0, 0));
|
---|
977 | TileRegion(memDC, hDC, maskDC, clientPtr, x, y, width, height);
|
---|
978 | TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState);
|
---|
979 | } else {
|
---|
980 | TileRegion(memDC, hDC, NULL, clientPtr, x, y, width, height);
|
---|
981 | }
|
---|
982 | SelectBitmap(memDC, oldBitmap);
|
---|
983 | DeleteDC(memDC);
|
---|
984 | TkWinReleaseDrawableDC(drawable, hDC, &state);
|
---|
985 | }
|
---|
986 |
|
---|
987 | void
|
---|
988 | Blt_TileRectangles(
|
---|
989 | Tk_Window tkwin,
|
---|
990 | Drawable drawable,
|
---|
991 | TileClient *clientPtr,
|
---|
992 | XRectangle rectArr[],
|
---|
993 | int nRectangles)
|
---|
994 | {
|
---|
995 | HBITMAP oldBitmap;
|
---|
996 | HDC hDC, memDC;
|
---|
997 | Tile *tilePtr;
|
---|
998 | TkWinDCState state;
|
---|
999 | TkWinDrawable *twdPtr;
|
---|
1000 | XRectangle *rectPtr, *endPtr;
|
---|
1001 |
|
---|
1002 | if (drawable == None) {
|
---|
1003 | return;
|
---|
1004 | }
|
---|
1005 | tilePtr = clientPtr->tilePtr;
|
---|
1006 | hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state);
|
---|
1007 | SetROP2(hDC, tkpWinRopModes[tilePtr->gc->function]);
|
---|
1008 |
|
---|
1009 | twdPtr = (TkWinDrawable *)tilePtr->pixmap;
|
---|
1010 | memDC = CreateCompatibleDC(hDC);
|
---|
1011 | oldBitmap = SelectBitmap(memDC, twdPtr->bitmap.handle);
|
---|
1012 |
|
---|
1013 | endPtr = rectArr + nRectangles;
|
---|
1014 | /* Tile the bounding box. */
|
---|
1015 | if (tilePtr->mask != None) {
|
---|
1016 | TkWinDCState maskState;
|
---|
1017 | HDC maskDC;
|
---|
1018 |
|
---|
1019 | maskDC = TkWinGetDrawableDC(tilePtr->display, tilePtr->mask,
|
---|
1020 | &maskState);
|
---|
1021 | SetBkColor(hDC, RGB(255, 255, 255));
|
---|
1022 | SetTextColor(hDC, RGB(0, 0, 0));
|
---|
1023 | for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
|
---|
1024 | TileRegion(memDC, hDC, maskDC, clientPtr, (int)rectPtr->x,
|
---|
1025 | (int)rectPtr->y, (int)rectPtr->width, (int)rectPtr->height);
|
---|
1026 | }
|
---|
1027 | TkWinReleaseDrawableDC(tilePtr->mask, maskDC, &maskState);
|
---|
1028 | } else {
|
---|
1029 | for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
|
---|
1030 | TileRegion(memDC, hDC, NULL, clientPtr, (int)rectPtr->x,
|
---|
1031 | (int)rectPtr->y, (int)rectPtr->width, (int)rectPtr->height);
|
---|
1032 | }
|
---|
1033 | }
|
---|
1034 | SelectBitmap(memDC, oldBitmap);
|
---|
1035 | DeleteDC(memDC);
|
---|
1036 | TkWinReleaseDrawableDC(drawable, hDC, &state);
|
---|
1037 | }
|
---|
1038 |
|
---|
1039 | #else
|
---|
1040 |
|
---|
1041 | /*
|
---|
1042 | *----------------------------------------------------------------------
|
---|
1043 | *
|
---|
1044 | * RectangleMask --
|
---|
1045 | *
|
---|
1046 | * Creates a rectangular mask also stippled by the mask of the
|
---|
1047 | * tile. This is used to draw the tiled polygon images with
|
---|
1048 | * transparent areas.
|
---|
1049 | *
|
---|
1050 | * Results:
|
---|
1051 | * A bitmap mask is returned.
|
---|
1052 | *
|
---|
1053 | *----------------------------------------------------------------------
|
---|
1054 | */
|
---|
1055 | static Pixmap
|
---|
1056 | RectangleMask(display, drawable, x, y, width, height, mask, xOrigin, yOrigin)
|
---|
1057 | Display *display;
|
---|
1058 | Drawable drawable;
|
---|
1059 | int x, y;
|
---|
1060 | unsigned int width, height;
|
---|
1061 | Pixmap mask;
|
---|
1062 | int xOrigin, yOrigin;
|
---|
1063 | {
|
---|
1064 | GC gc;
|
---|
1065 | Pixmap bitmap;
|
---|
1066 | XGCValues gcValues;
|
---|
1067 | unsigned long gcMask;
|
---|
1068 |
|
---|
1069 | bitmap = Tk_GetPixmap(display, drawable, width, height, 1);
|
---|
1070 | gcMask = (GCForeground | GCBackground | GCFillStyle |
|
---|
1071 | GCTileStipXOrigin | GCTileStipYOrigin | GCStipple);
|
---|
1072 | gcValues.foreground = 0x1;
|
---|
1073 | gcValues.background = 0x0;
|
---|
1074 | gcValues.fill_style = FillOpaqueStippled;
|
---|
1075 | gcValues.ts_x_origin = xOrigin - x;
|
---|
1076 | gcValues.ts_y_origin = yOrigin - y;
|
---|
1077 | gcValues.stipple = mask;
|
---|
1078 | gc = XCreateGC(display, bitmap, gcMask, &gcValues);
|
---|
1079 | XFillRectangle(display, bitmap, gc, 0, 0, width, height);
|
---|
1080 | Blt_FreePrivateGC(display, gc);
|
---|
1081 | return bitmap;
|
---|
1082 | }
|
---|
1083 |
|
---|
1084 | /*
|
---|
1085 | *----------------------------------------------------------------------
|
---|
1086 | *
|
---|
1087 | * Blt_TileRectangle --
|
---|
1088 | *
|
---|
1089 | * Draws a rectangle filled by a tiled image. This differs from
|
---|
1090 | * the normal XFillRectangle call in that we also try to handle
|
---|
1091 | * a transparency mask.
|
---|
1092 | *
|
---|
1093 | * Results:
|
---|
1094 | * None.
|
---|
1095 | *
|
---|
1096 | * Side Effects:
|
---|
1097 | * Draws the rectangle.
|
---|
1098 | *
|
---|
1099 | *----------------------------------------------------------------------
|
---|
1100 | */
|
---|
1101 | void
|
---|
1102 | Blt_TileRectangle(
|
---|
1103 | Tk_Window tkwin,
|
---|
1104 | Drawable drawable,
|
---|
1105 | TileClient *clientPtr,
|
---|
1106 | int x, int y,
|
---|
1107 | unsigned int width,
|
---|
1108 | unsigned int height)
|
---|
1109 | {
|
---|
1110 | Tile *tilePtr;
|
---|
1111 | Display *display;
|
---|
1112 |
|
---|
1113 | display = Tk_Display(tkwin);
|
---|
1114 | tilePtr = clientPtr->tilePtr;
|
---|
1115 | if (clientPtr->tilePtr->mask != None) {
|
---|
1116 | Pixmap mask;
|
---|
1117 |
|
---|
1118 | mask = RectangleMask(display, drawable, x, y, width, height,
|
---|
1119 | tilePtr->mask, clientPtr->xOrigin, clientPtr->yOrigin);
|
---|
1120 | XSetClipMask(display, tilePtr->gc, mask);
|
---|
1121 | XSetClipOrigin(display, tilePtr->gc, x, y);
|
---|
1122 | XFillRectangle(display, drawable, tilePtr->gc, x, y, width, height);
|
---|
1123 | XSetClipMask(display, tilePtr->gc, None);
|
---|
1124 | XSetClipOrigin(display, tilePtr->gc, 0, 0);
|
---|
1125 | Tk_FreePixmap(display, mask);
|
---|
1126 | } else {
|
---|
1127 | XFillRectangle(display, drawable, tilePtr->gc, x, y, width, height);
|
---|
1128 | }
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | /*
|
---|
1132 | *----------------------------------------------------------------------
|
---|
1133 | *
|
---|
1134 | * Blt_TileRectangles --
|
---|
1135 | *
|
---|
1136 | * Draws rectangles filled by a tiled image. This differs from
|
---|
1137 | * the normal XFillRectangles call in that we also try to handle
|
---|
1138 | * a transparency mask.
|
---|
1139 | *
|
---|
1140 | * Results:
|
---|
1141 | * None.
|
---|
1142 | *
|
---|
1143 | * Side Effects:
|
---|
1144 | * Draws the given rectangles.
|
---|
1145 | *
|
---|
1146 | *----------------------------------------------------------------------
|
---|
1147 | */
|
---|
1148 | void
|
---|
1149 | Blt_TileRectangles(
|
---|
1150 | Tk_Window tkwin,
|
---|
1151 | Drawable drawable,
|
---|
1152 | TileClient *clientPtr,
|
---|
1153 | XRectangle rectArr[],
|
---|
1154 | int nRectangles)
|
---|
1155 | {
|
---|
1156 | Tile *tilePtr;
|
---|
1157 |
|
---|
1158 | tilePtr = clientPtr->tilePtr;
|
---|
1159 | if (tilePtr->mask != None) {
|
---|
1160 | XRectangle *rectPtr, *endPtr;
|
---|
1161 |
|
---|
1162 | endPtr = rectArr + nRectangles;
|
---|
1163 | for (rectPtr = rectArr; rectPtr < endPtr; rectPtr++) {
|
---|
1164 | Blt_TileRectangle(tkwin, drawable, clientPtr, rectPtr->x,
|
---|
1165 | rectPtr->y, rectPtr->width, rectPtr->height);
|
---|
1166 | }
|
---|
1167 | } else {
|
---|
1168 | XFillRectangles(Tk_Display(tkwin), drawable, tilePtr->gc, rectArr,
|
---|
1169 | nRectangles);
|
---|
1170 | }
|
---|
1171 | }
|
---|
1172 |
|
---|
1173 | /*
|
---|
1174 | *----------------------------------------------------------------------
|
---|
1175 | *
|
---|
1176 | * PolygonMask --
|
---|
1177 | *
|
---|
1178 | * Creates a polygon shaped mask also stippled by the mask
|
---|
1179 | * of the tile. This is used to draw the tiled polygon images
|
---|
1180 | * with transparent areas.
|
---|
1181 | *
|
---|
1182 | * Results:
|
---|
1183 | * A bitmap mask is returned.
|
---|
1184 | *
|
---|
1185 | *----------------------------------------------------------------------
|
---|
1186 | */
|
---|
1187 | static Pixmap
|
---|
1188 | PolygonMask(display, pointArr, nPoints, regionPtr, mask, xOrigin, yOrigin)
|
---|
1189 | Display *display;
|
---|
1190 | XPoint *pointArr;
|
---|
1191 | int nPoints;
|
---|
1192 | Region2D *regionPtr;
|
---|
1193 | Pixmap mask;
|
---|
1194 | int xOrigin, yOrigin;
|
---|
1195 | {
|
---|
1196 | unsigned int width, height;
|
---|
1197 | Pixmap bitmap;
|
---|
1198 | GC gc;
|
---|
1199 | XPoint *destArr;
|
---|
1200 | register XPoint *srcPtr, *destPtr, *endPtr;
|
---|
1201 |
|
---|
1202 | width = regionPtr->right - regionPtr->left + 1;
|
---|
1203 | height = regionPtr->bottom - regionPtr->top + 1;
|
---|
1204 | bitmap =
|
---|
1205 | Tk_GetPixmap(display, DefaultRootWindow(display), width, height, 1);
|
---|
1206 |
|
---|
1207 | destArr = Blt_Malloc(sizeof(XPoint) * nPoints);
|
---|
1208 | endPtr = destArr + nPoints;
|
---|
1209 | srcPtr = pointArr;
|
---|
1210 | for (destPtr = destArr; destPtr < endPtr; destPtr++) {
|
---|
1211 | destPtr->x = srcPtr->x - regionPtr->left;
|
---|
1212 | destPtr->y = srcPtr->y - regionPtr->top;
|
---|
1213 | srcPtr++;
|
---|
1214 | }
|
---|
1215 | gc = XCreateGC(display, bitmap, 0, NULL);
|
---|
1216 | XFillRectangle(display, bitmap, gc, 0, 0, width, height);
|
---|
1217 | XSetForeground(display, gc, 0x01);
|
---|
1218 | XSetFillStyle(display, gc, FillStippled);
|
---|
1219 | XSetTSOrigin(display, gc, xOrigin - regionPtr->left,
|
---|
1220 | yOrigin - regionPtr->top);
|
---|
1221 | XSetStipple(display, gc, mask);
|
---|
1222 | XFillPolygon(display, bitmap, gc, destArr, nPoints, Complex,
|
---|
1223 | CoordModeOrigin);
|
---|
1224 | XFreeGC(display, gc);
|
---|
1225 | Blt_Free(destArr);
|
---|
1226 | return bitmap;
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | /*
|
---|
1230 | *----------------------------------------------------------------------
|
---|
1231 | *
|
---|
1232 | * Blt_TilePolygon --
|
---|
1233 | *
|
---|
1234 | * Draws a polygon filled by a tiled image. This differs from
|
---|
1235 | * the normal XFillPolygon call in that we also try to handle
|
---|
1236 | * a transparency mask.
|
---|
1237 | *
|
---|
1238 | * Results:
|
---|
1239 | * None.
|
---|
1240 | *
|
---|
1241 | * Side Effects:
|
---|
1242 | * Draws the polygon.
|
---|
1243 | *
|
---|
1244 | *----------------------------------------------------------------------
|
---|
1245 | */
|
---|
1246 | void
|
---|
1247 | Blt_TilePolygon(
|
---|
1248 | Tk_Window tkwin,
|
---|
1249 | Drawable drawable,
|
---|
1250 | TileClient *clientPtr,
|
---|
1251 | XPoint pointArr[],
|
---|
1252 | int nPoints)
|
---|
1253 | {
|
---|
1254 | Tile *tilePtr;
|
---|
1255 | Display *display;
|
---|
1256 |
|
---|
1257 | display = Tk_Display(tkwin);
|
---|
1258 | tilePtr = clientPtr->tilePtr;
|
---|
1259 | if (tilePtr->mask != None) {
|
---|
1260 | XPoint *pointPtr, *endPtr;
|
---|
1261 | Region2D region;
|
---|
1262 | Pixmap mask;
|
---|
1263 |
|
---|
1264 | /* Determine the bounding box of the polygon. */
|
---|
1265 | pointPtr = pointArr;
|
---|
1266 | region.left = region.right = pointPtr->x;
|
---|
1267 | region.top = region.bottom = pointPtr->y;
|
---|
1268 |
|
---|
1269 | endPtr = pointArr + nPoints;
|
---|
1270 | for (pointPtr = pointArr; pointPtr < endPtr; pointPtr++) {
|
---|
1271 | if (region.left > pointPtr->x) {
|
---|
1272 | region.left = pointPtr->x;
|
---|
1273 | } else if (region.right < pointPtr->x) {
|
---|
1274 | region.right = pointPtr->x;
|
---|
1275 | }
|
---|
1276 | if (region.top > pointPtr->y) {
|
---|
1277 | region.top = pointPtr->y;
|
---|
1278 | } else if (region.bottom < pointPtr->y) {
|
---|
1279 | region.bottom = pointPtr->y;
|
---|
1280 | }
|
---|
1281 | }
|
---|
1282 | mask = PolygonMask(display, pointArr, nPoints, ®ion,
|
---|
1283 | tilePtr->mask, clientPtr->xOrigin, clientPtr->yOrigin);
|
---|
1284 | XSetClipMask(display, tilePtr->gc, mask);
|
---|
1285 | XSetClipOrigin(display, tilePtr->gc, region.left, region.top);
|
---|
1286 | XFillPolygon(display, drawable, tilePtr->gc, pointArr,
|
---|
1287 | nPoints, Complex, CoordModeOrigin);
|
---|
1288 | XSetClipMask(display, tilePtr->gc, None);
|
---|
1289 | XSetClipOrigin(display, tilePtr->gc, 0, 0);
|
---|
1290 | Tk_FreePixmap(display, mask);
|
---|
1291 | } else {
|
---|
1292 | XFillPolygon(display, drawable, tilePtr->gc, pointArr,
|
---|
1293 | nPoints, Complex, CoordModeOrigin);
|
---|
1294 | }
|
---|
1295 | }
|
---|
1296 | #endif
|
---|