diff options
author | patthoyts <patthoyts@noemail.net> | 2006-10-19 00:48:25 (GMT) |
---|---|---|
committer | patthoyts <patthoyts@noemail.net> | 2006-10-19 00:48:25 (GMT) |
commit | dedb639a811e3cef7c5578b7a695d2d8c37ffdec (patch) | |
tree | c6dacfee23b28ea641e28ddb04d9239fcde64169 | |
parent | bd1b792226469129da66d476fb8a34f199d6939d (diff) | |
download | tk-dedb639a811e3cef7c5578b7a695d2d8c37ffdec.zip tk-dedb639a811e3cef7c5578b7a695d2d8c37ffdec.tar.gz tk-dedb639a811e3cef7c5578b7a695d2d8c37ffdec.tar.bz2 |
generic/tkImgBmap.c: Fixed line endings.
win/makefile.vc: Patched up build system to manage
win/rules.vc: AMD64 with MSVC8
win/nmakehlp.c: Ensure operation without Platform SDK.
FossilOrigin-Name: baa01e99942369cdd9063e7542074d19a3bf73af
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | generic/tkImgBmap.c | 2588 | ||||
-rw-r--r-- | win/makefile.vc | 62 | ||||
-rw-r--r-- | win/nmakehlp.c | 317 | ||||
-rw-r--r-- | win/rules.vc | 132 |
5 files changed, 1667 insertions, 1439 deletions
@@ -1,3 +1,10 @@ +2006-10-19 Pat Thoyts <patthoyts@users.sourceforge.net> + + * generic/tkImgBmap.c: Fixed line endings. + * win/makefile.vc: Patched up build system to manage + * win/rules.vc: AMD64 with MSVC8 + * win/nmakehlp.c: Ensure operation without Platform SDK. + 2006-10-18 Don Porter <dgp@users.sourceforge.net> *** 8.5a5 TAGGED FOR RELEASE *** diff --git a/generic/tkImgBmap.c b/generic/tkImgBmap.c index 35b7ccd..7bae9fe 100644 --- a/generic/tkImgBmap.c +++ b/generic/tkImgBmap.c @@ -1,1294 +1,1294 @@ -/*
- * tkImgBmap.c --
- *
- * This procedure implements images of type "bitmap" for Tk.
- *
- * Copyright (c) 1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- * Copyright (c) 1999 by Scriptics Corporation.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkImgBmap.c,v 1.19 2006/09/21 00:01:05 dkf Exp $
- */
-
-#include "tkInt.h"
-#include "tkPort.h"
-
-/*
- * The following data structure represents the master for a bitmap
- * image:
- */
-
-typedef struct BitmapMaster {
- Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means the
- * image is being deleted. */
- Tcl_Interp *interp; /* Interpreter for application that is using
- * image. */
- Tcl_Command imageCmd; /* Token for image command (used to delete it
- * when the image goes away). NULL means the
- * image command has already been deleted. */
- int width, height; /* Dimensions of image. */
- char *data; /* Data comprising bitmap (suitable for input
- * to XCreateBitmapFromData). May be NULL if
- * no data. Malloc'ed. */
- char *maskData; /* Data for bitmap's mask (suitable for input
- * to XCreateBitmapFromData). Malloc'ed. */
- Tk_Uid fgUid; /* Value of -foreground option (malloc'ed). */
- Tk_Uid bgUid; /* Value of -background option (malloc'ed). */
- char *fileString; /* Value of -file option (malloc'ed). */
- char *dataString; /* Value of -data option (malloc'ed). */
- char *maskFileString; /* Value of -maskfile option (malloc'ed). */
- char *maskDataString; /* Value of -maskdata option (malloc'ed). */
- struct BitmapInstance *instancePtr;
- /* First in list of all instances associated
- * with this master. */
-} BitmapMaster;
-
-/*
- * The following data structure represents all of the instances of an image
- * that lie within a particular window:
- */
-
-typedef struct BitmapInstance {
- int refCount; /* Number of instances that share this data
- * structure. */
- BitmapMaster *masterPtr; /* Pointer to master for image. */
- Tk_Window tkwin; /* Window in which the instances will be
- * displayed. */
- XColor *fg; /* Foreground color for displaying image. */
- XColor *bg; /* Background color for displaying image. */
- Pixmap bitmap; /* The bitmap to display. */
- Pixmap mask; /* Mask: only display bitmap pixels where
- * there are 1's here. */
- GC gc; /* Graphics context for displaying bitmap.
- * None means there was an error while setting
- * up the instance, so it cannot be
- * displayed. */
- struct BitmapInstance *nextPtr;
- /* Next in list of all instance structures
- * associated with masterPtr (NULL means end
- * of list). */
-} BitmapInstance;
-
-/*
- * The type record for bitmap images:
- */
-
-static int GetByte(Tcl_Channel chan);
-static int ImgBmapCreate(Tcl_Interp *interp,
- char *name, int argc, Tcl_Obj *CONST objv[],
- Tk_ImageType *typePtr, Tk_ImageMaster master,
- ClientData *clientDataPtr);
-static ClientData ImgBmapGet(Tk_Window tkwin, ClientData clientData);
-static void ImgBmapDisplay(ClientData clientData,
- Display *display, Drawable drawable,
- int imageX, int imageY, int width, int height,
- int drawableX, int drawableY);
-static void ImgBmapFree(ClientData clientData, Display *display);
-static void ImgBmapDelete(ClientData clientData);
-static int ImgBmapPostscript(ClientData clientData,
- Tcl_Interp *interp, Tk_Window tkwin,
- Tk_PostscriptInfo psinfo, int x, int y,
- int width, int height, int prepass);
-
-Tk_ImageType tkBitmapImageType = {
- "bitmap", /* name */
- ImgBmapCreate, /* createProc */
- ImgBmapGet, /* getProc */
- ImgBmapDisplay, /* displayProc */
- ImgBmapFree, /* freeProc */
- ImgBmapDelete, /* deleteProc */
- ImgBmapPostscript, /* postscriptProc */
- NULL /* nextPtr */
-};
-
-/*
- * Information used for parsing configuration specs:
- */
-
-static Tk_ConfigSpec configSpecs[] = {
- {TK_CONFIG_UID, "-background", NULL, NULL,
- "", Tk_Offset(BitmapMaster, bgUid), 0},
- {TK_CONFIG_STRING, "-data", NULL, NULL,
- NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK},
- {TK_CONFIG_STRING, "-file", NULL, NULL,
- NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK},
- {TK_CONFIG_UID, "-foreground", NULL, NULL,
- "#000000", Tk_Offset(BitmapMaster, fgUid), 0},
- {TK_CONFIG_STRING, "-maskdata", NULL, NULL,
- NULL, Tk_Offset(BitmapMaster, maskDataString), TK_CONFIG_NULL_OK},
- {TK_CONFIG_STRING, "-maskfile", NULL, NULL,
- NULL, Tk_Offset(BitmapMaster, maskFileString), TK_CONFIG_NULL_OK},
- {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
-};
-
-/*
- * The following data structure is used to describe the state of parsing a
- * bitmap file or string. It is used for communication between TkGetBitmapData
- * and NextBitmapWord.
- */
-
-#define MAX_WORD_LENGTH 100
-typedef struct ParseInfo {
- char *string; /* Next character of string data for bitmap,
- * or NULL if bitmap is being read from
- * file. */
- Tcl_Channel chan; /* File containing bitmap data, or NULL if no
- * file. */
- char word[MAX_WORD_LENGTH+1];
- /* Current word of bitmap data, NULL
- * terminated. */
- int wordLength; /* Number of non-NULL bytes in word. */
-} ParseInfo;
-
-/*
- * Prototypes for procedures used only locally in this file:
- */
-
-static int ImgBmapCmd(ClientData clientData, Tcl_Interp *interp,
- int argc, Tcl_Obj *CONST objv[]);
-static void ImgBmapCmdDeletedProc(ClientData clientData);
-static void ImgBmapConfigureInstance(BitmapInstance *instancePtr);
-static int ImgBmapConfigureMaster(BitmapMaster *masterPtr,
- int argc, Tcl_Obj *CONST objv[], int flags);
-static int NextBitmapWord(ParseInfo *parseInfoPtr);
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapCreate --
- *
- * This procedure is called by the Tk image code to create "test" images.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * The data structure for a new image is allocated.
- *
- *----------------------------------------------------------------------
- */
-
- /* ARGSUSED */
-static int
-ImgBmapCreate(
- Tcl_Interp *interp, /* Interpreter for application containing
- * image. */
- char *name, /* Name to use for image. */
- int argc, /* Number of arguments. */
- Tcl_Obj *CONST argv[], /* Argument objects for options (doesn't
- * include image name or type). */
- Tk_ImageType *typePtr, /* Pointer to our type record (not used). */
- Tk_ImageMaster master, /* Token for image, to be used by us in later
- * callbacks. */
- ClientData *clientDataPtr) /* Store manager's token for image here; it
- * will be returned in later callbacks. */
-{
- BitmapMaster *masterPtr;
-
- masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster));
- masterPtr->tkMaster = master;
- masterPtr->interp = interp;
- masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgBmapCmd,
- (ClientData) masterPtr, ImgBmapCmdDeletedProc);
- masterPtr->width = masterPtr->height = 0;
- masterPtr->data = NULL;
- masterPtr->maskData = NULL;
- masterPtr->fgUid = NULL;
- masterPtr->bgUid = NULL;
- masterPtr->fileString = NULL;
- masterPtr->dataString = NULL;
- masterPtr->maskFileString = NULL;
- masterPtr->maskDataString = NULL;
- masterPtr->instancePtr = NULL;
- if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
- ImgBmapDelete((ClientData) masterPtr);
- return TCL_ERROR;
- }
- *clientDataPtr = (ClientData) masterPtr;
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapConfigureMaster --
- *
- * This procedure is called when a bitmap image is created or
- * reconfigured. It process configuration options and resets any
- * instances of the image.
- *
- * Results:
- * A standard Tcl return value. If TCL_ERROR is returned then an error
- * message is left in the masterPtr->interp's result.
- *
- * Side effects:
- * Existing instances of the image will be redisplayed to match the new
- * configuration options.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ImgBmapConfigureMaster(
- BitmapMaster *masterPtr, /* Pointer to data structure describing
- * overall bitmap image to (reconfigure). */
- int objc, /* Number of entries in objv. */
- Tcl_Obj *CONST objv[], /* Pairs of configuration options for image. */
- int flags) /* Flags to pass to Tk_ConfigureWidget, such
- * as TK_CONFIG_ARGV_ONLY. */
-{
- BitmapInstance *instancePtr;
- int maskWidth, maskHeight, dummy1, dummy2;
-
- CONST char **argv = (CONST char **) ckalloc((objc+1) * sizeof(char *));
- for (dummy1 = 0; dummy1 < objc; dummy1++) {
- argv[dummy1]=Tcl_GetString(objv[dummy1]);
- }
- argv[objc] = NULL;
-
- if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
- configSpecs, objc, argv, (char *) masterPtr, flags)
- != TCL_OK) {
- ckfree((char *) argv);
- return TCL_ERROR;
- }
- ckfree((char *) argv);
-
- /*
- * Parse the bitmap and/or mask to create binary data. Make sure that the
- * bitmap and mask have the same dimensions.
- */
-
- if (masterPtr->data != NULL) {
- ckfree(masterPtr->data);
- masterPtr->data = NULL;
- }
- if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) {
- masterPtr->data = TkGetBitmapData(masterPtr->interp,
- masterPtr->dataString, masterPtr->fileString,
- &masterPtr->width, &masterPtr->height, &dummy1, &dummy2);
- if (masterPtr->data == NULL) {
- return TCL_ERROR;
- }
- }
- if (masterPtr->maskData != NULL) {
- ckfree(masterPtr->maskData);
- masterPtr->maskData = NULL;
- }
- if ((masterPtr->maskFileString != NULL)
- || (masterPtr->maskDataString != NULL)) {
- if (masterPtr->data == NULL) {
- Tcl_SetResult(masterPtr->interp, "can't have mask without bitmap",
- TCL_STATIC);
- return TCL_ERROR;
- }
- masterPtr->maskData = TkGetBitmapData(masterPtr->interp,
- masterPtr->maskDataString, masterPtr->maskFileString,
- &maskWidth, &maskHeight, &dummy1, &dummy2);
- if (masterPtr->maskData == NULL) {
- return TCL_ERROR;
- }
- if ((maskWidth != masterPtr->width)
- || (maskHeight != masterPtr->height)) {
- ckfree(masterPtr->maskData);
- masterPtr->maskData = NULL;
- Tcl_SetResult(masterPtr->interp,
- "bitmap and mask have different sizes", TCL_STATIC);
- return TCL_ERROR;
- }
- }
-
- /*
- * Cycle through all of the instances of this image, regenerating the
- * information for each instance. Then force the image to be redisplayed
- * everywhere that it is used.
- */
-
- for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
- instancePtr = instancePtr->nextPtr) {
- ImgBmapConfigureInstance(instancePtr);
- }
- Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
- masterPtr->height, masterPtr->width, masterPtr->height);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapConfigureInstance --
- *
- * This procedure is called to create displaying information for a bitmap
- * image instance based on the configuration information in the master.
- * It is invoked both when new instances are created and when the master
- * is reconfigured.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Generates errors via Tcl_BackgroundError if there are problems in
- * setting up the instance.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ImgBmapConfigureInstance(
- BitmapInstance *instancePtr)/* Instance to reconfigure. */
-{
- BitmapMaster *masterPtr = instancePtr->masterPtr;
- XColor *colorPtr;
- XGCValues gcValues;
- GC gc;
- unsigned int mask;
- Pixmap oldBitmap, oldMask;
-
- /*
- * For each of the options in masterPtr, translate the string form into an
- * internal form appropriate for instancePtr.
- */
-
- if (*masterPtr->bgUid != 0) {
- colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
- masterPtr->bgUid);
- if (colorPtr == NULL) {
- goto error;
- }
- } else {
- colorPtr = NULL;
- }
- if (instancePtr->bg != NULL) {
- Tk_FreeColor(instancePtr->bg);
- }
- instancePtr->bg = colorPtr;
-
- colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
- masterPtr->fgUid);
- if (colorPtr == NULL) {
- goto error;
- }
- if (instancePtr->fg != NULL) {
- Tk_FreeColor(instancePtr->fg);
- }
- instancePtr->fg = colorPtr;
-
- /*
- * Careful: We have to allocate new Pixmaps before deleting the old ones.
- * Otherwise, The XID allocator will always return the same XID for the
- * new Pixmaps as was used for the old Pixmaps. And that will prevent the
- * data and/or mask from changing in the GC below.
- */
-
- oldBitmap = instancePtr->bitmap;
- instancePtr->bitmap = None;
- oldMask = instancePtr->mask;
- instancePtr->mask = None;
-
- if (masterPtr->data != NULL) {
- instancePtr->bitmap = XCreateBitmapFromData(
- Tk_Display(instancePtr->tkwin),
- RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
- masterPtr->data, (unsigned) masterPtr->width,
- (unsigned) masterPtr->height);
- }
- if (masterPtr->maskData != NULL) {
- instancePtr->mask = XCreateBitmapFromData(
- Tk_Display(instancePtr->tkwin),
- RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
- masterPtr->maskData, (unsigned) masterPtr->width,
- (unsigned) masterPtr->height);
- }
-
- if (oldMask != None) {
- Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldMask);
- }
- if (oldBitmap != None) {
- Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldBitmap);
- }
-
- if (masterPtr->data != NULL) {
- gcValues.foreground = instancePtr->fg->pixel;
- gcValues.graphics_exposures = False;
- mask = GCForeground|GCGraphicsExposures;
- if (instancePtr->bg != NULL) {
- gcValues.background = instancePtr->bg->pixel;
- mask |= GCBackground;
- if (instancePtr->mask != None) {
- gcValues.clip_mask = instancePtr->mask;
- mask |= GCClipMask;
- }
- } else {
- gcValues.clip_mask = instancePtr->bitmap;
- mask |= GCClipMask;
- }
- gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues);
- } else {
- gc = None;
- }
- if (instancePtr->gc != None) {
- Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
- }
- instancePtr->gc = gc;
- return;
-
- error:
- /*
- * An error occurred: clear the graphics context in the instance to make
- * it clear that this instance cannot be displayed. Then report the error.
- */
-
- if (instancePtr->gc != None) {
- Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
- }
- instancePtr->gc = None;
- Tcl_AddErrorInfo(masterPtr->interp, "\n (while configuring image \"");
- Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
- Tcl_AddErrorInfo(masterPtr->interp, "\")");
- Tcl_BackgroundError(masterPtr->interp);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkGetBitmapData --
- *
- * Given a file name or ASCII string, this procedure parses the file or
- * string contents to produce binary data for a bitmap.
- *
- * Results:
- * If the bitmap description was parsed successfully then the return
- * value is a malloc-ed array containing the bitmap data. The dimensions
- * of the data are stored in *widthPtr and *heightPtr. *hotXPtr and
- * *hotYPtr are set to the bitmap hotspot if one is defined, otherwise
- * they are set to -1, -1. If an error occurred, NULL is returned and an
- * error message is left in the interp's result.
- *
- * Side effects:
- * A bitmap is created.
- *
- *----------------------------------------------------------------------
- */
-
-char *
-TkGetBitmapData(
- Tcl_Interp *interp, /* For reporting errors, or NULL. */
- char *string, /* String describing bitmap. May be NULL. */
- char *fileName, /* Name of file containing bitmap description.
- * Used only if string is NULL. Must not be
- * NULL if string is NULL. */
- int *widthPtr, int *heightPtr,
- /* Dimensions of bitmap get returned here. */
- int *hotXPtr, int *hotYPtr) /* Position of hot spot or -1,-1. */
-{
- int width, height, numBytes, hotX, hotY;
- CONST char *expandedFileName;
- char *p, *end;
- ParseInfo pi;
- char *data = NULL;
- Tcl_DString buffer;
-
- pi.string = string;
- if (string == NULL) {
- if ((interp != NULL) && Tcl_IsSafe(interp)) {
- Tcl_AppendResult(interp, "can't get bitmap data from a file in a",
- " safe interpreter", NULL);
- return NULL;
- }
- expandedFileName = Tcl_TranslateFileName(interp, fileName, &buffer);
- if (expandedFileName == NULL) {
- return NULL;
- }
- pi.chan = Tcl_OpenFileChannel(interp, expandedFileName, "r", 0);
- Tcl_DStringFree(&buffer);
- if (pi.chan == NULL) {
- if (interp != NULL) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "couldn't read bitmap file \"",
- fileName, "\": ", Tcl_PosixError(interp), NULL);
- }
- return NULL;
- }
-
- if (Tcl_SetChannelOption(interp, pi.chan, "-translation", "binary")
- != TCL_OK) {
- return NULL;
- }
- if (Tcl_SetChannelOption(interp, pi.chan, "-encoding", "binary")
- != TCL_OK) {
- return NULL;
- }
- } else {
- pi.chan = NULL;
- }
-
- /*
- * Parse the lines that define the dimensions of the bitmap, plus the
- * first line that defines the bitmap data (it declares the name of a data
- * variable but doesn't include any actual data). These lines look
- * something like the following:
- *
- * #define foo_width 16
- * #define foo_height 16
- * #define foo_x_hot 3
- * #define foo_y_hot 3
- * static char foo_bits[] = {
- *
- * The x_hot and y_hot lines may or may not be present. It's important to
- * check for "char" in the last line, in order to reject old X10-style
- * bitmaps that used shorts.
- */
-
- width = 0;
- height = 0;
- hotX = -1;
- hotY = -1;
- while (1) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
- && (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- width = strtol(pi.word, &end, 0);
- if ((end == pi.word) || (*end != 0)) {
- goto error;
- }
- } else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_')
- && (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- height = strtol(pi.word, &end, 0);
- if ((end == pi.word) || (*end != 0)) {
- goto error;
- }
- } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
- && (strcmp(pi.word+pi.wordLength-6, "_x_hot") == 0)) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- hotX = strtol(pi.word, &end, 0);
- if ((end == pi.word) || (*end != 0)) {
- goto error;
- }
- } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
- && (strcmp(pi.word+pi.wordLength-6, "_y_hot") == 0)) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- hotY = strtol(pi.word, &end, 0);
- if ((end == pi.word) || (*end != 0)) {
- goto error;
- }
- } else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) {
- while (1) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
- goto getData;
- }
- }
- } else if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
- if (interp != NULL) {
- Tcl_AppendResult(interp, "format error in bitmap data; ",
- "looks like it's an obsolete X10 bitmap file", NULL);
- }
- goto errorCleanup;
- }
- }
-
- /*
- * Now we've read everything but the data. Allocate an array and read in
- * the data.
- */
-
- getData:
- if ((width <= 0) || (height <= 0)) {
- goto error;
- }
- numBytes = ((width+7)/8) * height;
- data = (char *) ckalloc((unsigned) numBytes);
- for (p = data; numBytes > 0; p++, numBytes--) {
- if (NextBitmapWord(&pi) != TCL_OK) {
- goto error;
- }
- *p = (char) strtol(pi.word, &end, 0);
- if (end == pi.word) {
- goto error;
- }
- }
-
- /*
- * All done. Clean up and return.
- */
-
- if (pi.chan != NULL) {
- Tcl_Close(NULL, pi.chan);
- }
- *widthPtr = width;
- *heightPtr = height;
- *hotXPtr = hotX;
- *hotYPtr = hotY;
- return data;
-
- error:
- if (interp != NULL) {
- Tcl_SetResult(interp, "format error in bitmap data", TCL_STATIC);
- }
-
- errorCleanup:
- if (data != NULL) {
- ckfree(data);
- }
- if (pi.chan != NULL) {
- Tcl_Close(NULL, pi.chan);
- }
- return NULL;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NextBitmapWord --
- *
- * This procedure retrieves the next word of information (stuff between
- * commas or white space) from a bitmap description.
- *
- * Results:
- * Returns TCL_OK if all went well. In this case the next word, and its
- * length, will be availble in *parseInfoPtr. If the end of the bitmap
- * description was reached then TCL_ERROR is returned.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NextBitmapWord(
- ParseInfo *parseInfoPtr) /* Describes what we're reading and where we
- * are in it. */
-{
- char *src, *dst;
- int c;
-
- parseInfoPtr->wordLength = 0;
- dst = parseInfoPtr->word;
- if (parseInfoPtr->string != NULL) {
- for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ',');
- src++) {
- if (*src == 0) {
- return TCL_ERROR;
- }
- }
- for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) {
- *dst = *src;
- dst++;
- parseInfoPtr->wordLength++;
- if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
- return TCL_ERROR;
- }
- }
- parseInfoPtr->string = src;
- } else {
- for (c = GetByte(parseInfoPtr->chan); isspace(UCHAR(c)) || (c == ',');
- c = GetByte(parseInfoPtr->chan)) {
- if (c == EOF) {
- return TCL_ERROR;
- }
- }
- for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF);
- c = GetByte(parseInfoPtr->chan)) {
- *dst = c;
- dst++;
- parseInfoPtr->wordLength++;
- if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
- return TCL_ERROR;
- }
- }
- }
- if (parseInfoPtr->wordLength == 0) {
- return TCL_ERROR;
- }
- parseInfoPtr->word[parseInfoPtr->wordLength] = 0;
- return TCL_OK;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * ImgBmapCmd --
- *
- * This procedure is invoked to process the Tcl command that corresponds
- * to an image managed by this module. See the user documentation for
- * details on what it does.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-static int
-ImgBmapCmd(
- ClientData clientData, /* Information about the image master. */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *CONST objv[]) /* Argument objects. */
-{
- static CONST char *bmapOptions[] = {"cget", "configure", NULL};
- BitmapMaster *masterPtr = (BitmapMaster *) clientData;
- int index;
-
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
- return TCL_ERROR;
- }
- if (Tcl_GetIndexFromObj(interp, objv[1], bmapOptions, "option", 0,
- &index) != TCL_OK) {
- return TCL_ERROR;
- }
- switch (index) {
- case 0: /* cget */
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "option");
- return TCL_ERROR;
- }
- return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
- (char *) masterPtr, Tcl_GetString(objv[2]), 0);
- case 1: /* configure */
- if (objc == 2) {
- return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
- configSpecs, (char *) masterPtr, NULL, 0);
- } else if (objc == 3) {
- return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
- configSpecs, (char *) masterPtr,
- Tcl_GetString(objv[2]), 0);
- } else {
- return ImgBmapConfigureMaster(masterPtr, objc-2, objv+2,
- TK_CONFIG_ARGV_ONLY);
- }
- default:
- Tcl_Panic("bad const entries to bmapOptions in ImgBmapCmd");
- return TCL_OK;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapGet --
- *
- * This procedure is called for each use of a bitmap image in a widget.
- *
- * Results:
- * The return value is a token for the instance, which is passed back to
- * us in calls to ImgBmapDisplay and ImgBmapFree.
- *
- * Side effects:
- * A data structure is set up for the instance (or, an existing instance
- * is re-used for the new one).
- *
- *----------------------------------------------------------------------
- */
-
-static ClientData
-ImgBmapGet(
- Tk_Window tkwin, /* Window in which the instance will be
- * used. */
- ClientData masterData) /* Pointer to our master structure for the
- * image. */
-{
- BitmapMaster *masterPtr = (BitmapMaster *) masterData;
- BitmapInstance *instancePtr;
-
- /*
- * See if there is already an instance for this window. If so then just
- * re-use it.
- */
-
- for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
- instancePtr = instancePtr->nextPtr) {
- if (instancePtr->tkwin == tkwin) {
- instancePtr->refCount++;
- return (ClientData) instancePtr;
- }
- }
-
- /*
- * The image isn't already in use in this window. Make a new instance of
- * the image.
- */
-
- instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance));
- instancePtr->refCount = 1;
- instancePtr->masterPtr = masterPtr;
- instancePtr->tkwin = tkwin;
- instancePtr->fg = NULL;
- instancePtr->bg = NULL;
- instancePtr->bitmap = None;
- instancePtr->mask = None;
- instancePtr->gc = None;
- instancePtr->nextPtr = masterPtr->instancePtr;
- masterPtr->instancePtr = instancePtr;
- ImgBmapConfigureInstance(instancePtr);
-
- /*
- * If this is the first instance, must set the size of the image.
- */
-
- if (instancePtr->nextPtr == NULL) {
- Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
- masterPtr->height);
- }
-
- return (ClientData) instancePtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapDisplay --
- *
- * This procedure is invoked to draw a bitmap image.
- *
- * Results:
- * None.
- *
- * Side effects:
- * A portion of the image gets rendered in a pixmap or window.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ImgBmapDisplay(
- ClientData clientData, /* Pointer to BitmapInstance structure for
- * instance to be displayed. */
- Display *display, /* Display on which to draw image. */
- Drawable drawable, /* Pixmap or window in which to draw image. */
- int imageX, int imageY, /* Upper-left corner of region within image to
- * draw. */
- int width, int height, /* Dimensions of region within image to draw. */
- int drawableX, int drawableY)
- /* Coordinates within drawable that correspond
- * to imageX and imageY. */
-{
- BitmapInstance *instancePtr = (BitmapInstance *) clientData;
- int masking;
-
- /*
- * If there's no graphics context, it means that an error occurred while
- * creating the image instance so it can't be displayed.
- */
-
- if (instancePtr->gc == None) {
- return;
- }
-
- /*
- * If masking is in effect, must modify the mask origin within the
- * graphics context to line up with the image's origin. Then draw the
- * image and reset the clip origin, if there's a mask.
- */
-
- masking = (instancePtr->mask != None) || (instancePtr->bg == NULL);
- if (masking) {
- XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
- drawableY - imageY);
- }
- XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc,
- imageX, imageY, (unsigned) width, (unsigned) height,
- drawableX, drawableY, 1);
- if (masking) {
- XSetClipOrigin(display, instancePtr->gc, 0, 0);
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapFree --
- *
- * This procedure is called when a widget ceases to use a particular
- * instance of an image.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Internal data structures get cleaned up.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ImgBmapFree(
- ClientData clientData, /* Pointer to BitmapInstance structure for
- * instance to be displayed. */
- Display *display) /* Display containing window that used image. */
-{
- BitmapInstance *instancePtr = (BitmapInstance *) clientData;
- BitmapInstance *prevPtr;
-
- instancePtr->refCount--;
- if (instancePtr->refCount > 0) {
- return;
- }
-
- /*
- * There are no more uses of the image within this widget. Free the
- * instance structure.
- */
-
- if (instancePtr->fg != NULL) {
- Tk_FreeColor(instancePtr->fg);
- }
- if (instancePtr->bg != NULL) {
- Tk_FreeColor(instancePtr->bg);
- }
- if (instancePtr->bitmap != None) {
- Tk_FreePixmap(display, instancePtr->bitmap);
- }
- if (instancePtr->mask != None) {
- Tk_FreePixmap(display, instancePtr->mask);
- }
- if (instancePtr->gc != None) {
- Tk_FreeGC(display, instancePtr->gc);
- }
- if (instancePtr->masterPtr->instancePtr == instancePtr) {
- instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
- } else {
- for (prevPtr = instancePtr->masterPtr->instancePtr;
- prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
- /* Empty loop body */
- }
- prevPtr->nextPtr = instancePtr->nextPtr;
- }
- ckfree((char *) instancePtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapDelete --
- *
- * This procedure is called by the image code to delete the master
- * structure for an image.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Resources associated with the image get freed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ImgBmapDelete(
- ClientData masterData) /* Pointer to BitmapMaster structure for
- * image. Must not have any more instances. */
-{
- BitmapMaster *masterPtr = (BitmapMaster *) masterData;
-
- if (masterPtr->instancePtr != NULL) {
- Tcl_Panic("tried to delete bitmap image when instances still exist");
- }
- masterPtr->tkMaster = NULL;
- if (masterPtr->imageCmd != NULL) {
- Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
- }
- if (masterPtr->data != NULL) {
- ckfree(masterPtr->data);
- }
- if (masterPtr->maskData != NULL) {
- ckfree(masterPtr->maskData);
- }
- Tk_FreeOptions(configSpecs, (char *) masterPtr, NULL, 0);
- ckfree((char *) masterPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapCmdDeletedProc --
- *
- * This procedure is invoked when the image command for an image is
- * deleted. It deletes the image.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The image is deleted.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-ImgBmapCmdDeletedProc(
- ClientData clientData) /* Pointer to BitmapMaster structure for
- * image. */
-{
- BitmapMaster *masterPtr = (BitmapMaster *) clientData;
-
- masterPtr->imageCmd = NULL;
- if (masterPtr->tkMaster != NULL) {
- Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * GetByte --
- *
- * Get the next byte from the open channel.
- *
- * Results:
- * The next byte or EOF.
- *
- * Side effects:
- * We read from the channel.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-GetByte(
- Tcl_Channel chan) /* The channel we read from. */
-{
- char buffer;
- int size;
-
- size = Tcl_Read(chan, &buffer, 1);
- if (size <= 0) {
- return EOF;
- } else {
- return buffer;
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapPsImagemask --
- *
- * This procedure generates postscript suitable for rendering a single
- * bitmap of an image. A single bitmap image might contain both a
- * foreground and a background bitmap. This routine is called once for
- * each such bitmap in a bitmap image.
- *
- * Prior to invoking this routine, the following setup has occurred:
- *
- * 1. The postscript foreground color has been set to the color used
- * to render the bitmap.
- *
- * 2. The origin of the postscript coordinate system is set to the
- * lower left corner of the bitmap.
- *
- * 3. The postscript coordinate system has been scaled so that the
- * entire bitmap is one unit squared.
- *
- * Some postscript implementations cannot handle bitmap strings longer
- * than about 60k characters. If the bitmap data is that big or bigger,
- * then we render it by splitting it into several smaller bitmaps.
- *
- * Results:
- * Returns TCL_OK on success. Returns TCL_ERROR and leaves and error
- * message in interp->result if there is a problem.
- *
- * Side effects:
- * Postscript code is appended to interp->result.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ImgBmapPsImagemask(
- Tcl_Interp *interp, /* Append postscript to this interpreter */
- int width, int height, /* Width and height of the bitmap in pixels */
- char *data) /* Data for the bitmap */
-{
- int i, j, nBytePerRow;
- char buffer[200];
-
- /*
- * The bit order of bitmaps in Tk is the opposite of the bit order that
- * postscript uses. (In Tk, the least significant bit is on the right side
- * of the bitmap and in postscript the least significant bit is shown on
- * the left.) The following array is used to reverse the order of bits
- * within a byte so that the bits will be in the order postscript expects.
- */
-
- static unsigned char bit_reverse[] = {
- 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
- 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
- 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
- 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
- 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
- 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
- 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
- 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
- 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
- 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
- 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
- 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
- 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
- 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
- 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
- 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255,
- };
-
- if (width*height > 60000) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "unable to generate postscript for bitmaps "
- "larger than 60000 pixels", NULL);
- return TCL_ERROR;
- }
-
- sprintf(buffer, "0 0 moveto %d %d true [%d 0 0 %d 0 %d] {<\n",
- width, height, width, -height, height);
- Tcl_AppendResult(interp, buffer, NULL);
-
- nBytePerRow = (width+7)/8;
- for(i=0; i<height; i++){
- for(j=0; j<nBytePerRow; j++){
- sprintf(buffer, " %02x",
- bit_reverse[0xff & data[i*nBytePerRow + j]]);
- Tcl_AppendResult(interp, buffer, NULL);
- }
- Tcl_AppendResult(interp, "\n", NULL);
- }
-
- Tcl_AppendResult(interp, ">} imagemask \n", NULL);
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ImgBmapPostscript --
- *
- * This procedure generates postscript for rendering a bitmap image.
- *
- * Results:
-
- * On success, this routine writes postscript code into interp->result
- * and returns TCL_OK TCL_ERROR is returned and an error message is left
- * in interp->result if anything goes wrong.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-ImgBmapPostscript(
- ClientData clientData,
- Tcl_Interp *interp,
- Tk_Window tkwin,
- Tk_PostscriptInfo psinfo,
- int x, int y, int width, int height,
- int prepass)
-{
- BitmapMaster *masterPtr = (BitmapMaster *) clientData;
- char buffer[200];
-
- if (prepass) {
- return TCL_OK;
- }
-
- /*
- * There is nothing to do for bitmaps with zero width or height.
- */
-
- if (width<=0 || height<=0 || masterPtr->width<=0 || masterPtr->height<= 0){
- return TCL_OK;
- }
-
- /*
- * Translate the origin of the coordinate system to be the lower-left
- * corner of the bitmap and adjust the scale of the coordinate system so
- * that entire bitmap covers one square unit of the page. The calling
- * function put a "gsave" into the postscript and will add a "grestore" at
- * after this routine returns, so it is safe to make whatever changes are
- * necessary here.
- */
-
- if (x!=0 || y!=0) {
- sprintf(buffer, "%d %d moveto\n", x, y);
- Tcl_AppendResult(interp, buffer, NULL);
- }
- if (width!=1 || height!=1) {
- sprintf(buffer, "%d %d scale\n", width, height);
- Tcl_AppendResult(interp, buffer, NULL);
- }
-
- /*
- * Color the background, if there is one. This step is skipped if the
- * background is transparent. If the background is not transparent and
- * there is no background mask, then color the complete rectangle that
- * encloses the bitmap. If there is a background mask, then only apply
- * color to the bits specified by the mask.
- */
-
- if ((masterPtr->bgUid != NULL) && (masterPtr->bgUid[0] != '\000')) {
- XColor color;
-
- XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid,
- &color);
- if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {
- return TCL_ERROR;
- }
- if (masterPtr->maskData == NULL) {
- Tcl_AppendResult(interp,
- "0 0 moveto 1 0 rlineto 0 1 rlineto -1 0 rlineto ",
- "closepath fill\n", NULL);
- } else if (ImgBmapPsImagemask(interp, masterPtr->width,
- masterPtr->height, masterPtr->maskData) != TCL_OK) {
- return TCL_ERROR;
- }
- }
-
- /*
- * Draw the bitmap foreground, assuming there is one.
- */
-
- if ((masterPtr->fgUid != NULL) && (masterPtr->data != NULL)) {
- XColor color;
-
- XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->fgUid,
- &color);
- if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {
- return TCL_ERROR;
- }
- if (ImgBmapPsImagemask(interp, masterPtr->width, masterPtr->height,
- masterPtr->data) != TCL_OK) {
- return TCL_ERROR;
- }
- }
- return TCL_OK;
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */
+/* + * tkImgBmap.c -- + * + * This procedure implements images of type "bitmap" for Tk. + * + * Copyright (c) 1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1999 by Scriptics Corporation. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkImgBmap.c,v 1.20 2006/10/19 00:48:25 patthoyts Exp $ + */ + +#include "tkInt.h" +#include "tkPort.h" + +/* + * The following data structure represents the master for a bitmap + * image: + */ + +typedef struct BitmapMaster { + Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means the + * image is being deleted. */ + Tcl_Interp *interp; /* Interpreter for application that is using + * image. */ + Tcl_Command imageCmd; /* Token for image command (used to delete it + * when the image goes away). NULL means the + * image command has already been deleted. */ + int width, height; /* Dimensions of image. */ + char *data; /* Data comprising bitmap (suitable for input + * to XCreateBitmapFromData). May be NULL if + * no data. Malloc'ed. */ + char *maskData; /* Data for bitmap's mask (suitable for input + * to XCreateBitmapFromData). Malloc'ed. */ + Tk_Uid fgUid; /* Value of -foreground option (malloc'ed). */ + Tk_Uid bgUid; /* Value of -background option (malloc'ed). */ + char *fileString; /* Value of -file option (malloc'ed). */ + char *dataString; /* Value of -data option (malloc'ed). */ + char *maskFileString; /* Value of -maskfile option (malloc'ed). */ + char *maskDataString; /* Value of -maskdata option (malloc'ed). */ + struct BitmapInstance *instancePtr; + /* First in list of all instances associated + * with this master. */ +} BitmapMaster; + +/* + * The following data structure represents all of the instances of an image + * that lie within a particular window: + */ + +typedef struct BitmapInstance { + int refCount; /* Number of instances that share this data + * structure. */ + BitmapMaster *masterPtr; /* Pointer to master for image. */ + Tk_Window tkwin; /* Window in which the instances will be + * displayed. */ + XColor *fg; /* Foreground color for displaying image. */ + XColor *bg; /* Background color for displaying image. */ + Pixmap bitmap; /* The bitmap to display. */ + Pixmap mask; /* Mask: only display bitmap pixels where + * there are 1's here. */ + GC gc; /* Graphics context for displaying bitmap. + * None means there was an error while setting + * up the instance, so it cannot be + * displayed. */ + struct BitmapInstance *nextPtr; + /* Next in list of all instance structures + * associated with masterPtr (NULL means end + * of list). */ +} BitmapInstance; + +/* + * The type record for bitmap images: + */ + +static int GetByte(Tcl_Channel chan); +static int ImgBmapCreate(Tcl_Interp *interp, + char *name, int argc, Tcl_Obj *CONST objv[], + Tk_ImageType *typePtr, Tk_ImageMaster master, + ClientData *clientDataPtr); +static ClientData ImgBmapGet(Tk_Window tkwin, ClientData clientData); +static void ImgBmapDisplay(ClientData clientData, + Display *display, Drawable drawable, + int imageX, int imageY, int width, int height, + int drawableX, int drawableY); +static void ImgBmapFree(ClientData clientData, Display *display); +static void ImgBmapDelete(ClientData clientData); +static int ImgBmapPostscript(ClientData clientData, + Tcl_Interp *interp, Tk_Window tkwin, + Tk_PostscriptInfo psinfo, int x, int y, + int width, int height, int prepass); + +Tk_ImageType tkBitmapImageType = { + "bitmap", /* name */ + ImgBmapCreate, /* createProc */ + ImgBmapGet, /* getProc */ + ImgBmapDisplay, /* displayProc */ + ImgBmapFree, /* freeProc */ + ImgBmapDelete, /* deleteProc */ + ImgBmapPostscript, /* postscriptProc */ + NULL /* nextPtr */ +}; + +/* + * Information used for parsing configuration specs: + */ + +static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_UID, "-background", NULL, NULL, + "", Tk_Offset(BitmapMaster, bgUid), 0}, + {TK_CONFIG_STRING, "-data", NULL, NULL, + NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_STRING, "-file", NULL, NULL, + NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_UID, "-foreground", NULL, NULL, + "#000000", Tk_Offset(BitmapMaster, fgUid), 0}, + {TK_CONFIG_STRING, "-maskdata", NULL, NULL, + NULL, Tk_Offset(BitmapMaster, maskDataString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_STRING, "-maskfile", NULL, NULL, + NULL, Tk_Offset(BitmapMaster, maskFileString), TK_CONFIG_NULL_OK}, + {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0} +}; + +/* + * The following data structure is used to describe the state of parsing a + * bitmap file or string. It is used for communication between TkGetBitmapData + * and NextBitmapWord. + */ + +#define MAX_WORD_LENGTH 100 +typedef struct ParseInfo { + char *string; /* Next character of string data for bitmap, + * or NULL if bitmap is being read from + * file. */ + Tcl_Channel chan; /* File containing bitmap data, or NULL if no + * file. */ + char word[MAX_WORD_LENGTH+1]; + /* Current word of bitmap data, NULL + * terminated. */ + int wordLength; /* Number of non-NULL bytes in word. */ +} ParseInfo; + +/* + * Prototypes for procedures used only locally in this file: + */ + +static int ImgBmapCmd(ClientData clientData, Tcl_Interp *interp, + int argc, Tcl_Obj *CONST objv[]); +static void ImgBmapCmdDeletedProc(ClientData clientData); +static void ImgBmapConfigureInstance(BitmapInstance *instancePtr); +static int ImgBmapConfigureMaster(BitmapMaster *masterPtr, + int argc, Tcl_Obj *CONST objv[], int flags); +static int NextBitmapWord(ParseInfo *parseInfoPtr); + +/* + *---------------------------------------------------------------------- + * + * ImgBmapCreate -- + * + * This procedure is called by the Tk image code to create "test" images. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * The data structure for a new image is allocated. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static int +ImgBmapCreate( + Tcl_Interp *interp, /* Interpreter for application containing + * image. */ + char *name, /* Name to use for image. */ + int argc, /* Number of arguments. */ + Tcl_Obj *CONST argv[], /* Argument objects for options (doesn't + * include image name or type). */ + Tk_ImageType *typePtr, /* Pointer to our type record (not used). */ + Tk_ImageMaster master, /* Token for image, to be used by us in later + * callbacks. */ + ClientData *clientDataPtr) /* Store manager's token for image here; it + * will be returned in later callbacks. */ +{ + BitmapMaster *masterPtr; + + masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster)); + masterPtr->tkMaster = master; + masterPtr->interp = interp; + masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgBmapCmd, + (ClientData) masterPtr, ImgBmapCmdDeletedProc); + masterPtr->width = masterPtr->height = 0; + masterPtr->data = NULL; + masterPtr->maskData = NULL; + masterPtr->fgUid = NULL; + masterPtr->bgUid = NULL; + masterPtr->fileString = NULL; + masterPtr->dataString = NULL; + masterPtr->maskFileString = NULL; + masterPtr->maskDataString = NULL; + masterPtr->instancePtr = NULL; + if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) { + ImgBmapDelete((ClientData) masterPtr); + return TCL_ERROR; + } + *clientDataPtr = (ClientData) masterPtr; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapConfigureMaster -- + * + * This procedure is called when a bitmap image is created or + * reconfigured. It process configuration options and resets any + * instances of the image. + * + * Results: + * A standard Tcl return value. If TCL_ERROR is returned then an error + * message is left in the masterPtr->interp's result. + * + * Side effects: + * Existing instances of the image will be redisplayed to match the new + * configuration options. + * + *---------------------------------------------------------------------- + */ + +static int +ImgBmapConfigureMaster( + BitmapMaster *masterPtr, /* Pointer to data structure describing + * overall bitmap image to (reconfigure). */ + int objc, /* Number of entries in objv. */ + Tcl_Obj *CONST objv[], /* Pairs of configuration options for image. */ + int flags) /* Flags to pass to Tk_ConfigureWidget, such + * as TK_CONFIG_ARGV_ONLY. */ +{ + BitmapInstance *instancePtr; + int maskWidth, maskHeight, dummy1, dummy2; + + CONST char **argv = (CONST char **) ckalloc((objc+1) * sizeof(char *)); + for (dummy1 = 0; dummy1 < objc; dummy1++) { + argv[dummy1]=Tcl_GetString(objv[dummy1]); + } + argv[objc] = NULL; + + if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp), + configSpecs, objc, argv, (char *) masterPtr, flags) + != TCL_OK) { + ckfree((char *) argv); + return TCL_ERROR; + } + ckfree((char *) argv); + + /* + * Parse the bitmap and/or mask to create binary data. Make sure that the + * bitmap and mask have the same dimensions. + */ + + if (masterPtr->data != NULL) { + ckfree(masterPtr->data); + masterPtr->data = NULL; + } + if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) { + masterPtr->data = TkGetBitmapData(masterPtr->interp, + masterPtr->dataString, masterPtr->fileString, + &masterPtr->width, &masterPtr->height, &dummy1, &dummy2); + if (masterPtr->data == NULL) { + return TCL_ERROR; + } + } + if (masterPtr->maskData != NULL) { + ckfree(masterPtr->maskData); + masterPtr->maskData = NULL; + } + if ((masterPtr->maskFileString != NULL) + || (masterPtr->maskDataString != NULL)) { + if (masterPtr->data == NULL) { + Tcl_SetResult(masterPtr->interp, "can't have mask without bitmap", + TCL_STATIC); + return TCL_ERROR; + } + masterPtr->maskData = TkGetBitmapData(masterPtr->interp, + masterPtr->maskDataString, masterPtr->maskFileString, + &maskWidth, &maskHeight, &dummy1, &dummy2); + if (masterPtr->maskData == NULL) { + return TCL_ERROR; + } + if ((maskWidth != masterPtr->width) + || (maskHeight != masterPtr->height)) { + ckfree(masterPtr->maskData); + masterPtr->maskData = NULL; + Tcl_SetResult(masterPtr->interp, + "bitmap and mask have different sizes", TCL_STATIC); + return TCL_ERROR; + } + } + + /* + * Cycle through all of the instances of this image, regenerating the + * information for each instance. Then force the image to be redisplayed + * everywhere that it is used. + */ + + for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; + instancePtr = instancePtr->nextPtr) { + ImgBmapConfigureInstance(instancePtr); + } + Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width, + masterPtr->height, masterPtr->width, masterPtr->height); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapConfigureInstance -- + * + * This procedure is called to create displaying information for a bitmap + * image instance based on the configuration information in the master. + * It is invoked both when new instances are created and when the master + * is reconfigured. + * + * Results: + * None. + * + * Side effects: + * Generates errors via Tcl_BackgroundError if there are problems in + * setting up the instance. + * + *---------------------------------------------------------------------- + */ + +static void +ImgBmapConfigureInstance( + BitmapInstance *instancePtr)/* Instance to reconfigure. */ +{ + BitmapMaster *masterPtr = instancePtr->masterPtr; + XColor *colorPtr; + XGCValues gcValues; + GC gc; + unsigned int mask; + Pixmap oldBitmap, oldMask; + + /* + * For each of the options in masterPtr, translate the string form into an + * internal form appropriate for instancePtr. + */ + + if (*masterPtr->bgUid != 0) { + colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin, + masterPtr->bgUid); + if (colorPtr == NULL) { + goto error; + } + } else { + colorPtr = NULL; + } + if (instancePtr->bg != NULL) { + Tk_FreeColor(instancePtr->bg); + } + instancePtr->bg = colorPtr; + + colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin, + masterPtr->fgUid); + if (colorPtr == NULL) { + goto error; + } + if (instancePtr->fg != NULL) { + Tk_FreeColor(instancePtr->fg); + } + instancePtr->fg = colorPtr; + + /* + * Careful: We have to allocate new Pixmaps before deleting the old ones. + * Otherwise, The XID allocator will always return the same XID for the + * new Pixmaps as was used for the old Pixmaps. And that will prevent the + * data and/or mask from changing in the GC below. + */ + + oldBitmap = instancePtr->bitmap; + instancePtr->bitmap = None; + oldMask = instancePtr->mask; + instancePtr->mask = None; + + if (masterPtr->data != NULL) { + instancePtr->bitmap = XCreateBitmapFromData( + Tk_Display(instancePtr->tkwin), + RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)), + masterPtr->data, (unsigned) masterPtr->width, + (unsigned) masterPtr->height); + } + if (masterPtr->maskData != NULL) { + instancePtr->mask = XCreateBitmapFromData( + Tk_Display(instancePtr->tkwin), + RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)), + masterPtr->maskData, (unsigned) masterPtr->width, + (unsigned) masterPtr->height); + } + + if (oldMask != None) { + Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldMask); + } + if (oldBitmap != None) { + Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldBitmap); + } + + if (masterPtr->data != NULL) { + gcValues.foreground = instancePtr->fg->pixel; + gcValues.graphics_exposures = False; + mask = GCForeground|GCGraphicsExposures; + if (instancePtr->bg != NULL) { + gcValues.background = instancePtr->bg->pixel; + mask |= GCBackground; + if (instancePtr->mask != None) { + gcValues.clip_mask = instancePtr->mask; + mask |= GCClipMask; + } + } else { + gcValues.clip_mask = instancePtr->bitmap; + mask |= GCClipMask; + } + gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues); + } else { + gc = None; + } + if (instancePtr->gc != None) { + Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc); + } + instancePtr->gc = gc; + return; + + error: + /* + * An error occurred: clear the graphics context in the instance to make + * it clear that this instance cannot be displayed. Then report the error. + */ + + if (instancePtr->gc != None) { + Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc); + } + instancePtr->gc = None; + Tcl_AddErrorInfo(masterPtr->interp, "\n (while configuring image \""); + Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster)); + Tcl_AddErrorInfo(masterPtr->interp, "\")"); + Tcl_BackgroundError(masterPtr->interp); +} + +/* + *---------------------------------------------------------------------- + * + * TkGetBitmapData -- + * + * Given a file name or ASCII string, this procedure parses the file or + * string contents to produce binary data for a bitmap. + * + * Results: + * If the bitmap description was parsed successfully then the return + * value is a malloc-ed array containing the bitmap data. The dimensions + * of the data are stored in *widthPtr and *heightPtr. *hotXPtr and + * *hotYPtr are set to the bitmap hotspot if one is defined, otherwise + * they are set to -1, -1. If an error occurred, NULL is returned and an + * error message is left in the interp's result. + * + * Side effects: + * A bitmap is created. + * + *---------------------------------------------------------------------- + */ + +char * +TkGetBitmapData( + Tcl_Interp *interp, /* For reporting errors, or NULL. */ + char *string, /* String describing bitmap. May be NULL. */ + char *fileName, /* Name of file containing bitmap description. + * Used only if string is NULL. Must not be + * NULL if string is NULL. */ + int *widthPtr, int *heightPtr, + /* Dimensions of bitmap get returned here. */ + int *hotXPtr, int *hotYPtr) /* Position of hot spot or -1,-1. */ +{ + int width, height, numBytes, hotX, hotY; + CONST char *expandedFileName; + char *p, *end; + ParseInfo pi; + char *data = NULL; + Tcl_DString buffer; + + pi.string = string; + if (string == NULL) { + if ((interp != NULL) && Tcl_IsSafe(interp)) { + Tcl_AppendResult(interp, "can't get bitmap data from a file in a", + " safe interpreter", NULL); + return NULL; + } + expandedFileName = Tcl_TranslateFileName(interp, fileName, &buffer); + if (expandedFileName == NULL) { + return NULL; + } + pi.chan = Tcl_OpenFileChannel(interp, expandedFileName, "r", 0); + Tcl_DStringFree(&buffer); + if (pi.chan == NULL) { + if (interp != NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't read bitmap file \"", + fileName, "\": ", Tcl_PosixError(interp), NULL); + } + return NULL; + } + + if (Tcl_SetChannelOption(interp, pi.chan, "-translation", "binary") + != TCL_OK) { + return NULL; + } + if (Tcl_SetChannelOption(interp, pi.chan, "-encoding", "binary") + != TCL_OK) { + return NULL; + } + } else { + pi.chan = NULL; + } + + /* + * Parse the lines that define the dimensions of the bitmap, plus the + * first line that defines the bitmap data (it declares the name of a data + * variable but doesn't include any actual data). These lines look + * something like the following: + * + * #define foo_width 16 + * #define foo_height 16 + * #define foo_x_hot 3 + * #define foo_y_hot 3 + * static char foo_bits[] = { + * + * The x_hot and y_hot lines may or may not be present. It's important to + * check for "char" in the last line, in order to reject old X10-style + * bitmaps that used shorts. + */ + + width = 0; + height = 0; + hotX = -1; + hotY = -1; + while (1) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_') + && (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + width = strtol(pi.word, &end, 0); + if ((end == pi.word) || (*end != 0)) { + goto error; + } + } else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_') + && (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + height = strtol(pi.word, &end, 0); + if ((end == pi.word) || (*end != 0)) { + goto error; + } + } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_') + && (strcmp(pi.word+pi.wordLength-6, "_x_hot") == 0)) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + hotX = strtol(pi.word, &end, 0); + if ((end == pi.word) || (*end != 0)) { + goto error; + } + } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_') + && (strcmp(pi.word+pi.wordLength-6, "_y_hot") == 0)) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + hotY = strtol(pi.word, &end, 0); + if ((end == pi.word) || (*end != 0)) { + goto error; + } + } else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) { + while (1) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + if ((pi.word[0] == '{') && (pi.word[1] == 0)) { + goto getData; + } + } + } else if ((pi.word[0] == '{') && (pi.word[1] == 0)) { + if (interp != NULL) { + Tcl_AppendResult(interp, "format error in bitmap data; ", + "looks like it's an obsolete X10 bitmap file", NULL); + } + goto errorCleanup; + } + } + + /* + * Now we've read everything but the data. Allocate an array and read in + * the data. + */ + + getData: + if ((width <= 0) || (height <= 0)) { + goto error; + } + numBytes = ((width+7)/8) * height; + data = (char *) ckalloc((unsigned) numBytes); + for (p = data; numBytes > 0; p++, numBytes--) { + if (NextBitmapWord(&pi) != TCL_OK) { + goto error; + } + *p = (char) strtol(pi.word, &end, 0); + if (end == pi.word) { + goto error; + } + } + + /* + * All done. Clean up and return. + */ + + if (pi.chan != NULL) { + Tcl_Close(NULL, pi.chan); + } + *widthPtr = width; + *heightPtr = height; + *hotXPtr = hotX; + *hotYPtr = hotY; + return data; + + error: + if (interp != NULL) { + Tcl_SetResult(interp, "format error in bitmap data", TCL_STATIC); + } + + errorCleanup: + if (data != NULL) { + ckfree(data); + } + if (pi.chan != NULL) { + Tcl_Close(NULL, pi.chan); + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * NextBitmapWord -- + * + * This procedure retrieves the next word of information (stuff between + * commas or white space) from a bitmap description. + * + * Results: + * Returns TCL_OK if all went well. In this case the next word, and its + * length, will be availble in *parseInfoPtr. If the end of the bitmap + * description was reached then TCL_ERROR is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +NextBitmapWord( + ParseInfo *parseInfoPtr) /* Describes what we're reading and where we + * are in it. */ +{ + char *src, *dst; + int c; + + parseInfoPtr->wordLength = 0; + dst = parseInfoPtr->word; + if (parseInfoPtr->string != NULL) { + for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ','); + src++) { + if (*src == 0) { + return TCL_ERROR; + } + } + for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) { + *dst = *src; + dst++; + parseInfoPtr->wordLength++; + if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) { + return TCL_ERROR; + } + } + parseInfoPtr->string = src; + } else { + for (c = GetByte(parseInfoPtr->chan); isspace(UCHAR(c)) || (c == ','); + c = GetByte(parseInfoPtr->chan)) { + if (c == EOF) { + return TCL_ERROR; + } + } + for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF); + c = GetByte(parseInfoPtr->chan)) { + *dst = c; + dst++; + parseInfoPtr->wordLength++; + if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) { + return TCL_ERROR; + } + } + } + if (parseInfoPtr->wordLength == 0) { + return TCL_ERROR; + } + parseInfoPtr->word[parseInfoPtr->wordLength] = 0; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ImgBmapCmd -- + * + * This procedure is invoked to process the Tcl command that corresponds + * to an image managed by this module. See the user documentation for + * details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +static int +ImgBmapCmd( + ClientData clientData, /* Information about the image master. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *CONST objv[]) /* Argument objects. */ +{ + static CONST char *bmapOptions[] = {"cget", "configure", NULL}; + BitmapMaster *masterPtr = (BitmapMaster *) clientData; + int index; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[1], bmapOptions, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + switch (index) { + case 0: /* cget */ + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); + return TCL_ERROR; + } + return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs, + (char *) masterPtr, Tcl_GetString(objv[2]), 0); + case 1: /* configure */ + if (objc == 2) { + return Tk_ConfigureInfo(interp, Tk_MainWindow(interp), + configSpecs, (char *) masterPtr, NULL, 0); + } else if (objc == 3) { + return Tk_ConfigureInfo(interp, Tk_MainWindow(interp), + configSpecs, (char *) masterPtr, + Tcl_GetString(objv[2]), 0); + } else { + return ImgBmapConfigureMaster(masterPtr, objc-2, objv+2, + TK_CONFIG_ARGV_ONLY); + } + default: + Tcl_Panic("bad const entries to bmapOptions in ImgBmapCmd"); + return TCL_OK; + } +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapGet -- + * + * This procedure is called for each use of a bitmap image in a widget. + * + * Results: + * The return value is a token for the instance, which is passed back to + * us in calls to ImgBmapDisplay and ImgBmapFree. + * + * Side effects: + * A data structure is set up for the instance (or, an existing instance + * is re-used for the new one). + * + *---------------------------------------------------------------------- + */ + +static ClientData +ImgBmapGet( + Tk_Window tkwin, /* Window in which the instance will be + * used. */ + ClientData masterData) /* Pointer to our master structure for the + * image. */ +{ + BitmapMaster *masterPtr = (BitmapMaster *) masterData; + BitmapInstance *instancePtr; + + /* + * See if there is already an instance for this window. If so then just + * re-use it. + */ + + for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; + instancePtr = instancePtr->nextPtr) { + if (instancePtr->tkwin == tkwin) { + instancePtr->refCount++; + return (ClientData) instancePtr; + } + } + + /* + * The image isn't already in use in this window. Make a new instance of + * the image. + */ + + instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance)); + instancePtr->refCount = 1; + instancePtr->masterPtr = masterPtr; + instancePtr->tkwin = tkwin; + instancePtr->fg = NULL; + instancePtr->bg = NULL; + instancePtr->bitmap = None; + instancePtr->mask = None; + instancePtr->gc = None; + instancePtr->nextPtr = masterPtr->instancePtr; + masterPtr->instancePtr = instancePtr; + ImgBmapConfigureInstance(instancePtr); + + /* + * If this is the first instance, must set the size of the image. + */ + + if (instancePtr->nextPtr == NULL) { + Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width, + masterPtr->height); + } + + return (ClientData) instancePtr; +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapDisplay -- + * + * This procedure is invoked to draw a bitmap image. + * + * Results: + * None. + * + * Side effects: + * A portion of the image gets rendered in a pixmap or window. + * + *---------------------------------------------------------------------- + */ + +static void +ImgBmapDisplay( + ClientData clientData, /* Pointer to BitmapInstance structure for + * instance to be displayed. */ + Display *display, /* Display on which to draw image. */ + Drawable drawable, /* Pixmap or window in which to draw image. */ + int imageX, int imageY, /* Upper-left corner of region within image to + * draw. */ + int width, int height, /* Dimensions of region within image to draw. */ + int drawableX, int drawableY) + /* Coordinates within drawable that correspond + * to imageX and imageY. */ +{ + BitmapInstance *instancePtr = (BitmapInstance *) clientData; + int masking; + + /* + * If there's no graphics context, it means that an error occurred while + * creating the image instance so it can't be displayed. + */ + + if (instancePtr->gc == None) { + return; + } + + /* + * If masking is in effect, must modify the mask origin within the + * graphics context to line up with the image's origin. Then draw the + * image and reset the clip origin, if there's a mask. + */ + + masking = (instancePtr->mask != None) || (instancePtr->bg == NULL); + if (masking) { + XSetClipOrigin(display, instancePtr->gc, drawableX - imageX, + drawableY - imageY); + } + XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc, + imageX, imageY, (unsigned) width, (unsigned) height, + drawableX, drawableY, 1); + if (masking) { + XSetClipOrigin(display, instancePtr->gc, 0, 0); + } +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapFree -- + * + * This procedure is called when a widget ceases to use a particular + * instance of an image. + * + * Results: + * None. + * + * Side effects: + * Internal data structures get cleaned up. + * + *---------------------------------------------------------------------- + */ + +static void +ImgBmapFree( + ClientData clientData, /* Pointer to BitmapInstance structure for + * instance to be displayed. */ + Display *display) /* Display containing window that used image. */ +{ + BitmapInstance *instancePtr = (BitmapInstance *) clientData; + BitmapInstance *prevPtr; + + instancePtr->refCount--; + if (instancePtr->refCount > 0) { + return; + } + + /* + * There are no more uses of the image within this widget. Free the + * instance structure. + */ + + if (instancePtr->fg != NULL) { + Tk_FreeColor(instancePtr->fg); + } + if (instancePtr->bg != NULL) { + Tk_FreeColor(instancePtr->bg); + } + if (instancePtr->bitmap != None) { + Tk_FreePixmap(display, instancePtr->bitmap); + } + if (instancePtr->mask != None) { + Tk_FreePixmap(display, instancePtr->mask); + } + if (instancePtr->gc != None) { + Tk_FreeGC(display, instancePtr->gc); + } + if (instancePtr->masterPtr->instancePtr == instancePtr) { + instancePtr->masterPtr->instancePtr = instancePtr->nextPtr; + } else { + for (prevPtr = instancePtr->masterPtr->instancePtr; + prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) { + /* Empty loop body */ + } + prevPtr->nextPtr = instancePtr->nextPtr; + } + ckfree((char *) instancePtr); +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapDelete -- + * + * This procedure is called by the image code to delete the master + * structure for an image. + * + * Results: + * None. + * + * Side effects: + * Resources associated with the image get freed. + * + *---------------------------------------------------------------------- + */ + +static void +ImgBmapDelete( + ClientData masterData) /* Pointer to BitmapMaster structure for + * image. Must not have any more instances. */ +{ + BitmapMaster *masterPtr = (BitmapMaster *) masterData; + + if (masterPtr->instancePtr != NULL) { + Tcl_Panic("tried to delete bitmap image when instances still exist"); + } + masterPtr->tkMaster = NULL; + if (masterPtr->imageCmd != NULL) { + Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd); + } + if (masterPtr->data != NULL) { + ckfree(masterPtr->data); + } + if (masterPtr->maskData != NULL) { + ckfree(masterPtr->maskData); + } + Tk_FreeOptions(configSpecs, (char *) masterPtr, NULL, 0); + ckfree((char *) masterPtr); +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapCmdDeletedProc -- + * + * This procedure is invoked when the image command for an image is + * deleted. It deletes the image. + * + * Results: + * None. + * + * Side effects: + * The image is deleted. + * + *---------------------------------------------------------------------- + */ + +static void +ImgBmapCmdDeletedProc( + ClientData clientData) /* Pointer to BitmapMaster structure for + * image. */ +{ + BitmapMaster *masterPtr = (BitmapMaster *) clientData; + + masterPtr->imageCmd = NULL; + if (masterPtr->tkMaster != NULL) { + Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster)); + } +} + +/* + *---------------------------------------------------------------------- + * + * GetByte -- + * + * Get the next byte from the open channel. + * + * Results: + * The next byte or EOF. + * + * Side effects: + * We read from the channel. + * + *---------------------------------------------------------------------- + */ + +static int +GetByte( + Tcl_Channel chan) /* The channel we read from. */ +{ + char buffer; + int size; + + size = Tcl_Read(chan, &buffer, 1); + if (size <= 0) { + return EOF; + } else { + return buffer; + } +} + + +/* + *---------------------------------------------------------------------- + * + * ImgBmapPsImagemask -- + * + * This procedure generates postscript suitable for rendering a single + * bitmap of an image. A single bitmap image might contain both a + * foreground and a background bitmap. This routine is called once for + * each such bitmap in a bitmap image. + * + * Prior to invoking this routine, the following setup has occurred: + * + * 1. The postscript foreground color has been set to the color used + * to render the bitmap. + * + * 2. The origin of the postscript coordinate system is set to the + * lower left corner of the bitmap. + * + * 3. The postscript coordinate system has been scaled so that the + * entire bitmap is one unit squared. + * + * Some postscript implementations cannot handle bitmap strings longer + * than about 60k characters. If the bitmap data is that big or bigger, + * then we render it by splitting it into several smaller bitmaps. + * + * Results: + * Returns TCL_OK on success. Returns TCL_ERROR and leaves and error + * message in interp->result if there is a problem. + * + * Side effects: + * Postscript code is appended to interp->result. + * + *---------------------------------------------------------------------- + */ + +static int +ImgBmapPsImagemask( + Tcl_Interp *interp, /* Append postscript to this interpreter */ + int width, int height, /* Width and height of the bitmap in pixels */ + char *data) /* Data for the bitmap */ +{ + int i, j, nBytePerRow; + char buffer[200]; + + /* + * The bit order of bitmaps in Tk is the opposite of the bit order that + * postscript uses. (In Tk, the least significant bit is on the right side + * of the bitmap and in postscript the least significant bit is shown on + * the left.) The following array is used to reverse the order of bits + * within a byte so that the bits will be in the order postscript expects. + */ + + static unsigned char bit_reverse[] = { + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, + 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, + 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, + 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255, + }; + + if (width*height > 60000) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "unable to generate postscript for bitmaps " + "larger than 60000 pixels", NULL); + return TCL_ERROR; + } + + sprintf(buffer, "0 0 moveto %d %d true [%d 0 0 %d 0 %d] {<\n", + width, height, width, -height, height); + Tcl_AppendResult(interp, buffer, NULL); + + nBytePerRow = (width+7)/8; + for(i=0; i<height; i++){ + for(j=0; j<nBytePerRow; j++){ + sprintf(buffer, " %02x", + bit_reverse[0xff & data[i*nBytePerRow + j]]); + Tcl_AppendResult(interp, buffer, NULL); + } + Tcl_AppendResult(interp, "\n", NULL); + } + + Tcl_AppendResult(interp, ">} imagemask \n", NULL); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ImgBmapPostscript -- + * + * This procedure generates postscript for rendering a bitmap image. + * + * Results: + + * On success, this routine writes postscript code into interp->result + * and returns TCL_OK TCL_ERROR is returned and an error message is left + * in interp->result if anything goes wrong. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ImgBmapPostscript( + ClientData clientData, + Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo psinfo, + int x, int y, int width, int height, + int prepass) +{ + BitmapMaster *masterPtr = (BitmapMaster *) clientData; + char buffer[200]; + + if (prepass) { + return TCL_OK; + } + + /* + * There is nothing to do for bitmaps with zero width or height. + */ + + if (width<=0 || height<=0 || masterPtr->width<=0 || masterPtr->height<= 0){ + return TCL_OK; + } + + /* + * Translate the origin of the coordinate system to be the lower-left + * corner of the bitmap and adjust the scale of the coordinate system so + * that entire bitmap covers one square unit of the page. The calling + * function put a "gsave" into the postscript and will add a "grestore" at + * after this routine returns, so it is safe to make whatever changes are + * necessary here. + */ + + if (x!=0 || y!=0) { + sprintf(buffer, "%d %d moveto\n", x, y); + Tcl_AppendResult(interp, buffer, NULL); + } + if (width!=1 || height!=1) { + sprintf(buffer, "%d %d scale\n", width, height); + Tcl_AppendResult(interp, buffer, NULL); + } + + /* + * Color the background, if there is one. This step is skipped if the + * background is transparent. If the background is not transparent and + * there is no background mask, then color the complete rectangle that + * encloses the bitmap. If there is a background mask, then only apply + * color to the bits specified by the mask. + */ + + if ((masterPtr->bgUid != NULL) && (masterPtr->bgUid[0] != '\000')) { + XColor color; + + XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid, + &color); + if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) { + return TCL_ERROR; + } + if (masterPtr->maskData == NULL) { + Tcl_AppendResult(interp, + "0 0 moveto 1 0 rlineto 0 1 rlineto -1 0 rlineto ", + "closepath fill\n", NULL); + } else if (ImgBmapPsImagemask(interp, masterPtr->width, + masterPtr->height, masterPtr->maskData) != TCL_OK) { + return TCL_ERROR; + } + } + + /* + * Draw the bitmap foreground, assuming there is one. + */ + + if ((masterPtr->fgUid != NULL) && (masterPtr->data != NULL)) { + XColor color; + + XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->fgUid, + &color); + if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) { + return TCL_ERROR; + } + if (ImgBmapPsImagemask(interp, masterPtr->width, masterPtr->height, + masterPtr->data) != TCL_OK) { + return TCL_ERROR; + } + } + return TCL_OK; +} + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ diff --git a/win/makefile.vc b/win/makefile.vc index c9e622f..f99ee9c 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -12,12 +12,13 @@ # Copyright (c) 2001-2004 David Gravereaux. # #------------------------------------------------------------------------------ -# RCS: @(#) $Id: makefile.vc,v 1.94 2006/09/27 18:43:35 andreas_kupries Exp $ +# RCS: @(#) $Id: makefile.vc,v 1.95 2006/10/19 00:48:25 patthoyts Exp $ #------------------------------------------------------------------------------ # Check to see we are configured to build with MSVC (MSDEVDIR or MSVCDIR) -# or with the MS Platform SDK (MSSDK) -!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) +# or with the MS Platform SDK (MSSDK). Visual Studio .NET 2003 and 2005 define +# VCINSTALLDIR instead. +!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(MSSDK) && !defined(VCINSTALLDIR) MSG = ^ You need to run vcvars32.bat from Developer Studio or setenv.bat from the^ Platform SDK first to setup the environment. Jump to this line to read^ @@ -167,7 +168,7 @@ the build instructions. MSG = ^ You must run this makefile only from the directory it is in.^ Please `cd` to its location first. -!error $(MSG) +!error $(MSG) !endif PROJECT = tk @@ -188,7 +189,7 @@ DOTVERSION = 8.6 DOTVERSION = 9.0 !elseif [nmakehlp -g ../generic/tk.h TK_VERSION] == 0 MSG =^ -Can't get version string from ../generic/tk.h +Cannot get version string from ../generic/tk.h !error $(MSG) !endif VERSION = $(DOTVERSION:.=) @@ -375,22 +376,22 @@ TK_DEFINES = $(OPTDEFINES) !if !$(DEBUG) !if $(OPTIMIZING) -### This cranks the optimization level up. We can't use -02 because -### sometimes it causes problems. -cdebug = -Oti +### This cranks the optimization level to maximize speed +### We can't use -O2 because sometimes it causes problems. +cdebug = $(OPTIMIZATIONS) !else cdebug = !endif !else if "$(MACHINE)" == "IA64" -### Warnings are too many, can't support warnings into errors for -### an IA64 build. -cdebug = -Z7 -Od -GZ +### Warnings are too many, can't support warnings into errors. +cdebug = -Z7 -Od $(DEBUGFLAGS) !else -cdebug = -Z7 -WX -Od -GZ +cdebug = -Z7 -WX $(DEBUGFLAGS) !endif -# declarations common to all compiler options -cflags = -nologo -c -YX -Fp$(TMP_DIR)^\ +### Declarations common to all compiler options +cwarn = -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE +cflags = -nologo -c $(COMPILERFLAGS) $(cwarn) -Fp$(TMP_DIR)^\ !if $(FULLWARNINGS) cflags = $(cflags) -W4 @@ -398,14 +399,6 @@ cflags = $(cflags) -W4 cflags = $(cflags) -W3 !endif -!if $(PENT_0F_ERRATA) -cflags = $(cflags) -QI0f -!endif - -!if $(ITAN_B_ERRATA) -cflags = $(cflags) -QIA64_Bx -!endif - !if $(MSVCRT) !if $(DEBUG) && !$(UNCHECKED) crt = -MDd @@ -420,10 +413,10 @@ crt = -MT !endif !endif -BASE_CLFAGS = $(cdebug) $(cflags) $(crt) $(TK_INCLUDES) -TK_CFLAGS = $(BASE_CLFAGS) $(TK_DEFINES) -DUSE_TCL_STUBS +BASE_CFLAGS = $(cdebug) $(cflags) $(crt) $(TK_INCLUDES) +TK_CFLAGS = $(BASE_CFLAGS) $(TK_DEFINES) -DUSE_TCL_STUBS CON_CFLAGS = $(cdebug) $(cflags) $(crt) -DCONSOLE -WISH_CFLAGS = $(BASE_CLFAGS) $(TK_DEFINES) +WISH_CFLAGS = $(BASE_CFLAGS) $(TK_DEFINES) STUB_CFLAGS = $(cflags) $(cdebug) $(TK_DEFINES) @@ -437,8 +430,8 @@ ldebug = -debug:full -debugtype:cv ldebug = -release -opt:ref -opt:icf,3 !endif -# declarations common to all linker options -lflags = -nologo -machine:$(MACHINE) $(ldebug) +### Declarations common to all linker options +lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(FULLWARNINGS) lflags = $(lflags) -warn:3 @@ -449,10 +442,10 @@ lflags = $(lflags) -profile !endif !if $(ALIGN98_HACK) && !$(STATIC_BUILD) -# align sections for PE size savings. +### Align sections for PE size savings. lflags = $(lflags) -opt:nowin98 !else if !$(ALIGN98_HACK) && $(STATIC_BUILD) -# align sections for speed in loading by choosing the virtual page size. +### Align sections for speed in loading by choosing the virtual page size. lflags = $(lflags) -align:4096 !endif @@ -464,7 +457,7 @@ dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows -baselibs = kernel32.lib user32.lib +baselibs = kernel32.lib user32.lib # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" @@ -478,7 +471,7 @@ guilibs = $(baselibs) gdi32.lib #--------------------------------------------------------------------- !if "$(TESTPAT)" != "" -TESTFLAGS = -file $(TESTPAT) +TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !endif @@ -727,6 +720,12 @@ $(TMP_DIR)\tkStubImg.obj : $(GENERICDIR)\tkStubImg.c #--------------------------------------------------------------------- $(TMP_DIR)\wish.exe.manifest: $(WINDIR)\wish.exe.manifest.in +!if ![sed "1d" < NUL > NUL] + sed -f << $** > $@ +s/@MACHINE@/$(MACHINE:IX86=X86)/ +s/@TK_WIN_VERSION@/$(DOTVERSION).0.0/ +<< +!else $(TCLSH) << set f [open {$(WINDIR:\=/)/wish.exe.manifest.in} r] set data [read $$f] @@ -741,6 +740,7 @@ puts -nonewline $$f $$data close $$f exit << +!endif $(TMP_DIR)\tk.res: \ $(RCDIR)\buttons.bmp \ diff --git a/win/nmakehlp.c b/win/nmakehlp.c index d6939e4..a84ee28 100644 --- a/win/nmakehlp.c +++ b/win/nmakehlp.c @@ -1,4 +1,5 @@ -/* ---------------------------------------------------------------------------- +/* + * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. @@ -9,22 +10,37 @@ * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: nmakehlp.c,v 1.5 2004/02/01 10:40:07 davygrvy Exp $ + * RCS: @(#) $Id: nmakehlp.c,v 1.6 2006/10/19 00:48:25 patthoyts Exp $ * ---------------------------------------------------------------------------- */ + +#define _CRT_SECURE_NO_DEPRECATE #include <windows.h> #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #include <stdio.h> +#include <math.h> +#if defined(_M_IA64) || defined(_M_AMD64) +#pragma comment(lib, "bufferoverflowU") +#endif + +/* ISO hack for dumb VC++ */ +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + /* protos */ -int CheckForCompilerFeature (const char *option); -int CheckForLinkerFeature (const char *option); -int IsIn (const char *string, const char *substring); -int GrepForDefine (const char *file, const char *string); -DWORD WINAPI ReadFromPipe (LPVOID args); + +int CheckForCompilerFeature(const char *option); +int CheckForLinkerFeature(const char *option); +int IsIn(const char *string, const char *substring); +int GrepForDefine(const char *file, const char *string); +DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ + #define CHUNK 25 #define STATICBUFFERSIZE 1000 typedef struct { @@ -34,21 +50,30 @@ typedef struct { pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; + +/* + * exitcodes: 0 == no, 1 == yes, 2 == error + */ - - -/* exitcodes: 0 == no, 1 == yes, 2 == error */ int -main (int argc, char *argv[]) +main( + int argc, + char *argv[]) { char msg[300]; DWORD dwWritten; int chars; - /* make sure children (cl.exe and link.exe) are kept quiet. */ + /* + * Make sure children (cl.exe and link.exe) are kept quiet. + */ + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); - /* Make sure the compiler and linker aren't effected by the outside world. */ + /* + * Make sure the compiler and linker aren't effected by the outside world. + */ + SetEnvironmentVariable("CL", ""); SetEnvironmentVariable("LINK", ""); @@ -56,56 +81,70 @@ main (int argc, char *argv[]) switch (*(argv[1]+1)) { case 'c': if (argc != 3) { - chars = wsprintf(msg, "usage: %s -c <compiler option>\n" + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -c <compiler option>\n" "Tests for whether cl.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': if (argc != 3) { - chars = wsprintf(msg, "usage: %s -l <linker option>\n" + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -l <linker option>\n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } return CheckForLinkerFeature(argv[2]); case 'f': if (argc == 2) { - chars = wsprintf(msg, "usage: %s -f <string> <substring>\n" - "Find a substring within another\n" - "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -f <string> <substring>\n" + "Find a substring within another\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } else if (argc == 3) { - /* if the string is blank, there is no match */ + /* + * If the string is blank, there is no match. + */ + return 0; } else { return IsIn(argv[2], argv[3]); } case 'g': if (argc == 2) { - chars = wsprintf(msg, "usage: %s -g <file> <string>\n" - "grep for a #define\n" - "exitcodes: integer of the found string (no decimals)\n", argv[0]); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -g <file> <string>\n" + "grep for a #define\n" + "exitcodes: integer of the found string (no decimals)\n", + argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); return 2; } return GrepForDefine(argv[2], argv[3]); } } - chars = wsprintf(msg, "usage: %s -c|-l|-f ...\n" + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -c|-l|-f ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } - + int -CheckForCompilerFeature (const char *option) +CheckForCompilerFeature( + const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; @@ -129,24 +168,44 @@ CheckForCompilerFeature (const char *option) sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; - /* create a non-inheritible pipe. */ + /* + * Create a non-inheritible pipe. + */ + CreatePipe(&Out.pipe, &h, &sa, 0); - /* dupe the write side, make it inheritible, and close the original. */ - DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ - /* Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); - DuplicateHandle(hProcess, h, hProcess, &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); - /* base command line */ - strcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X "); - /* append our option for testing */ - strcat(cmdline, option); - /* filename to compile, which exists, but is nothing and empty. */ - strcat(cmdline, " .\\nul"); + /* + * Base command line. + */ + + lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X "); + + /* + * Append our option for testing + */ + + lstrcat(cmdline, option); + + /* + * Filename to compile, which exists, but is nothing and empty. + */ + + lstrcat(cmdline, " .\\nul"); ok = CreateProcess( NULL, /* Module name. */ @@ -162,41 +221,62 @@ CheckForCompilerFeature (const char *option) if (!ok) { DWORD err = GetLastError(); - int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + int chars = snprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars], + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } - /* close our references to the write handles that have now been inherited. */ + /* + * Close our references to the write handles that have now been inherited. + */ + CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); - /* start the pipe reader threads. */ + /* + * Start the pipe reader threads. + */ + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); - /* block waiting for the process to end. */ + /* + * Block waiting for the process to end. + */ + WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); - /* wait for our pipe to get done reading, should it be a little slow. */ + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); - /* look for the commandline warning code in both streams. */ - return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL); -} + /* + * Look for the commandline warning code in both streams. + * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. + */ + return !(strstr(Out.buffer, "D4002") != NULL + || strstr(Err.buffer, "D4002") != NULL + || strstr(Out.buffer, "D9002") != NULL + || strstr(Err.buffer, "D9002") != NULL); +} + int -CheckForLinkerFeature (const char *option) +CheckForLinkerFeature( + const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; @@ -220,22 +300,38 @@ CheckForLinkerFeature (const char *option) sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; - /* create a non-inheritible pipe. */ + /* + * Create a non-inheritible pipe. + */ + CreatePipe(&Out.pipe, &h, &sa, 0); - /* dupe the write side, make it inheritible, and close the original. */ - DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + /* + * Dupe the write side, make it inheritible, and close the original. + */ + + DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Same as above, but for the error side. + */ - /* Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); - DuplicateHandle(hProcess, h, hProcess, &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + + /* + * Base command line. + */ + + lstrcpy(cmdline, "link.exe -nologo "); - /* base command line */ - strcpy(cmdline, "link.exe -nologo "); - /* append our option for testing */ - strcat(cmdline, option); + /* + * Append our option for testing. + */ + + lstrcat(cmdline, option); ok = CreateProcess( NULL, /* Module name. */ @@ -251,51 +347,71 @@ CheckForLinkerFeature (const char *option) if (!ok) { DWORD err = GetLastError(); - int chars = wsprintf(msg, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); + int chars = snprintf(msg, sizeof(msg) - 1, + "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID) &msg[chars], + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, strlen(msg), &err, NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } - /* close our references to the write handles that have now been inherited. */ + /* + * Close our references to the write handles that have now been inherited. + */ + CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); - /* start the pipe reader threads. */ + /* + * Start the pipe reader threads. + */ + pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); - /* block waiting for the process to end. */ + /* + * Block waiting for the process to end. + */ + WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); - /* wait for our pipe to get done reading, should it be a little slow. */ + /* + * Wait for our pipe to get done reading, should it be a little slow. + */ + WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); - /* look for the commandline warning code in the stderr stream. */ - return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL); -} + /* + * Look for the commandline warning code in the stderr stream. + */ + return !(strstr(Out.buffer, "LNK1117") != NULL || + strstr(Err.buffer, "LNK1117") != NULL || + strstr(Out.buffer, "LNK4044") != NULL || + strstr(Err.buffer, "LNK4044") != NULL); +} + DWORD WINAPI -ReadFromPipe (LPVOID args) +ReadFromPipe( + LPVOID args) { pipeinfo *pi = (pipeinfo *) args; char *lastBuf = pi->buffer; DWORD dwRead; BOOL ok; -again: + again: if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { CloseHandle(pi->pipe); - return -1; + return (DWORD)-1; } ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); if (!ok || dwRead == 0) { @@ -307,22 +423,25 @@ again: return 0; /* makes the compiler happy */ } - + int -IsIn (const char *string, const char *substring) +IsIn( + const char *string, + const char *substring) { return (strstr(string, substring) != NULL); } - + /* - * Find a specified #define by name. + * Find a specified #define by name. * - * If the line is '#define TCL_VERSION "8.5"', it returns - * 85 as the result. + * If the line is '#define TCL_VERSION "8.5"', it returns 85 as the result. */ int -GrepForDefine (const char *file, const char *string) +GrepForDefine( + const char *file, + const char *string) { FILE *f; char s1[51], s2[51], s3[51]; @@ -337,15 +456,31 @@ GrepForDefine (const char *file, const char *string) do { r = fscanf(f, "%50s", s1); if (r == 1 && !strcmp(s1, "#define")) { - /* get next two words */ + /* + * Get next two words. + */ + r = fscanf(f, "%50s %50s", s2, s3); - if (r != 2) continue; - /* is the first word what we're looking for? */ + if (r != 2) { + continue; + } + + /* + * Is the first word what we're looking for? + */ + if (!strcmp(s2, string)) { fclose(f); - /* add 1 past first double quote char. "8.5" */ + + /* + * Add 1 past first double quote char. "8.5" + */ + d1 = atof(s3 + 1); /* 8.5 */ - return ((int) (d1 * 10) & 0xFF); /* 85 */ + while (floor(d1) != d1) { + d1 *= 10.0; + } + return ((int) d1); /* 85 */ } } } while (!feof(f)); diff --git a/win/rules.vc b/win/rules.vc index 6562add..4217753 100644 --- a/win/rules.vc +++ b/win/rules.vc @@ -8,9 +8,10 @@ # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2003 David Gravereaux. +# Copyright (c) 2003-2006 Patrick Thoyts # #------------------------------------------------------------------------------ -# RCS: @(#) $Id: rules.vc,v 1.12 2006/09/22 19:02:08 andreas_kupries Exp $ +# RCS: @(#) $Id: rules.vc,v 1.13 2006/10/19 00:48:26 patthoyts Exp $ #------------------------------------------------------------------------------ !ifndef _RULES_VC @@ -25,12 +26,16 @@ rc32 = $(RC) # built-in default. ### Assume the normal default. _INSTALLDIR = C:\Program Files\Tcl !else -### Fix the path seperators. +### Fix the path separators. _INSTALLDIR = $(INSTALLDIR:/=\) !endif !ifndef MACHINE +!if "$(CPU)" == "" MACHINE = IX86 +!else +MACHINE = $(CPU) +!endif !endif !ifndef CFG_ENCODING @@ -48,13 +53,14 @@ RMDIR = rmdir /S /Q !if ![ver | find "4.0" > nul] CPY = echo y | xcopy /i !else -CPY = xcopy /i /y +CPY = xcopy /i /y >NUL !endif !else CPY = xcopy /i RMDIR = deltree /Y !endif - +MKDIR = mkdir +COPY = copy /y >NUL !message =============================================================================== @@ -64,7 +70,7 @@ RMDIR = deltree /Y #---------------------------------------------------------- !if !exist(nmakehlp.exe) -!if [$(cc32) -nologo -ML nmakehlp.c -link -subsystem:console > nul] +!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul] !endif !endif @@ -73,7 +79,7 @@ RMDIR = deltree /Y #---------------------------------------------------------- ### test for optimizations -!if [nmakehlp -c -Otip] +!if [nmakehlp -c -Ot] !message *** Compiler has 'Optimizations' OPTIMIZING = 1 !else @@ -81,15 +87,75 @@ OPTIMIZING = 1 OPTIMIZING = 0 !endif +OPTIMIZATIONS = + +!if [nmakehlp -c -Ot] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot +!endif + +!if [nmakehlp -c -Oi] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi +!endif + +!if [nmakehlp -c -Op] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Op +!endif + +!if [nmakehlp -c -fp:precise] +OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:precise +!endif + +!if [nmakehlp -c -fp:except] +OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:except +!endif + +!if [nmakehlp -c -Gs] +OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs +!endif + +!if [nmakehlp -c -GS] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GS +!endif + +!if [nmakehlp -c -GL] +OPTIMIZATIONS = $(OPTIMIZATIONS) -GL +!endif + +DEBUGFLAGS = + +!if [nmakehlp -c -RTC1] +DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 +!elseif [nmakehlp -c -GZ] +DEBUGFLAGS = $(DEBUGFLAGS) -GZ +!endif + +COMPILERFLAGS =-W3 + +!if [nmakehlp -c -YX] +OPTIMIZATIONS = $(OPTIMIZATIONS) -YX +!endif + !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' -PENT_0F_ERRATA = 1 +COMPILERFLAGS = $(COMPILERFLAGSS) -QI0f !else !message *** Compiler doesn't have 'Pentium 0x0f fix' -PENT_0F_ERRATA = 0 !endif +!endif + +!if "$(MACHINE)" == "IA64" +### test for Itanium errata +!if [nmakehlp -c -QIA64_Bx] +!message *** Compiler has 'B-stepping errata workarounds' +COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx +!else +!message *** Compiler does not have 'B-stepping errata workarounds' +!endif +!endif + +!if "$(MACHINE)" == "IX86" ### test for -align:4096, when align:512 will do. !if [nmakehlp -l -opt:nowin98] !message *** Linker has 'Win98 alignment problem' @@ -99,21 +165,32 @@ ALIGN98_HACK = 1 ALIGN98_HACK = 0 !endif !else -PENT_0F_ERRATA = 0 ALIGN98_HACK = 0 !endif -!if "$(MACHINE)" == "IA64" -### test for Itanium errata -!if [nmakehlp -c -QIA64_Bx] -!message *** Compiler has 'B-stepping errata workarounds' -ITAN_B_ERRATA = 1 -!else -!message *** Compiler doesn't have 'B-stepping errata workarounds' -ITAN_B_ERRATA = 0 +LINKERFLAGS = + +!if [nmakehlp -l -ltcg] +LINKERFLAGS =-ltcg !endif + +#---------------------------------------------------------- +# MSVC8 (ships with Visual Studio 2005) generates a manifest +# file that we should link into the binaries. This is how. +#---------------------------------------------------------- + +_VC_MANIFEST_EMBED_EXE= +_VC_MANIFEST_EMBED_DLL= +!if ![cl /Zs /Tc NUL 2>&1 | find "Version 12" > NUL] +VCVER=6 +!elseif ![cl /Zs /Tc NUL 2>&1 | find "Version 13" > NUL] +VCVER=7 +!elseif ![cl /Zs /Tc NUL 2>&1 | find "Version 14" > NUL] +VCVER=8 +_VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 +_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 !else -ITAN_B_ERRATA = 0 +VCVER=0 !endif #---------------------------------------------------------- @@ -220,6 +297,13 @@ BUILDDIRTOP = Debug BUILDDIRTOP = Release !endif +!if "$(MACHINE)" != "IX86" +BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) +!endif +!if $(VCVER) > 6 +BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) +!endif + !if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) SUFX = $(SUFX:g=) !endif @@ -310,7 +394,7 @@ FULLWARNINGS = 0 # Set our defines now armed with our options. #---------------------------------------------------------- -OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) +OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS !if $(TCL_MEM_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG @@ -339,7 +423,7 @@ OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif -!if "$(MACHINE)" == "IA64" +!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT !endif @@ -357,7 +441,7 @@ TCLINSTALL = 1 _TCLDIR = $(_INSTALLDIR) !else MSG=^ -Don't know where tcl.h is. Set the TCLDIR macro. +Failed to find tcl.h. Set the TCLDIR macro. !error $(MSG) !endif !else @@ -370,7 +454,7 @@ TCLH = "$(_TCLDIR)\generic\tcl.h" TCLINSTALL = 0 !else MSG =^ -Don't know where tcl.h is. The TCLDIR macro doesn't appear correct. +Failed to find tcl.h. The TCLDIR macro does not appear correct. !error $(MSG) !endif !endif @@ -404,7 +488,6 @@ Can't get version string from $(TCLH) !error $(MSG) !endif -TCL_PATCHLEVEL = a5 TCL_VERSION = $(TCL_DOTVERSION:.=) !if $(TCL_VERSION) < 81 @@ -444,5 +527,8 @@ TCLTOOLSDIR = $(_TCLDIR)\tools !message *** Output directory will be '$(OUT_DIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Optional defines are '$(OPTDEFINES)' +!message *** Compiler version $(VCVER) +!message *** Compiler options '$(OPTIMIZATIONS) $(DEBUGFLAGS)' +!message *** Link options '$(LINKERFLAGS)' !endif |