static void UpdateImage( TreeDragImage dragImage /* Drag image record. */ ) { TreeCtrl *tree = dragImage->tree; Tk_PhotoHandle photoH; XImage *ximage; int width = dragImage->bounds[2] - dragImage->bounds[0]; int height = dragImage->bounds[3] - dragImage->bounds[1]; int alpha = 128; XColor *colorPtr; if (dragImage->image != NULL) { Tk_FreeImage(dragImage->image); dragImage->image = NULL; } photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); if (photoH == NULL) { Tcl_GlobalEval(tree->interp, "image create photo ::TreeCtrl::ImageDrag"); photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); if (photoH == NULL) return; } /* Pixmap -> XImage */ ximage = XGetImage(tree->display, dragImage->pixmap, 0, 0, (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); if (ximage == NULL) panic("tkTreeDrag.c:UpdateImage() ximage is NULL"); /* XImage -> Tk_Image */ colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); Tree_XImage2Photo(tree->interp, photoH, ximage, colorPtr->pixel, alpha); XDestroyImage(ximage); dragImage->image = Tk_GetImage(tree->interp, tree->tkwin, "::TreeCtrl::ImageDrag", NULL, (ClientData) NULL); }
/* * Ttk_UseImage -- * Acquire a Tk_Image from the cache. */ Tk_Image Ttk_UseImage(Ttk_ResourceCache cache, Tk_Window tkwin, Tcl_Obj *objPtr) { const char *imageName = Tcl_GetString(objPtr); int newEntry; Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry(&cache->imageTable,imageName,&newEntry); Tk_Image image; InitCacheWindow(cache, tkwin); if (!newEntry) { return Tcl_GetHashValue(entryPtr); } image = Tk_GetImage(cache->interp, tkwin, imageName, NullImageChanged,0); Tcl_SetHashValue(entryPtr, image); if (!image) { Tcl_BackgroundException(cache->interp, TCL_ERROR); } return image; }
/* TtkGetImageSpec -- * Constructs a Ttk_ImageSpec * from a Tcl_Obj *. * Result must be released using TtkFreeImageSpec. * * TODO: Need a variant of this that takes a user-specified ImageChanged proc */ Ttk_ImageSpec * TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr) { Ttk_ImageSpec *imageSpec = 0; int i = 0, n = 0, objc; Tcl_Obj **objv; imageSpec = (Ttk_ImageSpec *)ckalloc(sizeof(*imageSpec)); imageSpec->baseImage = 0; imageSpec->mapCount = 0; imageSpec->states = 0; imageSpec->images = 0; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { goto error; } if ((objc % 2) != 1) { if (interp) { Tcl_SetResult(interp, "image specification must contain an odd number of elements", TCL_STATIC); } goto error; } n = (objc - 1) / 2; imageSpec->states = (Ttk_StateSpec*)ckalloc(n * sizeof(Ttk_StateSpec)); imageSpec->images = (Tk_Image*)ckalloc(n * sizeof(Tk_Image *)); /* Get base image: */ imageSpec->baseImage = Tk_GetImage( interp, tkwin, Tcl_GetString(objv[0]), NullImageChanged, NULL); if (!imageSpec->baseImage) { goto error; } /* Extract state and image specifications: */ for (i = 0; i < n; ++i) { Tcl_Obj *stateSpec = objv[2*i + 1]; const char *imageName = Tcl_GetString(objv[2*i + 2]); Ttk_StateSpec state; if (Ttk_GetStateSpecFromObj(interp, stateSpec, &state) != TCL_OK) { goto error; } imageSpec->states[i] = state; imageSpec->images[i] = Tk_GetImage( interp, tkwin, imageName, NullImageChanged, NULL); if (imageSpec->images[i] == NULL) { goto error; } imageSpec->mapCount = i+1; } return imageSpec; error: TtkFreeImageSpec(imageSpec); return NULL; }
static int ConfigureImage( Tcl_Interp *interp, /* Used for error reporting. */ Tk_Canvas canvas, /* Canvas containing itemPtr. */ Tk_Item *itemPtr, /* Image item to reconfigure. */ int objc, /* Number of elements in objv. */ Tcl_Obj *const objv[], /* Arguments describing things to configure. */ int flags) /* Flags to pass to Tk_ConfigureWidget. */ { ImageItem *imgPtr = (ImageItem *) itemPtr; Tk_Window tkwin; Tk_Image image; tkwin = Tk_CanvasTkwin(canvas); if (TCL_OK != Tk_ConfigureWidget(interp, tkwin, configSpecs, objc, (const char **) objv, (char *) imgPtr, flags|TK_CONFIG_OBJS)) { return TCL_ERROR; } /* * Create the image. Save the old image around and don't free it until * after the new one is allocated. This keeps the reference count from * going to zero so the image doesn't have to be recreated if it hasn't * changed. */ if (imgPtr->activeImageString != NULL) { itemPtr->redraw_flags |= TK_ITEM_STATE_DEPENDANT; } else { itemPtr->redraw_flags &= ~TK_ITEM_STATE_DEPENDANT; } if (imgPtr->imageString != NULL) { image = Tk_GetImage(interp, tkwin, imgPtr->imageString, ImageChangedProc, imgPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (imgPtr->image != NULL) { Tk_FreeImage(imgPtr->image); } imgPtr->image = image; if (imgPtr->activeImageString != NULL) { image = Tk_GetImage(interp, tkwin, imgPtr->activeImageString, ImageChangedProc, imgPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (imgPtr->activeImage != NULL) { Tk_FreeImage(imgPtr->activeImage); } imgPtr->activeImage = image; if (imgPtr->disabledImageString != NULL) { image = Tk_GetImage(interp, tkwin, imgPtr->disabledImageString, ImageChangedProc, imgPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (imgPtr->disabledImage != NULL) { Tk_FreeImage(imgPtr->disabledImage); } imgPtr->disabledImage = image; ComputeImageBbox(canvas, imgPtr); return TCL_OK; }
Tk_Image HtmlImageImage(HtmlImage2 *pImage) { assert(pImage && (pImage->isValid == 1 || pImage->isValid == 0)); if (!pImage->isValid) { /* pImage->image is invalid. This happens if the underlying Tk * image, or the image that this is a scaled copy of, is changed * or deleted. It also happens the first time this function is * called after a call to HtmlImageScale(). */ Tk_PhotoHandle photo; Tk_PhotoImageBlock block; Tcl_Interp *interp = pImage->pImageServer->pTree->interp; HtmlImage2 *pUnscaled = pImage->pUnscaled; if (pUnscaled->pixmap) { Tcl_Obj *apObj[4]; int rc; /*printf("TODO: BAD. Have to recreate image to make scaled copy.\n");*/ apObj[0] = pUnscaled->pImageName; apObj[1] = Tcl_NewStringObj("configure", -1); apObj[2] = Tcl_NewStringObj("-data", -1); apObj[3] = pUnscaled->pCompressed; Tcl_IncrRefCount(apObj[1]); Tcl_IncrRefCount(apObj[2]); Tcl_IncrRefCount(apObj[3]); pUnscaled->nIgnoreChange++; rc = Tcl_EvalObjv(interp, 4, apObj, TCL_EVAL_GLOBAL); pUnscaled->nIgnoreChange--; assert(rc==TCL_OK); Tcl_IncrRefCount(apObj[3]); Tcl_DecrRefCount(apObj[2]); Tcl_DecrRefCount(apObj[1]); } assert(pUnscaled); if (!pImage->pImageName) { /* If pImageName is still NULL, then create a new photo * image to write the scaled data to. Todo: Is it possible * to do this without invoking a script, creating the Tcl * command etc.? */ Tk_Window win = pImage->pImageServer->pTree->tkwin; Tcl_Interp *interp = pImage->pImageServer->pTree->interp; const char *z; Tcl_Eval(interp, "image create photo"); pImage->pImageName = Tcl_GetObjResult(interp); Tcl_IncrRefCount(pImage->pImageName); assert(0 == pImage->pDelete); assert(0 == pImage->image); z = Tcl_GetString(pImage->pImageName); pImage->image = Tk_GetImage(interp, win, z, imageChanged, pImage); } assert(pImage->image); CHECK_INTEGER_PLAUSIBILITY(pImage->width); CHECK_INTEGER_PLAUSIBILITY(pImage->height); CHECK_INTEGER_PLAUSIBILITY(pUnscaled->width); CHECK_INTEGER_PLAUSIBILITY(pUnscaled->height); /* Write the scaled data into image pImage->image */ photo = Tk_FindPhoto(interp, Tcl_GetString(pUnscaled->pImageName)); if (photo) { Tk_PhotoGetImage(photo, &block); } if (photo && block.pixelPtr) { int x, y; /* Iterator variables */ int w, h; /* Width and height of unscaled image */ int sw, sh; /* Width and height of scaled image */ Tk_PhotoHandle s_photo; Tk_PhotoImageBlock s_block; sw = pImage->width; sh = pImage->height; w = pUnscaled->width; h = pUnscaled->height; s_photo = Tk_FindPhoto(interp, Tcl_GetString(pImage->pImageName)); s_block.pixelPtr = (unsigned char *)HtmlAlloc("temp", sw * sh * 4); s_block.width = sw; s_block.height = sh; s_block.pitch = sw * 4; s_block.pixelSize = 4; s_block.offset[0] = 0; s_block.offset[1] = 1; s_block.offset[2] = 2; s_block.offset[3] = 3; for (x=0; x<sw; x++) { int orig_x = ((x * w) / sw); for (y=0; y<sh; y++) { unsigned char *zOrig; unsigned char *zScale; int orig_y = ((y * h) / sh); zOrig = &block.pixelPtr[ orig_x * block.pixelSize + orig_y * block.pitch]; zScale = &s_block.pixelPtr[ x * s_block.pixelSize + y * s_block.pitch]; zScale[0] = zOrig[block.offset[0]]; zScale[1] = zOrig[block.offset[1]]; zScale[2] = zOrig[block.offset[2]]; zScale[3] = zOrig[block.offset[3]]; } } photoputblock(interp, s_photo, &s_block, 0, 0, sw, sh, 0); HtmlFree(s_block.pixelPtr); } else { return HtmlImageImage(pImage->pUnscaled); } pImage->isValid = 1; if (pUnscaled->pixmap) { Tcl_Obj *apObj[4]; apObj[0] = Tcl_NewStringObj("image", -1); apObj[1] = Tcl_NewStringObj("create", -1); apObj[2] = Tcl_NewStringObj("photo", -1); apObj[3] = pUnscaled->pImageName; Tcl_IncrRefCount(apObj[0]); Tcl_IncrRefCount(apObj[1]); Tcl_IncrRefCount(apObj[2]); pUnscaled->nIgnoreChange++; Tcl_EvalObjv(interp, 4, apObj, TCL_EVAL_GLOBAL); pUnscaled->nIgnoreChange--; Tcl_DecrRefCount(apObj[2]); Tcl_DecrRefCount(apObj[1]); Tcl_IncrRefCount(apObj[0]); } } return pImage->image; }
/* *--------------------------------------------------------------------------- * * HtmlImageServerGet -- * * Retrieve an HtmlImage2 object for the image at URL zUrl from * an image-server. The caller should match this call with a single * HtmlImageFree() when the image object is no longer required. * * If the image is not already in the cache, the Tcl script * configured as the widget -imagecmd is invoked. If this command * raises an error or returns an invalid result, then this function * returns NULL. A Tcl back-ground error is propagated in this case * also. * * Results: * Pointer to HtmlImage2 object containing the image from zUrl, or * NULL, if zUrl was invalid for some reason. * * Side effects: * May invoke -imagecmd script. * *--------------------------------------------------------------------------- */ HtmlImage2 * HtmlImageServerGet (HtmlImageServer *p, const char *zUrl) { Tcl_Obj *pImageCmd = p->pTree->options.imagecmd; Tcl_Interp *interp = p->pTree->interp; Tcl_HashEntry *pEntry = 0; HtmlImage2 *pImage = 0; /* Try to find the requested image in the hash table. */ if (pImageCmd) { int new_entry; pEntry = Tcl_CreateHashEntry(&p->aImage, zUrl, &new_entry); if (new_entry) { Tcl_Obj *pEval; Tcl_Obj *pResult; int rc; int nObj; Tcl_Obj **apObj = 0; Tk_Image img; /* The image could not be found in the hash table and an * -imagecmd callback is configured. The callback script * must be executed to obtain an image. Build up a script * in pEval and execute it. Put the result in variable pResult. */ pEval = Tcl_DuplicateObj(pImageCmd); Tcl_IncrRefCount(pEval); Tcl_ListObjAppendElement(interp, pEval, Tcl_NewStringObj(zUrl, -1)); rc = Tcl_EvalObjEx(interp, pEval, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pEval); if (rc != TCL_OK) { goto image_get_out; } pResult = Tcl_GetObjResult(interp); /* Read the result into array apObj. If the result was * not a valid Tcl list, return NULL and raise a background * error about the badly formed list. */ rc = Tcl_ListObjGetElements(interp, pResult, &nObj, &apObj); if (rc != TCL_OK) { goto image_get_out; } if (nObj==0) { Tcl_DeleteHashEntry(pEntry); goto image_unavailable; } pImage = HtmlNew(HtmlImage2); if (nObj == 1 || nObj == 2) { img = Tk_GetImage( interp, p->pTree->tkwin, Tcl_GetString(apObj[0]), imageChanged, pImage ); } if ((nObj != 1 && nObj != 2) || !img) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "-imagecmd returned bad value", 0); HtmlFree(pImage); pImage = 0; goto image_get_out; } Tcl_SetHashValue(pEntry, (ClientData)pImage); Tcl_IncrRefCount(apObj[0]); pImage->pImageName = apObj[0]; if (nObj == 2) { Tcl_IncrRefCount(apObj[1]); pImage->pDelete = apObj[1]; } pImage->pImageServer = p; pImage->zUrl = Tcl_GetHashKey(&p->aImage, pEntry); pImage->image = img; Tk_SizeOfImage(pImage->image, &pImage->width, &pImage->height); pImage->isValid = 1; HtmlImagePixmap(pImage); } } image_get_out: pImage = (HtmlImage2 *)(pEntry ? Tcl_GetHashValue(pEntry) : 0); HtmlImageRef(pImage); if (!pImage && pImageCmd) { Tcl_BackgroundError(interp); Tcl_ResetResult(interp); assert(pEntry); Tcl_DeleteHashEntry(pEntry); } image_unavailable: return pImage; }
/* *--------------------------------------------------------------------------- * * HtmlImageTile -- * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tk_Image HtmlImageTile( HtmlImage2 *pImage, /* Image object */ int *pW, int *pH ) { HtmlTree *pTree = pImage->pImageServer->pTree; Tcl_Interp *interp = pTree->interp; Tcl_Obj *pTileName; /* Name of tile image at the script level */ Tk_PhotoHandle tilephoto; /* Photo of tile */ Tk_PhotoImageBlock tileblock; /* Block of tile image */ int iTileWidth; int iTileHeight; Tk_PhotoHandle origphoto; Tk_PhotoImageBlock origblock; int x; int y; /* The tile has already been generated. Return it. */ if (pImage->pTileName) { goto return_tile; } /* The image is too big to bother with a tile. Return the original. */ if (!tilesize(pImage, &iTileWidth, &iTileHeight)) { goto return_original; } /* Retrieve the block for the original image */ origphoto = Tk_FindPhoto(interp, Tcl_GetString(pImage->pImageName)); if (!origphoto) goto return_original; Tk_PhotoGetImage(origphoto, &origblock); if (!origblock.pixelPtr) goto return_original; /* Create the tile image. Surely there is a way to do this without * invoking a script, but I haven't found it yet. */ Tcl_Eval(interp, "image create photo"); pTileName = Tcl_GetObjResult(interp); Tcl_IncrRefCount(pTileName); tilephoto = Tk_FindPhoto(interp, Tcl_GetString(pTileName)); Tk_PhotoGetImage(tilephoto, &tileblock); pImage->pTileName = pTileName; pImage->tile = Tk_GetImage( interp, pTree->tkwin, Tcl_GetString(pTileName), imageChanged, 0 ); /* Allocate a block to write the tile data into. */ tileblock.pixelPtr = (unsigned char *)HtmlAlloc( "temp", iTileWidth * iTileHeight * 4 ); tileblock.width = iTileWidth; tileblock.height = iTileHeight; tileblock.pitch = iTileWidth * 4; tileblock.pixelSize = 4; tileblock.offset[0] = 0; tileblock.offset[1] = 1; tileblock.offset[2] = 2; tileblock.offset[3] = 3; for (x = 0; x < iTileWidth; x++) { for (y = 0; y < iTileHeight; y++) { unsigned char *zOrig; unsigned char *zScale; zOrig = &origblock.pixelPtr[ (x % pImage->width) *origblock.pixelSize + (y % pImage->height) * origblock.pitch ]; zScale = &tileblock.pixelPtr[x * 4 + y * tileblock.pitch]; zScale[0] = zOrig[origblock.offset[0]]; zScale[1] = zOrig[origblock.offset[1]]; zScale[2] = zOrig[origblock.offset[2]]; zScale[3] = zOrig[origblock.offset[3]]; } } photoputblock(interp,tilephoto,&tileblock,0,0,iTileWidth,iTileHeight,0); HtmlFree(tileblock.pixelPtr); pImage->iTileWidth = iTileWidth; pImage->iTileHeight = iTileHeight; return_tile: *pW = pImage->iTileWidth; *pH = pImage->iTileHeight; return pImage->tile; return_original: HtmlImageSize(pImage, pW, pH); return HtmlImageImage(pImage); }
static int ConfigureMenuButton( Tcl_Interp *interp, /* Used for error reporting. */ register TkMenuButton *mbPtr, /* Information about widget; may or may not * already have values for some fields. */ int objc, /* Number of valid entries in objv. */ Tcl_Obj *const objv[]) /* Arguments. */ { Tk_SavedOptions savedOptions; Tcl_Obj *errorResult = NULL; int error; Tk_Image image; /* * Eliminate any existing trace on variables monitored by the menubutton. */ if (mbPtr->textVarName != NULL) { Tcl_UntraceVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuButtonTextVarProc, mbPtr); } /* * The following loop is potentially executed twice. During the first pass * configuration options get set to their new values. If there is an error * in this pass, we execute a second pass to restore all the options to * their previous values. */ for (error = 0; error <= 1; error++) { if (!error) { /* * First pass: set options to new values. */ if (Tk_SetOptions(interp, (char *) mbPtr, mbPtr->optionTable, objc, objv, mbPtr->tkwin, &savedOptions, NULL) != TCL_OK) { continue; } } else { /* * Second pass: restore options to old values. */ errorResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); } /* * A few options need special processing, such as setting the * background from a 3-D border, or filling in complicated defaults * that couldn't be specified to Tk_SetOptions. */ if ((mbPtr->state == STATE_ACTIVE) && !Tk_StrictMotif(mbPtr->tkwin)) { Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder); } else { Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder); } if (mbPtr->highlightWidth < 0) { mbPtr->highlightWidth = 0; } if (mbPtr->padX < 0) { mbPtr->padX = 0; } if (mbPtr->padY < 0) { mbPtr->padY = 0; } /* * Get the image for the widget, if there is one. Allocate the new * image before freeing the old one, so that the reference count * doesn't go to zero and cause image data to be discarded. */ if (mbPtr->imageString != NULL) { image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin, mbPtr->imageString, MenuButtonImageProc, mbPtr); if (image == NULL) { return TCL_ERROR; } } else { image = NULL; } if (mbPtr->image != NULL) { Tk_FreeImage(mbPtr->image); } mbPtr->image = image; /* * Recompute the geometry for the button. */ if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) { if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString, &mbPtr->width) != TCL_OK) { widthError: Tcl_AddErrorInfo(interp, "\n (processing -width option)"); continue; } if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString, &mbPtr->height) != TCL_OK) { heightError: Tcl_AddErrorInfo(interp, "\n (processing -height option)"); continue; } } else { if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width) != TCL_OK) { goto widthError; } if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height) != TCL_OK) { goto heightError; } } break; } if (!error) { Tk_FreeSavedOptions(&savedOptions); } if (mbPtr->textVarName != NULL) { /* * If no image or -compound is used, display the value of a variable. * Set up a trace to watch for any changes in it, create the variable * if it doesn't exist, and fetch its current value. */ const char *value; value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY); if (value == NULL) { Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text, TCL_GLOBAL_ONLY); } else { if (mbPtr->text != NULL) { ckfree(mbPtr->text); } mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1)); strcpy(mbPtr->text, value); } Tcl_TraceVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, MenuButtonTextVarProc, mbPtr); } TkMenuButtonWorldChanged(mbPtr); if (error) { Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } return TCL_OK; }
/* ** Given an <IMG> markup, find or create an appropriate HtmlImage ** structure and return a pointer to that structure. NULL might ** be returned. ** ** This routine may invoke a callback procedure which could delete ** the HTML widget. Use HtmlLock() if necessary to preserve the ** widget structure. */ HtmlImage *HtmlGetImage(HtmlWidget *htmlPtr, HtmlElement *p){ char *zWidth; char *zHeight; char *zSrc; const char *zImageName; HtmlImage *pImage; int result; Tcl_DString cmd; int lenSrc, lenW, lenH; /* Lengths of various strings */ if( p->base.type!=Html_IMG ){ CANT_HAPPEN; return 0; } if( htmlPtr->zGetImage==0 || htmlPtr->zGetImage[0]==0 ){ TestPoint(0); return 0; } zSrc = HtmlMarkupArg(p, "src", 0); if( zSrc==0 ){ return 0; } HtmlLock(htmlPtr); zSrc = HtmlResolveUri(htmlPtr, zSrc); if( HtmlUnlock(htmlPtr) || zSrc==0 ) return 0; zWidth = HtmlMarkupArg(p, "width", ""); zHeight = HtmlMarkupArg(p, "height", ""); for(pImage=htmlPtr->imageList; pImage; pImage=pImage->pNext){ if( strcmp(pImage->zUrl,zSrc)==0 && strcmp(pImage->zWidth, zWidth)==0 && strcmp(pImage->zHeight, zHeight)==0 ){ HtmlFree(zSrc); return pImage; } } Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, htmlPtr->zGetImage, -1); Tcl_DStringAppendElement(&cmd,zSrc); Tcl_DStringAppendElement(&cmd,zWidth); Tcl_DStringAppendElement(&cmd,zHeight); Tcl_DStringStartSublist(&cmd); HtmlAppendArglist(&cmd, p); Tcl_DStringEndSublist(&cmd); HtmlLock(htmlPtr); result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd)); Tcl_DStringFree(&cmd); if( HtmlUnlock(htmlPtr) ){ HtmlFree(zSrc); } zImageName = Tcl_GetStringResult(htmlPtr->interp); lenSrc = strlen(zSrc); lenW = strlen(zWidth); lenH = strlen(zHeight); pImage = HtmlAlloc( sizeof(HtmlImage) + lenSrc + lenW + lenH + 3 ); memset(pImage,0,sizeof(HtmlImage)); pImage->htmlPtr = htmlPtr; pImage->zUrl = (char*)&pImage[1]; strcpy(pImage->zUrl,zSrc); HtmlFree(zSrc); pImage->zWidth = &pImage->zUrl[lenSrc+1]; strcpy(pImage->zWidth, zWidth); pImage->zHeight = &pImage->zWidth[lenW+1]; strcpy(pImage->zHeight, zHeight); pImage->w = 0; pImage->h = 0; if( result==TCL_OK ){ pImage->image = Tk_GetImage(htmlPtr->interp, htmlPtr->clipwin, zImageName, ImageChangeProc, pImage); TestPoint(0); }else{ Tcl_AddErrorInfo(htmlPtr->interp, "\n (\"-imagecommand\" command executed by html widget)"); Tcl_BackgroundError(htmlPtr->interp); pImage->image = 0; TestPoint(0); } if( pImage->image==0 ){ HtmlFree((char*)pImage); TestPoint(0); return 0; } pImage->pNext = htmlPtr->imageList; htmlPtr->imageList = pImage; TestPoint(0); Tcl_ResetResult(htmlPtr->interp); return pImage; }