diff options
Diffstat (limited to 'tk8.6/generic/tkImage.c')
-rw-r--r-- | tk8.6/generic/tkImage.c | 1142 |
1 files changed, 1142 insertions, 0 deletions
diff --git a/tk8.6/generic/tkImage.c b/tk8.6/generic/tkImage.c new file mode 100644 index 0000000..359d6c6 --- /dev/null +++ b/tk8.6/generic/tkImage.c @@ -0,0 +1,1142 @@ +/* + * tkImage.c -- + * + * This module implements the image protocol, which allows lots of + * different kinds of images to be used in lots of different widgets. + * + * Copyright (c) 1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tkInt.h" + +/* + * Each call to Tk_GetImage returns a pointer to one of the following + * structures, which is used as a token by clients (widgets) that display + * images. + */ + +typedef struct Image { + Tk_Window tkwin; /* Window passed to Tk_GetImage (needed to + * "re-get" the image later if the manager + * changes). */ + Display *display; /* Display for tkwin. Needed because when the + * image is eventually freed tkwin may not + * exist anymore. */ + struct ImageMaster *masterPtr; + /* Master for this image (identifiers image + * manager, for example). */ + ClientData instanceData; /* One word argument to pass to image manager + * when dealing with this image instance. */ + Tk_ImageChangedProc *changeProc; + /* Code in widget to call when image changes + * in a way that affects redisplay. */ + ClientData widgetClientData;/* Argument to pass to changeProc. */ + struct Image *nextPtr; /* Next in list of all image instances + * associated with the same name. */ +} Image; + +/* + * For each image master there is one of the following structures, which + * represents a name in the image table and all of the images instantiated + * from it. Entries in mainPtr->imageTable point to these structures. + */ + +typedef struct ImageMaster { + Tk_ImageType *typePtr; /* Information about image type. NULL means + * that no image manager owns this image: the + * image was deleted. */ + ClientData masterData; /* One-word argument to pass to image mgr when + * dealing with the master, as opposed to + * instances. */ + int width, height; /* Last known dimensions for image. */ + Tcl_HashTable *tablePtr; /* Pointer to hash table containing image (the + * imageTable field in some TkMainInfo + * structure). */ + Tcl_HashEntry *hPtr; /* Hash entry in mainPtr->imageTable for this + * structure (used to delete the hash + * entry). */ + Image *instancePtr; /* Pointer to first in list of instances + * derived from this name. */ + int deleted; /* Flag set when image is being deleted. */ + TkWindow *winPtr; /* Main window of interpreter (used to detect + * when the world is falling apart.) */ +} ImageMaster; + +typedef struct ThreadSpecificData { + Tk_ImageType *imageTypeList;/* First in a list of all known image + * types. */ + Tk_ImageType *oldImageTypeList; + /* First in a list of all known old-style + * image types. */ + int initialized; /* Set to 1 if we've initialized the + * structure. */ +} ThreadSpecificData; +static Tcl_ThreadDataKey dataKey; + +/* + * Prototypes for local functions: + */ + +static void ImageTypeThreadExitProc(ClientData clientData); +static void DeleteImage(ImageMaster *masterPtr); +static void EventuallyDeleteImage(ImageMaster *masterPtr, + int forgetImageHashNow); + +/* + *---------------------------------------------------------------------- + * + * ImageTypeThreadExitProc -- + * + * Clean up the registered list of image types. + * + * Results: + * None. + * + * Side effects: + * The thread's linked lists of photo image formats is deleted. + * + *---------------------------------------------------------------------- + */ + +static void +ImageTypeThreadExitProc( + ClientData clientData) /* not used */ +{ + Tk_ImageType *freePtr; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + while (tsdPtr->oldImageTypeList != NULL) { + freePtr = tsdPtr->oldImageTypeList; + tsdPtr->oldImageTypeList = tsdPtr->oldImageTypeList->nextPtr; + ckfree(freePtr); + } + while (tsdPtr->imageTypeList != NULL) { + freePtr = tsdPtr->imageTypeList; + tsdPtr->imageTypeList = tsdPtr->imageTypeList->nextPtr; + ckfree(freePtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CreateOldImageType, Tk_CreateImageType -- + * + * This function is invoked by an image manager to tell Tk about a new + * kind of image and the functions that manage the new type. The function + * is typically invoked during Tcl_AppInit. + * + * Results: + * None. + * + * Side effects: + * The new image type is entered into a table used in the "image create" + * command. + * + *---------------------------------------------------------------------- + */ + +void +Tk_CreateOldImageType( + const Tk_ImageType *typePtr) + /* Structure describing the type. All of the + * fields except "nextPtr" must be filled in + * by caller. */ +{ + Tk_ImageType *copyPtr; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (!tsdPtr->initialized) { + tsdPtr->initialized = 1; + Tcl_CreateThreadExitHandler(ImageTypeThreadExitProc, NULL); + } + copyPtr = ckalloc(sizeof(Tk_ImageType)); + *copyPtr = *typePtr; + copyPtr->nextPtr = tsdPtr->oldImageTypeList; + tsdPtr->oldImageTypeList = copyPtr; +} + +void +Tk_CreateImageType( + const Tk_ImageType *typePtr) + /* Structure describing the type. All of the + * fields except "nextPtr" must be filled in + * by caller. */ +{ + Tk_ImageType *copyPtr; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (!tsdPtr->initialized) { + tsdPtr->initialized = 1; + Tcl_CreateThreadExitHandler(ImageTypeThreadExitProc, NULL); + } + copyPtr = ckalloc(sizeof(Tk_ImageType)); + *copyPtr = *typePtr; + copyPtr->nextPtr = tsdPtr->imageTypeList; + tsdPtr->imageTypeList = copyPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_ImageObjCmd -- + * + * This function is invoked to process the "image" Tcl command. See the + * user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +Tk_ImageObjCmd( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument strings. */ +{ + static const char *const imageOptions[] = { + "create", "delete", "height", "inuse", "names", "type", "types", + "width", NULL + }; + enum options { + IMAGE_CREATE, IMAGE_DELETE, IMAGE_HEIGHT, IMAGE_INUSE, IMAGE_NAMES, + IMAGE_TYPE, IMAGE_TYPES, IMAGE_WIDTH + }; + TkWindow *winPtr = clientData; + int i, isNew, firstOption, index; + Tk_ImageType *typePtr; + ImageMaster *masterPtr; + Image *imagePtr; + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + char idString[16 + TCL_INTEGER_SPACE]; + TkDisplay *dispPtr = winPtr->dispPtr; + const char *arg, *name; + Tcl_Obj *resultObj; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?args?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObjStruct(interp, objv[1], imageOptions, + sizeof(char *), "option", 0, &index) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum options) index) { + case IMAGE_CREATE: { + Tcl_Obj **args; + int oldimage = 0; + + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, + "type ?name? ?-option value ...?"); + return TCL_ERROR; + } + + /* + * Look up the image type. + */ + + arg = Tcl_GetString(objv[2]); + for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + if ((*arg == typePtr->name[0]) + && (strcmp(arg, typePtr->name) == 0)) { + break; + } + } + if (typePtr == NULL) { + oldimage = 1; + for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + if ((*arg == typePtr->name[0]) + && (strcmp(arg, typePtr->name) == 0)) { + break; + } + } + } + if (typePtr == NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "image type \"%s\" doesn't exist", arg)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "IMAGE_TYPE", arg, NULL); + return TCL_ERROR; + } + + /* + * Figure out a name to use for the new image. + */ + + if ((objc == 3) || (*(arg = Tcl_GetString(objv[3])) == '-')) { + do { + dispPtr->imageId++; + sprintf(idString, "image%d", dispPtr->imageId); + name = idString; + } while (Tcl_FindCommand(interp, name, NULL, 0) != NULL); + firstOption = 3; + } else { + TkWindow *topWin; + + name = arg; + firstOption = 4; + + /* + * Need to check if the _command_ that we are about to create is + * the name of the current master widget command (normally "." but + * could have been renamed) and fail in that case before a really + * nasty and hard to stop crash happens. + */ + + topWin = (TkWindow *) TkToplevelWindowForCommand(interp, name); + if (topWin != NULL && winPtr->mainPtr->winPtr == topWin) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "images may not be named the same as the main window", + -1)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "SMASH_MAIN", NULL); + return TCL_ERROR; + } + } + + /* + * Create the data structure for the new image. + */ + + hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable, name, &isNew); + if (isNew) { + masterPtr = ckalloc(sizeof(ImageMaster)); + masterPtr->typePtr = NULL; + masterPtr->masterData = NULL; + masterPtr->width = masterPtr->height = 1; + masterPtr->tablePtr = &winPtr->mainPtr->imageTable; + masterPtr->hPtr = hPtr; + masterPtr->instancePtr = NULL; + masterPtr->deleted = 0; + masterPtr->winPtr = winPtr->mainPtr->winPtr; + Tcl_Preserve(masterPtr->winPtr); + Tcl_SetHashValue(hPtr, masterPtr); + } else { + /* + * An image already exists by this name. Disconnect the instances + * from the master. + */ + + masterPtr = Tcl_GetHashValue(hPtr); + if (masterPtr->typePtr != NULL) { + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + masterPtr->typePtr->freeProc(imagePtr->instanceData, + imagePtr->display); + imagePtr->changeProc(imagePtr->widgetClientData, 0, 0, + masterPtr->width, masterPtr->height, + masterPtr->width, masterPtr->height); + } + masterPtr->typePtr->deleteProc(masterPtr->masterData); + masterPtr->typePtr = NULL; + } + masterPtr->deleted = 0; + } + + /* + * Call the image type manager so that it can perform its own + * initialization, then re-"get" for any existing instances of the + * image. + */ + + objv += firstOption; + objc -= firstOption; + args = (Tcl_Obj **) objv; + if (oldimage) { + int i; + + args = ckalloc((objc+1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + args[i] = (Tcl_Obj *) Tcl_GetString(objv[i]); + } + args[objc] = NULL; + } + Tcl_Preserve(masterPtr); + if (typePtr->createProc(interp, name, objc, args, typePtr, + (Tk_ImageMaster)masterPtr, &masterPtr->masterData) != TCL_OK){ + EventuallyDeleteImage(masterPtr, 0); + Tcl_Release(masterPtr); + if (oldimage) { + ckfree(args); + } + return TCL_ERROR; + } + Tcl_Release(masterPtr); + if (oldimage) { + ckfree(args); + } + masterPtr->typePtr = typePtr; + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + imagePtr->instanceData = typePtr->getProc(imagePtr->tkwin, + masterPtr->masterData); + } + Tcl_SetObjResult(interp, Tcl_NewStringObj( + Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), -1)); + break; + } + case IMAGE_DELETE: + for (i = 2; i < objc; i++) { + arg = Tcl_GetString(objv[i]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + goto alreadyDeleted; + } + masterPtr = Tcl_GetHashValue(hPtr); + if (masterPtr->deleted) { + goto alreadyDeleted; + } + DeleteImage(masterPtr); + } + break; + case IMAGE_NAMES: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search); + resultObj = Tcl_NewObj(); + for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + masterPtr = Tcl_GetHashValue(hPtr); + if (masterPtr->deleted) { + continue; + } + Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( + Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr), -1)); + } + Tcl_SetObjResult(interp, resultObj); + break; + case IMAGE_TYPES: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } + resultObj = Tcl_NewObj(); + for (typePtr = tsdPtr->imageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( + typePtr->name, -1)); + } + for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL; + typePtr = typePtr->nextPtr) { + Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( + typePtr->name, -1)); + } + Tcl_SetObjResult(interp, resultObj); + break; + + case IMAGE_HEIGHT: + case IMAGE_INUSE: + case IMAGE_TYPE: + case IMAGE_WIDTH: + /* + * These operations all parse virtually identically. First check to + * see if three args are given. Then get a non-deleted master from the + * third arg. + */ + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "name"); + return TCL_ERROR; + } + + arg = Tcl_GetString(objv[2]); + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg); + if (hPtr == NULL) { + goto alreadyDeleted; + } + masterPtr = Tcl_GetHashValue(hPtr); + if (masterPtr->deleted) { + goto alreadyDeleted; + } + + /* + * Now we read off the specific piece of data we were asked for. + */ + + switch ((enum options) index) { + case IMAGE_HEIGHT: + Tcl_SetObjResult(interp, Tcl_NewIntObj(masterPtr->height)); + break; + case IMAGE_INUSE: + Tcl_SetObjResult(interp, Tcl_NewBooleanObj( + masterPtr->typePtr && masterPtr->instancePtr)); + break; + case IMAGE_TYPE: + if (masterPtr->typePtr != NULL) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj(masterPtr->typePtr->name, -1)); + } + break; + case IMAGE_WIDTH: + Tcl_SetObjResult(interp, Tcl_NewIntObj(masterPtr->width)); + break; + default: + Tcl_Panic("can't happen"); + } + break; + } + return TCL_OK; + + alreadyDeleted: + Tcl_SetObjResult(interp, Tcl_ObjPrintf("image \"%s\" doesn't exist",arg)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "IMAGE", arg, NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_ImageChanged -- + * + * This function is called by an image manager whenever something has + * happened that requires the image to be redrawn (some of its pixels + * have changed, or its size has changed). + * + * Results: + * None. + * + * Side effects: + * Any widgets that display the image are notified so that they can + * redisplay themselves as appropriate. + * + *---------------------------------------------------------------------- + */ + +void +Tk_ImageChanged( + Tk_ImageMaster imageMaster, /* Image that needs redisplay. */ + int x, int y, /* Coordinates of upper-left pixel of region + * of image that needs to be redrawn. */ + int width, int height, /* Dimensions (in pixels) of region of image + * to redraw. If either dimension is zero then + * the image doesn't need to be redrawn + * (perhaps all that happened is that its size + * changed). */ + int imageWidth, int imageHeight) + /* New dimensions of image. */ +{ + ImageMaster *masterPtr = (ImageMaster *) imageMaster; + Image *imagePtr; + + masterPtr->width = imageWidth; + masterPtr->height = imageHeight; + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + imagePtr->changeProc(imagePtr->widgetClientData, x, y, width, height, + imageWidth, imageHeight); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_NameOfImage -- + * + * Given a token for an image master, this function returns the name of + * the image. + * + * Results: + * The return value is the string name for imageMaster. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +const char * +Tk_NameOfImage( + Tk_ImageMaster imageMaster) /* Token for image. */ +{ + ImageMaster *masterPtr = (ImageMaster *) imageMaster; + + if (masterPtr->hPtr == NULL) { + return NULL; + } + return Tcl_GetHashKey(masterPtr->tablePtr, masterPtr->hPtr); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetImage -- + * + * This function is invoked by a widget when it wants to use a particular + * image in a particular window. + * + * Results: + * The return value is a token for the image. If there is no image by the + * given name, then NULL is returned and an error message is left in the + * interp's result. + * + * Side effects: + * Tk records the fact that the widget is using the image, and it will + * invoke changeProc later if the widget needs redisplay (i.e. its size + * changes or some of its pixels change). The caller must eventually + * invoke Tk_FreeImage when it no longer needs the image. + * + *---------------------------------------------------------------------- + */ + +Tk_Image +Tk_GetImage( + Tcl_Interp *interp, /* Place to leave error message if image can't + * be found. */ + Tk_Window tkwin, /* Token for window in which image will be + * used. */ + const char *name, /* Name of desired image. */ + Tk_ImageChangedProc *changeProc, + /* Function to invoke when redisplay is needed + * because image's pixels or size changed. */ + ClientData clientData) /* One-word argument to pass to damageProc. */ +{ + Tcl_HashEntry *hPtr; + ImageMaster *masterPtr; + Image *imagePtr; + + hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->imageTable, name); + if (hPtr == NULL) { + goto noSuchImage; + } + masterPtr = Tcl_GetHashValue(hPtr); + if (masterPtr->typePtr == NULL) { + goto noSuchImage; + } + if (masterPtr->deleted) { + goto noSuchImage; + } + imagePtr = ckalloc(sizeof(Image)); + imagePtr->tkwin = tkwin; + imagePtr->display = Tk_Display(tkwin); + imagePtr->masterPtr = masterPtr; + imagePtr->instanceData = + masterPtr->typePtr->getProc(tkwin, masterPtr->masterData); + imagePtr->changeProc = changeProc; + imagePtr->widgetClientData = clientData; + imagePtr->nextPtr = masterPtr->instancePtr; + masterPtr->instancePtr = imagePtr; + return (Tk_Image) imagePtr; + + noSuchImage: + if (interp) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "image \"%s\" doesn't exist", name)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "IMAGE", name, NULL); + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeImage -- + * + * This function is invoked by a widget when it no longer needs an image + * acquired by a previous call to Tk_GetImage. For each call to + * Tk_GetImage there must be exactly one call to Tk_FreeImage. + * + * Results: + * None. + * + * Side effects: + * The association between the image and the widget is removed. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreeImage( + Tk_Image image) /* Token for image that is no longer needed by + * a widget. */ +{ + Image *imagePtr = (Image *) image; + ImageMaster *masterPtr = imagePtr->masterPtr; + Image *prevPtr; + + /* + * Clean up the particular instance. + */ + + if (masterPtr->typePtr != NULL) { + masterPtr->typePtr->freeProc(imagePtr->instanceData, + imagePtr->display); + } + prevPtr = masterPtr->instancePtr; + if (prevPtr == imagePtr) { + masterPtr->instancePtr = imagePtr->nextPtr; + } else { + while (prevPtr->nextPtr != imagePtr) { + prevPtr = prevPtr->nextPtr; + } + prevPtr->nextPtr = imagePtr->nextPtr; + } + ckfree(imagePtr); + + /* + * If there are no more instances left for the master, and if the master + * image has been deleted, then delete the master too. + */ + + if ((masterPtr->typePtr == NULL) && (masterPtr->instancePtr == NULL)) { + if (masterPtr->hPtr != NULL) { + Tcl_DeleteHashEntry(masterPtr->hPtr); + } + Tcl_Release(masterPtr->winPtr); + ckfree(masterPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_PostscriptImage -- + * + * This function is called by widgets that contain images in order to + * redisplay an image on the screen or an off-screen pixmap. + * + * Results: + * None. + * + * Side effects: + * The image's manager is notified, and it redraws the desired portion of + * the image before returning. + * + *---------------------------------------------------------------------- + */ + +int +Tk_PostscriptImage( + Tk_Image image, /* Token for image to redisplay. */ + Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo psinfo, /* postscript info */ + int x, int y, /* Upper-left pixel of region in image that + * needs to be redisplayed. */ + int width, int height, /* Dimensions of region to redraw. */ + int prepass) +{ + Image *imagePtr = (Image *) image; + int result; + XImage *ximage; + Pixmap pmap; + GC newGC; + XGCValues gcValues; + + if (imagePtr->masterPtr->typePtr == NULL) { + /* + * No master for image, so nothing to display on postscript. + */ + + return TCL_OK; + } + + /* + * Check if an image specific postscript-generation function exists; + * otherwise go on with generic code. + */ + + if (imagePtr->masterPtr->typePtr->postscriptProc != NULL) { + return imagePtr->masterPtr->typePtr->postscriptProc( + imagePtr->masterPtr->masterData, interp, tkwin, psinfo, + x, y, width, height, prepass); + } + + if (prepass) { + return TCL_OK; + } + + /* + * Create a Pixmap, tell the image to redraw itself there, and then + * generate an XImage from the Pixmap. We can then read pixel values out + * of the XImage. + */ + + pmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), width, height, + Tk_Depth(tkwin)); + + gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); + newGC = Tk_GetGC(tkwin, GCForeground, &gcValues); + if (newGC != None) { + XFillRectangle(Tk_Display(tkwin), pmap, newGC, 0, 0, + (unsigned) width, (unsigned) height); + Tk_FreeGC(Tk_Display(tkwin), newGC); + } + + Tk_RedrawImage(image, x, y, width, height, pmap, 0, 0); + + ximage = XGetImage(Tk_Display(tkwin), pmap, 0, 0, + (unsigned) width, (unsigned) height, AllPlanes, ZPixmap); + + Tk_FreePixmap(Tk_Display(tkwin), pmap); + + if (ximage == NULL) { + /* + * The XGetImage() function is apparently not implemented on this + * system. Just ignore it. + */ + + return TCL_OK; + } + result = TkPostscriptImage(interp, tkwin, psinfo, ximage, x, y, + width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_RedrawImage -- + * + * This function is called by widgets that contain images in order to + * redisplay an image on the screen or an off-screen pixmap. + * + * Results: + * None. + * + * Side effects: + * The image's manager is notified, and it redraws the desired portion of + * the image before returning. + * + *---------------------------------------------------------------------- + */ + +void +Tk_RedrawImage( + Tk_Image image, /* Token for image to redisplay. */ + int imageX, int imageY, /* Upper-left pixel of region in image that + * needs to be redisplayed. */ + int width, int height, /* Dimensions of region to redraw. */ + Drawable drawable, /* Drawable in which to display image (window + * or pixmap). If this is a pixmap, it must + * have the same depth as the window used in + * the Tk_GetImage call for the image. */ + int drawableX, int drawableY) + /* Coordinates in drawable that correspond to + * imageX and imageY. */ +{ + Image *imagePtr = (Image *) image; + + if (imagePtr->masterPtr->typePtr == NULL) { + /* + * No master for image, so nothing to display. + */ + + return; + } + + /* + * Clip the redraw area to the area of the image. + */ + + if (imageX < 0) { + width += imageX; + drawableX -= imageX; + imageX = 0; + } + if (imageY < 0) { + height += imageY; + drawableY -= imageY; + imageY = 0; + } + if ((imageX + width) > imagePtr->masterPtr->width) { + width = imagePtr->masterPtr->width - imageX; + } + if ((imageY + height) > imagePtr->masterPtr->height) { + height = imagePtr->masterPtr->height - imageY; + } + imagePtr->masterPtr->typePtr->displayProc(imagePtr->instanceData, + imagePtr->display, drawable, imageX, imageY, width, height, + drawableX, drawableY); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_SizeOfImage -- + * + * This function returns the current dimensions of an image. + * + * Results: + * The width and height of the image are returned in *widthPtr and + * *heightPtr. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_SizeOfImage( + Tk_Image image, /* Token for image whose size is wanted. */ + int *widthPtr, /* Return width of image here. */ + int *heightPtr) /* Return height of image here. */ +{ + Image *imagePtr = (Image *) image; + + *widthPtr = imagePtr->masterPtr->width; + *heightPtr = imagePtr->masterPtr->height; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_DeleteImage -- + * + * Given the name of an image, this function destroys the image. + * + * Results: + * None. + * + * Side effects: + * The image is destroyed; existing instances will display as blank + * areas. If no such image exists then the function does nothing. + * + *---------------------------------------------------------------------- + */ + +void +Tk_DeleteImage( + Tcl_Interp *interp, /* Interpreter in which the image was + * created. */ + const char *name) /* Name of image. */ +{ + Tcl_HashEntry *hPtr; + TkWindow *winPtr; + + winPtr = (TkWindow *) Tk_MainWindow(interp); + if (winPtr == NULL) { + return; + } + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name); + if (hPtr == NULL) { + return; + } + DeleteImage(Tcl_GetHashValue(hPtr)); +} + +/* + *---------------------------------------------------------------------- + * + * DeleteImage -- + * + * This function is responsible for deleting an image. + * + * Results: + * None. + * + * Side effects: + * The connection is dropped between instances of this image and an image + * master. Image instances will redisplay themselves as empty areas, but + * existing instances will not be deleted. + * + *---------------------------------------------------------------------- + */ + +static void +DeleteImage( + ImageMaster *masterPtr) /* Pointer to main data structure for image. */ +{ + Image *imagePtr; + Tk_ImageType *typePtr; + + typePtr = masterPtr->typePtr; + masterPtr->typePtr = NULL; + if (typePtr != NULL) { + for (imagePtr = masterPtr->instancePtr; imagePtr != NULL; + imagePtr = imagePtr->nextPtr) { + typePtr->freeProc(imagePtr->instanceData, imagePtr->display); + imagePtr->changeProc(imagePtr->widgetClientData, 0, 0, + masterPtr->width, masterPtr->height, masterPtr->width, + masterPtr->height); + } + typePtr->deleteProc(masterPtr->masterData); + } + if (masterPtr->instancePtr == NULL) { + if (masterPtr->hPtr != NULL) { + Tcl_DeleteHashEntry(masterPtr->hPtr); + } + Tcl_Release(masterPtr->winPtr); + ckfree(masterPtr); + } else { + masterPtr->deleted = 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * EventuallyDeleteImage -- + * + * Arrange for an image to be deleted when it is safe to do so. + * + * Results: + * None. + * + * Side effects: + * Image will get freed, though not until it is no longer Tcl_Preserve()d + * by anything. May be called multiple times on the same image without + * ill effects. + * + *---------------------------------------------------------------------- + */ + +static void +EventuallyDeleteImage( + ImageMaster *masterPtr, /* Pointer to main data structure for image. */ + int forgetImageHashNow) /* Flag to say whether the hash table is about + * to vanish. */ +{ + if (forgetImageHashNow) { + masterPtr->hPtr = NULL; + } + if (!masterPtr->deleted) { + masterPtr->deleted = 1; + Tcl_EventuallyFree(masterPtr, (Tcl_FreeProc *) DeleteImage); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkDeleteAllImages -- + * + * This function is called when an application is deleted. It calls back + * all of the managers for all images so that they can cleanup, then it + * deletes all of Tk's internal information about images. + * + * Results: + * None. + * + * Side effects: + * All information for all images gets deleted. + * + *---------------------------------------------------------------------- + */ + +void +TkDeleteAllImages( + TkMainInfo *mainPtr) /* Structure describing application that is + * going away. */ +{ + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + + for (hPtr = Tcl_FirstHashEntry(&mainPtr->imageTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + EventuallyDeleteImage(Tcl_GetHashValue(hPtr), 1); + } + Tcl_DeleteHashTable(&mainPtr->imageTable); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetImageMasterData -- + * + * Given the name of an image, this function returns the type of the + * image and the clientData associated with its master. + * + * Results: + * If there is no image by the given name, then NULL is returned and a + * NULL value is stored at *typePtrPtr. Otherwise the return value is the + * clientData returned by the createProc when the image was created and a + * pointer to the type structure for the image is stored at *typePtrPtr. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +ClientData +Tk_GetImageMasterData( + Tcl_Interp *interp, /* Interpreter in which the image was + * created. */ + const char *name, /* Name of image. */ + const Tk_ImageType **typePtrPtr) + /* Points to location to fill in with pointer + * to type information for image. */ +{ + TkWindow *winPtr = (TkWindow *) Tk_MainWindow(interp); + Tcl_HashEntry *hPtr; + ImageMaster *masterPtr; + + hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name); + if (hPtr == NULL) { + *typePtrPtr = NULL; + return NULL; + } + masterPtr = Tcl_GetHashValue(hPtr); + if (masterPtr->deleted) { + *typePtrPtr = NULL; + return NULL; + } + *typePtrPtr = masterPtr->typePtr; + return masterPtr->masterData; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_SetTSOrigin -- + * + * Set the pattern origin of the tile to a common point (i.e. the origin + * (0,0) of the top level window) so that tiles from two different + * widgets will match up. This done by setting the GCTileStipOrigin field + * is set to the translated origin of the toplevel window in the + * hierarchy. + * + * Results: + * None. + * + * Side Effects: + * The GCTileStipOrigin is reset in the GC. This will cause the tile + * origin to change when the GC is used for drawing. + * + *---------------------------------------------------------------------- + */ + +/*ARGSUSED*/ +void +Tk_SetTSOrigin( + Tk_Window tkwin, + GC gc, + int x, int y) +{ + while (!Tk_TopWinHierarchy(tkwin)) { + x -= Tk_X(tkwin) + Tk_Changes(tkwin)->border_width; + y -= Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width; + tkwin = Tk_Parent(tkwin); + } + XSetTSOrigin(Tk_Display(tkwin), gc, x, y); +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |