/[dtapublic]/projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkimgbmap.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tk_base_7_5_w_mods/tkimgbmap.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimgbmap.c revision 44 by dashley, Fri Oct 14 02:09:58 2016 UTC projs/dtats/trunk/shared_source/c_tk_base_7_5_w_mods/tkimgbmap.c revision 98 by dashley, Sun Dec 18 00:57:31 2016 UTC
# Line 1  Line 1 
 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkimgbmap.c,v 1.1.1.1 2001/06/13 05:02:24 dtashley Exp $ */  
   
 /*  
  * 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.1.1.1 2001/06/13 05:02:24 dtashley 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 _ANSI_ARGS_((Tcl_Channel chan));  
 static int              ImgBmapCreate _ANSI_ARGS_((Tcl_Interp *interp,  
                             char *name, int argc, Tcl_Obj *CONST objv[],  
                             Tk_ImageType *typePtr, Tk_ImageMaster master,  
                             ClientData *clientDataPtr));  
 static ClientData       ImgBmapGet _ANSI_ARGS_((Tk_Window tkwin,  
                             ClientData clientData));  
 static void             ImgBmapDisplay _ANSI_ARGS_((ClientData clientData,  
                             Display *display, Drawable drawable,  
                             int imageX, int imageY, int width, int height,  
                             int drawableX, int drawableY));  
 static void             ImgBmapFree _ANSI_ARGS_((ClientData clientData,  
                             Display *display));  
 static void             ImgBmapDelete _ANSI_ARGS_((ClientData clientData));  
 static int              ImgBmapPostscript _ANSI_ARGS_((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 */  
     (Tk_ImageType *) NULL       /* nextPtr */  
 };  
   
 /*  
  * Information used for parsing configuration specs:  
  */  
   
 static Tk_ConfigSpec configSpecs[] = {  
     {TK_CONFIG_UID, "-background", (char *) NULL, (char *) NULL,  
         "", Tk_Offset(BitmapMaster, bgUid), 0},  
     {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK},  
     {TK_CONFIG_UID, "-foreground", (char *) NULL, (char *) NULL,  
         "#000000", Tk_Offset(BitmapMaster, fgUid), 0},  
     {TK_CONFIG_STRING, "-maskdata", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(BitmapMaster, maskDataString),  
         TK_CONFIG_NULL_OK},  
     {TK_CONFIG_STRING, "-maskfile", (char *) NULL, (char *) NULL,  
         (char *) NULL, Tk_Offset(BitmapMaster, maskFileString),  
         TK_CONFIG_NULL_OK},  
     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,  
         (char *) 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 _ANSI_ARGS_((ClientData clientData,  
                             Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));  
 static void             ImgBmapCmdDeletedProc _ANSI_ARGS_((  
                             ClientData clientData));  
 static void             ImgBmapConfigureInstance _ANSI_ARGS_((  
                             BitmapInstance *instancePtr));  
 static int              ImgBmapConfigureMaster _ANSI_ARGS_((  
                             BitmapMaster *masterPtr, int argc, Tcl_Obj *CONST objv[],  
                             int flags));  
 static int              NextBitmapWord _ANSI_ARGS_((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(interp, name, argc, argv, typePtr, master, clientDataPtr)  
     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(masterPtr, objc, objv, flags)  
     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;  
   
     char **argv = (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(instancePtr)  
     BitmapInstance *instancePtr;        /* Instance to reconfigure. */  
 {  
     BitmapMaster *masterPtr = instancePtr->masterPtr;  
     XColor *colorPtr;  
     XGCValues gcValues;  
     GC gc;  
     unsigned int mask;  
     Pixmap 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;  
   
     if (instancePtr->bitmap != None) {  
         Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->bitmap);  
         instancePtr->bitmap = 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);  
     }  
   
     /*  
      * Careful:  We have to allocate a new mask Pixmap before deleting  
      * the old one.  Otherwise, The XID allocator will always return  
      * the same XID for the new Pixmap as was used for the old Pixmap.  
      * And that will prevent the mask from changing in the GC below.  
      */  
     oldMask = instancePtr->mask;  
     instancePtr->mask = None;  
     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 (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(interp, string, fileName, widthPtr, heightPtr,  
         hotXPtr, hotYPtr)  
     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, *heightPtr;          /* Dimensions of bitmap get returned  
                                          * here. */  
     int *hotXPtr, *hotYPtr;             /* Position of hot spot or -1,-1. */  
 {  
     int width, height, numBytes, hotX, hotY;  
     char *p, *end, *expandedFileName;  
     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", (char *) 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),  
                         (char *) 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",  
                         (char *) 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(parseInfoPtr)  
     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, interp, objc, objv)  
     ClientData clientData;      /* Information about the image master. */  
     Tcl_Interp *interp;         /* Current interpreter. */  
     int objc;                   /* Number of arguments. */  
     Tcl_Obj *CONST objv[];      /* Argument objects. */  
 {  
     static char *bmapOptions[] = {"cget", "configure", (char *) NULL};  
     BitmapMaster *masterPtr = (BitmapMaster *) clientData;  
     int code, 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: {  
         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: {  
         if (objc == 2) {  
             code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),  
                     configSpecs, (char *) masterPtr, (char *) NULL, 0);  
         } else if (objc == 3) {  
             code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),  
                     configSpecs, (char *) masterPtr,  
                     Tcl_GetString(objv[2]), 0);  
         } else {  
             code = ImgBmapConfigureMaster(masterPtr, objc-2, objv+2,  
                     TK_CONFIG_ARGV_ONLY);  
         }  
         return code;  
       }  
       default: {  
         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(tkwin, masterData)  
     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, display, drawable, imageX, imageY, width,  
         height, drawableX, drawableY)  
     ClientData clientData;      /* Pointer to BitmapInstance structure for  
                                  * 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, imageY;         /* Upper-left corner of region within image  
                                  * to draw. */  
     int width, height;          /* Dimensions of region within image to draw. */  
     int drawableX, 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, display)  
     ClientData clientData;      /* Pointer to BitmapInstance structure for  
                                  * 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(masterData)  
     ClientData masterData;      /* Pointer to BitmapMaster structure for  
                                  * image.  Must not have any more instances. */  
 {  
     BitmapMaster *masterPtr = (BitmapMaster *) masterData;  
   
     if (masterPtr->instancePtr != NULL) {  
         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, (Display *) 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 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(chan)  
     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;  
     }  
 }  
   
   
 /*  
  *----------------------------------------------------------------------  
  *  
  * ImgBmapPostscript --  
  *  
  *      This procedure is called by the image code to create  
  *      postscript output for an image.  
  *  
  * Results:  
  *      None.  
  *  
  * Side effects:  
  *      None.  
  *  
  *----------------------------------------------------------------------  
  */  
   
 static int  
 ImgBmapPostscript(clientData, interp, tkwin, psinfo, x, y, width, height,  
         prepass)  
     ClientData clientData;  
     Tcl_Interp *interp;  
     Tk_Window tkwin;  
     Tk_PostscriptInfo psinfo;  
     int x, y, width, height, prepass;  
 {  
     BitmapMaster *masterPtr = (BitmapMaster *) clientData;  
     int rowsAtOnce, rowsThisTime;  
     int curRow, yy;  
     char buffer[200];  
   
     if (prepass) {  
         return TCL_OK;  
     }  
     /*  
      * Color the background, if there is one.  
      */  
   
     if (masterPtr->bgUid != NULL) {  
         XColor color;  
         XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid,  
                 &color);  
         sprintf(buffer,  
                 "%d %d moveto %d 0 rlineto 0 %d rlineto %d %s\n",  
                 x, y, width, height, -width,"0 rlineto closepath");  
         Tcl_AppendResult(interp, buffer, (char *) NULL);  
         if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {  
             return TCL_ERROR;  
         }  
         Tcl_AppendResult(interp, "fill\n", (char *) NULL);  
     }  
   
     /*  
      * Draw the bitmap, if there is a foreground color.  If the bitmap  
      * is very large, then chop it up into multiple bitmaps, each  
      * consisting of one or more rows.  This is needed because Postscript  
      * can't handle single strings longer than 64 KBytes long.  
      */  
   
     if (masterPtr->fgUid != 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 (width > 60000) {  
             Tcl_ResetResult(interp);  
             Tcl_AppendResult(interp, "can't generate Postscript",  
                     " for bitmaps more than 60000 pixels wide",  
                     (char *) NULL);  
             return TCL_ERROR;  
         }  
         rowsAtOnce = 60000/width;  
         if (rowsAtOnce < 1) {  
             rowsAtOnce = 1;  
         }  
         sprintf(buffer, "%d %d translate\n", x, y);  
         Tcl_AppendResult(interp, buffer, (char *) NULL);  
         for (curRow = y+height-1; curRow >= y; curRow -= rowsAtOnce) {  
             rowsThisTime = rowsAtOnce;  
             if (rowsThisTime > (curRow + 1 - y)) {  
                 rowsThisTime = curRow + 1 - y;  
             }  
             sprintf(buffer, "%d %d", width, rowsThisTime);  
             Tcl_AppendResult(interp, buffer, " true matrix {\n<",  
                     (char *) NULL);  
             for (yy = curRow; yy >= (curRow - rowsThisTime + 1); yy--) {  
                 sprintf(buffer, "row %d\n", yy);  
                 Tcl_AppendResult(interp, buffer, (char *) NULL);  
             }  
             sprintf(buffer, "0 %.15g", (double) rowsThisTime);  
             Tcl_AppendResult(interp, ">\n} imagemask\n", buffer,  
                     " translate\n", (char *) NULL);  
         }  
     }  
     return TCL_OK;  
 }  
   
   
 /* $History: tkImgBmap.c $  
  *  
  * *****************  Version 1  *****************  
  * User: Dtashley     Date: 1/02/01    Time: 2:55a  
  * Created in $/IjuScripter, IjuConsole/Source/Tk Base  
  * Initial check-in.  
  */  
   
 /* End of TKIMGBMAP.C */  
1    /* $Header$ */
2    
3    /*
4     * tkImgBmap.c --
5     *
6     *      This procedure implements images of type "bitmap" for Tk.
7     *
8     * Copyright (c) 1994 The Regents of the University of California.
9     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10     * Copyright (c) 1999 by Scriptics Corporation.
11     *
12     * See the file "license.terms" for information on usage and redistribution
13     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14     *
15     * RCS: @(#) $Id: tkimgbmap.c,v 1.1.1.1 2001/06/13 05:02:24 dtashley Exp $
16     */
17    
18    #include "tkInt.h"
19    #include "tkPort.h"
20    
21    /*
22     * The following data structure represents the master for a bitmap
23     * image:
24     */
25    
26    typedef struct BitmapMaster {
27        Tk_ImageMaster tkMaster;    /* Tk's token for image master.  NULL means
28                                     * the image is being deleted. */
29        Tcl_Interp *interp;         /* Interpreter for application that is
30                                     * using image. */
31        Tcl_Command imageCmd;       /* Token for image command (used to delete
32                                     * it when the image goes away).  NULL means
33                                     * the image command has already been
34                                     * deleted. */
35        int width, height;          /* Dimensions of image. */
36        char *data;                 /* Data comprising bitmap (suitable for
37                                     * input to XCreateBitmapFromData).   May
38                                     * be NULL if no data.  Malloc'ed. */
39        char *maskData;             /* Data for bitmap's mask (suitable for
40                                     * input to XCreateBitmapFromData).
41                                     * Malloc'ed. */
42        Tk_Uid fgUid;               /* Value of -foreground option (malloc'ed). */
43        Tk_Uid bgUid;               /* Value of -background option (malloc'ed). */
44        char *fileString;           /* Value of -file option (malloc'ed). */
45        char *dataString;           /* Value of -data option (malloc'ed). */
46        char *maskFileString;       /* Value of -maskfile option (malloc'ed). */
47        char *maskDataString;       /* Value of -maskdata option (malloc'ed). */
48        struct BitmapInstance *instancePtr;
49                                    /* First in list of all instances associated
50                                     * with this master. */
51    } BitmapMaster;
52    
53    /*
54     * The following data structure represents all of the instances of an
55     * image that lie within a particular window:
56     */
57    
58    typedef struct BitmapInstance {
59        int refCount;               /* Number of instances that share this
60                                     * data structure. */
61        BitmapMaster *masterPtr;    /* Pointer to master for image. */
62        Tk_Window tkwin;            /* Window in which the instances will be
63                                     * displayed. */
64        XColor *fg;                 /* Foreground color for displaying image. */
65        XColor *bg;                 /* Background color for displaying image. */
66        Pixmap bitmap;              /* The bitmap to display. */
67        Pixmap mask;                /* Mask: only display bitmap pixels where
68                                     * there are 1's here. */
69        GC gc;                      /* Graphics context for displaying bitmap.
70                                     * None means there was an error while
71                                     * setting up the instance, so it cannot
72                                     * be displayed. */
73        struct BitmapInstance *nextPtr;
74                                    /* Next in list of all instance structures
75                                     * associated with masterPtr (NULL means
76                                     * end of list). */
77    } BitmapInstance;
78    
79    /*
80     * The type record for bitmap images:
81     */
82    
83    static int              GetByte _ANSI_ARGS_((Tcl_Channel chan));
84    static int              ImgBmapCreate _ANSI_ARGS_((Tcl_Interp *interp,
85                                char *name, int argc, Tcl_Obj *CONST objv[],
86                                Tk_ImageType *typePtr, Tk_ImageMaster master,
87                                ClientData *clientDataPtr));
88    static ClientData       ImgBmapGet _ANSI_ARGS_((Tk_Window tkwin,
89                                ClientData clientData));
90    static void             ImgBmapDisplay _ANSI_ARGS_((ClientData clientData,
91                                Display *display, Drawable drawable,
92                                int imageX, int imageY, int width, int height,
93                                int drawableX, int drawableY));
94    static void             ImgBmapFree _ANSI_ARGS_((ClientData clientData,
95                                Display *display));
96    static void             ImgBmapDelete _ANSI_ARGS_((ClientData clientData));
97    static int              ImgBmapPostscript _ANSI_ARGS_((ClientData clientData,
98                                Tcl_Interp *interp, Tk_Window tkwin,
99                                Tk_PostscriptInfo psinfo, int x, int y,
100                                int width, int height, int prepass));
101    
102    Tk_ImageType tkBitmapImageType = {
103        "bitmap",                   /* name */
104        ImgBmapCreate,              /* createProc */
105        ImgBmapGet,                 /* getProc */
106        ImgBmapDisplay,             /* displayProc */
107        ImgBmapFree,                /* freeProc */
108        ImgBmapDelete,              /* deleteProc */
109        ImgBmapPostscript,          /* postscriptProc */
110        (Tk_ImageType *) NULL       /* nextPtr */
111    };
112    
113    /*
114     * Information used for parsing configuration specs:
115     */
116    
117    static Tk_ConfigSpec configSpecs[] = {
118        {TK_CONFIG_UID, "-background", (char *) NULL, (char *) NULL,
119            "", Tk_Offset(BitmapMaster, bgUid), 0},
120        {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
121            (char *) NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK},
122        {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
123            (char *) NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK},
124        {TK_CONFIG_UID, "-foreground", (char *) NULL, (char *) NULL,
125            "#000000", Tk_Offset(BitmapMaster, fgUid), 0},
126        {TK_CONFIG_STRING, "-maskdata", (char *) NULL, (char *) NULL,
127            (char *) NULL, Tk_Offset(BitmapMaster, maskDataString),
128            TK_CONFIG_NULL_OK},
129        {TK_CONFIG_STRING, "-maskfile", (char *) NULL, (char *) NULL,
130            (char *) NULL, Tk_Offset(BitmapMaster, maskFileString),
131            TK_CONFIG_NULL_OK},
132        {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
133            (char *) NULL, 0, 0}
134    };
135    
136    /*
137     * The following data structure is used to describe the state of
138     * parsing a bitmap file or string.  It is used for communication
139     * between TkGetBitmapData and NextBitmapWord.
140     */
141    
142    #define MAX_WORD_LENGTH 100
143    typedef struct ParseInfo {
144        char *string;               /* Next character of string data for bitmap,
145                                     * or NULL if bitmap is being read from
146                                     * file. */
147        Tcl_Channel chan;           /* File containing bitmap data, or NULL
148                                     * if no file. */
149        char word[MAX_WORD_LENGTH+1];
150                                    /* Current word of bitmap data, NULL
151                                     * terminated. */
152        int wordLength;             /* Number of non-NULL bytes in word. */
153    } ParseInfo;
154    
155    /*
156     * Prototypes for procedures used only locally in this file:
157     */
158    
159    static int              ImgBmapCmd _ANSI_ARGS_((ClientData clientData,
160                                Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
161    static void             ImgBmapCmdDeletedProc _ANSI_ARGS_((
162                                ClientData clientData));
163    static void             ImgBmapConfigureInstance _ANSI_ARGS_((
164                                BitmapInstance *instancePtr));
165    static int              ImgBmapConfigureMaster _ANSI_ARGS_((
166                                BitmapMaster *masterPtr, int argc, Tcl_Obj *CONST objv[],
167                                int flags));
168    static int              NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr));
169    
170    /*
171     *----------------------------------------------------------------------
172     *
173     * ImgBmapCreate --
174     *
175     *      This procedure is called by the Tk image code to create "test"
176     *      images.
177     *
178     * Results:
179     *      A standard Tcl result.
180     *
181     * Side effects:
182     *      The data structure for a new image is allocated.
183     *
184     *----------------------------------------------------------------------
185     */
186    
187            /* ARGSUSED */
188    static int
189    ImgBmapCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
190        Tcl_Interp *interp;         /* Interpreter for application containing
191                                     * image. */
192        char *name;                 /* Name to use for image. */
193        int argc;                   /* Number of arguments. */
194        Tcl_Obj *CONST argv[];      /* Argument objects for options (doesn't
195                                     * include image name or type). */
196        Tk_ImageType *typePtr;      /* Pointer to our type record (not used). */
197        Tk_ImageMaster master;      /* Token for image, to be used by us in
198                                     * later callbacks. */
199        ClientData *clientDataPtr;  /* Store manager's token for image here;
200                                     * it will be returned in later callbacks. */
201    {
202        BitmapMaster *masterPtr;
203    
204        masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster));
205        masterPtr->tkMaster = master;
206        masterPtr->interp = interp;
207        masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgBmapCmd,
208                (ClientData) masterPtr, ImgBmapCmdDeletedProc);
209        masterPtr->width = masterPtr->height = 0;
210        masterPtr->data = NULL;
211        masterPtr->maskData = NULL;
212        masterPtr->fgUid = NULL;
213        masterPtr->bgUid = NULL;
214        masterPtr->fileString = NULL;
215        masterPtr->dataString = NULL;
216        masterPtr->maskFileString = NULL;
217        masterPtr->maskDataString = NULL;
218        masterPtr->instancePtr = NULL;
219        if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
220            ImgBmapDelete((ClientData) masterPtr);
221            return TCL_ERROR;
222        }
223        *clientDataPtr = (ClientData) masterPtr;
224        return TCL_OK;
225    }
226    
227    /*
228     *----------------------------------------------------------------------
229     *
230     * ImgBmapConfigureMaster --
231     *
232     *      This procedure is called when a bitmap image is created or
233     *      reconfigured.  It process configuration options and resets
234     *      any instances of the image.
235     *
236     * Results:
237     *      A standard Tcl return value.  If TCL_ERROR is returned then
238     *      an error message is left in the masterPtr->interp's result.
239     *
240     * Side effects:
241     *      Existing instances of the image will be redisplayed to match
242     *      the new configuration options.
243     *
244     *----------------------------------------------------------------------
245     */
246    
247    static int
248    ImgBmapConfigureMaster(masterPtr, objc, objv, flags)
249        BitmapMaster *masterPtr;    /* Pointer to data structure describing
250                                     * overall bitmap image to (reconfigure). */
251        int objc;                   /* Number of entries in objv. */
252        Tcl_Obj *CONST objv[];      /* Pairs of configuration options for image. */
253        int flags;                  /* Flags to pass to Tk_ConfigureWidget,
254                                     * such as TK_CONFIG_ARGV_ONLY. */
255    {
256        BitmapInstance *instancePtr;
257        int maskWidth, maskHeight, dummy1, dummy2;
258    
259        char **argv = (char **) ckalloc((objc+1) * sizeof(char *));
260        for (dummy1 = 0; dummy1 < objc; dummy1++) {
261            argv[dummy1]=Tcl_GetString(objv[dummy1]);
262        }
263        argv[objc] = NULL;
264    
265        if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
266                configSpecs, objc, argv, (char *) masterPtr, flags)
267                != TCL_OK) {
268            ckfree((char *) argv);
269            return TCL_ERROR;
270        }
271        ckfree((char *) argv);
272    
273        /*
274         * Parse the bitmap and/or mask to create binary data.  Make sure that
275         * the bitmap and mask have the same dimensions.
276         */
277    
278        if (masterPtr->data != NULL) {
279            ckfree(masterPtr->data);
280            masterPtr->data = NULL;
281        }
282        if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) {
283            masterPtr->data = TkGetBitmapData(masterPtr->interp,
284                    masterPtr->dataString, masterPtr->fileString,
285                    &masterPtr->width, &masterPtr->height, &dummy1, &dummy2);
286            if (masterPtr->data == NULL) {
287                return TCL_ERROR;
288            }
289        }
290        if (masterPtr->maskData != NULL) {
291            ckfree(masterPtr->maskData);
292            masterPtr->maskData = NULL;
293        }
294        if ((masterPtr->maskFileString != NULL)
295                || (masterPtr->maskDataString != NULL)) {
296            if (masterPtr->data == NULL) {
297                Tcl_SetResult(masterPtr->interp, "can't have mask without bitmap",
298                        TCL_STATIC);
299                return TCL_ERROR;
300            }
301            masterPtr->maskData = TkGetBitmapData(masterPtr->interp,
302                    masterPtr->maskDataString, masterPtr->maskFileString,
303                    &maskWidth, &maskHeight, &dummy1, &dummy2);
304            if (masterPtr->maskData == NULL) {
305                return TCL_ERROR;
306            }
307            if ((maskWidth != masterPtr->width)
308                    || (maskHeight != masterPtr->height)) {
309                ckfree(masterPtr->maskData);
310                masterPtr->maskData = NULL;
311                Tcl_SetResult(masterPtr->interp,
312                        "bitmap and mask have different sizes", TCL_STATIC);
313                return TCL_ERROR;
314            }
315        }
316    
317        /*
318         * Cycle through all of the instances of this image, regenerating
319         * the information for each instance.  Then force the image to be
320         * redisplayed everywhere that it is used.
321         */
322    
323        for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
324                instancePtr = instancePtr->nextPtr) {
325            ImgBmapConfigureInstance(instancePtr);
326        }
327        Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
328                masterPtr->height, masterPtr->width, masterPtr->height);
329        return TCL_OK;
330    }
331    
332    /*
333     *----------------------------------------------------------------------
334     *
335     * ImgBmapConfigureInstance --
336     *
337     *      This procedure is called to create displaying information for
338     *      a bitmap image instance based on the configuration information
339     *      in the master.  It is invoked both when new instances are
340     *      created and when the master is reconfigured.
341     *
342     * Results:
343     *      None.
344     *
345     * Side effects:
346     *      Generates errors via Tcl_BackgroundError if there are problems
347     *      in setting up the instance.
348     *
349     *----------------------------------------------------------------------
350     */
351    
352    static void
353    ImgBmapConfigureInstance(instancePtr)
354        BitmapInstance *instancePtr;        /* Instance to reconfigure. */
355    {
356        BitmapMaster *masterPtr = instancePtr->masterPtr;
357        XColor *colorPtr;
358        XGCValues gcValues;
359        GC gc;
360        unsigned int mask;
361        Pixmap oldMask;
362    
363        /*
364         * For each of the options in masterPtr, translate the string
365         * form into an internal form appropriate for instancePtr.
366         */
367    
368        if (*masterPtr->bgUid != 0) {
369            colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
370                    masterPtr->bgUid);
371            if (colorPtr == NULL) {
372                goto error;
373            }
374        } else {
375            colorPtr = NULL;
376        }
377        if (instancePtr->bg != NULL) {
378            Tk_FreeColor(instancePtr->bg);
379        }
380        instancePtr->bg = colorPtr;
381    
382        colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
383                masterPtr->fgUid);
384        if (colorPtr == NULL) {
385            goto error;
386        }
387        if (instancePtr->fg != NULL) {
388            Tk_FreeColor(instancePtr->fg);
389        }
390        instancePtr->fg = colorPtr;
391    
392        if (instancePtr->bitmap != None) {
393            Tk_FreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->bitmap);
394            instancePtr->bitmap = None;
395        }
396        if (masterPtr->data != NULL) {
397            instancePtr->bitmap = XCreateBitmapFromData(
398                    Tk_Display(instancePtr->tkwin),
399                    RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
400                    masterPtr->data, (unsigned) masterPtr->width,
401                    (unsigned) masterPtr->height);
402        }
403    
404        /*
405         * Careful:  We have to allocate a new mask Pixmap before deleting
406         * the old one.  Otherwise, The XID allocator will always return
407         * the same XID for the new Pixmap as was used for the old Pixmap.
408         * And that will prevent the mask from changing in the GC below.
409         */
410        oldMask = instancePtr->mask;
411        instancePtr->mask = None;
412        if (masterPtr->maskData != NULL) {
413            instancePtr->mask = XCreateBitmapFromData(
414                    Tk_Display(instancePtr->tkwin),
415                    RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
416                    masterPtr->maskData, (unsigned) masterPtr->width,
417                    (unsigned) masterPtr->height);
418        }
419        if (oldMask != None) {
420          Tk_FreePixmap(Tk_Display(instancePtr->tkwin), oldMask);
421        }
422    
423        if (masterPtr->data != NULL) {
424            gcValues.foreground = instancePtr->fg->pixel;
425            gcValues.graphics_exposures = False;
426            mask = GCForeground|GCGraphicsExposures;
427            if (instancePtr->bg != NULL) {
428                gcValues.background = instancePtr->bg->pixel;
429                mask |= GCBackground;
430                if (instancePtr->mask != None) {
431                    gcValues.clip_mask = instancePtr->mask;
432                    mask |= GCClipMask;
433                }
434            } else {
435                gcValues.clip_mask = instancePtr->bitmap;
436                mask |= GCClipMask;
437            }
438            gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues);
439        } else {
440            gc = None;
441        }
442        if (instancePtr->gc != None) {
443            Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
444        }
445        instancePtr->gc = gc;
446        return;
447    
448        error:
449        /*
450         * An error occurred: clear the graphics context in the instance to
451         * make it clear that this instance cannot be displayed.  Then report
452         * the error.
453         */
454    
455        if (instancePtr->gc != None) {
456            Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
457        }
458        instancePtr->gc = None;
459        Tcl_AddErrorInfo(masterPtr->interp, "\n    (while configuring image \"");
460        Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
461        Tcl_AddErrorInfo(masterPtr->interp, "\")");
462        Tcl_BackgroundError(masterPtr->interp);
463    }
464    
465    /*
466     *----------------------------------------------------------------------
467     *
468     * TkGetBitmapData --
469     *
470     *      Given a file name or ASCII string, this procedure parses the
471     *      file or string contents to produce binary data for a bitmap.
472     *
473     * Results:
474     *      If the bitmap description was parsed successfully then the
475     *      return value is a malloc-ed array containing the bitmap data.
476     *      The dimensions of the data are stored in *widthPtr and
477     *      *heightPtr.  *hotXPtr and *hotYPtr are set to the bitmap
478     *      hotspot if one is defined, otherwise they are set to -1, -1.
479     *      If an error occurred, NULL is returned and an error message is
480     *      left in the interp's result.
481     *
482     * Side effects:
483     *      A bitmap is created.
484     *
485     *----------------------------------------------------------------------
486     */
487    
488    char *
489    TkGetBitmapData(interp, string, fileName, widthPtr, heightPtr,
490            hotXPtr, hotYPtr)
491        Tcl_Interp *interp;                 /* For reporting errors, or NULL. */
492        char *string;                       /* String describing bitmap.  May
493                                             * be NULL. */
494        char *fileName;                     /* Name of file containing bitmap
495                                             * description.  Used only if string
496                                             * is NULL.  Must not be NULL if
497                                             * string is NULL. */
498        int *widthPtr, *heightPtr;          /* Dimensions of bitmap get returned
499                                             * here. */
500        int *hotXPtr, *hotYPtr;             /* Position of hot spot or -1,-1. */
501    {
502        int width, height, numBytes, hotX, hotY;
503        char *p, *end, *expandedFileName;
504        ParseInfo pi;
505        char *data = NULL;
506        Tcl_DString buffer;
507    
508        pi.string = string;
509        if (string == NULL) {
510            if ((interp != NULL) && Tcl_IsSafe(interp)) {
511                Tcl_AppendResult(interp, "can't get bitmap data from a file in a",
512                        " safe interpreter", (char *) NULL);
513                return NULL;
514            }
515            expandedFileName = Tcl_TranslateFileName(interp, fileName, &buffer);
516            if (expandedFileName == NULL) {
517                return NULL;
518            }
519            pi.chan = Tcl_OpenFileChannel(interp, expandedFileName, "r", 0);
520            Tcl_DStringFree(&buffer);
521            if (pi.chan == NULL) {
522                if (interp != NULL) {
523                    Tcl_ResetResult(interp);
524                    Tcl_AppendResult(interp, "couldn't read bitmap file \"",
525                            fileName, "\": ", Tcl_PosixError(interp),
526                            (char *) NULL);
527                }
528                return NULL;
529            }
530            
531            if (Tcl_SetChannelOption(interp, pi.chan, "-translation", "binary")
532                    != TCL_OK) {
533                return NULL;
534            }
535            if (Tcl_SetChannelOption(interp, pi.chan, "-encoding", "binary")
536                    != TCL_OK) {
537                return NULL;
538            }
539        } else {
540            pi.chan = NULL;
541        }
542    
543        /*
544         * Parse the lines that define the dimensions of the bitmap,
545         * plus the first line that defines the bitmap data (it declares
546         * the name of a data variable but doesn't include any actual
547         * data).  These lines look something like the following:
548         *
549         *          #define foo_width 16
550         *          #define foo_height 16
551         *          #define foo_x_hot 3
552         *          #define foo_y_hot 3
553         *          static char foo_bits[] = {
554         *
555         * The x_hot and y_hot lines may or may not be present.  It's
556         * important to check for "char" in the last line, in order to
557         * reject old X10-style bitmaps that used shorts.
558         */
559    
560        width = 0;
561        height = 0;
562        hotX = -1;
563        hotY = -1;
564        while (1) {
565            if (NextBitmapWord(&pi) != TCL_OK) {
566                goto error;
567            }
568            if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
569                    && (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) {
570                if (NextBitmapWord(&pi) != TCL_OK) {
571                    goto error;
572                }
573                width = strtol(pi.word, &end, 0);
574                if ((end == pi.word) || (*end != 0)) {
575                    goto error;
576                }
577            } else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_')
578                    && (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) {
579                if (NextBitmapWord(&pi) != TCL_OK) {
580                    goto error;
581                }
582                height = strtol(pi.word, &end, 0);
583                if ((end == pi.word) || (*end != 0)) {
584                    goto error;
585                }
586            } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
587                    && (strcmp(pi.word+pi.wordLength-6, "_x_hot") == 0)) {
588                if (NextBitmapWord(&pi) != TCL_OK) {
589                    goto error;
590                }
591                hotX = strtol(pi.word, &end, 0);
592                if ((end == pi.word) || (*end != 0)) {
593                    goto error;
594                }
595            } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
596                    && (strcmp(pi.word+pi.wordLength-6, "_y_hot") == 0)) {
597                if (NextBitmapWord(&pi) != TCL_OK) {
598                    goto error;
599                }
600                hotY = strtol(pi.word, &end, 0);
601                if ((end == pi.word) || (*end != 0)) {
602                    goto error;
603                }
604            } else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) {
605                while (1) {
606                    if (NextBitmapWord(&pi) != TCL_OK) {
607                        goto error;
608                    }
609                    if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
610                        goto getData;
611                    }
612                }
613            } else if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
614                if (interp != NULL) {
615                    Tcl_AppendResult(interp, "format error in bitmap data; ",
616                            "looks like it's an obsolete X10 bitmap file",
617                            (char *) NULL);
618                }
619                goto errorCleanup;
620            }
621        }
622    
623        /*
624         * Now we've read everything but the data.  Allocate an array
625         * and read in the data.
626         */
627    
628        getData:
629        if ((width <= 0) || (height <= 0)) {
630            goto error;
631        }
632        numBytes = ((width+7)/8) * height;
633        data = (char *) ckalloc((unsigned) numBytes);
634        for (p = data; numBytes > 0; p++, numBytes--) {
635            if (NextBitmapWord(&pi) != TCL_OK) {
636                goto error;
637            }
638            *p = (char) strtol(pi.word, &end, 0);
639            if (end == pi.word) {
640                goto error;
641            }
642        }
643    
644        /*
645         * All done.  Clean up and return.
646         */
647    
648        if (pi.chan != NULL) {
649            Tcl_Close(NULL, pi.chan);
650        }
651        *widthPtr = width;
652        *heightPtr = height;
653        *hotXPtr = hotX;
654        *hotYPtr = hotY;
655        return data;
656    
657        error:
658        if (interp != NULL) {
659            Tcl_SetResult(interp, "format error in bitmap data", TCL_STATIC);
660        }
661        
662        errorCleanup:
663        if (data != NULL) {
664            ckfree(data);
665        }
666        if (pi.chan != NULL) {
667            Tcl_Close(NULL, pi.chan);
668        }
669        return NULL;
670    }
671    
672    /*
673     *----------------------------------------------------------------------
674     *
675     * NextBitmapWord --
676     *
677     *      This procedure retrieves the next word of information (stuff
678     *      between commas or white space) from a bitmap description.
679     *
680     * Results:
681     *      Returns TCL_OK if all went well.  In this case the next word,
682     *      and its length, will be availble in *parseInfoPtr.  If the end
683     *      of the bitmap description was reached then TCL_ERROR is returned.
684     *
685     * Side effects:
686     *      None.
687     *
688     *----------------------------------------------------------------------
689     */
690    
691    static int
692    NextBitmapWord(parseInfoPtr)
693        ParseInfo *parseInfoPtr;            /* Describes what we're reading
694                                             * and where we are in it. */
695    {
696        char *src, *dst;
697        int c;
698    
699        parseInfoPtr->wordLength = 0;
700        dst = parseInfoPtr->word;
701        if (parseInfoPtr->string != NULL) {
702            for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ',');
703                    src++) {
704                if (*src == 0) {
705                    return TCL_ERROR;
706                }
707            }
708            for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) {
709                *dst = *src;
710                dst++;
711                parseInfoPtr->wordLength++;
712                if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
713                    return TCL_ERROR;
714                }
715            }
716            parseInfoPtr->string = src;
717        } else {
718            for (c = GetByte(parseInfoPtr->chan); isspace(UCHAR(c)) || (c == ',');
719                    c = GetByte(parseInfoPtr->chan)) {
720                if (c == EOF) {
721                    return TCL_ERROR;
722                }
723            }
724            for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF);
725                    c = GetByte(parseInfoPtr->chan)) {
726                *dst = c;
727                dst++;
728                parseInfoPtr->wordLength++;
729                if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
730                    return TCL_ERROR;
731                }
732            }
733        }
734        if (parseInfoPtr->wordLength == 0) {
735            return TCL_ERROR;
736        }
737        parseInfoPtr->word[parseInfoPtr->wordLength] = 0;
738        return TCL_OK;
739    }
740    
741    /*
742     *--------------------------------------------------------------
743     *
744     * ImgBmapCmd --
745     *
746     *      This procedure is invoked to process the Tcl command
747     *      that corresponds to an image managed by this module.
748     *      See the user documentation for details on what it does.
749     *
750     * Results:
751     *      A standard Tcl result.
752     *
753     * Side effects:
754     *      See the user documentation.
755     *
756     *--------------------------------------------------------------
757     */
758    
759    static int
760    ImgBmapCmd(clientData, interp, objc, objv)
761        ClientData clientData;      /* Information about the image master. */
762        Tcl_Interp *interp;         /* Current interpreter. */
763        int objc;                   /* Number of arguments. */
764        Tcl_Obj *CONST objv[];      /* Argument objects. */
765    {
766        static char *bmapOptions[] = {"cget", "configure", (char *) NULL};
767        BitmapMaster *masterPtr = (BitmapMaster *) clientData;
768        int code, index;
769    
770        if (objc < 2) {
771            Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
772            return TCL_ERROR;
773        }
774        if (Tcl_GetIndexFromObj(interp, objv[1], bmapOptions, "option", 0,
775                &index) != TCL_OK) {
776            return TCL_ERROR;
777        }
778        switch (index) {
779          case 0: {
780            if (objc != 3) {
781                Tcl_WrongNumArgs(interp, 2, objv, "option");
782                return TCL_ERROR;
783            }
784            return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
785                    (char *) masterPtr, Tcl_GetString(objv[2]), 0);
786          }
787          case 1: {
788            if (objc == 2) {
789                code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
790                        configSpecs, (char *) masterPtr, (char *) NULL, 0);
791            } else if (objc == 3) {
792                code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
793                        configSpecs, (char *) masterPtr,
794                        Tcl_GetString(objv[2]), 0);
795            } else {
796                code = ImgBmapConfigureMaster(masterPtr, objc-2, objv+2,
797                        TK_CONFIG_ARGV_ONLY);
798            }
799            return code;
800          }
801          default: {
802            panic("bad const entries to bmapOptions in ImgBmapCmd");
803          }
804        }
805        return TCL_OK;
806    }
807    
808    /*
809     *----------------------------------------------------------------------
810     *
811     * ImgBmapGet --
812     *
813     *      This procedure is called for each use of a bitmap image in a
814     *      widget.
815     *
816     * Results:
817     *      The return value is a token for the instance, which is passed
818     *      back to us in calls to ImgBmapDisplay and ImgBmapFree.
819     *
820     * Side effects:
821     *      A data structure is set up for the instance (or, an existing
822     *      instance is re-used for the new one).
823     *
824     *----------------------------------------------------------------------
825     */
826    
827    static ClientData
828    ImgBmapGet(tkwin, masterData)
829        Tk_Window tkwin;            /* Window in which the instance will be
830                                     * used. */
831        ClientData masterData;      /* Pointer to our master structure for the
832                                     * image. */
833    {
834        BitmapMaster *masterPtr = (BitmapMaster *) masterData;
835        BitmapInstance *instancePtr;
836    
837        /*
838         * See if there is already an instance for this window.  If so
839         * then just re-use it.
840         */
841    
842        for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
843                instancePtr = instancePtr->nextPtr) {
844            if (instancePtr->tkwin == tkwin) {
845                instancePtr->refCount++;
846                return (ClientData) instancePtr;
847            }
848        }
849    
850        /*
851         * The image isn't already in use in this window.  Make a new
852         * instance of the image.
853         */
854    
855        instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance));
856        instancePtr->refCount = 1;
857        instancePtr->masterPtr = masterPtr;
858        instancePtr->tkwin = tkwin;
859        instancePtr->fg = NULL;
860        instancePtr->bg = NULL;
861        instancePtr->bitmap = None;
862        instancePtr->mask = None;
863        instancePtr->gc = None;
864        instancePtr->nextPtr = masterPtr->instancePtr;
865        masterPtr->instancePtr = instancePtr;
866        ImgBmapConfigureInstance(instancePtr);
867    
868        /*
869         * If this is the first instance, must set the size of the image.
870         */
871    
872        if (instancePtr->nextPtr == NULL) {
873            Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
874                    masterPtr->height);
875        }
876    
877        return (ClientData) instancePtr;
878    }
879    
880    /*
881     *----------------------------------------------------------------------
882     *
883     * ImgBmapDisplay --
884     *
885     *      This procedure is invoked to draw a bitmap image.
886     *
887     * Results:
888     *      None.
889     *
890     * Side effects:
891     *      A portion of the image gets rendered in a pixmap or window.
892     *
893     *----------------------------------------------------------------------
894     */
895    
896    static void
897    ImgBmapDisplay(clientData, display, drawable, imageX, imageY, width,
898            height, drawableX, drawableY)
899        ClientData clientData;      /* Pointer to BitmapInstance structure for
900                                     * for instance to be displayed. */
901        Display *display;           /* Display on which to draw image. */
902        Drawable drawable;          /* Pixmap or window in which to draw image. */
903        int imageX, imageY;         /* Upper-left corner of region within image
904                                     * to draw. */
905        int width, height;          /* Dimensions of region within image to draw. */
906        int drawableX, drawableY;   /* Coordinates within drawable that
907                                     * correspond to imageX and imageY. */
908    {
909        BitmapInstance *instancePtr = (BitmapInstance *) clientData;
910        int masking;
911    
912        /*
913         * If there's no graphics context, it means that an error occurred
914         * while creating the image instance so it can't be displayed.
915         */
916    
917        if (instancePtr->gc == None) {
918            return;
919        }
920    
921        /*
922         * If masking is in effect, must modify the mask origin within
923         * the graphics context to line up with the image's origin.
924         * Then draw the image and reset the clip origin, if there's
925         * a mask.
926         */
927    
928        masking = (instancePtr->mask != None) || (instancePtr->bg == NULL);
929        if (masking) {
930            XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
931                    drawableY - imageY);
932        }
933        XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc,
934                imageX, imageY, (unsigned) width, (unsigned) height,
935                drawableX, drawableY, 1);
936        if (masking) {
937            XSetClipOrigin(display, instancePtr->gc, 0, 0);
938        }
939    }
940    
941    /*
942     *----------------------------------------------------------------------
943     *
944     * ImgBmapFree --
945     *
946     *      This procedure is called when a widget ceases to use a
947     *      particular instance of an image.
948     *
949     * Results:
950     *      None.
951     *
952     * Side effects:
953     *      Internal data structures get cleaned up.
954     *
955     *----------------------------------------------------------------------
956     */
957    
958    static void
959    ImgBmapFree(clientData, display)
960        ClientData clientData;      /* Pointer to BitmapInstance structure for
961                                     * for instance to be displayed. */
962        Display *display;           /* Display containing window that used image. */
963    {
964        BitmapInstance *instancePtr = (BitmapInstance *) clientData;
965        BitmapInstance *prevPtr;
966    
967        instancePtr->refCount--;
968        if (instancePtr->refCount > 0) {
969            return;
970        }
971    
972        /*
973         * There are no more uses of the image within this widget.  Free
974         * the instance structure.
975         */
976    
977        if (instancePtr->fg != NULL) {
978            Tk_FreeColor(instancePtr->fg);
979        }
980        if (instancePtr->bg != NULL) {
981            Tk_FreeColor(instancePtr->bg);
982        }
983        if (instancePtr->bitmap != None) {
984            Tk_FreePixmap(display, instancePtr->bitmap);
985        }
986        if (instancePtr->mask != None) {
987            Tk_FreePixmap(display, instancePtr->mask);
988        }
989        if (instancePtr->gc != None) {
990            Tk_FreeGC(display, instancePtr->gc);
991        }
992        if (instancePtr->masterPtr->instancePtr == instancePtr) {
993            instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
994        } else {
995            for (prevPtr = instancePtr->masterPtr->instancePtr;
996                    prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
997                /* Empty loop body */
998            }
999            prevPtr->nextPtr = instancePtr->nextPtr;
1000        }
1001        ckfree((char *) instancePtr);
1002    }
1003    
1004    /*
1005     *----------------------------------------------------------------------
1006     *
1007     * ImgBmapDelete --
1008     *
1009     *      This procedure is called by the image code to delete the
1010     *      master structure for an image.
1011     *
1012     * Results:
1013     *      None.
1014     *
1015     * Side effects:
1016     *      Resources associated with the image get freed.
1017     *
1018     *----------------------------------------------------------------------
1019     */
1020    
1021    static void
1022    ImgBmapDelete(masterData)
1023        ClientData masterData;      /* Pointer to BitmapMaster structure for
1024                                     * image.  Must not have any more instances. */
1025    {
1026        BitmapMaster *masterPtr = (BitmapMaster *) masterData;
1027    
1028        if (masterPtr->instancePtr != NULL) {
1029            panic("tried to delete bitmap image when instances still exist");
1030        }
1031        masterPtr->tkMaster = NULL;
1032        if (masterPtr->imageCmd != NULL) {
1033            Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
1034        }
1035        if (masterPtr->data != NULL) {
1036            ckfree(masterPtr->data);
1037        }
1038        if (masterPtr->maskData != NULL) {
1039            ckfree(masterPtr->maskData);
1040        }
1041        Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
1042        ckfree((char *) masterPtr);
1043    }
1044    
1045    /*
1046     *----------------------------------------------------------------------
1047     *
1048     * ImgBmapCmdDeletedProc --
1049     *
1050     *      This procedure is invoked when the image command for an image
1051     *      is deleted.  It deletes the image.
1052     *
1053     * Results:
1054     *      None.
1055     *
1056     * Side effects:
1057     *      The image is deleted.
1058     *
1059     *----------------------------------------------------------------------
1060     */
1061    
1062    static void
1063    ImgBmapCmdDeletedProc(clientData)
1064        ClientData clientData;      /* Pointer to BitmapMaster structure for
1065                                     * image. */
1066    {
1067        BitmapMaster *masterPtr = (BitmapMaster *) clientData;
1068    
1069        masterPtr->imageCmd = NULL;
1070        if (masterPtr->tkMaster != NULL) {
1071            Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
1072        }
1073    }
1074    
1075    /*
1076     *----------------------------------------------------------------------
1077     *
1078     * GetByte --
1079     *
1080     *      Get the next byte from the open channel.
1081     *
1082     * Results:
1083     *      The next byte or EOF.
1084     *
1085     * Side effects:
1086     *      We read from the channel.
1087     *
1088     *----------------------------------------------------------------------
1089     */
1090    
1091    static int
1092    GetByte(chan)
1093        Tcl_Channel chan;   /* The channel we read from. */
1094    {
1095        char buffer;
1096        int size;
1097    
1098        size = Tcl_Read(chan, &buffer, 1);
1099        if (size <= 0) {
1100            return EOF;
1101        } else {
1102            return buffer;
1103        }
1104    }
1105    
1106    
1107    /*
1108     *----------------------------------------------------------------------
1109     *
1110     * ImgBmapPostscript --
1111     *
1112     *      This procedure is called by the image code to create
1113     *      postscript output for an image.
1114     *
1115     * Results:
1116     *      None.
1117     *
1118     * Side effects:
1119     *      None.
1120     *
1121     *----------------------------------------------------------------------
1122     */
1123    
1124    static int
1125    ImgBmapPostscript(clientData, interp, tkwin, psinfo, x, y, width, height,
1126            prepass)
1127        ClientData clientData;
1128        Tcl_Interp *interp;
1129        Tk_Window tkwin;
1130        Tk_PostscriptInfo psinfo;
1131        int x, y, width, height, prepass;
1132    {
1133        BitmapMaster *masterPtr = (BitmapMaster *) clientData;
1134        int rowsAtOnce, rowsThisTime;
1135        int curRow, yy;
1136        char buffer[200];
1137    
1138        if (prepass) {
1139            return TCL_OK;
1140        }
1141        /*
1142         * Color the background, if there is one.
1143         */
1144    
1145        if (masterPtr->bgUid != NULL) {
1146            XColor color;
1147            XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->bgUid,
1148                    &color);
1149            sprintf(buffer,
1150                    "%d %d moveto %d 0 rlineto 0 %d rlineto %d %s\n",
1151                    x, y, width, height, -width,"0 rlineto closepath");
1152            Tcl_AppendResult(interp, buffer, (char *) NULL);
1153            if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {
1154                return TCL_ERROR;
1155            }
1156            Tcl_AppendResult(interp, "fill\n", (char *) NULL);
1157        }
1158    
1159        /*
1160         * Draw the bitmap, if there is a foreground color.  If the bitmap
1161         * is very large, then chop it up into multiple bitmaps, each
1162         * consisting of one or more rows.  This is needed because Postscript
1163         * can't handle single strings longer than 64 KBytes long.
1164         */
1165    
1166        if (masterPtr->fgUid != NULL) {
1167            XColor color;
1168            XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), masterPtr->fgUid,
1169                    &color);
1170            if (Tk_PostscriptColor(interp, psinfo, &color) != TCL_OK) {
1171                return TCL_ERROR;
1172            }
1173            if (width > 60000) {
1174                Tcl_ResetResult(interp);
1175                Tcl_AppendResult(interp, "can't generate Postscript",
1176                        " for bitmaps more than 60000 pixels wide",
1177                        (char *) NULL);
1178                return TCL_ERROR;
1179            }
1180            rowsAtOnce = 60000/width;
1181            if (rowsAtOnce < 1) {
1182                rowsAtOnce = 1;
1183            }
1184            sprintf(buffer, "%d %d translate\n", x, y);
1185            Tcl_AppendResult(interp, buffer, (char *) NULL);
1186            for (curRow = y+height-1; curRow >= y; curRow -= rowsAtOnce) {
1187                rowsThisTime = rowsAtOnce;
1188                if (rowsThisTime > (curRow + 1 - y)) {
1189                    rowsThisTime = curRow + 1 - y;
1190                }
1191                sprintf(buffer, "%d %d", width, rowsThisTime);
1192                Tcl_AppendResult(interp, buffer, " true matrix {\n<",
1193                        (char *) NULL);
1194                for (yy = curRow; yy >= (curRow - rowsThisTime + 1); yy--) {
1195                    sprintf(buffer, "row %d\n", yy);
1196                    Tcl_AppendResult(interp, buffer, (char *) NULL);
1197                }
1198                sprintf(buffer, "0 %.15g", (double) rowsThisTime);
1199                Tcl_AppendResult(interp, ">\n} imagemask\n", buffer,
1200                        " translate\n", (char *) NULL);
1201            }
1202        }
1203        return TCL_OK;
1204    }
1205    
1206    /* End of tkimgbmap.c */

Legend:
Removed from v.44  
changed lines
  Added in v.98

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25