1 /*
2  * tkGeometry.c --
3  *
4  *	This file contains generic Tk code for geometry management
5  *	(stuff that's used by all geometry managers).
6  *
7  * Copyright (c) 1990-1994 The Regents of the University of California.
8  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
9  *
10  * See the file "license.terms" for information on usage and redistribution
11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12  *
13  * RCS: @(#) $Id: tkGeometry.c,v 1.5 2001/09/26 20:25:17 pspjuth Exp $
14  */
15 
16 #include "tkPort.h"
17 #include "tkInt.h"
18 
19 /*
20  * Data structures of the following type are used by Tk_MaintainGeometry.
21  * For each slave managed by Tk_MaintainGeometry, there is one of these
22  * structures associated with its master.
23  */
24 
25 typedef struct MaintainSlave {
26     Tk_Window slave;		/* The slave window being positioned. */
27     Tk_Window master;		/* The master that determines slave's
28 				 * position; it must be a descendant of
29 				 * slave's parent. */
30     int x, y;			/* Desired position of slave relative to
31 				 * master. */
32     int width, height;		/* Desired dimensions of slave. */
33     struct MaintainSlave *nextPtr;
34 				/* Next in list of Maintains associated
35 				 * with master. */
36 } MaintainSlave;
37 
38 /*
39  * For each window that has been specified as a master to
40  * Tk_MaintainGeometry, there is a structure of the following type:
41  */
42 
43 typedef struct MaintainMaster {
44     Tk_Window ancestor;		/* The lowest ancestor of this window
45 				 * for which we have *not* created a
46 				 * StructureNotify handler.  May be the
47 				 * same as the window itself. */
48     int checkScheduled;		/* Non-zero means that there is already a
49 				 * call to MaintainCheckProc scheduled as
50 				 * an idle handler. */
51     MaintainSlave *slavePtr;	/* First in list of all slaves associated
52 				 * with this master. */
53 } MaintainMaster;
54 
55 /*
56  * Prototypes for static procedures in this file:
57  */
58 
59 static void		MaintainCheckProc _ANSI_ARGS_((ClientData clientData));
60 static void		MaintainMasterProc _ANSI_ARGS_((ClientData clientData,
61 			    XEvent *eventPtr));
62 static void		MaintainSlaveProc _ANSI_ARGS_((ClientData clientData,
63 			    XEvent *eventPtr));
64 
65 /*
66  *--------------------------------------------------------------
67  *
68  * Tk_ManageGeometry --
69  *
70  *	Arrange for a particular procedure to manage the geometry
71  *	of a given slave window.
72  *
73  * Results:
74  *	None.
75  *
76  * Side effects:
77  *	Proc becomes the new geometry manager for tkwin, replacing
78  *	any previous geometry manager.  The geometry manager will
79  *	be notified (by calling procedures in *mgrPtr) when interesting
80  *	things happen in the future.  If there was an existing geometry
81  *	manager for tkwin different from the new one, it is notified
82  *	by calling its lostSlaveProc.
83  *
84  *--------------------------------------------------------------
85  */
86 
87 void
Tk_ManageGeometry(tkwin,mgrPtr,clientData)88 Tk_ManageGeometry(tkwin, mgrPtr, clientData)
89     Tk_Window tkwin;		/* Window whose geometry is to
90 				 * be managed by proc.  */
91     Tk_GeomMgr *mgrPtr;		/* Static structure describing the
92 				 * geometry manager.  This structure
93 				 * must never go away. */
94     ClientData clientData;	/* Arbitrary one-word argument to
95 				 * pass to geometry manager procedures. */
96 {
97     register TkWindow *winPtr = (TkWindow *) tkwin;
98 
99     if ((winPtr->geomMgrPtr != NULL) && (mgrPtr != NULL)
100 	    && ((winPtr->geomMgrPtr != mgrPtr)
101 		|| (winPtr->geomData != clientData))
102 	    && (winPtr->geomMgrPtr->lostSlaveProc != NULL)) {
103 	(*winPtr->geomMgrPtr->lostSlaveProc)(winPtr->geomData, tkwin);
104     }
105 
106     winPtr->geomMgrPtr = mgrPtr;
107     winPtr->geomData = clientData;
108 }
109 
110 /*
111  *--------------------------------------------------------------
112  *
113  * Tk_GeometryRequest --
114  *
115  *	This procedure is invoked by widget code to indicate
116  *	its preferences about the size of a window it manages.
117  *	In general, widget code should call this procedure
118  *	rather than Tk_ResizeWindow.
119  *
120  * Results:
121  *	None.
122  *
123  * Side effects:
124  *	The geometry manager for tkwin (if any) is invoked to
125  *	handle the request.  If possible, it will reconfigure
126  *	tkwin and/or other windows to satisfy the request.  The
127  *	caller gets no indication of success or failure, but it
128  *	will get X events if the window size was actually
129  *	changed.
130  *
131  *--------------------------------------------------------------
132  */
133 
134 void
Tk_GeometryRequest(tkwin,reqWidth,reqHeight)135 Tk_GeometryRequest(tkwin, reqWidth, reqHeight)
136     Tk_Window tkwin;		/* Window that geometry information
137 				 * pertains to. */
138     int reqWidth, reqHeight;	/* Minimum desired dimensions for
139 				 * window, in pixels. */
140 {
141     register TkWindow *winPtr = (TkWindow *) tkwin;
142 
143     /*
144      * X gets very upset if a window requests a width or height of
145      * zero, so rounds requested sizes up to at least 1.
146      */
147 
148     if (reqWidth <= 0) {
149 	reqWidth = 1;
150     }
151     if (reqHeight <= 0) {
152 	reqHeight = 1;
153     }
154     if ((reqWidth == winPtr->reqWidth) && (reqHeight == winPtr->reqHeight)) {
155 	return;
156     }
157     winPtr->reqWidth = reqWidth;
158     winPtr->reqHeight = reqHeight;
159     if ((winPtr->geomMgrPtr != NULL)
160 	    && (winPtr->geomMgrPtr->requestProc != NULL)) {
161 	(*winPtr->geomMgrPtr->requestProc)(winPtr->geomData, tkwin);
162     }
163 }
164 
165 /*
166  *----------------------------------------------------------------------
167  *
168  * Tk_SetInternalBorderEx --
169  *
170  *	Notify relevant geometry managers that a window has an internal
171  *	border of a given width and that child windows should not be
172  *	placed on that border.
173  *
174  * Results:
175  *	None.
176  *
177  * Side effects:
178  *	The border widths are recorded for the window, and all geometry
179  *	managers of all children are notified so that can re-layout, if
180  *	necessary.
181  *
182  *----------------------------------------------------------------------
183  */
184 
185 void
Tk_SetInternalBorderEx(tkwin,left,right,top,bottom)186 Tk_SetInternalBorderEx(tkwin, left, right, top, bottom)
187     Tk_Window tkwin;		/* Window that will have internal border. */
188     int left, right;		/* Width of internal border, in pixels. */
189     int top, bottom;
190 {
191     register TkWindow *winPtr = (TkWindow *) tkwin;
192     register int changed = 0;
193 
194     if (left < 0) {
195 	left = 0;
196     }
197     if (left != winPtr->internalBorderLeft) {
198 	winPtr->internalBorderLeft = left;
199 	changed = 1;
200     }
201 
202     if (right < 0) {
203 	right = 0;
204     }
205     if (right != winPtr->internalBorderRight) {
206 	winPtr->internalBorderRight = right;
207 	changed = 1;
208     }
209 
210     if (top < 0) {
211 	top = 0;
212     }
213     if (top != winPtr->internalBorderTop) {
214 	winPtr->internalBorderTop = top;
215 	changed = 1;
216     }
217 
218     if (bottom < 0) {
219 	bottom = 0;
220     }
221     if (bottom != winPtr->internalBorderBottom) {
222 	winPtr->internalBorderBottom = bottom;
223 	changed = 1;
224     }
225 
226     /*
227      * All the slaves for which this is the master window must now be
228      * repositioned to take account of the new internal border width.
229      * To signal all the geometry managers to do this, just resize the
230      * window to its current size.  The ConfigureNotify event will
231      * cause geometry managers to recompute everything.
232      */
233 
234     if (changed) {
235 	Tk_ResizeWindow(tkwin, Tk_Width(tkwin), Tk_Height(tkwin));
236     }
237 }
238 /*
239  *----------------------------------------------------------------------
240  *
241  * Tk_SetInternalBorder --
242  *
243  *	Notify relevant geometry managers that a window has an internal
244  *	border of a given width and that child windows should not be
245  *	placed on that border.
246  *
247  * Results:
248  *	None.
249  *
250  * Side effects:
251  *	The border width is recorded for the window, and all geometry
252  *	managers of all children are notified so that can re-layout, if
253  *	necessary.
254  *
255  *----------------------------------------------------------------------
256  */
257 
258 void
Tk_SetInternalBorder(tkwin,width)259 Tk_SetInternalBorder(tkwin, width)
260     Tk_Window tkwin;		/* Window that will have internal border. */
261     int width;			/* Width of internal border, in pixels. */
262 {
263     Tk_SetInternalBorderEx(tkwin, width, width, width, width);
264 }
265 
266 /*
267  *----------------------------------------------------------------------
268  *
269  * Tk_SetMinimumRequestSize --
270  *
271  *	Notify relevant geometry managers that a window has a minimum
272  *	request size.
273  *
274  * Results:
275  *	None.
276  *
277  * Side effects:
278  *	The minimum request size is recorded for the window, and
279  *      a new size is requested for the window, if necessary.
280  *
281  *----------------------------------------------------------------------
282  */
283 
284 void
Tk_SetMinimumRequestSize(tkwin,minWidth,minHeight)285 Tk_SetMinimumRequestSize(tkwin, minWidth, minHeight)
286     Tk_Window tkwin;		/* Window that will have internal border. */
287     int minWidth, minHeight;	/* Minimum requested size, in pixels. */
288 {
289     register TkWindow *winPtr = (TkWindow *) tkwin;
290 
291     if ((winPtr->minReqWidth == minWidth) &&
292 	    (winPtr->minReqHeight == minHeight)) {
293 	return;
294     }
295 
296     winPtr->minReqWidth = minWidth;
297     winPtr->minReqHeight = minHeight;
298 
299     /*
300      * The changed min size may cause geometry managers to get a
301      * different result, so make them recompute.
302      * To signal all the geometry managers to do this, just resize the
303      * window to its current size.  The ConfigureNotify event will
304      * cause geometry managers to recompute everything.
305      */
306 
307     Tk_ResizeWindow(tkwin, Tk_Width(tkwin), Tk_Height(tkwin));
308 }
309 
310 /*
311  *----------------------------------------------------------------------
312  *
313  * Tk_MaintainGeometry --
314  *
315  *	This procedure is invoked by geometry managers to handle slaves
316  *	whose master's are not their parents.  It translates the desired
317  *	geometry for the slave into the coordinate system of the parent
318  *	and respositions the slave if it isn't already at the right place.
319  *	Furthermore, it sets up event handlers so that if the master (or
320  *	any of its ancestors up to the slave's parent) is mapped, unmapped,
321  *	or moved, then the slave will be adjusted to match.
322  *
323  * Results:
324  *	None.
325  *
326  * Side effects:
327  *	Event handlers are created and state is allocated to keep track
328  *	of slave.  Note:  if slave was already managed for master by
329  *	Tk_MaintainGeometry, then the previous information is replaced
330  *	with the new information.  The caller must eventually call
331  *	Tk_UnmaintainGeometry to eliminate the correspondence (or, the
332  *	state is automatically freed when either window is destroyed).
333  *
334  *----------------------------------------------------------------------
335  */
336 
337 void
Tk_MaintainGeometry(slave,master,x,y,width,height)338 Tk_MaintainGeometry(slave, master, x, y, width, height)
339     Tk_Window slave;		/* Slave for geometry management. */
340     Tk_Window master;		/* Master for slave; must be a descendant
341 				 * of slave's parent. */
342     int x, y;			/* Desired position of slave within master. */
343     int width, height;		/* Desired dimensions for slave. */
344 {
345     Tcl_HashEntry *hPtr;
346     MaintainMaster *masterPtr;
347     register MaintainSlave *slavePtr;
348     int new, map;
349     Tk_Window ancestor, parent;
350     TkDisplay *dispPtr = ((TkWindow *) master)->dispPtr;
351 
352     if (master == Tk_Parent(slave)) {
353 	/*
354 	 * If the slave is a direct descendant of the master, don't bother
355 	 * setting up the extra infrastructure for management, just make a
356 	 * call to Tk_MoveResizeWindow; the parent/child relationship will
357 	 * take care of the rest.
358 	 */
359 	Tk_MoveResizeWindow(slave, x, y, width, height);
360 
361 	/*
362 	 * Map the slave if the master is already mapped; otherwise, wait
363 	 * until the master is mapped later (in which case mapping the slave
364 	 * is taken care of elsewhere).
365 	 */
366 	if (Tk_IsMapped(master)) {
367 	    Tk_MapWindow(slave);
368 	}
369 	return;
370     }
371 
372     if (!dispPtr->geomInit) {
373 	dispPtr->geomInit = 1;
374 	Tcl_InitHashTable(&dispPtr->maintainHashTable, TCL_ONE_WORD_KEYS);
375     }
376 
377     /*
378      * See if there is already a MaintainMaster structure for the master;
379      * if not, then create one.
380      */
381 
382     parent = Tk_Parent(slave);
383     hPtr = Tcl_CreateHashEntry(&dispPtr->maintainHashTable,
384             (char *) master, &new);
385     if (!new) {
386 	masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr);
387     } else {
388 	masterPtr = (MaintainMaster *) ckalloc(sizeof(MaintainMaster));
389 	masterPtr->ancestor = master;
390 	masterPtr->checkScheduled = 0;
391 	masterPtr->slavePtr = NULL;
392 	Tcl_SetHashValue(hPtr, masterPtr);
393     }
394 
395     /*
396      * Create a MaintainSlave structure for the slave if there isn't
397      * already one.
398      */
399 
400     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
401 	    slavePtr = slavePtr->nextPtr) {
402 	if (slavePtr->slave == slave) {
403 	    goto gotSlave;
404 	}
405     }
406     slavePtr = (MaintainSlave *) ckalloc(sizeof(MaintainSlave));
407     slavePtr->slave = slave;
408     slavePtr->master = master;
409     slavePtr->nextPtr = masterPtr->slavePtr;
410     masterPtr->slavePtr = slavePtr;
411     Tk_CreateEventHandler(slave, StructureNotifyMask, MaintainSlaveProc,
412 	    (ClientData) slavePtr);
413 
414     /*
415      * Make sure that there are event handlers registered for all
416      * the windows between master and slave's parent (including master
417      * but not slave's parent).  There may already be handlers for master
418      * and some of its ancestors (masterPtr->ancestor tells how many).
419      */
420 
421     for (ancestor = master; ancestor != parent;
422 	    ancestor = Tk_Parent(ancestor)) {
423 	if (ancestor == masterPtr->ancestor) {
424 	    Tk_CreateEventHandler(ancestor, StructureNotifyMask,
425 		    MaintainMasterProc, (ClientData) masterPtr);
426 	    masterPtr->ancestor = Tk_Parent(ancestor);
427 	}
428     }
429 
430     /*
431      * Fill in up-to-date information in the structure, then update the
432      * window if it's not currently in the right place or state.
433      */
434 
435     gotSlave:
436     slavePtr->x = x;
437     slavePtr->y = y;
438     slavePtr->width = width;
439     slavePtr->height = height;
440     map = 1;
441     for (ancestor = slavePtr->master; ; ancestor = Tk_Parent(ancestor)) {
442 	if (!Tk_IsMapped(ancestor) && (ancestor != parent)) {
443 	    map = 0;
444 	}
445 	if (ancestor == parent) {
446 	    if ((x != Tk_X(slavePtr->slave))
447 		    || (y != Tk_Y(slavePtr->slave))
448 		    || (width != Tk_Width(slavePtr->slave))
449 		    || (height != Tk_Height(slavePtr->slave))) {
450 		Tk_MoveResizeWindow(slavePtr->slave, x, y, width, height);
451 	    }
452 	    if (map) {
453 		Tk_MapWindow(slavePtr->slave);
454 	    } else {
455 		Tk_UnmapWindow(slavePtr->slave);
456 	    }
457 	    break;
458 	}
459 	x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
460 	y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
461     }
462 }
463 
464 /*
465  *----------------------------------------------------------------------
466  *
467  * Tk_UnmaintainGeometry --
468  *
469  *	This procedure cancels a previous Tk_MaintainGeometry call,
470  *	so that the relationship between slave and master is no longer
471  *	maintained.
472  *
473  * Results:
474  *	None.
475  *
476  * Side effects:
477  *	The slave is unmapped and state is released, so that slave won't
478  *	track master any more.  If we weren't previously managing slave
479  *	relative to master, then this procedure has no effect.
480  *
481  *----------------------------------------------------------------------
482  */
483 
484 void
Tk_UnmaintainGeometry(slave,master)485 Tk_UnmaintainGeometry(slave, master)
486     Tk_Window slave;		/* Slave for geometry management. */
487     Tk_Window master;		/* Master for slave; must be a descendant
488 				 * of slave's parent. */
489 {
490     Tcl_HashEntry *hPtr;
491     MaintainMaster *masterPtr;
492     register MaintainSlave *slavePtr, *prevPtr;
493     Tk_Window ancestor;
494     TkDisplay *dispPtr = ((TkWindow *) slave)->dispPtr;
495 
496     if (master == Tk_Parent(slave)) {
497 	/*
498 	 * If the slave is a direct descendant of the master,
499 	 * Tk_MaintainGeometry will not have set up any of the extra
500 	 * infrastructure.  Don't even bother to look for it, just return.
501 	 */
502 	return;
503     }
504 
505     if (!dispPtr->geomInit) {
506 	dispPtr->geomInit = 1;
507 	Tcl_InitHashTable(&dispPtr->maintainHashTable, TCL_ONE_WORD_KEYS);
508     }
509 
510     if (!(((TkWindow *) slave)->flags & TK_ALREADY_DEAD)) {
511 	Tk_UnmapWindow(slave);
512     }
513     hPtr = Tcl_FindHashEntry(&dispPtr->maintainHashTable, (char *) master);
514     if (hPtr == NULL) {
515 	return;
516     }
517     masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr);
518     slavePtr = masterPtr->slavePtr;
519     if (slavePtr->slave == slave) {
520 	masterPtr->slavePtr = slavePtr->nextPtr;
521     } else {
522 	for (prevPtr = slavePtr, slavePtr = slavePtr->nextPtr; ;
523 		prevPtr = slavePtr, slavePtr = slavePtr->nextPtr) {
524 	    if (slavePtr == NULL) {
525 		return;
526 	    }
527 	    if (slavePtr->slave == slave) {
528 		prevPtr->nextPtr = slavePtr->nextPtr;
529 		break;
530 	    }
531 	}
532     }
533     Tk_DeleteEventHandler(slavePtr->slave, StructureNotifyMask,
534 	    MaintainSlaveProc, (ClientData) slavePtr);
535     ckfree((char *) slavePtr);
536     if (masterPtr->slavePtr == NULL) {
537 	if (masterPtr->ancestor != NULL) {
538 	    for (ancestor = master; ; ancestor = Tk_Parent(ancestor)) {
539 		Tk_DeleteEventHandler(ancestor, StructureNotifyMask,
540 			MaintainMasterProc, (ClientData) masterPtr);
541 		if (ancestor == masterPtr->ancestor) {
542 		    break;
543 		}
544 	    }
545 	}
546 	if (masterPtr->checkScheduled) {
547 	    Tcl_CancelIdleCall(MaintainCheckProc, (ClientData) masterPtr);
548 	}
549 	Tcl_DeleteHashEntry(hPtr);
550 	ckfree((char *) masterPtr);
551     }
552 }
553 
554 /*
555  *----------------------------------------------------------------------
556  *
557  * MaintainMasterProc --
558  *
559  *	This procedure is invoked by the Tk event dispatcher in
560  *	response to StructureNotify events on the master or one
561  *	of its ancestors, on behalf of Tk_MaintainGeometry.
562  *
563  * Results:
564  *	None.
565  *
566  * Side effects:
567  *	It schedules a call to MaintainCheckProc, which will eventually
568  *	caused the postions and mapped states to be recalculated for all
569  *	the maintained slaves of the master.  Or, if the master window is
570  *	being deleted then state is cleaned up.
571  *
572  *----------------------------------------------------------------------
573  */
574 
575 static void
MaintainMasterProc(clientData,eventPtr)576 MaintainMasterProc(clientData, eventPtr)
577     ClientData clientData;		/* Pointer to MaintainMaster structure
578 					 * for the master window. */
579     XEvent *eventPtr;			/* Describes what just happened. */
580 {
581     MaintainMaster *masterPtr = (MaintainMaster *) clientData;
582     MaintainSlave *slavePtr;
583     int done;
584 
585     if ((eventPtr->type == ConfigureNotify)
586 	    || (eventPtr->type == MapNotify)
587 	    || (eventPtr->type == UnmapNotify)) {
588 	if (!masterPtr->checkScheduled) {
589 	    masterPtr->checkScheduled = 1;
590 	    Tcl_DoWhenIdle(MaintainCheckProc, (ClientData) masterPtr);
591 	}
592     } else if (eventPtr->type == DestroyNotify) {
593 	/*
594 	 * Delete all of the state associated with this master, but
595 	 * be careful not to use masterPtr after the last slave is
596 	 * deleted, since its memory will have been freed.
597 	 */
598 
599 	done = 0;
600 	do {
601 	    slavePtr = masterPtr->slavePtr;
602 	    if (slavePtr->nextPtr == NULL) {
603 		done = 1;
604 	    }
605 	    Tk_UnmaintainGeometry(slavePtr->slave, slavePtr->master);
606 	} while (!done);
607     }
608 }
609 
610 /*
611  *----------------------------------------------------------------------
612  *
613  * MaintainSlaveProc --
614  *
615  *	This procedure is invoked by the Tk event dispatcher in
616  *	response to StructureNotify events on a slave being managed
617  *	by Tk_MaintainGeometry.
618  *
619  * Results:
620  *	None.
621  *
622  * Side effects:
623  *	If the event is a DestroyNotify event then the Maintain state
624  *	and event handlers for this slave are deleted.
625  *
626  *----------------------------------------------------------------------
627  */
628 
629 static void
MaintainSlaveProc(clientData,eventPtr)630 MaintainSlaveProc(clientData, eventPtr)
631     ClientData clientData;		/* Pointer to MaintainSlave structure
632 					 * for master-slave pair. */
633     XEvent *eventPtr;			/* Describes what just happened. */
634 {
635     MaintainSlave *slavePtr = (MaintainSlave *) clientData;
636 
637     if (eventPtr->type == DestroyNotify) {
638 	Tk_UnmaintainGeometry(slavePtr->slave, slavePtr->master);
639     }
640 }
641 
642 /*
643  *----------------------------------------------------------------------
644  *
645  * MaintainCheckProc --
646  *
647  *	This procedure is invoked by the Tk event dispatcher as an
648  *	idle handler, when a master or one of its ancestors has been
649  *	reconfigured, mapped, or unmapped.  Its job is to scan all of
650  *	the slaves for the master and reposition them, map them, or
651  *	unmap them as needed to maintain their geometry relative to
652  *	the master.
653  *
654  * Results:
655  *	None.
656  *
657  * Side effects:
658  *	Slaves can get repositioned, mapped, or unmapped.
659  *
660  *----------------------------------------------------------------------
661  */
662 
663 static void
MaintainCheckProc(clientData)664 MaintainCheckProc(clientData)
665     ClientData clientData;		/* Pointer to MaintainMaster structure
666 					 * for the master window. */
667 {
668     MaintainMaster *masterPtr = (MaintainMaster *) clientData;
669     MaintainSlave *slavePtr;
670     Tk_Window ancestor, parent;
671     int x, y, map;
672 
673     masterPtr->checkScheduled = 0;
674     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
675 	    slavePtr = slavePtr->nextPtr) {
676 	parent = Tk_Parent(slavePtr->slave);
677 	x = slavePtr->x;
678 	y = slavePtr->y;
679 	map = 1;
680 	for (ancestor = slavePtr->master; ; ancestor = Tk_Parent(ancestor)) {
681 	    if (!Tk_IsMapped(ancestor) && (ancestor != parent)) {
682 		map = 0;
683 	    }
684 	    if (ancestor == parent) {
685 		if ((x != Tk_X(slavePtr->slave))
686 			|| (y != Tk_Y(slavePtr->slave))) {
687 		    Tk_MoveWindow(slavePtr->slave, x, y);
688 		}
689 		if (map) {
690 		    Tk_MapWindow(slavePtr->slave);
691 		} else {
692 		    Tk_UnmapWindow(slavePtr->slave);
693 		}
694 		break;
695 	    }
696 	    x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
697 	    y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
698 	}
699     }
700 }
701