static TkBitmap * GetBitmap( Tcl_Interp *interp, /* Interpreter to use for error reporting, * this may be NULL. */ Tk_Window tkwin, /* Window in which bitmap will be used. */ const char *string) /* Description of bitmap. See manual entry for * details on legal syntax. */ { Tcl_HashEntry *nameHashPtr, *predefHashPtr; TkBitmap *bitmapPtr, *existingBitmapPtr; TkPredefBitmap *predefPtr; Pixmap bitmap; int isNew, width, height, dummy2; TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); if (!dispPtr->bitmapInit) { BitmapInit(dispPtr); } nameHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapNameTable, string, &isNew); if (!isNew) { existingBitmapPtr = Tcl_GetHashValue(nameHashPtr); for (bitmapPtr = existingBitmapPtr; bitmapPtr != NULL; bitmapPtr = bitmapPtr->nextPtr) { if ((Tk_Display(tkwin) == bitmapPtr->display) && (Tk_ScreenNumber(tkwin) == bitmapPtr->screenNum)) { bitmapPtr->resourceRefCount++; return bitmapPtr; } } } else { existingBitmapPtr = NULL; } /* * No suitable bitmap exists. Create a new bitmap from the information * contained in the string. If the string starts with "@" then the rest of * the string is a file name containing the bitmap. Otherwise the string * must refer to a bitmap defined by a call to Tk_DefineBitmap. */ if (*string == '@') { /* INTL: ISO char */ Tcl_DString buffer; int result; if (Tcl_IsSafe(interp)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "can't specify bitmap with '@' in a safe interpreter", -1)); Tcl_SetErrorCode(interp, "TK", "SAFE", "BITMAP_FILE", NULL); goto error; } /* * Note that we need to cast away the const from the string because * Tcl_TranslateFileName is non-const, even though it doesn't modify * the string. */ string = Tcl_TranslateFileName(interp, (char *) string + 1, &buffer); if (string == NULL) { goto error; } result = TkReadBitmapFile(Tk_Display(tkwin), RootWindowOfScreen(Tk_Screen(tkwin)), string, (unsigned int *) &width, (unsigned int *) &height, &bitmap, &dummy2, &dummy2); if (result != BitmapSuccess) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "error reading bitmap file \"%s\"", string)); Tcl_SetErrorCode(interp, "TK", "BITMAP", "FILE_ERROR", NULL); } Tcl_DStringFree(&buffer); goto error; } Tcl_DStringFree(&buffer); } else { predefHashPtr = Tcl_FindHashEntry(&tsdPtr->predefBitmapTable, string); if (predefHashPtr == NULL) { /* * The following platform specific call allows the user to define * bitmaps that may only exist during run time. If it returns None * nothing was found and we return the error. */ bitmap = TkpGetNativeAppBitmap(Tk_Display(tkwin), string, &width, &height); if (bitmap == None) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bitmap \"%s\" not defined", string)); Tcl_SetErrorCode(interp, "TK", "LOOKUP", "BITMAP", string, NULL); } goto error; } } else { predefPtr = Tcl_GetHashValue(predefHashPtr); width = predefPtr->width; height = predefPtr->height; if (predefPtr->native) { bitmap = TkpCreateNativeBitmap(Tk_Display(tkwin), predefPtr->source); if (bitmap == None) { Tcl_Panic("native bitmap creation failed"); } } else { bitmap = XCreateBitmapFromData(Tk_Display(tkwin), RootWindowOfScreen(Tk_Screen(tkwin)), predefPtr->source, (unsigned)width, (unsigned)height); } } } /* * Add information about this bitmap to our database. */ bitmapPtr = ckalloc(sizeof(TkBitmap)); bitmapPtr->bitmap = bitmap; bitmapPtr->width = width; bitmapPtr->height = height; bitmapPtr->display = Tk_Display(tkwin); bitmapPtr->screenNum = Tk_ScreenNumber(tkwin); bitmapPtr->resourceRefCount = 1; bitmapPtr->objRefCount = 0; bitmapPtr->nameHashPtr = nameHashPtr; bitmapPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->bitmapIdTable, (char *) bitmap, &isNew); if (!isNew) { Tcl_Panic("bitmap already registered in Tk_GetBitmap"); } bitmapPtr->nextPtr = existingBitmapPtr; Tcl_SetHashValue(nameHashPtr, bitmapPtr); Tcl_SetHashValue(bitmapPtr->idHashPtr, bitmapPtr); return bitmapPtr; error: if (isNew) { Tcl_DeleteHashEntry(nameHashPtr); } return NULL; }
static Cursor CreateCursorFromTableOrFile( Tcl_Interp *interp, /* Interpreter to use for error reporting. */ Tk_Window tkwin, /* Window in which cursor will be used. */ int argc, const char **argv, /* Cursor spec parsed into elements. */ const struct TkCursorName *tkCursorPtr) /* Non-NULL when cursor is defined in Tk * table. */ { Cursor cursor = None; int width, height, maskWidth, maskHeight; int xHot = -1, yHot = -1; int dummy1, dummy2; XColor fg, bg; const char *fgColor; const char *bgColor; int inTkTable = (tkCursorPtr != NULL); Display *display = Tk_Display(tkwin); Drawable drawable = RootWindowOfScreen(Tk_Screen(tkwin)); Pixmap source = None; Pixmap mask = None; /* * A cursor defined in a file accepts either 2 or 4 arguments. * * {srcfile fg} * {srcfile maskfile fg bg} * * A cursor defined in the Tk table accepts 1, 2, or 3 arguments. * * {tkcursorname} * {tkcursorname fg} * {tkcursorname fg bg} */ if (inTkTable) { /* * This logic is like TkReadBitmapFile(). */ char *data; data = TkGetBitmapData(NULL, tkCursorPtr->data, NULL, &width, &height, &xHot, &yHot); if (data == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "error reading bitmap data for \"%s\"", argv[0])); Tcl_SetErrorCode(interp, "TK", "CURSOR", "BITMAP_DATA", NULL); goto cleanup; } source = XCreateBitmapFromData(display, drawable, data, width,height); ckfree(data); } else { if (TkReadBitmapFile(display, drawable, &argv[0][1], (unsigned *) &width, (unsigned *) &height, &source, &xHot, &yHot) != BitmapSuccess) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "cleanup reading bitmap file \"%s\"", &argv[0][1])); Tcl_SetErrorCode(interp, "TK", "CURSOR", "BITMAP_FILE", NULL); goto cleanup; } } if ((xHot < 0) || (yHot < 0) || (xHot >= width) || (yHot >= height)) { if (inTkTable) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bad hot spot in bitmap data for \"%s\"", argv[0])); } else { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bad hot spot in bitmap file \"%s\"", &argv[0][1])); } Tcl_SetErrorCode(interp, "TK", "CURSOR", "HOTSPOT", NULL); goto cleanup; } /* * Parse color names from optional fg and bg arguments */ if (argc == 1) { fg.red = fg.green = fg.blue = 0; bg.red = bg.green = bg.blue = 65535; } else if (argc == 2) { fgColor = argv[1]; if (TkParseColor(display, Tk_Colormap(tkwin), fgColor, &fg) == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid color name \"%s\"", fgColor)); Tcl_SetErrorCode(interp, "TK", "CURSOR", "COLOR", NULL); goto cleanup; } if (inTkTable) { bg.red = bg.green = bg.blue = 0; } else { bg = fg; } } else { /* 3 or 4 arguments */ if (inTkTable) { fgColor = argv[1]; bgColor = argv[2]; } else { fgColor = argv[2]; bgColor = argv[3]; } if (TkParseColor(display, Tk_Colormap(tkwin), fgColor, &fg) == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid color name \"%s\"", fgColor)); Tcl_SetErrorCode(interp, "TK", "CURSOR", "COLOR", NULL); goto cleanup; } if (TkParseColor(display, Tk_Colormap(tkwin), bgColor, &bg) == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid color name \"%s\"", bgColor)); Tcl_SetErrorCode(interp, "TK", "CURSOR", "COLOR", NULL); goto cleanup; } } /* * If there is no mask data, then create the cursor now. */ if ((!inTkTable && (argc == 2)) || (inTkTable && tkCursorPtr->mask == NULL)) { cursor = XCreatePixmapCursor(display, source, source, &fg, &fg, (unsigned) xHot, (unsigned) yHot); goto cleanup; } /* * Parse bitmap mask data and create cursor with fg and bg colors. */ if (inTkTable) { /* * This logic is like TkReadBitmapFile(). */ char *data; data = TkGetBitmapData(NULL, tkCursorPtr->mask, NULL, &maskWidth, &maskHeight, &dummy1, &dummy2); if (data == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "error reading bitmap mask data for \"%s\"", argv[0])); Tcl_SetErrorCode(interp, "TK", "CURSOR", "MASK_DATA", NULL); goto cleanup; } mask = XCreateBitmapFromData(display, drawable, data, maskWidth, maskHeight); ckfree(data); } else { if (TkReadBitmapFile(display, drawable, argv[1], (unsigned int *) &maskWidth, (unsigned int *) &maskHeight, &mask, &dummy1, &dummy2) != BitmapSuccess) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "cleanup reading bitmap file \"%s\"", argv[1])); Tcl_SetErrorCode(interp, "TK", "CURSOR", "MASK_FILE", NULL); goto cleanup; } } if ((maskWidth != width) || (maskHeight != height)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "source and mask bitmaps have different sizes", -1)); Tcl_SetErrorCode(interp, "TK", "CURSOR", "SIZE_MATCH", NULL); goto cleanup; } cursor = XCreatePixmapCursor(display, source, mask, &fg, &bg, (unsigned) xHot, (unsigned) yHot); cleanup: if (source != None) { Tk_FreePixmap(display, source); } if (mask != None) { Tk_FreePixmap(display, mask); } return cursor; }