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