source: trunk/kitgen/8.x/blt/generic/bltTile.c@ 176

Last change on this file since 176 was 175, checked in by demin, 12 years ago

initial commit

File size: 34.8 KB
RevLine 
[175]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
38typedef 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
44typedef 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
68typedef 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
82typedef struct {
83 Display *display;
84 Tk_Uid nameId;
85 int depth;
86} TileKey;
87
88static TileInterpData *GetTileInterpData _ANSI_ARGS_((Tcl_Interp *interp));
89
90static Tcl_IdleProc UpdateTile;
91static Tk_ImageChangedProc ImageChangedProc;
92static Tcl_InterpDeleteProc TileInterpDeleteProc;
93
94static void DestroyClient _ANSI_ARGS_((TileClient *clientPtr));
95static 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 */
111static void
112RedrawTile(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 */
188static void
189UpdateTile(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 */
240static void
241ImageChangedProc(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 */
267static void
268DestroyTile(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 */
319static Tile *
320CreateTile(
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 */
366static void
367DestroyClient(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 */
404static TileClient *
405CreateClient(
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 */
463static void
464TileInterpDeleteProc(
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
484static TileInterpData *
485GetTileInterpData(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*/
523int
524Blt_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*/
557void
558Blt_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*/
581char *
582Blt_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*/
606Pixmap
607Blt_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*/
628void
629Blt_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*/
659void
660Blt_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*/
692void
693Blt_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
708void
709Blt_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
720static 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
743static void
744TileRegion(
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
849void
850Blt_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
942void
943Blt_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
987void
988Blt_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 */
1055static Pixmap
1056RectangleMask(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 */
1101void
1102Blt_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 */
1148void
1149Blt_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 */
1187static Pixmap
1188PolygonMask(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 */
1246void
1247Blt_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, &region,
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
Note: See TracBrowser for help on using the repository browser.