]>
Commit | Line | Data |
---|---|---|
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 1990-1992 Regents of the University of California | |
9 | * Permission to use, copy, modify, and distribute this | |
10 | * software and its documentation for any purpose and without | |
11 | * fee is hereby granted, provided that the above copyright | |
12 | * notice appear in all copies. The University of California | |
13 | * makes no representations about the suitability of this | |
14 | * software for any purpose. It is provided "as is" without | |
15 | * express or implied warranty. | |
16 | */ | |
17 | ||
18 | #ifndef lint | |
19 | static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkBitmap.c,v 1.16 92/08/24 09:45:43 ouster Exp $ SPRITE (Berkeley)"; | |
20 | #endif /* not lint */ | |
21 | ||
22 | #include "tkconfig.h" | |
23 | #include "tk.h" | |
24 | ||
25 | /* | |
26 | * The includes below are for pre-defined bitmaps. | |
27 | */ | |
28 | ||
29 | #include "bitmaps/gray50" | |
30 | #include "bitmaps/gray25" | |
31 | ||
32 | /* | |
33 | * One of the following data structures exists for each bitmap that is | |
34 | * currently in use. Each structure is indexed with both "idTable" and | |
35 | * "nameTable". | |
36 | */ | |
37 | ||
38 | typedef struct { | |
39 | Pixmap bitmap; /* X identifier for bitmap. None means this | |
40 | * bitmap was created by Tk_DefineBitmap | |
41 | * and it isn't currently in use. */ | |
42 | unsigned int width, height; /* Dimensions of bitmap. */ | |
43 | Display *display; /* Display for which bitmap is valid. */ | |
44 | int refCount; /* Number of active uses of bitmap. */ | |
45 | Tcl_HashEntry *hashPtr; /* Entry in nameTable for this structure | |
46 | * (needed when deleting). */ | |
47 | } TkBitmap; | |
48 | ||
49 | /* | |
50 | * Hash table to map from a textual description of a bitmap to the | |
51 | * TkBitmap record for the bitmap, and key structure used in that | |
52 | * hash table: | |
53 | */ | |
54 | ||
55 | static Tcl_HashTable nameTable; | |
56 | typedef struct { | |
57 | Tk_Uid name; /* Textual name for desired bitmap. */ | |
58 | Screen *screen; /* Screen for which bitmap will be used. */ | |
59 | } NameKey; | |
60 | ||
61 | /* | |
62 | * Hash table that maps from bitmap identifiers to the TkBitmap structure | |
63 | * for the bitmap. This table is indexed by Bitmap ids, and is used by | |
64 | * Tk_FreeBitmap. | |
65 | */ | |
66 | ||
67 | static Tcl_HashTable idTable; | |
68 | ||
69 | /* | |
70 | * For each call to Tk_DefineBitmap one of the following structures is | |
71 | * created to hold information about the bitmap. | |
72 | */ | |
73 | ||
74 | typedef struct { | |
75 | char *source; /* Bits for bitmap. */ | |
76 | unsigned int width, height; /* Dimensions of bitmap. */ | |
77 | } PredefBitmap; | |
78 | ||
79 | /* | |
80 | * Hash table create by Tk_DefineBitmap to map from a name to a | |
81 | * collection of in-core data about a bitmap. The table is | |
82 | * indexed by the address of the data for the bitmap, and the entries | |
83 | * contain pointers to PredefBitmap structures. | |
84 | */ | |
85 | ||
86 | static Tcl_HashTable predefTable; | |
87 | ||
88 | /* | |
89 | * Hash table used by Tk_GetBitmapFromData to map from a collection | |
90 | * of in-core data about a bitmap to a Tk_Uid giving an automatically- | |
91 | * generated name for the bitmap: | |
92 | */ | |
93 | ||
94 | static Tcl_HashTable dataTable; | |
95 | typedef struct { | |
96 | char *source; /* Bitmap bits. */ | |
97 | unsigned int width, height; /* Dimensions of bitmap. */ | |
98 | } DataKey; | |
99 | ||
100 | static int initialized = 0; /* 0 means static structures haven't been | |
101 | * initialized yet. */ | |
102 | ||
103 | /* | |
104 | * Forward declarations for procedures defined in this file: | |
105 | */ | |
106 | ||
107 | static void BitmapInit _ANSI_ARGS_((void)); | |
108 | \f | |
109 | /* | |
110 | *---------------------------------------------------------------------- | |
111 | * | |
112 | * Tk_GetBitmap -- | |
113 | * | |
114 | * Given a string describing a bitmap, locate (or create if necessary) | |
115 | * a bitmap that fits the description. | |
116 | * | |
117 | * Results: | |
118 | * The return value is the X identifer for the desired bitmap | |
119 | * (i.e. a Pixmap with a single plane), unless string couldn't be | |
120 | * parsed correctly. In this case, None is returned and an error | |
121 | * message is left in interp->result. The caller should never | |
122 | * modify the bitmap that is returned, and should eventually call | |
123 | * Tk_FreeBitmap when the bitmap is no longer needed. | |
124 | * | |
125 | * Side effects: | |
126 | * The bitmap is added to an internal database with a reference count. | |
127 | * For each call to this procedure, there should eventually be a call | |
128 | * to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps | |
129 | * aren't needed anymore. | |
130 | * | |
131 | *---------------------------------------------------------------------- | |
132 | */ | |
133 | ||
134 | Pixmap | |
135 | Tk_GetBitmap(interp, tkwin, string) | |
136 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
137 | Tk_Window tkwin; /* Window in which bitmap will be used. */ | |
138 | Tk_Uid string; /* Description of bitmap. See manual entry | |
139 | * for details on legal syntax. */ | |
140 | { | |
141 | NameKey key; | |
142 | Tcl_HashEntry *nameHashPtr, *idHashPtr, *predefHashPtr; | |
143 | register TkBitmap *bitmapPtr; | |
144 | PredefBitmap *predefPtr; | |
145 | int new; | |
146 | Pixmap bitmap; | |
147 | unsigned int width, height; | |
148 | int dummy2; | |
149 | ||
150 | if (!initialized) { | |
151 | BitmapInit(); | |
152 | } | |
153 | ||
154 | key.name = string; | |
155 | key.screen = Tk_Screen(tkwin); | |
156 | nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &key, &new); | |
157 | if (!new) { | |
158 | bitmapPtr = (TkBitmap *) Tcl_GetHashValue(nameHashPtr); | |
159 | bitmapPtr->refCount++; | |
160 | return bitmapPtr->bitmap; | |
161 | } | |
162 | ||
163 | /* | |
164 | * No suitable bitmap exists. Create a new bitmap from the | |
165 | * information contained in the string. If the string starts | |
166 | * with "@" then the rest of the string is a file name containing | |
167 | * the bitmap. Otherwise the string must refer to a bitmap | |
168 | * defined by a call to Tk_DefineBitmap. | |
169 | */ | |
170 | ||
171 | if (*string == '@') { | |
172 | string = Tcl_TildeSubst(interp, string + 1); | |
173 | if (string == NULL) { | |
174 | goto error; | |
175 | } | |
176 | if (XReadBitmapFile(Tk_Display(tkwin), | |
177 | RootWindowOfScreen(Tk_Screen(tkwin)), | |
178 | string, &width, &height, &bitmap, &dummy2, &dummy2) | |
179 | != BitmapSuccess) { | |
180 | Tcl_AppendResult(interp, "error reading bitmap file \"", string, | |
181 | "\"", (char *) NULL); | |
182 | goto error; | |
183 | } | |
184 | } else { | |
185 | predefHashPtr = Tcl_FindHashEntry(&predefTable, string); | |
186 | if (predefHashPtr == NULL) { | |
187 | Tcl_AppendResult(interp, "bitmap \"", string, | |
188 | "\" not defined", (char *) NULL); | |
189 | goto error; | |
190 | } | |
191 | predefPtr = (PredefBitmap *) Tcl_GetHashValue(predefHashPtr); | |
192 | width = predefPtr->width; | |
193 | height = predefPtr->height; | |
194 | bitmap = XCreateBitmapFromData(Tk_Display(tkwin), | |
195 | RootWindowOfScreen(Tk_Screen(tkwin)), predefPtr->source, | |
196 | width, height); | |
197 | } | |
198 | ||
199 | /* | |
200 | * Add information about this bitmap to our database. | |
201 | */ | |
202 | ||
203 | bitmapPtr = (TkBitmap *) ckalloc(sizeof(TkBitmap)); | |
204 | bitmapPtr->bitmap = bitmap; | |
205 | bitmapPtr->width = width; | |
206 | bitmapPtr->height = height; | |
207 | bitmapPtr->display = Tk_Display(tkwin); | |
208 | bitmapPtr->refCount = 1; | |
209 | bitmapPtr->hashPtr = nameHashPtr; | |
210 | idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) bitmapPtr->bitmap, | |
211 | &new); | |
212 | if (!new) { | |
213 | /* deh patched to support multiple displays */ | |
214 | /* panic("bitmap already registered in Tk_GetBitmap"); */ | |
215 | bitmapPtr->refCount = 1000; | |
216 | } | |
217 | Tcl_SetHashValue(nameHashPtr, bitmapPtr); | |
218 | Tcl_SetHashValue(idHashPtr, bitmapPtr); | |
219 | return bitmapPtr->bitmap; | |
220 | ||
221 | error: | |
222 | Tcl_DeleteHashEntry(nameHashPtr); | |
223 | return None; | |
224 | } | |
225 | \f | |
226 | /* | |
227 | *---------------------------------------------------------------------- | |
228 | * | |
229 | * Tk_DefineBitmap -- | |
230 | * | |
231 | * This procedure associates a textual name with a binary bitmap | |
232 | * description, so that the name may be used to refer to the | |
233 | * bitmap in future calls to Tk_GetBitmap. | |
234 | * | |
235 | * Results: | |
236 | * A standard Tcl result. If an error occurs then TCL_ERROR is | |
237 | * returned and a message is left in interp->result. | |
238 | * | |
239 | * Side effects: | |
240 | * "Name" is entered into the bitmap table and may be used from | |
241 | * here on to refer to the given bitmap. | |
242 | * | |
243 | *---------------------------------------------------------------------- | |
244 | */ | |
245 | ||
246 | int | |
247 | Tk_DefineBitmap(interp, name, source, width, height) | |
248 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
249 | Tk_Uid name; /* Name to use for bitmap. Must not already | |
250 | * be defined as a bitmap. */ | |
251 | char *source; /* Address of bits for bitmap. */ | |
252 | unsigned int width; /* Width of bitmap. */ | |
253 | unsigned int height; /* Height of bitmap. */ | |
254 | { | |
255 | int new; | |
256 | Tcl_HashEntry *predefHashPtr; | |
257 | PredefBitmap *predefPtr; | |
258 | ||
259 | if (!initialized) { | |
260 | BitmapInit(); | |
261 | } | |
262 | ||
263 | predefHashPtr = Tcl_CreateHashEntry(&predefTable, name, &new); | |
264 | if (!new) { | |
265 | Tcl_AppendResult(interp, "bitmap \"", name, | |
266 | "\" is already defined", (char *) NULL); | |
267 | return TCL_ERROR; | |
268 | } | |
269 | predefPtr = (PredefBitmap *) malloc(sizeof(PredefBitmap)); | |
270 | predefPtr->source = source; | |
271 | predefPtr->width = width; | |
272 | predefPtr->height = height; | |
273 | Tcl_SetHashValue(predefHashPtr, predefPtr); | |
274 | return TCL_OK; | |
275 | } | |
276 | \f | |
277 | /* | |
278 | *-------------------------------------------------------------- | |
279 | * | |
280 | * Tk_NameOfBitmap -- | |
281 | * | |
282 | * Given a bitmap, return a textual string identifying the | |
283 | * bitmap. | |
284 | * | |
285 | * Results: | |
286 | * The return value is the string name associated with bitmap. | |
287 | * | |
288 | * Side effects: | |
289 | * None. | |
290 | * | |
291 | *-------------------------------------------------------------- | |
292 | */ | |
293 | ||
294 | Tk_Uid | |
295 | Tk_NameOfBitmap(bitmap) | |
296 | Pixmap bitmap; /* Bitmap whose name is wanted. */ | |
297 | { | |
298 | Tcl_HashEntry *idHashPtr; | |
299 | TkBitmap *bitmapPtr; | |
300 | ||
301 | if (!initialized) { | |
302 | unknown: | |
303 | panic("Tk_NameOfBitmap received unknown bitmap argument"); | |
304 | } | |
305 | ||
306 | idHashPtr = Tcl_FindHashEntry(&idTable, (char *) bitmap); | |
307 | if (idHashPtr == NULL) { | |
308 | goto unknown; | |
309 | } | |
310 | bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); | |
311 | return ((NameKey *) bitmapPtr->hashPtr->key.words)->name; | |
312 | } | |
313 | \f | |
314 | /* | |
315 | *-------------------------------------------------------------- | |
316 | * | |
317 | * Tk_SizeOfBitmap -- | |
318 | * | |
319 | * Given a bitmap managed by this module, returns the width | |
320 | * and height of the bitmap.. | |
321 | * | |
322 | * Results: | |
323 | * The words at *widthPtr and *heightPtr are filled in with | |
324 | * the dimenstions of bitmap. | |
325 | * | |
326 | * Side effects: | |
327 | * If bitmap isn't managed by this module then the procedure | |
328 | * panics.. | |
329 | * | |
330 | *-------------------------------------------------------------- | |
331 | */ | |
332 | ||
333 | void | |
334 | Tk_SizeOfBitmap(bitmap, widthPtr, heightPtr) | |
335 | Pixmap bitmap; /* Bitmap whose size is wanted. */ | |
336 | unsigned int *widthPtr; /* Store bitmap width here. */ | |
337 | unsigned int *heightPtr; /* Store bitmap height here. */ | |
338 | { | |
339 | Tcl_HashEntry *idHashPtr; | |
340 | TkBitmap *bitmapPtr; | |
341 | ||
342 | if (!initialized) { | |
343 | unknownBitmap: | |
344 | panic("Tk_SizeOfBitmap received unknown bitmap argument"); | |
345 | } | |
346 | ||
347 | idHashPtr = Tcl_FindHashEntry(&idTable, (char *) bitmap); | |
348 | if (idHashPtr == NULL) { | |
349 | goto unknownBitmap; | |
350 | } | |
351 | bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); | |
352 | *widthPtr = bitmapPtr->width; | |
353 | *heightPtr = bitmapPtr->height; | |
354 | } | |
355 | \f | |
356 | /* | |
357 | *---------------------------------------------------------------------- | |
358 | * | |
359 | * Tk_FreeBitmap -- | |
360 | * | |
361 | * This procedure is called to release a bitmap allocated by | |
362 | * Tk_GetBitmap or TkGetBitmapFromData. | |
363 | * | |
364 | * Results: | |
365 | * None. | |
366 | * | |
367 | * Side effects: | |
368 | * The reference count associated with bitmap is decremented, and | |
369 | * it is officially deallocated if no-one is using it anymore. | |
370 | * | |
371 | *---------------------------------------------------------------------- | |
372 | */ | |
373 | ||
374 | void | |
375 | Tk_FreeBitmap(bitmap) | |
376 | Pixmap bitmap; /* Bitmap to be released. */ | |
377 | { | |
378 | Tcl_HashEntry *idHashPtr; | |
379 | register TkBitmap *bitmapPtr; | |
380 | ||
381 | if (!initialized) { | |
382 | panic("Tk_FreeBitmap called before Tk_GetBitmap"); | |
383 | } | |
384 | ||
385 | idHashPtr = Tcl_FindHashEntry(&idTable, (char *) bitmap); | |
386 | if (idHashPtr == NULL) { | |
387 | panic("Tk_FreeBitmap received unknown bitmap argument"); | |
388 | } | |
389 | bitmapPtr = (TkBitmap *) Tcl_GetHashValue(idHashPtr); | |
390 | bitmapPtr->refCount--; | |
391 | if (bitmapPtr->refCount == 0) { | |
392 | XFreePixmap(bitmapPtr->display, bitmapPtr->bitmap); | |
393 | Tcl_DeleteHashEntry(idHashPtr); | |
394 | Tcl_DeleteHashEntry(bitmapPtr->hashPtr); | |
395 | ckfree((char *) bitmapPtr); | |
396 | } | |
397 | } | |
398 | \f | |
399 | /* | |
400 | *---------------------------------------------------------------------- | |
401 | * | |
402 | * Tk_GetBitmapFromData -- | |
403 | * | |
404 | * Given a description of the bits for a bitmap, make a bitmap that | |
405 | * has the given properties. | |
406 | * | |
407 | * Results: | |
408 | * The return value is the X identifer for the desired bitmap | |
409 | * (a one-plane Pixmap), unless it couldn't be created properly. | |
410 | * In this case, None is returned and an error message is left in | |
411 | * interp->result. The caller should never modify the bitmap that | |
412 | * is returned, and should eventually call Tk_FreeBitmap when the | |
413 | * bitmap is no longer needed. | |
414 | * | |
415 | * Side effects: | |
416 | * The bitmap is added to an internal database with a reference count. | |
417 | * For each call to this procedure, there should eventually be a call | |
418 | * to Tk_FreeBitmap, so that the database can be cleaned up when bitmaps | |
419 | * aren't needed anymore. | |
420 | * | |
421 | *---------------------------------------------------------------------- | |
422 | */ | |
423 | ||
424 | /* ARGSUSED */ | |
425 | Pixmap | |
426 | Tk_GetBitmapFromData(interp, tkwin, source, width, height) | |
427 | Tcl_Interp *interp; /* Interpreter to use for error reporting. */ | |
428 | Tk_Window tkwin; /* Window in which bitmap will be used. */ | |
429 | char *source; /* Bitmap data for bitmap shape. */ | |
430 | unsigned int width, height; /* Dimensions of bitmap. */ | |
431 | { | |
432 | DataKey key; | |
433 | Tcl_HashEntry *dataHashPtr; | |
434 | Tk_Uid name = NULL; /* Initialization need only to prevent | |
435 | * compiler warning. */ | |
436 | int new; | |
437 | static autoNumber = 0; | |
438 | char string[20]; | |
439 | ||
440 | if (!initialized) { | |
441 | BitmapInit(); | |
442 | } | |
443 | ||
444 | key.source = source; | |
445 | key.width = width; | |
446 | key.height = height; | |
447 | dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &key, &new); | |
448 | if (!new) { | |
449 | name = (Tk_Uid) Tcl_GetHashValue(dataHashPtr); | |
450 | } else { | |
451 | autoNumber++; | |
452 | sprintf(string, "_tk%d", autoNumber); | |
453 | name = Tk_GetUid(string); | |
454 | Tcl_SetHashValue(dataHashPtr, name); | |
455 | if (Tk_DefineBitmap(interp, name, source, width, height) != TCL_OK) { | |
456 | Tcl_DeleteHashEntry(dataHashPtr); | |
457 | return TCL_ERROR; | |
458 | } | |
459 | } | |
460 | return Tk_GetBitmap(interp, tkwin, name); | |
461 | } | |
462 | \f | |
463 | /* | |
464 | *---------------------------------------------------------------------- | |
465 | * | |
466 | * BitmapInit -- | |
467 | * | |
468 | * Initialize the structures used for bitmap management. | |
469 | * | |
470 | * Results: | |
471 | * None. | |
472 | * | |
473 | * Side effects: | |
474 | * Read the code. | |
475 | * | |
476 | *---------------------------------------------------------------------- | |
477 | */ | |
478 | ||
479 | static void | |
480 | BitmapInit() | |
481 | { | |
482 | Tcl_Interp *dummy; | |
483 | ||
484 | dummy = Tcl_CreateInterp(); | |
485 | initialized = 1; | |
486 | Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int)); | |
487 | Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int)); | |
488 | Tcl_InitHashTable(&predefTable, TCL_ONE_WORD_KEYS); | |
489 | Tcl_InitHashTable(&idTable, TCL_ONE_WORD_KEYS); | |
490 | ||
491 | Tk_DefineBitmap(dummy, Tk_GetUid("gray50"), (char *)gray50_bits, | |
492 | gray50_width, gray50_height); | |
493 | Tk_DefineBitmap(dummy, Tk_GetUid("gray25"), | |
494 | (char *)gray25_bits, gray25_width, gray25_height); | |
495 | Tcl_DeleteInterp(dummy); | |
496 | } |