|
|
1.1 root 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
27: static char *AtFSid = "$Header: tkPixmap.c[1.1] Mon Sep 28 14:12:35 1992 [email protected] 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:
52: typedef 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:
69: static Tcl_HashTable nameTable;
70: typedef 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:
81: static 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:
88: typedef 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:
101: static 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:
109: static Tcl_HashTable dataTable;
110: typedef struct {
111: char *source; /* Bitmap bits. */
112: unsigned int width, height; /* Dimensions of bitmap. */
113: } DataKey;
114:
115: static 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:
122: static void PixmapInit _ANSI_ARGS_((Tk_Window tkwin));
123:
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: */
148: Pixmap
149: Tk_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:
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:
313: int
314: Tk_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:
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:
368: Tk_Uid
369: Tk_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:
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:
411: void
412: Tk_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:
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:
452: void
453: Tk_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:
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 */
507: Pixmap
508: Tk_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:
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:
562: static void
563: PixmapInit(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:
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:
604: int
605: Tk_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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.