1/* 2 * tkImage.c -- 3 * 4 * This module implements the image protocol, which allows lots of 5 * different kinds of images to be used in lots of different widgets. 6 * 7 * Copyright (c) 1994 The Regents of the University of California. 8 * Copyright (c) 1994-1997 Sun Microsystems, Inc. 9 * 10 * See the file "license.terms" for information on usage and redistribution of 11 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 12 * 13 * RCS: @(#) $Id$ 14 */ 15 16#include "tkInt.h" 17 18/* 19 * Each call to Tk_GetImage returns a pointer to one of the following 20 * structures, which is used as a token by clients (widgets) that 21 * display images. 22 */ 23 24typedef struct Image { 25 Tk_Window tkwin; /* Window passed to Tk_GetImage (needed to 26 * "re-get" the image later if the manager 27 * changes). */ 28 Display *display; /* Display for tkwin. Needed because when the 29 * image is eventually freed tkwin may not 30 * exist anymore. */ 31 struct ImageMaster *masterPtr; 32 /* Master for this image (identifiers image 33 * manager, for example). */ 34 ClientData instanceData; /* One word argument to pass to image manager 35 * when dealing with this image instance. */ 36 Tk_ImageChangedProc *changeProc; 37 /* Code in widget to call when image changes 38 * in a way that affects redisplay. */ 39 ClientData widgetClientData;/* Argument to pass to changeProc. */ 40 struct Image *nextPtr; /* Next in list of all image instances 41 * associated with the same name. */ 42} Image; 43 44/* 45 * For each image master there is one of the following structures, which 46 * represents a name in the image table and all of the images instantiated 47 * from it. Entries in mainPtr->imageTable point to these structures. 48 */ 49 50typedef struct ImageMaster { 51 Tk_ImageType *typePtr; /* Information about image type. NULL means 52 * that no image manager owns this image: the 53 * image was deleted. */ 54 ClientData masterData; /* One-word argument to pass to image mgr when 55 * dealing with the master, as opposed to 56 * instances. */ 57 int width, height; /* Last known dimensions for image. */ 58 Tcl_HashTable *tablePtr; /* Pointer to hash table containing image (the 59 * imageTable field in some TkMainInfo 60 * structure). */ 61 Tcl_HashEntry *hPtr; /* Hash entry in mainPtr->imageTable for this 62 * structure (used to delete the hash 63 * entry). */ 64 Image *instancePtr; /* Pointer to first in list of instances 65 * derived from this name. */ 66 int deleted; /* Flag set when image is being deleted. */ 67 TkWindow *winPtr; /* Main window of interpreter (used to detect 68 * when the world is falling apart.) */ 69} ImageMaster; 70 71typedef struct ThreadSpecificData { 72 Tk_ImageType *imageTypeList;/* First in a list of all known image 73 * types. */ 74 Tk_ImageType *oldImageTypeList; 75 /* First in a list of all known old-style 76 * image types. */ 77 int initialized; /* Set to 1 if we've initialized the 78 * structure. */ 79} ThreadSpecificData; 80static Tcl_ThreadDataKey dataKey; 81 82/* 83 * Prototypes for local functions: 84 */ 85 86static void ImageTypeThreadExitProc(ClientData clientData); 87static void DeleteImage(ImageMaster *masterPtr); 88static void EventuallyDeleteImage(ImageMaster *masterPtr, 89 int forgetImageHashNow); 90 91/* 92 *---------------------------------------------------------------------- 93 * 94 * ImageTypeThreadExitProc -- 95 * 96 * Clean up the registered list of image types. 97 * 98 * Results: 99 * None. 100 * 101 * Side effects: 102 * The thread's linked lists of photo image formats is deleted. 103 * 104 *---------------------------------------------------------------------- 105 */ 106 107static void 108ImageTypeThreadExitProc( 109 ClientData clientData) /* not used */ 110{ 111 Tk_ImageType *freePtr; 112 ThreadSpecificData *tsdPtr = 113 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 114 115 while (tsdPtr->oldImageTypeList != NULL) { 116 freePtr = tsdPtr->oldImageTypeList; 117 tsdPtr->oldImageTypeList = tsdPtr->oldImageTypeList->nextPtr; 118 ckfree((char *) freePtr); 119 } 120 while (tsdPtr->imageTypeList != NULL) { 121 freePtr = tsdPtr->imageTypeList; 122 tsdPtr->imageTypeList = tsdPtr->imageTypeList->nextPtr; 123 ckfree((char *) freePtr); 124 } 125} 126 127/* 128 *---------------------------------------------------------------------- 129 * 130 * Tk_CreateOldImageType, Tk_CreateImageType -- 131 * 132 * This function is invoked by an image manager to tell Tk about a new 133 * kind of image and the functions that manage the new type. The function 134 * is typically invoked during Tcl_AppInit. 135 * 136 * Results: 137 * None. 138 * 139 * Side effects: 140 * The new image type is entered into a table used in the "image create" 141 * command. 142 * 143 *---------------------------------------------------------------------- 144 */ 145 146void 147Tk_CreateOldImageType( 148 Tk_ImageType *typePtr) /* Structure describing the type. All of the 149 * fields except "nextPtr" must be filled in 150 * by caller. */ 151{ 152 Tk_ImageType *copyPtr; 153 ThreadSpecificData *tsdPtr = 154 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 155 156 if (!tsdPtr->initialized) { 157 tsdPtr->initialized = 1; 158 Tcl_CreateThreadExitHandler(ImageTypeThreadExitProc, NULL); 159 } 160 copyPtr = (Tk_ImageType *) ckalloc(sizeof(Tk_ImageType)); 161 *copyPtr = *typePtr; 162 copyPtr->nextPtr = tsdPtr->oldImageTypeList; 163 tsdPtr->oldImageTypeList = copyPtr; 164} 165 166void 167Tk_CreateImageType( 168 Tk_ImageType *typePtr) /* Structure describing the type. All of the 169 * fields except "nextPtr" must be filled in 170 * by caller. */ 171{ 172 Tk_ImageType *copyPtr; 173 ThreadSpecificData *tsdPtr = 174 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 175 176 if (!tsdPtr->initialized) { 177 tsdPtr->initialized = 1; 178 Tcl_CreateThreadExitHandler(ImageTypeThreadExitProc, NULL); 179 } 180 copyPtr = (Tk_ImageType *) ckalloc(sizeof(Tk_ImageType)); 181 *copyPtr = *typePtr; 182 copyPtr->nextPtr = tsdPtr->imageTypeList; 183 tsdPtr->imageTypeList = copyPtr; 184} 185 186/* 187 *---------------------------------------------------------------------- 188 * 189 * Tk_ImageObjCmd -- 190 * 191 * This function is invoked to process the "image" Tcl command. See the 192 * user documentation for details on what it does. 193 * 194 * Results: 195 * A standard Tcl result. 196 * 197 * Side effects: 198 * See the user documentation. 199 * 200 *---------------------------------------------------------------------- 201 */ 202 203int 204Tk_ImageObjCmd( 205 ClientData clientData, /* Main window associated with interpreter. */ 206 Tcl_Interp *interp, /* Current interpreter. */ 207 int objc, /* Number of arguments. */ 208 Tcl_Obj *CONST objv[]) /* Argument strings. */ 209{ 210 static CONST char *imageOptions[] = { 211 "create", "delete", "height", "inuse", "names", "type", "types", 212 "width", NULL 213 }; 214 enum options { 215 IMAGE_CREATE, IMAGE_DELETE, IMAGE_HEIGHT, IMAGE_INUSE, IMAGE_NAMES, 216 IMAGE_TYPE, IMAGE_TYPES, IMAGE_WIDTH 217 }; 218 TkWindow *winPtr = (TkWindow *) clientData; 219 int i, isNew, firstOption, index; 220 Tk_ImageType *typePtr; 221 ImageMaster *masterPtr; 222 Image *imagePtr; 223 Tcl_HashEntry *hPtr; 224 Tcl_HashSearch search; 225 char idString[16 + TCL_INTEGER_SPACE]; 226 TkDisplay *dispPtr = winPtr->dispPtr; 227 char *arg, *name; 228 ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 229 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); 230 231 if (objc < 2) { 232 Tcl_WrongNumArgs(interp, 1, objv, "option ?args?"); 233 return TCL_ERROR; 234 } 235 236 if (Tcl_GetIndexFromObj(interp, objv[1], imageOptions, "option", 0, 237 &index) != TCL_OK) { 238 return TCL_ERROR; 239 } 240 switch ((enum options) index) { 241 case IMAGE_CREATE: { 242 Tcl_Obj **args; 243 int oldimage = 0; 244 if (objc < 3) { 245 Tcl_WrongNumArgs(interp, 2, objv, "type ?name? ?options?"); 246 return TCL_ERROR; 247 } 248 249 /* 250 * Look up the image type. 251 */ 252 253 arg = Tcl_GetString(objv[2]); 254 for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; 255 typePtr = typePtr->nextPtr) { 256 if ((*arg == typePtr->name[0]) 257 && (strcmp(arg, typePtr->name) == 0)) { 258 break; 259 } 260 } 261 if (typePtr == NULL) { 262 oldimage = 1; 263 for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; 264 typePtr = typePtr->nextPtr) { 265 if ((*arg == typePtr->name[0]) 266 && (strcmp(arg, typePtr->name) == 0)) { 267 break; 268 } 269 } 270 } 271 if (typePtr == NULL) { 272 Tcl_AppendResult(interp, "image type \"", arg, "\" doesn't exist", 273 NULL); 274 return TCL_ERROR; 275 } 276 277 /* 278 * Figure out a name to use for the new image. 279 */ 280 281 if ((objc == 3) || (*(arg = Tcl_GetString(objv[3])) == '-')) { 282 Tcl_CmdInfo dummy; 283 do { 284 dispPtr->imageId++; 285 sprintf(idString, "image%d", dispPtr->imageId); 286 name = idString; 287 } while (Tcl_GetCommandInfo(interp, name, &dummy) != 0); 288 firstOption = 3; 289 } else { 290 TkWindow *topWin; 291 292 name = arg; 293 firstOption = 4; 294 295 /* 296 * Need to check if the _command_ that we are about to create is 297 * the name of the current master widget command (normally "." but 298 * could have been renamed) and fail in that case before a really 299 * nasty and hard to stop crash happens. 300 */ 301 302 topWin = (TkWindow *) TkToplevelWindowForCommand(interp, name); 303 if (topWin != NULL && winPtr->mainPtr->winPtr == topWin) { 304 Tcl_AppendResult(interp, "images may not be named the ", 305 "same as the main window", NULL); 306 return TCL_ERROR; 307 } 308 } 309 310 /* 311 * Create the data structure for the new image. 312 */ 313 314 hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, name, &isNew); 315 if (isNew) { 316 masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster)); 317 masterPtr->typePtr = NULL; 318 masterPtr->masterData = NULL; 319 masterPtr->width = masterPtr->height = 1; 320 masterPtr->tablePtr = &winPtr->mainPtr->imageTable; 321 masterPtr->hPtr = hPtr; 322 masterPtr->instancePtr = NULL; 323 masterPtr->deleted = 0; 324 masterPtr->winPtr = winPtr->mainPtr->winPtr; 325 Tcl_Preserve((ClientData) masterPtr->winPtr); 326 Tcl_SetHashValue(hPtr, masterPtr); 327 } else { 328 /* 329 * An image already exists by this name. Disconnect the instances 330 * from the master. 331 */ 332 333 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); 334 if (masterPtr->typePtr != NULL) { 335 for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; 336 imagePtr = imagePtr->nextPtr) { 337 (*masterPtr->typePtr->freeProc)(imagePtr->instanceData, 338 imagePtr->display); 339 (*imagePtr->changeProc)(imagePtr->widgetClientData, 340 0, 0, masterPtr->width, masterPtr->height, 341 masterPtr->width, masterPtr->height); 342 } 343 (*masterPtr->typePtr->deleteProc)(masterPtr->masterData); 344 masterPtr->typePtr = NULL; 345 } 346 masterPtr->deleted = 0; 347 } 348 349 /* 350 * Call the image type manager so that it can perform its own 351 * initialization, then re-"get" for any existing instances of the 352 * image. 353 */ 354 355 objv += firstOption; 356 objc -= firstOption; 357 args = (Tcl_Obj **) objv; 358 if (oldimage) { 359 int i; 360 361 args = (Tcl_Obj **) ckalloc((objc+1) * sizeof(char *)); 362 for (i = 0; i < objc; i++) { 363 args[i] = (Tcl_Obj *) Tcl_GetString(objv[i]); 364 } 365 args[objc] = NULL; 366 } 367 Tcl_Preserve((ClientData) masterPtr); 368 if ((*typePtr->createProc)(interp, name, objc, args, typePtr, 369 (Tk_ImageMaster)masterPtr, &masterPtr->masterData) != TCL_OK) { 370 EventuallyDeleteImage(masterPtr, 0); 371 Tcl_Release((ClientData) masterPtr); 372 if (oldimage) { 373 ckfree((char *) args); 374 } 375 return TCL_ERROR; 376 } 377 Tcl_Release((ClientData) masterPtr); 378 if (oldimage) { 379 ckfree((char *) args); 380 } 381 masterPtr->typePtr = typePtr; 382 for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; 383 imagePtr = imagePtr->nextPtr) { 384 imagePtr->instanceData = (*typePtr->getProc)(imagePtr->tkwin, 385 masterPtr->masterData); 386 } 387 Tcl_SetResult(interp, 388 Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), 389 TCL_STATIC); 390 break; 391 } 392 case IMAGE_DELETE: 393 for (i = 2; i < objc; i++) { 394 arg = Tcl_GetString(objv[i]); 395 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); 396 if (hPtr == NULL) { 397 goto alreadyDeleted; 398 } 399 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); 400 if (masterPtr->deleted) { 401 goto alreadyDeleted; 402 } 403 DeleteImage(masterPtr); 404 } 405 break; 406 case IMAGE_NAMES: 407 if (objc != 2) { 408 Tcl_WrongNumArgs(interp, 2, objv, NULL); 409 return TCL_ERROR; 410 } 411 hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); 412 for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 413 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); 414 if (masterPtr->deleted) { 415 continue; 416 } 417 Tcl_AppendElement(interp, Tcl_GetHashKey( 418 &winPtr->mainPtr->imageTable, hPtr)); 419 } 420 break; 421 case IMAGE_TYPES: 422 if (objc != 2) { 423 Tcl_WrongNumArgs(interp, 2, objv, NULL); 424 return TCL_ERROR; 425 } 426 for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; 427 typePtr = typePtr->nextPtr) { 428 Tcl_AppendElement(interp, typePtr->name); 429 } 430 for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; 431 typePtr = typePtr->nextPtr) { 432 Tcl_AppendElement(interp, typePtr->name); 433 } 434 break; 435 436 case IMAGE_HEIGHT: 437 case IMAGE_INUSE: 438 case IMAGE_TYPE: 439 case IMAGE_WIDTH: 440 /* 441 * These operations all parse virtually identically. First check to 442 * see if three args are given. Then get a non-deleted master from the 443 * third arg. 444 */ 445 446 if (objc != 3) { 447 Tcl_WrongNumArgs(interp, 2, objv, "name"); 448 return TCL_ERROR; 449 } 450 451 arg = Tcl_GetString(objv[2]); 452 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); 453 if (hPtr == NULL) { 454 goto alreadyDeleted; 455 } 456 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); 457 if (masterPtr->deleted) { 458 goto alreadyDeleted; 459 } 460 461 /* 462 * Now we read off the specific piece of data we were asked for. 463 */ 464 465 switch ((enum options) index) { 466 case IMAGE_HEIGHT: 467 Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->height); 468 break; 469 case IMAGE_INUSE: 470 Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 471 masterPtr->typePtr!=NULL && masterPtr->instancePtr!=NULL); 472 break; 473 case IMAGE_TYPE: 474 if (masterPtr->typePtr != NULL) { 475 Tcl_SetResult(interp, masterPtr->typePtr->name, TCL_STATIC); 476 } 477 break; 478 case IMAGE_WIDTH: 479 Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->width); 480 break; 481 default: 482 Tcl_Panic("can't happen"); 483 } 484 break; 485 } 486 return TCL_OK; 487 488 alreadyDeleted: 489 Tcl_AppendResult(interp, "image \"", arg, "\" doesn't exist", NULL); 490 return TCL_ERROR; 491} 492 493/* 494 *---------------------------------------------------------------------- 495 * 496 * Tk_ImageChanged -- 497 * 498 * This function is called by an image manager whenever something has 499 * happened that requires the image to be redrawn (some of its pixels 500 * have changed, or its size has changed). 501 * 502 * Results: 503 * None. 504 * 505 * Side effects: 506 * Any widgets that display the image are notified so that they can 507 * redisplay themselves as appropriate. 508 * 509 *---------------------------------------------------------------------- 510 */ 511 512void 513Tk_ImageChanged( 514 Tk_ImageMaster imageMaster, /* Image that needs redisplay. */ 515 int x, int y, /* Coordinates of upper-left pixel of region 516 * of image that needs to be redrawn. */ 517 int width, int height, /* Dimensions (in pixels) of region of image 518 * to redraw. If either dimension is zero then 519 * the image doesn't need to be redrawn 520 * (perhaps all that happened is that its size 521 * changed). */ 522 int imageWidth, int imageHeight) 523 /* New dimensions of image. */ 524{ 525 ImageMaster *masterPtr = (ImageMaster *) imageMaster; 526 Image *imagePtr; 527 528 masterPtr->width = imageWidth; 529 masterPtr->height = imageHeight; 530 for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; 531 imagePtr = imagePtr->nextPtr) { 532 (*imagePtr->changeProc)(imagePtr->widgetClientData, x, y, 533 width, height, imageWidth, imageHeight); 534 } 535} 536 537/* 538 *---------------------------------------------------------------------- 539 * 540 * Tk_NameOfImage -- 541 * 542 * Given a token for an image master, this function returns the name of 543 * the image. 544 * 545 * Results: 546 * The return value is the string name for imageMaster. 547 * 548 * Side effects: 549 * None. 550 * 551 *---------------------------------------------------------------------- 552 */ 553 554CONST char * 555Tk_NameOfImage( 556 Tk_ImageMaster imageMaster) /* Token for image. */ 557{ 558 ImageMaster *masterPtr = (ImageMaster *) imageMaster; 559 560 if (masterPtr->hPtr == NULL) { 561 return NULL; 562 } 563 return Tcl_GetHashKey(masterPtr->tablePtr, masterPtr->hPtr); 564} 565 566/* 567 *---------------------------------------------------------------------- 568 * 569 * Tk_GetImage -- 570 * 571 * This function is invoked by a widget when it wants to use a particular 572 * image in a particular window. 573 * 574 * Results: 575 * The return value is a token for the image. If there is no image by the 576 * given name, then NULL is returned and an error message is left in the 577 * interp's result. 578 * 579 * Side effects: 580 * Tk records the fact that the widget is using the image, and it will 581 * invoke changeProc later if the widget needs redisplay (i.e. its size 582 * changes or some of its pixels change). The caller must eventually 583 * invoke Tk_FreeImage when it no longer needs the image. 584 * 585 *---------------------------------------------------------------------- 586 */ 587 588Tk_Image 589Tk_GetImage( 590 Tcl_Interp *interp, /* Place to leave error message if image can't 591 * be found. */ 592 Tk_Window tkwin, /* Token for window in which image will be 593 * used. */ 594 CONST char *name, /* Name of desired image. */ 595 Tk_ImageChangedProc *changeProc, 596 /* Function to invoke when redisplay is needed 597 * because image's pixels or size changed. */ 598 ClientData clientData) /* One-word argument to pass to damageProc. */ 599{ 600 Tcl_HashEntry *hPtr; 601 ImageMaster *masterPtr; 602 Image *imagePtr; 603 604 hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->imageTable, name); 605 if (hPtr == NULL) { 606 goto noSuchImage; 607 } 608 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); 609 if (masterPtr->typePtr == NULL) { 610 goto noSuchImage; 611 } 612 if (masterPtr->deleted) { 613 goto noSuchImage; 614 } 615 imagePtr = (Image *) ckalloc(sizeof(Image)); 616 imagePtr->tkwin = tkwin; 617 imagePtr->display = Tk_Display(tkwin); 618 imagePtr->masterPtr = masterPtr; 619 imagePtr->instanceData = 620 (*masterPtr->typePtr->getProc)(tkwin, masterPtr->masterData); 621 imagePtr->changeProc = changeProc; 622 imagePtr->widgetClientData = clientData; 623 imagePtr->nextPtr = masterPtr->instancePtr; 624 masterPtr->instancePtr = imagePtr; 625 return (Tk_Image) imagePtr; 626 627 noSuchImage: 628 if (interp) { 629 Tcl_AppendResult(interp, "image \"", name, "\" doesn't exist", NULL); 630 } 631 return NULL; 632} 633 634/* 635 *---------------------------------------------------------------------- 636 * 637 * Tk_FreeImage -- 638 * 639 * This function is invoked by a widget when it no longer needs an image 640 * acquired by a previous call to Tk_GetImage. For each call to 641 * Tk_GetImage there must be exactly one call to Tk_FreeImage. 642 * 643 * Results: 644 * None. 645 * 646 * Side effects: 647 * The association between the image and the widget is removed. 648 * 649 *---------------------------------------------------------------------- 650 */ 651 652void 653Tk_FreeImage( 654 Tk_Image image) /* Token for image that is no longer needed by 655 * a widget. */ 656{ 657 Image *imagePtr = (Image *) image; 658 ImageMaster *masterPtr = imagePtr->masterPtr; 659 Image *prevPtr; 660 661 /* 662 * Clean up the particular instance. 663 */ 664 665 if (masterPtr->typePtr != NULL) { 666 (*masterPtr->typePtr->freeProc)(imagePtr->instanceData, 667 imagePtr->display); 668 } 669 prevPtr = masterPtr->instancePtr; 670 if (prevPtr == imagePtr) { 671 masterPtr->instancePtr = imagePtr->nextPtr; 672 } else { 673 while (prevPtr->nextPtr != imagePtr) { 674 prevPtr = prevPtr->nextPtr; 675 } 676 prevPtr->nextPtr = imagePtr->nextPtr; 677 } 678 ckfree((char *) imagePtr); 679 680 /* 681 * If there are no more instances left for the master, and if the master 682 * image has been deleted, then delete the master too. 683 */ 684 685 if ((masterPtr->typePtr == NULL) && (masterPtr->instancePtr == NULL)) { 686 if (masterPtr->hPtr != NULL) { 687 Tcl_DeleteHashEntry(masterPtr->hPtr); 688 } 689 Tcl_Release((ClientData) masterPtr->winPtr); 690 ckfree((char *) masterPtr); 691 } 692} 693 694/* 695 *---------------------------------------------------------------------- 696 * 697 * Tk_PostscriptImage -- 698 * 699 * This function is called by widgets that contain images in order to 700 * redisplay an image on the screen or an off-screen pixmap. 701 * 702 * Results: 703 * None. 704 * 705 * Side effects: 706 * The image's manager is notified, and it redraws the desired portion of 707 * the image before returning. 708 * 709 *---------------------------------------------------------------------- 710 */ 711 712int 713Tk_PostscriptImage( 714 Tk_Image image, /* Token for image to redisplay. */ 715 Tcl_Interp *interp, 716 Tk_Window tkwin, 717 Tk_PostscriptInfo psinfo, /* postscript info */ 718 int x, int y, /* Upper-left pixel of region in image that 719 * needs to be redisplayed. */ 720 int width, int height, /* Dimensions of region to redraw. */ 721 int prepass) 722{ 723 Image *imagePtr = (Image *) image; 724 int result; 725 XImage *ximage; 726 Pixmap pmap; 727 GC newGC; 728 XGCValues gcValues; 729 730 if (imagePtr->masterPtr->typePtr == NULL) { 731 /* 732 * No master for image, so nothing to display on postscript. 733 */ 734 735 return TCL_OK; 736 } 737 738 /* 739 * Check if an image specific postscript-generation function exists; 740 * otherwise go on with generic code. 741 */ 742 743 if (imagePtr->masterPtr->typePtr->postscriptProc != NULL) { 744 return (*imagePtr->masterPtr->typePtr->postscriptProc)( 745 imagePtr->masterPtr->masterData, interp, tkwin, psinfo, 746 x, y, width, height, prepass); 747 } 748 749 if (prepass) { 750 return TCL_OK; 751 } 752 753 /* 754 * Create a Pixmap, tell the image to redraw itself there, and then 755 * generate an XImage from the Pixmap. We can then read pixel values out 756 * of the XImage. 757 */ 758 759 pmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), width, height, 760 Tk_Depth(tkwin)); 761 762 gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); 763 newGC = Tk_GetGC(tkwin, GCForeground, &gcValues); 764 if (newGC != None) { 765 XFillRectangle(Tk_Display(tkwin), pmap, newGC, 766 0, 0, (unsigned int)width, (unsigned int)height); 767 Tk_FreeGC(Tk_Display(tkwin), newGC); 768 } 769 770 Tk_RedrawImage(image, x, y, width, height, pmap, 0, 0); 771 772 ximage = XGetImage(Tk_Display(tkwin), pmap, 0, 0, 773 (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); 774 775 Tk_FreePixmap(Tk_Display(tkwin), pmap); 776 777 if (ximage == NULL) { 778 /* 779 * The XGetImage() function is apparently not implemented on this 780 * system. Just ignore it. 781 */ 782 783 return TCL_OK; 784 } 785 result = TkPostscriptImage(interp, tkwin, psinfo, ximage, x, y, 786 width, height); 787 788 XDestroyImage(ximage); 789 return result; 790} 791 792/* 793 *---------------------------------------------------------------------- 794 * 795 * Tk_RedrawImage -- 796 * 797 * This function is called by widgets that contain images in order to 798 * redisplay an image on the screen or an off-screen pixmap. 799 * 800 * Results: 801 * None. 802 * 803 * Side effects: 804 * The image's manager is notified, and it redraws the desired portion of 805 * the image before returning. 806 * 807 *---------------------------------------------------------------------- 808 */ 809 810void 811Tk_RedrawImage( 812 Tk_Image image, /* Token for image to redisplay. */ 813 int imageX, int imageY, /* Upper-left pixel of region in image that 814 * needs to be redisplayed. */ 815 int width, int height, /* Dimensions of region to redraw. */ 816 Drawable drawable, /* Drawable in which to display image (window 817 * or pixmap). If this is a pixmap, it must 818 * have the same depth as the window used in 819 * the Tk_GetImage call for the image. */ 820 int drawableX, int drawableY) 821 /* Coordinates in drawable that correspond to 822 * imageX and imageY. */ 823{ 824 Image *imagePtr = (Image *) image; 825 826 if (imagePtr->masterPtr->typePtr == NULL) { 827 /* 828 * No master for image, so nothing to display. 829 */ 830 831 return; 832 } 833 834 /* 835 * Clip the redraw area to the area of the image. 836 */ 837 838 if (imageX < 0) { 839 width += imageX; 840 drawableX -= imageX; 841 imageX = 0; 842 } 843 if (imageY < 0) { 844 height += imageY; 845 drawableY -= imageY; 846 imageY = 0; 847 } 848 if ((imageX + width) > imagePtr->masterPtr->width) { 849 width = imagePtr->masterPtr->width - imageX; 850 } 851 if ((imageY + height) > imagePtr->masterPtr->height) { 852 height = imagePtr->masterPtr->height - imageY; 853 } 854 (*imagePtr->masterPtr->typePtr->displayProc)( 855 imagePtr->instanceData, imagePtr->display, drawable, 856 imageX, imageY, width, height, drawableX, drawableY); 857} 858 859/* 860 *---------------------------------------------------------------------- 861 * 862 * Tk_SizeOfImage -- 863 * 864 * This function returns the current dimensions of an image. 865 * 866 * Results: 867 * The width and height of the image are returned in *widthPtr and 868 * *heightPtr. 869 * 870 * Side effects: 871 * None. 872 * 873 *---------------------------------------------------------------------- 874 */ 875 876void 877Tk_SizeOfImage( 878 Tk_Image image, /* Token for image whose size is wanted. */ 879 int *widthPtr, /* Return width of image here. */ 880 int *heightPtr) /* Return height of image here. */ 881{ 882 Image *imagePtr = (Image *) image; 883 884 *widthPtr = imagePtr->masterPtr->width; 885 *heightPtr = imagePtr->masterPtr->height; 886} 887 888/* 889 *---------------------------------------------------------------------- 890 * 891 * Tk_DeleteImage -- 892 * 893 * Given the name of an image, this function destroys the image. 894 * 895 * Results: 896 * None. 897 * 898 * Side effects: 899 * The image is destroyed; existing instances will display as blank 900 * areas. If no such image exists then the function does nothing. 901 * 902 *---------------------------------------------------------------------- 903 */ 904 905void 906Tk_DeleteImage( 907 Tcl_Interp *interp, /* Interpreter in which the image was 908 * created. */ 909 CONST char *name) /* Name of image. */ 910{ 911 Tcl_HashEntry *hPtr; 912 TkWindow *winPtr; 913 914 winPtr = (TkWindow *) Tk_MainWindow(interp); 915 if (winPtr == NULL) { 916 return; 917 } 918 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name); 919 if (hPtr == NULL) { 920 return; 921 } 922 DeleteImage((ImageMaster *)Tcl_GetHashValue(hPtr)); 923} 924 925/* 926 *---------------------------------------------------------------------- 927 * 928 * DeleteImage -- 929 * 930 * This function is responsible for deleting an image. 931 * 932 * Results: 933 * None. 934 * 935 * Side effects: 936 * The connection is dropped between instances of this image and an image 937 * master. Image instances will redisplay themselves as empty areas, but 938 * existing instances will not be deleted. 939 * 940 *---------------------------------------------------------------------- 941 */ 942 943static void 944DeleteImage( 945 ImageMaster *masterPtr) /* Pointer to main data structure for image. */ 946{ 947 Image *imagePtr; 948 Tk_ImageType *typePtr; 949 950 typePtr = masterPtr->typePtr; 951 masterPtr->typePtr = NULL; 952 if (typePtr != NULL) { 953 for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; 954 imagePtr = imagePtr->nextPtr) { 955 (*typePtr->freeProc)(imagePtr->instanceData, 956 imagePtr->display); 957 (*imagePtr->changeProc)(imagePtr->widgetClientData, 0, 0, 958 masterPtr->width, masterPtr->height, masterPtr->width, 959 masterPtr->height); 960 } 961 (*typePtr->deleteProc)(masterPtr->masterData); 962 } 963 if (masterPtr->instancePtr == NULL) { 964 if (masterPtr->hPtr != NULL) { 965 Tcl_DeleteHashEntry(masterPtr->hPtr); 966 } 967 Tcl_Release((ClientData) masterPtr->winPtr); 968 ckfree((char *) masterPtr); 969 } else { 970 masterPtr->deleted = 1; 971 } 972} 973 974/* 975 *---------------------------------------------------------------------- 976 * 977 * EventuallyDeleteImage -- 978 * 979 * Arrange for an image to be deleted when it is safe to do so. 980 * 981 * Results: 982 * None. 983 * 984 * Side effects: 985 * Image will get freed, though not until it is no longer Tcl_Preserve()d 986 * by anything. May be called multiple times on the same image without 987 * ill effects. 988 * 989 *---------------------------------------------------------------------- 990 */ 991 992static void 993EventuallyDeleteImage( 994 ImageMaster *masterPtr, /* Pointer to main data structure for image. */ 995 int forgetImageHashNow) /* Flag to say whether the hash table is about 996 * to vanish. */ 997{ 998 if (forgetImageHashNow) { 999 masterPtr->hPtr = NULL; 1000 } 1001 if (!masterPtr->deleted) { 1002 masterPtr->deleted = 1; 1003 Tcl_EventuallyFree((ClientData) masterPtr, 1004 (Tcl_FreeProc *)DeleteImage); 1005 } 1006} 1007 1008/* 1009 *---------------------------------------------------------------------- 1010 * 1011 * TkDeleteAllImages -- 1012 * 1013 * This function is called when an application is deleted. It calls back 1014 * all of the managers for all images so that they can cleanup, then it 1015 * deletes all of Tk's internal information about images. 1016 * 1017 * Results: 1018 * None. 1019 * 1020 * Side effects: 1021 * All information for all images gets deleted. 1022 * 1023 *---------------------------------------------------------------------- 1024 */ 1025 1026void 1027TkDeleteAllImages( 1028 TkMainInfo *mainPtr) /* Structure describing application that is 1029 * going away. */ 1030{ 1031 Tcl_HashSearch search; 1032 Tcl_HashEntry *hPtr; 1033 1034 for (hPtr = Tcl_FirstHashEntry(&mainPtr->imageTable, &search); 1035 hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { 1036 EventuallyDeleteImage((ImageMaster *) Tcl_GetHashValue(hPtr), 1); 1037 } 1038 Tcl_DeleteHashTable(&mainPtr->imageTable); 1039} 1040 1041/* 1042 *---------------------------------------------------------------------- 1043 * 1044 * Tk_GetImageMasterData -- 1045 * 1046 * Given the name of an image, this function returns the type of the 1047 * image and the clientData associated with its master. 1048 * 1049 * Results: 1050 * If there is no image by the given name, then NULL is returned and a 1051 * NULL value is stored at *typePtrPtr. Otherwise the return value is the 1052 * clientData returned by the createProc when the image was created and a 1053 * pointer to the type structure for the image is stored at *typePtrPtr. 1054 * 1055 * Side effects: 1056 * None. 1057 * 1058 *---------------------------------------------------------------------- 1059 */ 1060 1061ClientData 1062Tk_GetImageMasterData( 1063 Tcl_Interp *interp, /* Interpreter in which the image was 1064 * created. */ 1065 CONST char *name, /* Name of image. */ 1066 Tk_ImageType **typePtrPtr) /* Points to location to fill in with pointer 1067 * to type information for image. */ 1068{ 1069 Tcl_HashEntry *hPtr; 1070 TkWindow *winPtr; 1071 ImageMaster *masterPtr; 1072 1073 winPtr = (TkWindow *) Tk_MainWindow(interp); 1074 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name); 1075 if (hPtr == NULL) { 1076 *typePtrPtr = NULL; 1077 return NULL; 1078 } 1079 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr); 1080 if (masterPtr->deleted) { 1081 *typePtrPtr = NULL; 1082 return NULL; 1083 } 1084 *typePtrPtr = masterPtr->typePtr; 1085 return masterPtr->masterData; 1086} 1087 1088/* 1089 *---------------------------------------------------------------------- 1090 * 1091 * Tk_SetTSOrigin -- 1092 * 1093 * Set the pattern origin of the tile to a common point (i.e. the origin 1094 * (0,0) of the top level window) so that tiles from two different 1095 * widgets will match up. This done by setting the GCTileStipOrigin field 1096 * is set to the translated origin of the toplevel window in the 1097 * hierarchy. 1098 * 1099 * Results: 1100 * None. 1101 * 1102 * Side Effects: 1103 * The GCTileStipOrigin is reset in the GC. This will cause the tile 1104 * origin to change when the GC is used for drawing. 1105 * 1106 *---------------------------------------------------------------------- 1107 */ 1108 1109/*ARGSUSED*/ 1110void 1111Tk_SetTSOrigin( 1112 Tk_Window tkwin, 1113 GC gc, 1114 int x, int y) 1115{ 1116 while (!Tk_TopWinHierarchy(tkwin)) { 1117 x -= Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; 1118 y -= Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; 1119 tkwin = Tk_Parent(tkwin); 1120 } 1121 XSetTSOrigin(Tk_Display(tkwin), gc, x, y); 1122} 1123 1124/* 1125 * Local Variables: 1126 * mode: c 1127 * c-basic-offset: 4 1128 * fill-column: 78 1129 * End: 1130 */ 1131