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