4 * This file maintains a database of read-only pixmaps for the Tk
5 * toolkit. This allows pixmaps to be shared between widgets and
6 * also avoids interactions with the X server.
8 * Copyright 1992 by Sven Delmas
10 * This source is based upon the file tkBitmap.c from:
12 * Copyright 1990-1992 Regents of the University of California
13 * Permission to use, copy, modify, and distribute this
14 * software and its documentation for any purpose and without
15 * fee is hereby granted, provided that the above copyright
16 * notice appear in all copies. The University of California
17 * makes no representations about the suitability of this
18 * software for any purpose. It is provided "as is" without
19 * express or implied warranty.
20 * file: /user6/ouster/wish/RCS/tkBitmap.c,v 1.16
21 * 92/08/24 09:45:43 ouster Exp $ SPRITE (Berkeley);
27 static char *AtFSid
= "$Header: tkPixmap.c[1.1] Mon Sep 28 14:12:35 1992 garfield@cs.tu-berlin.de frozen $";
34 * The includes below are for pre-defined bitmaps.
37 #include "bitmaps/gray50"
38 #include "bitmaps/gray25"
41 * Include the xpm 3 defines for color pixmaps
47 * One of the following data structures exists for each bitmap that is
48 * currently in use. Each structure is indexed with both "idTable" and
53 Pixmap bitmap
; /* X identifier for bitmap. None means this
54 * bitmap was created by Tk_DefinePixmap
55 * and it isn't currently in use. */
56 unsigned int width
, height
; /* Dimensions of bitmap. */
57 Display
*display
; /* Display for which bitmap is valid. */
58 int refCount
; /* Number of active uses of bitmap. */
59 Tcl_HashEntry
*hashPtr
; /* Entry in nameTable for this structure
60 * (needed when deleting). */
64 * Hash table to map from a textual description of a bitmap to the
65 * TkBitmap record for the bitmap, and key structure used in that
69 static Tcl_HashTable nameTable
;
71 Tk_Uid name
; /* Textual name for desired bitmap. */
72 Screen
*screen
; /* Screen for which bitmap will be used. */
76 * Hash table that maps from bitmap identifiers to the TkBitmap structure
77 * for the pixmap. This table is indexed by Bitmap ids, and is used by
81 static Tcl_HashTable idTable
;
84 * For each call to Tk_DefinePixmap one of the following structures is
85 * created to hold information about the pixmap.
89 char *source
; /* Bits for bitmap. */
90 Pixmap pixmap
; /* Pre-defined pixmap */
91 unsigned int width
, height
; /* Dimensions of bitmap. */
95 * Hash table create by Tk_DefinePixmap to map from a name to a
96 * collection of in-core data about a bitmap. The table is
97 * indexed by the address of the data for the bitmap, and the entries
98 * contain pointers to PredefBitmap structures.
101 static Tcl_HashTable predefTable
;
104 * Hash table used by Tk_GetPixmapFromData to map from a collection
105 * of in-core data about a bitmap to a Tk_Uid giving an automatically-
106 * generated name for the bitmap:
109 static Tcl_HashTable dataTable
;
111 char *source
; /* Bitmap bits. */
112 unsigned int width
, height
; /* Dimensions of bitmap. */
115 static int initialized
= 0; /* 0 means static structures haven't been
116 * initialized yet. */
119 * Forward declarations for procedures defined in this file:
122 static void PixmapInit
_ANSI_ARGS_((Tk_Window tkwin
));
125 *----------------------------------------------------------------------
129 * Given a string describing a bitmap or pixmap, locate (or create
130 * if necessary) a pixmap that fits the description.
133 * The return value is the X identifer for the desired pixmap,
134 * unless string couldn't be parsed correctly. In this case,
135 * None is returned and an error message is left in
136 * interp->result. The caller should never modify the pixmap
137 * that is returned, and should eventually call Tk_FreePixmap
138 * when the pixmap is no longer needed.
141 * The pixmap is added to an internal database with a reference count.
142 * For each call to this procedure, there should eventually be a call
143 * to Tk_FreePixmap, so that the database can be cleaned up when pixmaps
144 * aren't needed anymore.
146 *----------------------------------------------------------------------
150 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
151 Tk_Window tkwin
, /* Window in which pixmap will be used. */
152 Tk_Uid string
/* Description of pixmap. See manual entry
153 * for details on legal syntax. */
157 Tcl_HashEntry
*nameHashPtr
, *idHashPtr
, *predefHashPtr
;
158 register TkBitmap
*bitmapPtr
;
159 PredefBitmap
*predefPtr
;
163 unsigned int width
, height
;
165 XpmAttributes xpm_attributes
;
166 Display
*dpy
= Tk_Display(tkwin
);
173 key
.screen
= Tk_Screen(tkwin
);
174 nameHashPtr
= Tcl_CreateHashEntry(&nameTable
, (char *) &key
, &new);
176 bitmapPtr
= (TkBitmap
*) Tcl_GetHashValue(nameHashPtr
);
177 bitmapPtr
->refCount
++;
178 return bitmapPtr
->bitmap
;
182 * No suitable bitmap exists. Create a new bitmap from the
183 * information contained in the string. If the string starts
184 * with "@" then the rest of the string is a file name containing
185 * the bitmap. Otherwise the string must refer to a bitmap
186 * defined by a call to Tk_DefinePixmap.
189 if (*string
== '@') {
190 string
= Tcl_TildeSubst(interp
, string
+ 1);
191 if (string
== NULL
) {
195 if (XReadBitmapFile(dpy
, RootWindowOfScreen(Tk_Screen(tkwin
)),
196 string
, &width
, &height
, &bitmap_shape
, &dummy2
, &dummy2
)
199 xpm_attributes
.visual
= Tk_DefaultVisual(Tk_Screen(tkwin
));
200 xpm_attributes
.colormap
= Tk_DefaultColormap(Tk_Screen(tkwin
));
201 xpm_attributes
.depth
= Tk_DefaultDepth(Tk_Screen(tkwin
));
202 xpm_attributes
.valuemask
= XpmVisual
| XpmColormap
| XpmDepth
;
204 if (XpmReadFileToPixmap(dpy
, RootWindowOfScreen(Tk_Screen(tkwin
)),
205 string
, &bitmap
, &bitmap_shape
,
206 &xpm_attributes
) != BitmapSuccess
) {
207 Tcl_AppendResult(interp
, "error reading bitmap file \"",
208 string
, "\"", (char *) NULL
);
211 width
= xpm_attributes
.width
;
212 height
= xpm_attributes
.height
;
213 XpmFreeAttributes(&xpm_attributes
);
216 bitmap
= XCreatePixmap(dpy
, RootWindowOfScreen(Tk_Screen(tkwin
)),
218 Tk_DefaultDepth(Tk_Screen(tkwin
)));
219 XCopyPlane(dpy
, bitmap_shape
, bitmap
,
220 Tk_DefaultGC(Tk_Screen(tkwin
)),
221 0, 0, width
, height
, 0, 0, 1);
224 /* first try for a display-specific version */
225 predefHashPtr
= Tcl_FindHashEntry(&predefTable
, (char *) &key
);
226 if (predefHashPtr
== NULL
) {
227 /* try for a non-display specific version */
228 key
.screen
= (Screen
*) NULL
;
229 predefHashPtr
= Tcl_FindHashEntry(&predefTable
, (char *) &key
);
230 if (predefHashPtr
== NULL
) {
232 Tcl_AppendResult(interp
, "pixmap \"", string
,
233 "\" not defined", (char *) NULL
);
237 predefPtr
= (PredefBitmap
*) Tcl_GetHashValue(predefHashPtr
);
238 width
= predefPtr
->width
;
239 height
= predefPtr
->height
;
240 if (predefPtr
->source
!= NULL
) {
242 XCreateBitmapFromData(dpy
, Tk_DefaultRootWindow(dpy
),
243 predefPtr
->source
, width
, height
);
244 bitmap
= XCreatePixmap(dpy
, RootWindowOfScreen(Tk_Screen(tkwin
)),
246 Tk_DefaultDepth(Tk_Screen(tkwin
)));
247 XCopyPlane(dpy
, bitmap_shape
, bitmap
,
248 Tk_DefaultGC(Tk_Screen(tkwin
)),
249 0, 0, width
, height
, 0, 0, 1);
251 if (predefPtr
->pixmap
!= None
) {
252 bitmap
= predefPtr
->pixmap
;
255 XCreatePixmap(dpy
, RootWindowOfScreen(Tk_Screen(tkwin
)),
257 Tk_DefaultDepth(Tk_Screen(tkwin
)));
263 * Add information about this bitmap to our database.
266 bitmapPtr
= (TkBitmap
*) ckalloc(sizeof(TkBitmap
));
267 bitmapPtr
->bitmap
= bitmap
;
268 bitmapPtr
->width
= width
;
269 bitmapPtr
->height
= height
;
270 bitmapPtr
->display
= dpy
;
271 bitmapPtr
->refCount
= 1;
272 bitmapPtr
->hashPtr
= nameHashPtr
;
273 idHashPtr
= Tcl_CreateHashEntry(&idTable
, (char *) bitmapPtr
->bitmap
,
276 /* deh patched to support multiple displays */
277 /* panic("pixmap already registered in Tk_GetPixmap"); */
278 bitmapPtr
->refCount
= 1000;
280 Tcl_SetHashValue(nameHashPtr
, bitmapPtr
);
281 Tcl_SetHashValue(idHashPtr
, bitmapPtr
);
282 return bitmapPtr
->bitmap
;
285 Tcl_DeleteHashEntry(nameHashPtr
);
290 *----------------------------------------------------------------------
294 * This procedure associates a textual name with a binary pixmap
295 * description, so that the name may be used to refer to the
296 * pixmap in future calls to Tk_GetPixmap. The pixmap can
297 * be pre-created by the user, or can be created later
298 * by Tk_GetPixmap(). Since pixmaps are display-specific,
299 * a user supplied pixmap will be associated with tkwin's display.
300 * If pixmap is given as None, then a new pixmap will be created
301 * by Tk_GetPixmap for each unique display.
304 * A standard Tcl result. If an error occurs then TCL_ERROR is
305 * returned and a message is left in interp->result.
308 * "Name" is entered into the pixmap table and may be used from
309 * here on to refer to the given pixmap.
311 *----------------------------------------------------------------------
316 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
317 Tk_Uid name
, /* Name to use for bitmap. Must not already
318 * be defined as a bitmap. */
319 Tk_Window tkwin
, /* any window on screen where pixmap lives */
320 Pixmap pixmap
, /* pixmap to associate with name,
321 * or None to create a new pixmap */
322 char *source
, /* Address of bits for bitmap. */
323 unsigned int width
, /* Width of bitmap. */
324 unsigned int height
/* Height of bitmap. */
328 Tcl_HashEntry
*predefHashPtr
;
329 PredefBitmap
*predefPtr
;
337 key
.screen
= (pixmap
!= None
) ? Tk_Screen(tkwin
) : (Screen
*)NULL
;
338 predefHashPtr
= Tcl_CreateHashEntry(&predefTable
, (char *) &key
, &new);
340 Tcl_AppendResult(interp
, "bitmap \"", name
,
341 "\" is already defined", (char *) NULL
);
344 predefPtr
= (PredefBitmap
*) malloc(sizeof(PredefBitmap
));
345 predefPtr
->source
= source
;
346 predefPtr
->pixmap
= pixmap
;
347 predefPtr
->width
= width
;
348 predefPtr
->height
= height
;
349 Tcl_SetHashValue(predefHashPtr
, predefPtr
);
354 *--------------------------------------------------------------
358 * Given a pixmap, return a textual string identifying the
362 * The return value is the string name associated with pixmap.
367 *--------------------------------------------------------------
372 Pixmap bitmap
/* Bitmap whose name is wanted. */
375 Tcl_HashEntry
*idHashPtr
;
380 panic("Tk_NameOfPixmap received unknown pixmap argument");
383 idHashPtr
= Tcl_FindHashEntry(&idTable
, (char *) bitmap
);
384 if (idHashPtr
== NULL
) {
387 bitmapPtr
= (TkBitmap
*) Tcl_GetHashValue(idHashPtr
);
388 if (bitmapPtr
->hashPtr
== NULL
) {
389 /* the bitmap has been un-defined */
390 return Tk_GetUid("UndefinedBitmap");
392 return ((NameKey
*) bitmapPtr
->hashPtr
->key
.words
)->name
;
396 *--------------------------------------------------------------
400 * Given a pixmap managed by this module, returns the width
401 * and height of the pixmap..
404 * The words at *widthPtr and *heightPtr are filled in with
405 * the dimenstions of pixmap.
408 * If pixmap isn't managed by this module then the procedure
411 *--------------------------------------------------------------
416 Pixmap bitmap
, /* Bitmap whose size is wanted. */
417 unsigned int *widthPtr
, /* Store bitmap width here. */
418 unsigned int *heightPtr
/* Store bitmap height here. */
421 Tcl_HashEntry
*idHashPtr
;
426 panic("Tk_SizeOfPixmap received unknown pixmap argument");
429 idHashPtr
= Tcl_FindHashEntry(&idTable
, (char *) bitmap
);
430 if (idHashPtr
== NULL
) {
433 bitmapPtr
= (TkBitmap
*) Tcl_GetHashValue(idHashPtr
);
434 *widthPtr
= bitmapPtr
->width
;
435 *heightPtr
= bitmapPtr
->height
;
439 *----------------------------------------------------------------------
443 * This procedure is called to release a pixmap allocated by
450 * The reference count associated with bitmap is decremented, and
451 * it is officially deallocated if no-one is using it anymore.
453 *----------------------------------------------------------------------
458 Pixmap bitmap
/* Bitmap to be released. */
461 Tcl_HashEntry
*idHashPtr
;
462 register TkBitmap
*bitmapPtr
;
465 panic("Tk_FreePixmap called before Tk_GetPixmap");
468 idHashPtr
= Tcl_FindHashEntry(&idTable
, (char *) bitmap
);
469 if (idHashPtr
== NULL
) {
470 panic("Tk_FreePixmap received unknown pixmap argument");
472 bitmapPtr
= (TkBitmap
*) Tcl_GetHashValue(idHashPtr
);
473 bitmapPtr
->refCount
--;
474 if (bitmapPtr
->refCount
== 0) {
475 XFreePixmap(bitmapPtr
->display
, bitmapPtr
->bitmap
);
476 Tcl_DeleteHashEntry(idHashPtr
);
477 if (bitmapPtr
->hashPtr
!= NULL
) {
478 /* If hashPtr is NULL, the bitmap has been undefined,
479 * and already removed from the name table */
480 Tcl_DeleteHashEntry(bitmapPtr
->hashPtr
);
482 ckfree((char *) bitmapPtr
);
487 *----------------------------------------------------------------------
489 * Tk_GetPixmapFromData --
491 * Given a description of the bits for a pixmap, make a pixmap that
492 * has the given properties.
495 * The return value is the X identifer for the desired pixmap,
496 * unless it couldn't be created properly. In this case, None is
497 * returned and an error message is left in interp->result. The
498 * caller should never modify the bitmap that is returned, and
499 * should eventually call Tk_FreePixmap when the pixmap is no
503 * The pixmap is added to an internal database with a reference count.
504 * For each call to this procedure, there should eventually be a call
505 * to Tk_FreePixmap, so that the database can be cleaned up when pixmaps
506 * aren't needed anymore.
508 *----------------------------------------------------------------------
513 Tk_GetPixmapFromData (
514 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
515 Tk_Window tkwin
, /* Window in which bitmap will be used. */
516 char *source
, /* Bitmap data for bitmap shape. */
518 unsigned int height
/* Dimensions of bitmap. */
522 Tcl_HashEntry
*dataHashPtr
;
523 Tk_Uid name
= NULL
; /* Initialization need only to prevent
524 * compiler warning. */
526 static int autoNumber
= 0;
536 dataHashPtr
= Tcl_CreateHashEntry(&dataTable
, (char *) &key
, &new);
538 name
= (Tk_Uid
) Tcl_GetHashValue(dataHashPtr
);
541 sprintf(string
, "_tk%d", autoNumber
);
542 name
= Tk_GetUid(string
);
543 Tcl_SetHashValue(dataHashPtr
, name
);
544 if (Tk_DefinePixmap(interp
, name
, tkwin
, None
, source
, width
,
546 Tcl_DeleteHashEntry(dataHashPtr
);
550 return Tk_GetPixmap(interp
, tkwin
, name
);
554 *----------------------------------------------------------------------
558 * Initialize the structures used for pixmap management.
566 *----------------------------------------------------------------------
571 Tk_Window tkwin
/* any window on screen where pixmap lives */
576 dummy
= Tcl_CreateInterp();
578 Tcl_InitHashTable(&nameTable
, sizeof(NameKey
)/sizeof(int));
579 Tcl_InitHashTable(&dataTable
, sizeof(DataKey
)/sizeof(int));
580 Tcl_InitHashTable(&predefTable
, sizeof(NameKey
)/sizeof(int));
581 Tcl_InitHashTable(&idTable
, TCL_ONE_WORD_KEYS
);
583 Tk_DefinePixmap(dummy
, Tk_GetUid("gray50"), tkwin
, None
,
584 (char *)gray50_bits
, gray50_width
, gray50_height
);
585 Tk_DefinePixmap(dummy
, Tk_GetUid("gray25"), tkwin
, None
,
586 (char *)gray25_bits
, gray25_width
, gray25_height
);
587 Tcl_DeleteInterp(dummy
);
591 *----------------------------------------------------------------------
593 * Tk_UndefinePixmap --
595 * This procedure removes any association "name" with
596 * a bitmap or pixmap. This can be used to undefine
597 * names defined by either Tk_DefinePixmap or Tk_DefinePixmap.
598 * If tkwin is NULL, only display-independent pixmaps will
599 * be removed, otherwise both display-independent and
600 * the pixmap associated with tkwin will be undefined.
603 * A standard Tcl result. If an error occurs then TCL_ERROR is
604 * returned and a message is left in interp->result.
607 * "Name" is removed from the predef table.
609 *----------------------------------------------------------------------
614 Tcl_Interp
*interp
, /* Interpreter to use for error reporting. */
615 Tk_Uid name
, /* Name of bitmap/pixmap to undefine */
616 Tk_Window tkwin
/* any window on screen where pixmap lives */
620 Tcl_HashEntry
*predefHashPtr
, *nameHashPtr
;
629 key
.screen
= (Screen
*) NULL
;
630 predefHashPtr
= Tcl_FindHashEntry(&predefTable
, (char*)&key
);
631 if (predefHashPtr
!= NULL
) {
633 Tcl_DeleteHashEntry(predefHashPtr
);
636 key
.screen
= Tk_Screen(tkwin
);
637 predefHashPtr
= Tcl_FindHashEntry(&predefTable
, (char*)&key
);
638 if (predefHashPtr
!= NULL
) {
640 Tcl_DeleteHashEntry(predefHashPtr
);
643 Tcl_AppendResult(interp
, "pixmap \"", name
,
644 "\" doesn't exist", (char *) NULL
);
649 * Remove it from the name table if it is there (it might not
650 * have been created yet, it which case we wont find it). We
651 * delete it from the name table and mark the hashPtr as NULL
652 * so that we know it has been deleted. The pixmap still exists,
653 * and well later be freed and removed from idTable by Tk_FreeBitmap().
655 nameHashPtr
= Tcl_FindHashEntry(&nameTable
, (char *) &key
);
656 if (nameHashPtr
!= NULL
) {
657 bitmapPtr
= (TkBitmap
*) Tcl_GetHashValue(nameHashPtr
);
658 /* assert(nameHashPtr == bitmapPtr->hashPtr); */
659 /* assert(bitmapPtr->refCount > 0); */
660 bitmapPtr
->hashPtr
= (Tcl_HashEntry
*) NULL
;
661 Tcl_DeleteHashEntry(nameHashPtr
);