tkGeometry.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
源码类别:

通讯编程

开发平台:

Visual C++

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