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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimgbmap.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25