OSDN Git Service

Merge branch 'master' of git://github.com/monaka/binutils
[pf3gnuchains/pf3gnuchains3x.git] / tk / generic / tkImage.c
1 /* 
2  * tkImage.c --
3  *
4  *      This module implements the image protocol, which allows lots
5  *      of different kinds of images to be used in lots of different
6  *      widgets.
7  *
8  * Copyright (c) 1994 The Regents of the University of California.
9  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10  *
11  * See the file "license.terms" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * RCS: @(#) $Id$
15  */
16
17 #include "tkInt.h"
18 #include "tkPort.h"
19
20 /*
21  * Each call to Tk_GetImage returns a pointer to one of the following
22  * structures, which is used as a token by clients (widgets) that
23  * display images.
24  */
25
26 typedef struct Image {
27     Tk_Window tkwin;            /* Window passed to Tk_GetImage (needed to
28                                  * "re-get" the image later if the manager
29                                  * changes). */
30     Display *display;           /* Display for tkwin.  Needed because when
31                                  * the image is eventually freed tkwin may
32                                  * not exist anymore. */
33     struct ImageMaster *masterPtr;
34                                 /* Master for this image (identifiers image
35                                  * manager, for example). */
36     ClientData instanceData;
37                                 /* One word argument to pass to image manager
38                                  * when dealing with this image instance. */
39     Tk_ImageChangedProc *changeProc;
40                                 /* Code in widget to call when image changes
41                                  * in a way that affects redisplay. */
42     ClientData widgetClientData;
43                                 /* Argument to pass to changeProc. */
44     struct Image *nextPtr;      /* Next in list of all image instances
45                                  * associated with the same name. */
46
47 } Image;
48
49 /*
50  * For each image master there is one of the following structures,
51  * which represents a name in the image table and all of the images
52  * instantiated from it.  Entries in mainPtr->imageTable point to
53  * these structures.
54  */
55
56 typedef struct ImageMaster {
57     Tk_ImageType *typePtr;      /* Information about image type.  NULL means
58                                  * that no image manager owns this image:  the
59                                  * image was deleted. */
60     ClientData masterData;      /* One-word argument to pass to image mgr
61                                  * when dealing with the master, as opposed
62                                  * to instances. */
63     int width, height;          /* Last known dimensions for image. */
64     Tcl_HashTable *tablePtr;    /* Pointer to hash table containing image
65                                  * (the imageTable field in some TkMainInfo
66                                  * structure). */
67     Tcl_HashEntry *hPtr;        /* Hash entry in mainPtr->imageTable for
68                                  * this structure (used to delete the hash
69                                  * entry). */
70     Image *instancePtr;         /* Pointer to first in list of instances
71                                  * derived from this name. */
72     int deleted;                /* Flag set when image is being deleted. */
73     TkWindow *winPtr;           /* Main window of interpreter (used to
74                                  * detect when the world is falling apart.) */
75 } ImageMaster;
76
77 typedef struct ThreadSpecificData {
78     Tk_ImageType *imageTypeList;/* First in a list of all known image 
79                                  * types. */  
80     Tk_ImageType *oldImageTypeList;/* First in a list of all known old-style image 
81                                  * types. */  
82 } ThreadSpecificData;           
83 static Tcl_ThreadDataKey dataKey;
84
85 /*
86  * Prototypes for local procedures:
87  */
88
89 static void     DeleteImage _ANSI_ARGS_((ImageMaster *masterPtr));
90 static void     EventuallyDeleteImage _ANSI_ARGS_((ImageMaster *masterPtr));
91 \f
92 /*
93  *----------------------------------------------------------------------
94  *
95  * Tk_CreateOldImageType, Tk_CreateImageType --
96  *
97  *      This procedure is invoked by an image manager to tell Tk about
98  *      a new kind of image and the procedures that manage the new type.
99  *      The procedure is typically invoked during Tcl_AppInit.
100  *
101  * Results:
102  *      None.
103  *
104  * Side effects:
105  *      The new image type is entered into a table used in the "image
106  *      create" command.
107  *
108  *----------------------------------------------------------------------
109  */
110
111 void
112 Tk_CreateOldImageType(typePtr)
113     Tk_ImageType *typePtr;      /* Structure describing the type.  All of
114                                  * the fields except "nextPtr" must be filled
115                                  * in by caller.  Must not have been passed
116                                  * to Tk_CreateImageType previously. */
117 {
118     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
119             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
120
121     typePtr->nextPtr = tsdPtr->oldImageTypeList;
122     tsdPtr->oldImageTypeList = typePtr;
123 }
124
125 void
126 Tk_CreateImageType(typePtr)
127     Tk_ImageType *typePtr;      /* Structure describing the type.  All of
128                                  * the fields except "nextPtr" must be filled
129                                  * in by caller.  Must not have been passed
130                                  * to Tk_CreateImageType previously. */
131 {
132     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
133             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
134
135     typePtr->nextPtr = tsdPtr->imageTypeList;
136     tsdPtr->imageTypeList = typePtr;
137 }
138 \f
139 /*
140  *----------------------------------------------------------------------
141  *
142  * Tk_ImageObjCmd --
143  *
144  *      This procedure is invoked to process the "image" Tcl command.
145  *      See the user documentation for details on what it does.
146  *
147  * Results:
148  *      A standard Tcl result.
149  *
150  * Side effects:
151  *      See the user documentation.
152  *
153  *----------------------------------------------------------------------
154  */
155
156 int
157 Tk_ImageObjCmd(clientData, interp, objc, objv)
158     ClientData clientData;      /* Main window associated with interpreter. */
159     Tcl_Interp *interp;         /* Current interpreter. */
160     int objc;                   /* Number of arguments. */
161     Tcl_Obj *CONST objv[];      /* Argument strings. */
162 {
163     static CONST char *imageOptions[] = {
164         "create", "delete", "height", "inuse", "names", "type", "types",
165             "width", (char *) NULL
166     };
167     enum options {
168         IMAGE_CREATE, IMAGE_DELETE, IMAGE_HEIGHT, IMAGE_INUSE, IMAGE_NAMES,
169         IMAGE_TYPE, IMAGE_TYPES, IMAGE_WIDTH
170     };
171     TkWindow *winPtr = (TkWindow *) clientData;
172     int i, new, firstOption,  index;
173     Tk_ImageType *typePtr;
174     ImageMaster *masterPtr;
175     Image *imagePtr;
176     Tcl_HashEntry *hPtr;
177     Tcl_HashSearch search;
178     char idString[16 + TCL_INTEGER_SPACE], *name;
179     TkDisplay *dispPtr = winPtr->dispPtr;
180     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
181             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
182
183     if (objc < 2) {
184         Tcl_WrongNumArgs(interp, 1, objv, "option ?args?");
185         return TCL_ERROR;
186     }
187
188     if (Tcl_GetIndexFromObj(interp, objv[1], imageOptions, "option", 0,
189             &index) != TCL_OK) {
190         return TCL_ERROR;
191     }
192     switch ((enum options) index) {
193         case IMAGE_CREATE: {
194             char *arg;
195             Tcl_Obj **args;
196             int oldimage = 0;
197             if (objc < 3) {
198                 Tcl_WrongNumArgs(interp, 2, objv, "type ?name? ?options?");
199                 return TCL_ERROR;
200             }
201
202             /*
203              * Look up the image type.
204              */
205
206             arg = Tcl_GetString(objv[2]);
207             for (typePtr = tsdPtr->imageTypeList; typePtr != NULL;
208                  typePtr = typePtr->nextPtr) {
209                 if ((*arg == typePtr->name[0])
210                         && (strcmp(arg, typePtr->name) == 0)) {
211                     break;
212                 }
213             }
214             if (typePtr == NULL) {
215                 oldimage = 1;
216                 for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL;
217                      typePtr = typePtr->nextPtr) {
218                     if ((*arg == typePtr->name[0])
219                             && (strcmp(arg, typePtr->name) == 0)) {
220                         break;
221                     }
222                 }
223             }
224             if (typePtr == NULL) {
225                 Tcl_AppendResult(interp, "image type \"", arg,
226                         "\" doesn't exist", (char *) NULL);
227                 return TCL_ERROR;
228             }
229
230             /*
231              * Figure out a name to use for the new image.
232              */
233
234             if ((objc == 3) || (*(arg = Tcl_GetString(objv[3])) == '-')) {
235                 dispPtr->imageId++;
236                 sprintf(idString, "image%d", dispPtr->imageId);
237                 name = idString;
238                 firstOption = 3;
239             } else {
240                 name = arg;
241                 firstOption = 4;
242             }
243
244             /*
245              * Create the data structure for the new image.
246              */
247
248             hPtr = Tcl_CreateHashEntry(&winPtr->mainPtr->imageTable,
249                     name, &new);
250             if (new) {
251                 masterPtr = (ImageMaster *) ckalloc(sizeof(ImageMaster));
252                 masterPtr->typePtr = NULL;
253                 masterPtr->masterData = NULL;
254                 masterPtr->width = masterPtr->height = 1;
255                 masterPtr->tablePtr = &winPtr->mainPtr->imageTable;
256                 masterPtr->hPtr = hPtr;
257                 masterPtr->instancePtr = NULL;
258                 masterPtr->deleted = 0;
259                 masterPtr->winPtr = winPtr->mainPtr->winPtr;
260                 Tcl_Preserve((ClientData) masterPtr->winPtr);
261                 Tcl_SetHashValue(hPtr, masterPtr);
262             } else {
263                 /*
264                  * An image already exists by this name.  Disconnect the
265                  * instances from the master.
266                  */
267
268                 masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
269                 if (masterPtr->typePtr != NULL) {
270                     for (imagePtr = masterPtr->instancePtr; imagePtr != NULL;
271                          imagePtr = imagePtr->nextPtr) {
272                         (*masterPtr->typePtr->freeProc)(
273                             imagePtr->instanceData, imagePtr->display);
274                         (*imagePtr->changeProc)(imagePtr->widgetClientData,
275                                 0, 0, masterPtr->width, masterPtr->height,
276                                 masterPtr->width, masterPtr->height);
277                     }
278                     (*masterPtr->typePtr->deleteProc)(masterPtr->masterData);
279                     masterPtr->typePtr = NULL;
280                 }
281             }
282
283             /*
284              * Call the image type manager so that it can perform its own
285              * initialization, then re-"get" for any existing instances of
286              * the image.
287              */
288
289             objv += firstOption;
290             objc -= firstOption;
291             args = (Tcl_Obj **) objv;
292             if (oldimage) {
293                 int i;
294                 args = (Tcl_Obj **) ckalloc((objc+1) * sizeof(char *));
295                 for (i = 0; i < objc; i++) {
296                     args[i] = (Tcl_Obj *) Tcl_GetString(objv[i]);
297                 }
298                 args[objc] = NULL;
299             }
300             Tcl_Preserve((ClientData) masterPtr);
301             if ((*typePtr->createProc)(interp, name, objc,
302                     args, typePtr, (Tk_ImageMaster) masterPtr,
303                     &masterPtr->masterData) != TCL_OK) {
304                 EventuallyDeleteImage(masterPtr);
305                 Tcl_Release((ClientData) masterPtr);
306                 if (oldimage) {
307                     ckfree((char *) args);
308                 }
309                 return TCL_ERROR;
310             }
311             Tcl_Release((ClientData) masterPtr);
312             if (oldimage) {
313                 ckfree((char *) args);
314             }
315             masterPtr->typePtr = typePtr;
316             for (imagePtr = masterPtr->instancePtr; imagePtr != NULL;
317                  imagePtr = imagePtr->nextPtr) {
318                 imagePtr->instanceData = (*typePtr->getProc)(
319                     imagePtr->tkwin, masterPtr->masterData);
320             }
321             Tcl_SetResult(interp,
322                     Tcl_GetHashKey(&winPtr->mainPtr->imageTable, hPtr),
323                     TCL_STATIC);
324             break;
325         }
326         case IMAGE_DELETE: {
327             for (i = 2; i < objc; i++) {
328                 char *arg = Tcl_GetString(objv[i]);
329                 hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg);
330                 if (hPtr == NULL) {
331                     Tcl_AppendResult(interp, "image \"", arg,
332                             "\" doesn't exist", (char *) NULL);
333                     return TCL_ERROR;
334                 }
335                 DeleteImage((ImageMaster *) Tcl_GetHashValue(hPtr));
336             }
337             break;
338         }
339         case IMAGE_HEIGHT: {    
340             char *arg;
341             if (objc != 3) {
342                 Tcl_WrongNumArgs(interp, 2, objv, "name");
343                 return TCL_ERROR;
344             }
345             arg = Tcl_GetString(objv[2]);
346             hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg);
347             if (hPtr == NULL) {
348                 Tcl_AppendResult(interp, "image \"", arg,
349                         "\" doesn't exist", (char *) NULL);
350                 return TCL_ERROR;
351             }
352             masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
353             Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->height);
354             break;
355         }
356
357         case IMAGE_INUSE: {
358             int count = 0;
359             char *arg;
360             if (objc != 3) {
361                 Tcl_WrongNumArgs(interp, 2, objv, "name");
362                 return TCL_ERROR;
363             }
364             arg = Tcl_GetString(objv[2]);
365             hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg);
366             if (hPtr == NULL) {
367                 Tcl_AppendResult(interp, "image \"", arg,
368                         "\" doesn't exist", (char *) NULL);
369                 return TCL_ERROR;
370             }
371             masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
372             if (masterPtr->typePtr != NULL && masterPtr->instancePtr != NULL) {
373                 count = 1;
374             }
375             Tcl_SetBooleanObj(Tcl_GetObjResult(interp), count);
376             break;
377         }
378
379         case IMAGE_NAMES: {
380             if (objc != 2) {
381                 Tcl_WrongNumArgs(interp, 2, objv, NULL);
382                 return TCL_ERROR;
383             }
384             hPtr = Tcl_FirstHashEntry(&winPtr->mainPtr->imageTable, &search);
385             for ( ; hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
386                 Tcl_AppendElement(interp, Tcl_GetHashKey(
387                     &winPtr->mainPtr->imageTable, hPtr));
388             }
389             break;
390         }
391         
392         case IMAGE_TYPE: {
393             char *arg;
394             if (objc != 3) {
395                 Tcl_WrongNumArgs(interp, 2, objv, "name");
396                 return TCL_ERROR;
397             }
398             arg = Tcl_GetString(objv[2]);
399             hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg);
400             if (hPtr == NULL) {
401                 Tcl_AppendResult(interp, "image \"", arg,
402                         "\" doesn't exist", (char *) NULL);
403                 return TCL_ERROR;
404             }
405             masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
406             if (masterPtr->typePtr != NULL) {
407                 Tcl_SetResult(interp, masterPtr->typePtr->name, TCL_STATIC);
408             }
409             break;
410         }
411         case IMAGE_TYPES: {
412             if (objc != 2) {
413                 Tcl_WrongNumArgs(interp, 2, objv, NULL);
414                 return TCL_ERROR;
415             }
416             for (typePtr = tsdPtr->imageTypeList; typePtr != NULL;
417                  typePtr = typePtr->nextPtr) {
418                 Tcl_AppendElement(interp, typePtr->name);
419             }
420             for (typePtr = tsdPtr->oldImageTypeList; typePtr != NULL;
421                  typePtr = typePtr->nextPtr) {
422                 Tcl_AppendElement(interp, typePtr->name);
423             }
424             break;
425         }
426         case IMAGE_WIDTH: {
427             char *arg;
428             if (objc != 3) {
429                 Tcl_WrongNumArgs(interp, 2, objv, "name");
430                 return TCL_ERROR;
431             }
432             arg = Tcl_GetString(objv[2]);
433             hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, arg);
434             if (hPtr == NULL) {
435                 Tcl_AppendResult(interp, "image \"", arg,
436                         "\" doesn't exist", (char *) NULL);
437                 return TCL_ERROR;
438             }
439             masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
440             Tcl_SetIntObj(Tcl_GetObjResult(interp), masterPtr->width);
441             break;
442         }
443     }
444     return TCL_OK;
445 }
446 \f
447 /*
448  *----------------------------------------------------------------------
449  *
450  * Tk_ImageChanged --
451  *
452  *      This procedure is called by an image manager whenever something
453  *      has happened that requires the image to be redrawn (some of its
454  *      pixels have changed, or its size has changed).
455  *
456  * Results:
457  *      None.
458  *
459  * Side effects:
460  *      Any widgets that display the image are notified so that they
461  *      can redisplay themselves as appropriate.
462  *
463  *----------------------------------------------------------------------
464  */
465
466 void
467 Tk_ImageChanged(imageMaster, x, y, width, height, imageWidth,
468         imageHeight)
469     Tk_ImageMaster imageMaster; /* Image that needs redisplay. */
470     int x, y;                   /* Coordinates of upper-left pixel of
471                                  * region of image that needs to be
472                                  * redrawn. */
473     int width, height;          /* Dimensions (in pixels) of region of
474                                  * image to redraw.  If either dimension
475                                  * is zero then the image doesn't need to
476                                  * be redrawn (perhaps all that happened is
477                                  * that its size changed). */
478     int imageWidth, imageHeight;/* New dimensions of image. */
479 {
480     ImageMaster *masterPtr = (ImageMaster *) imageMaster;
481     Image *imagePtr;
482
483     masterPtr->width = imageWidth;
484     masterPtr->height = imageHeight;
485     for (imagePtr = masterPtr->instancePtr; imagePtr != NULL;
486          imagePtr = imagePtr->nextPtr) {
487         (*imagePtr->changeProc)(imagePtr->widgetClientData, x, y,
488                 width, height, imageWidth, imageHeight);
489     }
490 }
491 \f
492 /*
493  *----------------------------------------------------------------------
494  *
495  * Tk_NameOfImage --
496  *
497  *      Given a token for an image master, this procedure returns
498  *      the name of the image.
499  *
500  * Results:
501  *      The return value is the string name for imageMaster.
502  *
503  * Side effects:
504  *      None.
505  *
506  *----------------------------------------------------------------------
507  */
508
509 CONST char *
510 Tk_NameOfImage(imageMaster)
511     Tk_ImageMaster imageMaster;         /* Token for image. */
512 {
513     ImageMaster *masterPtr = (ImageMaster *) imageMaster;
514
515     return Tcl_GetHashKey(masterPtr->tablePtr, masterPtr->hPtr);
516 }
517 \f
518 /*
519  *----------------------------------------------------------------------
520  *
521  * Tk_GetImage --
522  *
523  *      This procedure is invoked by a widget when it wants to use
524  *      a particular image in a particular window.
525  *
526  * Results:
527  *      The return value is a token for the image.  If there is no image
528  *      by the given name, then NULL is returned and an error message is
529  *      left in the interp's result.
530  *
531  * Side effects:
532  *      Tk records the fact that the widget is using the image, and
533  *      it will invoke changeProc later if the widget needs redisplay
534  *      (i.e. its size changes or some of its pixels change).  The
535  *      caller must eventually invoke Tk_FreeImage when it no longer
536  *      needs the image.
537  *
538  *----------------------------------------------------------------------
539  */
540
541 Tk_Image
542 Tk_GetImage(interp, tkwin, name, changeProc, clientData)
543     Tcl_Interp *interp;         /* Place to leave error message if image
544                                  * can't be found. */
545     Tk_Window tkwin;            /* Token for window in which image will
546                                  * be used. */
547     CONST char *name;           /* Name of desired image. */
548     Tk_ImageChangedProc *changeProc;
549                                 /* Procedure to invoke when redisplay is
550                                  * needed because image's pixels or size
551                                  * changed. */
552     ClientData clientData;      /* One-word argument to pass to damageProc. */
553 {
554     Tcl_HashEntry *hPtr;
555     ImageMaster *masterPtr;
556     Image *imagePtr;
557
558     hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->imageTable, name);
559     if (hPtr == NULL) {
560         goto noSuchImage;
561     }
562     masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
563     if (masterPtr->typePtr == NULL) {
564         goto noSuchImage;
565     }
566     imagePtr = (Image *) ckalloc(sizeof(Image));
567     imagePtr->tkwin = tkwin;
568     imagePtr->display = Tk_Display(tkwin);
569     imagePtr->masterPtr = masterPtr;
570     imagePtr->instanceData =
571             (*masterPtr->typePtr->getProc)(tkwin, masterPtr->masterData);
572     imagePtr->changeProc = changeProc;
573     imagePtr->widgetClientData = clientData;
574     imagePtr->nextPtr = masterPtr->instancePtr;
575     masterPtr->instancePtr = imagePtr;
576     return (Tk_Image) imagePtr;
577
578     noSuchImage:
579     Tcl_AppendResult(interp, "image \"", name, "\" doesn't exist",
580             (char *) NULL);
581     return NULL;
582 }
583 \f
584 /*
585  *----------------------------------------------------------------------
586  *
587  * Tk_FreeImage --
588  *
589  *      This procedure is invoked by a widget when it no longer needs
590  *      an image acquired by a previous call to Tk_GetImage.  For each
591  *      call to Tk_GetImage there must be exactly one call to Tk_FreeImage.
592  *
593  * Results:
594  *      None.
595  *
596  * Side effects:
597  *      The association between the image and the widget is removed.
598  *
599  *----------------------------------------------------------------------
600  */
601
602 void
603 Tk_FreeImage(image)
604     Tk_Image image;             /* Token for image that is no longer
605                                  * needed by a widget. */
606 {
607     Image *imagePtr = (Image *) image;
608     ImageMaster *masterPtr = imagePtr->masterPtr;
609     Image *prevPtr;
610
611     /*
612      * Clean up the particular instance.
613      */
614
615     if (masterPtr->typePtr != NULL) {
616         (*masterPtr->typePtr->freeProc)(imagePtr->instanceData,
617                 imagePtr->display);
618     }
619     prevPtr = masterPtr->instancePtr;
620     if (prevPtr == imagePtr) {
621         masterPtr->instancePtr = imagePtr->nextPtr;
622     } else {
623         while (prevPtr->nextPtr != imagePtr) {
624             prevPtr = prevPtr->nextPtr;
625         }
626         prevPtr->nextPtr = imagePtr->nextPtr;
627     }
628     ckfree((char *) imagePtr);
629
630     /* 
631      * If there are no more instances left for the master, and if the
632      * master image has been deleted, then delete the master too.
633      */
634
635     if ((masterPtr->typePtr == NULL) && (masterPtr->instancePtr == NULL)) {
636         Tcl_DeleteHashEntry(masterPtr->hPtr);
637         ckfree((char *) masterPtr);
638     }
639 }
640 \f
641 /*
642  *----------------------------------------------------------------------
643  *
644  * Tk_PostscriptImage --
645  *
646  *      This procedure is called by widgets that contain images in order
647  *      to redisplay an image on the screen or an off-screen pixmap.
648  *
649  * Results:
650  *      None.
651  *
652  * Side effects:
653  *      The image's manager is notified, and it redraws the desired
654  *      portion of the image before returning.
655  *
656  *----------------------------------------------------------------------
657  */
658
659 int
660 Tk_PostscriptImage(image, interp, tkwin, psinfo, x, y, width, height, prepass)
661     Tk_Image image;             /* Token for image to redisplay. */
662     Tcl_Interp *interp;
663     Tk_Window tkwin;
664     Tk_PostscriptInfo psinfo;   /* postscript info */
665     int x, y;                   /* Upper-left pixel of region in image that
666                                  * needs to be redisplayed. */
667     int width, height;          /* Dimensions of region to redraw. */
668     int prepass;
669 {
670     Image *imagePtr = (Image *) image;
671     int result;
672     XImage *ximage;
673     Pixmap pmap;
674     GC newGC;
675     XGCValues gcValues;
676
677     if (imagePtr->masterPtr->typePtr == NULL) {
678         /*
679          * No master for image, so nothing to display on postscript.
680          */
681         return TCL_OK;
682     }
683
684     /*
685      * Check if an image specific postscript-generation function
686      * exists; otherwise go on with generic code.
687      */
688
689     if (imagePtr->masterPtr->typePtr->postscriptProc != NULL) {
690         return (*imagePtr->masterPtr->typePtr->postscriptProc)(
691             imagePtr->masterPtr->masterData, interp, tkwin, psinfo,
692             x, y, width, height, prepass);
693     }
694
695     if (prepass) {
696         return TCL_OK;
697     }
698
699     /*
700      * Create a Pixmap, tell the image to redraw itself there, and then
701      * generate an XImage from the Pixmap.  We can then read pixel 
702      * values out of the XImage.
703      */
704
705     pmap = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
706                         width, height, Tk_Depth(tkwin));
707
708     gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin));
709     newGC = Tk_GetGC(tkwin, GCForeground, &gcValues);
710     if (newGC != None) {
711         XFillRectangle(Tk_Display(tkwin), pmap, newGC,
712                 0, 0, (unsigned int)width, (unsigned int)height);
713         Tk_FreeGC(Tk_Display(tkwin), newGC);
714     }
715
716     Tk_RedrawImage(image, x, y, width, height, pmap, 0, 0);
717
718     ximage = XGetImage(Tk_Display(tkwin), pmap, 0, 0,
719             (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap);
720
721     Tk_FreePixmap(Tk_Display(tkwin), pmap);
722     
723     if (ximage == NULL) {
724         /* The XGetImage() function is apparently not
725          * implemented on this system. Just ignore it.
726          */
727         return TCL_OK;
728     }
729     result = TkPostscriptImage(interp, tkwin, psinfo, ximage, x, y,
730             width, height);
731
732     XDestroyImage(ximage);
733     return result;
734 }
735
736 /*
737  *----------------------------------------------------------------------
738  *
739  * Tk_RedrawImage --
740  *
741  *      This procedure is called by widgets that contain images in order
742  *      to redisplay an image on the screen or an off-screen pixmap.
743  *
744  * Results:
745  *      None.
746  *
747  * Side effects:
748  *      The image's manager is notified, and it redraws the desired
749  *      portion of the image before returning.
750  *
751  *----------------------------------------------------------------------
752  */
753
754 void
755 Tk_RedrawImage(image, imageX, imageY, width, height, drawable,
756         drawableX, drawableY)
757     Tk_Image image;             /* Token for image to redisplay. */
758     int imageX, imageY;         /* Upper-left pixel of region in image that
759                                  * needs to be redisplayed. */
760     int width, height;          /* Dimensions of region to redraw. */
761     Drawable drawable;          /* Drawable in which to display image
762                                  * (window or pixmap).  If this is a pixmap,
763                                  * it must have the same depth as the window
764                                  * used in the Tk_GetImage call for the
765                                  * image. */
766     int drawableX, drawableY;   /* Coordinates in drawable that correspond
767                                  * to imageX and imageY. */
768 {
769     Image *imagePtr = (Image *) image;
770
771     if (imagePtr->masterPtr->typePtr == NULL) {
772         /*
773          * No master for image, so nothing to display.
774          */
775
776         return;
777     }
778
779     /*
780      * Clip the redraw area to the area of the image.
781      */
782
783     if (imageX < 0) {
784         width += imageX;
785         drawableX -= imageX;
786         imageX = 0;
787     }
788     if (imageY < 0) {
789         height += imageY;
790         drawableY -= imageY;
791         imageY = 0;
792     }
793     if ((imageX + width) > imagePtr->masterPtr->width) {
794         width = imagePtr->masterPtr->width - imageX;
795     }
796     if ((imageY + height) > imagePtr->masterPtr->height) {
797         height = imagePtr->masterPtr->height - imageY;
798     }
799     (*imagePtr->masterPtr->typePtr->displayProc)(
800             imagePtr->instanceData, imagePtr->display, drawable,
801             imageX, imageY, width, height, drawableX, drawableY);
802 }
803 \f
804 /*
805  *----------------------------------------------------------------------
806  *
807  * Tk_SizeOfImage --
808  *
809  *      This procedure returns the current dimensions of an image.
810  *
811  * Results:
812  *      The width and height of the image are returned in *widthPtr
813  *      and *heightPtr.
814  *
815  * Side effects:
816  *      None.
817  *
818  *----------------------------------------------------------------------
819  */
820
821 void
822 Tk_SizeOfImage(image, widthPtr, heightPtr)
823     Tk_Image image;             /* Token for image whose size is wanted. */
824     int *widthPtr;              /* Return width of image here. */
825     int *heightPtr;             /* Return height of image here. */
826 {
827     Image *imagePtr = (Image *) image;
828
829     *widthPtr = imagePtr->masterPtr->width;
830     *heightPtr = imagePtr->masterPtr->height;
831 }
832 \f
833 /*
834  *----------------------------------------------------------------------
835  *
836  * Tk_DeleteImage --
837  *
838  *      Given the name of an image, this procedure destroys the
839  *      image.
840  *
841  * Results:
842  *      None.
843  *
844  * Side effects:
845  *      The image is destroyed; existing instances will display as
846  *      blank areas.  If no such image exists then the procedure does
847  *      nothing.
848  *
849  *----------------------------------------------------------------------
850  */
851
852 void
853 Tk_DeleteImage(interp, name)
854     Tcl_Interp *interp;         /* Interpreter in which the image was
855                                  * created. */
856     CONST char *name;           /* Name of image. */
857 {
858     Tcl_HashEntry *hPtr;
859     TkWindow *winPtr;
860
861     winPtr = (TkWindow *) Tk_MainWindow(interp);
862     if (winPtr == NULL) {
863         return;
864     }
865     hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name);
866     if (hPtr == NULL) {
867         return;
868     }
869     DeleteImage((ImageMaster *)Tcl_GetHashValue(hPtr));
870 }
871 \f
872 /*
873  *----------------------------------------------------------------------
874  *
875  * DeleteImage --
876  *
877  *      This procedure is responsible for deleting an image.
878  *
879  * Results:
880  *      None.
881  *
882  * Side effects:
883  *      The connection is dropped between instances of this image and
884  *      an image master.  Image instances will redisplay themselves
885  *      as empty areas, but existing instances will not be deleted.
886  *
887  *----------------------------------------------------------------------
888  */
889
890 static void
891 DeleteImage(masterPtr)
892     ImageMaster *masterPtr;     /* Pointer to main data structure for image. */
893 {
894     Image *imagePtr;
895     Tk_ImageType *typePtr;
896
897     typePtr = masterPtr->typePtr;
898     masterPtr->typePtr = NULL;
899     if (typePtr != NULL) {
900         for (imagePtr = masterPtr->instancePtr; imagePtr != NULL;
901                 imagePtr = imagePtr->nextPtr) {
902            (*typePtr->freeProc)(imagePtr->instanceData,
903                    imagePtr->display);
904            (*imagePtr->changeProc)(imagePtr->widgetClientData, 0, 0,
905                     masterPtr->width, masterPtr->height, masterPtr->width,
906                     masterPtr->height);
907         }
908         (*typePtr->deleteProc)(masterPtr->masterData);
909     }
910     if (masterPtr->instancePtr == NULL) {
911         if ((masterPtr->winPtr->flags & TK_ALREADY_DEAD) == 0) {
912             Tcl_DeleteHashEntry(masterPtr->hPtr);
913         }
914         Tcl_Release((ClientData) masterPtr->winPtr);
915         ckfree((char *) masterPtr);
916     }
917 }
918 \f
919 /*
920  *----------------------------------------------------------------------
921  *
922  * EventuallyDeleteImage --
923  *
924  *      Arrange for an image to be deleted when it is safe to do so.
925  *
926  * Results:
927  *      None.
928  *
929  * Side effects:
930  *      Image will get freed, though not until it is no longer
931  *      Tcl_Preserve()d by anything.  May be called multiple times on
932  *      the same image without ill effects.
933  *
934  *----------------------------------------------------------------------
935  */
936
937 static void
938 EventuallyDeleteImage(masterPtr)
939     ImageMaster *masterPtr;     /* Pointer to main data structure for image. */
940 {
941     if (!masterPtr->deleted) {
942         masterPtr->deleted = 1;
943         Tcl_EventuallyFree((ClientData) masterPtr,
944                 (Tcl_FreeProc *)DeleteImage);
945     }
946 }
947 \f
948 /*
949  *----------------------------------------------------------------------
950  *
951  * TkDeleteAllImages --
952  *
953  *      This procedure is called when an application is deleted.  It
954  *      calls back all of the managers for all images so that they
955  *      can cleanup, then it deletes all of Tk's internal information
956  *      about images.
957  *
958  * Results:
959  *      None.
960  *
961  * Side effects:
962  *      All information for all images gets deleted.
963  *
964  *----------------------------------------------------------------------
965  */
966
967 void
968 TkDeleteAllImages(mainPtr)
969     TkMainInfo *mainPtr;        /* Structure describing application that is
970                                  * going away. */
971 {
972     Tcl_HashSearch search;
973     Tcl_HashEntry *hPtr;
974
975     for (hPtr = Tcl_FirstHashEntry(&mainPtr->imageTable, &search);
976             hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
977         EventuallyDeleteImage((ImageMaster *) Tcl_GetHashValue(hPtr));
978     }
979     Tcl_DeleteHashTable(&mainPtr->imageTable);
980 }
981 \f
982 /*
983  *----------------------------------------------------------------------
984  *
985  * Tk_GetImageMasterData --
986  *
987  *      Given the name of an image, this procedure returns the type
988  *      of the image and the clientData associated with its master.
989  *
990  * Results:
991  *      If there is no image by the given name, then NULL is returned
992  *      and a NULL value is stored at *typePtrPtr.  Otherwise the return
993  *      value is the clientData returned by the createProc when the
994  *      image was created and a pointer to the type structure for the
995  *      image is stored at *typePtrPtr.
996  *
997  * Side effects:
998  *      None.
999  *
1000  *----------------------------------------------------------------------
1001  */
1002
1003 ClientData
1004 Tk_GetImageMasterData(interp, name, typePtrPtr)
1005     Tcl_Interp *interp;         /* Interpreter in which the image was
1006                                  * created. */
1007     CONST char *name;           /* Name of image. */
1008     Tk_ImageType **typePtrPtr;  /* Points to location to fill in with
1009                                  * pointer to type information for image. */
1010 {
1011     Tcl_HashEntry *hPtr;
1012     TkWindow *winPtr;
1013     ImageMaster *masterPtr;
1014
1015     winPtr = (TkWindow *) Tk_MainWindow(interp);
1016     hPtr = Tcl_FindHashEntry(&winPtr->mainPtr->imageTable, name);
1017     if (hPtr == NULL) {
1018         *typePtrPtr = NULL;
1019         return NULL;
1020     }
1021     masterPtr = (ImageMaster *) Tcl_GetHashValue(hPtr);
1022     *typePtrPtr = masterPtr->typePtr;
1023     return masterPtr->masterData;
1024 }
1025
1026 /*
1027  *----------------------------------------------------------------------
1028  *
1029  * Tk_SetTSOrigin --
1030  *
1031  *      Set the pattern origin of the tile to a common point (i.e. the
1032  *      origin (0,0) of the top level window) so that tiles from two
1033  *      different widgets will match up.  This done by setting the
1034  *      GCTileStipOrigin field is set to the translated origin of the
1035  *      toplevel window in the hierarchy.
1036  *
1037  * Results:
1038  *      None.
1039  *
1040  * Side Effects:
1041  *      The GCTileStipOrigin is reset in the GC.  This will cause the
1042  *      tile origin to change when the GC is used for drawing.
1043  *
1044  *----------------------------------------------------------------------
1045  */
1046 /*ARGSUSED*/
1047 void
1048 Tk_SetTSOrigin(tkwin, gc, x, y)
1049     Tk_Window tkwin;
1050     GC gc;
1051     int x, y;
1052 {
1053     while (!Tk_TopWinHierarchy(tkwin)) {
1054         x -= Tk_X(tkwin) + Tk_Changes(tkwin)->border_width;
1055         y -= Tk_Y(tkwin) + Tk_Changes(tkwin)->border_width;
1056         tkwin = Tk_Parent(tkwin);
1057     }
1058     XSetTSOrigin(Tk_Display(tkwin), gc, x, y);
1059 }
1060