1
/*--------------------------------------------------------------*/
3
/* tkPixmap.c --- routines for implementing an "xpm" format */
4
/* pixmap image type in Tk. Lifted mostly from Tk's */
5
/* bitmap image format source "tkImgBmap.c" */
7
/*--------------------------------------------------------------*/
9
#if defined(TCL_WRAPPER) && defined(HAVE_XPM)
14
#include <X11/Intrinsic.h>
15
#include <X11/StringDefs.h>
22
* The following data structure represents the master for an XPM-format
26
typedef struct XPMMaster {
27
Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means
28
* the image is being deleted. */
29
Tcl_Interp *interp; /* Interpreter for application that is
31
Tcl_Command imageCmd; /* Token for image command (used to delete
32
* it when the image goes away). NULL means
33
* the image command has already been
35
XpmImage *imageData; /* Contains primary information about the image */
36
XpmInfo *imageInfo; /* Contains comment and extension information */
37
char *fileString; /* Value of -file option (malloc'ed). */
38
struct XPMInstance *instancePtr;
39
/* First in list of all instances associated
40
* with this master. */
44
* The following data structure represents all of the instances of an
45
* image that lie within a particular window:
48
typedef struct XPMInstance {
49
int refCount; /* Number of instances that share this
51
XPMMaster *masterPtr; /* Pointer to master for image. */
52
Tk_Window tkwin; /* Window in which the instances will be
54
Pixmap pixmap; /* The pixmap to display. */
55
Pixmap mask; /* The bitmap to use for the shapemask */
56
GC gc; /* Graphics context for displaying pixmap */
57
struct XPMInstance *nextPtr;
58
/* Next in list of all instance structures
59
* associated with masterPtr (NULL means
64
* The type record for bitmap images:
67
static int ImgXPMCreate _ANSI_ARGS_((Tcl_Interp *interp,
68
char *name, int argc, Tcl_Obj *CONST objv[],
69
Tk_ImageType *typePtr, Tk_ImageMaster master,
70
ClientData *clientDataPtr));
71
static ClientData ImgXPMGet _ANSI_ARGS_((Tk_Window tkwin,
72
ClientData clientData));
73
static void ImgXPMDisplay _ANSI_ARGS_((ClientData clientData,
74
Display *display, Drawable drawable,
75
int imageX, int imageY, int width, int height,
76
int drawableX, int drawableY));
77
static void ImgXPMFree _ANSI_ARGS_((ClientData clientData,
79
static void ImgXPMDelete _ANSI_ARGS_((ClientData clientData));
81
Tk_ImageType tkXPMImageType = {
83
ImgXPMCreate, /* createProc */
84
ImgXPMGet, /* getProc */
85
ImgXPMDisplay, /* displayProc */
86
ImgXPMFree, /* freeProc */
87
ImgXPMDelete, /* deleteProc */
88
NULL, /* postscriptProc */
89
(Tk_ImageType *) NULL /* nextPtr */
93
* Information used for parsing configuration specs:
94
* Size defaults to a 16x16 area.
97
static Tk_ConfigSpec configSpecs[] = {
98
{TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
99
(char *) NULL, Tk_Offset(XPMMaster, fileString), TK_CONFIG_NULL_OK},
100
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
105
* Prototypes for procedures used only locally in this file:
108
static int ImgXPMCmd _ANSI_ARGS_((ClientData clientData,
109
Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
110
static void ImgXPMCmdDeletedProc _ANSI_ARGS_((
111
ClientData clientData));
112
static void ImgXPMConfigureInstance _ANSI_ARGS_((
113
XPMInstance *instancePtr));
114
static int ImgXPMConfigureMaster _ANSI_ARGS_((
115
XPMMaster *masterPtr, int argc, Tcl_Obj *CONST objv[],
119
*----------------------------------------------------------------------
123
* This procedure is called by the Tk image code to create "test"
127
* A standard Tcl result.
130
* The data structure for a new image is allocated.
132
*----------------------------------------------------------------------
137
ImgXPMCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
138
Tcl_Interp *interp; /* Interpreter for application containing
140
char *name; /* Name to use for image. */
141
int argc; /* Number of arguments. */
142
Tcl_Obj *CONST argv[]; /* Argument objects for options (doesn't
143
* include image name or type). */
144
Tk_ImageType *typePtr; /* Pointer to our type record (not used). */
145
Tk_ImageMaster master; /* Token for image, to be used by us in
146
* later callbacks. */
147
ClientData *clientDataPtr; /* Store manager's token for image here;
148
* it will be returned in later callbacks. */
150
XPMMaster *masterPtr;
152
masterPtr = (XPMMaster *) ckalloc(sizeof(XPMMaster));
153
masterPtr->tkMaster = master;
154
masterPtr->interp = interp;
155
masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgXPMCmd,
156
(ClientData) masterPtr, ImgXPMCmdDeletedProc);
157
masterPtr->imageData = NULL;
158
masterPtr->imageInfo = NULL;
159
masterPtr->fileString = NULL;
160
masterPtr->instancePtr = NULL;
161
if (ImgXPMConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
162
ImgXPMDelete((ClientData) masterPtr);
165
*clientDataPtr = (ClientData) masterPtr;
170
*----------------------------------------------------------------------
172
* ImgXPMConfigureMaster --
174
* This procedure is called when a bitmap image is created or
175
* reconfigured. It process configuration options and resets
176
* any instances of the image.
179
* A standard Tcl return value. If TCL_ERROR is returned then
180
* an error message is left in the masterPtr->interp's result.
183
* Existing instances of the image will be redisplayed to match
184
* the new configuration options.
186
*----------------------------------------------------------------------
190
ImgXPMConfigureMaster(masterPtr, objc, objv, flags)
191
XPMMaster *masterPtr; /* Pointer to data structure describing
192
* overall pixmap image to (reconfigure). */
193
int objc; /* Number of entries in objv. */
194
Tcl_Obj *CONST objv[]; /* Pairs of configuration options for image. */
195
int flags; /* Flags to pass to Tk_ConfigureWidget,
196
* such as TK_CONFIG_ARGV_ONLY. */
198
XPMInstance *instancePtr;
199
int maskWidth, maskHeight, dummy1;
201
char **argv = (char **) Tcl_Alloc((objc+1) * sizeof(char *));
202
for (dummy1 = 0; dummy1 < objc; dummy1++) {
203
argv[dummy1]=Tcl_GetString(objv[dummy1]);
207
if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
208
configSpecs, objc, argv, (char *) masterPtr, flags)
210
Tcl_Free((char *) argv);
213
Tcl_Free((char *) argv);
216
* Parse the pixmap and/or mask to create binary data. Make sure that
217
* the pixmap and mask have the same dimensions.
220
if (masterPtr->imageData != NULL) {
221
XpmFreeXpmImage(masterPtr->imageData);
222
masterPtr->imageData = NULL;
224
if (masterPtr->imageInfo != NULL) {
225
XpmFreeXpmInfo(masterPtr->imageInfo);
226
masterPtr->imageInfo = NULL;
228
if (masterPtr->fileString != NULL) {
229
masterPtr->imageData = (XpmImage *)malloc(sizeof(XpmImage));
230
masterPtr->imageInfo = (XpmInfo *)malloc(sizeof(XpmInfo));
231
if (XpmReadFileToXpmImage(masterPtr->fileString,
232
masterPtr->imageData, masterPtr->imageInfo) != XpmSuccess) {
233
free((char *)masterPtr->imageData);
234
free((char *)masterPtr->imageInfo);
235
masterPtr->imageData = NULL;
236
masterPtr->imageInfo = NULL;
242
* Cycle through all of the instances of this image, regenerating
243
* the information for each instance. Then force the image to be
244
* redisplayed everywhere that it is used.
247
for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
248
instancePtr = instancePtr->nextPtr) {
249
ImgXPMConfigureInstance(instancePtr);
251
Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->imageData->width,
252
masterPtr->imageData->height, masterPtr->imageData->width,
253
masterPtr->imageData->height);
258
*----------------------------------------------------------------------
260
* ImgXPMConfigureInstance --
262
* This procedure is called to create displaying information for
263
* a xpm image instance based on the configuration information
264
* in the master. It is invoked both when new instances are
265
* created and when the master is reconfigured.
271
* Generates errors via Tcl_BackgroundError if there are problems
272
* in setting up the instance.
274
*----------------------------------------------------------------------
278
ImgXPMConfigureInstance(instancePtr)
279
XPMInstance *instancePtr; /* Instance to reconfigure. */
281
XPMMaster *masterPtr = instancePtr->masterPtr;
286
Tk_Window tkwind = instancePtr->tkwin;
288
XpmAttributes locattr;
289
Display *dpy = Tk_Display(instancePtr->tkwin);
291
if ((xwind = Tk_WindowId(tkwind)) == 0)
292
Tk_MakeWindowExist(tkwind);
294
if ((xwind = Tk_WindowId(tkwind)) == 0)
298
* For each of the options in masterPtr, translate the string
299
* form into an internal form appropriate for instancePtr.
302
if (instancePtr->pixmap != None) {
303
XFreePixmap(dpy, instancePtr->pixmap);
304
instancePtr->pixmap = None;
307
if (masterPtr->imageData != NULL) {
308
if (masterPtr->imageData->width <= 0
309
|| masterPtr->imageData->height <= 0) goto error;
310
oldMask = instancePtr->mask;
311
instancePtr->mask = None;
312
locattr.valuemask = XpmSize | XpmCloseness;
313
locattr.closeness = 65536;
315
XpmCreatePixmapFromXpmImage(dpy, xwind, masterPtr->imageData,
316
&instancePtr->pixmap, &instancePtr->mask, &locattr);
317
if (oldMask != None) {
318
XFreePixmap(dpy, oldMask);
322
/* Create the GC for copying the pixmap */
324
if (masterPtr->imageData != NULL) {
325
gcValues.graphics_exposures = False;
326
gcmask = GCGraphicsExposures;
327
gc = Tk_GetGC(instancePtr->tkwin, gcmask, &gcValues);
328
XSetClipMask(dpy, gc, instancePtr->mask);
332
if (instancePtr->gc != None) {
333
Tk_FreeGC(dpy, instancePtr->gc);
335
instancePtr->gc = gc;
341
* An error occurred: clear the graphics context in the instance to
342
* make it clear that this instance cannot be displayed. Then report
346
if (instancePtr->gc != None)
347
Tk_FreeGC(dpy, instancePtr->gc);
348
instancePtr->gc = None;
350
Tcl_AddErrorInfo(masterPtr->interp, "\n (while configuring image \"");
351
Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
352
Tcl_AddErrorInfo(masterPtr->interp, "\")");
353
Tcl_BackgroundError(masterPtr->interp);
358
*--------------------------------------------------------------
362
* This procedure is invoked to process the Tcl command
363
* that corresponds to an image managed by this module.
364
* See the user documentation for details on what it does.
367
* A standard Tcl result.
370
* See the user documentation.
372
*--------------------------------------------------------------
376
ImgXPMCmd(clientData, interp, objc, objv)
377
ClientData clientData; /* Information about the image master. */
378
Tcl_Interp *interp; /* Current interpreter. */
379
int objc; /* Number of arguments. */
380
Tcl_Obj *CONST objv[]; /* Argument objects. */
382
static char *xpmOptions[] = {"cget", "configure", (char *) NULL};
383
XPMMaster *masterPtr = (XPMMaster *) clientData;
387
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
390
if (Tcl_GetIndexFromObj(interp, objv[1], xpmOptions, "option", 0,
397
Tcl_WrongNumArgs(interp, 2, objv, "option");
400
return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
401
(char *) masterPtr, Tcl_GetString(objv[2]), 0);
405
code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
406
configSpecs, (char *) masterPtr, (char *) NULL, 0);
407
} else if (objc == 3) {
408
code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
409
configSpecs, (char *) masterPtr,
410
Tcl_GetString(objv[2]), 0);
412
code = ImgXPMConfigureMaster(masterPtr, objc-2, objv+2,
413
TK_CONFIG_ARGV_ONLY);
418
panic("bad const entries to xpmOptions in ImgXPMCmd");
425
*----------------------------------------------------------------------
429
* This procedure is called for each use of a xpm image in a
433
* The return value is a token for the instance, which is passed
434
* back to us in calls to ImgXPMDisplay and ImgXPMFree.
437
* A data structure is set up for the instance (or, an existing
438
* instance is re-used for the new one).
440
*----------------------------------------------------------------------
444
ImgXPMGet(tkwin, masterData)
445
Tk_Window tkwin; /* Window in which the instance will be
447
ClientData masterData; /* Pointer to our master structure for the
450
XPMMaster *masterPtr = (XPMMaster *) masterData;
451
XPMInstance *instancePtr;
454
* See if there is already an instance for this window. If so
455
* then just re-use it.
458
for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
459
instancePtr = instancePtr->nextPtr) {
460
if (instancePtr->tkwin == tkwin) {
461
instancePtr->refCount++;
462
return (ClientData) instancePtr;
467
* The image isn't already in use in this window. Make a new
468
* instance of the image.
471
instancePtr = (XPMInstance *) Tcl_Alloc(sizeof(XPMInstance));
472
instancePtr->refCount = 1;
473
instancePtr->masterPtr = masterPtr;
474
instancePtr->tkwin = tkwin;
475
instancePtr->pixmap = None;
476
instancePtr->mask = None;
477
instancePtr->gc = None;
478
instancePtr->nextPtr = masterPtr->instancePtr;
479
masterPtr->instancePtr = instancePtr;
480
ImgXPMConfigureInstance(instancePtr);
483
* If this is the first instance, must set the size of the image.
486
if (instancePtr->nextPtr == NULL) {
487
if (masterPtr->imageData != NULL)
488
Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
489
masterPtr->imageData->width, masterPtr->imageData->height);
491
Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, 0, 0);
494
return (ClientData) instancePtr;
498
*----------------------------------------------------------------------
502
* This procedure is invoked to draw a xpm image.
508
* A portion of the image gets rendered in a pixmap or window.
510
*----------------------------------------------------------------------
514
ImgXPMDisplay(clientData, display, drawable, imageX, imageY, width,
515
height, drawableX, drawableY)
516
ClientData clientData; /* Pointer to BitmapInstance structure for
517
* for instance to be displayed. */
518
Display *display; /* Display on which to draw image. */
519
Drawable drawable; /* Pixmap or window in which to draw image. */
520
int imageX, imageY; /* Upper-left corner of region within image
522
int width, height; /* Dimensions of region within image to draw. */
523
int drawableX, drawableY; /* Coordinates within drawable that
524
* correspond to imageX and imageY. */
526
XPMInstance *instancePtr = (XPMInstance *) clientData;
530
* If there's no GC, then an error occurred during image creation
531
* and it should not be displayed.
534
if (instancePtr->gc == None) return;
536
masking = (instancePtr->mask != None);
538
XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
541
XCopyArea(display, instancePtr->pixmap, drawable, instancePtr->gc,
542
imageX, imageY, (unsigned) width, (unsigned) height,
543
drawableX, drawableY);
545
XSetClipOrigin(display, instancePtr->gc, 0, 0);
550
*----------------------------------------------------------------------
554
* This procedure is called when a widget ceases to use a
555
* particular instance of an image.
561
* Internal data structures get cleaned up.
563
*----------------------------------------------------------------------
567
ImgXPMFree(clientData, display)
568
ClientData clientData; /* Pointer to BitmapInstance structure for
569
* for instance to be displayed. */
570
Display *display; /* Display containing window that used image. */
572
XPMInstance *instancePtr = (XPMInstance *) clientData;
573
XPMInstance *prevPtr;
575
instancePtr->refCount--;
576
if (instancePtr->refCount > 0) {
581
* There are no more uses of the image within this widget. Free
582
* the instance structure.
585
if (instancePtr->pixmap != None) {
586
XFreePixmap(display, instancePtr->pixmap);
588
if (instancePtr->mask != None) {
589
XFreePixmap(display, instancePtr->mask);
591
if (instancePtr->masterPtr->instancePtr == instancePtr) {
592
instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
594
for (prevPtr = instancePtr->masterPtr->instancePtr;
595
prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
596
/* Empty loop body */
598
prevPtr->nextPtr = instancePtr->nextPtr;
600
Tcl_Free((char *) instancePtr);
604
*----------------------------------------------------------------------
608
* This procedure is called by the image code to delete the
609
* master structure for an image.
615
* Resources associated with the image get freed.
617
*----------------------------------------------------------------------
621
ImgXPMDelete(masterData)
622
ClientData masterData; /* Pointer to BitmapMaster structure for
623
* image. Must not have any more instances. */
625
XPMMaster *masterPtr = (XPMMaster *) masterData;
627
if (masterPtr->instancePtr != NULL) {
628
panic("tried to delete xpm image when instances still exist");
630
masterPtr->tkMaster = NULL;
631
if (masterPtr->imageCmd != NULL) {
632
Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
634
if (masterPtr->imageData != NULL) {
635
XpmFreeXpmImage(masterPtr->imageData);
637
if (masterPtr->imageInfo != NULL) {
638
XpmFreeXpmInfo(masterPtr->imageInfo);
640
Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
641
Tcl_Free((char *) masterPtr);
645
*----------------------------------------------------------------------
647
* ImgXPMCmdDeletedProc --
649
* This procedure is invoked when the image command for an image
650
* is deleted. It deletes the image.
656
* The image is deleted.
658
*----------------------------------------------------------------------
662
ImgXPMCmdDeletedProc(clientData)
663
ClientData clientData; /* Pointer to BitmapMaster structure for
666
XPMMaster *masterPtr = (XPMMaster *) clientData;
668
masterPtr->imageCmd = NULL;
669
if (masterPtr->tkMaster != NULL) {
670
Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
675
*---------------------------------------------------------
676
* register the XPM image type with the Tk "image" command
677
*---------------------------------------------------------
681
RegisterXPMImageType()
683
Tk_CreateImageType(&tkXPMImageType);
686
#endif /* TCL_WRAPPER && HAVE_XPM */