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