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