home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Extensions / pixmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-01  |  37.0 KB  |  1,376 lines

  1. /* 
  2.  * tixImgXpm.c --
  3.  *
  4.  *    This file implements images of type "pixmap" for Tix.
  5.  *
  6.  * Copyright statement for tixImgXpm.c
  7.  *        Copyright 1996 Ioi Kim Lam
  8.  *
  9.  * The following terms apply only to this file and no other parts of the
  10.  * Tix library.
  11.  *
  12.  *  Permission is hereby granted, without written agreement and
  13.  *  without license or royalty fees, to use, copy, modify, and
  14.  *  distribute this file, for any purpose, provided that existing
  15.  *  copyright notices are retained in all copies and that this
  16.  *  notice is included verbatim in any distributions.
  17.  *
  18.  * DISCLAIMER OF ALL WARRANTIES
  19.  *
  20.  *  IN NO EVENT SHALL THE AUTHOR OF THIS SOFTWARE BE LIABLE TO ANY PARTY
  21.  *  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  22.  *  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  23.  *  IF THE AUTHOR OF THIS SOFTWARE HAS BEEN ADVISED OF THE POSSIBILITY OF
  24.  *  SUCH DAMAGE.
  25.  *
  26.  *  THE AUTHOR OF THIS SOFTWARE SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  27.  *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  28.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
  29.  *  PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE AUTHOR OF THIS
  30.  *  SOFTWARE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
  31.  *  ENHANCEMENTS, OR MODIFICATIONS.
  32.  *  ___________________________________________________________________
  33.  *
  34.  *
  35.  * This file is adapted from the Tk 4.0 source file tkImgBmap.c
  36.  * Original tkImgBmap.c copyright information
  37.  *   Copyright (c) 1994 The Regents of the University of California.
  38.  *   Copyright (c) 1994-1995 Sun Microsystems, Inc.
  39.  *
  40.  *   See the file "license.terms.tcltk" for information
  41.  *   on usage and redistribution of the original tkImgBmap.c file, and for 
  42.  *   a DISCLAIMER OF ALL WARRANTIES from the authors of tkImgBmap.c.
  43.  */
  44. #ifdef USE_TK
  45. #ifdef STk_CODE
  46. #  include <stk.h>
  47. #endif
  48.  
  49. #include "tkInt.h"
  50. #include "tkPort.h"
  51.  
  52. /*
  53.  * The following data structure represents the master for a pixmap
  54.  * image:
  55.  */
  56.  
  57. typedef struct PixmapMaster {
  58.     Tk_ImageMaster tkMaster;    /* Tk's token for image master.  NULL means
  59.                  * the image is being deleted. */
  60.     Tcl_Interp *interp;        /* Interpreter for application that is
  61.                  * using image. */
  62.     Tcl_Command imageCmd;    /* Token for image command (used to delete
  63.                  * it when the image goes away).  NULL means
  64.                  * the image command has already been
  65.                  * deleted. */
  66.     char *fileString;        /* Value of -file option (malloc'ed).
  67.                  * valid only if the -file option is specified
  68.                  */
  69.     char *dataString;        /* Value of -data option (malloc'ed).
  70.                  * valid only if the -data option is specified
  71.                  */
  72.                 /* First in list of all instances associated
  73.                  * with this master. */
  74.     Tk_Uid id;            /* ID's for XPM data already compiled
  75.                  * into the tixwish binary */
  76.     int size[2];        /* width and height */
  77.     int ncolors;        /* number of colors */
  78.     int cpp;            /* characters per pixel */
  79.     char ** data;        /* The data that defines this pixmap 
  80.                  * image (array of strings). It is
  81.                  * converted into an X Pixmap when this
  82.                  * image is instanciated
  83.                  */
  84.     int isDataAlloced;        /* False iff the data is got from
  85.                  * the -id switch */
  86.     struct PixmapInstance *instancePtr;
  87. } PixmapMaster;
  88.  
  89. /* Make this more portable */
  90.  
  91. typedef struct ColorStruct {
  92.     char c;            /* This is used if CPP is one */
  93.     char * cstring;        /* This is used if CPP is bigger than one */
  94.     XColor * colorPtr;
  95. } ColorStruct;
  96.  
  97. /*
  98.  * The following data structure represents all of the instances of an
  99.  * image that lie within a particular window:
  100.  *
  101.  * %% ToDo
  102.  * Currently one instance is created for each window that uses this pixmap.
  103.  * This is usually OK because pixmaps are usually not shared or only shared by
  104.  * a small number of windows. To improve resource allocation, we can
  105.  * create an instance for each (Display x Visual x Depth) combo. This will
  106.  * usually reduce the number of instances to one.
  107.  */
  108. typedef struct PixmapInstance {
  109.     int refCount;        /* Number of instances that share this
  110.                  * data structure. */
  111.     PixmapMaster *masterPtr;    /* Pointer to master for image. */
  112.     Tk_Window tkwin;        /* Window in which the instances will be
  113.                  * displayed. */
  114.     Pixmap pixmap;        /* The pixmap to display. */
  115.     Pixmap mask;        /* Mask: only display pixmap pixels where
  116.                  * there are 1's here. */
  117.     GC gc;            /* Graphics context for displaying pixmap.
  118.                  * None means there was an error while
  119.                  * setting up the instance, so it cannot
  120.                  * be displayed. */
  121.     struct PixmapInstance *nextPtr;
  122.                 /* Next in list of all instance structures
  123.                  * associated with masterPtr (NULL means
  124.                  * end of list).
  125.                  */
  126.     ColorStruct * colors;
  127. } PixmapInstance;
  128.  
  129. /*
  130.  * The type record for pixmap images:
  131.  */
  132.  
  133. static int        ImgXpmCreate _ANSI_ARGS_((Tcl_Interp *interp,
  134.                 char *name, int argc, char **argv,
  135.                 Tk_ImageType *typePtr, Tk_ImageMaster master,
  136.                 ClientData *clientDataPtr));
  137. static ClientData    ImgXpmGet _ANSI_ARGS_((Tk_Window tkwin,
  138.                 ClientData clientData));
  139. static void        ImgXpmDisplay _ANSI_ARGS_((ClientData clientData,
  140.                 Display *display, Drawable drawable, 
  141.                 int imageX, int imageY, int width, int height,
  142.                 int drawableX, int drawableY));
  143. static void        ImgXpmFree _ANSI_ARGS_((ClientData clientData,
  144.                 Display *display));
  145. static void        ImgXpmDelete _ANSI_ARGS_((ClientData clientData));
  146.  
  147. Tk_ImageType tixPixmapImageType = {
  148.     "pixmap",            /* name */
  149.     ImgXpmCreate,        /* createProc */
  150.     ImgXpmGet,            /* getProc */
  151.     ImgXpmDisplay,        /* displayProc */
  152.     ImgXpmFree,            /* freeProc */
  153.     ImgXpmDelete,        /* deleteProc */
  154.     (Tk_ImageType *) NULL    /* nextPtr */
  155. };
  156.  
  157. /*
  158.  * Information used for parsing configuration specs:
  159.  */
  160.  
  161. static Tk_ConfigSpec configSpecs[] = {
  162.     {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
  163.     (char *) NULL, Tk_Offset(PixmapMaster, dataString), TK_CONFIG_NULL_OK},
  164.     {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
  165.     (char *) NULL, Tk_Offset(PixmapMaster, fileString), TK_CONFIG_NULL_OK},
  166.     {TK_CONFIG_UID, "-id", (char *) NULL, (char *) NULL,
  167.     (char *) NULL, Tk_Offset(PixmapMaster, id), TK_CONFIG_NULL_OK},
  168.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  169.     (char *) NULL, 0, 0}
  170. };
  171.  
  172. /*
  173.  * Prototypes for procedures used only locally in this file:
  174.  */
  175. static int        ImgXpmCmd _ANSI_ARGS_((ClientData clientData,
  176.                 Tcl_Interp *interp, int argc, char **argv));
  177. static void        ImgXpmCmdDeletedProc _ANSI_ARGS_((
  178.                 ClientData clientData));
  179. static void        ImgXpmConfigureInstance _ANSI_ARGS_((
  180.                 PixmapInstance *instancePtr));
  181. static int        ImgXpmConfigureMaster _ANSI_ARGS_((
  182.                 PixmapMaster *masterPtr, int argc, char **argv,
  183.                 int flags));
  184. static int        ImgXpmGetData _ANSI_ARGS_((Tcl_Interp *interp,
  185.                 PixmapMaster *masterPtr));
  186. static char **         ImgXpmGetDataFromFile _ANSI_ARGS_((Tcl_Interp * interp,
  187.                 char * string, int * numLines_return));
  188. static char **         ImgXpmGetDataFromId _ANSI_ARGS_((Tcl_Interp * interp,
  189.                 char * id));
  190. static char **         ImgXpmGetDataFromString _ANSI_ARGS_((Tcl_Interp*interp,
  191.                 char * string, int * numLines_return));
  192. static int         ImgXpmGetPixmapFromData _ANSI_ARGS_((
  193.                 Tcl_Interp * interp,
  194.                 PixmapMaster *masterPtr,
  195.                 PixmapInstance *instancePtr));
  196.  
  197. /* Local data, used only in this file */
  198. static Tcl_HashTable xpmTable;
  199. static int xpmTableInited = 0;
  200.  
  201.  
  202. /*
  203.  *----------------------------------------------------------------------
  204.  *
  205.  * ImgXpmCreate --
  206.  *
  207.  *    This procedure is called by the Tk image code to create "pixmap"
  208.  *    images.
  209.  *
  210.  * Results:
  211.  *    A standard Tcl result.
  212.  *
  213.  * Side effects:
  214.  *    The data structure for a new image is allocated.
  215.  *
  216.  *----------------------------------------------------------------------
  217.  */
  218. static int
  219. ImgXpmCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
  220.     Tcl_Interp *interp;        /* Interpreter for application containing
  221.                  * image. */
  222.     char *name;            /* Name to use for image. */
  223.     int argc;            /* Number of arguments. */
  224.     char **argv;        /* Argument strings for options (doesn't
  225.                  * include image name or type). */
  226.     Tk_ImageType *typePtr;    /* Pointer to our type record (not used). */
  227.     Tk_ImageMaster master;    /* Token for image, to be used by us in
  228.                  * later callbacks. */
  229.     ClientData *clientDataPtr;    /* Store manager's token for image here;
  230.                  * it will be returned in later callbacks. */
  231. {
  232.     PixmapMaster *masterPtr;
  233.  
  234.     masterPtr = (PixmapMaster *) ckalloc(sizeof(PixmapMaster));
  235.     masterPtr->tkMaster = master;
  236.     masterPtr->interp = interp;
  237.     masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgXpmCmd,
  238.         (ClientData) masterPtr, ImgXpmCmdDeletedProc);
  239.  
  240.     masterPtr->fileString = NULL;
  241.     masterPtr->dataString = NULL;
  242.     masterPtr->id = NULL;
  243.     masterPtr->data = NULL;
  244.     masterPtr->isDataAlloced = 0;
  245.     masterPtr->instancePtr = NULL;
  246.  
  247.     if (ImgXpmConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
  248.     ImgXpmDelete((ClientData) masterPtr);
  249.     return TCL_ERROR;
  250.     }
  251.     *clientDataPtr = (ClientData) masterPtr;
  252.     return TCL_OK;
  253. }
  254.  
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * ImgXpmConfigureMaster --
  259.  *
  260.  *    This procedure is called when a pixmap image is created or
  261.  *    reconfigured.  It process configuration options and resets
  262.  *    any instances of the image.
  263.  *
  264.  * Results:
  265.  *    A standard Tcl return value.  If TCL_ERROR is returned then
  266.  *    an error message is left in masterPtr->interp->result.
  267.  *
  268.  * Side effects:
  269.  *    Existing instances of the image will be redisplayed to match
  270.  *    the new configuration options.
  271.  *
  272.  *    If any error occurs, the state of *masterPtr is restored to
  273.  *    previous state.
  274.  *
  275.  *----------------------------------------------------------------------
  276.  */
  277. static int
  278. ImgXpmConfigureMaster(masterPtr, argc, argv, flags)
  279.     PixmapMaster *masterPtr;    /* Pointer to data structure describing
  280.                  * overall pixmap image to (reconfigure). */
  281.     int argc;            /* Number of entries in argv. */
  282.     char **argv;        /* Pairs of configuration options for image. */
  283.     int flags;            /* Flags to pass to Tk_ConfigureWidget,
  284.                  * such as TK_CONFIG_ARGV_ONLY. */
  285. {
  286.     PixmapInstance *instancePtr;
  287.     char * oldData, * oldFile;
  288.     Tk_Uid oldId;
  289.  
  290.     oldData = masterPtr->dataString;
  291.     oldFile = masterPtr->fileString;
  292.     oldId   = masterPtr->id;
  293.  
  294.     if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
  295.         configSpecs, argc, argv, (char *) masterPtr, flags)
  296.         != TCL_OK) {
  297.     return TCL_ERROR;
  298.     }
  299.  
  300.     if (masterPtr->id != NULL ||
  301.     masterPtr->dataString != NULL ||
  302.     masterPtr->fileString != NULL) {
  303.     if (ImgXpmGetData(masterPtr->interp, masterPtr) != TCL_OK) {
  304.         goto error;
  305.     }
  306.     } else {
  307.     Tcl_AppendResult(masterPtr->interp,
  308.         "must specify one of -data, -file or -id", NULL);
  309.     goto error;
  310.     }
  311.  
  312.     /*
  313.      * Cycle through all of the instances of this image, regenerating
  314.      * the information for each instance.  Then force the image to be
  315.      * redisplayed everywhere that it is used.
  316.      */
  317.     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
  318.     instancePtr = instancePtr->nextPtr) {
  319.     ImgXpmConfigureInstance(instancePtr);
  320.     }
  321.  
  322.     if (masterPtr->data) {
  323.     Tk_ImageChanged(masterPtr->tkMaster, 0, 0,
  324.         masterPtr->size[0], masterPtr->size[1],
  325.         masterPtr->size[0], masterPtr->size[1]);
  326.     } else {
  327.     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, 0, 0);
  328.     }
  329.  
  330.   done:
  331.     return TCL_OK;
  332.  
  333.   error:
  334.     /* Restore it to the original (possible valid) mode */
  335.     masterPtr->dataString = oldData;
  336.     masterPtr->fileString = oldFile;
  337.     masterPtr->id = oldId;
  338.     return TCL_ERROR;
  339. }
  340.  
  341. /*
  342.  *----------------------------------------------------------------------
  343.  *
  344.  * ImgXpmGetData --
  345.  *
  346.  *    Given a file name or ASCII string, this procedure parses the
  347.  *    file or string contents to produce binary data for a pixmap.
  348.  *
  349.  * Results:
  350.  *    If the pixmap description was parsed successfully then the data
  351.  *    is read into an array of strings. This array will later be used
  352.  *    to create X Pixmaps for each instance.
  353.  *
  354.  * Side effects:
  355.  *    The masterPtr->data array is allocated when successful. Contents of
  356.  *    *masterPtr is changed only when successful.
  357.  *----------------------------------------------------------------------
  358.  */
  359. static int
  360. ImgXpmGetData(interp, masterPtr)
  361.     Tcl_Interp *interp;            /* For reporting errors. */
  362.     PixmapMaster *masterPtr;
  363. {
  364.     char ** data;
  365.     int  isAllocated;            /* do we need to free "data"? */
  366.     int listArgc;
  367.     char ** listArgv = NULL;
  368.     int numLines;
  369.     int size[2];
  370.     int cpp;
  371.     int ncolors;
  372.  
  373.     if (masterPtr->id != NULL) {
  374.     data = ImgXpmGetDataFromId(interp, masterPtr->id);
  375.     isAllocated = 0;
  376.     }
  377.     else if (masterPtr->fileString != NULL) {
  378.     data = ImgXpmGetDataFromFile(interp, masterPtr->fileString, &numLines);
  379.     isAllocated = 1;
  380.     }
  381.     else if (masterPtr->dataString != NULL) {
  382.     data = ImgXpmGetDataFromString(interp,masterPtr->dataString,&numLines);
  383.     isAllocated = 1;
  384.     }
  385.     else {
  386.     /* Should have been enforced by ImgXpmConfigureMaster() */
  387.     panic("ImgXpmGetData(): -data, -file and -id are all NULL");
  388.     }
  389.  
  390.     if (data == NULL) {
  391.     return TCL_ERROR;
  392.     }
  393.  
  394.     /* Parse the first line of the data and get info about this pixmap */
  395.     if (Tcl_SplitList(interp, data[0], &listArgc, &listArgv) != TCL_OK) {
  396.     goto error;
  397.     }
  398.  
  399.     if (listArgc < 4) {
  400.     Tcl_AppendResult(interp, "File format error", NULL);
  401.     goto error;
  402.     }
  403.  
  404.     if (Tcl_GetInt(interp, listArgv[0], &size[0]) != TCL_OK) {
  405.     goto error;
  406.     }
  407.     if (Tcl_GetInt(interp, listArgv[1], &size[1]) != TCL_OK) {
  408.     goto error;
  409.     }
  410.     if (Tcl_GetInt(interp, listArgv[2], &ncolors) != TCL_OK) {
  411.     goto error;
  412.     }
  413.     if (Tcl_GetInt(interp, listArgv[3], &cpp) != TCL_OK) {
  414.     goto error;
  415.     }
  416.  
  417.     if (isAllocated) {
  418.     if (numLines != size[1] + ncolors + 1) {
  419.         /* the number of lines read from the file/data
  420.          * is not the same as specified in the data
  421.          */
  422.         goto error;
  423.     }
  424.     }
  425.  
  426.   done:
  427.     if (masterPtr->isDataAlloced && masterPtr->data) {
  428.     ckfree((char*)masterPtr->data);
  429.     }
  430.     masterPtr->isDataAlloced = isAllocated;
  431.     masterPtr->data = data;
  432.     masterPtr->size[0] = size[0];
  433.     masterPtr->size[1] = size[1];
  434.     masterPtr->cpp = cpp;
  435.     masterPtr->ncolors = ncolors;
  436.     
  437.     return TCL_OK;
  438.  
  439.   error:
  440.     Tcl_ResetResult(interp);
  441.     Tcl_AppendResult(interp, "File format error", NULL);
  442.  
  443.     if (isAllocated && data) {
  444.     ckfree((char*)data);
  445.     }
  446.     if (listArgv) {
  447.     ckfree((char*)listArgv);
  448.     }
  449.            
  450.     return TCL_ERROR;
  451. }
  452.  
  453. static char ** ImgXpmGetDataFromId(interp, id)
  454.     Tcl_Interp * interp;
  455.     char * id;
  456. {
  457.     Tcl_HashEntry * hashPtr;
  458.  
  459.     if (xpmTableInited == 0) {
  460.     hashPtr = NULL;
  461.     } else {
  462.     hashPtr = Tcl_FindHashEntry(&xpmTable, id);
  463.     }
  464.  
  465.     if (hashPtr == NULL) {
  466.     Tcl_AppendResult(interp, "unknown pixmap ID \"", id,
  467.         "\"", NULL);
  468.     return (char**)NULL;
  469.     } else {
  470.     return (char**)Tcl_GetHashValue(hashPtr);
  471.     }
  472. }
  473.  
  474. static char ** ImgXpmGetDataFromString(interp, string, numLines_return)
  475.     Tcl_Interp * interp;
  476.     char * string;
  477.     int * numLines_return;
  478. {
  479.     int skipped;
  480.     int quoated;
  481.     char * p, * list;
  482.     int numLines;
  483.     char ** data;
  484.  
  485.     /* skip the leading blanks (leading blanks are not defined in the
  486.      * the XPM definition, but skipping them shouldn't hurt. Also, the ability
  487.      * to skip the leading blanks is good for using in-line XPM data in TCL
  488.      * scripts
  489.      */
  490.     while (isspace(*string)) {
  491.     ++ string;
  492.     }
  493.  
  494.     /* parse the header */
  495.     if (strncmp("/* XPM ", string, 7) != 0) {
  496.     goto error;
  497.     }
  498.     /* skip the first two lines */
  499.     for (skipped=0,p=string;;) {
  500.     while (*p && *p != '\n') {
  501.         ++ p;
  502.     }
  503.     if (*p) {
  504.         ++ p;
  505.         ++ skipped;
  506.     } else {
  507.         goto error;
  508.     }
  509.     if (skipped == 2) {
  510.         break;
  511.     }
  512.     }
  513.  
  514.     /* Change the buffer in to a proper TCL list */
  515.     quoated = 0;
  516.     list = p;
  517.     while (*p) {
  518.     if (quoated) {
  519.         if (*p == '"') {
  520.         quoated = 1;
  521.         }
  522.         ++ p;
  523.     }
  524.     else {
  525.         if (*p == '/' && *(p+1) == '*') {
  526.         /*
  527.          * Skip comments
  528.          */
  529.         *p++ = ' ';
  530.         *p++ = ' ';
  531.         while (1) {
  532.             if (*p == 0) {
  533.             break;
  534.             }
  535.             if (*p == '*' && *(p+1) == '/') {
  536.             *p++ = ' ';
  537.             *p++ = ' ';
  538.             break;
  539.             }
  540.             *p++ = ' ';
  541.         }
  542.         }
  543.  
  544.         if (*p == '"') {
  545.         quoated = 0;
  546.         ++ p;
  547.         continue;
  548.         }
  549.         if (*p == '\r') {
  550.         *p = ' ';
  551.         }
  552.         else if (*p == '\n') {
  553.         *p = ' ';
  554.         }
  555.         else if (*p == ',') {
  556.         *p = ' ';
  557.         }
  558.         else if (*p == '}') {
  559.         *p = 0;
  560.         break;
  561.         }
  562.         ++p;
  563.     }
  564.     }
  565.  
  566.     /* The following code depends on the fact that Tcl_SplitList
  567.      * strips away double quoates inside a list: ie:
  568.      * if string == "\"1\" \"2\"" then
  569.      *        list[0] = "1"
  570.      *        list[1] = "2"
  571.      * and NOT
  572.      *
  573.      *        list[0] = "\"1\""
  574.      *        list[1] = "\"2\""
  575.      */
  576.     if (Tcl_SplitList(interp, list, &numLines, &data) != TCL_OK) {
  577.     goto error;
  578.     } else {
  579.     if (numLines == 0) {
  580.         /* error: empty data? */
  581.         if (data != NULL) {
  582.         ckfree((char*)data);
  583.         goto error;
  584.         }
  585.     }
  586.     * numLines_return = numLines;
  587.     return data;
  588.     }
  589.  
  590.   error:
  591.     Tcl_AppendResult(interp, "File format error", NULL);
  592.     return (char**) NULL;
  593. }
  594.  
  595. static char ** ImgXpmGetDataFromFile(interp, fileName, numLines_return)
  596.     Tcl_Interp * interp;
  597.     char * fileName;
  598.     int * numLines_return;
  599. {
  600.     int fileId, size;
  601.     char ** data;
  602.     struct stat statBuf;
  603.     char *cmdBuffer = NULL;
  604.     Tcl_DString buffer;            /* initialized by Tcl_TildeSubst */
  605.  
  606.     fileName = Tcl_TildeSubst(interp, fileName, &buffer);
  607.     if (fileName == NULL) {
  608.     goto error;
  609.     }
  610.  
  611.     fileId = open(fileName, O_RDONLY, 0);
  612.     if (fileId < 0) {
  613.     Tcl_AppendResult(interp, "couldn't read file \"", fileName,
  614.         "\": ", Tcl_PosixError(interp), (char *) NULL);
  615.     goto error;
  616.     }
  617.     if (fstat(fileId, &statBuf) == -1) {
  618.     Tcl_AppendResult(interp, "couldn't stat file \"", fileName,
  619.         "\": ", Tcl_PosixError(interp), (char *) NULL);
  620.     close(fileId);
  621.     goto error;
  622.     }
  623.     cmdBuffer = (char *) ckalloc((unsigned) statBuf.st_size+1);
  624.     size = read(fileId, cmdBuffer, (size_t) statBuf.st_size);
  625.     if (size < 0) {
  626.     Tcl_AppendResult(interp, "error in reading file \"", fileName,
  627.         "\": ", Tcl_PosixError(interp), (char *) NULL);
  628.     close(fileId);
  629.     goto error;
  630.     }
  631.     if (close(fileId) != 0) {
  632.     Tcl_AppendResult(interp, "error closing file \"", fileName,
  633.         "\": ", Tcl_PosixError(interp), (char *) NULL);
  634.     goto error;
  635.     }
  636.     cmdBuffer[size] = 0;
  637.  
  638.   done:
  639.     data = ImgXpmGetDataFromString(interp, cmdBuffer, numLines_return);
  640.     ckfree(cmdBuffer);
  641.     Tcl_DStringFree(&buffer);
  642.     return data;
  643.  
  644.   error:
  645.     if (cmdBuffer != NULL) {
  646.     ckfree(cmdBuffer);
  647.     }
  648.     Tcl_DStringFree(&buffer);
  649.     return (char**)NULL;
  650. }
  651.  
  652. /*----------------------------------------------------------------------
  653.  * ImgXpmGetPixmapFromData --
  654.  *
  655.  *    Creates a pixmap for an image instance.
  656.  *----------------------------------------------------------------------
  657.  */
  658. static int ImgXpmGetPixmapFromData(interp, masterPtr, instancePtr)
  659.     Tcl_Interp * interp;
  660.     PixmapMaster *masterPtr;
  661.     PixmapInstance *instancePtr;
  662. {
  663.     XImage * image = NULL, * mask = NULL;
  664.     int pad, depth, i, j, k, n, lOffset, isTransp = 0, isMono;
  665.     int listArgc;
  666.     char ** listArgv;
  667.     ColorStruct * colors;
  668.     GC gc;
  669.     Display *display = Tk_Display(instancePtr->tkwin);
  670.  
  671.     depth = Tk_Depth(instancePtr->tkwin);
  672.     if (depth > 16) {
  673.     pad = 32;
  674.     }
  675.     else if (depth > 8) {
  676.     pad = 16;
  677.     }
  678.     else {
  679.     pad = 8;
  680.     }
  681.  
  682.     switch ((Tk_Visual(instancePtr->tkwin))->class) {
  683.       case StaticGray:
  684.       case GrayScale:
  685.     isMono = 1;
  686.     break;
  687.       default:
  688.     isMono = 0;
  689.     }
  690.  
  691.     /*
  692.      * Create the XImage structures to store the temporary image
  693.      */
  694.     image = XCreateImage(display,
  695.     Tk_Visual(instancePtr->tkwin),
  696.     depth, ZPixmap, 0, 0,
  697.     masterPtr->size[0], masterPtr->size[1], pad, 0);
  698.     image->data =
  699.       (char *)ckalloc(image->bytes_per_line * masterPtr->size[1]);
  700.  
  701.     mask  = XCreateImage(display,
  702.     Tk_Visual(instancePtr->tkwin),
  703.     1, ZPixmap, 0, 0,
  704.     masterPtr->size[0], masterPtr->size[1], pad, 0);
  705.     mask->data =
  706.       (char *)ckalloc(mask->bytes_per_line  * masterPtr->size[1]);
  707.  
  708.     /*
  709.      * Parse the colors
  710.      */
  711.     lOffset = 1;
  712.     colors = (ColorStruct*)ckalloc(sizeof(ColorStruct)*masterPtr->ncolors);
  713.     listArgv = 0;
  714.  
  715.     /* Initialize the color structures */
  716.     for (i=0; i<masterPtr->ncolors; i++) {
  717.     colors[i].colorPtr = NULL;
  718.     if (masterPtr->cpp == 1) {
  719.         colors[i].c = 0;
  720.     } else {
  721.         colors[i].cstring = (char*)ckalloc(masterPtr->cpp);
  722.         colors[i].cstring[0] = 0;
  723.     }
  724.     }
  725.  
  726.     for (i=0; i<masterPtr->ncolors; i++) {
  727.     char * colorName = NULL;
  728.  
  729.     if (Tcl_SplitList(interp,
  730.         masterPtr->data[i+lOffset]+masterPtr->cpp,
  731.         &listArgc, &listArgv) != TCL_OK) {
  732.         colors[i].colorPtr = NULL;
  733.         continue;
  734.     }
  735.     if (listArgc < 2) {
  736.         colors[i].colorPtr = NULL;
  737.         continue;
  738.     }
  739.     for (j=0; j<listArgc; j+=2) {
  740.         /* The symbolic color names are not implemented
  741.          */
  742.         if (listArgv[j][0] == 'm') {
  743.         if (isMono) {
  744.             if (depth == 1) {
  745.             colorName = listArgv[j+1];
  746.             break;
  747.             } else if (colorName == NULL) {    /* use as default */
  748.             colorName = listArgv[j+1];
  749.             continue;
  750.             }
  751.         }
  752.         }
  753.         else if (listArgv[j][0] == 'g' && listArgv[j][1] == '4') {
  754.         if (isMono) {
  755.             if (depth == 4) {
  756.             colorName = listArgv[j+1];
  757.             break;
  758.             } else if (colorName == NULL) {    /* use as default */
  759.             colorName = listArgv[j+1];
  760.             continue;
  761.             }
  762.         }
  763.         }
  764.         else if (listArgv[j][0] == 'g') {
  765.         if (isMono) {
  766.             if (depth > 4) {
  767.             colorName = listArgv[j+1];
  768.             break;
  769.             } else if (colorName == NULL) {    /* use as default */
  770.             colorName = listArgv[j+1];
  771.             continue;
  772.             }
  773.         }
  774.         }
  775.         else if (listArgv[j][0] == 'c') {
  776.         if (!isMono || colorName == NULL) {
  777.             colorName = listArgv[j+1];
  778.             break;
  779.         }
  780.         }
  781.     }
  782.     if (colorName == NULL) {
  783.         colorName = listArgv[1];
  784.     }
  785.  
  786.     if (masterPtr->cpp == 1) {
  787.         colors[i].c = masterPtr->data[i+lOffset][0];
  788.     } else {
  789.         strncpy(colors[i].cstring, masterPtr->data[i+lOffset],
  790.         (size_t)masterPtr->cpp);
  791.     } 
  792.  
  793.     if (strcasecmp(listArgv[j+1], "none") != 0) {
  794.         colors[i].colorPtr = Tk_GetColor(interp,
  795.         instancePtr->tkwin, Tk_GetUid(colorName));
  796.         if (colors[i].colorPtr == NULL) {
  797.         colors[i].colorPtr = Tk_GetColor(interp,
  798.         instancePtr->tkwin, Tk_GetUid("black"));
  799.         }
  800.     }
  801.     ckfree((char*)listArgv);
  802.     listArgv = 0;
  803.     }
  804.  
  805.     lOffset += masterPtr->ncolors;
  806.  
  807.     /*
  808.      * Parse the main body of the image
  809.      */
  810.     for (i=0; i<masterPtr->size[1]; i++) {
  811.     char * p = masterPtr->data[i+lOffset];
  812.  
  813.     for (j=0; j<masterPtr->size[0]; j++) {
  814.         if (masterPtr->cpp == 1) {
  815.         for (k=0; k<masterPtr->ncolors; k++) {
  816.             if (*p == colors[k].c) {
  817.             if (colors[k].colorPtr != NULL) {
  818.                 XPutPixel(image, j, i, colors[k].colorPtr->pixel);
  819.                 XPutPixel(mask,  j, i, 1);
  820.             } else {
  821.                 XPutPixel(mask,  j, i, 0);
  822.                 isTransp = 1;
  823.             }
  824.             break;
  825.             }
  826.         }
  827.         if (*p) {
  828.             p++;
  829.         }
  830.         } else {
  831.         for (k=0; k<masterPtr->ncolors; k++) {
  832.             if (strncmp(p, colors[k].cstring, 
  833.                 (size_t)masterPtr->cpp) == 0) {
  834.             if (colors[k].colorPtr != NULL) {
  835.                 XPutPixel(image, j, i, colors[k].colorPtr->pixel);
  836.                 XPutPixel(mask,  j, i, 1);
  837.             } else {
  838.                 XPutPixel(mask,  j, i, 0);
  839.                 isTransp = 1;
  840.             }
  841.             break;
  842.             }
  843.         }
  844.         for (k=0; *p && k<masterPtr->cpp; k++) {
  845.             p++;
  846.         }
  847.         }
  848.     }
  849.     }
  850.  
  851.     /*
  852.      * Create the pixmap(s) from the XImage structure. The mask is created
  853.      * only if needed (i.e., there is at least one transparent pixel)
  854.      */
  855.     instancePtr->colors = colors;
  856.  
  857.     /* main image */
  858.     instancePtr->pixmap = Tk_GetPixmap(display,
  859.     Tk_WindowId(instancePtr->tkwin),
  860.     masterPtr->size[0], masterPtr->size[1], depth);
  861.  
  862.     gc = Tk_GetGC(instancePtr->tkwin, 0, NULL);
  863.     XPutImage(display, instancePtr->pixmap,
  864.     gc, image, 0, 0, 0, 0, masterPtr->size[0], masterPtr->size[1]);
  865.     Tk_FreeGC(display, gc);
  866.  
  867.     /* mask, if necessary */
  868.     if (isTransp) {
  869.     instancePtr->mask = Tk_GetPixmap(display,
  870.         Tk_WindowId(instancePtr->tkwin),
  871.         masterPtr->size[0], masterPtr->size[1], 1);
  872.     gc = XCreateGC(display, instancePtr->mask, 0, NULL);
  873.     XPutImage(display, instancePtr->mask,
  874.         gc, mask,  0, 0, 0, 0, masterPtr->size[0], masterPtr->size[1]);
  875.     XFreeGC(display, gc);
  876.     } else {
  877.     instancePtr->mask = None;
  878.     }
  879.  
  880.     /* Done */
  881.     if (image) {
  882.     ckfree((char*)image->data);
  883.     image->data = NULL;
  884.     XDestroyImage(image);
  885.     }
  886.     if (mask) {
  887.     ckfree((char*)mask->data);
  888.     mask->data = NULL;
  889.     XDestroyImage(mask);
  890.     }
  891.  
  892.     if (listArgv) {
  893.     ckfree((char*)listArgv);
  894.     }
  895. }
  896.  
  897. /*
  898.  *----------------------------------------------------------------------
  899.  *
  900.  * ImgXpmConfigureInstance --
  901.  *
  902.  *    This procedure is called to create displaying information for
  903.  *    a pixmap image instance based on the configuration information
  904.  *    in the master.  It is invoked both when new instances are
  905.  *    created and when the master is reconfigured.
  906.  *
  907.  * Results:
  908.  *    None.
  909.  *
  910.  * Side effects:
  911.  *    Generates errors via Tk_BackgroundError if there are problems
  912.  *    in setting up the instance.
  913.  *
  914.  *----------------------------------------------------------------------
  915.  */
  916. static void
  917. ImgXpmConfigureInstance(instancePtr)
  918.     PixmapInstance *instancePtr;    /* Instance to reconfigure. */
  919. {
  920.     PixmapMaster *masterPtr = instancePtr->masterPtr;
  921.     int xpmCode;
  922.     XGCValues gcValues;
  923.     GC gc;
  924.     unsigned int gcMask;
  925.  
  926.     if (instancePtr->pixmap != None) {
  927.     XFreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->pixmap);
  928.     }
  929.     if (instancePtr->mask != None) {
  930.     XFreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->mask);
  931.     }
  932.  
  933.     if (instancePtr->colors != NULL) {
  934.     int i;
  935.     for (i=0; i<masterPtr->ncolors; i++) {
  936.         if (instancePtr->colors[i].colorPtr != NULL) {
  937.         Tk_FreeColor(instancePtr->colors[i].colorPtr);
  938.         }
  939.         if (masterPtr->cpp != 1) {
  940.         ckfree(instancePtr->colors[i].cstring);
  941.         }
  942.     }
  943.     ckfree((char*)instancePtr->colors);
  944.     }
  945.  
  946.     if (Tk_WindowId(instancePtr->tkwin) == None) {
  947.     Tk_MakeWindowExist(instancePtr->tkwin);
  948.     }
  949.  
  950.     /* Assumption: masterPtr->data is always non NULL (enfored by
  951.      * ImgXpmConfigureMaster()). Also, the data must be in a valid
  952.      * format (partially enforced by ImgXpmConfigureMaster(), see comments
  953.      * inside that function).
  954.      */
  955.     ImgXpmGetPixmapFromData(masterPtr->interp, masterPtr, instancePtr);
  956.  
  957.     /* Allocate a GC for drawing this instance (mask is not used if there
  958.      * is no transparent pixels inside the image).*/
  959.     if (instancePtr->mask != None) {
  960.     gcMask = GCGraphicsExposures|GCClipMask;
  961.     } else {
  962.     gcMask = GCGraphicsExposures;
  963.     }
  964.     gcValues.graphics_exposures = False;
  965.     gcValues.clip_mask = instancePtr->mask;
  966.     
  967.     gc = Tk_GetGC(instancePtr->tkwin, gcMask, &gcValues);
  968.  
  969.     if (instancePtr->gc != None) {
  970.     Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
  971.     }
  972.     instancePtr->gc = gc;
  973.     return;
  974. }
  975.  
  976. /*
  977.  *--------------------------------------------------------------
  978.  *
  979.  * ImgXpmCmd --
  980.  *
  981.  *    This procedure is invoked to process the Tcl command
  982.  *    that corresponds to an image managed by this module.
  983.  *    See the user documentation for details on what it does.
  984.  *
  985.  * Results:
  986.  *    A standard Tcl result.
  987.  *
  988.  * Side effects:
  989.  *    See the user documentation.
  990.  *
  991.  *--------------------------------------------------------------
  992.  */
  993.  
  994. static int
  995. ImgXpmCmd(clientData, interp, argc, argv)
  996.     ClientData clientData;    /* Information about button widget. */
  997.     Tcl_Interp *interp;        /* Current interpreter. */
  998.     int argc;            /* Number of arguments. */
  999.     char **argv;        /* Argument strings. */
  1000. {
  1001.     PixmapMaster *masterPtr = (PixmapMaster *) clientData;
  1002.     int c, code;
  1003.     size_t length;
  1004.  
  1005.     if (argc < 2) {
  1006.     sprintf(interp->result,
  1007.         "wrong # args: should be \"%.50s option ?arg arg ...?\"",
  1008.         argv[0]);
  1009.     return TCL_ERROR;
  1010.     }
  1011.     c = argv[1][0];
  1012.     length = strlen(argv[1]);
  1013.     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  1014.         && (length >= 2)) {
  1015.     if (argc != 3) {
  1016.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  1017.             argv[0], " cget option\"",
  1018.             (char *) NULL);
  1019.         return TCL_ERROR;
  1020.     }
  1021.     return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
  1022.         (char *) masterPtr, argv[2], 0);
  1023.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  1024.         && (length >= 2)) {
  1025.     if (argc == 2) {
  1026.         code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
  1027.             configSpecs, (char *) masterPtr, (char *) NULL, 0);
  1028.     } else if (argc == 3) {
  1029.         code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
  1030.             configSpecs, (char *) masterPtr, argv[2], 0);
  1031.     } else {
  1032.         code = ImgXpmConfigureMaster(masterPtr, argc-2, argv+2,
  1033.             TK_CONFIG_ARGV_ONLY);
  1034.     }
  1035.     return code;
  1036.     }
  1037.  
  1038.   error:
  1039.  
  1040.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  1041.     "\": must be cget or configure", (char *) NULL);
  1042.     return TCL_ERROR;
  1043. }
  1044.  
  1045. /*
  1046.  *----------------------------------------------------------------------
  1047.  *
  1048.  * ImgXpmGet --
  1049.  *
  1050.  *    This procedure is called for each use of a pixmap image in a
  1051.  *    widget.
  1052.  *
  1053.  * Results:
  1054.  *    The return value is a token for the instance, which is passed
  1055.  *    back to us in calls to ImgXpmDisplay and ImgXpmFre.
  1056.  *
  1057.  * Side effects:
  1058.  *    A data structure is set up for the instance (or, an existing
  1059.  *    instance is re-used for the new one).
  1060.  *
  1061.  *----------------------------------------------------------------------
  1062.  */
  1063.  
  1064. static ClientData
  1065. ImgXpmGet(tkwin, masterData)
  1066.     Tk_Window tkwin;        /* Window in which the instance will be
  1067.                  * used. */
  1068.     ClientData masterData;    /* Pointer to our master structure for the
  1069.                  * image. */
  1070. {
  1071.     PixmapMaster *masterPtr = (PixmapMaster *) masterData;
  1072.     PixmapInstance *instancePtr;
  1073.  
  1074.     /*
  1075.      * See if there is already an instance for this window.  If so
  1076.      * then just re-use it.
  1077.      */
  1078.  
  1079.     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
  1080.         instancePtr = instancePtr->nextPtr) {
  1081.     if (instancePtr->tkwin == tkwin) {
  1082.         instancePtr->refCount++;
  1083.         return (ClientData) instancePtr;
  1084.     }
  1085.     }
  1086.  
  1087.     /*
  1088.      * The image isn't already in use in this window.  Make a new
  1089.      * instance of the image.
  1090.      */
  1091.     instancePtr = (PixmapInstance *) ckalloc(sizeof(PixmapInstance));
  1092.     instancePtr->refCount = 1;
  1093.     instancePtr->masterPtr = masterPtr;
  1094.     instancePtr->tkwin = tkwin;
  1095.     instancePtr->pixmap = None;
  1096.     instancePtr->mask = None;
  1097.     instancePtr->gc = None;
  1098.     instancePtr->nextPtr = masterPtr->instancePtr;
  1099.     instancePtr->colors = NULL;
  1100.     masterPtr->instancePtr = instancePtr;
  1101.     ImgXpmConfigureInstance(instancePtr);
  1102.  
  1103.     /*
  1104.      * If this is the first instance, must set the size of the image.
  1105.      */
  1106.     if (instancePtr->nextPtr == NULL) {
  1107.     if (masterPtr->data) {
  1108.         Tk_ImageChanged(masterPtr->tkMaster, 0, 0,
  1109.             masterPtr->size[0], masterPtr->size[1],
  1110.             masterPtr->size[0], masterPtr->size[1]);
  1111.     } else {
  1112.         Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, 0, 0);
  1113.     }
  1114.     }
  1115.  
  1116.     return (ClientData) instancePtr;
  1117. }
  1118.  
  1119. /*
  1120.  *----------------------------------------------------------------------
  1121.  *
  1122.  * ImgXpmDisplay --
  1123.  *
  1124.  *    This procedure is invoked to draw a pixmap image.
  1125.  *
  1126.  * Results:
  1127.  *    None.
  1128.  *
  1129.  * Side effects:
  1130.  *    A portion of the image gets rendered in a pixmap or window.
  1131.  *
  1132.  *----------------------------------------------------------------------
  1133.  */
  1134.  
  1135. static void
  1136. ImgXpmDisplay(clientData, display, drawable, imageX, imageY, width,
  1137.     height, drawableX, drawableY)
  1138.     ClientData clientData;    /* Pointer to PixmapInstance structure for
  1139.                  * for instance to be displayed. */
  1140.     Display *display;        /* Display on which to draw image. */
  1141.     Drawable drawable;        /* Pixmap or window in which to draw image. */
  1142.     int imageX, imageY;        /* Upper-left corner of region within image
  1143.                  * to draw. */
  1144.     int width, height;        /* Dimensions of region within image to draw.*/
  1145.     int drawableX, drawableY;    /* Coordinates within drawable that
  1146.                  * correspond to imageX and imageY. */
  1147. {
  1148.     PixmapInstance *instancePtr = (PixmapInstance *) clientData;
  1149.  
  1150.     /*
  1151.      * If there's no graphics context, it means that an error occurred
  1152.      * while creating the image instance so it can't be displayed.
  1153.      */
  1154.  
  1155.     if (instancePtr->gc == None) {
  1156.     return;
  1157.     }
  1158.  
  1159.     /*
  1160.      * We always use masking: modify the mask origin within
  1161.      * the graphics context to line up with the image's origin.
  1162.      * Then draw the image and reset the clip origin, if there's
  1163.      * a mask.
  1164.      */
  1165.  
  1166.     XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
  1167.     drawableY - imageY);
  1168.     XCopyArea(display, instancePtr->pixmap, drawable, instancePtr->gc,
  1169.     imageX, imageY, (unsigned) width, (unsigned) height,
  1170.     drawableX, drawableY);
  1171.     XSetClipOrigin(display, instancePtr->gc, 0, 0);
  1172. }
  1173.  
  1174. /*
  1175.  *----------------------------------------------------------------------
  1176.  *
  1177.  * ImgXpmFree --
  1178.  *
  1179.  *    This procedure is called when a widget ceases to use a
  1180.  *    particular instance of an image.
  1181.  *
  1182.  * Results:
  1183.  *    None.
  1184.  *
  1185.  * Side effects:
  1186.  *    Internal data structures get cleaned up.
  1187.  *
  1188.  *----------------------------------------------------------------------
  1189.  */
  1190.  
  1191. static void
  1192. ImgXpmFree(clientData, display)
  1193.     ClientData clientData;    /* Pointer to PixmapInstance structure for
  1194.                  * for instance to be displayed. */
  1195.     Display *display;        /* Display containing window that used image.*/
  1196. {
  1197.     PixmapInstance *instancePtr = (PixmapInstance *) clientData;
  1198.     PixmapInstance *prevPtr;
  1199.  
  1200.     instancePtr->refCount--;
  1201.     if (instancePtr->refCount > 0) {
  1202.     return;
  1203.     }
  1204.  
  1205.     /*
  1206.      * There are no more uses of the image within this widget.  Free
  1207.      * the instance structure.
  1208.      */
  1209.     if (instancePtr->pixmap != None) {
  1210.     XFreePixmap(display, instancePtr->pixmap);
  1211.     }
  1212.     if (instancePtr->mask != None) {
  1213.     XFreePixmap(display, instancePtr->mask);
  1214.     }
  1215.     if (instancePtr->gc != None) {
  1216.     Tk_FreeGC(display, instancePtr->gc);
  1217.     }
  1218.     if (instancePtr->colors != NULL) {
  1219.     int i;
  1220.     for (i=0; i<instancePtr->masterPtr->ncolors; i++) {
  1221.         if (instancePtr->colors[i].colorPtr != NULL) {
  1222.         Tk_FreeColor(instancePtr->colors[i].colorPtr);
  1223.         }
  1224.         if (instancePtr->masterPtr->cpp != 1) {
  1225.         ckfree(instancePtr->colors[i].cstring);
  1226.         }
  1227.     }
  1228.     ckfree((char*)instancePtr->colors);
  1229.     }
  1230.  
  1231.     if (instancePtr->masterPtr->instancePtr == instancePtr) {
  1232.     instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
  1233.     } else {
  1234.     for (prevPtr = instancePtr->masterPtr->instancePtr;
  1235.         prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
  1236.         /* Empty loop body */
  1237.     }
  1238.     prevPtr->nextPtr = instancePtr->nextPtr;
  1239.     }
  1240.     ckfree((char *) instancePtr);
  1241. }
  1242.  
  1243. /*
  1244.  *----------------------------------------------------------------------
  1245.  *
  1246.  * ImgXpmDelete --
  1247.  *
  1248.  *    This procedure is called by the image code to delete the
  1249.  *    master structure for an image.
  1250.  *
  1251.  * Results:
  1252.  *    None.
  1253.  *
  1254.  * Side effects:
  1255.  *    Resources associated with the image get freed.
  1256.  *
  1257.  *----------------------------------------------------------------------
  1258.  */
  1259.  
  1260. static void
  1261. ImgXpmDelete(masterData)
  1262.     ClientData masterData;    /* Pointer to PixmapMaster structure for
  1263.                  * image.  Must not have any more instances. */
  1264. {
  1265.     PixmapMaster *masterPtr = (PixmapMaster *) masterData;
  1266.  
  1267.     if (masterPtr->instancePtr != NULL) {
  1268.     panic("tried to delete pixmap image when instances still exist");
  1269.     }
  1270.     masterPtr->tkMaster = NULL;
  1271.     if (masterPtr->imageCmd != NULL) {
  1272.     Tcl_DeleteCommand(masterPtr->interp,
  1273.         Tcl_GetCommandName(masterPtr->interp, masterPtr->imageCmd));
  1274.     }
  1275.     if (masterPtr->isDataAlloced && masterPtr->data != NULL) {
  1276.     ckfree((char*)masterPtr->data);
  1277.     }
  1278.     Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
  1279.     ckfree((char *) masterPtr);
  1280. }
  1281.  
  1282. /*
  1283.  *----------------------------------------------------------------------
  1284.  *
  1285.  * ImgXpmCmdDeletedProc --
  1286.  *
  1287.  *    This procedure is invoked when the image command for an image
  1288.  *    is deleted.  It deletes the image.
  1289.  *
  1290.  * Results:
  1291.  *    None.
  1292.  *
  1293.  * Side effects:
  1294.  *    The image is deleted.
  1295.  *
  1296.  *----------------------------------------------------------------------
  1297.  */
  1298. static void
  1299. ImgXpmCmdDeletedProc(clientData)
  1300.     ClientData clientData;    /* Pointer to PixmapMaster structure for
  1301.                  * image. */
  1302. {
  1303.     PixmapMaster *masterPtr = (PixmapMaster *) clientData;
  1304.  
  1305.     masterPtr->imageCmd = NULL;
  1306.     if (masterPtr->tkMaster != NULL) {
  1307.     Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
  1308.     }
  1309. }
  1310.  
  1311.  
  1312. /*
  1313.  *----------------------------------------------------------------------
  1314.  *
  1315.  * Tix_DefinePixmap
  1316.  *
  1317.  *    Define an XPM data structure with an unique name, so that you can
  1318.  *    later refer to this pixmap using the -id switch in [image create
  1319.  *    pixmap].
  1320.  *
  1321.  * Results:
  1322.  *    None.
  1323.  *
  1324.  * Side effects:
  1325.  *    The data is stored in a HashTable.
  1326.  *----------------------------------------------------------------------
  1327.  */
  1328. int
  1329. Tix_DefinePixmap(interp, name, data)
  1330.     Tcl_Interp * interp;
  1331.     Tk_Uid name;        /* Name to use for bitmap.  Must not already
  1332.                  * be defined as a bitmap. */
  1333.     char **data;
  1334. {
  1335.     int new;
  1336.     Tcl_HashEntry *hshPtr;
  1337.  
  1338.     if (!xpmTableInited) {
  1339.     xpmTableInited = 1;
  1340.     Tcl_InitHashTable(&xpmTable, TCL_ONE_WORD_KEYS);
  1341.     }
  1342.  
  1343.     hshPtr = Tcl_CreateHashEntry(&xpmTable, name, &new);
  1344.     if (!new) {
  1345.         Tcl_AppendResult(interp, "pixmap \"", name,
  1346.         "\" is already defined", (char *) NULL);
  1347.     return TCL_ERROR;
  1348.     }
  1349.     Tcl_SetHashValue(hshPtr, (char*)data);
  1350.     return TCL_OK;
  1351. }
  1352.  
  1353. int
  1354. Xpm_Init(interp)
  1355.     Tcl_Interp *interp;        /* Interpreter in which the package is
  1356.                  * to be made available. */
  1357. {
  1358.     Tk_CreateImageType(&tixPixmapImageType);
  1359.     return TCL_OK;
  1360. }
  1361.  
  1362. #ifdef STk_CODE
  1363. PRIMITIVE STk_init_pixmap(void)
  1364. {
  1365.   extern Tcl_Interp *STk_main_interp;
  1366.  
  1367.   Xpm_Init(STk_main_interp);
  1368.   return UNDEFINED;
  1369. }
  1370. #endif
  1371.  
  1372. #else
  1373.   /* Some compilers hate to produce an empty object file. */
  1374.   static char dumb = '?';
  1375. #endif
  1376.