/* * tkBitmap.c -- * * This file maintains a database of read-only bitmaps for the Tk * toolkit. This allows bitmaps to be shared between widgets and * also avoids interactions with the X server. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tkBitmap.c,v 1.10 2002/08/05 04:30:38 dgp Exp $ */ #include "tkPort.h" #include "tkInt.h" /* * The includes below are for pre-defined bitmaps. * * Platform-specific issue: Windows complains when the bitmaps are * included, because an array of characters is being initialized with * integers as elements. For lint purposes, the following pragmas * temporarily turn off that warning message. */ #if defined(__WIN32__) || defined(_WIN32) #pragma warning (disable : 4305) #endif #include "error.bmp" #include "gray12.bmp" #include "gray25.bmp" #include "gray50.bmp" #include "gray75.bmp" #include "hourglass.bmp" #include "info.bmp" #include "questhead.bmp" #include "question.bmp" #include "warning.bmp" #if defined(__WIN32__) || defined(_WIN32) #pragma warning (default : 4305) #endif /* * One of the following data structures exists for each bitmap that is * currently in use. Each structure is indexed with both "idTable" and * "nameTable". */ typedef struct TkBitmap { Pixmap bitmap; /* X identifier for bitmap. None means this * bitmap was created by Tk_DefineBitmap * and it isn't currently in use. */ int width, height; /* Dimensions of bitmap. */ Display *display; /* Display for which bitmap is valid. */ int screenNum; /* Screen on which bitmap is valid */ int resourceRefCount; /* Number of active uses of this bitmap (each * active use corresponds to a call to * Tk_AllocBitmapFromObj or Tk_GetBitmap). * If this count is 0, then this TkBitmap * structure is no longer valid and it isn't * present in nameTable: it is being kept * around only because there are objects * referring to it. The structure is freed * when resourceRefCount and objRefCount * are both 0. */ int objRefCount; /* Number of Tcl_Obj's that reference * this structure. */ Tcl_HashEntry *nameHashPtr; /* Entry in nameTable for this structure * (needed when deleting). */ Tcl_HashEntry *idHashPtr; /* Entry in idTable for this structure * (needed when deleting). */ struct TkBitmap *nextPtr; /* Points to the next TkBitmap structure with * the same name. All bitmaps with the * same name (but different displays or * screens) are chained together off a * single entry in nameTable. */ } TkBitmap; /* * Used in bitmapDataTable, stored in the TkDisplay structure, to map * between in-core data about a bitmap to its TkBitmap structure. */ typedef struct { CONST char *source; /* Bitmap bits. */ int width, height; /* Dimensions of bitmap. */ } DataKey; typedef struct ThreadSpecificData { int initialized; /* 0 means table below needs initializing. */ Tcl_HashTable predefBitmapTable; /* Hash table created by Tk_DefineBitmap * to map from a name to a collection * of in-core data about a bitmap. The * table is indexed by the address of the * data for the bitmap, and the entries * contain pointers to TkPredefBitmap * structures. */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; /* * Forward declarations for procedures defined in this file: */ static void BitmapInit _ANSI_ARGS_((TkDisplay *dispPtr)); static void DupBitmapObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr, Tcl_Obj *dupObjPtr)); static void FreeBitmap _ANSI_ARGS_((TkBitmap *bitmapPtr)); static void FreeBitmapObjProc _ANSI_ARGS_((Tcl_Obj *objPtr)); static TkBitmap * GetBitmap _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window tkwin, CONST char *name)); static TkBitmap * GetBitmapFromObj _ANSI_ARGS_((Tk_Window tkwin, Tcl_Obj *objPtr)); static void InitBitmapObj _ANSI_ARGS_((Tcl_Obj *objPtr)); /* * The following structure defines the implementation of the "bitmap" Tcl * object, which maps a string bitmap name to a TkBitmap object. The * ptr1 field of the Tcl_Obj points to a TkBitmap object. */ Tcl_ObjType tkBitmapObjType = { "bitmap", /* name */ FreeBitmapObjProc, /* freeIntRepProc */ DupBitmapObjProc, /* dupIntRepProc */ NULL, /* updateStringProc */ NULL /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * Tk_AllocBitmapFromObj -- * * Given a Tcl_Obj *, map the value to a corresponding * Pixmap structure based on the tkwin given. * * Results: * The return value is the X identifer for the desired bitmap * (i.e. a Pixmap with a single plane), unless string couldn't be * parsed correctly. In this case, None is returned and an error * message is left in the interp's result. The caller should never * modify the bitmap that is returned, and should eventually call * Tk_FreeBitmapFromObj when the bitmap is no longer needed. * * Side effects: * The bitmap is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeBitmapFromObj, so that the database can be cleaned up * when bitmaps aren't needed anymore. * *---------------------------------------------------------------------- */ Pixmap Tk_AllocBitmapFromObj(interp, tkwin, objPtr) Tcl_Interp *interp; /* Interp for error results. This may * be NULL. */ Tk_Window tkwin; /* Need the screen the bitmap is used on.*/ Tcl_Obj *objPtr; /* Object describing bitmap; see manual * entry for legal syntax of string value. */ { TkBitmap *bitmapPtr; if (objPtr->typePtr != &tkBitmapObjType) { InitBitmapObj(objPtr); } bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1; /* * If the object currently points to a TkBitmap, see if it's the * one we want. If so, increment its reference count and return. */ if (bitmapPtr != NULL) { if (bitmapPtr->resourceRefCount == 0) { /* * This is a stale reference: it refers to a TkBitmap that's * no longer in use. Clear the reference. */ FreeBitmapObjProc(objPtr); bitmapPtr = NULL; } else if ( (Tk_Display(tkwin) == bitmapPtr->display) && (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum) ) { bitmapPtr->resourceRefCount++; return bitmapPtr->bitmap; } } /* * The object didn't point to the TkBitmap that we wanted. Search * the list of TkBitmaps with the same name to see if one of the * others is the right one. */ if (bitmapPtr != NULL) { TkBitmap *firstBitmapPtr = (TkBitmap *) Tcl_GetHashValue(bitmapPtr->nameHashPtr); FreeBitmapObjProc(objPtr); for (bitmapPtr = firstBitmapPtr; bitmapPtr != NULL; bitmapPtr = bitmapPtr->nextPtr) { if ( (Tk_Display(tkwin) == bitmapPtr->display) && (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum) ) { bitmapPtr->resourceRefCount++; bitmapPtr->objRefCount++; objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; return bitmapPtr->bitmap; } } } /* * Still no luck. Call GetBitmap to allocate a new TkBitmap object. */ bitmapPtr = GetBitmap(interp, tkwin, Tcl_GetString(objPtr)); objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; if (bitmapPtr == NULL) { return None; } bitmapPtr->objRefCount++; return bitmapPtr->bitmap; } /* *---------------------------------------------------------------------- * * Tk_GetBitmap -- * * Given a string describing a bitmap, locate (or create if necessary) * a bitmap that fits the description. * * Results: * The return value is the X identifer for the desired bitmap * (i.e. a Pixmap with a single plane), unless string couldn't be * parsed correctly. In this case, None is returned and an error * message is left in the interp's result. The caller should never * modify the bitmap that is returned, and should eventually call * Tk_FreeBitmap when the bitmap is no longer needed. * * Side effects: * The bitmap is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps * aren't needed anymore. * *---------------------------------------------------------------------- */ Pixmap Tk_GetBitmap(interp, tkwin, string) Tcl_Interp *interp; /* Interpreter to use for error reporting, * this may be NULL. */ Tk_Window tkwin; /* Window in which bitmap will be used. */ CONST char *string; /* Description of bitmap. See manual entry * for details on legal syntax. */ { TkBitmap *bitmapPtr = GetBitmap(interp, tkwin, string); if (bitmapPtr == NULL) { return None; } return bitmapPtr->bitmap; } /* *---------------------------------------------------------------------- * * GetBitmap -- * * Given a string describing a bitmap, locate (or create if necessary) * a bitmap that fits the description. This routine returns the * internal data structure for the bitmap. This avoids extra * hash table lookups in Tk_AllocBitmapFromObj. * * Results: * The return value is the X identifer for the desired bitmap * (i.e. a Pixmap with a single plane), unless string couldn't be * parsed correctly. In this case, None is returned and an error * message is left in the interp's result. The caller should never * modify the bitmap that is returned, and should eventually call * Tk_FreeBitmap when the bitmap is no longer needed. * * Side effects: * The bitmap is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeBitmap or Tk_FreeBitmapFromObj, so that the database can * be cleaned up when bitmaps aren't needed anymore. * *---------------------------------------------------------------------- */ static TkBitmap * GetBitmap(interp, tkwin, string) Tcl_Interp *interp; /* Interpreter to use for error reporting, * this may be NULL. */ Tk_Window tkwin; /* Window in which bitmap will be used. */ CONST char *string; /* Description of bitmap. See manual entry * for details on legal syntax. */ { Tcl_HashEntry *nameHashPtr, *predefHashPtr; TkBitmap *bitmapPtr, *existingBitmapPtr; TkPredefBitmap *predefPtr; int new; Pixmap bitmap; int width, height; int dummy2; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (!dispPtr->bitmapInit) { BitmapInit(dispPtr); } nameHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapNameTable, string, &new); if (!new) { existingBitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr); for (bitmapPtr = existingBitmapPtr; bitmapPtr != NULL; bitmapPtr = bitmapPtr->nextPtr) { if ( (Tk_Display(tkwin) == bitmapPtr->display) && (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum) ) { bitmapPtr->resourceRefCount++; return bitmapPtr; } } } else { existingBitmapPtr = NULL; } /* * No suitable bitmap exists. Create a new bitmap from the * information contained in the string. If the string starts * with "@" then the rest of the string is a file name containing * the bitmap. Otherwise the string must refer to a bitmap * defined by a call to Tk_DefineBitmap. */ if (*string == '@') { /* INTL: ISO char */ Tcl_DString buffer; int result; if (Tcl_IsSafe(interp)) { Tcl_AppendResult(interp, "can't specify bitmap with '@' in a", " safe interpreter", (char *) NULL); goto error; } /* * Note that we need to cast away the CONST from the string because * Tcl_TranslateFileName is non const, even though it doesn't modify * the string. */ string = Tcl_TranslateFileName(interp, (char *) string + 1, &buffer); if (string == NULL) { goto error; } result = TkReadBitmapFile(Tk_Display(tkwin), RootWindowOfScreen(Tk_Screen(tkwin)), string, (unsigned int *) &width, (unsigned int *) &height, &bitmap, &dummy2, &dummy2); if (result != BitmapSuccess) { if (interp != NULL) { Tcl_AppendResult(interp, "error reading bitmap file \"", string, "\"", (char *) NULL); } Tcl_DStringFree(&buffer); goto error; } Tcl_DStringFree(&buffer); } else { predefHashPtr = Tcl_FindHashEntry(&tsdPtr->predefBitmapTable, string); if (predefHashPtr == NULL) { /* * The following platform specific call allows the user to * define bitmaps that may only exist during run time. If * it returns None nothing was found and we return the error. */ bitmap = TkpGetNativeAppBitmap(Tk_Display(tkwin), string, &width, &height); if (bitmap == None) { if (interp != NULL) { Tcl_AppendResult(interp, "bitmap \"", string, "\" not defined", (char *) NULL); } goto error; } } else { predefPtr = (TkPredefBitmap *) Tcl_GetHashValue(predefHashPtr); width = predefPtr->width; height = predefPtr->height; if (predefPtr->native) { bitmap = TkpCreateNativeBitmap(Tk_Display(tkwin), predefPtr->source); if (bitmap == None) { panic("native bitmap creation failed"); } } else { bitmap = XCreateBitmapFromData(Tk_Display(tkwin), RootWindowOfScreen(Tk_Screen(tkwin)), predefPtr->source, (unsigned) width, (unsigned) height); } } } /* * Add information about this bitmap to our database. */ bitmapPtr = (TkBitmap *) ckalloc(sizeof(TkBitmap)); bitmapPtr->bitmap = bitmap; bitmapPtr->width = width; bitmapPtr->height = height; bitmapPtr->display = Tk_Display(tkwin); bitmapPtr->screenNum = Tk_ScreenNumber(tkwin); bitmapPtr->resourceRefCount = 1; bitmapPtr->objRefCount = 0; bitmapPtr->nameHashPtr = nameHashPtr; bitmapPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap, &new); if (!new) { panic("bitmap already registered in Tk_GetBitmap"); } bitmapPtr->nextPtr = existingBitmapPtr; Tcl_SetHashValue(nameHashPtr, bitmapPtr); Tcl_SetHashValue(bitmapPtr->idHashPtr, bitmapPtr); return bitmapPtr; error: if (new) { Tcl_DeleteHashEntry(nameHashPtr); } return NULL; } /* *---------------------------------------------------------------------- * * Tk_DefineBitmap -- * * This procedure associates a textual name with a binary bitmap * description, so that the name may be used to refer to the * bitmap in future calls to Tk_GetBitmap. * * Results: * A standard Tcl result. If an error occurs then TCL_ERROR is * returned and a message is left in the interp's result. * * Side effects: * "Name" is entered into the bitmap table and may be used from * here on to refer to the given bitmap. * *---------------------------------------------------------------------- */ int Tk_DefineBitmap(interp, name, source, width, height) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ CONST char *name; /* Name to use for bitmap. Must not already * be defined as a bitmap. */ CONST char *source; /* Address of bits for bitmap. */ int width; /* Width of bitmap. */ int height; /* Height of bitmap. */ { int new; Tcl_HashEntry *predefHashPtr; TkPredefBitmap *predefPtr; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * Initialize the Bitmap module if not initialized already for this * thread. Since the current TkDisplay structure cannot be * introspected from here, pass a NULL pointer to BitmapInit, * which will know to initialize only the data in the * ThreadSpecificData structure for the current thread. */ if (!tsdPtr->initialized) { BitmapInit((TkDisplay *) NULL); } predefHashPtr = Tcl_CreateHashEntry(&tsdPtr->predefBitmapTable, name, &new); if (!new) { Tcl_AppendResult(interp, "bitmap \"", name, "\" is already defined", (char *) NULL); return TCL_ERROR; } predefPtr = (TkPredefBitmap *) ckalloc(sizeof(TkPredefBitmap)); predefPtr->source = source; predefPtr->width = width; predefPtr->height = height; predefPtr->native = 0; Tcl_SetHashValue(predefHashPtr, predefPtr); return TCL_OK; } /* *-------------------------------------------------------------- * * Tk_NameOfBitmap -- * * Given a bitmap, return a textual string identifying the * bitmap. * * Results: * The return value is the string name associated with bitmap. * * Side effects: * None. * *-------------------------------------------------------------- */ CONST char * Tk_NameOfBitmap(display, bitmap) Display *display; /* Display for which bitmap was * allocated. */ Pixmap bitmap; /* Bitmap whose name is wanted. */ { Tcl_HashEntry *idHashPtr; TkBitmap *bitmapPtr; TkDisplay *dispPtr = TkGetDisplay(display); if (dispPtr == NULL || !dispPtr->bitmapInit) { unknown: panic("Tk_NameOfBitmap received unknown bitmap argument"); } idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); if (idHashPtr == NULL) { goto unknown; } bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); return bitmapPtr->nameHashPtr->key.string; } /* *-------------------------------------------------------------- * * Tk_SizeOfBitmap -- * * Given a bitmap managed by this module, returns the width * and height of the bitmap. * * Results: * The words at *widthPtr and *heightPtr are filled in with * the dimenstions of bitmap. * * Side effects: * If bitmap isn't managed by this module then the procedure * panics.. * *-------------------------------------------------------------- */ void Tk_SizeOfBitmap(display, bitmap, widthPtr, heightPtr) Display *display; /* Display for which bitmap was * allocated. */ Pixmap bitmap; /* Bitmap whose size is wanted. */ int *widthPtr; /* Store bitmap width here. */ int *heightPtr; /* Store bitmap height here. */ { Tcl_HashEntry *idHashPtr; TkBitmap *bitmapPtr; TkDisplay *dispPtr = TkGetDisplay(display); if (!dispPtr->bitmapInit) { unknownBitmap: panic("Tk_SizeOfBitmap received unknown bitmap argument"); } idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); if (idHashPtr == NULL) { goto unknownBitmap; } bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); *widthPtr = bitmapPtr->width; *heightPtr = bitmapPtr->height; } /* *---------------------------------------------------------------------- * * FreeBitmap -- * * This procedure does all the work of releasing a bitmap allocated by * Tk_GetBitmap or TkGetBitmapFromData. It is invoked by both * Tk_FreeBitmap and Tk_FreeBitmapFromObj * * Results: * None. * * Side effects: * The reference count associated with bitmap is decremented, and * it is officially deallocated if no-one is using it anymore. * *---------------------------------------------------------------------- */ static void FreeBitmap(bitmapPtr) TkBitmap *bitmapPtr; /* Bitmap to be released. */ { TkBitmap *prevPtr; bitmapPtr->resourceRefCount--; if (bitmapPtr->resourceRefCount > 0) { return; } Tk_FreePixmap(bitmapPtr->display, bitmapPtr->bitmap); Tcl_DeleteHashEntry(bitmapPtr->idHashPtr); prevPtr = (TkBitmap *) Tcl_GetHashValue(bitmapPtr->nameHashPtr); if (prevPtr == bitmapPtr) { if (bitmapPtr->nextPtr == NULL) { Tcl_DeleteHashEntry(bitmapPtr->nameHashPtr); } else { Tcl_SetHashValue(bitmapPtr->nameHashPtr, bitmapPtr->nextPtr); } } else { while (prevPtr->nextPtr != bitmapPtr) { prevPtr = prevPtr->nextPtr; } prevPtr->nextPtr = bitmapPtr->nextPtr; } if (bitmapPtr->objRefCount == 0) { ckfree((char *) bitmapPtr); } } /* *---------------------------------------------------------------------- * * Tk_FreeBitmap -- * * This procedure is called to release a bitmap allocated by * Tk_GetBitmap or TkGetBitmapFromData. * * Results: * None. * * Side effects: * The reference count associated with bitmap is decremented, and * it is officially deallocated if no-one is using it anymore. * *---------------------------------------------------------------------- */ void Tk_FreeBitmap(display, bitmap) Display *display; /* Display for which bitmap was * allocated. */ Pixmap bitmap; /* Bitmap to be released. */ { Tcl_HashEntry *idHashPtr; TkDisplay *dispPtr = TkGetDisplay(display); if (!dispPtr->bitmapInit) { panic("Tk_FreeBitmap called before Tk_GetBitmap"); } idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); if (idHashPtr == NULL) { panic("Tk_FreeBitmap received unknown bitmap argument"); } FreeBitmap((TkBitmap *) Tcl_GetHashValue(idHashPtr)); } /* *---------------------------------------------------------------------- * * Tk_FreeBitmapFromObj -- * * This procedure is called to release a bitmap allocated by * Tk_AllocBitmapFromObj. It does not throw away the Tcl_Obj *; * it only gets rid of the hash table entry for this bitmap * and clears the cached value that is normally stored in the object. * * Results: * None. * * Side effects: * The reference count associated with the bitmap represented by * objPtr is decremented, and the bitmap is released to X if there are * no remaining uses for it. * *---------------------------------------------------------------------- */ void Tk_FreeBitmapFromObj(tkwin, objPtr) Tk_Window tkwin; /* The window this bitmap lives in. Needed * for the display value. */ Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */ { FreeBitmap(GetBitmapFromObj(tkwin, objPtr)); } /* *--------------------------------------------------------------------------- * * FreeBitmapObjProc -- * * This proc is called to release an object reference to a bitmap. * Called when the object's internal rep is released or when * the cached bitmapPtr needs to be changed. * * Results: * None. * * Side effects: * The object reference count is decremented. When both it * and the hash ref count go to zero, the color's resources * are released. * *--------------------------------------------------------------------------- */ static void FreeBitmapObjProc(objPtr) Tcl_Obj *objPtr; /* The object we are releasing. */ { TkBitmap *bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1; if (bitmapPtr != NULL) { bitmapPtr->objRefCount--; if ((bitmapPtr->objRefCount == 0) && (bitmapPtr->resourceRefCount == 0)) { ckfree((char *) bitmapPtr); } objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; } } /* *--------------------------------------------------------------------------- * * DupBitmapObjProc -- * * When a cached bitmap object is duplicated, this is called to * update the internal reps. * * Results: * None. * * Side effects: * The color's objRefCount is incremented and the internal rep * of the copy is set to point to it. * *--------------------------------------------------------------------------- */ static void DupBitmapObjProc(srcObjPtr, dupObjPtr) Tcl_Obj *srcObjPtr; /* The object we are copying from. */ Tcl_Obj *dupObjPtr; /* The object we are copying to. */ { TkBitmap *bitmapPtr = (TkBitmap *) srcObjPtr->internalRep.twoPtrValue.ptr1; dupObjPtr->typePtr = srcObjPtr->typePtr; dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; if (bitmapPtr != NULL) { bitmapPtr->objRefCount++; } } /* *---------------------------------------------------------------------- * * Tk_GetBitmapFromData -- * * Given a description of the bits for a bitmap, make a bitmap that * has the given properties. *** NOTE: this procedure is obsolete * and really shouldn't be used anymore. *** * * Results: * The return value is the X identifer for the desired bitmap * (a one-plane Pixmap), unless it couldn't be created properly. * In this case, None is returned and an error message is left in * the interp's result. The caller should never modify the bitmap that * is returned, and should eventually call Tk_FreeBitmap when the * bitmap is no longer needed. * * Side effects: * The bitmap is added to an internal database with a reference count. * For each call to this procedure, there should eventually be a call * to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps * aren't needed anymore. * *---------------------------------------------------------------------- */ /* ARGSUSED */ Pixmap Tk_GetBitmapFromData(interp, tkwin, source, width, height) Tcl_Interp *interp; /* Interpreter to use for error reporting. */ Tk_Window tkwin; /* Window in which bitmap will be used. */ CONST char *source; /* Bitmap data for bitmap shape. */ int width, height; /* Dimensions of bitmap. */ { DataKey nameKey; Tcl_HashEntry *dataHashPtr; int new; char string[16 + TCL_INTEGER_SPACE]; char *name; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; BitmapInit(dispPtr); nameKey.source = source; nameKey.width = width; nameKey.height = height; dataHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapDataTable, (char *) &nameKey, &new); if (!new) { name = (char *) Tcl_GetHashValue(dataHashPtr); } else { dispPtr->bitmapAutoNumber++; sprintf(string, "_tk%d", dispPtr->bitmapAutoNumber); name = string; Tcl_SetHashValue(dataHashPtr, name); if (Tk_DefineBitmap(interp, name, source, width, height) != TCL_OK) { Tcl_DeleteHashEntry(dataHashPtr); return TCL_ERROR; } } return Tk_GetBitmap(interp, tkwin, name); } /* *---------------------------------------------------------------------- * * Tk_GetBitmapFromObj -- * * Returns the bitmap referred to by a Tcl object. The bitmap must * already have been allocated via a call to Tk_AllocBitmapFromObj * or Tk_GetBitmap. * * Results: * Returns the Pixmap that matches the tkwin and the string rep * of objPtr. * * Side effects: * If the object is not already a bitmap, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ Pixmap Tk_GetBitmapFromObj(tkwin, objPtr) Tk_Window tkwin; Tcl_Obj *objPtr; /* The object from which to get pixels. */ { TkBitmap *bitmapPtr = GetBitmapFromObj(tkwin, objPtr); return bitmapPtr->bitmap; } /* *---------------------------------------------------------------------- * * GetBitmapFromObj -- * * Returns the bitmap referred to by a Tcl object. The bitmap must * already have been allocated via a call to Tk_AllocBitmapFromObj * or Tk_GetBitmap. * * Results: * Returns the TkBitmap * that matches the tkwin and the string rep * of objPtr. * * Side effects: * If the object is not already a bitmap, the conversion will free * any old internal representation. * *---------------------------------------------------------------------- */ static TkBitmap * GetBitmapFromObj(tkwin, objPtr) Tk_Window tkwin; /* Window in which the bitmap will be used. */ Tcl_Obj *objPtr; /* The object that describes the desired * bitmap. */ { TkBitmap *bitmapPtr; Tcl_HashEntry *hashPtr; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; if (objPtr->typePtr != &tkBitmapObjType) { InitBitmapObj(objPtr); } bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1; if (bitmapPtr != NULL) { if ((bitmapPtr->resourceRefCount > 0) && (Tk_Display(tkwin) == bitmapPtr->display)) { return bitmapPtr; } hashPtr = bitmapPtr->nameHashPtr; FreeBitmapObjProc(objPtr); } else { hashPtr = Tcl_FindHashEntry(&dispPtr->bitmapNameTable, Tcl_GetString(objPtr)); if (hashPtr == NULL) { goto error; } } /* * At this point we've got a hash table entry, off of which hang * one or more TkBitmap structures. See if any of them will work. */ for (bitmapPtr = (TkBitmap *) Tcl_GetHashValue(hashPtr); bitmapPtr != NULL; bitmapPtr = bitmapPtr->nextPtr) { if (Tk_Display(tkwin) == bitmapPtr->display) { objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr; bitmapPtr->objRefCount++; return bitmapPtr; } } error: panic("GetBitmapFromObj called with non-existent bitmap!"); /* * The following code isn't reached; it's just there to please compilers. */ return NULL; } /* *---------------------------------------------------------------------- * * InitBitmapObj -- * * Bookeeping procedure to change an objPtr to a bitmap type. * * Results: * None. * * Side effects: * The old internal rep of the object is freed. The internal * rep is cleared. The final form of the object is set * by either Tk_AllocBitmapFromObj or GetBitmapFromObj. * *---------------------------------------------------------------------- */ static void InitBitmapObj(objPtr) Tcl_Obj *objPtr; /* The object to convert. */ { Tcl_ObjType *typePtr; /* * Free the old internalRep before setting the new one. */ Tcl_GetString(objPtr); typePtr = objPtr->typePtr; if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) { (*typePtr->freeIntRepProc)(objPtr); } objPtr->typePtr = &tkBitmapObjType; objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL; } /* *---------------------------------------------------------------------- * * BitmapInit -- * Initializes hash tables used by this module. Initializes * tables stored in TkDisplay structure if a TkDisplay pointer * is passed in. Iinitializes the thread-local data * in the current thread's ThreadSpecificData structure. * * Results: * None. * * Side effects: * Read the code. * *---------------------------------------------------------------------- */ static void BitmapInit(dispPtr) TkDisplay *dispPtr; /* TkDisplay structure encapsulating * thread-specific data used by this * module, or NULL if unavailable. */ { Tcl_Interp *dummy; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* * First initialize the data in the ThreadSpecificData strucuture, * if needed. */ if (!tsdPtr->initialized) { tsdPtr->initialized = 1; dummy = Tcl_CreateInterp(); Tcl_InitHashTable(&tsdPtr->predefBitmapTable, TCL_STRING_KEYS); Tk_DefineBitmap(dummy, "error", (char *) error_bits, error_width, error_height); Tk_DefineBitmap(dummy, "gray75", (char *) gray75_bits, gray75_width, gray75_height); Tk_DefineBitmap(dummy, "gray50", (char *) gray50_bits, gray50_width, gray50_height); Tk_DefineBitmap(dummy, "gray25", (char *) gray25_bits, gray25_width, gray25_height); Tk_DefineBitmap(dummy, "gray12", (char *) gray12_bits, gray12_width, gray12_height); Tk_DefineBitmap(dummy, "hourglass", (char *) hourglass_bits, hourglass_width, hourglass_height); Tk_DefineBitmap(dummy, "info", (char *) info_bits, info_width, info_height); Tk_DefineBitmap(dummy, "questhead", (char *) questhead_bits, questhead_width, questhead_height); Tk_DefineBitmap(dummy, "question", (char *) question_bits, question_width, question_height); Tk_DefineBitmap(dummy, "warning", (char *) warning_bits, warning_width, warning_height); TkpDefineNativeBitmaps(); Tcl_DeleteInterp(dummy); } /* * Was a valid TkDisplay pointer passed? If so, initialize the * Bitmap module tables in that structure. */ if (dispPtr != NULL) { dispPtr->bitmapInit = 1; Tcl_InitHashTable(&dispPtr->bitmapNameTable, TCL_STRING_KEYS); Tcl_InitHashTable(&dispPtr->bitmapDataTable, sizeof(DataKey) /sizeof(int)); /* * The call below is tricky: can't use sizeof(IdKey) because it * gets padded with extra unpredictable bytes on some 64-bit * machines. */ /* * The comment above doesn't make sense... */ Tcl_InitHashTable(&dispPtr->bitmapIdTable, TCL_ONE_WORD_KEYS); } } /* *---------------------------------------------------------------------- * * TkReadBitmapFile -- * * Loads a bitmap image in X bitmap format into the specified * drawable. This is equivelent to the XReadBitmapFile in X. * * Results: * Sets the size, hotspot, and bitmap on success. * * Side effects: * Creates a new bitmap from the file data. * *---------------------------------------------------------------------- */ int TkReadBitmapFile(display, d, filename, width_return, height_return, bitmap_return, x_hot_return, y_hot_return) Display* display; Drawable d; CONST char* filename; unsigned int* width_return; unsigned int* height_return; Pixmap* bitmap_return; int* x_hot_return; int* y_hot_return; { char *data; data = TkGetBitmapData(NULL, NULL, (char *) filename, (int *) width_return, (int *) height_return, x_hot_return, y_hot_return); if (data == NULL) { return BitmapFileInvalid; } *bitmap_return = XCreateBitmapFromData(display, d, data, *width_return, *height_return); ckfree(data); return BitmapSuccess; } /* *---------------------------------------------------------------------- * * TkDebugBitmap -- * * This procedure returns debugging information about a bitmap. * * Results: * The return value is a list with one sublist for each TkBitmap * corresponding to "name". Each sublist has two elements that * contain the resourceRefCount and objRefCount fields from the * TkBitmap structure. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * TkDebugBitmap(tkwin, name) Tk_Window tkwin; /* The window in which the bitmap will be * used (not currently used). */ char *name; /* Name of the desired color. */ { TkBitmap *bitmapPtr; Tcl_HashEntry *hashPtr; Tcl_Obj *resultPtr, *objPtr; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; resultPtr = Tcl_NewObj(); hashPtr = Tcl_FindHashEntry(&dispPtr->bitmapNameTable, name); if (hashPtr != NULL) { bitmapPtr = (TkBitmap *) Tcl_GetHashValue(hashPtr); if (bitmapPtr == NULL) { panic("TkDebugBitmap found empty hash table entry"); } for ( ; (bitmapPtr != NULL); bitmapPtr = bitmapPtr->nextPtr) { objPtr = Tcl_NewObj(); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewIntObj(bitmapPtr->resourceRefCount)); Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewIntObj(bitmapPtr->objRefCount)); Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); } } return resultPtr; } /* *---------------------------------------------------------------------- * * TkGetBitmapPredefTable -- * This procedure is used by tkMacBitmap.c to access the thread- * specific predefBitmap table that maps from the names of * the predefined bitmaps to data associated with those * bitmaps. It is required because the table is allocated in * thread-local storage and is not visible outside this file. * Results: * Returns a pointer to the predefined bitmap hash table for * the current thread. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_HashTable * TkGetBitmapPredefTable() { ThreadSpecificData *tsdPtr = (ThreadSpecificData *) Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); return &tsdPtr->predefBitmapTable; }