diff options
Diffstat (limited to 'tk8.6/generic/tkBitmap.c')
-rw-r--r-- | tk8.6/generic/tkBitmap.c | 1205 |
1 files changed, 1205 insertions, 0 deletions
diff --git a/tk8.6/generic/tkBitmap.c b/tk8.6/generic/tkBitmap.c new file mode 100644 index 0000000..54bab69 --- /dev/null +++ b/tk8.6/generic/tkBitmap.c @@ -0,0 +1,1205 @@ +/* + * 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. + */ + +#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(_MSC_VER) +#pragma warning (disable : 4305) +#endif + +#include "error.xbm" +#include "gray12.xbm" +#include "gray25.xbm" +#include "gray50.xbm" +#include "gray75.xbm" +#include "hourglass.xbm" +#include "info.xbm" +#include "questhead.xbm" +#include "question.xbm" +#include "warning.xbm" + +#if defined(_MSC_VER) +#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 { + 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 functions defined in this file: + */ + +static void BitmapInit(TkDisplay *dispPtr); +static void DupBitmapObjProc(Tcl_Obj *srcObjPtr, + Tcl_Obj *dupObjPtr); +static void FreeBitmap(TkBitmap *bitmapPtr); +static void FreeBitmapObj(Tcl_Obj *objPtr); +static void FreeBitmapObjProc(Tcl_Obj *objPtr); +static TkBitmap * GetBitmap(Tcl_Interp *interp, Tk_Window tkwin, + const char *name); +static TkBitmap * GetBitmapFromObj(Tk_Window tkwin, Tcl_Obj *objPtr); +static void InitBitmapObj(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. + */ + +const 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 function, 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( + 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 = 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. + */ + + FreeBitmapObj(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 = Tcl_GetHashValue(bitmapPtr->nameHashPtr); + + FreeBitmapObj(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 = 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 = 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 function, 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( + 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 function, 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( + 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; + Pixmap bitmap; + int isNew, width = 0, height = 0, dummy2; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (!dispPtr->bitmapInit) { + BitmapInit(dispPtr); + } + + nameHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapNameTable, string, + &isNew); + if (!isNew) { + existingBitmapPtr = 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_SetObjResult(interp, Tcl_NewStringObj( + "can't specify bitmap with '@' in a safe interpreter", + -1)); + Tcl_SetErrorCode(interp, "TK", "SAFE", "BITMAP_FILE", 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_SetObjResult(interp, Tcl_ObjPrintf( + "error reading bitmap file \"%s\"", string)); + Tcl_SetErrorCode(interp, "TK", "BITMAP", "FILE_ERROR", 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_SetObjResult(interp, Tcl_ObjPrintf( + "bitmap \"%s\" not defined", string)); + Tcl_SetErrorCode(interp, "TK", "LOOKUP", "BITMAP", string, + NULL); + } + goto error; + } + } else { + predefPtr = Tcl_GetHashValue(predefHashPtr); + width = predefPtr->width; + height = predefPtr->height; + if (predefPtr->native) { + bitmap = TkpCreateNativeBitmap(Tk_Display(tkwin), + predefPtr->source); + if (bitmap == None) { + Tcl_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 = 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, &isNew); + if (!isNew) { + Tcl_Panic("bitmap already registered in Tk_GetBitmap"); + } + bitmapPtr->nextPtr = existingBitmapPtr; + Tcl_SetHashValue(nameHashPtr, bitmapPtr); + Tcl_SetHashValue(bitmapPtr->idHashPtr, bitmapPtr); + return bitmapPtr; + + error: + if (isNew) { + Tcl_DeleteHashEntry(nameHashPtr); + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_DefineBitmap -- + * + * This function 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( + 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 void *source, /* Address of bits for bitmap. */ + int width, /* Width of bitmap. */ + int height) /* Height of bitmap. */ +{ + int isNew; + Tcl_HashEntry *predefHashPtr; + TkPredefBitmap *predefPtr; + ThreadSpecificData *tsdPtr = + 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(NULL); + } + + predefHashPtr = Tcl_CreateHashEntry(&tsdPtr->predefBitmapTable, + name, &isNew); + if (!isNew) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bitmap \"%s\" is already defined", name)); + Tcl_SetErrorCode(interp, "TK", "BITMAP", "EXISTS", NULL); + return TCL_ERROR; + } + predefPtr = 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 *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: + Tcl_Panic("Tk_NameOfBitmap received unknown bitmap argument"); + } + + idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); + if (idHashPtr == NULL) { + goto unknown; + } + bitmapPtr = 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 function panics.. + * + *-------------------------------------------------------------- + */ + +void +Tk_SizeOfBitmap( + 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: + Tcl_Panic("Tk_SizeOfBitmap received unknown bitmap argument"); + } + + idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); + if (idHashPtr == NULL) { + goto unknownBitmap; + } + bitmapPtr = Tcl_GetHashValue(idHashPtr); + *widthPtr = bitmapPtr->width; + *heightPtr = bitmapPtr->height; +} + +/* + *---------------------------------------------------------------------- + * + * FreeBitmap -- + * + * This function 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( + 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 = 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(bitmapPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeBitmap -- + * + * This function 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 *display, /* Display for which bitmap was allocated. */ + Pixmap bitmap) /* Bitmap to be released. */ +{ + Tcl_HashEntry *idHashPtr; + TkDisplay *dispPtr = TkGetDisplay(display); + + if (!dispPtr->bitmapInit) { + Tcl_Panic("Tk_FreeBitmap called before Tk_GetBitmap"); + } + + idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap); + if (idHashPtr == NULL) { + Tcl_Panic("Tk_FreeBitmap received unknown bitmap argument"); + } + FreeBitmap(Tcl_GetHashValue(idHashPtr)); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreeBitmapFromObj -- + * + * This function 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( + 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, FreeBitmapObj -- + * + * 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( + Tcl_Obj *objPtr) /* The object we are releasing. */ +{ + FreeBitmapObj(objPtr); + objPtr->typePtr = NULL; +} + +static void +FreeBitmapObj( + Tcl_Obj *objPtr) /* The object we are releasing. */ +{ + TkBitmap *bitmapPtr = objPtr->internalRep.twoPtrValue.ptr1; + + if (bitmapPtr != NULL) { + bitmapPtr->objRefCount--; + if ((bitmapPtr->objRefCount == 0) + && (bitmapPtr->resourceRefCount == 0)) { + ckfree(bitmapPtr); + } + objPtr->internalRep.twoPtrValue.ptr1 = 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( + Tcl_Obj *srcObjPtr, /* The object we are copying from. */ + Tcl_Obj *dupObjPtr) /* The object we are copying to. */ +{ + TkBitmap *bitmapPtr = srcObjPtr->internalRep.twoPtrValue.ptr1; + + dupObjPtr->typePtr = srcObjPtr->typePtr; + dupObjPtr->internalRep.twoPtrValue.ptr1 = 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 function 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 function, 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( + Tcl_Interp *interp, /* Interpreter to use for error reporting. */ + Tk_Window tkwin, /* Window in which bitmap will be used. */ + const void *source, /* Bitmap data for bitmap shape. */ + int width, int height) /* Dimensions of bitmap. */ +{ + DataKey nameKey; + Tcl_HashEntry *dataHashPtr; + int isNew; + char string[16 + TCL_INTEGER_SPACE]; + char *name; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + if (!tsdPtr->initialized) { + BitmapInit(dispPtr); + } + + nameKey.source = source; + nameKey.width = width; + nameKey.height = height; + dataHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapDataTable, + (char *) &nameKey, &isNew); + if (!isNew) { + name = 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( + 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( + 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 = objPtr->internalRep.twoPtrValue.ptr1; + if (bitmapPtr != NULL) { + if ((bitmapPtr->resourceRefCount > 0) + && (Tk_Display(tkwin) == bitmapPtr->display)) { + return bitmapPtr; + } + hashPtr = bitmapPtr->nameHashPtr; + FreeBitmapObj(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 = Tcl_GetHashValue(hashPtr); bitmapPtr != NULL; + bitmapPtr = bitmapPtr->nextPtr) { + if (Tk_Display(tkwin) == bitmapPtr->display) { + objPtr->internalRep.twoPtrValue.ptr1 = bitmapPtr; + bitmapPtr->objRefCount++; + return bitmapPtr; + } + } + + error: + Tcl_Panic("GetBitmapFromObj called with non-existent bitmap!"); + /* + * The following code isn't reached; it's just there to please compilers. + */ + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * InitBitmapObj -- + * + * Bookeeping function 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( + Tcl_Obj *objPtr) /* The object to convert. */ +{ + const 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 = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * BitmapInit -- + * + * Initializes hash tables used by this module. Initializes tables stored + * in TkDisplay structure if a TkDisplay pointer is passed in. Also + * initializes the thread-local data in the current thread's + * ThreadSpecificData structure. + * + * Results: + * None. + * + * Side effects: + * Read the code. + * + *---------------------------------------------------------------------- + */ + +static void +BitmapInit( + TkDisplay *dispPtr) /* TkDisplay structure encapsulating + * thread-specific data used by this module, + * or NULL if unavailable. */ +{ + Tcl_Interp *dummy; + ThreadSpecificData *tsdPtr = + 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", error_bits, + error_width, error_height); + Tk_DefineBitmap(dummy, "gray75", gray75_bits, + gray75_width, gray75_height); + Tk_DefineBitmap(dummy, "gray50", gray50_bits, + gray50_width, gray50_height); + Tk_DefineBitmap(dummy, "gray25", gray25_bits, + gray25_width, gray25_height); + Tk_DefineBitmap(dummy, "gray12", gray12_bits, + gray12_width, gray12_height); + Tk_DefineBitmap(dummy, "hourglass", hourglass_bits, + hourglass_width, hourglass_height); + Tk_DefineBitmap(dummy, "info", info_bits, + info_width, info_height); + Tk_DefineBitmap(dummy, "questhead", questhead_bits, + questhead_width, questhead_height); + Tk_DefineBitmap(dummy, "question", question_bits, + question_width, question_height); + Tk_DefineBitmap(dummy, "warning", 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 *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, 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 function 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( + Tk_Window tkwin, /* The window in which the bitmap will be used + * (not currently used). */ + const 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 = Tcl_GetHashValue(hashPtr); + if (bitmapPtr == NULL) { + Tcl_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 function 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(void) +{ + ThreadSpecificData *tsdPtr = + Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); + + return &tsdPtr->predefBitmapTable; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |