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