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