/* * 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. * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ static char sccsid[] = "@(#) tkBitmap.c 1.25 94/10/17 17:50:35"; #include "tkPort.h" #include "tk.h" /* * The includes below are for pre-defined bitmaps. */ #include "bitmaps/error" #include "bitmaps/gray25" #include "bitmaps/gray50" #include "bitmaps/hourglass" #include "bitmaps/info" #include "bitmaps/questhead" #include "bitmaps/question" #include "bitmaps/warning" /* * 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 { Pixmap bitmap; /* X identifier for bitmap. None means this * bitmap was created by Tk_DefineBitmap * and it isn't currently in use. */ unsigned int width, height; /* Dimensions of bitmap. */ Display *display; /* Display for which bitmap is valid. */ int refCount; /* Number of active uses of bitmap. */ Tcl_HashEntry *hashPtr; /* Entry in nameTable for this structure * (needed when deleting). */ } TkBitmap; /* * Hash table to map from a textual description of a bitmap to the * TkBitmap record for the bitmap, and key structure used in that * hash table: */ static Tcl_HashTable nameTable; typedef struct { Tk_Uid name; /* Textual name for desired bitmap. */ Screen *screen; /* Screen on which bitmap will be used. */ } NameKey; /* * Hash table that maps from to the TkBitmap structure * for the bitmap. This table is used by Tk_FreeBitmap. */ static Tcl_HashTable idTable; typedef struct { Display *display; /* Display for which bitmap was allocated. */ Pixmap pixmap; /* X identifier for pixmap. */ } IdKey; /* * For each call to Tk_DefineBitmap one of the following structures is * created to hold information about the bitmap. */ typedef struct { char *source; /* Bits for bitmap. */ unsigned int width, height; /* Dimensions of bitmap. */ } PredefBitmap; /* * Hash table create 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 PredefBitmap structures. */ static Tcl_HashTable predefTable; /* * Hash table used by Tk_GetBitmapFromData to map from a collection * of in-core data about a bitmap to a Tk_Uid giving an automatically- * generated name for the bitmap: */ static Tcl_HashTable dataTable; typedef struct { char *source; /* Bitmap bits. */ unsigned int width, height; /* Dimensions of bitmap. */ } DataKey; static int initialized = 0; /* 0 means static structures haven't been * initialized yet. */ /* * Forward declarations for procedures defined in this file: */ static void BitmapInit _ANSI_ARGS_((void)); /* *---------------------------------------------------------------------- * * 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 interp->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. */ Tk_Window tkwin; /* Window in which bitmap will be used. */ Tk_Uid string; /* Description of bitmap. See manual entry * for details on legal syntax. */ { NameKey nameKey; IdKey idKey; Tcl_HashEntry *nameHashPtr, *idHashPtr, *predefHashPtr; register TkBitmap *bitmapPtr; PredefBitmap *predefPtr; int new; Pixmap bitmap; unsigned int width, height; int dummy2; if (!initialized) { BitmapInit(); } nameKey.name = string; nameKey.screen = Tk_Screen(tkwin); nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new); if (!new) { bitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr); bitmapPtr->refCount++; return bitmapPtr->bitmap; } /* * 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 == '@') { Tcl_DString buffer; int result; string = Tcl_TildeSubst(interp, string + 1, &buffer); if (string == NULL) { goto error; } result = XReadBitmapFile(Tk_Display(tkwin), RootWindowOfScreen(nameKey.screen), string, &width, &height, &bitmap, &dummy2, &dummy2); Tcl_DStringFree(&buffer); if (result != BitmapSuccess) { Tcl_AppendResult(interp, "error reading bitmap file \"", string, "\"", (char *) NULL); goto error; } } else { predefHashPtr = Tcl_FindHashEntry(&predefTable, string); if (predefHashPtr == NULL) { Tcl_AppendResult(interp, "bitmap \"", string, "\" not defined", (char *) NULL); goto error; } predefPtr = (PredefBitmap *) Tcl_GetHashValue(predefHashPtr); width = predefPtr->width; height = predefPtr->height; bitmap = XCreateBitmapFromData(Tk_Display(tkwin), RootWindowOfScreen(nameKey.screen), predefPtr->source, width, 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->refCount = 1; bitmapPtr->hashPtr = nameHashPtr; idKey.display = bitmapPtr->display; idKey.pixmap = bitmap; idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new); if (!new) { panic("bitmap already registered in Tk_GetBitmap"); } Tcl_SetHashValue(nameHashPtr, bitmapPtr); Tcl_SetHashValue(idHashPtr, bitmapPtr); return bitmapPtr->bitmap; error: Tcl_DeleteHashEntry(nameHashPtr); return None; } /* *---------------------------------------------------------------------- * * 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 interp->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. */ Tk_Uid name; /* Name to use for bitmap. Must not already * be defined as a bitmap. */ char *source; /* Address of bits for bitmap. */ unsigned int width; /* Width of bitmap. */ unsigned int height; /* Height of bitmap. */ { int new; Tcl_HashEntry *predefHashPtr; PredefBitmap *predefPtr; if (!initialized) { BitmapInit(); } predefHashPtr = Tcl_CreateHashEntry(&predefTable, name, &new); if (!new) { Tcl_AppendResult(interp, "bitmap \"", name, "\" is already defined", (char *) NULL); return TCL_ERROR; } predefPtr = (PredefBitmap *) ckalloc(sizeof(PredefBitmap)); predefPtr->source = source; predefPtr->width = width; predefPtr->height = height; 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. * *-------------------------------------------------------------- */ Tk_Uid Tk_NameOfBitmap(display, bitmap) Display *display; /* Display for which bitmap was * allocated. */ Pixmap bitmap; /* Bitmap whose name is wanted. */ { IdKey idKey; Tcl_HashEntry *idHashPtr; TkBitmap *bitmapPtr; if (!initialized) { unknown: panic("Tk_NameOfBitmap received unknown bitmap argument"); } idKey.display = display; idKey.pixmap = bitmap; idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); if (idHashPtr == NULL) { goto unknown; } bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); return ((NameKey *) bitmapPtr->hashPtr->key.words)->name; } /* *-------------------------------------------------------------- * * 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. */ unsigned int *widthPtr; /* Store bitmap width here. */ unsigned int *heightPtr; /* Store bitmap height here. */ { IdKey idKey; Tcl_HashEntry *idHashPtr; TkBitmap *bitmapPtr; if (!initialized) { unknownBitmap: panic("Tk_SizeOfBitmap received unknown bitmap argument"); } idKey.display = display; idKey.pixmap = bitmap; idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); if (idHashPtr == NULL) { goto unknownBitmap; } bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); *widthPtr = bitmapPtr->width; *heightPtr = bitmapPtr->height; } /* *---------------------------------------------------------------------- * * 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; register TkBitmap *bitmapPtr; IdKey idKey; if (!initialized) { panic("Tk_FreeBitmap called before Tk_GetBitmap"); } idKey.display = display; idKey.pixmap = bitmap; idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey); if (idHashPtr == NULL) { panic("Tk_FreeBitmap received unknown bitmap argument"); } bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); bitmapPtr->refCount--; if (bitmapPtr->refCount == 0) { XFreePixmap(bitmapPtr->display, bitmapPtr->bitmap); Tk_FreeXId(bitmapPtr->display, (XID) bitmapPtr->bitmap); Tcl_DeleteHashEntry(idHashPtr); Tcl_DeleteHashEntry(bitmapPtr->hashPtr); ckfree((char *) bitmapPtr); } } /* *---------------------------------------------------------------------- * * 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 * interp->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. */ char *source; /* Bitmap data for bitmap shape. */ unsigned int width, height; /* Dimensions of bitmap. */ { DataKey nameKey; Tcl_HashEntry *dataHashPtr; Tk_Uid name = NULL; /* Initialization need only to prevent * compiler warning. */ int new; static autoNumber = 0; char string[20]; if (!initialized) { BitmapInit(); } nameKey.source = source; nameKey.width = width; nameKey.height = height; dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &nameKey, &new); if (!new) { name = (Tk_Uid) Tcl_GetHashValue(dataHashPtr); } else { autoNumber++; sprintf(string, "_tk%d", autoNumber); name = Tk_GetUid(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); } /* *---------------------------------------------------------------------- * * BitmapInit -- * * Initialize the structures used for bitmap management. * * Results: * None. * * Side effects: * Read the code. * *---------------------------------------------------------------------- */ static void BitmapInit() { Tcl_Interp *dummy; dummy = Tcl_CreateInterp(); initialized = 1; Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int)); Tcl_InitHashTable(&predefTable, TCL_ONE_WORD_KEYS); /* * The call below is tricky: can't use sizeof(IdKey) because it * gets padded with extra unpredictable bytes on some 64-bit * machines. */ Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Pixmap)) /sizeof(int)); Tk_DefineBitmap(dummy, Tk_GetUid("error"), error_bits, error_width, error_height); Tk_DefineBitmap(dummy, Tk_GetUid("gray50"), gray50_bits, gray50_width, gray50_height); Tk_DefineBitmap(dummy, Tk_GetUid("gray25"), gray25_bits, gray25_width, gray25_height); Tk_DefineBitmap(dummy, Tk_GetUid("hourglass"), hourglass_bits, hourglass_width, hourglass_height); Tk_DefineBitmap(dummy, Tk_GetUid("info"), info_bits, info_width, info_height); Tk_DefineBitmap(dummy, Tk_GetUid("questhead"), questhead_bits, questhead_width, questhead_height); Tk_DefineBitmap(dummy, Tk_GetUid("question"), question_bits, question_width, question_height); Tk_DefineBitmap(dummy, Tk_GetUid("warning"), warning_bits, warning_width, warning_height); Tcl_DeleteInterp(dummy); }