4 * This file implements window items for canvas widgets.
6 * Copyright 1992 Regents of the University of California.
7 * Permission to use, copy, modify, and distribute this
8 * software and its documentation for any purpose and without
9 * fee is hereby granted, provided that the above copyright
10 * notice appear in all copies. The University of California
11 * makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without
13 * express or implied warranty.
17 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkCanvWind.c,v 1.4 92/08/24 09:24:22 ouster Exp $ SPRITE (Berkeley)";
26 * The structure below defines the record for each window item.
29 typedef struct WindowItem
{
30 Tk_Item header
; /* Generic stuff that's the same for all
31 * types. MUST BE FIRST IN STRUCTURE. */
32 double x
, y
; /* Coordinates of positioning point for
34 Tk_Window tkwin
; /* Window associated with item. NULL means
35 * window has been destroyed. */
36 int width
; /* Width to use for window (<= 0 means use
37 * window's requested width). */
38 int height
; /* Width to use for window (<= 0 means use
39 * window's requested width). */
40 Tk_Anchor anchor
; /* Where to anchor window relative to
42 Tk_Canvas
*canvasPtr
; /* Canvas containing this item. */
46 * Information used for parsing configuration specs:
49 static Tk_ConfigSpec configSpecs
[] = {
50 {TK_CONFIG_ANCHOR
, "-anchor", (char *) NULL
, (char *) NULL
,
51 "center", Tk_Offset(WindowItem
, anchor
), TK_CONFIG_DONT_SET_DEFAULT
},
52 {TK_CONFIG_PIXELS
, "-height", (char *) NULL
, (char *) NULL
,
53 "0", Tk_Offset(WindowItem
, height
), TK_CONFIG_DONT_SET_DEFAULT
},
54 {TK_CONFIG_CUSTOM
, "-tags", (char *) NULL
, (char *) NULL
,
55 (char *) NULL
, 0, TK_CONFIG_NULL_OK
, &tkCanvasTagsOption
},
56 {TK_CONFIG_PIXELS
, "-width", (char *) NULL
, (char *) NULL
,
57 "0", Tk_Offset(WindowItem
, width
), TK_CONFIG_DONT_SET_DEFAULT
},
58 {TK_CONFIG_WINDOW
, "-window", (char *) NULL
, (char *) NULL
,
59 (char *) NULL
, Tk_Offset(WindowItem
, tkwin
), TK_CONFIG_NULL_OK
},
60 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
65 * Prototypes for procedures defined in this file:
68 static void ComputeWindowBbox
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
69 WindowItem
*winItemPtr
));
70 static int ConfigureWinItem
_ANSI_ARGS_((
71 Tk_Canvas
*canvasPtr
, Tk_Item
*itemPtr
, int argc
,
72 char **argv
, int flags
));
73 static int CreateWinItem
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
74 struct Tk_Item
*itemPtr
, int argc
, char **argv
));
75 static void DeleteWinItem
_ANSI_ARGS_((Tk_Item
*itemPtr
));
76 static void DisplayWinItem
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
77 Tk_Item
*itemPtr
, Drawable dst
));
78 static void ScaleWinItem
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
79 Tk_Item
*itemPtr
, double originX
, double originY
,
80 double scaleX
, double scaleY
));
81 static void TranslateWinItem
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
82 Tk_Item
*itemPtr
, double deltaX
, double deltaY
));
83 static int WinItemCoords
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
84 Tk_Item
*itemPtr
, int argc
, char **argv
));
85 static void WinItemRequestProc
_ANSI_ARGS_((ClientData clientData
,
87 static void WinItemStructureProc
_ANSI_ARGS_((
88 ClientData clientData
, XEvent
*eventPtr
));
89 static int WinItemToArea
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
90 Tk_Item
*itemPtr
, double *rectPtr
));
91 static double WinItemToPoint
_ANSI_ARGS_((Tk_Canvas
*canvasPtr
,
92 Tk_Item
*itemPtr
, double *pointPtr
));
95 * The structures below defines the rectangle and oval item types
96 * by means of procedures that can be invoked by generic item code.
99 Tk_ItemType TkWindowType
= {
101 sizeof(WindowItem
), /* itemSize */
102 CreateWinItem
, /* createProc */
103 configSpecs
, /* configSpecs */
104 ConfigureWinItem
, /* configureProc */
105 WinItemCoords
, /* coordProc */
106 DeleteWinItem
, /* deleteProc */
107 DisplayWinItem
, /* displayProc */
108 1, /* alwaysRedraw */
109 WinItemToPoint
, /* pointProc */
110 WinItemToArea
, /* areaProc */
111 (Tk_ItemPostscriptProc
*) NULL
, /* postscriptProc */
112 ScaleWinItem
, /* scaleProc */
113 TranslateWinItem
, /* translateProc */
114 (Tk_ItemIndexProc
*) NULL
, /* indexProc */
115 (Tk_ItemCursorProc
*) NULL
, /* cursorProc */
116 (Tk_ItemSelectionProc
*) NULL
, /* selectionProc */
117 (Tk_ItemInsertProc
*) NULL
, /* insertProc */
118 (Tk_ItemDCharsProc
*) NULL
, /* dTextProc */
119 (Tk_ItemType
*) NULL
/* nextPtr */
123 *--------------------------------------------------------------
127 * This procedure is invoked to create a new window
131 * A standard Tcl return value. If an error occurred in
132 * creating the item, then an error message is left in
133 * canvasPtr->interp->result; in this case itemPtr is
134 * left uninitialized, so it can be safely freed by the
138 * A new window item is created.
140 *--------------------------------------------------------------
144 CreateWinItem(canvasPtr
, itemPtr
, argc
, argv
)
145 register Tk_Canvas
*canvasPtr
; /* Canvas to hold new item. */
146 Tk_Item
*itemPtr
; /* Record to hold new item; header
147 * has been initialized by caller. */
148 int argc
; /* Number of arguments in argv. */
149 char **argv
; /* Arguments describing rectangle. */
151 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
154 Tcl_AppendResult(canvasPtr
->interp
, "wrong # args: should be \"",
155 Tk_PathName(canvasPtr
->tkwin
), "\" create ",
156 itemPtr
->typePtr
->name
, " x y ?options?",
162 * Initialize item's record.
165 winItemPtr
->tkwin
= NULL
;
166 winItemPtr
->width
= 0;
167 winItemPtr
->height
= 0;
168 winItemPtr
->anchor
= TK_ANCHOR_CENTER
;
169 winItemPtr
->canvasPtr
= canvasPtr
;
172 * Process the arguments to fill in the item record.
175 if ((TkGetCanvasCoord(canvasPtr
, argv
[0], &winItemPtr
->x
) != TCL_OK
)
176 || (TkGetCanvasCoord(canvasPtr
, argv
[1],
177 &winItemPtr
->y
) != TCL_OK
)) {
181 if (ConfigureWinItem(canvasPtr
, itemPtr
, argc
-2, argv
+2, 0) != TCL_OK
) {
182 DeleteWinItem(itemPtr
);
189 *--------------------------------------------------------------
193 * This procedure is invoked to process the "coords" widget
194 * command on window items. See the user documentation for
195 * details on what it does.
198 * Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
201 * The coordinates for the given item may be changed.
203 *--------------------------------------------------------------
207 WinItemCoords(canvasPtr
, itemPtr
, argc
, argv
)
208 register Tk_Canvas
*canvasPtr
; /* Canvas containing item. */
209 Tk_Item
*itemPtr
; /* Item whose coordinates are to be
210 * read or modified. */
211 int argc
; /* Number of coordinates supplied in
213 char **argv
; /* Array of coordinates: x1, y1,
216 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
219 sprintf(canvasPtr
->interp
->result
, "%g %g", winItemPtr
->x
,
221 } else if (argc
== 2) {
222 if ((TkGetCanvasCoord(canvasPtr
, argv
[0], &winItemPtr
->x
) != TCL_OK
)
223 || (TkGetCanvasCoord(canvasPtr
, argv
[1],
224 &winItemPtr
->y
) != TCL_OK
)) {
227 ComputeWindowBbox(canvasPtr
, winItemPtr
);
229 sprintf(canvasPtr
->interp
->result
,
230 "wrong # coordinates: expected 0 or 2, got %d",
238 *--------------------------------------------------------------
240 * ConfigureWinItem --
242 * This procedure is invoked to configure various aspects
243 * of a window item, such as its anchor position.
246 * A standard Tcl result code. If an error occurs, then
247 * an error message is left in canvasPtr->interp->result.
250 * Configuration information may be set for itemPtr.
252 *--------------------------------------------------------------
256 ConfigureWinItem(canvasPtr
, itemPtr
, argc
, argv
, flags
)
257 Tk_Canvas
*canvasPtr
; /* Canvas containing itemPtr. */
258 Tk_Item
*itemPtr
; /* Window item to reconfigure. */
259 int argc
; /* Number of elements in argv. */
260 char **argv
; /* Arguments describing things to configure. */
261 int flags
; /* Flags to pass to Tk_ConfigureWidget. */
263 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
266 oldWindow
= winItemPtr
->tkwin
;
267 if (Tk_ConfigureWidget(canvasPtr
->interp
, canvasPtr
->tkwin
,
268 configSpecs
, argc
, argv
, (char *) winItemPtr
, flags
) != TCL_OK
) {
273 * A few of the options require additional processing.
276 if (oldWindow
!= winItemPtr
->tkwin
) {
277 if (oldWindow
!= NULL
) {
278 Tk_DeleteEventHandler(oldWindow
, StructureNotifyMask
,
279 WinItemStructureProc
, (ClientData
) winItemPtr
);
280 Tk_ManageGeometry(oldWindow
, (Tk_GeometryProc
*) NULL
,
282 Tk_UnmapWindow(oldWindow
);
284 if (winItemPtr
->tkwin
!= NULL
) {
285 Tk_Window ancestor
, parent
;
288 * Make sure that the canvas is either the parent of the
289 * window associated with the item or a descendant of that
290 * parent. Also, don't allow a top-level window to be
291 * managed inside a canvas.
294 parent
= Tk_Parent(winItemPtr
->tkwin
);
295 for (ancestor
= canvasPtr
->tkwin
; ;
296 ancestor
= Tk_Parent(ancestor
)) {
297 if (ancestor
== parent
) {
300 if (((Tk_FakeWin
*) (ancestor
))->flags
& TK_TOP_LEVEL
) {
302 Tcl_AppendResult(canvasPtr
->interp
, "can't use ",
303 Tk_PathName(winItemPtr
->tkwin
),
304 " in a window item of this canvas", (char *) NULL
);
305 winItemPtr
->tkwin
= NULL
;
309 if (((Tk_FakeWin
*) (winItemPtr
->tkwin
))->flags
& TK_TOP_LEVEL
) {
312 if (winItemPtr
->tkwin
== canvasPtr
->tkwin
) {
315 Tk_CreateEventHandler(winItemPtr
->tkwin
, StructureNotifyMask
,
316 WinItemStructureProc
, (ClientData
) winItemPtr
);
317 Tk_ManageGeometry(winItemPtr
->tkwin
, WinItemRequestProc
,
318 (ClientData
) winItemPtr
);
322 ComputeWindowBbox(canvasPtr
, winItemPtr
);
328 *--------------------------------------------------------------
332 * This procedure is called to clean up the data structure
333 * associated with a window item.
339 * Resources associated with itemPtr are released.
341 *--------------------------------------------------------------
345 DeleteWinItem(itemPtr
)
346 Tk_Item
*itemPtr
; /* Item that is being deleted. */
348 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
350 if (winItemPtr
->tkwin
!= NULL
) {
351 Tk_DeleteEventHandler(winItemPtr
->tkwin
, StructureNotifyMask
,
352 WinItemStructureProc
, (ClientData
) winItemPtr
);
353 Tk_ManageGeometry(winItemPtr
->tkwin
, (Tk_GeometryProc
*) NULL
,
355 Tk_UnmapWindow(winItemPtr
->tkwin
);
360 *--------------------------------------------------------------
362 * ComputeWindowBbox --
364 * This procedure is invoked to compute the bounding box of
365 * all the pixels that may be drawn as part of a window item.
366 * This procedure is where the child window's placement is
373 * The fields x1, y1, x2, and y2 are updated in the header
376 *--------------------------------------------------------------
381 ComputeWindowBbox(canvasPtr
, winItemPtr
)
382 Tk_Canvas
*canvasPtr
; /* Canvas that contains item. */
383 register WindowItem
*winItemPtr
; /* Item whose bbox is to be
386 int width
, height
, x
, y
;
388 x
= winItemPtr
->x
+ 0.5;
389 y
= winItemPtr
->y
+ 0.5;
391 if (winItemPtr
->tkwin
== NULL
) {
392 winItemPtr
->header
.x1
= winItemPtr
->header
.x2
= x
;
393 winItemPtr
->header
.y1
= winItemPtr
->header
.y2
= y
;
398 * Compute dimensions of window.
401 width
= winItemPtr
->width
;
403 width
= Tk_ReqWidth(winItemPtr
->tkwin
);
408 height
= winItemPtr
->height
;
410 height
= Tk_ReqHeight(winItemPtr
->tkwin
);
417 * Compute location of window, using anchor information.
420 switch (winItemPtr
->anchor
) {
447 case TK_ANCHOR_CENTER
:
454 * Store the information in the item header.
457 winItemPtr
->header
.x1
= x
;
458 winItemPtr
->header
.y1
= y
;
459 winItemPtr
->header
.x2
= x
+ width
;
460 winItemPtr
->header
.y2
= y
+ height
;
464 *--------------------------------------------------------------
468 * This procedure is invoked to "draw" a window item in a given
469 * drawable. Since the window draws itself, we needn't do any
470 * actual redisplay here. However, this procedure takes care
471 * of actually repositioning the child window so that it occupies
472 * the correct screen position.
478 * The child window's position may get changed.
480 *--------------------------------------------------------------
485 DisplayWinItem(canvasPtr
, itemPtr
, drawable
)
486 register Tk_Canvas
*canvasPtr
; /* Canvas that contains item. */
487 Tk_Item
*itemPtr
; /* Item to be displayed. */
488 Drawable drawable
; /* Pixmap or window in which to draw
491 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
492 int x
,y
, width
, height
;
493 Tk_Window ancestor
, parent
;
495 if (winItemPtr
->tkwin
== NULL
) {
498 x
= winItemPtr
->header
.x1
- canvasPtr
->xOrigin
;
499 y
= winItemPtr
->header
.y1
- canvasPtr
->yOrigin
;
500 width
= winItemPtr
->header
.x2
- winItemPtr
->header
.x1
;
501 height
= winItemPtr
->header
.y2
- winItemPtr
->header
.y1
;
504 * If the canvas isn't the parent of the window, then translate the
505 * coordinates from those of the canvas to those of the window's
509 parent
= Tk_Parent(winItemPtr
->tkwin
);
510 for (ancestor
= canvasPtr
->tkwin
; ancestor
!= parent
;
511 ancestor
= Tk_Parent(ancestor
)) {
512 x
+= Tk_X(ancestor
) + Tk_Changes(ancestor
)->border_width
;
513 y
+= Tk_Y(ancestor
) + Tk_Changes(ancestor
)->border_width
;
517 * Reconfigure the window if it isn't already in the correct place.
520 if ((x
!= Tk_X(winItemPtr
->tkwin
)) || (y
!= Tk_Y(winItemPtr
->tkwin
))
521 || (width
!= Tk_Width(winItemPtr
->tkwin
))
522 || (height
!= Tk_Height(winItemPtr
->tkwin
))) {
523 Tk_MoveResizeWindow(winItemPtr
->tkwin
, x
, y
, (unsigned int) width
,
524 (unsigned int) height
);
526 if (!Tk_IsMapped(winItemPtr
->tkwin
)) {
527 Tk_MapWindow(winItemPtr
->tkwin
);
532 *--------------------------------------------------------------
536 * Computes the distance from a given point to a given
537 * rectangle, in canvas units.
540 * The return value is 0 if the point whose x and y coordinates
541 * are coordPtr[0] and coordPtr[1] is inside the window. If the
542 * point isn't inside the window then the return value is the
543 * distance from the point to the window.
548 *--------------------------------------------------------------
553 WinItemToPoint(canvasPtr
, itemPtr
, pointPtr
)
554 Tk_Canvas
*canvasPtr
; /* Canvas containing item. */
555 Tk_Item
*itemPtr
; /* Item to check against point. */
556 double *pointPtr
; /* Pointer to x and y coordinates. */
558 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
559 double x1
, x2
, y1
, y2
, xDiff
, yDiff
;
561 x1
= winItemPtr
->header
.x1
;
562 y1
= winItemPtr
->header
.y1
;
563 x2
= winItemPtr
->header
.x2
;
564 y2
= winItemPtr
->header
.y2
;
567 * Point is outside rectangle.
570 if (pointPtr
[0] < x1
) {
571 xDiff
= x1
- pointPtr
[0];
572 } else if (pointPtr
[0] > x2
) {
573 xDiff
= pointPtr
[0] - x2
;
578 if (pointPtr
[1] < y1
) {
579 yDiff
= y1
- pointPtr
[1];
580 } else if (pointPtr
[1] > y2
) {
581 yDiff
= pointPtr
[1] - y2
;
586 return hypot(xDiff
, yDiff
);
590 *--------------------------------------------------------------
594 * This procedure is called to determine whether an item
595 * lies entirely inside, entirely outside, or overlapping
599 * -1 is returned if the item is entirely outside the area
600 * given by rectPtr, 0 if it overlaps, and 1 if it is entirely
601 * inside the given area.
606 *--------------------------------------------------------------
611 WinItemToArea(canvasPtr
, itemPtr
, rectPtr
)
612 Tk_Canvas
*canvasPtr
; /* Canvas containing item. */
613 Tk_Item
*itemPtr
; /* Item to check against rectangle. */
614 double *rectPtr
; /* Pointer to array of four coordinates
615 * (x1, y1, x2, y2) describing rectangular
618 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
620 if ((rectPtr
[2] <= winItemPtr
->header
.x1
)
621 || (rectPtr
[0] >= winItemPtr
->header
.x2
)
622 || (rectPtr
[3] <= winItemPtr
->header
.y1
)
623 || (rectPtr
[1] >= winItemPtr
->header
.y2
)) {
626 if ((rectPtr
[0] <= winItemPtr
->header
.x1
)
627 && (rectPtr
[1] <= winItemPtr
->header
.y1
)
628 && (rectPtr
[2] >= winItemPtr
->header
.x2
)
629 && (rectPtr
[3] >= winItemPtr
->header
.y2
)) {
636 *--------------------------------------------------------------
640 * This procedure is invoked to rescale a rectangle or oval
647 * The rectangle or oval referred to by itemPtr is rescaled
648 * so that the following transformation is applied to all
650 * x' = originX + scaleX*(x-originX)
651 * y' = originY + scaleY*(y-originY)
653 *--------------------------------------------------------------
657 ScaleWinItem(canvasPtr
, itemPtr
, originX
, originY
, scaleX
, scaleY
)
658 Tk_Canvas
*canvasPtr
; /* Canvas containing rectangle. */
659 Tk_Item
*itemPtr
; /* Rectangle to be scaled. */
660 double originX
, originY
; /* Origin about which to scale rect. */
661 double scaleX
; /* Amount to scale in X direction. */
662 double scaleY
; /* Amount to scale in Y direction. */
664 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
666 winItemPtr
->x
= originX
+ scaleX
*(winItemPtr
->x
- originX
);
667 winItemPtr
->y
= originY
+ scaleY
*(winItemPtr
->y
- originY
);
668 if (winItemPtr
->width
> 0) {
669 winItemPtr
->width
= scaleY
*winItemPtr
->width
;
671 if (winItemPtr
->height
> 0) {
672 winItemPtr
->height
= scaleY
*winItemPtr
->height
;
674 ComputeWindowBbox(canvasPtr
, winItemPtr
);
678 *--------------------------------------------------------------
680 * TranslateWinItem --
682 * This procedure is called to move a rectangle or oval by a
689 * The position of the rectangle or oval is offset by
690 * (xDelta, yDelta), and the bounding box is updated in the
691 * generic part of the item structure.
693 *--------------------------------------------------------------
697 TranslateWinItem(canvasPtr
, itemPtr
, deltaX
, deltaY
)
698 Tk_Canvas
*canvasPtr
; /* Canvas containing item. */
699 Tk_Item
*itemPtr
; /* Item that is being moved. */
700 double deltaX
, deltaY
; /* Amount by which item is to be
703 register WindowItem
*winItemPtr
= (WindowItem
*) itemPtr
;
705 winItemPtr
->x
+= deltaX
;
706 winItemPtr
->y
+= deltaY
;
707 ComputeWindowBbox(canvasPtr
, winItemPtr
);
711 *--------------------------------------------------------------
713 * WinItemStructureProc --
715 * This procedure is invoked whenever StructureNotify events
716 * occur for a window that's managed as part of a canvas window
717 * item. This procudure's only purpose is to clean up when
718 * windows are deleted.
724 * The window is disassociated from the window item when it is
727 *--------------------------------------------------------------
731 WinItemStructureProc(clientData
, eventPtr
)
732 ClientData clientData
; /* Pointer to record describing window item. */
733 XEvent
*eventPtr
; /* Describes what just happened. */
735 register WindowItem
*winItemPtr
= (WindowItem
*) clientData
;
737 if (eventPtr
->type
== DestroyNotify
) {
738 winItemPtr
->tkwin
= NULL
;
743 *--------------------------------------------------------------
745 * WinItemRequestProc --
747 * This procedure is invoked whenever a window that's associated
748 * with a window canvas item changes its requested dimensions.
754 * The size and location on the screen of the window may change,
755 * depending on the options specified for the window item.
757 *--------------------------------------------------------------
762 WinItemRequestProc(clientData
, tkwin
)
763 ClientData clientData
; /* Pointer to record for window item. */
764 Tk_Window tkwin
; /* Window that changed its desired
767 WindowItem
*winItemPtr
= (WindowItem
*) clientData
;
769 ComputeWindowBbox(winItemPtr
->canvasPtr
, winItemPtr
);
770 DisplayWinItem(winItemPtr
->canvasPtr
, (Tk_Item
*) winItemPtr
,