1206 lines
35 KiB
C
1206 lines
35 KiB
C
/*
|
||
* 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:
|
||
*/
|