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