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