]> cvs.zerfleddert.de Git - micropolis/blame - src/tk/tkpixmap.c
Fix for shared memory leak by Kurt Miller.
[micropolis] / src / tk / tkpixmap.c
CommitLineData
6a5fa4e0
MG
1/*
2 * tkPixmap.c --
3 *
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.
7 *
8 * Copyright 1992 by Sven Delmas
9 *
10 * This source is based upon the file tkBitmap.c from:
11 *
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);
22 */
23
24#if defined(USE_XPM3)
25
26#ifndef lint
27static char *AtFSid = "$Header: tkPixmap.c[1.1] Mon Sep 28 14:12:35 1992 garfield@cs.tu-berlin.de frozen $";
28#endif /* not lint */
29
30#include "tkconfig.h"
31#include "tk.h"
32
33/*
34 * The includes below are for pre-defined bitmaps.
35 */
36
37#include "bitmaps/gray50"
38#include "bitmaps/gray25"
39
40/*
41 * Include the xpm 3 defines for color pixmaps
42 */
43//#include "xpmtk.h"
44#include <xpm.h>
45
46/*
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
49 * "nameTable".
50 */
51
52typedef struct {
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). */
61} TkBitmap;
62
63/*
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
66 * hash table:
67 */
68
69static Tcl_HashTable nameTable;
70typedef struct {
71 Tk_Uid name; /* Textual name for desired bitmap. */
72 Screen *screen; /* Screen for which bitmap will be used. */
73} NameKey;
74
75/*
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
78 * Tk_FreePixmap.
79 */
80
81static Tcl_HashTable idTable;
82
83/*
84 * For each call to Tk_DefinePixmap one of the following structures is
85 * created to hold information about the pixmap.
86 */
87
88typedef struct {
89 char *source; /* Bits for bitmap. */
90 Pixmap pixmap; /* Pre-defined pixmap */
91 unsigned int width, height; /* Dimensions of bitmap. */
92} PredefBitmap;
93
94/*
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.
99 */
100
101static Tcl_HashTable predefTable;
102
103/*
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:
107 */
108
109static Tcl_HashTable dataTable;
110typedef struct {
111 char *source; /* Bitmap bits. */
112 unsigned int width, height; /* Dimensions of bitmap. */
113} DataKey;
114
115static int initialized = 0; /* 0 means static structures haven't been
116 * initialized yet. */
117
118/*
119 * Forward declarations for procedures defined in this file:
120 */
121
122static void PixmapInit _ANSI_ARGS_((Tk_Window tkwin));
123\f
124/*
125 *----------------------------------------------------------------------
126 *
127 * Tk_GetPixmap --
128 *
129 * Given a string describing a bitmap or pixmap, locate (or create
130 * if necessary) a pixmap that fits the description.
131 *
132 * Results:
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.
139 *
140 * Side effects:
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.
145 *
146 *----------------------------------------------------------------------
147 */
148Pixmap
149Tk_GetPixmap(interp, tkwin, string)
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. */
154{
155 NameKey key;
156 Tcl_HashEntry *nameHashPtr, *idHashPtr, *predefHashPtr;
157 register TkBitmap *bitmapPtr;
158 PredefBitmap *predefPtr;
159 int new;
160 Pixmap bitmap;
161 Pixmap bitmap_shape;
162 unsigned int width, height;
163 int dummy2;
164 XpmAttributes xpm_attributes;
165 Display *dpy = Tk_Display(tkwin);
166
167 if (!initialized) {
168 PixmapInit(tkwin);
169 }
170
171 key.name = string;
172 key.screen = Tk_Screen(tkwin);
173 nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &key, &new);
174 if (!new) {
175 bitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr);
176 bitmapPtr->refCount++;
177 return bitmapPtr->bitmap;
178 }
179
180 /*
181 * No suitable bitmap exists. Create a new bitmap from the
182 * information contained in the string. If the string starts
183 * with "@" then the rest of the string is a file name containing
184 * the bitmap. Otherwise the string must refer to a bitmap
185 * defined by a call to Tk_DefinePixmap.
186 */
187
188 if (*string == '@') {
189 string = Tcl_TildeSubst(interp, string + 1);
190 if (string == NULL) {
191 goto error;
192 }
193
194 if (XReadBitmapFile(dpy, RootWindowOfScreen(Tk_Screen(tkwin)),
195 string, &width, &height, &bitmap_shape, &dummy2, &dummy2)
196 != BitmapSuccess)
197 {
198 xpm_attributes.visual = Tk_DefaultVisual(Tk_Screen(tkwin));
199 xpm_attributes.colormap = Tk_DefaultColormap(Tk_Screen(tkwin));
200 xpm_attributes.depth = Tk_DefaultDepth(Tk_Screen(tkwin));
201 xpm_attributes.valuemask = XpmVisual | XpmColormap | XpmDepth;
202
203 if (XpmReadFileToPixmap(dpy, RootWindowOfScreen(Tk_Screen(tkwin)),
204 string, &bitmap, &bitmap_shape,
205 &xpm_attributes) != BitmapSuccess) {
206 Tcl_AppendResult(interp, "error reading bitmap file \"",
207 string, "\"", (char *) NULL);
208 goto error;
209 } {
210 width = xpm_attributes.width;
211 height = xpm_attributes.height;
212 XpmFreeAttributes(&xpm_attributes);
213 }
214 } else {
215 bitmap = XCreatePixmap(dpy, RootWindowOfScreen(Tk_Screen(tkwin)),
216 width, height,
217 Tk_DefaultDepth(Tk_Screen(tkwin)));
218 XCopyPlane(dpy, bitmap_shape, bitmap,
219 Tk_DefaultGC(Tk_Screen(tkwin)),
220 0, 0, width, height, 0, 0, 1);
221 }
222 } else {
223 /* first try for a display-specific version */
224 predefHashPtr = Tcl_FindHashEntry(&predefTable, (char *) &key);
225 if (predefHashPtr == NULL) {
226 /* try for a non-display specific version */
227 key.screen = (Screen*) NULL;
228 predefHashPtr = Tcl_FindHashEntry(&predefTable, (char *) &key);
229 if (predefHashPtr == NULL) {
230 /* give up */
231 Tcl_AppendResult(interp, "pixmap \"", string,
232 "\" not defined", (char *) NULL);
233 goto error;
234 }
235 }
236 predefPtr = (PredefBitmap *) Tcl_GetHashValue(predefHashPtr);
237 width = predefPtr->width;
238 height = predefPtr->height;
239 if (predefPtr->source != NULL) {
240 bitmap_shape =
241 XCreateBitmapFromData(dpy, Tk_DefaultRootWindow(dpy),
242 predefPtr->source, width, height);
243 bitmap = XCreatePixmap(dpy, RootWindowOfScreen(Tk_Screen(tkwin)),
244 width, height,
245 Tk_DefaultDepth(Tk_Screen(tkwin)));
246 XCopyPlane(dpy, bitmap_shape, bitmap,
247 Tk_DefaultGC(Tk_Screen(tkwin)),
248 0, 0, width, height, 0, 0, 1);
249 } else {
250 if (predefPtr->pixmap != None) {
251 bitmap = predefPtr->pixmap;
252 } else {
253 bitmap =
254 XCreatePixmap(dpy, RootWindowOfScreen(Tk_Screen(tkwin)),
255 width, height,
256 Tk_DefaultDepth(Tk_Screen(tkwin)));
257 }
258 }
259 }
260
261 /*
262 * Add information about this bitmap to our database.
263 */
264
265 bitmapPtr = (TkBitmap *) ckalloc(sizeof(TkBitmap));
266 bitmapPtr->bitmap = bitmap;
267 bitmapPtr->width = width;
268 bitmapPtr->height = height;
269 bitmapPtr->display = dpy;
270 bitmapPtr->refCount = 1;
271 bitmapPtr->hashPtr = nameHashPtr;
272 idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) bitmapPtr->bitmap,
273 &new);
274 if (!new) {
275/* deh patched to support multiple displays */
276/* panic("pixmap already registered in Tk_GetPixmap"); */
277 bitmapPtr->refCount = 1000;
278 }
279 Tcl_SetHashValue(nameHashPtr, bitmapPtr);
280 Tcl_SetHashValue(idHashPtr, bitmapPtr);
281 return bitmapPtr->bitmap;
282
283 error:
284 Tcl_DeleteHashEntry(nameHashPtr);
285 return None;
286}
287\f
288/*
289 *----------------------------------------------------------------------
290 *
291 * Tk_DefinePixmap --
292 *
293 * This procedure associates a textual name with a binary pixmap
294 * description, so that the name may be used to refer to the
295 * pixmap in future calls to Tk_GetPixmap. The pixmap can
296 * be pre-created by the user, or can be created later
297 * by Tk_GetPixmap(). Since pixmaps are display-specific,
298 * a user supplied pixmap will be associated with tkwin's display.
299 * If pixmap is given as None, then a new pixmap will be created
300 * by Tk_GetPixmap for each unique display.
301 *
302 * Results:
303 * A standard Tcl result. If an error occurs then TCL_ERROR is
304 * returned and a message is left in interp->result.
305 *
306 * Side effects:
307 * "Name" is entered into the pixmap table and may be used from
308 * here on to refer to the given pixmap.
309 *
310 *----------------------------------------------------------------------
311 */
312
313int
314Tk_DefinePixmap(interp, name, tkwin, pixmap, source, width, height)
315 Tcl_Interp *interp; /* Interpreter to use for error reporting. */
316 Tk_Uid name; /* Name to use for bitmap. Must not already
317 * be defined as a bitmap. */
318 Tk_Window tkwin; /* any window on screen where pixmap lives */
319 Pixmap pixmap; /* pixmap to associate with name,
320 * or None to create a new pixmap */
321 char *source; /* Address of bits for bitmap. */
322 unsigned int width; /* Width of bitmap. */
323 unsigned int height; /* Height of bitmap. */
324{
325 int new;
326 Tcl_HashEntry *predefHashPtr;
327 PredefBitmap *predefPtr;
328 NameKey key;
329
330 if (!initialized) {
331 PixmapInit(tkwin);
332 }
333
334 key.name = name;
335 key.screen = (pixmap != None) ? Tk_Screen(tkwin) : (Screen *)NULL;
336 predefHashPtr = Tcl_CreateHashEntry(&predefTable, (char *) &key, &new);
337 if (!new) {
338 Tcl_AppendResult(interp, "bitmap \"", name,
339 "\" is already defined", (char *) NULL);
340 return TCL_ERROR;
341 }
342 predefPtr = (PredefBitmap *) malloc(sizeof(PredefBitmap));
343 predefPtr->source = source;
344 predefPtr->pixmap = pixmap;
345 predefPtr->width = width;
346 predefPtr->height = height;
347 Tcl_SetHashValue(predefHashPtr, predefPtr);
348 return TCL_OK;
349}
350\f
351/*
352 *--------------------------------------------------------------
353 *
354 * Tk_NameOfPixmap --
355 *
356 * Given a pixmap, return a textual string identifying the
357 * pixmap.
358 *
359 * Results:
360 * The return value is the string name associated with pixmap.
361 *
362 * Side effects:
363 * None.
364 *
365 *--------------------------------------------------------------
366 */
367
368Tk_Uid
369Tk_NameOfPixmap(bitmap)
370 Pixmap bitmap; /* Bitmap whose name is wanted. */
371{
372 Tcl_HashEntry *idHashPtr;
373 TkBitmap *bitmapPtr;
374
375 if (!initialized) {
376 unknown:
377 panic("Tk_NameOfPixmap received unknown pixmap argument");
378 }
379
380 idHashPtr = Tcl_FindHashEntry(&idTable, (char *) bitmap);
381 if (idHashPtr == NULL) {
382 goto unknown;
383 }
384 bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr);
385 if (bitmapPtr->hashPtr == NULL) {
386 /* the bitmap has been un-defined */
387 return Tk_GetUid("UndefinedBitmap");
388 }
389 return ((NameKey *) bitmapPtr->hashPtr->key.words)->name;
390}
391\f
392/*
393 *--------------------------------------------------------------
394 *
395 * Tk_SizeOfPixmap --
396 *
397 * Given a pixmap managed by this module, returns the width
398 * and height of the pixmap..
399 *
400 * Results:
401 * The words at *widthPtr and *heightPtr are filled in with
402 * the dimenstions of pixmap.
403 *
404 * Side effects:
405 * If pixmap isn't managed by this module then the procedure
406 * panics..
407 *
408 *--------------------------------------------------------------
409 */
410
411void
412Tk_SizeOfPixmap(bitmap, widthPtr, heightPtr)
413 Pixmap bitmap; /* Bitmap whose size is wanted. */
414 unsigned int *widthPtr; /* Store bitmap width here. */
415 unsigned int *heightPtr; /* Store bitmap height here. */
416{
417 Tcl_HashEntry *idHashPtr;
418 TkBitmap *bitmapPtr;
419
420 if (!initialized) {
421 unknownBitmap:
422 panic("Tk_SizeOfPixmap received unknown pixmap argument");
423 }
424
425 idHashPtr = Tcl_FindHashEntry(&idTable, (char *) bitmap);
426 if (idHashPtr == NULL) {
427 goto unknownBitmap;
428 }
429 bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr);
430 *widthPtr = bitmapPtr->width;
431 *heightPtr = bitmapPtr->height;
432}
433\f
434/*
435 *----------------------------------------------------------------------
436 *
437 * Tk_FreePixmap --
438 *
439 * This procedure is called to release a pixmap allocated by
440 * Tk_GetPixmap.
441 *
442 * Results:
443 * None.
444 *
445 * Side effects:
446 * The reference count associated with bitmap is decremented, and
447 * it is officially deallocated if no-one is using it anymore.
448 *
449 *----------------------------------------------------------------------
450 */
451
452void
453Tk_FreePixmap(bitmap)
454 Pixmap bitmap; /* Bitmap to be released. */
455{
456 Tcl_HashEntry *idHashPtr;
457 register TkBitmap *bitmapPtr;
458
459 if (!initialized) {
460 panic("Tk_FreePixmap called before Tk_GetPixmap");
461 }
462
463 idHashPtr = Tcl_FindHashEntry(&idTable, (char *) bitmap);
464 if (idHashPtr == NULL) {
465 panic("Tk_FreePixmap received unknown pixmap argument");
466 }
467 bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr);
468 bitmapPtr->refCount--;
469 if (bitmapPtr->refCount == 0) {
470 XFreePixmap(bitmapPtr->display, bitmapPtr->bitmap);
471 Tcl_DeleteHashEntry(idHashPtr);
472 if (bitmapPtr->hashPtr != NULL) {
473 /* If hashPtr is NULL, the bitmap has been undefined,
474 * and already removed from the name table */
475 Tcl_DeleteHashEntry(bitmapPtr->hashPtr);
476 }
477 ckfree((char *) bitmapPtr);
478 }
479}
480\f
481/*
482 *----------------------------------------------------------------------
483 *
484 * Tk_GetPixmapFromData --
485 *
486 * Given a description of the bits for a pixmap, make a pixmap that
487 * has the given properties.
488 *
489 * Results:
490 * The return value is the X identifer for the desired pixmap,
491 * unless it couldn't be created properly. In this case, None is
492 * returned and an error message is left in interp->result. The
493 * caller should never modify the bitmap that is returned, and
494 * should eventually call Tk_FreePixmap when the pixmap is no
495 * longer needed.
496 *
497 * Side effects:
498 * The pixmap is added to an internal database with a reference count.
499 * For each call to this procedure, there should eventually be a call
500 * to Tk_FreePixmap, so that the database can be cleaned up when pixmaps
501 * aren't needed anymore.
502 *
503 *----------------------------------------------------------------------
504 */
505
506 /* ARGSUSED */
507Pixmap
508Tk_GetPixmapFromData(interp, tkwin, source, width, height)
509 Tcl_Interp *interp; /* Interpreter to use for error reporting. */
510 Tk_Window tkwin; /* Window in which bitmap will be used. */
511 char *source; /* Bitmap data for bitmap shape. */
512 unsigned int width, height; /* Dimensions of bitmap. */
513{
514 DataKey key;
515 Tcl_HashEntry *dataHashPtr;
516 Tk_Uid name = NULL; /* Initialization need only to prevent
517 * compiler warning. */
518 int new;
519 static autoNumber = 0;
520 char string[20];
521
522 if (!initialized) {
523 PixmapInit(tkwin);
524 }
525
526 key.source = source;
527 key.width = width;
528 key.height = height;
529 dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &key, &new);
530 if (!new) {
531 name = (Tk_Uid) Tcl_GetHashValue(dataHashPtr);
532 } else {
533 autoNumber++;
534 sprintf(string, "_tk%d", autoNumber);
535 name = Tk_GetUid(string);
536 Tcl_SetHashValue(dataHashPtr, name);
537 if (Tk_DefinePixmap(interp, name, tkwin, None, source, width,
538 height) != TCL_OK) {
539 Tcl_DeleteHashEntry(dataHashPtr);
540 return TCL_ERROR;
541 }
542 }
543 return Tk_GetPixmap(interp, tkwin, name);
544}
545\f
546/*
547 *----------------------------------------------------------------------
548 *
549 * PixmapInit --
550 *
551 * Initialize the structures used for pixmap management.
552 *
553 * Results:
554 * None.
555 *
556 * Side effects:
557 * Read the code.
558 *
559 *----------------------------------------------------------------------
560 */
561
562static void
563PixmapInit(tkwin)
564 Tk_Window tkwin; /* any window on screen where pixmap lives */
565{
566 Tcl_Interp *dummy;
567
568 dummy = Tcl_CreateInterp();
569 initialized = 1;
570 Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
571 Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int));
572 Tcl_InitHashTable(&predefTable, sizeof(NameKey)/sizeof(int));
573 Tcl_InitHashTable(&idTable, TCL_ONE_WORD_KEYS);
574
575 Tk_DefinePixmap(dummy, Tk_GetUid("gray50"), tkwin, None,
576 (char *)gray50_bits, gray50_width, gray50_height);
577 Tk_DefinePixmap(dummy, Tk_GetUid("gray25"), tkwin, None,
578 (char *)gray25_bits, gray25_width, gray25_height);
579 Tcl_DeleteInterp(dummy);
580}
581\f
582/*
583 *----------------------------------------------------------------------
584 *
585 * Tk_UndefinePixmap --
586 *
587 * This procedure removes any association "name" with
588 * a bitmap or pixmap. This can be used to undefine
589 * names defined by either Tk_DefinePixmap or Tk_DefinePixmap.
590 * If tkwin is NULL, only display-independent pixmaps will
591 * be removed, otherwise both display-independent and
592 * the pixmap associated with tkwin will be undefined.
593 *
594 * Results:
595 * A standard Tcl result. If an error occurs then TCL_ERROR is
596 * returned and a message is left in interp->result.
597 *
598 * Side effects:
599 * "Name" is removed from the predef table.
600 *
601 *----------------------------------------------------------------------
602 */
603
604int
605Tk_UndefinePixmap(interp, name, tkwin)
606 Tcl_Interp *interp; /* Interpreter to use for error reporting. */
607 Tk_Uid name; /* Name of bitmap/pixmap to undefine */
608 Tk_Window tkwin; /* any window on screen where pixmap lives */
609{
610 NameKey key;
611 Tcl_HashEntry *predefHashPtr, *nameHashPtr;
612 TkBitmap *bitmapPtr;
613 int cnt = 0;
614
615 if (!initialized) {
616 PixmapInit(tkwin);
617 }
618
619 key.name = name;
620 key.screen = (Screen *) NULL;
621 predefHashPtr = Tcl_FindHashEntry(&predefTable, (char*)&key);
622 if (predefHashPtr != NULL) {
623 ++cnt;
624 Tcl_DeleteHashEntry(predefHashPtr);
625 }
626
627 key.screen = Tk_Screen(tkwin);
628 predefHashPtr = Tcl_FindHashEntry(&predefTable, (char*)&key);
629 if (predefHashPtr != NULL) {
630 ++cnt;
631 Tcl_DeleteHashEntry(predefHashPtr);
632 }
633 if (cnt == 0) {
634 Tcl_AppendResult(interp, "pixmap \"", name,
635 "\" doesn't exist", (char *) NULL);
636 return TCL_ERROR;
637 }
638
639 /*
640 * Remove it from the name table if it is there (it might not
641 * have been created yet, it which case we wont find it). We
642 * delete it from the name table and mark the hashPtr as NULL
643 * so that we know it has been deleted. The pixmap still exists,
644 * and well later be freed and removed from idTable by Tk_FreeBitmap().
645 */
646 nameHashPtr = Tcl_FindHashEntry(&nameTable, (char *) &key);
647 if (nameHashPtr != NULL) {
648 bitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr);
649 /* assert(nameHashPtr == bitmapPtr->hashPtr); */
650 /* assert(bitmapPtr->refCount > 0); */
651 bitmapPtr->hashPtr = (Tcl_HashEntry*) NULL;
652 Tcl_DeleteHashEntry(nameHashPtr);
653 }
654 return TCL_OK;
655}
656
657#endif
Impressum, Datenschutz