1 /*
2  * tkCanvWind.c --
3  *
4  *	This file implements window items for canvas widgets.
5  *
6  * Copyright (c) 1992-1994 The Regents of the University of California.
7  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
8  *
9  * See the file "license.terms" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  * SCCS: @(#) tkCanvWind.c 1.26 96/09/06 08:41:52
13  */
14 
15 #include "tkInt.h"
16 #include "tkCanvas.h"
17 
18 /*
19  * The structure below defines the record for each window item.
20  */
21 
22 typedef struct WindowItem  {
23     Tk_Item header;		/* Generic stuff that's the same for all
24 				 * types.  MUST BE FIRST IN STRUCTURE. */
25     double x, y;		/* Coordinates of positioning point for
26 				 * window. */
27     Tk_Window tkwin;		/* Window associated with item.  NULL means
28 				 * window has been destroyed. */
29     int width;			/* Width to use for window (<= 0 means use
30 				 * window's requested width). */
31     int height;			/* Width to use for window (<= 0 means use
32 				 * window's requested width). */
33     Tk_Anchor anchor;		/* Where to anchor window relative to
34 				 * (x,y). */
35     Tk_Canvas canvas;		/* Canvas containing this item. */
36 } WindowItem;
37 
38 /*
39  * Information used for parsing configuration specs:
40  */
41 
42 static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc,
43     Tk_CanvasTagsPrintProc, (ClientData) NULL
44 };
45 
46 static Tk_ConfigSpec configSpecs[] = {
47     {TK_CONFIG_ANCHOR, "-anchor", (char *) NULL, (char *) NULL,
48 	"center", Tk_Offset(WindowItem, anchor), TK_CONFIG_DONT_SET_DEFAULT},
49     {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL,
50 	"0", Tk_Offset(WindowItem, height), TK_CONFIG_DONT_SET_DEFAULT},
51     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
52 	(char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption},
53     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
54 	"0", Tk_Offset(WindowItem, width), TK_CONFIG_DONT_SET_DEFAULT},
55     {TK_CONFIG_WINDOW, "-window", (char *) NULL, (char *) NULL,
56 	(char *) NULL, Tk_Offset(WindowItem, tkwin), TK_CONFIG_NULL_OK},
57     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
58 	(char *) NULL, 0, 0}
59 };
60 
61 /*
62  * Prototypes for procedures defined in this file:
63  */
64 
65 static void		ComputeWindowBbox _ANSI_ARGS_((Tk_Canvas canvas,
66 			    WindowItem *winItemPtr));
67 static int		ConfigureWinItem _ANSI_ARGS_((Tcl_Interp *interp,
68 			    Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
69 			    char **argv, int flags));
70 static int		CreateWinItem _ANSI_ARGS_((Tcl_Interp *interp,
71 			    Tk_Canvas canvas, struct Tk_Item *itemPtr,
72 			    int argc, char **argv));
73 static void		DeleteWinItem _ANSI_ARGS_((Tk_Canvas canvas,
74 			    Tk_Item *itemPtr, Display *display));
75 static void		DisplayWinItem _ANSI_ARGS_((Tk_Canvas canvas,
76 			    Tk_Item *itemPtr, Display *display, Drawable dst,
77 			    int x, int y, int width, int height));
78 static void		ScaleWinItem _ANSI_ARGS_((Tk_Canvas canvas,
79 			    Tk_Item *itemPtr, double originX, double originY,
80 			    double scaleX, double scaleY));
81 static void		TranslateWinItem _ANSI_ARGS_((Tk_Canvas canvas,
82 			    Tk_Item *itemPtr, double deltaX, double deltaY));
83 static int		WinItemCoords _ANSI_ARGS_((Tcl_Interp *interp,
84 			    Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
85 			    char **argv));
86 static void		WinItemLostSlaveProc _ANSI_ARGS_((
87 			    ClientData clientData, Tk_Window tkwin));
88 static void		WinItemRequestProc _ANSI_ARGS_((ClientData clientData,
89 			    Tk_Window tkwin));
90 static void		WinItemStructureProc _ANSI_ARGS_((
91 			    ClientData clientData, XEvent *eventPtr));
92 static int		WinItemToArea _ANSI_ARGS_((Tk_Canvas canvas,
93 			    Tk_Item *itemPtr, double *rectPtr));
94 static double		WinItemToPoint _ANSI_ARGS_((Tk_Canvas canvas,
95 			    Tk_Item *itemPtr, double *pointPtr));
96 
97 /*
98  * The structure below defines the window item type by means of procedures
99  * that can be invoked by generic item code.
100  */
101 
102 Tk_ItemType tkWindowType = {
103     "window",				/* name */
104     sizeof(WindowItem),			/* itemSize */
105     CreateWinItem,			/* createProc */
106     configSpecs,			/* configSpecs */
107     ConfigureWinItem,			/* configureProc */
108     WinItemCoords,			/* coordProc */
109     DeleteWinItem,			/* deleteProc */
110     DisplayWinItem,			/* displayProc */
111     1,					/* alwaysRedraw */
112     WinItemToPoint,			/* pointProc */
113     WinItemToArea,			/* areaProc */
114     (Tk_ItemPostscriptProc *) NULL,	/* postscriptProc */
115     ScaleWinItem,			/* scaleProc */
116     TranslateWinItem,			/* translateProc */
117     (Tk_ItemIndexProc *) NULL,		/* indexProc */
118     (Tk_ItemCursorProc *) NULL,		/* cursorProc */
119     (Tk_ItemSelectionProc *) NULL,	/* selectionProc */
120     (Tk_ItemInsertProc *) NULL,		/* insertProc */
121     (Tk_ItemDCharsProc *) NULL,		/* dTextProc */
122     (Tk_ItemType *) NULL		/* nextPtr */
123 };
124 
125 
126 /*
127  * The structure below defines the official type record for the
128  * placer:
129  */
130 
131 static Tk_GeomMgr canvasGeomType = {
132     "canvas",				/* name */
133     WinItemRequestProc,			/* requestProc */
134     WinItemLostSlaveProc,		/* lostSlaveProc */
135 };
136 
137 /*
138  *--------------------------------------------------------------
139  *
140  * CreateWinItem --
141  *
142  *	This procedure is invoked to create a new window
143  *	item in a canvas.
144  *
145  * Results:
146  *	A standard Tcl return value.  If an error occurred in
147  *	creating the item, then an error message is left in
148  *	interp->result;  in this case itemPtr is
149  *	left uninitialized, so it can be safely freed by the
150  *	caller.
151  *
152  * Side effects:
153  *	A new window item is created.
154  *
155  *--------------------------------------------------------------
156  */
157 
158 static int
CreateWinItem(interp,canvas,itemPtr,argc,argv)159 CreateWinItem(interp, canvas, itemPtr, argc, argv)
160     Tcl_Interp *interp;			/* Interpreter for error reporting. */
161     Tk_Canvas canvas;			/* Canvas to hold new item. */
162     Tk_Item *itemPtr;			/* Record to hold new item;  header
163 					 * has been initialized by caller. */
164     int argc;				/* Number of arguments in argv. */
165     char **argv;			/* Arguments describing rectangle. */
166 {
167     WindowItem *winItemPtr = (WindowItem *) itemPtr;
168 
169     if (argc < 2) {
170 	Tcl_AppendResult(interp, "wrong # args: should be \"",
171 		Tk_PathName(Tk_CanvasTkwin(canvas)), " create ",
172 		itemPtr->typePtr->name, " x y ?options?\"",
173 		(char *) NULL);
174 	return TCL_ERROR;
175     }
176 
177     /*
178      * Initialize item's record.
179      */
180 
181     winItemPtr->tkwin = NULL;
182     winItemPtr->width = 0;
183     winItemPtr->height = 0;
184     winItemPtr->anchor = TK_ANCHOR_CENTER;
185     winItemPtr->canvas = canvas;
186 
187     /*
188      * Process the arguments to fill in the item record.
189      */
190 
191     if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) != TCL_OK)
192 	    || (Tk_CanvasGetCoord(interp, canvas, argv[1],
193 		&winItemPtr->y) != TCL_OK)) {
194 	return TCL_ERROR;
195     }
196 
197     if (ConfigureWinItem(interp, canvas, itemPtr, argc-2, argv+2, 0)
198 	    != TCL_OK) {
199 	DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
200 	return TCL_ERROR;
201     }
202     return TCL_OK;
203 }
204 
205 /*
206  *--------------------------------------------------------------
207  *
208  * WinItemCoords --
209  *
210  *	This procedure is invoked to process the "coords" widget
211  *	command on window items.  See the user documentation for
212  *	details on what it does.
213  *
214  * Results:
215  *	Returns TCL_OK or TCL_ERROR, and sets interp->result.
216  *
217  * Side effects:
218  *	The coordinates for the given item may be changed.
219  *
220  *--------------------------------------------------------------
221  */
222 
223 static int
WinItemCoords(interp,canvas,itemPtr,argc,argv)224 WinItemCoords(interp, canvas, itemPtr, argc, argv)
225     Tcl_Interp *interp;			/* Used for error reporting. */
226     Tk_Canvas canvas;			/* Canvas containing item. */
227     Tk_Item *itemPtr;			/* Item whose coordinates are to be
228 					 * read or modified. */
229     int argc;				/* Number of coordinates supplied in
230 					 * argv. */
231     char **argv;			/* Array of coordinates: x1, y1,
232 					 * x2, y2, ... */
233 {
234     WindowItem *winItemPtr = (WindowItem *) itemPtr;
235     char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE];
236 
237     if (argc == 0) {
238 	Tcl_PrintDouble(interp, winItemPtr->x, x);
239 	Tcl_PrintDouble(interp, winItemPtr->y, y);
240 	Tcl_AppendResult(interp, x, " ", y, (char *) NULL);
241     } else if (argc == 2) {
242 	if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x)
243 		!= TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1],
244 		&winItemPtr->y) != TCL_OK)) {
245 	    return TCL_ERROR;
246 	}
247 	ComputeWindowBbox(canvas, winItemPtr);
248     } else {
249 	sprintf(interp->result,
250 		"wrong # coordinates: expected 0 or 2, got %d", argc);
251 	return TCL_ERROR;
252     }
253     return TCL_OK;
254 }
255 
256 /*
257  *--------------------------------------------------------------
258  *
259  * ConfigureWinItem --
260  *
261  *	This procedure is invoked to configure various aspects
262  *	of a window item, such as its anchor position.
263  *
264  * Results:
265  *	A standard Tcl result code.  If an error occurs, then
266  *	an error message is left in interp->result.
267  *
268  * Side effects:
269  *	Configuration information may be set for itemPtr.
270  *
271  *--------------------------------------------------------------
272  */
273 
274 static int
ConfigureWinItem(interp,canvas,itemPtr,argc,argv,flags)275 ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags)
276     Tcl_Interp *interp;		/* Used for error reporting. */
277     Tk_Canvas canvas;		/* Canvas containing itemPtr. */
278     Tk_Item *itemPtr;		/* Window item to reconfigure. */
279     int argc;			/* Number of elements in argv.  */
280     char **argv;		/* Arguments describing things to configure. */
281     int flags;			/* Flags to pass to Tk_ConfigureWidget. */
282 {
283     WindowItem *winItemPtr = (WindowItem *) itemPtr;
284     Tk_Window oldWindow;
285     Tk_Window canvasTkwin;
286 
287     oldWindow = winItemPtr->tkwin;
288     canvasTkwin = Tk_CanvasTkwin(canvas);
289     if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, argv,
290 	    (char *) winItemPtr, flags) != TCL_OK) {
291 	return TCL_ERROR;
292     }
293 
294     /*
295      * A few of the options require additional processing.
296      */
297 
298     if (oldWindow != winItemPtr->tkwin) {
299 	if (oldWindow != NULL) {
300 	    Tk_DeleteEventHandler(oldWindow, StructureNotifyMask,
301 		    WinItemStructureProc, (ClientData) winItemPtr);
302 	    Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL,
303 		    (ClientData) NULL);
304 	    Tk_UnmaintainGeometry(oldWindow, canvasTkwin);
305 	    Tk_UnmapWindow(oldWindow);
306 	}
307 	if (winItemPtr->tkwin != NULL) {
308 	    Tk_Window ancestor, parent;
309 
310 	    /*
311 	     * Make sure that the canvas is either the parent of the
312 	     * window associated with the item or a descendant of that
313 	     * parent.  Also, don't allow a top-level window to be
314 	     * managed inside a canvas.
315 	     */
316 
317 	    parent = Tk_Parent(winItemPtr->tkwin);
318 	    for (ancestor = canvasTkwin; ;
319 		    ancestor = Tk_Parent(ancestor)) {
320 		if (ancestor == parent) {
321 		    break;
322 		}
323 		if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) {
324 		    badWindow:
325 		    Tcl_AppendResult(interp, "can't use ",
326 			    Tk_PathName(winItemPtr->tkwin),
327 			    " in a window item of this canvas", (char *) NULL);
328 		    winItemPtr->tkwin = NULL;
329 		    return TCL_ERROR;
330 		}
331 	    }
332 	    if (((Tk_FakeWin *) (winItemPtr->tkwin))->flags & TK_TOP_LEVEL) {
333 		goto badWindow;
334 	    }
335 	    if (winItemPtr->tkwin == canvasTkwin) {
336 		goto badWindow;
337 	    }
338 	    Tk_CreateEventHandler(winItemPtr->tkwin, StructureNotifyMask,
339 		    WinItemStructureProc, (ClientData) winItemPtr);
340 	    Tk_ManageGeometry(winItemPtr->tkwin, &canvasGeomType,
341 		    (ClientData) winItemPtr);
342 	}
343     }
344 
345     ComputeWindowBbox(canvas, winItemPtr);
346 
347     return TCL_OK;
348 }
349 
350 /*
351  *--------------------------------------------------------------
352  *
353  * DeleteWinItem --
354  *
355  *	This procedure is called to clean up the data structure
356  *	associated with a window item.
357  *
358  * Results:
359  *	None.
360  *
361  * Side effects:
362  *	Resources associated with itemPtr are released.
363  *
364  *--------------------------------------------------------------
365  */
366 
367 static void
DeleteWinItem(canvas,itemPtr,display)368 DeleteWinItem(canvas, itemPtr, display)
369     Tk_Canvas canvas;			/* Overall info about widget. */
370     Tk_Item *itemPtr;			/* Item that is being deleted. */
371     Display *display;			/* Display containing window for
372 					 * canvas. */
373 {
374     WindowItem *winItemPtr = (WindowItem *) itemPtr;
375     Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas);
376 
377     if (winItemPtr->tkwin != NULL) {
378 	Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask,
379 		WinItemStructureProc, (ClientData) winItemPtr);
380 	Tk_ManageGeometry(winItemPtr->tkwin, (Tk_GeomMgr *) NULL,
381 		(ClientData) NULL);
382 	if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) {
383 	    Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin);
384 	}
385 	Tk_UnmapWindow(winItemPtr->tkwin);
386     }
387 }
388 
389 /*
390  *--------------------------------------------------------------
391  *
392  * ComputeWindowBbox --
393  *
394  *	This procedure is invoked to compute the bounding box of
395  *	all the pixels that may be drawn as part of a window item.
396  *	This procedure is where the child window's placement is
397  *	computed.
398  *
399  * Results:
400  *	None.
401  *
402  * Side effects:
403  *	The fields x1, y1, x2, and y2 are updated in the header
404  *	for itemPtr.
405  *
406  *--------------------------------------------------------------
407  */
408 
409 static void
ComputeWindowBbox(canvas,winItemPtr)410 ComputeWindowBbox(canvas, winItemPtr)
411     Tk_Canvas canvas;			/* Canvas that contains item. */
412     WindowItem *winItemPtr;		/* Item whose bbox is to be
413 					 * recomputed. */
414 {
415     int width, height, x, y;
416 
417     x = winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5);
418     y = winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5);
419 
420     if (winItemPtr->tkwin == NULL) {
421 	winItemPtr->header.x1 = winItemPtr->header.x2 = x;
422 	winItemPtr->header.y1 = winItemPtr->header.y2 = y;
423 	return;
424     }
425 
426     /*
427      * Compute dimensions of window.
428      */
429 
430     width = winItemPtr->width;
431     if (width <= 0) {
432 	width = Tk_ReqWidth(winItemPtr->tkwin);
433 	if (width <= 0) {
434 	    width = 1;
435 	}
436     }
437     height = winItemPtr->height;
438     if (height <= 0) {
439 	height = Tk_ReqHeight(winItemPtr->tkwin);
440 	if (height <= 0) {
441 	    height = 1;
442 	}
443     }
444 
445     /*
446      * Compute location of window, using anchor information.
447      */
448 
449     switch (winItemPtr->anchor) {
450 	case TK_ANCHOR_N:
451 	    x -= width/2;
452 	    break;
453 	case TK_ANCHOR_NE:
454 	    x -= width;
455 	    break;
456 	case TK_ANCHOR_E:
457 	    x -= width;
458 	    y -= height/2;
459 	    break;
460 	case TK_ANCHOR_SE:
461 	    x -= width;
462 	    y -= height;
463 	    break;
464 	case TK_ANCHOR_S:
465 	    x -= width/2;
466 	    y -= height;
467 	    break;
468 	case TK_ANCHOR_SW:
469 	    y -= height;
470 	    break;
471 	case TK_ANCHOR_W:
472 	    y -= height/2;
473 	    break;
474 	case TK_ANCHOR_NW:
475 	    break;
476 	case TK_ANCHOR_CENTER:
477 	    x -= width/2;
478 	    y -= height/2;
479 	    break;
480     }
481 
482     /*
483      * Store the information in the item header.
484      */
485 
486     winItemPtr->header.x1 = x;
487     winItemPtr->header.y1 = y;
488     winItemPtr->header.x2 = x + width;
489     winItemPtr->header.y2 = y + height;
490 }
491 
492 /*
493  *--------------------------------------------------------------
494  *
495  * DisplayWinItem --
496  *
497  *	This procedure is invoked to "draw" a window item in a given
498  *	drawable.  Since the window draws itself, we needn't do any
499  *	actual redisplay here.  However, this procedure takes care
500  *	of actually repositioning the child window so that it occupies
501  *	the correct screen position.
502  *
503  * Results:
504  *	None.
505  *
506  * Side effects:
507  *	The child window's position may get changed.  Note: this
508  *	procedure gets called both when a window needs to be displayed
509  *	and when it ceases to be visible on the screen (e.g. it was
510  *	scrolled or moved off-screen or the enclosing canvas is
511  *	unmapped).
512  *
513  *--------------------------------------------------------------
514  */
515 
516 static void
DisplayWinItem(canvas,itemPtr,display,drawable,regionX,regionY,regionWidth,regionHeight)517 DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY,
518 	regionWidth, regionHeight)
519     Tk_Canvas canvas;			/* Canvas that contains item. */
520     Tk_Item *itemPtr;			/* Item to be displayed. */
521     Display *display;			/* Display on which to draw item. */
522     Drawable drawable;			/* Pixmap or window in which to draw
523 					 * item. */
524     int regionX, regionY, regionWidth, regionHeight;
525 					/* Describes region of canvas that
526 					 * must be redisplayed (not used). */
527 {
528     WindowItem *winItemPtr = (WindowItem *) itemPtr;
529     int width, height;
530     short x, y;
531     Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas);
532 
533     if (winItemPtr->tkwin == NULL) {
534 	return;
535     }
536 
537     Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1,
538 	    (double) winItemPtr->header.y1, &x, &y);
539     width = winItemPtr->header.x2 - winItemPtr->header.x1;
540     height = winItemPtr->header.y2 - winItemPtr->header.y1;
541 
542     /*
543      * Reposition and map the window (but in different ways depending
544      * on whether the canvas is the window's parent).
545      */
546 
547     if (canvasTkwin == Tk_Parent(winItemPtr->tkwin)) {
548 	if ((x != Tk_X(winItemPtr->tkwin)) || (y != Tk_Y(winItemPtr->tkwin))
549 		|| (width != Tk_Width(winItemPtr->tkwin))
550 		|| (height != Tk_Height(winItemPtr->tkwin))) {
551 	    Tk_MoveResizeWindow(winItemPtr->tkwin, x, y, width, height);
552 	}
553 	Tk_MapWindow(winItemPtr->tkwin);
554     } else {
555 	Tk_MaintainGeometry(winItemPtr->tkwin, canvasTkwin, x, y,
556 		width, height);
557     }
558 }
559 
560 /*
561  *--------------------------------------------------------------
562  *
563  * WinItemToPoint --
564  *
565  *	Computes the distance from a given point to a given
566  *	rectangle, in canvas units.
567  *
568  * Results:
569  *	The return value is 0 if the point whose x and y coordinates
570  *	are coordPtr[0] and coordPtr[1] is inside the window.  If the
571  *	point isn't inside the window then the return value is the
572  *	distance from the point to the window.
573  *
574  * Side effects:
575  *	None.
576  *
577  *--------------------------------------------------------------
578  */
579 
580 static double
WinItemToPoint(canvas,itemPtr,pointPtr)581 WinItemToPoint(canvas, itemPtr, pointPtr)
582     Tk_Canvas canvas;		/* Canvas containing item. */
583     Tk_Item *itemPtr;		/* Item to check against point. */
584     double *pointPtr;		/* Pointer to x and y coordinates. */
585 {
586     WindowItem *winItemPtr = (WindowItem *) itemPtr;
587     double x1, x2, y1, y2, xDiff, yDiff;
588 
589     x1 = winItemPtr->header.x1;
590     y1 = winItemPtr->header.y1;
591     x2 = winItemPtr->header.x2;
592     y2 = winItemPtr->header.y2;
593 
594     /*
595      * Point is outside rectangle.
596      */
597 
598     if (pointPtr[0] < x1) {
599 	xDiff = x1 - pointPtr[0];
600     } else if (pointPtr[0] >= x2)  {
601 	xDiff = pointPtr[0] + 1 - x2;
602     } else {
603 	xDiff = 0;
604     }
605 
606     if (pointPtr[1] < y1) {
607 	yDiff = y1 - pointPtr[1];
608     } else if (pointPtr[1] >= y2)  {
609 	yDiff = pointPtr[1] + 1 - y2;
610     } else {
611 	yDiff = 0;
612     }
613 
614     return hypot(xDiff, yDiff);
615 }
616 
617 /*
618  *--------------------------------------------------------------
619  *
620  * WinItemToArea --
621  *
622  *	This procedure is called to determine whether an item
623  *	lies entirely inside, entirely outside, or overlapping
624  *	a given rectangle.
625  *
626  * Results:
627  *	-1 is returned if the item is entirely outside the area
628  *	given by rectPtr, 0 if it overlaps, and 1 if it is entirely
629  *	inside the given area.
630  *
631  * Side effects:
632  *	None.
633  *
634  *--------------------------------------------------------------
635  */
636 
637 static int
WinItemToArea(canvas,itemPtr,rectPtr)638 WinItemToArea(canvas, itemPtr, rectPtr)
639     Tk_Canvas canvas;		/* Canvas containing item. */
640     Tk_Item *itemPtr;		/* Item to check against rectangle. */
641     double *rectPtr;		/* Pointer to array of four coordinates
642 				 * (x1, y1, x2, y2) describing rectangular
643 				 * area.  */
644 {
645     WindowItem *winItemPtr = (WindowItem *) itemPtr;
646 
647     if ((rectPtr[2] <= winItemPtr->header.x1)
648 	    || (rectPtr[0] >= winItemPtr->header.x2)
649 	    || (rectPtr[3] <= winItemPtr->header.y1)
650 	    || (rectPtr[1] >= winItemPtr->header.y2)) {
651 	return -1;
652     }
653     if ((rectPtr[0] <= winItemPtr->header.x1)
654 	    && (rectPtr[1] <= winItemPtr->header.y1)
655 	    && (rectPtr[2] >= winItemPtr->header.x2)
656 	    && (rectPtr[3] >= winItemPtr->header.y2)) {
657 	return 1;
658     }
659     return 0;
660 }
661 
662 /*
663  *--------------------------------------------------------------
664  *
665  * ScaleWinItem --
666  *
667  *	This procedure is invoked to rescale a rectangle or oval
668  *	item.
669  *
670  * Results:
671  *	None.
672  *
673  * Side effects:
674  *	The rectangle or oval referred to by itemPtr is rescaled
675  *	so that the following transformation is applied to all
676  *	point coordinates:
677  *		x' = originX + scaleX*(x-originX)
678  *		y' = originY + scaleY*(y-originY)
679  *
680  *--------------------------------------------------------------
681  */
682 
683 static void
ScaleWinItem(canvas,itemPtr,originX,originY,scaleX,scaleY)684 ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY)
685     Tk_Canvas canvas;			/* Canvas containing rectangle. */
686     Tk_Item *itemPtr;			/* Rectangle to be scaled. */
687     double originX, originY;		/* Origin about which to scale rect. */
688     double scaleX;			/* Amount to scale in X direction. */
689     double scaleY;			/* Amount to scale in Y direction. */
690 {
691     WindowItem *winItemPtr = (WindowItem *) itemPtr;
692 
693     winItemPtr->x = originX + scaleX*(winItemPtr->x - originX);
694     winItemPtr->y = originY + scaleY*(winItemPtr->y - originY);
695     if (winItemPtr->width > 0) {
696 	winItemPtr->width = scaleX*winItemPtr->width;
697     }
698     if (winItemPtr->height > 0) {
699 	winItemPtr->height = scaleY*winItemPtr->height;
700     }
701     ComputeWindowBbox(canvas, winItemPtr);
702 }
703 
704 /*
705  *--------------------------------------------------------------
706  *
707  * TranslateWinItem --
708  *
709  *	This procedure is called to move a rectangle or oval by a
710  *	given amount.
711  *
712  * Results:
713  *	None.
714  *
715  * Side effects:
716  *	The position of the rectangle or oval is offset by
717  *	(xDelta, yDelta), and the bounding box is updated in the
718  *	generic part of the item structure.
719  *
720  *--------------------------------------------------------------
721  */
722 
723 static void
TranslateWinItem(canvas,itemPtr,deltaX,deltaY)724 TranslateWinItem(canvas, itemPtr, deltaX, deltaY)
725     Tk_Canvas canvas;			/* Canvas containing item. */
726     Tk_Item *itemPtr;			/* Item that is being moved. */
727     double deltaX, deltaY;		/* Amount by which item is to be
728 					 * moved. */
729 {
730     WindowItem *winItemPtr = (WindowItem *) itemPtr;
731 
732     winItemPtr->x += deltaX;
733     winItemPtr->y += deltaY;
734     ComputeWindowBbox(canvas, winItemPtr);
735 }
736 
737 /*
738  *--------------------------------------------------------------
739  *
740  * WinItemStructureProc --
741  *
742  *	This procedure is invoked whenever StructureNotify events
743  *	occur for a window that's managed as part of a canvas window
744  *	item.  This procudure's only purpose is to clean up when
745  *	windows are deleted.
746  *
747  * Results:
748  *	None.
749  *
750  * Side effects:
751  *	The window is disassociated from the window item when it is
752  *	deleted.
753  *
754  *--------------------------------------------------------------
755  */
756 
757 static void
WinItemStructureProc(clientData,eventPtr)758 WinItemStructureProc(clientData, eventPtr)
759     ClientData clientData;	/* Pointer to record describing window item. */
760     XEvent *eventPtr;		/* Describes what just happened. */
761 {
762     WindowItem *winItemPtr = (WindowItem *) clientData;
763 
764     if (eventPtr->type == DestroyNotify) {
765 	winItemPtr->tkwin = NULL;
766     }
767 }
768 
769 /*
770  *--------------------------------------------------------------
771  *
772  * WinItemRequestProc --
773  *
774  *	This procedure is invoked whenever a window that's associated
775  *	with a window canvas item changes its requested dimensions.
776  *
777  * Results:
778  *	None.
779  *
780  * Side effects:
781  *	The size and location on the screen of the window may change,
782  *	depending on the options specified for the window item.
783  *
784  *--------------------------------------------------------------
785  */
786 
787 static void
WinItemRequestProc(clientData,tkwin)788 WinItemRequestProc(clientData, tkwin)
789     ClientData clientData;		/* Pointer to record for window item. */
790     Tk_Window tkwin;			/* Window that changed its desired
791 					 * size. */
792 {
793     WindowItem *winItemPtr = (WindowItem *) clientData;
794 
795     ComputeWindowBbox(winItemPtr->canvas, winItemPtr);
796     DisplayWinItem(winItemPtr->canvas, (Tk_Item *) winItemPtr,
797 	    (Display *) NULL, (Drawable) None, 0, 0, 0, 0);
798 }
799 
800 /*
801  *--------------------------------------------------------------
802  *
803  * WinItemLostSlaveProc --
804  *
805  *	This procedure is invoked by Tk whenever some other geometry
806  *	claims control over a slave that used to be managed by us.
807  *
808  * Results:
809  *	None.
810  *
811  * Side effects:
812  *	Forgets all canvas-related information about the slave.
813  *
814  *--------------------------------------------------------------
815  */
816 
817 	/* ARGSUSED */
818 static void
WinItemLostSlaveProc(clientData,tkwin)819 WinItemLostSlaveProc(clientData, tkwin)
820     ClientData clientData;	/* WindowItem structure for slave window that
821 				 * was stolen away. */
822     Tk_Window tkwin;		/* Tk's handle for the slave window. */
823 {
824     WindowItem *winItemPtr = (WindowItem *) clientData;
825     Tk_Window canvasTkwin = Tk_CanvasTkwin(winItemPtr->canvas);
826 
827     Tk_DeleteEventHandler(winItemPtr->tkwin, StructureNotifyMask,
828 	    WinItemStructureProc, (ClientData) winItemPtr);
829     if (canvasTkwin != Tk_Parent(winItemPtr->tkwin)) {
830 	Tk_UnmaintainGeometry(winItemPtr->tkwin, canvasTkwin);
831     }
832     Tk_UnmapWindow(winItemPtr->tkwin);
833     winItemPtr->tkwin = NULL;
834 }
835