OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkImgBmap.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.