| 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 | } |