home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tk42r2s.zip / tk4.2 / os2 / tkOS2Wm.c < prev    next >
C/C++ Source or Header  |  1999-07-27  |  103KB  |  3,309 lines

  1. /* 
  2.  * tkOS2Wm.c --
  3.  *
  4.  *    This module takes care of the interactions between a Tk-based
  5.  *    application and the window manager.  Among other things, it
  6.  *    implements the "wm" command and passes geometry information
  7.  *    to the window manager.
  8.  *
  9.  * Copyright (c) 1996-1998 Illya Vaes
  10.  * Copyright (c) 1995 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16.  
  17. #include "tkOS2Int.h"
  18.  
  19. extern Tcl_HashTable windowTable;
  20.                                 /* Table of child windows indexed by handle. */
  21.  
  22. /*
  23.  * This module keeps a list of all top-level windows.
  24.  */
  25.  
  26. static WmInfo *firstWmPtr = NULL;    /* Points to first top-level window. */
  27. static WmInfo *foregroundWmPtr = NULL;    /* Points to the foreground window. */
  28.  
  29. /*
  30.  * The variable below is used to enable or disable tracing in this
  31.  * module.  If tracing is enabled, then information is printed on
  32.  * standard output about interesting interactions with the window
  33.  * manager.
  34.  */
  35.  
  36. static int wmTracing = 0;
  37.  
  38. /*
  39.  * The following structure is the official type record for geometry
  40.  * management of top-level windows.
  41.  */
  42.  
  43. static void        TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
  44.                                                     Tk_Window tkwin));
  45.  
  46. static Tk_GeomMgr wmMgrType = {
  47.     "wm",                /* name */
  48.     TopLevelReqProc,            /* requestProc */
  49.     (Tk_GeomLostSlaveProc *) NULL,    /* lostSlaveProc */
  50. };
  51.  
  52. /*
  53.  * Global system palette.  This value always refers to the currently
  54.  * installed foreground logical palette.
  55.  */
  56.  
  57. static HPAL systemPalette = NULLHANDLE;
  58.  
  59. /*
  60.  * This flag is cleared when the first window is mapped in a non-iconic
  61.  * state.
  62.  */
  63.  
  64. static int firstWindow = 1;
  65.  
  66. /*
  67.  * Forward declarations for procedures defined in this file:
  68.  */
  69.  
  70. static void    DeiconifyWindow _ANSI_ARGS_((TkWindow *winPtr));
  71. static void     GetMaxSize _ANSI_ARGS_((WmInfo *wmPtr, int *maxWidthPtr,
  72.                     int *maxHeightPtr));
  73. static void     GetMinSize _ANSI_ARGS_((WmInfo *wmPtr, int *minWidthPtr,
  74.                     int *minHeightPtr));
  75. static void    IconifyWindow _ANSI_ARGS_((TkWindow *winPtr));
  76. static void     InvalidateSubTree _ANSI_ARGS_((TkWindow *winPtr,
  77.                     Colormap colormap));
  78. static int    ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp, char *string,
  79.                     TkWindow *winPtr));
  80. static void     RefreshColormap _ANSI_ARGS_((Colormap colormap));
  81. static void    TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
  82.                     XEvent *eventPtr));
  83. static void    TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
  84.                     Tk_Window tkwin));
  85. static void    UpdateGeometryInfo _ANSI_ARGS_((ClientData clientData));
  86.  
  87. /*
  88.  *----------------------------------------------------------------------
  89.  *
  90.  * TkOS2WmSetLimits --
  91.  *
  92.  *    Updates the minimum and maximum window size constraints.
  93.  *
  94.  * Results:
  95.  *    None.
  96.  *
  97.  * Side effects:
  98.  *    Changes the values of the info pointer to reflect the current
  99.  *    minimum and maximum size values.
  100.  *
  101.  *----------------------------------------------------------------------
  102.  */
  103.  
  104. void
  105. TkOS2WmSetLimits(hwnd, info)
  106.     HWND hwnd;
  107.     TRACKINFO *info;
  108. {
  109.     TkOS2Drawable *todPtr;
  110.     TkWindow *winPtr;
  111.     register WmInfo *wmPtr;
  112.     int maxWidth, maxHeight;
  113.     int minWidth, minHeight;
  114.     int base;
  115.  
  116.     /*
  117.      * Get the window from the user data slot.
  118.      */
  119.  
  120.     todPtr = (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
  121.     winPtr = TkOS2GetWinPtr(todPtr);
  122.  
  123.     if (winPtr == NULL) {
  124.     return;
  125.     }
  126.  
  127.     wmPtr = winPtr->wmInfoPtr;
  128.     
  129.     /*
  130.      * Copy latest constraint info.
  131.      */
  132.  
  133.     wmPtr->defMinWidth = info->ptlMinTrackSize.x;
  134.     wmPtr->defMinHeight = info->ptlMinTrackSize.y;
  135.     wmPtr->defMaxWidth = info->ptlMaxTrackSize.x;
  136.     wmPtr->defMaxHeight = info->ptlMaxTrackSize.y;
  137.  
  138.     GetMaxSize(wmPtr, &maxWidth, &maxHeight);
  139.     GetMinSize(wmPtr, &minWidth, &minHeight);
  140.     
  141.     if (wmPtr->gridWin != NULL) {
  142.         base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
  143.         if (base < 0) {
  144.             base = 0;
  145.         }
  146.         base += wmPtr->borderWidth;
  147.         info->ptlMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
  148.         info->ptlMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
  149.  
  150.         base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
  151.         if (base < 0) {
  152.             base = 0;
  153.         }
  154.         base += wmPtr->borderHeight;
  155.         info->ptlMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
  156.         info->ptlMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
  157.     } else {
  158.         info->ptlMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
  159.         info->ptlMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
  160.         info->ptlMinTrackSize.x = minWidth + wmPtr->borderWidth;
  161.         info->ptlMinTrackSize.y = minHeight + wmPtr->borderHeight;
  162.     }
  163.  
  164.     /*
  165.      * If the window isn't supposed to be resizable, then set the
  166.      * minimum and maximum dimensions to be the same as the current size.
  167.      */
  168.  
  169.     if (!(wmPtr->flags & WM_SYNC_PENDING)) {
  170.         if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
  171.             info->ptlMinTrackSize.x = winPtr->changes.width +
  172.                                       wmPtr->borderWidth;
  173.             info->ptlMaxTrackSize.x = info->ptlMinTrackSize.x;
  174.         }
  175.         if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
  176.             info->ptlMinTrackSize.y = winPtr->changes.height +
  177.                                       wmPtr->borderHeight;
  178.             info->ptlMaxTrackSize.y = info->ptlMinTrackSize.y;
  179.         }
  180.     }
  181. }
  182.  
  183. /*
  184.  *--------------------------------------------------------------
  185.  *
  186.  * TkWmNewWindow --
  187.  *
  188.  *    This procedure is invoked whenever a new top-level
  189.  *    window is created.  Its job is to initialize the WmInfo
  190.  *    structure for the window.
  191.  *
  192.  * Results:
  193.  *    None.
  194.  *
  195.  * Side effects:
  196.  *    A WmInfo structure gets allocated and initialized.
  197.  *
  198.  *--------------------------------------------------------------
  199.  */
  200.  
  201. void
  202. TkWmNewWindow(winPtr)
  203.     TkWindow *winPtr;        /* Newly-created top-level window. */
  204. {
  205.     register WmInfo *wmPtr;
  206.  
  207.     wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
  208.     winPtr->wmInfoPtr = wmPtr;
  209.     wmPtr->winPtr = winPtr;
  210.     wmPtr->reparent = None;
  211.     wmPtr->titleUid = NULL;
  212.     wmPtr->iconName = NULL;
  213.     wmPtr->master = None;
  214.     wmPtr->hints.flags = InputHint | StateHint;
  215.     wmPtr->hints.input = True;
  216.     wmPtr->hints.initial_state = NormalState;
  217.     wmPtr->hints.icon_pixmap = None;
  218.     wmPtr->hints.icon_window = None;
  219.     wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
  220.     wmPtr->hints.icon_mask = None;
  221.     wmPtr->hints.window_group = None;
  222.     wmPtr->leaderName = NULL;
  223.     wmPtr->masterWindowName = NULL;
  224.     wmPtr->icon = NULL;
  225.     wmPtr->iconFor = NULL;
  226.     wmPtr->withdrawn = 0;
  227.     wmPtr->sizeHintsFlags = 0;
  228.  
  229.     /*
  230.      * Default the maximum dimensions to the size of the display.
  231.      */
  232.  
  233.     wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
  234.     wmPtr->defMaxWidth = DisplayWidth(winPtr->display,
  235.             winPtr->screenNum);
  236.     wmPtr->defMaxHeight = DisplayHeight(winPtr->display,
  237.             winPtr->screenNum);
  238.     wmPtr->minWidth = wmPtr->minHeight = 1;
  239.     wmPtr->maxWidth = wmPtr->maxHeight = 0;
  240.     wmPtr->gridWin = NULL;
  241.     wmPtr->widthInc = wmPtr->heightInc = 1;
  242.     wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
  243.     wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
  244.     wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
  245.     wmPtr->gravity = NorthWestGravity;
  246.     wmPtr->width = -1;
  247.     wmPtr->height = -1;
  248.     wmPtr->style = WM_TOPLEVEL_STYLE;
  249.     wmPtr->exStyle = EX_TOPLEVEL_STYLE;
  250.     wmPtr->x = winPtr->changes.x;
  251.     wmPtr->y = winPtr->changes.y;
  252.  
  253.     wmPtr->borderWidth = -1;
  254.     wmPtr->borderHeight = -1;
  255.     wmPtr->xInParent = 0;
  256.     wmPtr->yInParent = 0;
  257.  
  258.     wmPtr->cmapList = NULL;
  259.     wmPtr->cmapCount = 0;
  260.  
  261.     wmPtr->configWidth = -1;
  262.     wmPtr->configHeight = -1;
  263.     wmPtr->protPtr = NULL;
  264.     wmPtr->cmdArgv = NULL;
  265.     wmPtr->clientMachine = NULL;
  266.     wmPtr->flags = WM_NEVER_MAPPED;
  267.     wmPtr->nextPtr = firstWmPtr;
  268.     firstWmPtr = wmPtr;
  269.  
  270.     /*
  271.      * Tk must monitor structure events for top-level windows, in order
  272.      * to detect size and position changes caused by window managers.
  273.      */
  274.  
  275.     Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
  276.         TopLevelEventProc, (ClientData) winPtr);
  277.  
  278.     /*
  279.      * Arrange for geometry requests to be reflected from the window
  280.      * to the window manager.
  281.      */
  282.  
  283.     Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
  284. }
  285.  
  286. /*
  287.  *--------------------------------------------------------------
  288.  *
  289.  * TkWmMapWindow --
  290.  *
  291.  *    This procedure is invoked to map a top-level window.  This
  292.  *    module gets a chance to update all window-manager-related
  293.  *    information in properties before the window manager sees
  294.  *    the map event and checks the properties.  It also gets to
  295.  *    decide whether or not to even map the window after all.
  296.  *
  297.  * Results:
  298.  *    None.
  299.  *
  300.  * Side effects:
  301.  *    Properties of winPtr may get updated to provide up-to-date
  302.  *    information to the window manager.  The window may also get
  303.  *    mapped, but it may not be if this procedure decides that
  304.  *    isn't appropriate (e.g. because the window is withdrawn).
  305.  *
  306.  *--------------------------------------------------------------
  307.  */
  308.  
  309. void
  310. TkWmMapWindow(winPtr)
  311.     TkWindow *winPtr;        /* Top-level window that's about to
  312.                  * be mapped. */
  313. {
  314.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  315.     XEvent event;
  316.     BOOL ret;
  317.     HWND child = TkOS2GetHWND(winPtr->window);
  318.  
  319.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  320.     int x, y, width, height;
  321.     TkOS2Drawable *parentPtr;
  322.     HWND frame = NULLHANDLE;
  323.         FRAMECDATA fcdata;
  324.         LONG yPos;
  325.         Tcl_HashEntry *hPtr;
  326.         int new;
  327.  
  328.     wmPtr->flags &= ~WM_NEVER_MAPPED;
  329.  
  330.     /*
  331.      * This is the first time this window has ever been mapped.
  332.      * Store all the window-manager-related information for the
  333.      * window.
  334.      */
  335.  
  336.     if (wmPtr->titleUid == NULL) {
  337.         wmPtr->titleUid = winPtr->nameUid;
  338.     }
  339.  
  340.     /*
  341.          * Pick the decorative frame style.  Override redirect windows get
  342.          * created as undecorated popups.  Transient windows get a modal dialog
  343.          * frame.  Neither override, nor transient windows appear in the
  344.          * tasklist.
  345.      */
  346.     
  347.     if (winPtr->atts.override_redirect) {
  348.         wmPtr->style = WM_OVERRIDE_STYLE;
  349.         wmPtr->exStyle = EX_OVERRIDE_STYLE;
  350.     } else if (wmPtr->master) {
  351.             wmPtr->style = WM_TRANSIENT_STYLE;
  352.             wmPtr->exStyle = EX_TRANSIENT_STYLE;
  353.             frame = TkOS2GetHWND(wmPtr->master);
  354.     } else {
  355.         wmPtr->style = WM_TOPLEVEL_STYLE;
  356.         wmPtr->exStyle = EX_TOPLEVEL_STYLE;
  357.     }
  358.  
  359.         /*
  360.          * If the window is supposed to be visible, we need to create it
  361.          * in that state.  Otherwise we won't get the proper defaulting
  362.          * behavior for the initial position.
  363.          */
  364.  
  365.         if (wmPtr->hints.initial_state == NormalState) {
  366.             wmPtr->style |= WS_VISIBLE;
  367.         }
  368.  
  369.         /*
  370.          * Compute the border size and the location of the child window
  371.          * in the reparent window for the current window style.
  372.          * In OS/2, Y coordinates are from below, so y-in-parent is the same
  373.          * as the width of any decorative frame in the Y direction.
  374.          * In a similar fashion, x-in-parent is width of frame in X direction.
  375.          * The borderHeight and borderWidth are the sum of decorations in the
  376.          * Y (2 * frame + titlebar, if applicable) and X (2 * frame) directions.
  377.          */
  378.  
  379.         if (wmPtr->exStyle & FCF_SIZEBORDER) {
  380.             /* Size border */
  381.             wmPtr->xInParent = xSizeBorder;
  382.             wmPtr->yInParent = ySizeBorder;
  383.             wmPtr->borderWidth = 2 * xSizeBorder;
  384.             wmPtr->borderHeight = 2 * ySizeBorder;
  385.         } else if (wmPtr->exStyle & FCF_DLGBORDER) {
  386.             /* Dialog border */
  387.             wmPtr->xInParent = xDlgBorder;
  388.             wmPtr->yInParent = yDlgBorder;
  389.             wmPtr->borderWidth = 2 * xDlgBorder;
  390.             wmPtr->borderHeight = 2 * yDlgBorder;
  391.         } else if (wmPtr->exStyle & FCF_BORDER) {
  392.             /* Nominal border */
  393.             wmPtr->xInParent = xBorder;
  394.             wmPtr->yInParent = yBorder;
  395.             wmPtr->borderWidth = 2 * xBorder;
  396.             wmPtr->borderHeight = 2 * yBorder;
  397.         } else {
  398.             /* No border style */
  399.             wmPtr->xInParent = 0;
  400.             wmPtr->yInParent = 0;
  401.             wmPtr->borderWidth = 0;
  402.             wmPtr->borderHeight = 0;
  403.         }
  404.         yPos = wmPtr->yInParent;
  405.         if (wmPtr->exStyle & FCF_TITLEBAR) {
  406.             wmPtr->borderHeight += titleBar;
  407.         }
  408.  
  409.         /*
  410.          * Compute the geometry of the parent and child windows.
  411.          */
  412.  
  413.         wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
  414.         UpdateGeometryInfo((ClientData)winPtr);
  415.         wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
  416.  
  417.         width = wmPtr->borderWidth + winPtr->changes.width;
  418.         height = wmPtr->borderHeight + winPtr->changes.height;
  419.  
  420.         /*
  421.          * Set the initial position from the user or program specified
  422.          * location.  If nothing has been specified, then let the system
  423.          * pick a location.
  424.          */
  425.  
  426.         if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))) {
  427.             x = CW_USEDEFAULT;
  428.             y = CW_USEDEFAULT;
  429.             wmPtr->style |= FCF_SHELLPOSITION;
  430.         } else {
  431.             x = winPtr->changes.x;
  432.             y = winPtr->changes.y;
  433.         }
  434.  
  435.         /*
  436.          * Create the containing window.
  437.          */
  438.  
  439.         parentPtr = (TkOS2Drawable *) ckalloc(sizeof(TkOS2Drawable));
  440.         parentPtr->type = TOD_WM_WINDOW;
  441.         parentPtr->window.winPtr = winPtr;
  442.         wmPtr->reparent = (Window)parentPtr;
  443.  
  444.         fcdata.cb = sizeof(FRAMECDATA);
  445.         fcdata.flCreateFlags = (ULONG)wmPtr->exStyle;
  446.         fcdata.hmodResources = 0L;
  447.         fcdata.idResources = 0;
  448. #define ID_FRAME 1
  449.     frame  = WinCreateWindow(
  450.         HWND_DESKTOP,        /* Parent */
  451.         WC_FRAME,        /* Class */
  452.         wmPtr->titleUid,    /* Window text */
  453.         wmPtr->style,        /* Style */
  454.         x, yScreen - height - y,/* Initial X and Y coordinates */
  455.         width,            /* Width */
  456.         height,            /* Height */
  457.         NULLHANDLE,        /* Owner */
  458.         HWND_TOP,        /* Insertbehind (sibling) */
  459.         ID_FRAME,        /* Window ID */
  460.         &fcdata,    /* Ptr to control data */
  461.         NULL);            /* Ptr to presentation parameters */
  462.  
  463.         /* Force frame window to display the title bar, buttons, ... */
  464.         WinSendMsg(frame, WM_UPDATEFRAME, (MPARAM)0, (MPARAM)0);
  465.  
  466.         /* Subclass Frame window */
  467.         WinSetWindowULong(frame, QWL_USER, (ULONG)parentPtr);
  468.         oldFrameProc = WinSubclassWindow(frame, TkOS2FrameProc);
  469.  
  470.         /*
  471.          * Do WM_CREATE processing that wasn't possible because we couldn't
  472.          * subclass the window before its creation...
  473.          * Add the window and handle to the window table.
  474.          */
  475.  
  476.         parentPtr->window.handle = frame;
  477.         hPtr = Tcl_CreateHashEntry(&windowTable, (char *)frame, &new);
  478.         if (!new) {
  479.             panic("Duplicate window handle: %p", frame);
  480.         }
  481.         Tcl_SetHashValue(hPtr, parentPtr);
  482.  
  483.         /*
  484.          * Now we need to reparent the contained window and set its
  485.          * style appropriately.  Be sure to update the style first so that
  486.          * PM doesn't try to set the focus to the child window.
  487.          * PM windows are always children, no WS_CHILD
  488.          */
  489.  
  490.     ret= WinSetParent(child, frame, TRUE);
  491.         WinSetWindowPos(child, HWND_TOP, wmPtr->xInParent, wmPtr->yInParent,
  492.                   winPtr->changes.width, winPtr->changes.height,
  493.                   SWP_SIZE | SWP_MOVE | SWP_SHOW);
  494.  
  495.     /*
  496.      * Generate a reparent event.
  497.      */
  498.  
  499.     event.type = ReparentNotify;
  500.     winPtr->display->request++;
  501.     event.xreparent.serial = winPtr->display->request;
  502.     event.xreparent.send_event = False;
  503.     event.xreparent.display = winPtr->display;
  504.     event.xreparent.event = winPtr->window;
  505.     event.xreparent.window = winPtr->window;
  506.     event.xreparent.parent = wmPtr->reparent;
  507.     event.xreparent.x = wmPtr->xInParent;
  508.     event.xreparent.y = wmPtr->yInParent;
  509.     event.xreparent.override_redirect = winPtr->atts.override_redirect;
  510.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  511.     } else if (wmPtr->hints.initial_state == WithdrawnState) {
  512.     return;
  513.     } else {
  514.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  515.         Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  516.     }
  517.     UpdateGeometryInfo((ClientData) winPtr);
  518.  
  519.     /* If applicable, make visible in switch-list */
  520.         if (wmPtr->exStyle & FCF_TASKLIST) {
  521.             HSWITCH hSwitch;
  522.             SWCNTRL switchData;
  523.  
  524.             hSwitch = WinQuerySwitchHandle(TkOS2GetHWND(wmPtr->reparent), 0);
  525.             rc = WinQuerySwitchEntry(hSwitch, &switchData);
  526.             /* Set visibility on */
  527.             switchData.uchVisibility = SWL_VISIBLE;
  528.             rc = WinChangeSwitchEntry(hSwitch, &switchData);
  529.         }
  530.     }
  531.  
  532.     /*
  533.      * Map the window in either the iconified or normal state.  Note that
  534.      * we only send a map event if the window is in the normal state.
  535.      */
  536.     
  537.     if (wmPtr->hints.initial_state == IconicState) {
  538.     wmPtr->flags |= WM_SYNC_PENDING;
  539.     rc = WinSetWindowPos(TkOS2GetHWND(wmPtr->reparent), HWND_TOP,
  540.                          0, 0, 0, 0, SWP_MINIMIZE);
  541.     wmPtr->flags &= ~WM_SYNC_PENDING;
  542.  
  543.     /*
  544.      * Send an unmap event if we are iconifying a currently displayed
  545.      * window.
  546.      */
  547.  
  548.     if (!wmPtr->withdrawn) {
  549.         XUnmapWindow(winPtr->display, winPtr->window);
  550.     }
  551.     } else if (wmPtr->hints.initial_state == WithdrawnState) {
  552.     return;
  553.  
  554.     } else {
  555.     XMapWindow(winPtr->display, winPtr->window);
  556.  
  557.         /*
  558.          * If this is the first window displayed, be sure to activate it.
  559.          */
  560.  
  561.     wmPtr->flags |= WM_SYNC_PENDING;
  562.     /* Take care to also *raise* the window so we see it */
  563.         rc = WinSetWindowPos(TkOS2GetHWND(wmPtr->reparent), HWND_TOP,
  564.                              0, 0, 0, 0,
  565.                              SWP_RESTORE | SWP_SHOW | SWP_ZORDER);
  566.         if (firstWindow) {
  567.             rc = WinSetWindowPos(TkOS2GetHWND(wmPtr->reparent), HWND_TOP,
  568.                              0, 0, 0, 0, SWP_ACTIVATE);
  569.             firstWindow = 0;
  570.         }
  571.     wmPtr->flags &= ~WM_SYNC_PENDING;
  572.     }
  573. }
  574.  
  575. /*
  576.  *--------------------------------------------------------------
  577.  *
  578.  * TkWmUnmapWindow --
  579.  *
  580.  *    This procedure is invoked to unmap a top-level window.  The
  581.  *    only thing it does special is unmap the decorative frame before
  582.  *    unmapping the toplevel window.
  583.  *
  584.  * Results:
  585.  *    None.
  586.  *
  587.  * Side effects:
  588.  *    Unmaps the decorative frame and the window.
  589.  *
  590.  *--------------------------------------------------------------
  591.  */
  592.  
  593. void
  594. TkWmUnmapWindow(winPtr)
  595.     TkWindow *winPtr;        /* Top-level window that's about to
  596.                  * be unmapped. */
  597. {
  598.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  599.  
  600.     wmPtr->flags |= WM_SYNC_PENDING;
  601.     rc = WinShowWindow(TkOS2GetHWND(wmPtr->reparent), FALSE);
  602.  
  603.     /* If applicable, remove from task list */
  604.     if (wmPtr->exStyle & FCF_TASKLIST) {
  605.         HSWITCH hSwitch;
  606.         SWCNTRL switchData;
  607.         hSwitch = WinQuerySwitchHandle(TkOS2GetHWND(wmPtr->reparent), 0);
  608.         rc = WinQuerySwitchEntry(hSwitch, &switchData);
  609.         /* Set visibility off */
  610.         switchData.uchVisibility = SWL_INVISIBLE;
  611.         rc = WinChangeSwitchEntry(hSwitch, &switchData);
  612.     }
  613.  
  614.     wmPtr->flags &= ~WM_SYNC_PENDING;
  615.     XUnmapWindow(winPtr->display, winPtr->window);
  616. }
  617.  
  618. /*
  619.  *--------------------------------------------------------------
  620.  *
  621.  * TkWmDeadWindow --
  622.  *
  623.  *    This procedure is invoked when a top-level window is
  624.  *    about to be deleted.  It cleans up the wm-related data
  625.  *    structures for the window.
  626.  *
  627.  * Results:
  628.  *    None.
  629.  *
  630.  * Side effects:
  631.  *    The WmInfo structure for winPtr gets freed up.
  632.  *
  633.  *--------------------------------------------------------------
  634.  */
  635.  
  636. void
  637. TkWmDeadWindow(winPtr)
  638.     TkWindow *winPtr;        /* Top-level window that's being deleted. */
  639. {
  640.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  641.     WmInfo *wmPtr2;
  642.  
  643.     if (wmPtr == NULL) {
  644.     return;
  645.     }
  646.  
  647.     /*
  648.      * Clean up event related window info.
  649.      */
  650.  
  651.     if (firstWmPtr == wmPtr) {
  652.     firstWmPtr = wmPtr->nextPtr;
  653.     } else {
  654.     register WmInfo *prevPtr;
  655.  
  656.     for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
  657.         if (prevPtr == NULL) {
  658.         panic("couldn't unlink window in TkWmDeadWindow");
  659.         }
  660.         if (prevPtr->nextPtr == wmPtr) {
  661.         prevPtr->nextPtr = wmPtr->nextPtr;
  662.         break;
  663.         }
  664.     }
  665.     }
  666.     if (wmPtr->hints.flags & IconPixmapHint) {
  667.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  668.     }
  669.     if (wmPtr->hints.flags & IconMaskHint) {
  670.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  671.     }
  672.     if (wmPtr->icon != NULL) {
  673.     wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  674.     wmPtr2->iconFor = NULL;
  675.     wmPtr2->withdrawn = 1;
  676.     }
  677.     if (wmPtr->iconFor != NULL) {
  678.     wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
  679.     wmPtr2->icon = NULL;
  680.     wmPtr2->hints.flags &= ~IconWindowHint;
  681.     }
  682.     while (wmPtr->protPtr != NULL) {
  683.     ProtocolHandler *protPtr;
  684.  
  685.     protPtr = wmPtr->protPtr;
  686.     wmPtr->protPtr = protPtr->nextPtr;
  687.     Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  688.     }
  689.     if (wmPtr->cmdArgv != NULL) {
  690.     ckfree((char *) wmPtr->cmdArgv);
  691.     }
  692.     if (wmPtr->clientMachine != NULL) {
  693.     ckfree((char *) wmPtr->clientMachine);
  694.     }
  695.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  696.     Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  697.     }
  698.  
  699.     /*
  700.      * Destroy the decorative frame window.  Note that the back pointer
  701.      * to the child window must be cleared before calling WinDestroyWindow
  702.      * to avoid generating events on a window that is already dead.
  703.      * Note that we don't free the reparent here because it will be
  704.      * freed when the WM_DESTROY message is processed.
  705.      */
  706.  
  707.     if (wmPtr->reparent != None) {
  708.     ((TkOS2Drawable *) wmPtr->reparent)->window.winPtr = NULL;
  709.     WinDestroyWindow(TkOS2GetHWND(wmPtr->reparent));
  710.     }
  711.     ckfree((char *) wmPtr);
  712.     winPtr->wmInfoPtr = NULL;
  713. }
  714.  
  715. /*
  716.  *--------------------------------------------------------------
  717.  *
  718.  * TkWmSetClass --
  719.  *
  720.  *    This procedure is invoked whenever a top-level window's
  721.  *    class is changed.  If the window has been mapped then this
  722.  *    procedure updates the window manager property for the
  723.  *    class.  If the window hasn't been mapped, the update is
  724.  *    deferred until just before the first mapping.
  725.  *
  726.  * Results:
  727.  *    None.
  728.  *
  729.  * Side effects:
  730.  *    A window property may get updated.
  731.  *
  732.  *--------------------------------------------------------------
  733.  */
  734.  
  735. void
  736. TkWmSetClass(winPtr)
  737.     TkWindow *winPtr;        /* Newly-created top-level window. */
  738. {
  739.     return;
  740. }
  741.  
  742. /*
  743.  *----------------------------------------------------------------------
  744.  *
  745.  * Tk_WmCmd --
  746.  *
  747.  *    This procedure is invoked to process the "wm" Tcl command.
  748.  *    See the user documentation for details on what it does.
  749.  *
  750.  * Results:
  751.  *    A standard Tcl result.
  752.  *
  753.  * Side effects:
  754.  *    See the user documentation.
  755.  *
  756.  *----------------------------------------------------------------------
  757.  */
  758.  
  759.     /* ARGSUSED */
  760. int
  761. Tk_WmCmd(clientData, interp, argc, argv)
  762.     ClientData clientData;    /* Main window associated with
  763.                  * interpreter. */
  764.     Tcl_Interp *interp;        /* Current interpreter. */
  765.     int argc;            /* Number of arguments. */
  766.     char **argv;        /* Argument strings. */
  767. {
  768.     Tk_Window tkwin = (Tk_Window) clientData;
  769.     TkWindow *winPtr;
  770.     register WmInfo *wmPtr;
  771.     int c;
  772.     size_t length;
  773.  
  774.     if (argc < 2) {
  775.     wrongNumArgs:
  776.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  777.         argv[0], " option window ?arg ...?\"", (char *) NULL);
  778.     return TCL_ERROR;
  779.     }
  780.     c = argv[1][0];
  781.     length = strlen(argv[1]);
  782.     if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
  783.         && (length >= 3)) {
  784.     if ((argc != 2) && (argc != 3)) {
  785.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  786.             argv[0], " tracing ?boolean?\"", (char *) NULL);
  787.         return TCL_ERROR;
  788.     }
  789.     if (argc == 2) {
  790.         interp->result = (wmTracing) ? "on" : "off";
  791.         return TCL_OK;
  792.     }
  793.     return Tcl_GetBoolean(interp, argv[2], &wmTracing);
  794.     }
  795.  
  796.     if (argc < 3) {
  797.     goto wrongNumArgs;
  798.     }
  799.     winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
  800.     if (winPtr == NULL) {
  801.     return TCL_ERROR;
  802.     }
  803.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  804.     Tcl_AppendResult(interp, "window \"", winPtr->pathName,
  805.         "\" isn't a top-level window", (char *) NULL);
  806.     return TCL_ERROR;
  807.     }
  808.     wmPtr = winPtr->wmInfoPtr;
  809.     if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
  810.     int numer1, denom1, numer2, denom2;
  811.  
  812.     if ((argc != 3) && (argc != 7)) {
  813.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  814.             argv[0], " aspect window ?minNumer minDenom ",
  815.             "maxNumer maxDenom?\"", (char *) NULL);
  816.         return TCL_ERROR;
  817.     }
  818.     if (argc == 3) {
  819.         if (wmPtr->sizeHintsFlags & PAspect) {
  820.         sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
  821.             wmPtr->minAspect.y, wmPtr->maxAspect.x,
  822.             wmPtr->maxAspect.y);
  823.         }
  824.         return TCL_OK;
  825.     }
  826.     if (*argv[3] == '\0') {
  827.         wmPtr->sizeHintsFlags &= ~PAspect;
  828.     } else {
  829.         if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
  830.             || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
  831.             || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
  832.             || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
  833.         return TCL_ERROR;
  834.         }
  835.         if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
  836.             (denom2 <= 0)) {
  837.         interp->result = "aspect number can't be <= 0";
  838.         return TCL_ERROR;
  839.         }
  840.         wmPtr->minAspect.x = numer1;
  841.         wmPtr->minAspect.y = denom1;
  842.         wmPtr->maxAspect.x = numer2;
  843.         wmPtr->maxAspect.y = denom2;
  844.         wmPtr->sizeHintsFlags |= PAspect;
  845.     }
  846.     goto updateGeom;
  847.     } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
  848.         && (length >= 2)) {
  849.     if ((argc != 3) && (argc != 4)) {
  850.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  851.             argv[0], " client window ?name?\"",
  852.             (char *) NULL);
  853.         return TCL_ERROR;
  854.     }
  855.     if (argc == 3) {
  856.         if (wmPtr->clientMachine != NULL) {
  857.         interp->result = wmPtr->clientMachine;
  858.         }
  859.         return TCL_OK;
  860.     }
  861.     if (argv[3][0] == 0) {
  862.         if (wmPtr->clientMachine != NULL) {
  863.         ckfree((char *) wmPtr->clientMachine);
  864.         wmPtr->clientMachine = NULL;
  865.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  866.             XDeleteProperty(winPtr->display, winPtr->window,
  867.                 Tk_InternAtom((Tk_Window) winPtr,
  868.                 "WM_CLIENT_MACHINE"));
  869.         }
  870.         }
  871.         return TCL_OK;
  872.     }
  873.     if (wmPtr->clientMachine != NULL) {
  874.         ckfree((char *) wmPtr->clientMachine);
  875.     }
  876.     wmPtr->clientMachine = (char *)
  877.         ckalloc((unsigned) (strlen(argv[3]) + 1));
  878.     strcpy(wmPtr->clientMachine, argv[3]);
  879.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  880.         XTextProperty textProp;
  881.         if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
  882.             != 0) {
  883.         XSetWMClientMachine(winPtr->display, winPtr->window,
  884.             &textProp);
  885.         XFree((char *) textProp.value);
  886.         }
  887.     }
  888.     } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
  889.         && (length >= 3)) {
  890.     TkWindow **cmapList;
  891.     TkWindow *winPtr2;
  892.     int i, windowArgc, gotToplevel = 0;
  893.     char **windowArgv;
  894.  
  895.     if ((argc != 3) && (argc != 4)) {
  896.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  897.             argv[0], " colormapwindows window ?windowList?\"",
  898.             (char *) NULL);
  899.         return TCL_ERROR;
  900.     }
  901.     if (argc == 3) {
  902.         Tk_MakeWindowExist((Tk_Window) winPtr);
  903.         for (i = 0; i < wmPtr->cmapCount; i++) {
  904.         if ((i == (wmPtr->cmapCount-1))
  905.             && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
  906.             break;
  907.         }
  908.         Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
  909.         }
  910.         return TCL_OK;
  911.     }
  912.     if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
  913.         != TCL_OK) {
  914.         return TCL_ERROR;
  915.     }
  916.     cmapList = (TkWindow **) ckalloc((unsigned)
  917.         ((windowArgc+1)*sizeof(TkWindow*)));
  918.     for (i = 0; i < windowArgc; i++) {
  919.         winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
  920.             tkwin);
  921.         if (winPtr2 == NULL) {
  922.         ckfree((char *) cmapList);
  923.         ckfree((char *) windowArgv);
  924.         return TCL_ERROR;
  925.         }
  926.         if (winPtr2 == winPtr) {
  927.         gotToplevel = 1;
  928.         }
  929.         if (winPtr2->window == None) {
  930.         Tk_MakeWindowExist((Tk_Window) winPtr2);
  931.         }
  932.         cmapList[i] = winPtr2;
  933.     }
  934.     if (!gotToplevel) {
  935.         wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
  936.         cmapList[windowArgc] = winPtr;
  937.         windowArgc++;
  938.     } else {
  939.         wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
  940.     }
  941.     wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
  942.     if (wmPtr->cmapList != NULL) {
  943.         ckfree((char *)wmPtr->cmapList);
  944.     }
  945.     wmPtr->cmapList = cmapList;
  946.     wmPtr->cmapCount = windowArgc;
  947.     ckfree((char *) windowArgv);
  948.  
  949.     /*
  950.      * Now we need to force the updated colormaps to be installed.
  951.      */
  952.  
  953.         if (wmPtr == foregroundWmPtr) {
  954.             TkOS2WmInstallColormaps(TkOS2GetHWND(wmPtr->reparent),
  955.               /* WM_QUERYNEWPALETTE -> WM_REALIZEPALETTE + focus notification */
  956.                     WM_REALIZEPALETTE, 1);
  957.         } else {
  958.             if ((TkOS2Drawable *)wmPtr->reparent != (TkOS2Drawable *)NULL) {
  959.                 TkOS2WmInstallColormaps(TkOS2GetHWND(wmPtr->reparent),
  960.                /* WM_PALETTECHANGED -> WM_REALIZEPALETTE + focus notification */
  961.                                         WM_REALIZEPALETTE, 0);
  962.             }
  963.         }
  964.     return TCL_OK;
  965.     } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
  966.         && (length >= 3)) {
  967.     int cmdArgc;
  968.     char **cmdArgv;
  969.  
  970.     if ((argc != 3) && (argc != 4)) {
  971.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  972.             argv[0], " command window ?value?\"",
  973.             (char *) NULL);
  974.         return TCL_ERROR;
  975.     }
  976.     if (argc == 3) {
  977.         if (wmPtr->cmdArgv != NULL) {
  978.         interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
  979.         interp->freeProc = TCL_DYNAMIC;
  980.         }
  981.         return TCL_OK;
  982.     }
  983.     if (argv[3][0] == 0) {
  984.         if (wmPtr->cmdArgv != NULL) {
  985.         ckfree((char *) wmPtr->cmdArgv);
  986.         wmPtr->cmdArgv = NULL;
  987.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  988.             XDeleteProperty(winPtr->display, winPtr->window,
  989.                 Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
  990.         }
  991.         }
  992.         return TCL_OK;
  993.     }
  994.     if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
  995.         return TCL_ERROR;
  996.     }
  997.     if (wmPtr->cmdArgv != NULL) {
  998.         ckfree((char *) wmPtr->cmdArgv);
  999.     }
  1000.     wmPtr->cmdArgc = cmdArgc;
  1001.     wmPtr->cmdArgv = cmdArgv;
  1002.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1003.         XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
  1004.     }
  1005.     } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
  1006.     if (argc != 3) {
  1007.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1008.             argv[0], " deiconify window\"", (char *) NULL);
  1009.         return TCL_ERROR;
  1010.     }
  1011.     if (wmPtr->iconFor != NULL) {
  1012.         Tcl_AppendResult(interp, "can't deiconify ", argv[2],
  1013.             ": it is an icon for ", winPtr->pathName, (char *) NULL);
  1014.         return TCL_ERROR;
  1015.     }
  1016.     DeiconifyWindow(winPtr);
  1017.     } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
  1018.         && (length >= 2)) {
  1019.     if ((argc != 3) && (argc != 4)) {
  1020.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1021.             argv[0], " focusmodel window ?active|passive?\"",
  1022.             (char *) NULL);
  1023.         return TCL_ERROR;
  1024.     }
  1025.     if (argc == 3) {
  1026.         interp->result = wmPtr->hints.input ? "passive" : "active";
  1027.         return TCL_OK;
  1028.     }
  1029.     c = argv[3][0];
  1030.     length = strlen(argv[3]);
  1031.     if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
  1032.         wmPtr->hints.input = False;
  1033.     } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
  1034.         wmPtr->hints.input = True;
  1035.     } else {
  1036.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1037.             "\": must be active or passive", (char *) NULL);
  1038.         return TCL_ERROR;
  1039.     }
  1040.     } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
  1041.         && (length >= 2)) {
  1042.     Window window;
  1043.  
  1044.     if (argc != 3) {
  1045.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1046.             argv[0], " frame window\"", (char *) NULL);
  1047.         return TCL_ERROR;
  1048.     }
  1049.     window = wmPtr->reparent;
  1050.     if (window == None) {
  1051.         window = Tk_WindowId((Tk_Window) winPtr);
  1052.     }
  1053.     sprintf(interp->result, "0x%x", (unsigned int) window);
  1054.     } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
  1055.         && (length >= 2)) {
  1056.     char xSign, ySign;
  1057.     int width, height;
  1058.  
  1059.     if ((argc != 3) && (argc != 4)) {
  1060.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1061.             argv[0], " geometry window ?newGeometry?\"",
  1062.             (char *) NULL);
  1063.         return TCL_ERROR;
  1064.     }
  1065.     if (argc == 3) {
  1066.         xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
  1067.         ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
  1068.         if (wmPtr->gridWin != NULL) {
  1069.         width = wmPtr->reqGridWidth + (winPtr->changes.width
  1070.             - winPtr->reqWidth)/wmPtr->widthInc;
  1071.         height = wmPtr->reqGridHeight + (winPtr->changes.height
  1072.             - winPtr->reqHeight)/wmPtr->heightInc;
  1073.         } else {
  1074.         width = winPtr->changes.width;
  1075.         height = winPtr->changes.height;
  1076.         }
  1077.         sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
  1078.             xSign, wmPtr->x, ySign, wmPtr->y);
  1079.         return TCL_OK;
  1080.     }
  1081.     if (*argv[3] == '\0') {
  1082.         wmPtr->width = -1;
  1083.         wmPtr->height = -1;
  1084.         goto updateGeom;
  1085.     }
  1086.     return ParseGeometry(interp, argv[3], winPtr);
  1087.     } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
  1088.         && (length >= 3)) {
  1089.     int reqWidth, reqHeight, widthInc, heightInc;
  1090.  
  1091.     if ((argc != 3) && (argc != 7)) {
  1092.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1093.             argv[0], " grid window ?baseWidth baseHeight ",
  1094.             "widthInc heightInc?\"", (char *) NULL);
  1095.         return TCL_ERROR;
  1096.     }
  1097.     if (argc == 3) {
  1098.         if (wmPtr->sizeHintsFlags & PBaseSize) {
  1099.         sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
  1100.             wmPtr->reqGridHeight, wmPtr->widthInc,
  1101.             wmPtr->heightInc);
  1102.         }
  1103.         return TCL_OK;
  1104.     }
  1105.     if (*argv[3] == '\0') {
  1106.         /*
  1107.          * Turn off gridding and reset the width and height
  1108.          * to make sense as ungridded numbers.
  1109.          */
  1110.  
  1111.         wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  1112.         if (wmPtr->width != -1) {
  1113.         wmPtr->width = winPtr->reqWidth + (wmPtr->width
  1114.             - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1115.         wmPtr->height = winPtr->reqHeight + (wmPtr->height
  1116.             - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1117.         }
  1118.         wmPtr->widthInc = 1;
  1119.         wmPtr->heightInc = 1;
  1120.     } else {
  1121.         if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
  1122.             || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
  1123.             || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
  1124.             || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
  1125.         return TCL_ERROR;
  1126.         }
  1127.         if (reqWidth < 0) {
  1128.         interp->result = "baseWidth can't be < 0";
  1129.         return TCL_ERROR;
  1130.         }
  1131.         if (reqHeight < 0) {
  1132.         interp->result = "baseHeight can't be < 0";
  1133.         return TCL_ERROR;
  1134.         }
  1135.         if (widthInc < 0) {
  1136.         interp->result = "widthInc can't be < 0";
  1137.         return TCL_ERROR;
  1138.         }
  1139.         if (heightInc < 0) {
  1140.         interp->result = "heightInc can't be < 0";
  1141.         return TCL_ERROR;
  1142.         }
  1143.         Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
  1144.             heightInc);
  1145.     }
  1146.     goto updateGeom;
  1147.     } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
  1148.         && (length >= 3)) {
  1149.     Tk_Window tkwin2;
  1150.  
  1151.     if ((argc != 3) && (argc != 4)) {
  1152.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1153.             argv[0], " group window ?pathName?\"",
  1154.             (char *) NULL);
  1155.         return TCL_ERROR;
  1156.     }
  1157.     if (argc == 3) {
  1158.         if (wmPtr->hints.flags & WindowGroupHint) {
  1159.         interp->result = wmPtr->leaderName;
  1160.         }
  1161.         return TCL_OK;
  1162.     }
  1163.     if (*argv[3] == '\0') {
  1164.         wmPtr->hints.flags &= ~WindowGroupHint;
  1165.         wmPtr->leaderName = NULL;
  1166.     } else {
  1167.         tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
  1168.         if (tkwin2 == NULL) {
  1169.         return TCL_ERROR;
  1170.         }
  1171.         Tk_MakeWindowExist(tkwin2);
  1172.         wmPtr->hints.window_group = Tk_WindowId(tkwin2);
  1173.         wmPtr->hints.flags |= WindowGroupHint;
  1174.         wmPtr->leaderName = Tk_PathName(tkwin2);
  1175.     }
  1176.     } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
  1177.         && (length >= 5)) {
  1178.     Pixmap pixmap;
  1179.  
  1180.     if ((argc != 3) && (argc != 4)) {
  1181.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1182.             argv[0], " iconbitmap window ?bitmap?\"",
  1183.             (char *) NULL);
  1184.         return TCL_ERROR;
  1185.     }
  1186.     if (argc == 3) {
  1187.         if (wmPtr->hints.flags & IconPixmapHint) {
  1188.         interp->result = Tk_NameOfBitmap(winPtr->display,
  1189.             wmPtr->hints.icon_pixmap);
  1190.         }
  1191.         return TCL_OK;
  1192.     }
  1193.     if (*argv[3] == '\0') {
  1194.         if (wmPtr->hints.icon_pixmap != None) {
  1195.         Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  1196.         }
  1197.         wmPtr->hints.flags &= ~IconPixmapHint;
  1198.     } else {
  1199.         pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
  1200.             Tk_GetUid(argv[3]));
  1201.         if (pixmap == None) {
  1202.         return TCL_ERROR;
  1203.         }
  1204.         wmPtr->hints.icon_pixmap = pixmap;
  1205.         wmPtr->hints.flags |= IconPixmapHint;
  1206.     }
  1207.     } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
  1208.         && (length >= 5)) {
  1209.     if (argc != 3) {
  1210.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1211.             argv[0], " iconify window\"", (char *) NULL);
  1212.         return TCL_ERROR;
  1213.     }
  1214.     if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  1215.         Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
  1216.             "\": override-redirect flag is set", (char *) NULL);
  1217.         return TCL_ERROR;
  1218.     }
  1219.     if (wmPtr->master != None) {
  1220.         Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
  1221.             "\": it is a transient", (char *) NULL);
  1222.         return TCL_ERROR;
  1223.     }
  1224.     if (wmPtr->iconFor != NULL) {
  1225.         Tcl_AppendResult(interp, "can't iconify ", argv[2],
  1226.             ": it is an icon for ", winPtr->pathName, (char *) NULL);
  1227.         return TCL_ERROR;
  1228.     }
  1229.     IconifyWindow(winPtr);
  1230.     } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
  1231.         && (length >= 5)) {
  1232.     Pixmap pixmap;
  1233.  
  1234.     if ((argc != 3) && (argc != 4)) {
  1235.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1236.             argv[0], " iconmask window ?bitmap?\"",
  1237.             (char *) NULL);
  1238.         return TCL_ERROR;
  1239.     }
  1240.     if (argc == 3) {
  1241.         if (wmPtr->hints.flags & IconMaskHint) {
  1242.         interp->result = Tk_NameOfBitmap(winPtr->display,
  1243.             wmPtr->hints.icon_mask);
  1244.         }
  1245.         return TCL_OK;
  1246.     }
  1247.     if (*argv[3] == '\0') {
  1248.         if (wmPtr->hints.icon_mask != None) {
  1249.         Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  1250.         }
  1251.         wmPtr->hints.flags &= ~IconMaskHint;
  1252.     } else {
  1253.         pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
  1254.         if (pixmap == None) {
  1255.         return TCL_ERROR;
  1256.         }
  1257.         wmPtr->hints.icon_mask = pixmap;
  1258.         wmPtr->hints.flags |= IconMaskHint;
  1259.     }
  1260.     } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
  1261.         && (length >= 5)) {
  1262.     if (argc > 4) {
  1263.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1264.             argv[0], " iconname window ?newName?\"", (char *) NULL);
  1265.         return TCL_ERROR;
  1266.     }
  1267.     if (argc == 3) {
  1268.         interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
  1269.         return TCL_OK;
  1270.     } else {
  1271.         wmPtr->iconName = Tk_GetUid(argv[3]);
  1272.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1273.         XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
  1274.         }
  1275.     }
  1276.     } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
  1277.         && (length >= 5)) {
  1278.     int x, y;
  1279.  
  1280.     if ((argc != 3) && (argc != 5)) {
  1281.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1282.             argv[0], " iconposition window ?x y?\"",
  1283.             (char *) NULL);
  1284.         return TCL_ERROR;
  1285.     }
  1286.     if (argc == 3) {
  1287.         if (wmPtr->hints.flags & IconPositionHint) {
  1288.         sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
  1289.             wmPtr->hints.icon_y);
  1290.         }
  1291.         return TCL_OK;
  1292.     }
  1293.     if (*argv[3] == '\0') {
  1294.         wmPtr->hints.flags &= ~IconPositionHint;
  1295.     } else {
  1296.         if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
  1297.             || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
  1298.         return TCL_ERROR;
  1299.         }
  1300.         wmPtr->hints.icon_x = x;
  1301.         wmPtr->hints.icon_y = y;
  1302.         wmPtr->hints.flags |= IconPositionHint;
  1303.     }
  1304.     } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
  1305.         && (length >= 5)) {
  1306.     Tk_Window tkwin2;
  1307.     WmInfo *wmPtr2;
  1308.         XSetWindowAttributes atts;
  1309.  
  1310.     if ((argc != 3) && (argc != 4)) {
  1311.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1312.             argv[0], " iconwindow window ?pathName?\"",
  1313.             (char *) NULL);
  1314.         return TCL_ERROR;
  1315.     }
  1316.     if (argc == 3) {
  1317.         if (wmPtr->icon != NULL) {
  1318.         interp->result = Tk_PathName(wmPtr->icon);
  1319.         }
  1320.         return TCL_OK;
  1321.     }
  1322.     if (*argv[3] == '\0') {
  1323.         wmPtr->hints.flags &= ~IconWindowHint;
  1324.         if (wmPtr->icon != NULL) {
  1325.                 /*
  1326.                  * Let the window use button events again, then remove
  1327.                  * it as icon window.
  1328.                  */
  1329.  
  1330.                 atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
  1331.                         | ButtonPressMask;
  1332.                 Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
  1333.         wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  1334.         wmPtr2->iconFor = NULL;
  1335.         wmPtr2->withdrawn = 1;
  1336.         wmPtr2->hints.initial_state = WithdrawnState;
  1337.         }
  1338.         wmPtr->icon = NULL;
  1339.     } else {
  1340.         tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
  1341.         if (tkwin2 == NULL) {
  1342.         return TCL_ERROR;
  1343.         }
  1344.         if (!Tk_IsTopLevel(tkwin2)) {
  1345.         Tcl_AppendResult(interp, "can't use ", argv[3],
  1346.             " as icon window: not at top level", (char *) NULL);
  1347.         return TCL_ERROR;
  1348.         }
  1349.         wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
  1350.         if (wmPtr2->iconFor != NULL) {
  1351.         Tcl_AppendResult(interp, argv[3], " is already an icon for ",
  1352.             Tk_PathName(wmPtr2->iconFor), (char *) NULL);
  1353.         return TCL_ERROR;
  1354.         }
  1355.         if (wmPtr->icon != NULL) {
  1356.         WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  1357.         wmPtr3->iconFor = NULL;
  1358.         wmPtr3->withdrawn = 1;
  1359.  
  1360.                 /*
  1361.                  * Let the window use button events again.
  1362.                  */
  1363.  
  1364.                 atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
  1365.                         | ButtonPressMask;
  1366.                 Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
  1367.         }
  1368.  
  1369.             /*
  1370.              * Disable button events in the icon window:  some window
  1371.              * managers (like olvwm) want to get the events themselves,
  1372.              * but X only allows one application at a time to receive
  1373.              * button events for a window.
  1374.              */
  1375.  
  1376.             atts.event_mask = Tk_Attributes(tkwin2)->event_mask
  1377.                     & ~ButtonPressMask;
  1378.             Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
  1379.         Tk_MakeWindowExist(tkwin2);
  1380.         wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
  1381.         wmPtr->hints.flags |= IconWindowHint;
  1382.         wmPtr->icon = tkwin2;
  1383.         wmPtr2->iconFor = (Tk_Window) winPtr;
  1384.         if (!wmPtr2->withdrawn && !(wmPtr2->flags & WM_NEVER_MAPPED)) {
  1385.         wmPtr2->withdrawn = 0;
  1386.         if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2),
  1387.             Tk_ScreenNumber(tkwin2)) == 0) {
  1388.             interp->result =
  1389.                 "couldn't send withdraw message to window manager";
  1390.             return TCL_ERROR;
  1391.         }
  1392.         }
  1393.     }
  1394.     } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
  1395.         && (length >= 2)) {
  1396.     int width, height;
  1397.     if ((argc != 3) && (argc != 5)) {
  1398.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1399.             argv[0], " maxsize window ?width height?\"", (char *) NULL);
  1400.         return TCL_ERROR;
  1401.     }
  1402.     if (argc == 3) {
  1403.             GetMaxSize(wmPtr, &width, &height);
  1404.         sprintf(interp->result, "%d %d", width, height);
  1405.         return TCL_OK;
  1406.     }
  1407.     if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
  1408.         || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
  1409.         return TCL_ERROR;
  1410.     }
  1411.     wmPtr->maxWidth = width;
  1412.     wmPtr->maxHeight = height;
  1413.     goto updateGeom;
  1414.     } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
  1415.         && (length >= 2)) {
  1416.     int width, height;
  1417.     if ((argc != 3) && (argc != 5)) {
  1418.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1419.             argv[0], " minsize window ?width height?\"", (char *) NULL);
  1420.         return TCL_ERROR;
  1421.     }
  1422.     if (argc == 3) {
  1423.             GetMinSize(wmPtr, &width, &height);
  1424.             sprintf(interp->result, "%d %d", width, height);
  1425.         return TCL_OK;
  1426.     }
  1427.     if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
  1428.         || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
  1429.         return TCL_ERROR;
  1430.     }
  1431.     wmPtr->minWidth = width;
  1432.     wmPtr->minHeight = height;
  1433.     goto updateGeom;
  1434.     } else if ((c == 'o')
  1435.         && (strncmp(argv[1], "overrideredirect", length) == 0)) {
  1436.     int boolean;
  1437.     XSetWindowAttributes atts;
  1438.  
  1439.     if ((argc != 3) && (argc != 4)) {
  1440.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1441.             argv[0], " overrideredirect window ?boolean?\"",
  1442.             (char *) NULL);
  1443.         return TCL_ERROR;
  1444.     }
  1445.     if (argc == 3) {
  1446.         if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  1447.         interp->result = "1";
  1448.         } else {
  1449.         interp->result = "0";
  1450.         }
  1451.         return TCL_OK;
  1452.     }
  1453.     if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
  1454.         return TCL_ERROR;
  1455.     }
  1456.     atts.override_redirect = (boolean) ? True : False;
  1457.     Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
  1458.         &atts);
  1459.     } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
  1460.         && (length >= 2)) {
  1461.     if ((argc != 3) && (argc != 4)) {
  1462.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1463.             argv[0], " positionfrom window ?user/program?\"",
  1464.             (char *) NULL);
  1465.         return TCL_ERROR;
  1466.     }
  1467.     if (argc == 3) {
  1468.         if (wmPtr->sizeHintsFlags & USPosition) {
  1469.         interp->result = "user";
  1470.         } else if (wmPtr->sizeHintsFlags & PPosition) {
  1471.         interp->result = "program";
  1472.         }
  1473.         return TCL_OK;
  1474.     }
  1475.     if (*argv[3] == '\0') {
  1476.         wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
  1477.     } else {
  1478.         c = argv[3][0];
  1479.         length = strlen(argv[3]);
  1480.         if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
  1481.         wmPtr->sizeHintsFlags &= ~PPosition;
  1482.         wmPtr->sizeHintsFlags |= USPosition;
  1483.         } else if ((c == 'p') && (strncmp(argv[3], "program", length) == 0)) {
  1484.         wmPtr->sizeHintsFlags &= ~USPosition;
  1485.         wmPtr->sizeHintsFlags |= PPosition;
  1486.         } else {
  1487.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1488.             "\": must be program or user", (char *) NULL);
  1489.         return TCL_ERROR;
  1490.         }
  1491.     }
  1492.     goto updateGeom;
  1493.     } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
  1494.         && (length >= 2)) {
  1495.     register ProtocolHandler *protPtr, *prevPtr;
  1496.     Atom protocol;
  1497.     int cmdLength;
  1498.  
  1499.     if ((argc < 3) || (argc > 5)) {
  1500.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1501.             argv[0], " protocol window ?name? ?command?\"",
  1502.             (char *) NULL);
  1503.         return TCL_ERROR;
  1504.     }
  1505.     if (argc == 3) {
  1506.         /*
  1507.          * Return a list of all defined protocols for the window.
  1508.          */
  1509.         for (protPtr = wmPtr->protPtr; protPtr != NULL;
  1510.             protPtr = protPtr->nextPtr) {
  1511.         Tcl_AppendElement(interp,
  1512.             Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
  1513.         }
  1514.         return TCL_OK;
  1515.     }
  1516.     protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
  1517.     if (argc == 4) {
  1518.         /*
  1519.          * Return the command to handle a given protocol.
  1520.          */
  1521.         for (protPtr = wmPtr->protPtr; protPtr != NULL;
  1522.             protPtr = protPtr->nextPtr) {
  1523.         if (protPtr->protocol == protocol) {
  1524.             interp->result = protPtr->command;
  1525.             return TCL_OK;
  1526.         }
  1527.         }
  1528.         return TCL_OK;
  1529.     }
  1530.  
  1531.     /*
  1532.      * Delete any current protocol handler, then create a new
  1533.      * one with the specified command, unless the command is
  1534.      * empty.
  1535.      */
  1536.  
  1537.     for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
  1538.         prevPtr = protPtr, protPtr = protPtr->nextPtr) {
  1539.         if (protPtr->protocol == protocol) {
  1540.         if (prevPtr == NULL) {
  1541.             wmPtr->protPtr = protPtr->nextPtr;
  1542.         } else {
  1543.             prevPtr->nextPtr = protPtr->nextPtr;
  1544.         }
  1545.         Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  1546.         break;
  1547.         }
  1548.     }
  1549.     cmdLength = strlen(argv[4]);
  1550.     if (cmdLength > 0) {
  1551.         protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
  1552.         protPtr->protocol = protocol;
  1553.         protPtr->nextPtr = wmPtr->protPtr;
  1554.         wmPtr->protPtr = protPtr;
  1555.         protPtr->interp = interp;
  1556.         strcpy(protPtr->command, argv[4]);
  1557.     }
  1558.     } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
  1559.         int width, height;
  1560.  
  1561.         if ((argc != 3) && (argc != 5)) {
  1562.             Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1563.                     argv[0], " resizable window ?width height?\"",
  1564.                     (char *) NULL);
  1565.             return TCL_ERROR;
  1566.         }
  1567.         if (argc == 3) {
  1568.             sprintf(interp->result, "%d %d",
  1569.                     (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
  1570.                     (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
  1571.             return TCL_OK;
  1572.         }
  1573.         if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
  1574.                 || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
  1575.             return TCL_ERROR;
  1576.         }
  1577.         if (width) {
  1578.             wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
  1579.         } else {
  1580.             wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
  1581.         }
  1582.         if (height) {
  1583.             wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
  1584.         } else {
  1585.             wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
  1586.         }
  1587.         wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1588.         goto updateGeom;
  1589.     } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
  1590.         && (length >= 2)) {
  1591.     if ((argc != 3) && (argc != 4)) {
  1592.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1593.             argv[0], " sizefrom window ?user|program?\"",
  1594.             (char *) NULL);
  1595.         return TCL_ERROR;
  1596.     }
  1597.     if (argc == 3) {
  1598.         if (wmPtr->sizeHintsFlags & USSize) {
  1599.         interp->result = "user";
  1600.         } else if (wmPtr->sizeHintsFlags & PSize) {
  1601.         interp->result = "program";
  1602.         }
  1603.         return TCL_OK;
  1604.     }
  1605.     if (*argv[3] == '\0') {
  1606.         wmPtr->sizeHintsFlags &= ~(USSize|PSize);
  1607.     } else {
  1608.         c = argv[3][0];
  1609.         length = strlen(argv[3]);
  1610.         if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
  1611.         wmPtr->sizeHintsFlags &= ~PSize;
  1612.         wmPtr->sizeHintsFlags |= USSize;
  1613.         } else if ((c == 'p')
  1614.             && (strncmp(argv[3], "program", length) == 0)) {
  1615.         wmPtr->sizeHintsFlags &= ~USSize;
  1616.         wmPtr->sizeHintsFlags |= PSize;
  1617.         } else {
  1618.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1619.             "\": must be program or user", (char *) NULL);
  1620.         return TCL_ERROR;
  1621.         }
  1622.     }
  1623.     goto updateGeom;
  1624.     } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
  1625.         && (length >= 2)) {
  1626.     if (argc != 3) {
  1627.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1628.             argv[0], " state window\"", (char *) NULL);
  1629.         return TCL_ERROR;
  1630.     }
  1631.     if (wmPtr->iconFor != NULL) {
  1632.         interp->result = "icon";
  1633.     } else if (wmPtr->withdrawn) {
  1634.         interp->result = "withdrawn";
  1635.     } else if (Tk_IsMapped((Tk_Window) winPtr)
  1636.         || ((wmPtr->flags & WM_NEVER_MAPPED)
  1637.         && (wmPtr->hints.initial_state == NormalState))) {
  1638.         interp->result = "normal";
  1639.     } else {
  1640.         interp->result = "iconic";
  1641.     }
  1642.     } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
  1643.         && (length >= 2)) {
  1644.     if (argc > 4) {
  1645.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1646.             argv[0], " title window ?newTitle?\"", (char *) NULL);
  1647.         return TCL_ERROR;
  1648.     }
  1649.     if (argc == 3) {
  1650.         interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
  1651.             : winPtr->nameUid;
  1652.         return TCL_OK;
  1653.     } else {
  1654.         wmPtr->titleUid = Tk_GetUid(argv[3]);
  1655.         if ((!(wmPtr->flags & WM_NEVER_MAPPED)) &&
  1656.                 wmPtr->reparent != None) {
  1657.                 HSWITCH hSwitch;
  1658.                 SWCNTRL switchData;
  1659.  
  1660.                 hSwitch= WinQuerySwitchHandle(TkOS2GetHWND(wmPtr->reparent), 0);
  1661.                 rc = WinQuerySwitchEntry(hSwitch, &switchData);
  1662.                 /* Set visibility on */
  1663.                 strncpy(switchData.szSwtitle, wmPtr->titleUid, MAXNAMEL+4);
  1664.                 rc = WinChangeSwitchEntry(hSwitch, &switchData);
  1665.         WinSetWindowText(TkOS2GetHWND(wmPtr->reparent),wmPtr->titleUid);
  1666.         }
  1667.     }
  1668.     } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
  1669.         && (length >= 3)) {
  1670.     Tk_Window master;
  1671.  
  1672.     if ((argc != 3) && (argc != 4)) {
  1673.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1674.             argv[0], " transient window ?master?\"", (char *) NULL);
  1675.         return TCL_ERROR;
  1676.     }
  1677.     if (argc == 3) {
  1678.         if (wmPtr->master != None) {
  1679.         interp->result = wmPtr->masterWindowName;
  1680.         }
  1681.         return TCL_OK;
  1682.     }
  1683.     if (argv[3][0] == '\0') {
  1684.         wmPtr->master = None;
  1685.         wmPtr->masterWindowName = NULL;
  1686.     } else {
  1687.         master = Tk_NameToWindow(interp, argv[3], tkwin);
  1688.         if (master == NULL) {
  1689.         return TCL_ERROR;
  1690.         }
  1691.         Tk_MakeWindowExist(master);
  1692.         wmPtr->master = Tk_WindowId(master);
  1693.         wmPtr->masterWindowName = Tk_PathName(master);
  1694.     }
  1695.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1696.         XSetTransientForHint(winPtr->display, winPtr->window,
  1697.             wmPtr->master);
  1698.     }
  1699.     } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
  1700.     if (argc != 3) {
  1701.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1702.             argv[0], " withdraw window\"", (char *) NULL);
  1703.         return TCL_ERROR;
  1704.     }
  1705.     if (wmPtr->iconFor != NULL) {
  1706.         Tcl_AppendResult(interp, "can't withdraw ", argv[2],
  1707.             ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
  1708.             (char *) NULL);
  1709.         return TCL_ERROR;
  1710.     }
  1711.     wmPtr->hints.initial_state = WithdrawnState;
  1712.     wmPtr->withdrawn = 1;
  1713.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  1714.         return TCL_OK;
  1715.     }
  1716.  
  1717.     TkWmUnmapWindow(winPtr);
  1718.     } else {
  1719.     Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
  1720.         "\": must be aspect, client, command, deiconify, ",
  1721.         "focusmodel, frame, geometry, grid, group, iconbitmap, ",
  1722.         "iconify, iconmask, iconname, iconposition, ",
  1723.         "iconwindow, maxsize, minsize, overrideredirect, ",
  1724.         "positionfrom, protocol, resizable, sizefrom, state, title, ",
  1725.         "tracing, transient, or withdraw",
  1726.         (char *) NULL);
  1727.     return TCL_ERROR;
  1728.     }
  1729.     return TCL_OK;
  1730.  
  1731.     updateGeom:
  1732.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1733.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1734.     wmPtr->flags |= WM_UPDATE_PENDING;
  1735.     }
  1736.     return TCL_OK;
  1737. }
  1738.  
  1739. /*
  1740.  *----------------------------------------------------------------------
  1741.  *
  1742.  * Tk_SetGrid --
  1743.  *
  1744.  *    This procedure is invoked by a widget when it wishes to set a grid
  1745.  *    coordinate system that controls the size of a top-level window.
  1746.  *    It provides a C interface equivalent to the "wm grid" command and
  1747.  *    is usually asscoiated with the -setgrid option.
  1748.  *
  1749.  * Results:
  1750.  *    None.
  1751.  *
  1752.  * Side effects:
  1753.  *    Grid-related information will be passed to the window manager, so
  1754.  *    that the top-level window associated with tkwin will resize on
  1755.  *    even grid units.  If some other window already controls gridding
  1756.  *    for the top-level window then this procedure call has no effect.
  1757.  *
  1758.  *----------------------------------------------------------------------
  1759.  */
  1760.  
  1761. void
  1762. Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
  1763.     Tk_Window tkwin;        /* Token for window.  New window mgr info
  1764.                  * will be posted for the top-level window
  1765.                  * associated with this window. */
  1766.     int reqWidth;        /* Width (in grid units) corresponding to
  1767.                  * the requested geometry for tkwin. */
  1768.     int reqHeight;        /* Height (in grid units) corresponding to
  1769.                  * the requested geometry for tkwin. */
  1770.     int widthInc, heightInc;    /* Pixel increments corresponding to a
  1771.                  * change of one grid unit. */
  1772. {
  1773.     TkWindow *winPtr = (TkWindow *) tkwin;
  1774.     register WmInfo *wmPtr;
  1775.  
  1776.     /*
  1777.      * Find the top-level window for tkwin, plus the window manager
  1778.      * information.
  1779.      */
  1780.  
  1781.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  1782.     winPtr = winPtr->parentPtr;
  1783.     }
  1784.     wmPtr = winPtr->wmInfoPtr;
  1785.  
  1786.     if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
  1787.     return;
  1788.     }
  1789.  
  1790.     if ((wmPtr->reqGridWidth == reqWidth)
  1791.         && (wmPtr->reqGridHeight == reqHeight)
  1792.         && (wmPtr->widthInc == widthInc)
  1793.         && (wmPtr->heightInc == heightInc)
  1794.         && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
  1795.             == (PBaseSize|PResizeInc))) {
  1796.     return;
  1797.     }
  1798.  
  1799.     /*
  1800.      * If gridding was previously off, then forget about any window
  1801.      * size requests made by the user or via "wm geometry":  these are
  1802.      * in pixel units and there's no easy way to translate them to
  1803.      * grid units since the new requested size of the top-level window in
  1804.      * pixels may not yet have been registered yet (it may filter up
  1805.      * the hierarchy in DoWhenIdle handlers).  However, if the window
  1806.      * has never been mapped yet then just leave the window size alone:
  1807.      * assume that it is intended to be in grid units but just happened
  1808.      * to have been specified before this procedure was called.
  1809.      */
  1810.  
  1811.     if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
  1812.     wmPtr->width = -1;
  1813.     wmPtr->height = -1;
  1814.     }
  1815.  
  1816.     /* 
  1817.      * Set the new gridding information, and start the process of passing
  1818.      * all of this information to the window manager.
  1819.      */
  1820.  
  1821.     wmPtr->gridWin = tkwin;
  1822.     wmPtr->reqGridWidth = reqWidth;
  1823.     wmPtr->reqGridHeight = reqHeight;
  1824.     wmPtr->widthInc = widthInc;
  1825.     wmPtr->heightInc = heightInc;
  1826.     wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
  1827.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1828.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1829.     wmPtr->flags |= WM_UPDATE_PENDING;
  1830.     }
  1831. }
  1832.  
  1833. /*
  1834.  *----------------------------------------------------------------------
  1835.  *
  1836.  * Tk_UnsetGrid --
  1837.  *
  1838.  *    This procedure cancels the effect of a previous call
  1839.  *    to Tk_SetGrid.
  1840.  *
  1841.  * Results:
  1842.  *    None.
  1843.  *
  1844.  * Side effects:
  1845.  *    If tkwin currently controls gridding for its top-level window,
  1846.  *    gridding is cancelled for that top-level window;  if some other
  1847.  *    window controls gridding then this procedure has no effect.
  1848.  *
  1849.  *----------------------------------------------------------------------
  1850.  */
  1851.  
  1852. void
  1853. Tk_UnsetGrid(tkwin)
  1854.     Tk_Window tkwin;        /* Token for window that is currently
  1855.                  * controlling gridding. */
  1856. {
  1857.     TkWindow *winPtr = (TkWindow *) tkwin;
  1858.     register WmInfo *wmPtr;
  1859.  
  1860.     /*
  1861.      * Find the top-level window for tkwin, plus the window manager
  1862.      * information.
  1863.      */
  1864.  
  1865.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  1866.     winPtr = winPtr->parentPtr;
  1867.     }
  1868.     wmPtr = winPtr->wmInfoPtr;
  1869.     if (tkwin != wmPtr->gridWin) {
  1870.     return;
  1871.     }
  1872.  
  1873.     wmPtr->gridWin = NULL;
  1874.     wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  1875.     if (wmPtr->width != -1) {
  1876.     wmPtr->width = winPtr->reqWidth + (wmPtr->width
  1877.         - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1878.     wmPtr->height = winPtr->reqHeight + (wmPtr->height
  1879.         - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1880.     }
  1881.     wmPtr->widthInc = 1;
  1882.     wmPtr->heightInc = 1;
  1883.  
  1884.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1885.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1886.     wmPtr->flags |= WM_UPDATE_PENDING;
  1887.     }
  1888. }
  1889.  
  1890. /*
  1891.  *----------------------------------------------------------------------
  1892.  *
  1893.  * TopLevelEventProc --
  1894.  *
  1895.  *    This procedure is invoked when a top-level (or other externally-
  1896.  *    managed window) is restructured in any way.
  1897.  *
  1898.  * Results:
  1899.  *    None.
  1900.  *
  1901.  * Side effects:
  1902.  *    Tk's internal data structures for the window get modified to
  1903.  *    reflect the structural change.
  1904.  *
  1905.  *----------------------------------------------------------------------
  1906.  */
  1907.  
  1908. static void
  1909. TopLevelEventProc(clientData, eventPtr)
  1910.     ClientData clientData;        /* Window for which event occurred. */
  1911.     XEvent *eventPtr;            /* Event that just happened. */
  1912. {
  1913.     register TkWindow *winPtr = (TkWindow *) clientData;
  1914.  
  1915.     if (eventPtr->type == DestroyNotify) {
  1916.     Tk_ErrorHandler handler;
  1917.  
  1918.     if (!(winPtr->flags & TK_ALREADY_DEAD)) {
  1919.         /*
  1920.          * A top-level window was deleted externally (e.g., by the window
  1921.          * manager).  This is probably not a good thing, but cleanup as
  1922.          * best we can.  The error handler is needed because
  1923.          * Tk_DestroyWindow will try to destroy the window, but of course
  1924.          * it's already gone.
  1925.          */
  1926.     
  1927.         handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
  1928.             (Tk_ErrorProc *) NULL, (ClientData) NULL);
  1929.         Tk_DestroyWindow((Tk_Window) winPtr);
  1930.         Tk_DeleteErrorHandler(handler);
  1931.     }
  1932.     }
  1933. }
  1934.  
  1935. /*
  1936.  *----------------------------------------------------------------------
  1937.  *
  1938.  * TopLevelReqProc --
  1939.  *
  1940.  *    This procedure is invoked by the geometry manager whenever
  1941.  *    the requested size for a top-level window is changed.
  1942.  *
  1943.  * Results:
  1944.  *    None.
  1945.  *
  1946.  * Side effects:
  1947.  *    Arrange for the window to be resized to satisfy the request
  1948.  *    (this happens as a when-idle action).
  1949.  *
  1950.  *----------------------------------------------------------------------
  1951.  */
  1952.  
  1953.     /* ARGSUSED */
  1954. static void
  1955. TopLevelReqProc(dummy, tkwin)
  1956.     ClientData dummy;            /* Not used. */
  1957.     Tk_Window tkwin;            /* Information about window. */
  1958. {
  1959.     TkWindow *winPtr = (TkWindow *) tkwin;
  1960.     WmInfo *wmPtr;
  1961.  
  1962.     wmPtr = winPtr->wmInfoPtr;
  1963.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1964.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1965.     wmPtr->flags |= WM_UPDATE_PENDING;
  1966.     }
  1967. }
  1968.  
  1969. /*
  1970.  *----------------------------------------------------------------------
  1971.  *
  1972.  * UpdateGeometryInfo --
  1973.  *
  1974.  *    This procedure is invoked when a top-level window is first
  1975.  *    mapped, and also as a when-idle procedure, to bring the
  1976.  *    geometry and/or position of a top-level window back into
  1977.  *    line with what has been requested by the user and/or widgets.
  1978.  *    This procedure doesn't return until the window manager has
  1979.  *    responded to the geometry change.
  1980.  *
  1981.  * Results:
  1982.  *    None.
  1983.  *
  1984.  * Side effects:
  1985.  *    The window's size and location may change, unless the WM prevents
  1986.  *    that from happening.
  1987.  *
  1988.  *----------------------------------------------------------------------
  1989.  */
  1990.  
  1991. static void
  1992. UpdateGeometryInfo(clientData)
  1993.     ClientData clientData;        /* Pointer to the window's record. */
  1994. {
  1995.     register TkWindow *winPtr = (TkWindow *) clientData;
  1996.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1997.     int x, y, width, height;
  1998.  
  1999.     wmPtr->flags &= ~WM_UPDATE_PENDING;
  2000.  
  2001.     /*
  2002.      * Compute the new size for the top-level window.  See the
  2003.      * user documentation for details on this, but the size
  2004.      * requested depends on (a) the size requested internally
  2005.      * by the window's widgets, (b) the size requested by the
  2006.      * user in a "wm geometry" command or via wm-based interactive
  2007.      * resizing (if any), and (c) whether or not the window is
  2008.      * gridded.  Don't permit sizes <= 0 because this upsets
  2009.      * the X server.
  2010.      */
  2011.  
  2012.     if (wmPtr->width == -1) {
  2013.     width = winPtr->reqWidth;
  2014.     } else if (wmPtr->gridWin != NULL) {
  2015.     width = winPtr->reqWidth
  2016.         + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
  2017.     } else {
  2018.     width = wmPtr->width;
  2019.     }
  2020.     if (width <= 0) {
  2021.     width = 1;
  2022.     }
  2023.     if (wmPtr->height == -1) {
  2024.         height = winPtr->reqHeight;
  2025.     } else if (wmPtr->gridWin != NULL) {
  2026.         height = winPtr->reqHeight
  2027.                 + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
  2028.     } else {
  2029.         height = wmPtr->height;
  2030.     }
  2031.     if (height <= 0) {
  2032.     height = 1;
  2033.     }
  2034.  
  2035.     /*
  2036.      * Compute the new position for the upper-left pixel of the window's
  2037.      * decorative frame.  This is tricky, because we need to include the
  2038.      * border widths supplied by a reparented parent in this calculation,
  2039.      * but can't use the parent's current overall size since that may
  2040.      * change as a result of this code.
  2041.      */
  2042.  
  2043.     if (wmPtr->flags & WM_NEGATIVE_X) {
  2044.     x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
  2045.         - (width + wmPtr->borderWidth);
  2046.     } else {
  2047.     x =  wmPtr->x;
  2048.     }
  2049.     if (wmPtr->flags & WM_NEGATIVE_Y) {
  2050.     y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
  2051.         - (height + wmPtr->borderHeight);
  2052.     } else {
  2053.     y =  wmPtr->y;
  2054.     }
  2055.  
  2056.     /*
  2057.      * Reconfigure the window if it isn't already configured correctly.  Base
  2058.      * the size check on what we *asked for* last time, not what we got.
  2059.      */
  2060.  
  2061.     if ((wmPtr->flags & WM_MOVE_PENDING)
  2062.         || (width != wmPtr->configWidth)
  2063.         || (height != wmPtr->configHeight)) {
  2064.     wmPtr->configWidth = width;
  2065.     wmPtr->configHeight = height;
  2066.  
  2067.        /*
  2068.         * Don't bother moving the window if we are in the process of
  2069.         * creating it.  Just update the geometry info based on what
  2070.         * we asked for.
  2071.         */
  2072.  
  2073.         if (!(wmPtr->flags & WM_CREATE_PENDING)) {
  2074.  
  2075.             wmPtr->flags |= WM_SYNC_PENDING;
  2076.             /*
  2077.              * Make sure we get the right size/position
  2078.              * Use SWP_NOADJUST to prevent getting a WM_QUERYTRACKINFO msg
  2079.              * (because of WM_ADJUSTWINDOWPOS message handling), which causes
  2080.              * the window to move up.
  2081.              */
  2082.         WinSetWindowPos(TkOS2GetHWND(wmPtr->reparent), HWND_TOP, x,
  2083.                         yScreen - (y + height + wmPtr->borderHeight),
  2084.                             width + wmPtr->borderWidth,
  2085.                             height + wmPtr->borderHeight,
  2086.                             SWP_SIZE | SWP_MOVE | SWP_NOADJUST);
  2087.             wmPtr->flags &= ~WM_SYNC_PENDING;
  2088.         } else {
  2089.             winPtr->changes.x = x;
  2090.             winPtr->changes.y = y;
  2091.             winPtr->changes.width = width;
  2092.             winPtr->changes.height = height;
  2093.         }
  2094.     } else {
  2095.     return;
  2096.     }
  2097. }
  2098.  
  2099. /*
  2100.  *--------------------------------------------------------------
  2101.  *
  2102.  * ParseGeometry --
  2103.  *
  2104.  *    This procedure parses a geometry string and updates
  2105.  *    information used to control the geometry of a top-level
  2106.  *    window.
  2107.  *
  2108.  * Results:
  2109.  *    A standard Tcl return value, plus an error message in
  2110.  *    interp->result if an error occurs.
  2111.  *
  2112.  * Side effects:
  2113.  *    The size and/or location of winPtr may change.
  2114.  *
  2115.  *--------------------------------------------------------------
  2116.  */
  2117.  
  2118. static int
  2119. ParseGeometry(interp, string, winPtr)
  2120.     Tcl_Interp *interp;        /* Used for error reporting. */
  2121.     char *string;        /* String containing new geometry.  Has the
  2122.                  * standard form "=wxh+x+y". */
  2123.     TkWindow *winPtr;        /* Pointer to top-level window whose
  2124.                  * geometry is to be changed. */
  2125. {
  2126.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2127.     int x, y, width, height, flags;
  2128.     char *end;
  2129.     register char *p = string;
  2130.  
  2131.     /*
  2132.      * The leading "=" is optional.
  2133.      */
  2134.  
  2135.     if (*p == '=') {
  2136.     p++;
  2137.     }
  2138.  
  2139.     /*
  2140.      * Parse the width and height, if they are present.  Don't
  2141.      * actually update any of the fields of wmPtr until we've
  2142.      * successfully parsed the entire geometry string.
  2143.      */
  2144.  
  2145.     width = wmPtr->width;
  2146.     height = wmPtr->height;
  2147.     x = wmPtr->x;
  2148.     y = wmPtr->y;
  2149.     flags = wmPtr->flags;
  2150.     if (isdigit(UCHAR(*p))) {
  2151.     width = strtoul(p, &end, 10);
  2152.     p = end;
  2153.     if (*p != 'x') {
  2154.         goto error;
  2155.     }
  2156.     p++;
  2157.     if (!isdigit(UCHAR(*p))) {
  2158.         goto error;
  2159.     }
  2160.     height = strtoul(p, &end, 10);
  2161.     p = end;
  2162.     }
  2163.  
  2164.     /*
  2165.      * Parse the X and Y coordinates, if they are present.
  2166.      */
  2167.  
  2168.     if (*p != '\0') {
  2169.     flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  2170.     if (*p == '-') {
  2171.         flags |= WM_NEGATIVE_X;
  2172.     } else if (*p != '+') {
  2173.         goto error;
  2174.     }
  2175.     x = strtol(p+1, &end, 10);
  2176.     /* Beware of apps using +-x */
  2177.         if (x < 0) {
  2178.         flags |= WM_NEGATIVE_X;
  2179.         x = -y;
  2180.         }
  2181.     p = end;
  2182.     if (*p == '-') {
  2183.         flags |= WM_NEGATIVE_Y;
  2184.     } else if (*p != '+') {
  2185.         goto error;
  2186.     }
  2187.     y = strtol(p+1, &end, 10);
  2188.     /* Beware of apps using +-y, eg. SpecTcl 1.1 */
  2189.         if (y < 0) {
  2190.         flags |= WM_NEGATIVE_Y;
  2191.         y = -y;
  2192.         }
  2193.     if (*end != '\0') {
  2194.         goto error;
  2195.     }
  2196.  
  2197.     /*
  2198.      * Assume that the geometry information came from the user,
  2199.      * unless an explicit source has been specified.  Otherwise
  2200.      * most window managers assume that the size hints were
  2201.      * program-specified and they ignore them.
  2202.      */
  2203.  
  2204.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2205.         wmPtr->sizeHintsFlags |= USPosition;
  2206.     }
  2207.     }
  2208.  
  2209.     /*
  2210.      * Everything was parsed OK.  Update the fields of *wmPtr and
  2211.      * arrange for the appropriate information to be percolated out
  2212.      * to the window manager at the next idle moment.
  2213.      */
  2214.  
  2215.     wmPtr->width = width;
  2216.     wmPtr->height = height;
  2217.     if ((x != wmPtr->x) || (y != wmPtr->y)
  2218.         || ((flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y))
  2219.         != (wmPtr->flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)))) {
  2220.     wmPtr->x = x;
  2221.     wmPtr->y = y;
  2222.     flags |= WM_MOVE_PENDING;
  2223.     }
  2224.     wmPtr->flags = flags;
  2225.  
  2226.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2227.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2228.     wmPtr->flags |= WM_UPDATE_PENDING;
  2229.     }
  2230.     return TCL_OK;
  2231.  
  2232.     error:
  2233.     Tcl_AppendResult(interp, "bad geometry specifier \"",
  2234.         string, "\"", (char *) NULL);
  2235.     return TCL_ERROR;
  2236. }
  2237.  
  2238. /*
  2239.  *----------------------------------------------------------------------
  2240.  *
  2241.  * Tk_GetRootCoords --
  2242.  *
  2243.  *    Given a token for a window, this procedure traces through the
  2244.  *    window's lineage to find the (virtual) root-window coordinates
  2245.  *    corresponding to point (0,0) in the window.
  2246.  *
  2247.  * Results:
  2248.  *    The locations pointed to by xPtr and yPtr are filled in with
  2249.  *    the root coordinates of the (0,0) point in tkwin.  If a virtual
  2250.  *    root window is in effect for the window, then the coordinates
  2251.  *    in the virtual root are returned.
  2252.  *
  2253.  * Side effects:
  2254.  *    None.
  2255.  *
  2256.  *----------------------------------------------------------------------
  2257.  */
  2258.  
  2259. void
  2260. Tk_GetRootCoords(tkwin, xPtr, yPtr)
  2261.     Tk_Window tkwin;        /* Token for window. */
  2262.     int *xPtr;            /* Where to store x-displacement of (0,0). */
  2263.     int *yPtr;            /* Where to store y-displacement of (0,0). */
  2264. {
  2265.     int x, y;
  2266.     register TkWindow *winPtr = (TkWindow *) tkwin;
  2267.  
  2268.     /*
  2269.      * Search back through this window's parents all the way to a
  2270.      * top-level window, combining the offsets of each window within
  2271.      * its parent.
  2272.      */
  2273.  
  2274.     x = y = 0;
  2275.     while (1) {
  2276.     x += winPtr->changes.x + winPtr->changes.border_width;
  2277.     y += winPtr->changes.y + winPtr->changes.border_width;
  2278.     if (winPtr->flags & TK_TOP_LEVEL) {
  2279.         x += winPtr->wmInfoPtr->xInParent;
  2280.         y += winPtr->wmInfoPtr->yInParent;
  2281.             if (winPtr->wmInfoPtr->exStyle & FCF_TITLEBAR) {
  2282.             y += titleBar;
  2283.             }
  2284.         break;
  2285.     }
  2286.     winPtr = winPtr->parentPtr;
  2287.     }
  2288.     *xPtr = x;
  2289.     *yPtr = y;
  2290. }
  2291.  
  2292. /*
  2293.  *----------------------------------------------------------------------
  2294.  *
  2295.  * Tk_CoordsToWindow --
  2296.  *
  2297.  *    Given the (virtual) root coordinates of a point, this procedure
  2298.  *    returns the token for the top-most window covering that point,
  2299.  *    if there exists such a window in this application.
  2300.  *
  2301.  * Results:
  2302.  *    The return result is either a token for the window corresponding
  2303.  *    to rootX and rootY, or else NULL to indicate that there is no such
  2304.  *    window.
  2305.  *
  2306.  * Side effects:
  2307.  *    None.
  2308.  *
  2309.  *----------------------------------------------------------------------
  2310.  */
  2311.  
  2312. Tk_Window
  2313. Tk_CoordsToWindow(rootX, rootY, tkwin)
  2314.     int rootX, rootY;        /* Coordinates of point in root window.  If
  2315.                  * a virtual-root window manager is in use,
  2316.                  * these coordinates refer to the virtual
  2317.                  * root, not the real root. */
  2318.     Tk_Window tkwin;        /* Token for any window in application;
  2319.                  * used to identify the display. */
  2320. {
  2321.     POINTL pos;
  2322.     HWND hwnd;
  2323.     TkOS2Drawable *todPtr;
  2324.     TkWindow *winPtr;
  2325.  
  2326.     pos.x = rootX;
  2327.     /* Translate to PM coordinates */
  2328.     pos.y = yScreen - rootY;
  2329.     hwnd = WinWindowFromPoint(HWND_DESKTOP, &pos, TRUE);
  2330.     if (hwnd == HWND_DESKTOP) return NULL;
  2331.  
  2332.     todPtr = TkOS2GetDrawableFromHandle(hwnd);
  2333.     if (todPtr && (todPtr->type == TOD_WINDOW)) {
  2334.     winPtr = TkOS2GetWinPtr(todPtr);
  2335.     if (winPtr->mainPtr == ((TkWindow *) tkwin)->mainPtr) {
  2336.         return (Tk_Window) winPtr;
  2337.     }
  2338.     }
  2339.     return NULL;
  2340. }
  2341.  
  2342. /*
  2343.  *----------------------------------------------------------------------
  2344.  *
  2345.  * Tk_GetVRootGeometry --
  2346.  *
  2347.  *    This procedure returns information about the virtual root
  2348.  *    window corresponding to a particular Tk window.
  2349.  *
  2350.  * Results:
  2351.  *    The values at xPtr, yPtr, widthPtr, and heightPtr are set
  2352.  *    with the offset and dimensions of the root window corresponding
  2353.  *    to tkwin.  If tkwin is being managed by a virtual root window
  2354.  *    manager these values correspond to the virtual root window being
  2355.  *    used for tkwin;  otherwise the offsets will be 0 and the
  2356.  *    dimensions will be those of the screen.
  2357.  *
  2358.  * Side effects:
  2359.  *    Vroot window information is refreshed if it is out of date.
  2360.  *
  2361.  *----------------------------------------------------------------------
  2362.  */
  2363.  
  2364. void
  2365. Tk_GetVRootGeometry(tkwin, xPtr, yPtr, widthPtr, heightPtr)
  2366.     Tk_Window tkwin;        /* Window whose virtual root is to be
  2367.                  * queried. */
  2368.     int *xPtr, *yPtr;        /* Store x and y offsets of virtual root
  2369.                  * here. */
  2370.     int *widthPtr, *heightPtr;    /* Store dimensions of virtual root here. */
  2371. {
  2372.     TkWindow *winPtr = (TkWindow *) tkwin;
  2373.  
  2374.     *xPtr = 0;
  2375.     *yPtr = 0;
  2376.     *widthPtr = DisplayWidth(winPtr->display, winPtr->screenNum);
  2377.     *heightPtr = DisplayHeight(winPtr->display, winPtr->screenNum);
  2378. }
  2379.  
  2380. /*
  2381.  *----------------------------------------------------------------------
  2382.  *
  2383.  * Tk_MoveToplevelWindow --
  2384.  *
  2385.  *    This procedure is called instead of Tk_MoveWindow to adjust
  2386.  *    the x-y location of a top-level window.  It delays the actual
  2387.  *    move to a later time and keeps window-manager information
  2388.  *    up-to-date with the move
  2389.  *
  2390.  * Results:
  2391.  *    None.
  2392.  *
  2393.  * Side effects:
  2394.  *    The window is eventually moved so that its upper-left corner
  2395.  *    (actually, the upper-left corner of the window's decorative
  2396.  *    frame, if there is one) is at (x,y).
  2397.  *
  2398.  *----------------------------------------------------------------------
  2399.  */
  2400.  
  2401. void
  2402. Tk_MoveToplevelWindow(tkwin, x, y)
  2403.     Tk_Window tkwin;        /* Window to move. */
  2404.     int x, y;            /* New location for window (within
  2405.                  * parent). */
  2406. {
  2407.     TkWindow *winPtr = (TkWindow *) tkwin;
  2408.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2409.  
  2410.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  2411.     panic("Tk_MoveToplevelWindow called with non-toplevel window");
  2412.     }
  2413.     wmPtr->x = x;
  2414.     wmPtr->y = y;
  2415.     wmPtr->flags |= WM_MOVE_PENDING;
  2416.     wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  2417.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2418.     wmPtr->sizeHintsFlags |= USPosition;
  2419.     }
  2420.  
  2421.     /*
  2422.      * If the window has already been mapped, must bring its geometry
  2423.      * up-to-date immediately, otherwise an event might arrive from the
  2424.      * server that would overwrite wmPtr->x and wmPtr->y and lose the
  2425.      * new position.
  2426.      */
  2427.  
  2428.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2429.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  2430.         Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  2431.     }
  2432.     UpdateGeometryInfo((ClientData) winPtr);
  2433.     }
  2434. }
  2435.  
  2436. /*
  2437.  *----------------------------------------------------------------------
  2438.  *
  2439.  * TkWmProtocolEventProc --
  2440.  *
  2441.  *    This procedure is called by the Tk_HandleEvent whenever a
  2442.  *    ClientMessage event arrives whose type is "WM_PROTOCOLS".
  2443.  *    This procedure handles the message from the window manager
  2444.  *    in an appropriate fashion.
  2445.  *
  2446.  * Results:
  2447.  *    None.
  2448.  *
  2449.  * Side effects:
  2450.  *    Depends on what sort of handler, if any, was set up for the
  2451.  *    protocol.
  2452.  *
  2453.  *----------------------------------------------------------------------
  2454.  */
  2455.  
  2456. void
  2457. TkWmProtocolEventProc(winPtr, eventPtr)
  2458.     TkWindow *winPtr;        /* Window to which the event was sent. */
  2459.     XEvent *eventPtr;        /* X event. */
  2460. {
  2461.     WmInfo *wmPtr;
  2462.     register ProtocolHandler *protPtr;
  2463.     Atom protocol;
  2464.     int result;
  2465.     Tcl_Interp *interp;
  2466.  
  2467.     wmPtr = winPtr->wmInfoPtr;
  2468.     if (wmPtr == NULL) {
  2469.     return;
  2470.     }
  2471.     protocol = (Atom) eventPtr->xclient.data.l[0];
  2472.     for (protPtr = wmPtr->protPtr; protPtr != NULL;
  2473.         protPtr = protPtr->nextPtr) {
  2474.     if (protocol == protPtr->protocol) {
  2475.         Tcl_Preserve((ClientData) protPtr);
  2476.             interp = protPtr->interp;
  2477.             Tcl_Preserve((ClientData) interp);
  2478.             result = Tcl_GlobalEval(interp, protPtr->command);
  2479.         if (result != TCL_OK) {
  2480.                 Tcl_AddErrorInfo(interp, "\n    (command for \"");
  2481.                 Tcl_AddErrorInfo(interp,
  2482.                         Tk_GetAtomName((Tk_Window) winPtr, protocol));
  2483.                 Tcl_AddErrorInfo(interp, "\" window manager protocol)");
  2484.                 Tcl_BackgroundError(interp);
  2485.         }
  2486.         Tcl_Release((ClientData) interp);
  2487.         Tcl_Release((ClientData) protPtr);
  2488.         return;
  2489.     }
  2490.     }
  2491.  
  2492.     /*
  2493.      * No handler was present for this protocol.  If this is a
  2494.      * WM_DELETE_WINDOW message then just destroy the window.
  2495.      */
  2496.  
  2497.     if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
  2498.     Tk_DestroyWindow((Tk_Window) winPtr);
  2499.     }
  2500. }
  2501.  
  2502. /*
  2503.  *----------------------------------------------------------------------
  2504.  *
  2505.  * TkWmRestackToplevel --
  2506.  *
  2507.  *    This procedure restacks a top-level window.
  2508.  *
  2509.  * Results:
  2510.  *    None.
  2511.  *
  2512.  * Side effects:
  2513.  *    WinPtr gets restacked  as specified by aboveBelow and otherPtr.
  2514.  *    This procedure doesn't return until the restack has taken
  2515.  *    effect and the ConfigureNotify event for it has been received.
  2516.  *
  2517.  *----------------------------------------------------------------------
  2518.  */
  2519.  
  2520. void
  2521. TkWmRestackToplevel(winPtr, aboveBelow, otherPtr)
  2522.     TkWindow *winPtr;        /* Window to restack. */
  2523.     int aboveBelow;        /* Gives relative position for restacking;
  2524.                  * must be Above or Below. */
  2525.     TkWindow *otherPtr;        /* Window relative to which to restack;
  2526.                  * if NULL, then winPtr gets restacked
  2527.                  * above or below *all* siblings. */
  2528. {
  2529.     XWindowChanges changes;
  2530.     unsigned int mask;
  2531.     Window window;
  2532.  
  2533.     changes.stack_mode = aboveBelow;
  2534.     mask = CWStackMode;
  2535.     if (winPtr->window == None) {
  2536.     Tk_MakeWindowExist((Tk_Window) winPtr);
  2537.     }
  2538.     if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2539.         /*
  2540.          * Can't set stacking order properly until the window is on the
  2541.          * screen (mapping it may give it a reparent window), so make sure
  2542.          * it's on the screen.
  2543.          */
  2544.  
  2545.         TkWmMapWindow(winPtr);
  2546.     }
  2547.     window = (winPtr->wmInfoPtr->reparent != None)
  2548.         ? winPtr->wmInfoPtr->reparent : winPtr->window;
  2549.     if (otherPtr != NULL) {
  2550.     if (otherPtr->window == None) {
  2551.         Tk_MakeWindowExist((Tk_Window) otherPtr);
  2552.     }
  2553.         if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2554.             TkWmMapWindow(otherPtr);
  2555.         }
  2556.     changes.sibling = (otherPtr->wmInfoPtr->reparent != None)
  2557.         ? otherPtr->wmInfoPtr->reparent : otherPtr->window;
  2558.     mask = CWStackMode|CWSibling;
  2559.     }
  2560.  
  2561.     /*
  2562.      * Reconfigure the window.  Since this is Presentation Manager, the
  2563.      * reconfiguration will happen immediately.
  2564.      */
  2565.  
  2566.     XConfigureWindow(winPtr->display, window, mask, &changes);
  2567. }
  2568.  
  2569. /*
  2570.  *----------------------------------------------------------------------
  2571.  *
  2572.  * TkWmAddToColormapWindows --
  2573.  *
  2574.  *    This procedure is called to add a given window to the
  2575.  *    WM_COLORMAP_WINDOWS property for its top-level, if it
  2576.  *    isn't already there.  It is invoked by the Tk code that
  2577.  *    creates a new colormap, in order to make sure that colormap
  2578.  *    information is propagated to the window manager by default.
  2579.  *
  2580.  * Results:
  2581.  *    None.
  2582.  *
  2583.  * Side effects:
  2584.  *    WinPtr's window gets added to the WM_COLORMAP_WINDOWS
  2585.  *    property of its nearest top-level ancestor, unless the
  2586.  *    colormaps have been set explicitly with the
  2587.  *    "wm colormapwindows" command.
  2588.  *
  2589.  *----------------------------------------------------------------------
  2590.  */
  2591.  
  2592. void
  2593. TkWmAddToColormapWindows(winPtr)
  2594.     TkWindow *winPtr;        /* Window with a non-default colormap.
  2595.                  * Should not be a top-level window. */
  2596. {
  2597.     TkWindow *topPtr;
  2598.     TkWindow **oldPtr, **newPtr;
  2599.     int count, i;
  2600.  
  2601.     if (winPtr->window == None) {
  2602.     return;
  2603.     }
  2604.  
  2605.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  2606.     if (topPtr == NULL) {
  2607.         /*
  2608.          * Window is being deleted.  Skip the whole operation.
  2609.          */
  2610.  
  2611.         return;
  2612.     }
  2613.     if (topPtr->flags & TK_TOP_LEVEL) {
  2614.         break;
  2615.     }
  2616.     }
  2617.     if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
  2618.     return;
  2619.     }
  2620.  
  2621.     /*
  2622.      * Make sure that the window isn't already in the list.
  2623.      */
  2624.  
  2625.     count = topPtr->wmInfoPtr->cmapCount;
  2626.     oldPtr = topPtr->wmInfoPtr->cmapList;
  2627.  
  2628.     for (i = 0; i < count; i++) {
  2629.     if (oldPtr[i] == winPtr) {
  2630.         return;
  2631.     }
  2632.     }
  2633.  
  2634.     /*
  2635.      * Make a new bigger array and use it to reset the property.
  2636.      * Automatically add the toplevel itself as the last element
  2637.      * of the list.
  2638.      */
  2639.  
  2640.     newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
  2641.     if (count > 0) {
  2642.     memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
  2643.     }
  2644.     /*
  2645.      * Fix taken from Tk 8.0 Windows version: count-1 and count instead of
  2646.      * count and count+1. Necessary for tests for 'wm colormapwindows'.
  2647.      */
  2648.     if (count == 0) {
  2649.         count++;
  2650.     }
  2651.     newPtr[count-1] = winPtr;
  2652.     newPtr[count] = topPtr;
  2653.     if (oldPtr != NULL) {
  2654.     ckfree((char *) oldPtr);
  2655.     }
  2656.  
  2657.     topPtr->wmInfoPtr->cmapList = newPtr;
  2658.     topPtr->wmInfoPtr->cmapCount = count+1;
  2659.  
  2660.     /*
  2661.      * Now we need to force the updated colormaps to be installed.
  2662.      */
  2663.  
  2664.     if (topPtr->wmInfoPtr == foregroundWmPtr) {
  2665.         TkOS2WmInstallColormaps(TkOS2GetHWND(topPtr->wmInfoPtr->reparent),
  2666.               /* WM_QUERYNEWPALETTE -> WM_REALIZEPALETTE + focus notification */
  2667.                                 WM_REALIZEPALETTE, 1);
  2668.     } else {
  2669.         TkOS2WmInstallColormaps(TkOS2GetHWND(topPtr->wmInfoPtr->reparent),
  2670.                /* WM_PALETTECHANGED -> WM_REALIZEPALETTE + focus notification */
  2671.                                 WM_REALIZEPALETTE, 0);
  2672.     }
  2673. }
  2674.  
  2675. /*
  2676.  *----------------------------------------------------------------------
  2677.  *
  2678.  * TkWmRemoveFromColormapWindows --
  2679.  *
  2680.  *      This procedure is called to remove a given window from the
  2681.  *      WM_COLORMAP_WINDOWS property for its top-level.  It is invoked
  2682.  *      when windows are deleted.
  2683.  *
  2684.  * Results:
  2685.  *      None.
  2686.  *
  2687.  * Side effects:
  2688.  *      WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
  2689.  *      property of its nearest top-level ancestor, unless the
  2690.  *      top-level itself is being deleted too.
  2691.  *
  2692.  *----------------------------------------------------------------------
  2693.  */
  2694.  
  2695. void
  2696. TkWmRemoveFromColormapWindows(winPtr)
  2697.     TkWindow *winPtr;           /* Window that may be present in
  2698.                                  * WM_COLORMAP_WINDOWS property for its
  2699.                                  * top-level.  Should not be a top-level
  2700.                                  * window. */
  2701. {
  2702.     TkWindow *topPtr;
  2703.     TkWindow **oldPtr;
  2704.     int count, i, j;
  2705.  
  2706.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  2707.         if (topPtr == NULL) {
  2708.             /*
  2709.              * Ancestors have been deleted, so skip the whole operation.
  2710.              * Seems like this can't ever happen?
  2711.              */
  2712.  
  2713.             return;
  2714.         }
  2715.         if (topPtr->flags & TK_TOP_LEVEL) {
  2716.             break;
  2717.         }
  2718.     }
  2719.     if (topPtr->flags & TK_ALREADY_DEAD) {
  2720.         /*
  2721.          * Top-level is being deleted, so there's no need to cleanup
  2722.          * the WM_COLORMAP_WINDOWS property.
  2723.          */
  2724.  
  2725.         return;
  2726.     }
  2727.  
  2728.     /*
  2729.      * Find the window and slide the following ones down to cover
  2730.      * it up.
  2731.      */
  2732.  
  2733.     count = topPtr->wmInfoPtr->cmapCount;
  2734.     oldPtr = topPtr->wmInfoPtr->cmapList;
  2735.     for (i = 0; i < count; i++) {
  2736.         if (oldPtr[i] == winPtr) {
  2737.             for (j = i ; j < count-1; j++) {
  2738.                 oldPtr[j] = oldPtr[j+1];
  2739.             }
  2740.             topPtr->wmInfoPtr->cmapCount = count-1;
  2741.             break;
  2742.         }
  2743.     }
  2744. }
  2745.  
  2746. /*
  2747.  *----------------------------------------------------------------------
  2748.  *
  2749.  * TkOS2WmConfigure --
  2750.  *
  2751.  *    Generate a ConfigureNotify event based on the current position
  2752.  *    information.
  2753.  *
  2754.  * Results:
  2755.  *    None.
  2756.  *
  2757.  * Side effects:
  2758.  *    Queues a new event.
  2759.  *
  2760.  *----------------------------------------------------------------------
  2761.  */
  2762.  
  2763. void
  2764. TkOS2WmConfigure(winPtr, pos)
  2765.     TkWindow *winPtr;
  2766.     SWP *pos; /* OS/2 PM y-coordinate */
  2767. {
  2768.     XEvent event;
  2769.     WmInfo *wmPtr;
  2770.     int width, height;
  2771.     SWP swp;
  2772.     ULONG x11y;
  2773.     ULONG rc;
  2774.  
  2775.     if (winPtr == NULL) {
  2776.     return;
  2777.     }
  2778.  
  2779.     wmPtr = winPtr->wmInfoPtr;
  2780.  
  2781.     /* PM Coordinates are reversed, translate wrt. screen height */
  2782.     x11y = yScreen - pos->cy - pos->y;
  2783.  
  2784.     /*
  2785.      * If the window was just iconified, then we don't need to update
  2786.      * the geometry, just iconify the window.
  2787.      */
  2788.  
  2789.     /* Is the window already iconified ? */
  2790.     swp.fl = pos->fl;
  2791.     if (swp.fl & SWP_MINIMIZE) {
  2792.         /* window now minimized */
  2793.     if (wmPtr->hints.initial_state == NormalState) {
  2794.             /* synchronize Tk with it */
  2795.         IconifyWindow(winPtr);
  2796.     }
  2797.         return;
  2798.     } else if (wmPtr->hints.initial_state == IconicState ||
  2799.                (wmPtr->hints.initial_state == WithdrawnState && pos->fl & SWP_RESTORE)) {
  2800.         DeiconifyWindow(winPtr);
  2801.     }
  2802.  
  2803.     width = pos->cx - wmPtr->borderWidth;
  2804.     height = pos->cy - wmPtr->borderHeight;
  2805.  
  2806.     /*
  2807.      * Update size information from the event.  There are a couple of
  2808.      * tricky points here:
  2809.      *
  2810.      * 1. If the user changed the size externally then set wmPtr->width
  2811.      *    and wmPtr->height just as if a "wm geometry" command had been
  2812.      *    invoked with the same information.
  2813.      * 2. However, if the size is changing in response to a request
  2814.      *    coming from us (WM_SYNC_PENDING is set), then don't set wmPtr->width
  2815.      *    or wmPtr->height (otherwise the window will stop tracking geometry
  2816.      *    manager requests).
  2817.      */
  2818.  
  2819.    if (!(wmPtr->flags & WM_SYNC_PENDING)) {
  2820.        if ((width != winPtr->changes.width)
  2821.                || (height != winPtr->changes.height)) {
  2822.            if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
  2823.                /*
  2824.                 * Don't set external width, since the user didn't change it
  2825.                 * from what the widgets asked for.
  2826.                 */
  2827.            } else {
  2828.                if (wmPtr->gridWin != NULL) {
  2829.                    wmPtr->width = wmPtr->reqGridWidth
  2830.                        + (width - winPtr->reqWidth)/wmPtr->widthInc;
  2831.                    if (wmPtr->width < 0) {
  2832.                        wmPtr->width = 0;
  2833.                    }
  2834.                } else {
  2835.                    wmPtr->width = width;
  2836.                }
  2837.            }
  2838.            if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
  2839.                /*
  2840.                 * Don't set external height, since the user didn't change it
  2841.                 * from what the widgets asked for.
  2842.                  */
  2843.             } else {
  2844.                 if (wmPtr->gridWin != NULL) {
  2845.                     wmPtr->height = wmPtr->reqGridHeight
  2846.                         + (height - winPtr->reqHeight)/wmPtr->heightInc;
  2847.                     if (wmPtr->height < 0) {
  2848.                         wmPtr->height = 0;
  2849.                     }
  2850.                 } else {
  2851.                     wmPtr->height = height;
  2852.                 }
  2853.             }
  2854.             wmPtr->configWidth = width;
  2855.             wmPtr->configHeight = height;
  2856.         }
  2857.         wmPtr->x = pos->x;
  2858.         wmPtr->y = x11y;
  2859.         wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  2860.     } else {
  2861.         if (wmPtr->flags & WM_NEGATIVE_X) {
  2862.             wmPtr->x = DisplayWidth(winPtr->display, winPtr->screenNum)
  2863.                 - pos->x - (width + wmPtr->borderWidth);
  2864.         } else {
  2865.             wmPtr->x = pos->x;
  2866.         }
  2867.         if (wmPtr->flags & WM_NEGATIVE_Y) {
  2868.             wmPtr->y = DisplayHeight(winPtr->display, winPtr->screenNum)
  2869.                 - x11y - (height + wmPtr->borderHeight);
  2870.         } else {
  2871.             wmPtr->y = x11y;
  2872.         }
  2873.     }
  2874.  
  2875.     /*
  2876.      * Update the shape of the contained window.
  2877.      */
  2878.  
  2879.     winPtr->changes.x = pos->x;
  2880.     winPtr->changes.y = x11y;
  2881.     winPtr->changes.width = width;
  2882.     winPtr->changes.height = height;
  2883.     WinSetWindowPos(TkOS2GetHWND(winPtr->window), HWND_TOP, wmPtr->xInParent,
  2884.                     wmPtr->yInParent, width, height, SWP_MOVE | SWP_SIZE);
  2885.  
  2886.     /*
  2887.      * Generate a ConfigureNotify event.
  2888.      */
  2889.  
  2890.     event.type = ConfigureNotify;
  2891.     event.xconfigure.serial = winPtr->display->request;
  2892.     event.xconfigure.send_event = False;
  2893.     event.xconfigure.display = winPtr->display;
  2894.     event.xconfigure.event = winPtr->window;
  2895.     event.xconfigure.window = winPtr->window;
  2896.     event.xconfigure.border_width = winPtr->changes.border_width;
  2897.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  2898.     event.xconfigure.x = pos->x;
  2899.     event.xconfigure.y = x11y;
  2900.     event.xconfigure.width = width;
  2901.     event.xconfigure.height = height;
  2902.     if (winPtr->changes.stack_mode == Above) {
  2903.         event.xconfigure.above = winPtr->changes.sibling;
  2904.     } else {
  2905.         event.xconfigure.above = None;
  2906.     }
  2907.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  2908. }
  2909.  
  2910. /*
  2911.  *----------------------------------------------------------------------
  2912.  *
  2913.  * IconifyWindow --
  2914.  *
  2915.  *    Put a toplevel window into the iconified state.
  2916.  *
  2917.  * Results:
  2918.  *    None.
  2919.  *
  2920.  * Side effects:
  2921.  *    Iconifies the window, possibly mapping it for the first time.
  2922.  *
  2923.  *----------------------------------------------------------------------
  2924.  */
  2925.  
  2926. void
  2927. IconifyWindow(winPtr)
  2928.     TkWindow *winPtr;        /* Window to be iconified. */
  2929. {
  2930.     WmInfo *wmPtr = winPtr->wmInfoPtr;
  2931.  
  2932.     wmPtr->hints.initial_state = IconicState;
  2933.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2934.     if (wmPtr->withdrawn) {
  2935.         Tk_MapWindow((Tk_Window) winPtr);
  2936.         wmPtr->withdrawn = 0;
  2937.     } else {
  2938.         wmPtr->flags |= WM_SYNC_PENDING;
  2939.         WinSetWindowPos(TkOS2GetHWND(wmPtr->reparent), HWND_DESKTOP,
  2940.                     0, 0, 0, 0, SWP_MINIMIZE);
  2941.         wmPtr->flags &= ~WM_SYNC_PENDING;
  2942.         XUnmapWindow(winPtr->display, winPtr->window);
  2943.     }
  2944.     }
  2945. }
  2946.  
  2947. /*
  2948.  *----------------------------------------------------------------------
  2949.  *
  2950.  * DeiconifyWindow --
  2951.  *
  2952.  *    Put a toplevel window into the deiconified state.
  2953.  *
  2954.  * Results:
  2955.  *    None.
  2956.  *
  2957.  * Side effects:
  2958.  *    Deiconifies the window, possibly mapping it for the first time.
  2959.  *
  2960.  *----------------------------------------------------------------------
  2961.  */
  2962.  
  2963. void
  2964. DeiconifyWindow(winPtr)
  2965.     TkWindow *winPtr;        /* Window to be deiconified. */
  2966. {
  2967.     WmInfo *wmPtr = winPtr->wmInfoPtr;
  2968.  
  2969.     wmPtr->hints.initial_state = NormalState;
  2970.     wmPtr->withdrawn = 0;
  2971.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2972.         if (wmPtr->withdrawn) {
  2973.             wmPtr->withdrawn = 0;
  2974.         }
  2975.     Tk_MapWindow((Tk_Window) winPtr);
  2976.     }
  2977. }
  2978.  
  2979. /*
  2980.  *----------------------------------------------------------------------
  2981.  *
  2982.  * TkOS2WmInstallColormaps --
  2983.  *
  2984.  *    Installs the colormaps associated with the toplevel which is
  2985.  *    currently active.
  2986.  *
  2987.  * Results:
  2988.  *    None
  2989.  *
  2990.  * Side effects:
  2991.  *    May change the system palette and generate damage.
  2992.  *
  2993.  *----------------------------------------------------------------------
  2994.  */
  2995.  
  2996. int
  2997. TkOS2WmInstallColormaps(hwnd, message, isForemost)
  2998.     HWND hwnd;            /* Toplevel wrapper window whose colormaps
  2999.                  * should be installed. */
  3000.     int message;        /* Either WM_REALIZEPALETTE or
  3001.                  * WM_SETFOCUS */
  3002.     int isForemost;        /* 1 if window is foremost, else 0 */
  3003. {
  3004.     int i;
  3005.     HPS hps;
  3006.     HPAL oldPalette;
  3007.     ULONG colorsChanged;
  3008.     TkOS2Drawable *todPtr =
  3009.         (TkOS2Drawable *) WinQueryWindowULong(hwnd, QWL_USER);
  3010.     TkWindow *winPtr = TkOS2GetWinPtr(todPtr);
  3011.     WmInfo *wmPtr;
  3012.  
  3013.     if (winPtr == NULL) {
  3014.     return 0;
  3015.     }
  3016.  
  3017.     wmPtr = winPtr->wmInfoPtr;
  3018.     hps = WinGetPS(hwnd);
  3019.  
  3020.     /*
  3021.      * The application should call WinRealizePalette if it has a palette,
  3022.      * or pass on to the default window procedure if it doesn't.
  3023.      * If the return value from WinRealizePalette is greater than 0, the
  3024.      * application should invalidate its window to cause a repaint using
  3025.      * the newly-realized palette.
  3026.      */
  3027.  
  3028.     /*
  3029.      * Install all of the palettes.
  3030.      */
  3031.  
  3032.     if (wmPtr->cmapCount > 0) {
  3033.         winPtr = wmPtr->cmapList[0];
  3034.     }
  3035.     i = 1;
  3036.  
  3037.     oldPalette = GpiSelectPalette(hps, TkOS2GetPalette(winPtr->atts.colormap));
  3038.     if ( WinRealizePalette(hwnd, hps, &colorsChanged) > 0 ) {
  3039.         RefreshColormap(winPtr->atts.colormap);
  3040.     }
  3041.     for (; i < wmPtr->cmapCount; i++) {
  3042.         HPS winPS;
  3043.         winPtr = wmPtr->cmapList[i];
  3044.         winPS = WinGetPS(TkOS2GetHWND(winPtr->window));
  3045.         GpiSelectPalette(winPS, TkOS2GetPalette(winPtr->atts.colormap));
  3046.         if ( WinRealizePalette(TkOS2GetHWND(winPtr->window), winPS, &colorsChanged) > 0 ) {
  3047.         }
  3048.         WinReleasePS(winPS);
  3049.     }
  3050.  
  3051.     WinReleasePS(hps);
  3052.     return TRUE;
  3053. }
  3054.  
  3055. /*
  3056.  *----------------------------------------------------------------------
  3057.  *
  3058.  * RefreshColormap --
  3059.  *
  3060.  *      This function is called to force all of the windows that use
  3061.  *      a given colormap to redraw themselves.  The quickest way to
  3062.  *      do this is to iterate over the toplevels, looking in the
  3063.  *      cmapList for matches.  This will quickly eliminate subtrees
  3064.  *      that don't use a given colormap.
  3065.  *
  3066.  * Results:
  3067.  *      None.
  3068.  *
  3069.  * Side effects:
  3070.  *      Causes damage events to be generated.
  3071.  *
  3072.  *----------------------------------------------------------------------
  3073.  */
  3074.  
  3075. static void
  3076. RefreshColormap(colormap)
  3077.     Colormap colormap;
  3078. {
  3079.     WmInfo *wmPtr;
  3080.     int i;
  3081.  
  3082.     for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
  3083.         if (wmPtr->cmapCount > 0) {
  3084.             for (i = 0; i < wmPtr->cmapCount; i++) {
  3085.                 if ((wmPtr->cmapList[i]->atts.colormap == colormap)
  3086.                         && Tk_IsMapped(wmPtr->cmapList[i])) {
  3087.                     InvalidateSubTree(wmPtr->cmapList[i], colormap);
  3088.                 }
  3089.             }
  3090.         } else if ((wmPtr->winPtr->atts.colormap == colormap)
  3091.                 && Tk_IsMapped(wmPtr->winPtr)) {
  3092.             InvalidateSubTree(wmPtr->winPtr, colormap);
  3093.         }
  3094.     }
  3095. }
  3096.  
  3097. /*
  3098.  *----------------------------------------------------------------------
  3099.  *
  3100.  * InvalidateSubTree --
  3101.  *
  3102.  *      This function recursively generates damage for a window and
  3103.  *      all of its mapped children that belong to the same toplevel and
  3104.  *      are using the specified colormap.
  3105.  *
  3106.  * Results:
  3107.  *      None.
  3108.  *
  3109.  * Side effects:
  3110.  *      Generates damage for the specified subtree.
  3111.  *
  3112.  *----------------------------------------------------------------------
  3113.  */
  3114.  
  3115. static void
  3116. InvalidateSubTree(winPtr, colormap)
  3117.     TkWindow *winPtr;
  3118.     Colormap colormap;
  3119. {
  3120.  
  3121.     TkWindow *childPtr;
  3122.  
  3123.     /*
  3124.      * Generate damage for the current window if it is using the
  3125.      * specified colormap.
  3126.      */
  3127.  
  3128.     if (winPtr->atts.colormap == colormap) {
  3129.         WinInvalidateRect(TkOS2GetHWND(winPtr->window), NULL, FALSE);
  3130.     }
  3131.  
  3132.      for (childPtr = winPtr->childList; childPtr != NULL;
  3133.              childPtr = childPtr->nextPtr) {
  3134.          /*
  3135.           * We can stop the descent when we hit an unmapped or
  3136.           * toplevel window.
  3137.           */
  3138.  
  3139.          if (!Tk_IsTopLevel(childPtr) && Tk_IsMapped(childPtr)) {
  3140.              InvalidateSubTree(childPtr, colormap);
  3141.          }
  3142.      }
  3143. }
  3144.  
  3145. /*
  3146.  *----------------------------------------------------------------------
  3147.  *
  3148.  * TkOS2GetSystemPalette --
  3149.  *
  3150.  *    Retrieves the currently installed foreground palette.
  3151.  *
  3152.  * Results:
  3153.  *    Returns the global foreground palette, if there is one.
  3154.  *    Otherwise, returns NULL.
  3155.  *
  3156.  * Side effects:
  3157.  *    None.
  3158.  *
  3159.  *----------------------------------------------------------------------
  3160.  */
  3161.  
  3162. HPAL
  3163. TkOS2GetSystemPalette()
  3164. {
  3165.     return systemPalette;
  3166. }
  3167.  
  3168. /*
  3169.  *----------------------------------------------------------------------
  3170.  *
  3171.  * GetMinSize --
  3172.  *
  3173.  *      This procedure computes the current minWidth and minHeight
  3174.  *      values for a window, taking into account the possibility
  3175.  *      that they may be defaulted.
  3176.  *
  3177.  * Results:
  3178.  *      The values at *minWidthPtr and *minHeightPtr are filled
  3179.  *      in with the minimum allowable dimensions of wmPtr's window,
  3180.  *      in grid units.  If the requested minimum is smaller than the
  3181.  *      system required minimum, then this procedure computes the
  3182.  *      smallest size that will satisfy both the system and the
  3183.  *      grid constraints.
  3184.  *
  3185.  * Side effects:
  3186.  *      None.
  3187.  *
  3188.  *----------------------------------------------------------------------
  3189.  */
  3190.  
  3191. static void
  3192. GetMinSize(wmPtr, minWidthPtr, minHeightPtr)
  3193.     WmInfo *wmPtr;              /* Window manager information for the
  3194.                                  * window. */
  3195.     int *minWidthPtr;           /* Where to store the current minimum
  3196.                                  * width of the window. */
  3197.     int *minHeightPtr;          /* Where to store the current minimum
  3198.                                  * height of the window. */
  3199. {
  3200.     int tmp, base;
  3201.     TkWindow *winPtr = wmPtr->winPtr;
  3202.  
  3203.     /*
  3204.      * Compute the minimum width by taking the default client size
  3205.      * and rounding it up to the nearest grid unit.  Return the greater
  3206.      * of the default minimum and the specified minimum.
  3207.      */
  3208.  
  3209.     tmp = wmPtr->defMinWidth - wmPtr->borderWidth;
  3210.     if (tmp < 0) {
  3211.         tmp = 0;
  3212.     }
  3213.     if (wmPtr->gridWin != NULL) {
  3214.         base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
  3215.         if (base < 0) {
  3216.             base = 0;
  3217.         }
  3218.         tmp = ((tmp - base) + wmPtr->widthInc - 1)/wmPtr->widthInc;
  3219.     }
  3220.     if (tmp < wmPtr->minWidth) {
  3221.         tmp = wmPtr->minWidth;
  3222.     }
  3223.     *minWidthPtr = tmp;
  3224.  
  3225.     /*
  3226.      * Compute the minimum height in a similar fashion.
  3227.      */
  3228.  
  3229.     tmp = wmPtr->defMinHeight - wmPtr->borderHeight;
  3230.     if (tmp < 0) {
  3231.         tmp = 0;
  3232.     }
  3233.     if (wmPtr->gridWin != NULL) {
  3234.         base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
  3235.         if (base < 0) {
  3236.             base = 0;
  3237.         }
  3238.         tmp = ((tmp - base) + wmPtr->heightInc - 1)/wmPtr->heightInc;
  3239.     }
  3240.     if (tmp < wmPtr->minHeight) {
  3241.         tmp = wmPtr->minHeight;
  3242.     }
  3243.     *minHeightPtr = tmp;
  3244. }
  3245.  
  3246. /*
  3247.  *----------------------------------------------------------------------
  3248.  *
  3249.  * GetMaxSize --
  3250.  *
  3251.  *      This procedure computes the current maxWidth and maxHeight
  3252.  *      values for a window, taking into account the possibility
  3253.  *      that they may be defaulted.
  3254.  *
  3255.  * Results:
  3256.  *      The values at *maxWidthPtr and *maxHeightPtr are filled
  3257.  *      in with the maximum allowable dimensions of wmPtr's window,
  3258.  *      in grid units.  If no maximum has been specified for the
  3259.  *      window, then this procedure computes the largest sizes that
  3260.  *      will fit on the screen.
  3261.  *
  3262.  * Side effects:
  3263.  *      None.
  3264.  *
  3265.  *----------------------------------------------------------------------
  3266.  */
  3267.  
  3268. static void
  3269. GetMaxSize(wmPtr, maxWidthPtr, maxHeightPtr)
  3270.     WmInfo *wmPtr;              /* Window manager information for the
  3271.                                  * window. */
  3272.     int *maxWidthPtr;           /* Where to store the current maximum
  3273.                                  * width of the window. */
  3274.     int *maxHeightPtr;          /* Where to store the current maximum
  3275.                                  * height of the window. */
  3276. {
  3277.     int tmp;
  3278.  
  3279.     if (wmPtr->maxWidth > 0) {
  3280.         *maxWidthPtr = wmPtr->maxWidth;
  3281.     } else {
  3282.         /*
  3283.          * Must compute a default width.  Fill up the display, leaving a
  3284.          * bit of extra space for the window manager's borders.
  3285.          */
  3286.  
  3287.         tmp = wmPtr->defMaxWidth - wmPtr->borderWidth;
  3288.         if (wmPtr->gridWin != NULL) {
  3289.             /*
  3290.              * Gridding is turned on;  convert from pixels to grid units.
  3291.              */
  3292.  
  3293.             tmp = wmPtr->reqGridWidth
  3294.                     + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
  3295.         }
  3296.         *maxWidthPtr = tmp;
  3297.     }
  3298.     if (wmPtr->maxHeight > 0) {
  3299.         *maxHeightPtr = wmPtr->maxHeight;
  3300.     } else {
  3301.         tmp = wmPtr->defMaxHeight - wmPtr->borderHeight;
  3302.         if (wmPtr->gridWin != NULL) {
  3303.             tmp = wmPtr->reqGridHeight
  3304.                     + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
  3305.         }
  3306.         *maxHeightPtr = tmp;
  3307.     }
  3308. }
  3309.