1 /*
2  * tkBitmap.c --
3  *
4  *	This file maintains a database of read-only bitmaps for the Tk
5  *	toolkit.  This allows bitmaps to be shared between widgets and
6  *	also avoids interactions with the X server.
7  *
8  * Copyright (c) 1990-1994 The Regents of the University of California.
9  * Copyright (c) 1994-1998 Sun Microsystems, Inc.
10  *
11  * See the file "license.terms" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * RCS: @(#) $Id: tkBitmap.c,v 1.10 2002/08/05 04:30:38 dgp Exp $
15  */
16 
17 #include "tkPort.h"
18 #include "tkInt.h"
19 
20 /*
21  * The includes below are for pre-defined bitmaps.
22  *
23  * Platform-specific issue: Windows complains when the bitmaps are
24  * included, because an array of characters is being initialized with
25  * integers as elements.  For lint purposes, the following pragmas
26  * temporarily turn off that warning message.
27  */
28 
29 #if defined(__WIN32__) || defined(_WIN32)
30 #pragma warning (disable : 4305)
31 #endif
32 
33 #include "error.bmp"
34 #include "gray12.bmp"
35 #include "transpnt.bmp"
36 #include "gray25.bmp"
37 #include "gray50.bmp"
38 #include "gray75.bmp"
39 #include "hourglass.bmp"
40 #include "info.bmp"
41 #include "questhead.bmp"
42 #include "question.bmp"
43 #include "warning.bmp"
44 #include "tk.bmp"
45 
46 #if defined(__WIN32__) || defined(_WIN32)
47 #pragma warning (default : 4305)
48 #endif
49 
50 /*
51  * One of the following data structures exists for each bitmap that is
52  * currently in use.  Each structure is indexed with both "idTable" and
53  * "nameTable".
54  */
55 
56 typedef struct TkBitmap {
57     Pixmap bitmap;		/* X identifier for bitmap.  None means this
58 				 * bitmap was created by Tk_DefineBitmap
59 				 * and it isn't currently in use. */
60     int width, height;		/* Dimensions of bitmap. */
61     Display *display;		/* Display for which bitmap is valid. */
62     int screenNum;		/* Screen on which bitmap is valid */
63     int resourceRefCount;	/* Number of active uses of this bitmap (each
64 				 * active use corresponds to a call to
65 				 * Tk_AllocBitmapFromObj or Tk_GetBitmap).
66 				 * If this count is 0, then this TkBitmap
67 				 * structure is no longer valid and it isn't
68 				 * present in nameTable: it is being kept
69 				 * around only because there are objects
70 				 * referring to it.  The structure is freed
71 				 * when resourceRefCount and objRefCount
72 				 * are both 0. */
73     int objRefCount;		/* Number of Tcl_Obj's that reference
74 				 * this structure. */
75     Tcl_HashEntry *nameHashPtr;	/* Entry in nameTable for this structure
76 				 * (needed when deleting). */
77     Tcl_HashEntry *idHashPtr;	/* Entry in idTable for this structure
78 				 * (needed when deleting). */
79     struct TkBitmap *nextPtr;	/* Points to the next TkBitmap structure with
80 				 * the same name.  All bitmaps with the
81 				 * same name (but different displays or
82 				 * screens) are chained together off a
83 				 * single entry in nameTable. */
84 } TkBitmap;
85 
86 /*
87  * Used in bitmapDataTable, stored in the TkDisplay structure, to map
88  * between in-core data about a bitmap to its TkBitmap structure.
89  */
90 
91 typedef struct {
92     CONST char *source;		/* Bitmap bits. */
93     int width, height;		/* Dimensions of bitmap. */
94 } DataKey;
95 
96 typedef struct ThreadSpecificData {
97     int initialized;            /* 0 means table below needs initializing. */
98     Tcl_HashTable predefBitmapTable;
99                                 /* Hash table created by Tk_DefineBitmap
100 				 * to map from a name to a collection
101 				 * of in-core data about a bitmap.  The
102 				 * table is indexed by the address of the
103 				 * data for the bitmap, and the entries
104 				 * contain pointers to TkPredefBitmap
105 				 * structures. */
106 } ThreadSpecificData;
107 static Tcl_ThreadDataKey dataKey;
108 
109 /*
110  * Forward declarations for procedures defined in this file:
111  */
112 
113 static void		BitmapInit _ANSI_ARGS_((TkDisplay *dispPtr));
114 static void		DupBitmapObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
115 			    Tcl_Obj *dupObjPtr));
116 static void		FreeBitmap _ANSI_ARGS_((TkBitmap *bitmapPtr));
117 static void		FreeBitmapObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
118 static TkBitmap *	GetBitmap _ANSI_ARGS_((Tcl_Interp *interp,
119 			    Tk_Window tkwin, CONST char *name));
120 static TkBitmap *	GetBitmapFromObj _ANSI_ARGS_((Tk_Window tkwin,
121 			    Tcl_Obj *objPtr));
122 static void		InitBitmapObj _ANSI_ARGS_((Tcl_Obj *objPtr));
123 
124 /*
125  * The following structure defines the implementation of the "bitmap" Tcl
126  * object, which maps a string bitmap name to a TkBitmap object.  The
127  * ptr1 field of the Tcl_Obj points to a TkBitmap object.
128  */
129 
130 Tcl_ObjType tkBitmapObjType = {
131     "bitmap",			/* name */
132     FreeBitmapObjProc,		/* freeIntRepProc */
133     DupBitmapObjProc,		/* dupIntRepProc */
134     NULL,			/* updateStringProc */
135     NULL			/* setFromAnyProc */
136 };
137 
138 /*
139  *----------------------------------------------------------------------
140  *
141  * Tk_AllocBitmapFromObj --
142  *
143  *	Given a Tcl_Obj *, map the value to a corresponding
144  *	Pixmap structure based on the tkwin given.
145  *
146  * Results:
147  *	The return value is the X identifer for the desired bitmap
148  *	(i.e. a Pixmap with a single plane), unless string couldn't be
149  *	parsed correctly.  In this case, None is returned and an error
150  *	message is left in the interp's result.  The caller should never
151  *	modify the bitmap that is returned, and should eventually call
152  *	Tk_FreeBitmapFromObj when the bitmap is no longer needed.
153  *
154  * Side effects:
155  *	The bitmap is added to an internal database with a reference count.
156  *	For each call to this procedure, there should eventually be a call
157  *	to Tk_FreeBitmapFromObj, so that the database can be cleaned up
158  *	when bitmaps aren't needed anymore.
159  *
160  *----------------------------------------------------------------------
161  */
162 
163 Pixmap
Tk_AllocBitmapFromObj(interp,tkwin,objPtr)164 Tk_AllocBitmapFromObj(interp, tkwin, objPtr)
165     Tcl_Interp *interp;		/* Interp for error results. This may
166 				 * be NULL. */
167     Tk_Window tkwin;		/* Need the screen the bitmap is used on.*/
168     Tcl_Obj *objPtr;		/* Object describing bitmap; see manual
169 				 * entry for legal syntax of string value. */
170 {
171     TkBitmap *bitmapPtr;
172 
173     if (objPtr->typePtr != &tkBitmapObjType) {
174 	InitBitmapObj(objPtr);
175     }
176     bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1;
177 
178     /*
179      * If the object currently points to a TkBitmap, see if it's the
180      * one we want.  If so, increment its reference count and return.
181      */
182 
183     if (bitmapPtr != NULL) {
184 	if (bitmapPtr->resourceRefCount == 0) {
185 	    /*
186 	     * This is a stale reference: it refers to a TkBitmap that's
187 	     * no longer in use.  Clear the reference.
188 	     */
189 
190 	    FreeBitmapObjProc(objPtr);
191 	    bitmapPtr = NULL;
192 	} else if ( (Tk_Display(tkwin) == bitmapPtr->display)
193 		&& (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum) ) {
194 	    bitmapPtr->resourceRefCount++;
195 	    return bitmapPtr->bitmap;
196 	}
197     }
198 
199     /*
200      * The object didn't point to the TkBitmap that we wanted.  Search
201      * the list of TkBitmaps with the same name to see if one of the
202      * others is the right one.
203      */
204 
205     if (bitmapPtr != NULL) {
206 	TkBitmap *firstBitmapPtr =
207 		(TkBitmap *) Tcl_GetHashValue(bitmapPtr->nameHashPtr);
208 	FreeBitmapObjProc(objPtr);
209 	for (bitmapPtr = firstBitmapPtr; bitmapPtr != NULL;
210 		bitmapPtr = bitmapPtr->nextPtr) {
211 	    if ( (Tk_Display(tkwin) == bitmapPtr->display) &&
212 		    (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum) ) {
213 		bitmapPtr->resourceRefCount++;
214 		bitmapPtr->objRefCount++;
215 		objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr;
216 		return bitmapPtr->bitmap;
217 	    }
218 	}
219     }
220 
221     /*
222      * Still no luck.  Call GetBitmap to allocate a new TkBitmap object.
223      */
224 
225     bitmapPtr = GetBitmap(interp, tkwin, Tcl_GetString(objPtr));
226     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr;
227     if (bitmapPtr == NULL) {
228 	return None;
229     }
230     bitmapPtr->objRefCount++;
231     return bitmapPtr->bitmap;
232 }
233 
234 /*
235  *----------------------------------------------------------------------
236  *
237  * Tk_GetBitmap --
238  *
239  *	Given a string describing a bitmap, locate (or create if necessary)
240  *	a bitmap that fits the description.
241  *
242  * Results:
243  *	The return value is the X identifer for the desired bitmap
244  *	(i.e. a Pixmap with a single plane), unless string couldn't be
245  *	parsed correctly.  In this case, None is returned and an error
246  *	message is left in the interp's result.  The caller should never
247  *	modify the bitmap that is returned, and should eventually call
248  *	Tk_FreeBitmap when the bitmap is no longer needed.
249  *
250  * Side effects:
251  *	The bitmap is added to an internal database with a reference count.
252  *	For each call to this procedure, there should eventually be a call
253  *	to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps
254  *	aren't needed anymore.
255  *
256  *----------------------------------------------------------------------
257  */
258 
259 Pixmap
Tk_GetBitmap(interp,tkwin,string)260 Tk_GetBitmap(interp, tkwin, string)
261     Tcl_Interp *interp;		/* Interpreter to use for error reporting,
262 				 * this may be NULL. */
263     Tk_Window tkwin;		/* Window in which bitmap will be used. */
264     CONST char *string;		/* Description of bitmap.  See manual entry
265 				 * for details on legal syntax. */
266 {
267     TkBitmap *bitmapPtr = GetBitmap(interp, tkwin, string);
268     if (bitmapPtr == NULL) {
269 	return None;
270     }
271     return bitmapPtr->bitmap;
272 }
273 
274 /*
275  *----------------------------------------------------------------------
276  *
277  * GetBitmap --
278  *
279  *	Given a string describing a bitmap, locate (or create if necessary)
280  *	a bitmap that fits the description. This routine returns the
281  *	internal data structure for the bitmap. This avoids extra
282  *	hash table lookups in Tk_AllocBitmapFromObj.
283  *
284  * Results:
285  *	The return value is the X identifer for the desired bitmap
286  *	(i.e. a Pixmap with a single plane), unless string couldn't be
287  *	parsed correctly.  In this case, None is returned and an error
288  *	message is left in the interp's result.  The caller should never
289  *	modify the bitmap that is returned, and should eventually call
290  *	Tk_FreeBitmap when the bitmap is no longer needed.
291  *
292  * Side effects:
293  *	The bitmap is added to an internal database with a reference count.
294  *	For each call to this procedure, there should eventually be a call
295  *	to Tk_FreeBitmap or Tk_FreeBitmapFromObj, so that the database can
296  *	be cleaned up when bitmaps aren't needed anymore.
297  *
298  *----------------------------------------------------------------------
299  */
300 
301 static TkBitmap *
GetBitmap(interp,tkwin,string)302 GetBitmap(interp, tkwin, string)
303     Tcl_Interp *interp;		/* Interpreter to use for error reporting,
304 				 * this may be NULL. */
305     Tk_Window tkwin;		/* Window in which bitmap will be used. */
306     CONST char *string;		/* Description of bitmap.  See manual entry
307 				 * for details on legal syntax. */
308 {
309     Tcl_HashEntry *nameHashPtr, *predefHashPtr;
310     TkBitmap *bitmapPtr, *existingBitmapPtr;
311     TkPredefBitmap *predefPtr;
312     int new;
313     Pixmap bitmap;
314     int width, height;
315     int dummy2;
316     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
317     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
318             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
319 
320     if (!dispPtr->bitmapInit) {
321 	BitmapInit(dispPtr);
322     }
323 
324     nameHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapNameTable, string, &new);
325     if (!new) {
326 	existingBitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr);
327 	for (bitmapPtr = existingBitmapPtr; bitmapPtr != NULL;
328 		bitmapPtr = bitmapPtr->nextPtr) {
329 	    if ( (Tk_Display(tkwin) == bitmapPtr->display) &&
330 		    (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum) ) {
331 		bitmapPtr->resourceRefCount++;
332 		return bitmapPtr;
333 	    }
334 	}
335     } else {
336 	existingBitmapPtr = NULL;
337     }
338 
339     /*
340      * No suitable bitmap exists.  Create a new bitmap from the
341      * information contained in the string.  If the string starts
342      * with "@" then the rest of the string is a file name containing
343      * the bitmap.  Otherwise the string must refer to a bitmap
344      * defined by a call to Tk_DefineBitmap.
345      */
346 
347     if (*string == '@') {	/* INTL: ISO char */
348 	Tcl_DString buffer;
349 	int result;
350 
351         if (Tcl_IsSafe(interp)) {
352             Tcl_AppendResult(interp, "can't specify bitmap with '@' in a",
353                     " safe interpreter", (char *) NULL);
354             goto error;
355         }
356 
357 	/*
358 	 * Note that we need to cast away the CONST from the string because
359 	 * Tcl_TranslateFileName is non const, even though it doesn't modify
360 	 * the string.
361 	 */
362 
363 	string = Tcl_TranslateFileName(interp, (char *) string + 1, &buffer);
364 	if (string == NULL) {
365 	    goto error;
366 	}
367 	result = TkReadBitmapFile(interp, Tk_Display(tkwin),
368 		RootWindowOfScreen(Tk_Screen(tkwin)), string,
369 		(unsigned int *) &width, (unsigned int *) &height,
370 		&bitmap, &dummy2, &dummy2);
371 	if (result != BitmapSuccess) {
372 	    if (interp != NULL) {
373 		Tcl_AppendResult(interp, "error reading bitmap file \"", string,
374 		    "\"", (char *) NULL);
375 	    }
376 	    Tcl_DStringFree(&buffer);
377 	    goto error;
378 	}
379 	Tcl_DStringFree(&buffer);
380     } else {
381 	predefHashPtr = Tcl_FindHashEntry(&tsdPtr->predefBitmapTable,
382                 string);
383 	if (predefHashPtr == NULL) {
384 	    /*
385 	     * The following platform specific call allows the user to
386 	     * define bitmaps that may only exist during run time.  If
387 	     * it returns None nothing was found and we return the error.
388 	     */
389 	    bitmap = TkpGetNativeAppBitmap(Tk_Display(tkwin), string,
390 		    &width, &height);
391 
392 	    if (bitmap == None) {
393 		if (interp != NULL) {
394 		    Tcl_AppendResult(interp, "bitmap \"", string,
395 			"\" not defined", (char *) NULL);
396 		}
397 		goto error;
398 	    }
399 	} else {
400 	    predefPtr = (TkPredefBitmap *) Tcl_GetHashValue(predefHashPtr);
401 	    width = predefPtr->width;
402 	    height = predefPtr->height;
403 	    if (predefPtr->native) {
404 		bitmap = TkpCreateNativeBitmap(Tk_Display(tkwin),
405 		    predefPtr->source);
406 		if (bitmap == None) {
407 		    panic("native bitmap creation failed");
408 		}
409 	    } else {
410 		bitmap = XCreateBitmapFromData(Tk_Display(tkwin),
411 		    RootWindowOfScreen(Tk_Screen(tkwin)),
412 		    predefPtr->source,
413 		    (unsigned) width, (unsigned) height);
414 	    }
415 	}
416     }
417 
418     /*
419      * Add information about this bitmap to our database.
420      */
421 
422     bitmapPtr = (TkBitmap *) ckalloc(sizeof(TkBitmap));
423     bitmapPtr->bitmap = bitmap;
424     bitmapPtr->width = width;
425     bitmapPtr->height = height;
426     bitmapPtr->display = Tk_Display(tkwin);
427     bitmapPtr->screenNum = Tk_ScreenNumber(tkwin);
428     bitmapPtr->resourceRefCount = 1;
429     bitmapPtr->objRefCount = 0;
430     bitmapPtr->nameHashPtr = nameHashPtr;
431     bitmapPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapIdTable,
432             (char *) bitmap, &new);
433     if (!new) {
434 	panic("bitmap already registered in Tk_GetBitmap");
435     }
436     bitmapPtr->nextPtr = existingBitmapPtr;
437     Tcl_SetHashValue(nameHashPtr, bitmapPtr);
438     Tcl_SetHashValue(bitmapPtr->idHashPtr, bitmapPtr);
439     return bitmapPtr;
440 
441     error:
442     if (new) {
443 	Tcl_DeleteHashEntry(nameHashPtr);
444     }
445     return NULL;
446 }
447 
448 /*
449  *----------------------------------------------------------------------
450  *
451  * Tk_DefineBitmap --
452  *
453  *	This procedure associates a textual name with a binary bitmap
454  *	description, so that the name may be used to refer to the
455  *	bitmap in future calls to Tk_GetBitmap.
456  *
457  * Results:
458  *	A standard Tcl result.  If an error occurs then TCL_ERROR is
459  *	returned and a message is left in the interp's result.
460  *
461  * Side effects:
462  *	"Name" is entered into the bitmap table and may be used from
463  *	here on to refer to the given bitmap.
464  *
465  *----------------------------------------------------------------------
466  */
467 
468 int
Tk_DefineBitmap(interp,name,source,width,height)469 Tk_DefineBitmap(interp, name, source, width, height)
470     Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
471     CONST char *name;		/* Name to use for bitmap.  Must not already
472 				 * be defined as a bitmap. */
473     CONST char *source;		/* Address of bits for bitmap. */
474     int width;			/* Width of bitmap. */
475     int height;			/* Height of bitmap. */
476 {
477     int new;
478     Tcl_HashEntry *predefHashPtr;
479     TkPredefBitmap *predefPtr;
480     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
481             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
482 
483     /*
484      * Initialize the Bitmap module if not initialized already for this
485      * thread.  Since the current TkDisplay structure cannot be
486      * introspected from here, pass a NULL pointer to BitmapInit,
487      * which will know to initialize only the data in the
488      * ThreadSpecificData structure for the current thread.
489      */
490 
491     if (!tsdPtr->initialized) {
492 	BitmapInit((TkDisplay *) NULL);
493     }
494 
495     predefHashPtr = Tcl_CreateHashEntry(&tsdPtr->predefBitmapTable,
496             name, &new);
497     if (!new) {
498         Tcl_AppendResult(interp, "bitmap \"", name,
499 		"\" is already defined", (char *) NULL);
500 	return TCL_ERROR;
501     }
502     predefPtr = (TkPredefBitmap *) ckalloc(sizeof(TkPredefBitmap));
503     predefPtr->source = source;
504     predefPtr->width = width;
505     predefPtr->height = height;
506     predefPtr->native = 0;
507     Tcl_SetHashValue(predefHashPtr, predefPtr);
508     return TCL_OK;
509 }
510 
511 /*
512  *--------------------------------------------------------------
513  *
514  * Tk_NameOfBitmap --
515  *
516  *	Given a bitmap, return a textual string identifying the
517  *	bitmap.
518  *
519  * Results:
520  *	The return value is the string name associated with bitmap.
521  *
522  * Side effects:
523  *	None.
524  *
525  *--------------------------------------------------------------
526  */
527 
528 CONST char *
Tk_NameOfBitmap(display,bitmap)529 Tk_NameOfBitmap(display, bitmap)
530     Display *display;			/* Display for which bitmap was
531 					 * allocated. */
532     Pixmap bitmap;			/* Bitmap whose name is wanted. */
533 {
534     Tcl_HashEntry *idHashPtr;
535     TkBitmap *bitmapPtr;
536     TkDisplay *dispPtr = TkGetDisplay(display);
537 
538     if (dispPtr == NULL || !dispPtr->bitmapInit) {
539 	unknown:
540 	panic("Tk_NameOfBitmap received unknown bitmap argument");
541     }
542 
543     idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap);
544     if (idHashPtr == NULL) {
545 	goto unknown;
546     }
547     bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr);
548     return bitmapPtr->nameHashPtr->key.string;
549 }
550 
551 /*
552  *--------------------------------------------------------------
553  *
554  * Tk_SizeOfBitmap --
555  *
556  *	Given a bitmap managed by this module, returns the width
557  *	and height of the bitmap.
558  *
559  * Results:
560  *	The words at *widthPtr and *heightPtr are filled in with
561  *	the dimenstions of bitmap.
562  *
563  * Side effects:
564  *	If bitmap isn't managed by this module then the procedure
565  *	panics..
566  *
567  *--------------------------------------------------------------
568  */
569 
570 void
Tk_SizeOfBitmap(display,bitmap,widthPtr,heightPtr)571 Tk_SizeOfBitmap(display, bitmap, widthPtr, heightPtr)
572     Display *display;			/* Display for which bitmap was
573 					 * allocated. */
574     Pixmap bitmap;			/* Bitmap whose size is wanted. */
575     int *widthPtr;			/* Store bitmap width here. */
576     int *heightPtr;			/* Store bitmap height here. */
577 {
578     Tcl_HashEntry *idHashPtr;
579     TkBitmap *bitmapPtr;
580     TkDisplay *dispPtr = TkGetDisplay(display);
581 
582     if (!dispPtr->bitmapInit) {
583 	unknownBitmap:
584 	panic("Tk_SizeOfBitmap received unknown bitmap argument");
585     }
586 
587     idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap);
588     if (idHashPtr == NULL) {
589 	goto unknownBitmap;
590     }
591     bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr);
592     *widthPtr = bitmapPtr->width;
593     *heightPtr = bitmapPtr->height;
594 }
595 
596 /*
597  *----------------------------------------------------------------------
598  *
599  * FreeBitmap --
600  *
601  *	This procedure does all the work of releasing a bitmap allocated by
602  *	Tk_GetBitmap or TkGetBitmapFromData.  It is invoked by both
603  *	Tk_FreeBitmap and Tk_FreeBitmapFromObj
604  *
605  * Results:
606  *	None.
607  *
608  * Side effects:
609  *	The reference count associated with bitmap is decremented, and
610  *	it is officially deallocated if no-one is using it anymore.
611  *
612  *----------------------------------------------------------------------
613  */
614 
615 static void
FreeBitmap(bitmapPtr)616 FreeBitmap(bitmapPtr)
617     TkBitmap *bitmapPtr;			/* Bitmap to be released. */
618 {
619     TkBitmap *prevPtr;
620 
621     bitmapPtr->resourceRefCount--;
622     if (bitmapPtr->resourceRefCount > 0) {
623 	return;
624     }
625 
626     Tk_FreePixmap(bitmapPtr->display, bitmapPtr->bitmap);
627     Tcl_DeleteHashEntry(bitmapPtr->idHashPtr);
628     prevPtr = (TkBitmap *) Tcl_GetHashValue(bitmapPtr->nameHashPtr);
629     if (prevPtr == bitmapPtr) {
630 	if (bitmapPtr->nextPtr == NULL) {
631 	    Tcl_DeleteHashEntry(bitmapPtr->nameHashPtr);
632 	} else {
633 	    Tcl_SetHashValue(bitmapPtr->nameHashPtr, bitmapPtr->nextPtr);
634 	}
635     } else {
636 	while (prevPtr->nextPtr != bitmapPtr) {
637 	    prevPtr = prevPtr->nextPtr;
638 	}
639 	prevPtr->nextPtr = bitmapPtr->nextPtr;
640     }
641     if (bitmapPtr->objRefCount == 0) {
642 	ckfree((char *) bitmapPtr);
643     }
644 }
645 
646 /*
647  *----------------------------------------------------------------------
648  *
649  * Tk_FreeBitmap --
650  *
651  *	This procedure is called to release a bitmap allocated by
652  *	Tk_GetBitmap or TkGetBitmapFromData.
653  *
654  * Results:
655  *	None.
656  *
657  * Side effects:
658  *	The reference count associated with bitmap is decremented, and
659  *	it is officially deallocated if no-one is using it anymore.
660  *
661  *----------------------------------------------------------------------
662  */
663 
664 void
Tk_FreeBitmap(display,bitmap)665 Tk_FreeBitmap(display, bitmap)
666     Display *display;			/* Display for which bitmap was
667 					 * allocated. */
668     Pixmap bitmap;			/* Bitmap to be released. */
669 {
670     Tcl_HashEntry *idHashPtr;
671     TkDisplay *dispPtr = TkGetDisplay(display);
672 
673     if (!dispPtr->bitmapInit) {
674 	panic("Tk_FreeBitmap called before Tk_GetBitmap");
675     }
676 
677     idHashPtr = Tcl_FindHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap);
678     if (idHashPtr == NULL) {
679 	panic("Tk_FreeBitmap received unknown bitmap argument");
680     }
681     FreeBitmap((TkBitmap *) Tcl_GetHashValue(idHashPtr));
682 }
683 
684 /*
685  *----------------------------------------------------------------------
686  *
687  * Tk_FreeBitmapFromObj --
688  *
689  *	This procedure is called to release a bitmap allocated by
690  *	Tk_AllocBitmapFromObj. It does not throw away the Tcl_Obj *;
691  *	it only gets rid of the hash table entry for this bitmap
692  *	and clears the cached value that is normally stored in the object.
693  *
694  * Results:
695  *	None.
696  *
697  * Side effects:
698  *	The reference count associated with the bitmap represented by
699  *	objPtr is decremented, and the bitmap is released to X if there are
700  *	no remaining uses for it.
701  *
702  *----------------------------------------------------------------------
703  */
704 
705 void
Tk_FreeBitmapFromObj(tkwin,objPtr)706 Tk_FreeBitmapFromObj(tkwin, objPtr)
707     Tk_Window tkwin;		/* The window this bitmap lives in. Needed
708 				 * for the display value. */
709     Tcl_Obj *objPtr;		/* The Tcl_Obj * to be freed. */
710 {
711     FreeBitmap(GetBitmapFromObj(tkwin, objPtr));
712 }
713 
714 /*
715  *---------------------------------------------------------------------------
716  *
717  * FreeBitmapObjProc --
718  *
719  *	This proc is called to release an object reference to a bitmap.
720  *	Called when the object's internal rep is released or when
721  *	the cached bitmapPtr needs to be changed.
722  *
723  * Results:
724  *	None.
725  *
726  * Side effects:
727  *	The object reference count is decremented. When both it
728  *	and the hash ref count go to zero, the color's resources
729  *	are released.
730  *
731  *---------------------------------------------------------------------------
732  */
733 
734 static void
FreeBitmapObjProc(objPtr)735 FreeBitmapObjProc(objPtr)
736     Tcl_Obj *objPtr;		/* The object we are releasing. */
737 {
738     TkBitmap *bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1;
739 
740     if (bitmapPtr != NULL) {
741 	bitmapPtr->objRefCount--;
742 	if ((bitmapPtr->objRefCount == 0)
743 		&& (bitmapPtr->resourceRefCount == 0)) {
744 	    ckfree((char *) bitmapPtr);
745 	}
746 	objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL;
747     }
748 }
749 
750 /*
751  *---------------------------------------------------------------------------
752  *
753  * DupBitmapObjProc --
754  *
755  *	When a cached bitmap object is duplicated, this is called to
756  *	update the internal reps.
757  *
758  * Results:
759  *	None.
760  *
761  * Side effects:
762  *	The color's objRefCount is incremented and the internal rep
763  *	of the copy is set to point to it.
764  *
765  *---------------------------------------------------------------------------
766  */
767 
768 static void
DupBitmapObjProc(srcObjPtr,dupObjPtr)769 DupBitmapObjProc(srcObjPtr, dupObjPtr)
770     Tcl_Obj *srcObjPtr;		/* The object we are copying from. */
771     Tcl_Obj *dupObjPtr;		/* The object we are copying to. */
772 {
773     TkBitmap *bitmapPtr = (TkBitmap *) srcObjPtr->internalRep.twoPtrValue.ptr1;
774 
775     dupObjPtr->typePtr = srcObjPtr->typePtr;
776     dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr;
777 
778     if (bitmapPtr != NULL) {
779 	bitmapPtr->objRefCount++;
780     }
781 }
782 
783 /*
784  *----------------------------------------------------------------------
785  *
786  * Tk_GetBitmapFromData --
787  *
788  *	Given a description of the bits for a bitmap, make a bitmap that
789  *	has the given properties. *** NOTE:  this procedure is obsolete
790  *	and really shouldn't be used anymore. ***
791  *
792  * Results:
793  *	The return value is the X identifer for the desired bitmap
794  *	(a one-plane Pixmap), unless it couldn't be created properly.
795  *	In this case, None is returned and an error message is left in
796  *	the interp's result.  The caller should never modify the bitmap that
797  *	is returned, and should eventually call Tk_FreeBitmap when the
798  *	bitmap is no longer needed.
799  *
800  * Side effects:
801  *	The bitmap is added to an internal database with a reference count.
802  *	For each call to this procedure, there should eventually be a call
803  *	to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps
804  *	aren't needed anymore.
805  *
806  *----------------------------------------------------------------------
807  */
808 
809 	/* ARGSUSED */
810 Pixmap
Tk_GetBitmapFromData(interp,tkwin,source,width,height)811 Tk_GetBitmapFromData(interp, tkwin, source, width, height)
812     Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
813     Tk_Window tkwin;		/* Window in which bitmap will be used. */
814     CONST char *source;		/* Bitmap data for bitmap shape. */
815     int width, height;		/* Dimensions of bitmap. */
816 {
817     DataKey nameKey;
818     Tcl_HashEntry *dataHashPtr;
819     int new;
820     char string[16 + TCL_INTEGER_SPACE];
821     char *name;
822     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
823 
824     BitmapInit(dispPtr);
825 
826     nameKey.source = source;
827     nameKey.width = width;
828     nameKey.height = height;
829     dataHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapDataTable,
830             (char *) &nameKey, &new);
831     if (!new) {
832 	name = (char *) Tcl_GetHashValue(dataHashPtr);
833     } else {
834 	dispPtr->bitmapAutoNumber++;
835 	sprintf(string, "_tk%d", dispPtr->bitmapAutoNumber);
836 	name = string;
837 	Tcl_SetHashValue(dataHashPtr, name);
838 	if (Tk_DefineBitmap(interp, name, source, width, height) != TCL_OK) {
839 	    Tcl_DeleteHashEntry(dataHashPtr);
840 	    return TCL_ERROR;
841 	}
842     }
843     return Tk_GetBitmap(interp, tkwin, name);
844 }
845 
846 /*
847  *----------------------------------------------------------------------
848  *
849  * Tk_GetBitmapFromObj --
850  *
851  *	Returns the bitmap referred to by a Tcl object.  The bitmap must
852  *	already have been allocated via a call to Tk_AllocBitmapFromObj
853  *	or Tk_GetBitmap.
854  *
855  * Results:
856  *	Returns the Pixmap that matches the tkwin and the string rep
857  *	of objPtr.
858  *
859  * Side effects:
860  *	If the object is not already a bitmap, the conversion will free
861  *	any old internal representation.
862  *
863  *----------------------------------------------------------------------
864  */
865 
866 Pixmap
Tk_GetBitmapFromObj(tkwin,objPtr)867 Tk_GetBitmapFromObj(tkwin, objPtr)
868     Tk_Window tkwin;
869     Tcl_Obj *objPtr;		/* The object from which to get pixels. */
870 {
871     TkBitmap *bitmapPtr = GetBitmapFromObj(tkwin, objPtr);
872     return bitmapPtr->bitmap;
873 }
874 
875 /*
876  *----------------------------------------------------------------------
877  *
878  * GetBitmapFromObj --
879  *
880  *	Returns the bitmap referred to by a Tcl object.  The bitmap must
881  *	already have been allocated via a call to Tk_AllocBitmapFromObj
882  *	or Tk_GetBitmap.
883  *
884  * Results:
885  *	Returns the TkBitmap * that matches the tkwin and the string rep
886  *	of  objPtr.
887  *
888  * Side effects:
889  *	If the object is not already a bitmap, the conversion will free
890  *	any old internal representation.
891  *
892  *----------------------------------------------------------------------
893  */
894 
895 static TkBitmap *
GetBitmapFromObj(tkwin,objPtr)896 GetBitmapFromObj(tkwin, objPtr)
897     Tk_Window tkwin;		/* Window in which the bitmap will be used. */
898     Tcl_Obj *objPtr;		/* The object that describes the desired
899 				 * bitmap. */
900 {
901     TkBitmap *bitmapPtr;
902     Tcl_HashEntry *hashPtr;
903     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
904 
905     if (objPtr->typePtr != &tkBitmapObjType) {
906 	InitBitmapObj(objPtr);
907     }
908 
909     bitmapPtr = (TkBitmap *) objPtr->internalRep.twoPtrValue.ptr1;
910     if (bitmapPtr != NULL) {
911 	if ((bitmapPtr->resourceRefCount > 0)
912 		&& (Tk_Display(tkwin) == bitmapPtr->display)) {
913 	    return bitmapPtr;
914 	}
915 	hashPtr = bitmapPtr->nameHashPtr;
916 	FreeBitmapObjProc(objPtr);
917     } else {
918 	hashPtr = Tcl_FindHashEntry(&dispPtr->bitmapNameTable,
919                 Tcl_GetString(objPtr));
920 	if (hashPtr == NULL) {
921 	    goto error;
922 	}
923     }
924 
925     /*
926      * At this point we've got a hash table entry, off of which hang
927      * one or more TkBitmap structures.  See if any of them will work.
928      */
929 
930     for (bitmapPtr = (TkBitmap *) Tcl_GetHashValue(hashPtr);
931 	    bitmapPtr != NULL;  bitmapPtr = bitmapPtr->nextPtr) {
932 	if (Tk_Display(tkwin) == bitmapPtr->display) {
933 	    objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) bitmapPtr;
934 	    bitmapPtr->objRefCount++;
935 	    return bitmapPtr;
936 	}
937     }
938 
939     error:
940     panic("GetBitmapFromObj called with non-existent bitmap!");
941     /*
942      * The following code isn't reached; it's just there to please compilers.
943      */
944     return NULL;
945 }
946 
947 /*
948  *----------------------------------------------------------------------
949  *
950  * InitBitmapObj --
951  *
952  *	Bookeeping procedure to change an objPtr to a bitmap type.
953  *
954  * Results:
955  *	None.
956  *
957  * Side effects:
958  *	The old internal rep of the object is freed. The internal
959  *	rep is cleared. The final form of the object is set
960  *	by either Tk_AllocBitmapFromObj or GetBitmapFromObj.
961  *
962  *----------------------------------------------------------------------
963  */
964 
965 static void
InitBitmapObj(objPtr)966 InitBitmapObj(objPtr)
967     Tcl_Obj *objPtr;		/* The object to convert. */
968 {
969     Tcl_ObjType *typePtr;
970 
971     /*
972      * Free the old internalRep before setting the new one.
973      */
974 
975     Tcl_GetString(objPtr);
976     typePtr = objPtr->typePtr;
977     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
978 	(*typePtr->freeIntRepProc)(objPtr);
979     }
980     TclObjSetType(objPtr,&tkBitmapObjType);
981     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL;
982 }
983 
984 /*
985  *----------------------------------------------------------------------
986  *
987  * BitmapInit --
988  *	Initializes hash tables used by this module.  Initializes
989  *      tables stored in TkDisplay structure if a TkDisplay pointer
990  *      is passed in.  Iinitializes the thread-local data
991  *      in the current thread's ThreadSpecificData structure.
992  *
993  * Results:
994  *      None.
995  *
996  * Side effects:
997  *	Read the code.
998  *
999  *----------------------------------------------------------------------
1000  */
1001 
1002 static void
BitmapInit(dispPtr)1003 BitmapInit(dispPtr)
1004     TkDisplay *dispPtr;         /* TkDisplay structure encapsulating
1005 				 * thread-specific data used by this
1006 				 * module, or NULL if unavailable. */
1007 {
1008     Tcl_Interp *dummy;
1009     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1010             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1011 
1012     /*
1013      * First initialize the data in the ThreadSpecificData strucuture,
1014      * if needed.
1015      */
1016 
1017     if (!tsdPtr->initialized) {
1018 	tsdPtr->initialized = 1;
1019         dummy = Tcl_CreateInterp();
1020 	Tcl_InitHashTable(&tsdPtr->predefBitmapTable, TCL_STRING_KEYS);
1021 
1022         Tk_DefineBitmap(dummy, "error", (char *) error_bits,
1023 		error_width, error_height);
1024         Tk_DefineBitmap(dummy, "gray75", (char *) gray75_bits,
1025                 gray75_width, gray75_height);
1026         Tk_DefineBitmap(dummy, "gray50", (char *) gray50_bits,
1027                 gray50_width, gray50_height);
1028         Tk_DefineBitmap(dummy, "gray25", (char *) gray25_bits,
1029                 gray25_width, gray25_height);
1030         Tk_DefineBitmap(dummy, "gray12", (char *) gray12_bits,
1031                 gray12_width, gray12_height);
1032         Tk_DefineBitmap(dummy, "hourglass", (char *) hourglass_bits,
1033                 hourglass_width, hourglass_height);
1034         Tk_DefineBitmap(dummy, "info", (char *) info_bits,
1035 	        info_width, info_height);
1036         Tk_DefineBitmap(dummy, "questhead", (char *) questhead_bits,
1037 	        questhead_width, questhead_height);
1038         Tk_DefineBitmap(dummy, "question", (char *) question_bits,
1039 	        question_width, question_height);
1040         Tk_DefineBitmap(dummy, "warning", (char *) warning_bits,
1041 	        warning_width, warning_height);
1042 
1043         Tk_DefineBitmap(dummy, "transparent", (char *) transparent_bits,
1044 	        transparent_width, transparent_height);
1045         Tk_DefineBitmap(dummy, "Tk", (char *) Tkbmp_bits,
1046 	        Tkbmp_width, Tkbmp_height);
1047 
1048         TkpDefineNativeBitmaps();
1049         Tcl_DeleteInterp(dummy);
1050     }
1051 
1052     /*
1053      * Was a valid TkDisplay pointer passed?  If so, initialize the
1054      * Bitmap module tables in that structure.
1055      */
1056 
1057     if (dispPtr != NULL) {
1058         dispPtr->bitmapInit = 1;
1059 	Tcl_InitHashTable(&dispPtr->bitmapNameTable, TCL_STRING_KEYS);
1060 	Tcl_InitHashTable(&dispPtr->bitmapDataTable, sizeof(DataKey)
1061                 /sizeof(int));
1062 
1063 	/*
1064 	 * The call below is tricky:  can't use sizeof(IdKey) because it
1065 	 * gets padded with extra unpredictable bytes on some 64-bit
1066 	 * machines.
1067 	 */
1068 
1069 	/*
1070 	 * The comment above doesn't make sense...
1071 	 */
1072 	Tcl_InitHashTable(&dispPtr->bitmapIdTable, TCL_ONE_WORD_KEYS);
1073     }
1074 }
1075 
1076 /*
1077  *----------------------------------------------------------------------
1078  *
1079  * TkReadBitmapFile --
1080  *
1081  *	Loads a bitmap image in X bitmap format into the specified
1082  *	drawable.  This is equivelent to the XReadBitmapFile in X.
1083  *
1084  * Results:
1085  *	Sets the size, hotspot, and bitmap on success.
1086  *
1087  * Side effects:
1088  *	Creates a new bitmap from the file data.
1089  *
1090  *----------------------------------------------------------------------
1091  */
1092 
1093 int
TkReadBitmapFile(interp,display,d,filename,width_return,height_return,bitmap_return,x_hot_return,y_hot_return)1094 TkReadBitmapFile(interp, display, d, filename, width_return, height_return,
1095 	bitmap_return, x_hot_return, y_hot_return)
1096     Tcl_Interp *interp;
1097     Display* display;
1098     Drawable d;
1099     CONST char* filename;
1100     unsigned int* width_return;
1101     unsigned int* height_return;
1102     Pixmap* bitmap_return;
1103     int* x_hot_return;
1104     int* y_hot_return;
1105 {
1106     char *data;
1107 
1108     data = TkGetBitmapData(interp, NULL, (char *) filename,
1109 	    (int *) width_return, (int *) height_return, x_hot_return,
1110 	    y_hot_return);
1111     if (data == NULL) {
1112 	return BitmapFileInvalid;
1113     }
1114 
1115     *bitmap_return = XCreateBitmapFromData(display, d, data, *width_return,
1116 	    *height_return);
1117 
1118     ckfree(data);
1119     return BitmapSuccess;
1120   }
1121 
1122 /*
1123  *----------------------------------------------------------------------
1124  *
1125  * TkDebugBitmap --
1126  *
1127  *	This procedure returns debugging information about a bitmap.
1128  *
1129  * Results:
1130  *	The return value is a list with one sublist for each TkBitmap
1131  *	corresponding to "name".  Each sublist has two elements that
1132  *	contain the resourceRefCount and objRefCount fields from the
1133  *	TkBitmap structure.
1134  *
1135  * Side effects:
1136  *	None.
1137  *
1138  *----------------------------------------------------------------------
1139  */
1140 
1141 Tcl_Obj *
TkDebugBitmap(tkwin,name)1142 TkDebugBitmap(tkwin, name)
1143     Tk_Window tkwin;		/* The window in which the bitmap will be
1144 				 * used (not currently used). */
1145     char *name;			/* Name of the desired color. */
1146 {
1147     TkBitmap *bitmapPtr;
1148     Tcl_HashEntry *hashPtr;
1149     Tcl_Obj *resultPtr, *objPtr;
1150     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
1151 
1152     resultPtr = Tcl_NewObj();
1153     hashPtr = Tcl_FindHashEntry(&dispPtr->bitmapNameTable, name);
1154     if (hashPtr != NULL) {
1155 	bitmapPtr = (TkBitmap *) Tcl_GetHashValue(hashPtr);
1156 	if (bitmapPtr == NULL) {
1157 	    panic("TkDebugBitmap found empty hash table entry");
1158 	}
1159 	for ( ; (bitmapPtr != NULL); bitmapPtr = bitmapPtr->nextPtr) {
1160 	    objPtr = Tcl_NewObj();
1161 	    Tcl_ListObjAppendElement(NULL, objPtr,
1162 		    Tcl_NewIntObj(bitmapPtr->resourceRefCount));
1163 	    Tcl_ListObjAppendElement(NULL, objPtr,
1164 		    Tcl_NewIntObj(bitmapPtr->objRefCount));
1165 	    Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
1166 	}
1167     }
1168     return resultPtr;
1169 }
1170 
1171 
1172 /*
1173  *----------------------------------------------------------------------
1174  *
1175  * TkGetBitmapPredefTable --
1176  *      This procedure is used by tkMacBitmap.c to access the thread-
1177  *      specific predefBitmap table that maps from the names of
1178  *      the predefined bitmaps to data associated with those
1179  *      bitmaps.  It is required because the table is allocated in
1180  *      thread-local storage and is not visible outside this file.
1181 
1182  * Results:
1183  *      Returns a pointer to the predefined bitmap hash table for
1184  *      the current thread.
1185  *
1186  * Side effects:
1187  *	None.
1188  *
1189  *----------------------------------------------------------------------
1190  */
1191 Tcl_HashTable *
TkGetBitmapPredefTable()1192 TkGetBitmapPredefTable()
1193 {
1194     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
1195             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
1196 
1197     return &tsdPtr->predefBitmapTable;
1198 }
1199 
1200