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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (hide annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (7 years, 8 months ago) by dashley
Original Path: projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimgbmap.c
File MIME type: text/plain
File size: 36938 byte(s)
License and property (keyword) changes.
1 dashley 69 /* $Header$ */
2 dashley 25
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 dashley 69 /* End of tkimgbmap.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25