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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [libgui/] [src/] [xpmlib.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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