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, &region,
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