/*
* 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 "transpnt.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"
#include "tk.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(interp, 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);
}
TclObjSetType(objPtr,&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);
Tk_DefineBitmap(dummy, "transparent", (char *) transparent_bits,
transparent_width, transparent_height);
Tk_DefineBitmap(dummy, "Tk", (char *) Tkbmp_bits,
Tkbmp_width, Tkbmp_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(interp, display, d, filename, width_return, height_return,
bitmap_return, x_hot_return, y_hot_return)
Tcl_Interp *interp;
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(interp, 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;
}