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

通讯编程

开发平台:

Visual C++

  1.  *
  2.  * Results:
  3.  * A standard Tcl result.
  4.  *
  5.  * Side effects:
  6.  * See the user documentation.
  7.  *
  8.  *----------------------------------------------------------------------
  9.  */
  10. static int
  11. WmIconmaskCmd(tkwin, winPtr, interp, objc, objv)
  12.     Tk_Window tkwin; /* Main window of the application. */
  13.     TkWindow *winPtr;           /* Toplevel to work with */
  14.     Tcl_Interp *interp; /* Current interpreter. */
  15.     int objc; /* Number of arguments. */
  16.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  17. {
  18.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  19.     Pixmap pixmap;
  20.     char *argv3;
  21.     if ((objc != 3) && (objc != 4)) {
  22. Tcl_WrongNumArgs(interp, 2, objv, "window ?bitmap?");
  23. return TCL_ERROR;
  24.     }
  25.     if (objc == 3) {
  26. if (wmPtr->hints.flags & IconMaskHint) {
  27.     Tcl_SetResult(interp, (char *)
  28.     Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
  29.     TCL_STATIC);
  30. }
  31. return TCL_OK;
  32.     }
  33.     argv3 = Tcl_GetString(objv[3]);
  34.     if (*argv3 == '') {
  35. if (wmPtr->hints.icon_mask != None) {
  36.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  37. }
  38. wmPtr->hints.flags &= ~IconMaskHint;
  39.     } else {
  40. pixmap = Tk_GetBitmap(interp, tkwin, argv3);
  41. if (pixmap == None) {
  42.     return TCL_ERROR;
  43. }
  44. wmPtr->hints.icon_mask = pixmap;
  45. wmPtr->hints.flags |= IconMaskHint;
  46.     }
  47.     return TCL_OK;
  48. }
  49. /*
  50.  *----------------------------------------------------------------------
  51.  *
  52.  * WmIconnameCmd --
  53.  *
  54.  * This procedure is invoked to process the "wm iconname" Tcl command.
  55.  * See the user documentation for details on what it does.
  56.  *
  57.  * Results:
  58.  * A standard Tcl result.
  59.  *
  60.  * Side effects:
  61.  * See the user documentation.
  62.  *
  63.  *----------------------------------------------------------------------
  64.  */
  65. static int
  66. WmIconnameCmd(tkwin, winPtr, interp, objc, objv)
  67.     Tk_Window tkwin; /* Main window of the application. */
  68.     TkWindow *winPtr;           /* Toplevel to work with */
  69.     Tcl_Interp *interp; /* Current interpreter. */
  70.     int objc; /* Number of arguments. */
  71.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  72. {
  73.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  74.     char *argv3;
  75.     int length;
  76.     if (objc > 4) {
  77. Tcl_WrongNumArgs(interp, 2, objv, "window ?newName?");
  78. return TCL_ERROR;
  79.     }
  80.     if (objc == 3) {
  81. Tcl_SetResult(interp,
  82. ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""),
  83. TCL_STATIC);
  84. return TCL_OK;
  85.     } else {
  86. if (wmPtr->iconName != NULL) {
  87.     ckfree((char *) wmPtr->iconName);
  88. }
  89. argv3 = Tcl_GetStringFromObj(objv[3], &length);
  90. wmPtr->iconName = ckalloc((unsigned) (length + 1));
  91. strcpy(wmPtr->iconName, argv3);
  92. if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  93.     XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
  94. }
  95.     }
  96.     return TCL_OK;
  97. }
  98. /*
  99.  *----------------------------------------------------------------------
  100.  *
  101.  * WmIconphotoCmd --
  102.  *
  103.  * This procedure is invoked to process the "wm iconphoto"
  104.  * Tcl command.
  105.  * See the user documentation for details on what it does.
  106.  *
  107.  * Results:
  108.  * A standard Tcl result.
  109.  *
  110.  * Side effects:
  111.  * See the user documentation.
  112.  *
  113.  *----------------------------------------------------------------------
  114.  */
  115. static int
  116. WmIconphotoCmd(tkwin, winPtr, interp, objc, objv)
  117.     Tk_Window tkwin; /* Main window of the application. */
  118.     TkWindow *winPtr;           /* Toplevel to work with */
  119.     Tcl_Interp *interp; /* Current interpreter. */
  120.     int objc; /* Number of arguments. */
  121.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  122. {
  123.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  124.     TkWindow *useWinPtr = winPtr; /* window to apply to (NULL if -default) */
  125.     Tk_PhotoHandle photo;
  126.     Tk_PhotoImageBlock block;
  127.     int i, size, width, height, idx, bufferSize, startObj = 3;
  128.     unsigned char *bgraPixelPtr;
  129.     BlockOfIconImagesPtr lpIR;
  130.     WinIconPtr titlebaricon = NULL;
  131.     HICON hIcon;
  132.     if (objc < 4) {
  133. Tcl_WrongNumArgs(interp, 2, objv,
  134. "window ?-default? image1 ?image2 ...?");
  135. return TCL_ERROR;
  136.     }
  137.     /*
  138.      * Iterate over all images to validate their existence.
  139.      */
  140.     if (strcmp(Tcl_GetString(objv[3]), "-default") == 0) {
  141. useWinPtr = NULL;
  142. startObj = 4;
  143. if (objc == 4) {
  144.     Tcl_WrongNumArgs(interp, 2, objv,
  145.     "window ?-default? image1 ?image2 ...?");
  146.     return TCL_ERROR;
  147. }
  148.     }
  149.     for (i = startObj; i < objc; i++) {
  150. photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
  151. if (photo == NULL) {
  152.     Tcl_AppendResult(interp, "can't use "", Tcl_GetString(objv[i]),
  153.     "" as iconphoto: not a photo image", (char *) NULL);
  154.     return TCL_ERROR;
  155. }
  156.     }
  157.     /* We have calculated the size of the data. Try to allocate the needed
  158.      * memory space. */
  159.     size = sizeof(BlockOfIconImages)
  160. + (sizeof(ICONIMAGE) * (objc - (startObj+1)));
  161.     lpIR = (BlockOfIconImagesPtr) Tcl_AttemptAlloc(size);
  162.     if (lpIR == NULL) {
  163. return TCL_ERROR;
  164.     }
  165.     ZeroMemory(lpIR, size);
  166.     lpIR->nNumImages = objc - startObj;
  167.     for (i = startObj; i < objc; i++) {
  168. photo = Tk_FindPhoto(interp, Tcl_GetString(objv[i]));
  169. Tk_PhotoGetSize(photo, &width, &height);
  170. Tk_PhotoGetImage(photo, &block);
  171. /*
  172.  * Convert the image data into BGRA format (RGBQUAD) and then
  173.  * encode the image data into an HICON.
  174.  */
  175. bufferSize = height * width * block.pixelSize;
  176. bgraPixelPtr = ckalloc(bufferSize);
  177. for (idx = 0 ; idx < bufferSize ; idx += 4) {
  178.     bgraPixelPtr[idx] = block.pixelPtr[idx+2];
  179.     bgraPixelPtr[idx+1] = block.pixelPtr[idx+1];
  180.     bgraPixelPtr[idx+2] = block.pixelPtr[idx+0];
  181.     bgraPixelPtr[idx+3] = block.pixelPtr[idx+3];
  182. }
  183. hIcon = CreateIcon(Tk_GetHINSTANCE(), width, height, 1, 32,
  184. NULL, (BYTE *) bgraPixelPtr);
  185. ckfree(bgraPixelPtr);
  186. if (hIcon == NULL) {
  187.     /* XXX should free up created icons */
  188.     Tcl_Free((char *) lpIR);
  189.     Tcl_AppendResult(interp, "failed to create icon for "",
  190.     Tcl_GetString(objv[i]), """, (char *) NULL);
  191.     return TCL_ERROR;
  192. }
  193. lpIR->IconImages[i-startObj].Width  = width;
  194. lpIR->IconImages[i-startObj].Height = height;
  195. lpIR->IconImages[i-startObj].Colors = 4;
  196. lpIR->IconImages[i-startObj].hIcon  = hIcon;
  197.     }
  198.     titlebaricon = (WinIconPtr) ckalloc(sizeof(WinIconInstance));
  199.     titlebaricon->iconBlock = lpIR;
  200.     titlebaricon->refCount = 1;
  201.     if (WinSetIcon(interp, titlebaricon, (Tk_Window) useWinPtr) != TCL_OK) {
  202. /* We didn't use the titlebaricon after all */
  203. DecrIconRefCount(titlebaricon);
  204. return TCL_ERROR;
  205.     }
  206.     return TCL_OK;
  207. }
  208. /*
  209.  *----------------------------------------------------------------------
  210.  *
  211.  * WmIconpositionCmd --
  212.  *
  213.  * This procedure is invoked to process the "wm iconposition"
  214.  * Tcl command.
  215.  * See the user documentation for details on what it does.
  216.  *
  217.  * Results:
  218.  * A standard Tcl result.
  219.  *
  220.  * Side effects:
  221.  * See the user documentation.
  222.  *
  223.  *----------------------------------------------------------------------
  224.  */
  225. static int
  226. WmIconpositionCmd(tkwin, winPtr, interp, objc, objv)
  227.     Tk_Window tkwin; /* Main window of the application. */
  228.     TkWindow *winPtr;           /* Toplevel to work with */
  229.     Tcl_Interp *interp; /* Current interpreter. */
  230.     int objc; /* Number of arguments. */
  231.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  232. {
  233.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  234.     int x, y;
  235.     if ((objc != 3) && (objc != 5)) {
  236. Tcl_WrongNumArgs(interp, 2, objv, "window ?x y?");
  237. return TCL_ERROR;
  238.     }
  239.     if (objc == 3) {
  240. if (wmPtr->hints.flags & IconPositionHint) {
  241.     char buf[TCL_INTEGER_SPACE * 2];
  242.     sprintf(buf, "%d %d", wmPtr->hints.icon_x,
  243.     wmPtr->hints.icon_y);
  244.     Tcl_SetResult(interp, buf, TCL_VOLATILE);
  245. }
  246. return TCL_OK;
  247.     }
  248.     if (*Tcl_GetString(objv[3]) == '') {
  249. wmPtr->hints.flags &= ~IconPositionHint;
  250.     } else {
  251. if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
  252. || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)){
  253.     return TCL_ERROR;
  254. }
  255. wmPtr->hints.icon_x = x;
  256. wmPtr->hints.icon_y = y;
  257. wmPtr->hints.flags |= IconPositionHint;
  258.     }
  259.     return TCL_OK;
  260. }
  261. /*
  262.  *----------------------------------------------------------------------
  263.  *
  264.  * WmIconwindowCmd --
  265.  *
  266.  * This procedure is invoked to process the "wm iconwindow" Tcl command.
  267.  * See the user documentation for details on what it does.
  268.  *
  269.  * Results:
  270.  * A standard Tcl result.
  271.  *
  272.  * Side effects:
  273.  * See the user documentation.
  274.  *
  275.  *----------------------------------------------------------------------
  276.  */
  277. static int
  278. WmIconwindowCmd(tkwin, winPtr, interp, objc, objv)
  279.     Tk_Window tkwin; /* Main window of the application. */
  280.     TkWindow *winPtr;           /* Toplevel to work with */
  281.     Tcl_Interp *interp; /* Current interpreter. */
  282.     int objc; /* Number of arguments. */
  283.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  284. {
  285.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  286.     Tk_Window tkwin2;
  287.     WmInfo *wmPtr2;
  288.     XSetWindowAttributes atts;
  289.     if ((objc != 3) && (objc != 4)) {
  290. Tcl_WrongNumArgs(interp, 2, objv, "window ?pathName?");
  291. return TCL_ERROR;
  292.     }
  293.     if (objc == 3) {
  294. if (wmPtr->icon != NULL) {
  295.     Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC);
  296. }
  297. return TCL_OK;
  298.     }
  299.     if (*Tcl_GetString(objv[3]) == '') {
  300. wmPtr->hints.flags &= ~IconWindowHint;
  301. if (wmPtr->icon != NULL) {
  302.     /*
  303.      * Let the window use button events again, then remove
  304.      * it as icon window.
  305.      */
  306.     atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
  307.     | ButtonPressMask;
  308.     Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
  309.     wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  310.     wmPtr2->iconFor = NULL;
  311.     wmPtr2->hints.initial_state = WithdrawnState;
  312. }
  313. wmPtr->icon = NULL;
  314.     } else {
  315. if (TkGetWindowFromObj(interp, tkwin, objv[3], &tkwin2) != TCL_OK) {
  316.     return TCL_ERROR;
  317. }
  318. if (!Tk_IsTopLevel(tkwin2)) {
  319.     Tcl_AppendResult(interp, "can't use ", Tcl_GetString(objv[3]),
  320.     " as icon window: not at top level", (char *) NULL);
  321.     return TCL_ERROR;
  322. }
  323. wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
  324. if (wmPtr2->iconFor != NULL) {
  325.     Tcl_AppendResult(interp, Tcl_GetString(objv[3]),
  326.     " is already an icon for ",
  327.     Tk_PathName(wmPtr2->iconFor), (char *) NULL);
  328.     return TCL_ERROR;
  329. }
  330. if (wmPtr->icon != NULL) {
  331.     WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  332.     wmPtr3->iconFor = NULL;
  333.     /*
  334.      * Let the window use button events again.
  335.      */
  336.     atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
  337.     | ButtonPressMask;
  338.     Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
  339. }
  340. /*
  341.  * Disable button events in the icon window:  some window
  342.  * managers (like olvwm) want to get the events themselves,
  343.  * but X only allows one application at a time to receive
  344.  * button events for a window.
  345.  */
  346. atts.event_mask = Tk_Attributes(tkwin2)->event_mask
  347. & ~ButtonPressMask;
  348. Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
  349. Tk_MakeWindowExist(tkwin2);
  350. wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
  351. wmPtr->hints.flags |= IconWindowHint;
  352. wmPtr->icon = tkwin2;
  353. wmPtr2->iconFor = (Tk_Window) winPtr;
  354. if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
  355.     wmPtr2->flags |= WM_WITHDRAWN;
  356.     TkpWmSetState(((TkWindow *) tkwin2), WithdrawnState);
  357. }
  358.     }
  359.     return TCL_OK;
  360. }
  361. /*
  362.  *----------------------------------------------------------------------
  363.  *
  364.  * WmMaxsizeCmd --
  365.  *
  366.  * This procedure is invoked to process the "wm maxsize" Tcl command.
  367.  * See the user documentation for details on what it does.
  368.  *
  369.  * Results:
  370.  * A standard Tcl result.
  371.  *
  372.  * Side effects:
  373.  * See the user documentation.
  374.  *
  375.  *----------------------------------------------------------------------
  376.  */
  377. static int
  378. WmMaxsizeCmd(tkwin, winPtr, interp, objc, objv)
  379.     Tk_Window tkwin; /* Main window of the application. */
  380.     TkWindow *winPtr;           /* Toplevel to work with */
  381.     Tcl_Interp *interp; /* Current interpreter. */
  382.     int objc; /* Number of arguments. */
  383.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  384. {
  385.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  386.     int width, height;
  387.     if ((objc != 3) && (objc != 5)) {
  388. Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
  389. return TCL_ERROR;
  390.     }
  391.     if (objc == 3) {
  392. char buf[TCL_INTEGER_SPACE * 2];
  393. GetMaxSize(wmPtr, &width, &height);
  394. sprintf(buf, "%d %d", width, height);
  395. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  396. return TCL_OK;
  397.     }
  398.     if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
  399.     || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
  400. return TCL_ERROR;
  401.     }
  402.     wmPtr->maxWidth = width;
  403.     wmPtr->maxHeight = height;
  404.     WmUpdateGeom(wmPtr, winPtr);
  405.     return TCL_OK;
  406. }
  407. /*
  408.  *----------------------------------------------------------------------
  409.  *
  410.  * WmMinsizeCmd --
  411.  *
  412.  * This procedure is invoked to process the "wm minsize" Tcl command.
  413.  * See the user documentation for details on what it does.
  414.  *
  415.  * Results:
  416.  * A standard Tcl result.
  417.  *
  418.  * Side effects:
  419.  * See the user documentation.
  420.  *
  421.  *----------------------------------------------------------------------
  422.  */
  423. static int
  424. WmMinsizeCmd(tkwin, winPtr, interp, objc, objv)
  425.     Tk_Window tkwin; /* Main window of the application. */
  426.     TkWindow *winPtr;           /* Toplevel to work with */
  427.     Tcl_Interp *interp; /* Current interpreter. */
  428.     int objc; /* Number of arguments. */
  429.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  430. {
  431.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  432.     int width, height;
  433.     if ((objc != 3) && (objc != 5)) {
  434. Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
  435. return TCL_ERROR;
  436.     }
  437.     if (objc == 3) {
  438. char buf[TCL_INTEGER_SPACE * 2];
  439. GetMinSize(wmPtr, &width, &height);
  440. sprintf(buf, "%d %d", width, height);
  441. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  442. return TCL_OK;
  443.     }
  444.     if ((Tcl_GetIntFromObj(interp, objv[3], &width) != TCL_OK)
  445.     || (Tcl_GetIntFromObj(interp, objv[4], &height) != TCL_OK)) {
  446. return TCL_ERROR;
  447.     }
  448.     wmPtr->minWidth = width;
  449.     wmPtr->minHeight = height;
  450.     WmUpdateGeom(wmPtr, winPtr);
  451.     return TCL_OK;
  452. }
  453. /*
  454.  *----------------------------------------------------------------------
  455.  *
  456.  * WmOverrideredirectCmd --
  457.  *
  458.  * This procedure is invoked to process the "wm overrideredirect"
  459.  * Tcl command.
  460.  * See the user documentation for details on what it does.
  461.  *
  462.  * Results:
  463.  * A standard Tcl result.
  464.  *
  465.  * Side effects:
  466.  * See the user documentation.
  467.  *
  468.  *----------------------------------------------------------------------
  469.  */
  470. static int
  471. WmOverrideredirectCmd(tkwin, winPtr, interp, objc, objv)
  472.     Tk_Window tkwin; /* Main window of the application. */
  473.     TkWindow *winPtr;           /* Toplevel to work with */
  474.     Tcl_Interp *interp; /* Current interpreter. */
  475.     int objc; /* Number of arguments. */
  476.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  477. {
  478.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  479.     int boolean, curValue;
  480.     XSetWindowAttributes atts;
  481.     if ((objc != 3) && (objc != 4)) {
  482. Tcl_WrongNumArgs(interp, 2, objv, "window ?boolean?");
  483. return TCL_ERROR;
  484.     }
  485.     curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
  486.     if (objc == 3) {
  487. Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue);
  488. return TCL_OK;
  489.     }
  490.     if (Tcl_GetBooleanFromObj(interp, objv[3], &boolean) != TCL_OK) {
  491. return TCL_ERROR;
  492.     }
  493.     if (curValue != boolean) {
  494. /*
  495.  * Only do this if we are really changing value, because it
  496.  * causes some funky stuff to occur
  497.  */
  498. atts.override_redirect = (boolean) ? True : False;
  499. Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
  500. &atts);
  501. if (!(wmPtr->flags & (WM_NEVER_MAPPED)
  502. && !(winPtr->flags & TK_EMBEDDED))) {
  503.     UpdateWrapper(winPtr);
  504. }
  505.     }
  506.     return TCL_OK;
  507. }
  508. /*
  509.  *----------------------------------------------------------------------
  510.  *
  511.  * WmPositionfromCmd --
  512.  *
  513.  * This procedure is invoked to process the "wm positionfrom"
  514.  * Tcl command.
  515.  * See the user documentation for details on what it does.
  516.  *
  517.  * Results:
  518.  * A standard Tcl result.
  519.  *
  520.  * Side effects:
  521.  * See the user documentation.
  522.  *
  523.  *----------------------------------------------------------------------
  524.  */
  525. static int
  526. WmPositionfromCmd(tkwin, winPtr, interp, objc, objv)
  527.     Tk_Window tkwin; /* Main window of the application. */
  528.     TkWindow *winPtr;           /* Toplevel to work with */
  529.     Tcl_Interp *interp; /* Current interpreter. */
  530.     int objc; /* Number of arguments. */
  531.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  532. {
  533.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  534.     static CONST char *optionStrings[] = {
  535. "program", "user", (char *) NULL };
  536.     enum options {
  537. OPT_PROGRAM, OPT_USER };
  538.     int index;
  539.     if ((objc != 3) && (objc != 4)) {
  540. Tcl_WrongNumArgs(interp, 2, objv, "window ?user/program?");
  541. return TCL_ERROR;
  542.     }
  543.     if (objc == 3) {
  544. if (wmPtr->sizeHintsFlags & USPosition) {
  545.     Tcl_SetResult(interp, "user", TCL_STATIC);
  546. } else if (wmPtr->sizeHintsFlags & PPosition) {
  547.     Tcl_SetResult(interp, "program", TCL_STATIC);
  548. }
  549. return TCL_OK;
  550.     }
  551.     if (*Tcl_GetString(objv[3]) == '') {
  552. wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
  553.     } else {
  554. if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
  555. &index) != TCL_OK) {
  556.     return TCL_ERROR;
  557. }
  558. if (index == OPT_USER) {
  559.     wmPtr->sizeHintsFlags &= ~PPosition;
  560.     wmPtr->sizeHintsFlags |= USPosition;
  561. } else {
  562.     wmPtr->sizeHintsFlags &= ~USPosition;
  563.     wmPtr->sizeHintsFlags |= PPosition;
  564. }
  565.     }
  566.     WmUpdateGeom(wmPtr, winPtr);
  567.     return TCL_OK;
  568. }
  569. /*
  570.  *----------------------------------------------------------------------
  571.  *
  572.  * WmProtocolCmd --
  573.  *
  574.  * This procedure is invoked to process the "wm protocol" Tcl command.
  575.  * See the user documentation for details on what it does.
  576.  *
  577.  * Results:
  578.  * A standard Tcl result.
  579.  *
  580.  * Side effects:
  581.  * See the user documentation.
  582.  *
  583.  *----------------------------------------------------------------------
  584.  */
  585. static int
  586. WmProtocolCmd(tkwin, winPtr, interp, objc, objv)
  587.     Tk_Window tkwin; /* Main window of the application. */
  588.     TkWindow *winPtr;           /* Toplevel to work with */
  589.     Tcl_Interp *interp; /* Current interpreter. */
  590.     int objc; /* Number of arguments. */
  591.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  592. {
  593.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  594.     register ProtocolHandler *protPtr, *prevPtr;
  595.     Atom protocol;
  596.     char *cmd;
  597.     int cmdLength;
  598.     if ((objc < 3) || (objc > 5)) {
  599. Tcl_WrongNumArgs(interp, 2, objv, "window ?name? ?command?");
  600. return TCL_ERROR;
  601.     }
  602.     if (objc == 3) {
  603. /*
  604.  * Return a list of all defined protocols for the window.
  605.  */
  606. for (protPtr = wmPtr->protPtr; protPtr != NULL;
  607.      protPtr = protPtr->nextPtr) {
  608.     Tcl_AppendElement(interp,
  609.     Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
  610. }
  611. return TCL_OK;
  612.     }
  613.     protocol = Tk_InternAtom((Tk_Window) winPtr, Tcl_GetString(objv[3]));
  614.     if (objc == 4) {
  615. /*
  616.  * Return the command to handle a given protocol.
  617.  */
  618. for (protPtr = wmPtr->protPtr; protPtr != NULL;
  619.      protPtr = protPtr->nextPtr) {
  620.     if (protPtr->protocol == protocol) {
  621. Tcl_SetResult(interp, protPtr->command, TCL_STATIC);
  622. return TCL_OK;
  623.     }
  624. }
  625. return TCL_OK;
  626.     }
  627.     /*
  628.      * Delete any current protocol handler, then create a new
  629.      * one with the specified command, unless the command is
  630.      * empty.
  631.      */
  632.     for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
  633.  prevPtr = protPtr, protPtr = protPtr->nextPtr) {
  634. if (protPtr->protocol == protocol) {
  635.     if (prevPtr == NULL) {
  636. wmPtr->protPtr = protPtr->nextPtr;
  637.     } else {
  638. prevPtr->nextPtr = protPtr->nextPtr;
  639.     }
  640.     Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  641.     break;
  642. }
  643.     }
  644.     cmd = Tcl_GetStringFromObj(objv[4], &cmdLength);
  645.     if (cmdLength > 0) {
  646. protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
  647. protPtr->protocol = protocol;
  648. protPtr->nextPtr = wmPtr->protPtr;
  649. wmPtr->protPtr = protPtr;
  650. protPtr->interp = interp;
  651. strcpy(protPtr->command, cmd);
  652.     }
  653.     return TCL_OK;
  654. }
  655. /*
  656.  *----------------------------------------------------------------------
  657.  *
  658.  * WmResizableCmd --
  659.  *
  660.  * This procedure is invoked to process the "wm resizable" Tcl command.
  661.  * See the user documentation for details on what it does.
  662.  *
  663.  * Results:
  664.  * A standard Tcl result.
  665.  *
  666.  * Side effects:
  667.  * See the user documentation.
  668.  *
  669.  *----------------------------------------------------------------------
  670.  */
  671. static int
  672. WmResizableCmd(tkwin, winPtr, interp, objc, objv)
  673.     Tk_Window tkwin; /* Main window of the application. */
  674.     TkWindow *winPtr;           /* Toplevel to work with */
  675.     Tcl_Interp *interp; /* Current interpreter. */
  676.     int objc; /* Number of arguments. */
  677.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  678. {
  679.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  680.     int width, height;
  681.     if ((objc != 3) && (objc != 5)) {
  682. Tcl_WrongNumArgs(interp, 2, objv, "window ?width height?");
  683. return TCL_ERROR;
  684.     }
  685.     if (objc == 3) {
  686. char buf[TCL_INTEGER_SPACE * 2];
  687. sprintf(buf, "%d %d",
  688. (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
  689. (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
  690. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  691. return TCL_OK;
  692.     }
  693.     if ((Tcl_GetBooleanFromObj(interp, objv[3], &width) != TCL_OK)
  694.     || (Tcl_GetBooleanFromObj(interp, objv[4], &height) != TCL_OK)) {
  695. return TCL_ERROR;
  696.     }
  697.     if (width) {
  698. wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
  699.     } else {
  700. wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
  701.     }
  702.     if (height) {
  703. wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
  704.     } else {
  705. wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
  706.     }
  707.     if (!((wmPtr->flags & WM_NEVER_MAPPED)
  708.     && !(winPtr->flags & TK_EMBEDDED))) {
  709. UpdateWrapper(winPtr);
  710.     }
  711.     WmUpdateGeom(wmPtr, winPtr);
  712.     return TCL_OK;
  713. }
  714. /*
  715.  *----------------------------------------------------------------------
  716.  *
  717.  * WmSizefromCmd --
  718.  *
  719.  * This procedure is invoked to process the "wm sizefrom" Tcl command.
  720.  * See the user documentation for details on what it does.
  721.  *
  722.  * Results:
  723.  * A standard Tcl result.
  724.  *
  725.  * Side effects:
  726.  * See the user documentation.
  727.  *
  728.  *----------------------------------------------------------------------
  729.  */
  730. static int
  731. WmSizefromCmd(tkwin, winPtr, interp, objc, objv)
  732.     Tk_Window tkwin; /* Main window of the application. */
  733.     TkWindow *winPtr;           /* Toplevel to work with */
  734.     Tcl_Interp *interp; /* Current interpreter. */
  735.     int objc; /* Number of arguments. */
  736.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  737. {
  738.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  739.     static CONST char *optionStrings[] = {
  740. "program", "user", (char *) NULL };
  741.     enum options {
  742. OPT_PROGRAM, OPT_USER };
  743.     int index;
  744.     if ((objc != 3) && (objc != 4)) {
  745. Tcl_WrongNumArgs(interp, 2, objv, "window ?user|program?");
  746. return TCL_ERROR;
  747.     }
  748.     if (objc == 3) {
  749. if (wmPtr->sizeHintsFlags & USSize) {
  750.     Tcl_SetResult(interp, "user", TCL_STATIC);
  751. } else if (wmPtr->sizeHintsFlags & PSize) {
  752.     Tcl_SetResult(interp, "program", TCL_STATIC);
  753. }
  754. return TCL_OK;
  755.     }
  756.     if (*Tcl_GetString(objv[3]) == '') {
  757. wmPtr->sizeHintsFlags &= ~(USSize|PSize);
  758.     } else {
  759. if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
  760. &index) != TCL_OK) {
  761.     return TCL_ERROR;
  762. }
  763. if (index == OPT_USER) {
  764.     wmPtr->sizeHintsFlags &= ~PSize;
  765.     wmPtr->sizeHintsFlags |= USSize;
  766. } else { /* OPT_PROGRAM */
  767.     wmPtr->sizeHintsFlags &= ~USSize;
  768.     wmPtr->sizeHintsFlags |= PSize;
  769. }
  770.     }
  771.     WmUpdateGeom(wmPtr, winPtr);
  772.     return TCL_OK;
  773. }
  774. /*
  775.  *----------------------------------------------------------------------
  776.  *
  777.  * WmStackorderCmd --
  778.  *
  779.  * This procedure is invoked to process the "wm stackorder" Tcl command.
  780.  * See the user documentation for details on what it does.
  781.  *
  782.  * Results:
  783.  * A standard Tcl result.
  784.  *
  785.  * Side effects:
  786.  * See the user documentation.
  787.  *
  788.  *----------------------------------------------------------------------
  789.  */
  790. static int
  791. WmStackorderCmd(tkwin, winPtr, interp, objc, objv)
  792.     Tk_Window tkwin; /* Main window of the application. */
  793.     TkWindow *winPtr;           /* Toplevel to work with */
  794.     Tcl_Interp *interp; /* Current interpreter. */
  795.     int objc; /* Number of arguments. */
  796.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  797. {
  798.     TkWindow **windows, **window_ptr;
  799.     static CONST char *optionStrings[] = {
  800. "isabove", "isbelow", (char *) NULL };
  801.     enum options {
  802. OPT_ISABOVE, OPT_ISBELOW };
  803.     int index;
  804.     if ((objc != 3) && (objc != 5)) {
  805. Tcl_WrongNumArgs(interp, 2, objv, "window ?isabove|isbelow window?");
  806. return TCL_ERROR;
  807.     }
  808.     if (objc == 3) {
  809. windows = TkWmStackorderToplevel(winPtr);
  810. if (windows == NULL) {
  811.     Tcl_Panic("TkWmStackorderToplevel failed");
  812. } else {
  813.     for (window_ptr = windows; *window_ptr ; window_ptr++) {
  814. Tcl_AppendElement(interp, (*window_ptr)->pathName);
  815.     }
  816.     ckfree((char *) windows);
  817.     return TCL_OK;
  818. }
  819.     } else {
  820. TkWindow *winPtr2;
  821. int index1=-1, index2=-1, result;
  822. if (TkGetWindowFromObj(interp, tkwin, objv[4], (Tk_Window *) &winPtr2)
  823. != TCL_OK) {
  824.     return TCL_ERROR;
  825. }
  826. if (!Tk_IsTopLevel(winPtr2)) {
  827.     Tcl_AppendResult(interp, "window "", winPtr2->pathName,
  828.     "" isn't a top-level window", (char *) NULL);
  829.     return TCL_ERROR;
  830. }
  831. if (!Tk_IsMapped(winPtr)) {
  832.     Tcl_AppendResult(interp, "window "", winPtr->pathName,
  833.     "" isn't mapped", (char *) NULL);
  834.     return TCL_ERROR;
  835. }
  836. if (!Tk_IsMapped(winPtr2)) {
  837.     Tcl_AppendResult(interp, "window "", winPtr2->pathName,
  838.     "" isn't mapped", (char *) NULL);
  839.     return TCL_ERROR;
  840. }
  841. /*
  842.  * Lookup stacking order of all toplevels that are children
  843.  * of "." and find the position of winPtr and winPtr2
  844.  * in the stacking order.
  845.  */
  846. windows = TkWmStackorderToplevel(winPtr->mainPtr->winPtr);
  847. if (windows == NULL) {
  848.     Tcl_AppendResult(interp, "TkWmStackorderToplevel failed",
  849.                     (char *) NULL);
  850.     return TCL_ERROR;
  851. } else {
  852.     for (window_ptr = windows; *window_ptr ; window_ptr++) {
  853. if (*window_ptr == winPtr)
  854.     index1 = (window_ptr - windows);
  855. if (*window_ptr == winPtr2)
  856.     index2 = (window_ptr - windows);
  857.     }
  858.     if (index1 == -1)
  859. Tcl_Panic("winPtr window not found");
  860.     if (index2 == -1)
  861. Tcl_Panic("winPtr2 window not found");
  862.     ckfree((char *) windows);
  863. }
  864. if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
  865. &index) != TCL_OK) {
  866.     return TCL_ERROR;
  867. }
  868. if (index == OPT_ISABOVE) {
  869.     result = index1 > index2;
  870. } else { /* OPT_ISBELOW */
  871.     result = index1 < index2;
  872. }
  873. Tcl_SetIntObj(Tcl_GetObjResult(interp), result);
  874. return TCL_OK;
  875.     }
  876.     return TCL_OK;
  877. }
  878. /*
  879.  *----------------------------------------------------------------------
  880.  *
  881.  * WmStateCmd --
  882.  *
  883.  * This procedure is invoked to process the "wm state" Tcl command.
  884.  * See the user documentation for details on what it does.
  885.  *
  886.  * Results:
  887.  * A standard Tcl result.
  888.  *
  889.  * Side effects:
  890.  * See the user documentation.
  891.  *
  892.  *----------------------------------------------------------------------
  893.  */
  894. static int
  895. WmStateCmd(tkwin, winPtr, interp, objc, objv)
  896.     Tk_Window tkwin; /* Main window of the application. */
  897.     TkWindow *winPtr;           /* Toplevel to work with */
  898.     Tcl_Interp *interp; /* Current interpreter. */
  899.     int objc; /* Number of arguments. */
  900.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  901. {
  902.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  903.     static CONST char *optionStrings[] = {
  904. "normal", "iconic", "withdrawn", "zoomed", (char *) NULL };
  905.     enum options {
  906. OPT_NORMAL, OPT_ICONIC, OPT_WITHDRAWN, OPT_ZOOMED };
  907.     int index;
  908.     if ((objc < 3) || (objc > 4)) {
  909. Tcl_WrongNumArgs(interp, 2, objv, "window ?state?");
  910. return TCL_ERROR;
  911.     }
  912.     if (objc == 4) {
  913. if (wmPtr->iconFor != NULL) {
  914.     Tcl_AppendResult(interp, "can't change state of ",
  915.     Tcl_GetString(objv[2]),
  916.     ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
  917.     (char *) NULL);
  918.     return TCL_ERROR;
  919. }
  920. if (winPtr->flags & TK_EMBEDDED) {
  921.     Tcl_AppendResult(interp, "can't change state of ",
  922.     winPtr->pathName, ": it is an embedded window",
  923.     (char *) NULL);
  924.     return TCL_ERROR;
  925. }
  926. if (Tcl_GetIndexFromObj(interp, objv[3], optionStrings, "argument", 0,
  927. &index) != TCL_OK) {
  928.     return TCL_ERROR;
  929. }
  930. if (index == OPT_NORMAL) {
  931.     wmPtr->flags &= ~WM_WITHDRAWN;
  932.     TkpWmSetState(winPtr, NormalState);
  933.     /*
  934.      * This varies from 'wm deiconify' because it does not
  935.      * force the window to be raised and receive focus
  936.      */
  937. } else if (index == OPT_ICONIC) {
  938.     if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  939. Tcl_AppendResult(interp, "can't iconify "",
  940. winPtr->pathName,
  941. "": override-redirect flag is set",
  942. (char *) NULL);
  943. return TCL_ERROR;
  944.     }
  945.     if (wmPtr->masterPtr != NULL) {
  946. Tcl_AppendResult(interp, "can't iconify "",
  947. winPtr->pathName,
  948. "": it is a transient", (char *) NULL);
  949. return TCL_ERROR;
  950.     }
  951.     TkpWmSetState(winPtr, IconicState);
  952. } else if (index == OPT_WITHDRAWN) {
  953.     wmPtr->flags |= WM_WITHDRAWN;
  954.     TkpWmSetState(winPtr, WithdrawnState);
  955. } else if (index == OPT_ZOOMED) {
  956.     TkpWmSetState(winPtr, ZoomState);
  957. } else {
  958.     Tcl_Panic("wm state not matched");
  959. }
  960.     } else {
  961. if (wmPtr->iconFor != NULL) {
  962.     Tcl_SetResult(interp, "icon", TCL_STATIC);
  963. } else {
  964.     switch (wmPtr->hints.initial_state) {
  965.       case NormalState:
  966. Tcl_SetResult(interp, "normal", TCL_STATIC);
  967. break;
  968.       case IconicState:
  969. Tcl_SetResult(interp, "iconic", TCL_STATIC);
  970. break;
  971.       case WithdrawnState:
  972. Tcl_SetResult(interp, "withdrawn", TCL_STATIC);
  973. break;
  974.       case ZoomState:
  975. Tcl_SetResult(interp, "zoomed", TCL_STATIC);
  976. break;
  977.     }
  978. }
  979.     }
  980.     return TCL_OK;
  981. }
  982. /*
  983.  *----------------------------------------------------------------------
  984.  *
  985.  * WmTitleCmd --
  986.  *
  987.  * This procedure is invoked to process the "wm title" Tcl command.
  988.  * See the user documentation for details on what it does.
  989.  *
  990.  * Results:
  991.  * A standard Tcl result.
  992.  *
  993.  * Side effects:
  994.  * See the user documentation.
  995.  *
  996.  *----------------------------------------------------------------------
  997.  */
  998. static int
  999. WmTitleCmd(tkwin, winPtr, interp, objc, objv)
  1000.     Tk_Window tkwin; /* Main window of the application. */
  1001.     TkWindow *winPtr;           /* Toplevel to work with */
  1002.     Tcl_Interp *interp; /* Current interpreter. */
  1003.     int objc; /* Number of arguments. */
  1004.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1005. {
  1006.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1007.     char *argv3;
  1008.     int length;
  1009.     if (objc > 4) {
  1010. Tcl_WrongNumArgs(interp, 2, objv, "window ?newTitle?");
  1011. return TCL_ERROR;
  1012.     }
  1013.     if (objc == 3) {
  1014. Tcl_SetResult(interp, (char *)
  1015. ((wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid),
  1016. TCL_STATIC);
  1017. return TCL_OK;
  1018.     } else {
  1019. if (wmPtr->title != NULL) {
  1020.     ckfree((char *) wmPtr->title);
  1021. }
  1022. argv3 = Tcl_GetStringFromObj(objv[3], &length);
  1023. wmPtr->title = ckalloc((unsigned) (length + 1));
  1024. strcpy(wmPtr->title, argv3);
  1025. if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
  1026.     Tcl_DString titleString;
  1027.     Tcl_WinUtfToTChar(wmPtr->title, -1, &titleString);
  1028.     (*tkWinProcs->setWindowText)(wmPtr->wrapper,
  1029.     (LPCTSTR) Tcl_DStringValue(&titleString));
  1030.     Tcl_DStringFree(&titleString);
  1031. }
  1032.     }
  1033.     return TCL_OK;
  1034. }
  1035. /*
  1036.  *----------------------------------------------------------------------
  1037.  *
  1038.  * WmTransientCmd --
  1039.  *
  1040.  * This procedure is invoked to process the "wm transient" Tcl command.
  1041.  * See the user documentation for details on what it does.
  1042.  *
  1043.  * Results:
  1044.  * A standard Tcl result.
  1045.  *
  1046.  * Side effects:
  1047.  * See the user documentation.
  1048.  *
  1049.  *----------------------------------------------------------------------
  1050.  */
  1051. static int
  1052. WmTransientCmd(tkwin, winPtr, interp, objc, objv)
  1053.     Tk_Window tkwin; /* Main window of the application. */
  1054.     TkWindow *winPtr;           /* Toplevel to work with */
  1055.     Tcl_Interp *interp; /* Current interpreter. */
  1056.     int objc; /* Number of arguments. */
  1057.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1058. {
  1059.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1060.     TkWindow *masterPtr = wmPtr->masterPtr;
  1061.     WmInfo *wmPtr2;
  1062.     if ((objc != 3) && (objc != 4)) {
  1063. Tcl_WrongNumArgs(interp, 2, objv, "window ?master?");
  1064. return TCL_ERROR;
  1065.     }
  1066.     if (objc == 3) {
  1067. if (masterPtr != NULL) {
  1068.     Tcl_SetResult(interp, Tk_PathName(masterPtr), TCL_STATIC);
  1069. }
  1070. return TCL_OK;
  1071.     }
  1072.     if (Tcl_GetString(objv[3])[0] == '') {
  1073. if (masterPtr != NULL) {
  1074.     /*
  1075.      * If we had a master, tell them that we aren't tied
  1076.      * to them anymore
  1077.      */
  1078.     masterPtr->wmInfoPtr->numTransients--;
  1079.     Tk_DeleteEventHandler((Tk_Window) masterPtr,
  1080.     VisibilityChangeMask|StructureNotifyMask,
  1081.     WmWaitVisibilityOrMapProc, (ClientData) winPtr);
  1082. }
  1083. wmPtr->masterPtr = NULL;
  1084.     } else {
  1085. if (TkGetWindowFromObj(interp, tkwin, objv[3],
  1086. (Tk_Window *) &masterPtr) != TCL_OK) {
  1087.     return TCL_ERROR;
  1088. }
  1089. while (!Tk_TopWinHierarchy(masterPtr)) {
  1090.     /*
  1091.      * Ensure that the master window is actually a Tk toplevel.
  1092.      */
  1093.     masterPtr = masterPtr->parentPtr;
  1094. }
  1095. Tk_MakeWindowExist((Tk_Window) masterPtr);
  1096. if (wmPtr->iconFor != NULL) {
  1097.     Tcl_AppendResult(interp, "can't make "",
  1098.     Tcl_GetString(objv[2]),
  1099.     "" a transient: it is an icon for ",
  1100.     Tk_PathName(wmPtr->iconFor),
  1101.     (char *) NULL);
  1102.     return TCL_ERROR;
  1103. }
  1104. wmPtr2 = masterPtr->wmInfoPtr;
  1105. if (wmPtr2->iconFor != NULL) {
  1106.     Tcl_AppendResult(interp, "can't make "",
  1107.     Tcl_GetString(objv[3]),
  1108.     "" a master: it is an icon for ",
  1109.     Tk_PathName(wmPtr2->iconFor),
  1110.     (char *) NULL);
  1111.     return TCL_ERROR;
  1112. }
  1113. if (masterPtr == winPtr) {
  1114.     Tcl_AppendResult(interp, "can't make "", Tk_PathName(winPtr),
  1115.     "" its own master",
  1116.     (char *) NULL);
  1117.     return TCL_ERROR;
  1118. } else if (masterPtr != wmPtr->masterPtr) {
  1119.     /*
  1120.      * Remove old master map/unmap binding before setting
  1121.      * the new master. The event handler will ensure that
  1122.      * transient states reflect the state of the master.
  1123.      */
  1124.     if (wmPtr->masterPtr != NULL) {
  1125. wmPtr->masterPtr->wmInfoPtr->numTransients--;
  1126. Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
  1127. VisibilityChangeMask|StructureNotifyMask,
  1128. WmWaitVisibilityOrMapProc, (ClientData) winPtr);
  1129.     }
  1130.     masterPtr->wmInfoPtr->numTransients++;
  1131.     Tk_CreateEventHandler((Tk_Window) masterPtr,
  1132.     VisibilityChangeMask|StructureNotifyMask,
  1133.     WmWaitVisibilityOrMapProc, (ClientData) winPtr);
  1134.     wmPtr->masterPtr = masterPtr;
  1135. }
  1136.     }
  1137.     if (!((wmPtr->flags & WM_NEVER_MAPPED)
  1138.     && !(winPtr->flags & TK_EMBEDDED))) {
  1139. if (wmPtr->masterPtr != NULL &&
  1140. !Tk_IsMapped(wmPtr->masterPtr)) {
  1141.     TkpWmSetState(winPtr, WithdrawnState);
  1142. } else {
  1143.     UpdateWrapper(winPtr);
  1144. }
  1145.     }
  1146.     return TCL_OK;
  1147. }
  1148. /*
  1149.  *----------------------------------------------------------------------
  1150.  *
  1151.  * WmWithdrawCmd --
  1152.  *
  1153.  * This procedure is invoked to process the "wm withdraw" Tcl command.
  1154.  * See the user documentation for details on what it does.
  1155.  *
  1156.  * Results:
  1157.  * A standard Tcl result.
  1158.  *
  1159.  * Side effects:
  1160.  * See the user documentation.
  1161.  *
  1162.  *----------------------------------------------------------------------
  1163.  */
  1164. static int
  1165. WmWithdrawCmd(tkwin, winPtr, interp, objc, objv)
  1166.     Tk_Window tkwin; /* Main window of the application. */
  1167.     TkWindow *winPtr;           /* Toplevel to work with */
  1168.     Tcl_Interp *interp; /* Current interpreter. */
  1169.     int objc; /* Number of arguments. */
  1170.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1171. {
  1172.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1173.     if (objc != 3) {
  1174. Tcl_WrongNumArgs(interp, 2, objv, "window");
  1175. return TCL_ERROR;
  1176.     }
  1177.     if (wmPtr->iconFor != NULL) {
  1178. Tcl_AppendResult(interp, "can't withdraw ", Tcl_GetString(objv[2]),
  1179. ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
  1180. (char *) NULL);
  1181. return TCL_ERROR;
  1182.     }
  1183.     wmPtr->flags |= WM_WITHDRAWN;
  1184.     TkpWmSetState(winPtr, WithdrawnState);
  1185.     return TCL_OK;
  1186. }
  1187. /*
  1188.  * Invoked by those wm subcommands that affect geometry.
  1189.  * Schedules a geometry update.
  1190.  */
  1191. static void
  1192. WmUpdateGeom(wmPtr, winPtr)
  1193.     WmInfo *wmPtr;
  1194.     TkWindow *winPtr;
  1195. {
  1196.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1197. Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1198. wmPtr->flags |= WM_UPDATE_PENDING;
  1199.     }
  1200. }
  1201. /*ARGSUSED*/
  1202. static void
  1203. WmWaitVisibilityOrMapProc(clientData, eventPtr)
  1204.     ClientData clientData; /* Pointer to window. */
  1205.     XEvent *eventPtr; /* Information about event. */
  1206. {
  1207.     TkWindow *winPtr = (TkWindow *) clientData;
  1208.     TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr;
  1209.     if (masterPtr == NULL)
  1210. return;
  1211.     if (eventPtr->type == MapNotify) {
  1212. if (!(winPtr->wmInfoPtr->flags & WM_WITHDRAWN))
  1213.     TkpWmSetState(winPtr, NormalState);
  1214.     } else if (eventPtr->type == UnmapNotify) {
  1215. TkpWmSetState(winPtr, WithdrawnState);
  1216.     }
  1217.     if (eventPtr->type == VisibilityNotify) {
  1218. int state = masterPtr->wmInfoPtr->hints.initial_state;
  1219. if ((state == NormalState) || (state == ZoomState)) {
  1220.     state = winPtr->wmInfoPtr->hints.initial_state;
  1221.     if ((state == NormalState) || (state == ZoomState)) {
  1222. UpdateWrapper(winPtr);
  1223.     }
  1224. }
  1225.     }
  1226. }
  1227. /*
  1228.  *----------------------------------------------------------------------
  1229.  *
  1230.  * Tk_SetGrid --
  1231.  *
  1232.  * This procedure is invoked by a widget when it wishes to set a grid
  1233.  * coordinate system that controls the size of a top-level window.
  1234.  * It provides a C interface equivalent to the "wm grid" command and
  1235.  * is usually asscoiated with the -setgrid option.
  1236.  *
  1237.  * Results:
  1238.  * None.
  1239.  *
  1240.  * Side effects:
  1241.  * Grid-related information will be passed to the window manager, so
  1242.  * that the top-level window associated with tkwin will resize on
  1243.  * even grid units.  If some other window already controls gridding
  1244.  * for the top-level window then this procedure call has no effect.
  1245.  *
  1246.  *----------------------------------------------------------------------
  1247.  */
  1248. void
  1249. Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
  1250.     Tk_Window tkwin; /* Token for window.  New window mgr info
  1251.  * will be posted for the top-level window
  1252.  * associated with this window. */
  1253.     int reqWidth; /* Width (in grid units) corresponding to
  1254.  * the requested geometry for tkwin. */
  1255.     int reqHeight; /* Height (in grid units) corresponding to
  1256.  * the requested geometry for tkwin. */
  1257.     int widthInc, heightInc; /* Pixel increments corresponding to a
  1258.  * change of one grid unit. */
  1259. {
  1260.     TkWindow *winPtr = (TkWindow *) tkwin;
  1261.     register WmInfo *wmPtr;
  1262.     /*
  1263.      * Ensure widthInc and heightInc are greater than 0
  1264.      */
  1265.     if (widthInc <= 0) {
  1266. widthInc = 1;
  1267.     }
  1268.     if (heightInc <= 0) {
  1269. heightInc = 1;
  1270.     }
  1271.     /*
  1272.      * Find the top-level window for tkwin, plus the window manager
  1273.      * information.
  1274.      */
  1275.     while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
  1276. winPtr = winPtr->parentPtr;
  1277.     }
  1278.     wmPtr = winPtr->wmInfoPtr;
  1279.     if (wmPtr == NULL) {
  1280. return;
  1281.     }
  1282.     if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
  1283. return;
  1284.     }
  1285.     if ((wmPtr->reqGridWidth == reqWidth)
  1286.     && (wmPtr->reqGridHeight == reqHeight)
  1287.     && (wmPtr->widthInc == widthInc)
  1288.     && (wmPtr->heightInc == heightInc)
  1289.     && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
  1290.     == (PBaseSize|PResizeInc))) {
  1291. return;
  1292.     }
  1293.     /*
  1294.      * If gridding was previously off, then forget about any window
  1295.      * size requests made by the user or via "wm geometry":  these are
  1296.      * in pixel units and there's no easy way to translate them to
  1297.      * grid units since the new requested size of the top-level window in
  1298.      * pixels may not yet have been registered yet (it may filter up
  1299.      * the hierarchy in DoWhenIdle handlers).  However, if the window
  1300.      * has never been mapped yet then just leave the window size alone:
  1301.      * assume that it is intended to be in grid units but just happened
  1302.      * to have been specified before this procedure was called.
  1303.      */
  1304.     if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
  1305. wmPtr->width = -1;
  1306. wmPtr->height = -1;
  1307.     }
  1308.     /*
  1309.      * Set the new gridding information, and start the process of passing
  1310.      * all of this information to the window manager.
  1311.      */
  1312.     wmPtr->gridWin = tkwin;
  1313.     wmPtr->reqGridWidth = reqWidth;
  1314.     wmPtr->reqGridHeight = reqHeight;
  1315.     wmPtr->widthInc = widthInc;
  1316.     wmPtr->heightInc = heightInc;
  1317.     wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
  1318.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1319. Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1320. wmPtr->flags |= WM_UPDATE_PENDING;
  1321.     }
  1322. }
  1323. /*
  1324.  *----------------------------------------------------------------------
  1325.  *
  1326.  * Tk_UnsetGrid --
  1327.  *
  1328.  * This procedure cancels the effect of a previous call
  1329.  * to Tk_SetGrid.
  1330.  *
  1331.  * Results:
  1332.  * None.
  1333.  *
  1334.  * Side effects:
  1335.  * If tkwin currently controls gridding for its top-level window,
  1336.  * gridding is cancelled for that top-level window;  if some other
  1337.  * window controls gridding then this procedure has no effect.
  1338.  *
  1339.  *----------------------------------------------------------------------
  1340.  */
  1341. void
  1342. Tk_UnsetGrid(tkwin)
  1343.     Tk_Window tkwin; /* Token for window that is currently
  1344.  * controlling gridding. */
  1345. {
  1346.     TkWindow *winPtr = (TkWindow *) tkwin;
  1347.     register WmInfo *wmPtr;
  1348.     /*
  1349.      * Find the top-level window for tkwin, plus the window manager
  1350.      * information.
  1351.      */
  1352.     while (!(winPtr->flags & TK_TOP_HIERARCHY)) {
  1353. winPtr = winPtr->parentPtr;
  1354.     }
  1355.     wmPtr = winPtr->wmInfoPtr;
  1356.     if (wmPtr == NULL) {
  1357. return;
  1358.     }
  1359.     if (tkwin != wmPtr->gridWin) {
  1360. return;
  1361.     }
  1362.     wmPtr->gridWin = NULL;
  1363.     wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  1364.     if (wmPtr->width != -1) {
  1365. wmPtr->width = winPtr->reqWidth + (wmPtr->width
  1366. - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1367. wmPtr->height = winPtr->reqHeight + (wmPtr->height
  1368. - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1369.     }
  1370.     wmPtr->widthInc = 1;
  1371.     wmPtr->heightInc = 1;
  1372.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1373. Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1374. wmPtr->flags |= WM_UPDATE_PENDING;
  1375.     }
  1376. }
  1377. /*
  1378.  *----------------------------------------------------------------------
  1379.  *
  1380.  * TopLevelEventProc --
  1381.  *
  1382.  * This procedure is invoked when a top-level (or other externally-
  1383.  * managed window) is restructured in any way.
  1384.  *
  1385.  * Results:
  1386.  * None.
  1387.  *
  1388.  * Side effects:
  1389.  * Tk's internal data structures for the window get modified to
  1390.  * reflect the structural change.
  1391.  *
  1392.  *----------------------------------------------------------------------
  1393.  */
  1394. static void
  1395. TopLevelEventProc(clientData, eventPtr)
  1396.     ClientData clientData; /* Window for which event occurred. */
  1397.     XEvent *eventPtr; /* Event that just happened. */
  1398. {
  1399.     register TkWindow *winPtr = (TkWindow *) clientData;
  1400.     if (eventPtr->type == DestroyNotify) {
  1401. Tk_ErrorHandler handler;
  1402. if (!(winPtr->flags & TK_ALREADY_DEAD)) {
  1403.     /*
  1404.      * A top-level window was deleted externally (e.g., by the window
  1405.      * manager).  This is probably not a good thing, but cleanup as
  1406.      * best we can.  The error handler is needed because
  1407.      * Tk_DestroyWindow will try to destroy the window, but of course
  1408.      * it's already gone.
  1409.      */
  1410.     handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
  1411.     (Tk_ErrorProc *) NULL, (ClientData) NULL);
  1412.     Tk_DestroyWindow((Tk_Window) winPtr);
  1413.     Tk_DeleteErrorHandler(handler);
  1414. }
  1415.     }
  1416.     else if (eventPtr->type == ConfigureNotify) {
  1417. WmInfo *wmPtr;
  1418. wmPtr = winPtr->wmInfoPtr;
  1419. if (winPtr->flags & TK_EMBEDDED) {
  1420.     Tk_Window tkwin = (Tk_Window)winPtr;
  1421.     SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
  1422.         Tk_ReqHeight(tkwin));
  1423. }
  1424.     }
  1425. }
  1426. /*
  1427.  *----------------------------------------------------------------------
  1428.  *
  1429.  * TopLevelReqProc --
  1430.  *
  1431.  * This procedure is invoked by the geometry manager whenever
  1432.  * the requested size for a top-level window is changed.
  1433.  *
  1434.  * Results:
  1435.  * None.
  1436.  *
  1437.  * Side effects:
  1438.  * Arrange for the window to be resized to satisfy the request
  1439.  * (this happens as a when-idle action).
  1440.  *
  1441.  *----------------------------------------------------------------------
  1442.  */
  1443. /* ARGSUSED */
  1444. static void
  1445. TopLevelReqProc(dummy, tkwin)
  1446.     ClientData dummy; /* Not used. */
  1447.     Tk_Window tkwin; /* Information about window. */
  1448. {
  1449.     TkWindow *winPtr = (TkWindow *) tkwin;
  1450.     WmInfo *wmPtr;
  1451.     wmPtr = winPtr->wmInfoPtr;
  1452.     if ((winPtr->flags & TK_EMBEDDED) && (wmPtr->wrapper != NULL)) {
  1453. SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
  1454.     Tk_ReqHeight(tkwin));
  1455.     }
  1456.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1457. Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1458. wmPtr->flags |= WM_UPDATE_PENDING;
  1459.     }
  1460. }
  1461. /*
  1462.  *----------------------------------------------------------------------
  1463.  *
  1464.  * UpdateGeometryInfo --
  1465.  *
  1466.  * This procedure is invoked when a top-level window is first
  1467.  * mapped, and also as a when-idle procedure, to bring the
  1468.  * geometry and/or position of a top-level window back into
  1469.  * line with what has been requested by the user and/or widgets.
  1470.  * This procedure doesn't return until the system has
  1471.  * responded to the geometry change.
  1472.  *
  1473.  * Results:
  1474.  * None.
  1475.  *
  1476.  * Side effects:
  1477.  * The window's size and location may change, unless the WM prevents
  1478.  * that from happening.
  1479.  *
  1480.  *----------------------------------------------------------------------
  1481.  */
  1482. static void
  1483. UpdateGeometryInfo(clientData)
  1484.     ClientData clientData; /* Pointer to the window's record. */
  1485. {
  1486.     int x, y; /* Position of border on desktop. */
  1487.     int width, height; /* Size of client area. */
  1488.     int min, max;
  1489.     RECT rect;
  1490.     register TkWindow *winPtr = (TkWindow *) clientData;
  1491.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1492.     wmPtr->flags &= ~WM_UPDATE_PENDING;
  1493.     /*
  1494.      * If the window is minimized or maximized, we should not update
  1495.      * our geometry since it will end up with the wrong values.
  1496.      * ConfigureToplevel will reschedule UpdateGeometryInfo when the
  1497.      * state of the window changes.
  1498.      */
  1499.     if (wmPtr->wrapper && (IsIconic(wmPtr->wrapper) ||
  1500.     IsZoomed(wmPtr->wrapper))) {
  1501. return;
  1502.     }
  1503.     /*
  1504.      * Compute the border size for the current window style.  This
  1505.      * size will include the resize handles, the title bar and the
  1506.      * menubar.  Note that this size will not be correct if the
  1507.      * menubar spans multiple lines.  The height will be off by a
  1508.      * multiple of the menubar height.  It really only measures the
  1509.      * minimum size of the border.
  1510.      */
  1511.     rect.left = rect.right = rect.top = rect.bottom = 0;
  1512.     AdjustWindowRectEx(&rect, wmPtr->style, wmPtr->hMenu != NULL,
  1513.     wmPtr->exStyle);
  1514.     wmPtr->borderWidth = rect.right - rect.left;
  1515.     wmPtr->borderHeight = rect.bottom - rect.top;
  1516.     /*
  1517.      * Compute the new size for the top-level window.  See the
  1518.      * user documentation for details on this, but the size
  1519.      * requested depends on (a) the size requested internally
  1520.      * by the window's widgets, (b) the size requested by the
  1521.      * user in a "wm geometry" command or via wm-based interactive
  1522.      * resizing (if any), (c) whether or not the window is
  1523.      * gridded, and (d) the current min or max size for
  1524.      * the toplevel. Don't permit sizes <= 0 because this upsets
  1525.      * the X server.
  1526.      */
  1527.     if (wmPtr->width == -1) {
  1528. width = winPtr->reqWidth;
  1529.     } else if (wmPtr->gridWin != NULL) {
  1530. width = winPtr->reqWidth
  1531. + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1532.     } else {
  1533. width = wmPtr->width;
  1534.     }
  1535.     if (width <= 0) {
  1536. width = 1;
  1537.     }
  1538.     /*
  1539.      * Account for window max/min width
  1540.      */
  1541.     if (wmPtr->gridWin != NULL) {
  1542. min = winPtr->reqWidth
  1543. + (wmPtr->minWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1544. if (wmPtr->maxWidth > 0) {
  1545.     max = winPtr->reqWidth
  1546. + (wmPtr->maxWidth - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1547. } else {
  1548.     max = 0;
  1549. }
  1550.     } else {
  1551. min = wmPtr->minWidth;
  1552. max = wmPtr->maxWidth;
  1553.     }
  1554.     if (width < min) {
  1555. width = min;
  1556.     } else if ((max > 0) && (width > max)) {
  1557. width = max;
  1558.     }
  1559.     if (wmPtr->height == -1) {
  1560. height = winPtr->reqHeight;
  1561.     } else if (wmPtr->gridWin != NULL) {
  1562. height = winPtr->reqHeight
  1563. + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1564.     } else {
  1565. height = wmPtr->height;
  1566.     }
  1567.     if (height <= 0) {
  1568. height = 1;
  1569.     }
  1570.     /*
  1571.      * Account for window max/min height
  1572.      */
  1573.     if (wmPtr->gridWin != NULL) {
  1574. min = winPtr->reqHeight
  1575. + (wmPtr->minHeight - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1576. if (wmPtr->maxHeight > 0) {
  1577.     max = winPtr->reqHeight
  1578. + (wmPtr->maxHeight - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1579. } else {
  1580.     max = 0;
  1581. }
  1582.     } else {
  1583. min = wmPtr->minHeight;
  1584. max = wmPtr->maxHeight;
  1585.     }
  1586.     if (height < min) {
  1587. height = min;
  1588.     } else if ((max > 0) && (height > max)) {
  1589. height = max;
  1590.     }
  1591.     /*
  1592.      * Compute the new position for the upper-left pixel of the window's
  1593.      * decorative frame.  This is tricky, because we need to include the
  1594.      * border widths supplied by a reparented parent in this calculation,
  1595.      * but can't use the parent's current overall size since that may
  1596.      * change as a result of this code.
  1597.      */
  1598.     if (wmPtr->flags & WM_NEGATIVE_X) {
  1599. x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
  1600. - (width + wmPtr->borderWidth);
  1601.     } else {
  1602. x =  wmPtr->x;
  1603.     }
  1604.     if (wmPtr->flags & WM_NEGATIVE_Y) {
  1605. y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
  1606. - (height + wmPtr->borderHeight);
  1607.     } else {
  1608. y =  wmPtr->y;
  1609.     }
  1610.     /*
  1611.      * If this window is embedded and the container is also in this
  1612.      * process, we don't need to do anything special about the
  1613.      * geometry, except to make sure that the desired size is known
  1614.      * by the container.  Also, zero out any position information,
  1615.      * since embedded windows are not allowed to move.
  1616.      */
  1617.     if (winPtr->flags & TK_BOTH_HALVES) {
  1618. TkWindow *childPtr = TkpGetOtherWindow(winPtr);
  1619. wmPtr->x = wmPtr->y = 0;
  1620. wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  1621. if (childPtr != NULL) {
  1622.     Tk_GeometryRequest((Tk_Window) childPtr, width, height);
  1623. }
  1624. return;
  1625.     }
  1626.     /*
  1627.      * Reconfigure the window if it isn't already configured correctly.  Base
  1628.      * the size check on what we *asked for* last time, not what we got.
  1629.      * Return immediately if there have been no changes in the requested
  1630.      * geometry of the toplevel.
  1631.      */
  1632.     /* TODO: need to add flag for possible menu size change */
  1633.     if (!((wmPtr->flags & WM_MOVE_PENDING)
  1634.     || (width != wmPtr->configWidth)
  1635.     || (height != wmPtr->configHeight))) {
  1636. return;
  1637.     }
  1638.     wmPtr->flags &= ~WM_MOVE_PENDING;
  1639.     wmPtr->configWidth = width;
  1640.     wmPtr->configHeight = height;
  1641.     /*
  1642.      * Don't bother moving the window if we are in the process of
  1643.      * creating it.  Just update the geometry info based on what
  1644.      * we asked for.
  1645.      */
  1646.     if (wmPtr->flags & WM_CREATE_PENDING) {
  1647. winPtr->changes.x = x;
  1648. winPtr->changes.y = y;
  1649. winPtr->changes.width = width;
  1650. winPtr->changes.height = height;
  1651. return;
  1652.     }
  1653.     wmPtr->flags |= WM_SYNC_PENDING;
  1654.     if (winPtr->flags & TK_EMBEDDED) {
  1655. /*
  1656.  * The wrapper window is in a different process, so we need
  1657.  * to send it a geometry request.  This protocol assumes that
  1658.  * the other process understands this Tk message, otherwise
  1659.  * our requested geometry will be ignored.
  1660.  */
  1661. SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, width, height);
  1662.     } else {
  1663. int reqHeight, reqWidth;
  1664. RECT windowRect;
  1665. int menuInc = GetSystemMetrics(SM_CYMENU);
  1666. int newHeight;
  1667. /*
  1668.  * We have to keep resizing the window until we get the
  1669.  * requested height in the client area. If the client
  1670.  * area has zero height, then the window rect is too
  1671.  * small by definition. Try increasing the border height
  1672.  * and try again. Once we have a positive size, then
  1673.  * we can adjust the height exactly. If the window
  1674.  * rect comes back smaller than we requested, we have
  1675.  * hit the maximum constraints that Windows imposes.
  1676.  * Once we find a positive client size, the next size
  1677.  * is the one we try no matter what.
  1678.  */
  1679. reqHeight = height + wmPtr->borderHeight;
  1680. reqWidth = width + wmPtr->borderWidth;
  1681. while (1) {
  1682.     MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
  1683.     GetWindowRect(wmPtr->wrapper, &windowRect);
  1684.     newHeight = windowRect.bottom - windowRect.top;
  1685.     /*
  1686.      * If the request wasn't satisfied, we have hit an external
  1687.      * constraint and must stop.
  1688.      */
  1689.     if (newHeight < reqHeight) {
  1690. break;
  1691.     }
  1692.     /*
  1693.      * Now check the size of the client area against our ideal.
  1694.      */
  1695.     GetClientRect(wmPtr->wrapper, &windowRect);
  1696.     newHeight = windowRect.bottom - windowRect.top;
  1697.     if (newHeight == height) {
  1698. /*
  1699.  * We're done.
  1700.  */
  1701. break;
  1702.     } else if (newHeight > height) {
  1703. /*
  1704.  * One last resize to get rid of the extra space.
  1705.  */
  1706. menuInc = newHeight - height;
  1707. reqHeight -= menuInc;
  1708. if (wmPtr->flags & WM_NEGATIVE_Y) {
  1709.     y += menuInc;
  1710. }
  1711. MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
  1712. break;
  1713.     }
  1714.     /*
  1715.      * We didn't get enough space to satisfy our requested
  1716.      * height, so the menu must have wrapped.  Increase the
  1717.      * size of the window by one menu height and move the
  1718.      * window if it is positioned relative to the lower right
  1719.      * corner of the screen.
  1720.      */
  1721.     reqHeight += menuInc;
  1722.     if (wmPtr->flags & WM_NEGATIVE_Y) {
  1723. y -= menuInc;
  1724.     }
  1725. }
  1726. if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1727.     DrawMenuBar(wmPtr->wrapper);
  1728. }
  1729.     }
  1730.     wmPtr->flags &= ~WM_SYNC_PENDING;
  1731. }
  1732. /*
  1733.  *--------------------------------------------------------------
  1734.  *
  1735.  * ParseGeometry --
  1736.  *
  1737.  * This procedure parses a geometry string and updates
  1738.  * information used to control the geometry of a top-level
  1739.  * window.
  1740.  *
  1741.  * Results:
  1742.  * A standard Tcl return value, plus an error message in
  1743.  * the interp's result if an error occurs.
  1744.  *
  1745.  * Side effects:
  1746.  * The size and/or location of winPtr may change.
  1747.  *
  1748.  *--------------------------------------------------------------
  1749.  */
  1750. static int
  1751. ParseGeometry(interp, string, winPtr)
  1752.     Tcl_Interp *interp; /* Used for error reporting. */
  1753.     char *string; /* String containing new geometry.  Has the
  1754.  * standard form "=wxh+x+y". */
  1755.     TkWindow *winPtr; /* Pointer to top-level window whose
  1756.  * geometry is to be changed. */
  1757. {
  1758.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  1759.     int x, y, width, height, flags;
  1760.     char *end;
  1761.     register char *p = string;
  1762.     /*
  1763.      * The leading "=" is optional.
  1764.      */
  1765.     if (*p == '=') {
  1766. p++;
  1767.     }
  1768.     /*
  1769.      * Parse the width and height, if they are present.  Don't
  1770.      * actually update any of the fields of wmPtr until we've
  1771.      * successfully parsed the entire geometry string.
  1772.      */
  1773.     width = wmPtr->width;
  1774.     height = wmPtr->height;
  1775.     x = wmPtr->x;
  1776.     y = wmPtr->y;
  1777.     flags = wmPtr->flags;
  1778.     if (isdigit(UCHAR(*p))) {
  1779. width = strtoul(p, &end, 10);
  1780. p = end;
  1781. if (*p != 'x') {
  1782.     goto error;
  1783. }
  1784. p++;
  1785. if (!isdigit(UCHAR(*p))) {
  1786.     goto error;
  1787. }
  1788. height = strtoul(p, &end, 10);
  1789. p = end;
  1790.     }
  1791.     /*
  1792.      * Parse the X and Y coordinates, if they are present.
  1793.      */
  1794.     if (*p != '') {
  1795. flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  1796. if (*p == '-') {
  1797.     flags |= WM_NEGATIVE_X;
  1798. } else if (*p != '+') {
  1799.     goto error;
  1800. }
  1801. p++;
  1802. if (!isdigit(UCHAR(*p)) && (*p != '-')) {
  1803.     goto error;
  1804. }
  1805. x = strtol(p, &end, 10);
  1806. p = end;
  1807. if (*p == '-') {
  1808.     flags |= WM_NEGATIVE_Y;
  1809. } else if (*p != '+') {
  1810.     goto error;
  1811. }
  1812. p++;
  1813. if (!isdigit(UCHAR(*p)) && (*p != '-')) {
  1814.     goto error;
  1815. }
  1816. y = strtol(p, &end, 10);
  1817. if (*end != '') {
  1818.     goto error;
  1819. }
  1820. /*
  1821.  * Assume that the geometry information came from the user,
  1822.  * unless an explicit source has been specified.  Otherwise
  1823.  * most window managers assume that the size hints were
  1824.  * program-specified and they ignore them.
  1825.  */
  1826. if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  1827.     wmPtr->sizeHintsFlags |= USPosition;
  1828. }
  1829.     }
  1830.     /*
  1831.      * Everything was parsed OK.  Update the fields of *wmPtr and
  1832.      * arrange for the appropriate information to be percolated out
  1833.      * to the window manager at the next idle moment.
  1834.      */
  1835.     wmPtr->width = width;
  1836.     wmPtr->height = height;
  1837.     wmPtr->x = x;
  1838.     wmPtr->y = y;
  1839.     flags |= WM_MOVE_PENDING;
  1840.     wmPtr->flags = flags;
  1841.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  1842. Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  1843. wmPtr->flags |= WM_UPDATE_PENDING;
  1844.     }
  1845.     return TCL_OK;
  1846.     error:
  1847.     Tcl_AppendResult(interp, "bad geometry specifier "",
  1848.     string, """, (char *) NULL);
  1849.     return TCL_ERROR;
  1850. }
  1851. /*
  1852.  *----------------------------------------------------------------------
  1853.  *
  1854.  * Tk_GetRootCoords --
  1855.  *
  1856.  * Given a token for a window, this procedure traces through the
  1857.  * window's lineage to find the (virtual) root-window coordinates
  1858.  * corresponding to point (0,0) in the window.
  1859.  *
  1860.  * Results:
  1861.  * The locations pointed to by xPtr and yPtr are filled in with
  1862.  * the root coordinates of the (0,0) point in tkwin.
  1863.  *
  1864.  * Side effects:
  1865.  * None.
  1866.  *
  1867.  *----------------------------------------------------------------------
  1868.  */
  1869. void
  1870. Tk_GetRootCoords(tkwin, xPtr, yPtr)
  1871.     Tk_Window tkwin; /* Token for window. */
  1872.     int *xPtr; /* Where to store x-displacement of (0,0). */
  1873.     int *yPtr; /* Where to store y-displacement of (0,0). */
  1874. {
  1875.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1876.     /*
  1877.      * If the window is mapped, let Windows figure out the translation.
  1878.      */
  1879.     if (winPtr->window != None) {
  1880. HWND hwnd = Tk_GetHWND(winPtr->window);
  1881. POINT point;
  1882. point.x = 0;
  1883. point.y = 0;
  1884. ClientToScreen(hwnd, &point);
  1885. *xPtr = point.x;
  1886. *yPtr = point.y;
  1887.     } else {
  1888. *xPtr = 0;
  1889. *yPtr = 0;
  1890.     }
  1891. }
  1892. /*
  1893.  *----------------------------------------------------------------------
  1894.  *
  1895.  * Tk_CoordsToWindow --
  1896.  *
  1897.  * Given the (virtual) root coordinates of a point, this procedure
  1898.  * returns the token for the top-most window covering that point,
  1899.  * if there exists such a window in this application.
  1900.  *
  1901.  * Results:
  1902.  * The return result is either a token for the window corresponding
  1903.  * to rootX and rootY, or else NULL to indicate that there is no such
  1904.  * window.
  1905.  *
  1906.  * Side effects:
  1907.  * None.
  1908.  *
  1909.  *----------------------------------------------------------------------
  1910.  */
  1911. Tk_Window
  1912. Tk_CoordsToWindow(rootX, rootY, tkwin)
  1913.     int rootX, rootY; /* Coordinates of point in root window.  If
  1914.  * a virtual-root window manager is in use,
  1915.  * these coordinates refer to the virtual
  1916.  * root, not the real root. */
  1917.     Tk_Window tkwin; /* Token for any window in application;
  1918.  * used to identify the display. */
  1919. {
  1920.     POINT pos;
  1921.     HWND hwnd;
  1922.     TkWindow *winPtr;
  1923.     pos.x = rootX;
  1924.     pos.y = rootY;
  1925.     hwnd = WindowFromPoint(pos);
  1926.     winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
  1927.     if (winPtr && (winPtr->mainPtr == ((TkWindow *) tkwin)->mainPtr)) {
  1928. return (Tk_Window) winPtr;
  1929.     }
  1930.     return NULL;
  1931. }
  1932. /*
  1933.  *----------------------------------------------------------------------
  1934.  *
  1935.  * Tk_GetVRootGeometry --
  1936.  *
  1937.  * This procedure returns information about the virtual root
  1938.  * window corresponding to a particular Tk window.
  1939.  *
  1940.  * Results:
  1941.  * The values at xPtr, yPtr, widthPtr, and heightPtr are set
  1942.  * with the offset and dimensions of the root window corresponding
  1943.  * to tkwin.  If tkwin is being managed by a virtual root window
  1944.  * manager these values correspond to the virtual root window being
  1945.  * used for tkwin;  otherwise the offsets will be 0 and the
  1946.  * dimensions will be those of the screen.
  1947.  *
  1948.  * Side effects:
  1949.  * Vroot window information is refreshed if it is out of date.
  1950.  *
  1951.  *----------------------------------------------------------------------
  1952.  */
  1953. void
  1954. Tk_GetVRootGeometry(tkwin, xPtr, yPtr, widthPtr, heightPtr)
  1955.     Tk_Window tkwin; /* Window whose virtual root is to be
  1956.  * queried. */
  1957.     int *xPtr, *yPtr; /* Store x and y offsets of virtual root
  1958.  * here. */
  1959.     int *widthPtr, *heightPtr; /* Store dimensions of virtual root here. */
  1960. {
  1961.     TkWindow *winPtr = (TkWindow *) tkwin;
  1962.     /*
  1963.      * XXX: This is not correct for multiple monitors.  There may be many
  1964.      * changes required to get this right, and it may effect existing
  1965.      * applications that don't consider possible <0 vroot.  See
  1966.      * http://msdn.microsoft.com/library/en-us/gdi/monitor_3lrn.asp
  1967.      * for more info.
  1968.      */
  1969.     *xPtr = 0;
  1970.     *yPtr = 0;
  1971.     *widthPtr = DisplayWidth(winPtr->display, winPtr->screenNum);
  1972.     *heightPtr = DisplayHeight(winPtr->display, winPtr->screenNum);
  1973. }
  1974. /*
  1975.  *----------------------------------------------------------------------
  1976.  *
  1977.  * Tk_MoveToplevelWindow --
  1978.  *
  1979.  * This procedure is called instead of Tk_MoveWindow to adjust
  1980.  * the x-y location of a top-level window.  It delays the actual
  1981.  * move to a later time and keeps window-manager information
  1982.  * up-to-date with the move
  1983.  *
  1984.  * Results:
  1985.  * None.
  1986.  *
  1987.  * Side effects:
  1988.  * The window is eventually moved so that its upper-left corner
  1989.  * (actually, the upper-left corner of the window's decorative
  1990.  * frame, if there is one) is at (x,y).
  1991.  *
  1992.  *----------------------------------------------------------------------
  1993.  */
  1994. void
  1995. Tk_MoveToplevelWindow(tkwin, x, y)
  1996.     Tk_Window tkwin; /* Window to move. */
  1997.     int x, y; /* New location for window (within
  1998.  * parent). */
  1999. {
  2000.     TkWindow *winPtr = (TkWindow *) tkwin;
  2001.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2002.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  2003. Tcl_Panic("Tk_MoveToplevelWindow called with non-toplevel window");
  2004.     }
  2005.     wmPtr->x = x;
  2006.     wmPtr->y = y;
  2007.     wmPtr->flags |= WM_MOVE_PENDING;
  2008.     wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  2009.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2010. wmPtr->sizeHintsFlags |= USPosition;
  2011.     }
  2012.     /*
  2013.      * If the window has already been mapped, must bring its geometry
  2014.      * up-to-date immediately, otherwise an event might arrive from the
  2015.      * server that would overwrite wmPtr->x and wmPtr->y and lose the
  2016.      * new position.
  2017.      */
  2018.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2019. if (wmPtr->flags & WM_UPDATE_PENDING) {
  2020.     Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  2021. }
  2022. UpdateGeometryInfo((ClientData) winPtr);
  2023.     }
  2024. }
  2025. /*
  2026.  *----------------------------------------------------------------------
  2027.  *
  2028.  * TkWmProtocolEventProc --
  2029.  *
  2030.  * This procedure is called by the Tk_HandleEvent whenever a
  2031.  * ClientMessage event arrives whose type is "WM_PROTOCOLS".
  2032.  * This procedure handles the message from the window manager
  2033.  * in an appropriate fashion.
  2034.  *
  2035.  * Results:
  2036.  * None.
  2037.  *
  2038.  * Side effects:
  2039.  * Depends on what sort of handler, if any, was set up for the
  2040.  * protocol.
  2041.  *
  2042.  *----------------------------------------------------------------------
  2043.  */
  2044. void
  2045. TkWmProtocolEventProc(winPtr, eventPtr)
  2046.     TkWindow *winPtr; /* Window to which the event was sent. */
  2047.     XEvent *eventPtr; /* X event. */
  2048. {
  2049.     WmInfo *wmPtr;
  2050.     register ProtocolHandler *protPtr;
  2051.     Atom protocol;
  2052.     int result;
  2053.     Tcl_Interp *interp;
  2054.     wmPtr = winPtr->wmInfoPtr;
  2055.     if (wmPtr == NULL) {
  2056. return;
  2057.     }
  2058.     protocol = (Atom) eventPtr->xclient.data.l[0];
  2059.     for (protPtr = wmPtr->protPtr; protPtr != NULL;
  2060.     protPtr = protPtr->nextPtr) {
  2061. if (protocol == protPtr->protocol) {
  2062.     /*
  2063.      * Cache atom name, as we might destroy the window as a
  2064.      * result of the eval.
  2065.      */
  2066.     CONST char *name = Tk_GetAtomName((Tk_Window) winPtr, protocol);
  2067.     Tcl_Preserve((ClientData) protPtr);
  2068.             interp = protPtr->interp;
  2069.             Tcl_Preserve((ClientData) interp);
  2070.     result = Tcl_GlobalEval(interp, protPtr->command);
  2071.     if (result != TCL_OK) {
  2072. Tcl_AddErrorInfo(interp, "n    (command for "");
  2073. Tcl_AddErrorInfo(interp, name);
  2074. Tcl_AddErrorInfo(interp, "" window manager protocol)");
  2075. Tcl_BackgroundError(interp);
  2076.     }
  2077.             Tcl_Release((ClientData) interp);
  2078.     Tcl_Release((ClientData) protPtr);
  2079.     return;
  2080. }
  2081.     }
  2082.     /*
  2083.      * No handler was present for this protocol.  If this is a
  2084.      * WM_DELETE_WINDOW message then just destroy the window.
  2085.      */
  2086.     if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
  2087. Tk_DestroyWindow((Tk_Window) winPtr);
  2088.     }
  2089. }
  2090. /*
  2091.  *----------------------------------------------------------------------
  2092.  *
  2093.  * TkWmStackorderToplevelEnumProc --
  2094.  *
  2095.  * This procedure is invoked once for each HWND Window on the
  2096.  * display as a result of calling EnumWindows from
  2097.  * TkWmStackorderToplevel.
  2098.  *
  2099.  * Results:
  2100.  * TRUE to request further iteration.
  2101.  *
  2102.  * Side effects:
  2103.  * Adds entries to the passed array of TkWindows.
  2104.  *
  2105.  *----------------------------------------------------------------------
  2106.  */
  2107. BOOL CALLBACK TkWmStackorderToplevelEnumProc(hwnd, lParam)
  2108.     HWND hwnd;     /* handle to parent window */
  2109.     LPARAM lParam; /* application-defined value */
  2110. {
  2111.     Tcl_HashEntry *hPtr;
  2112.     TkWindow *childWinPtr;
  2113.     TkWmStackorderToplevelPair *pair =
  2114.         (TkWmStackorderToplevelPair *) lParam;
  2115.     /*fprintf(stderr, "Looking up HWND %dn", hwnd);*/
  2116.     hPtr = Tcl_FindHashEntry(pair->table, (char *) hwnd);
  2117.     if (hPtr != NULL) {
  2118.         childWinPtr = (TkWindow *) Tcl_GetHashValue(hPtr);
  2119.         /* Double check that same HWND does not get passed twice */
  2120.         if (childWinPtr == NULL) {
  2121.             Tcl_Panic("duplicate HWND in TkWmStackorderToplevelEnumProc");
  2122.         } else {
  2123.             Tcl_SetHashValue(hPtr, NULL);
  2124.         }
  2125.         /*fprintf(stderr, "Found mapped HWND %d -> %x (%s)n", hwnd,
  2126.   childWinPtr, childWinPtr->pathName);*/
  2127.         *(pair->window_ptr)-- = childWinPtr;
  2128.     }
  2129.     return TRUE;
  2130. }
  2131. /*
  2132.  *----------------------------------------------------------------------
  2133.  *
  2134.  * TkWmStackorderToplevelWrapperMap --
  2135.  *
  2136.  * This procedure will create a table that maps the wrapper
  2137.  * HWND id for a toplevel to the TkWindow structure that is wraps.
  2138.  *
  2139.  * Results:
  2140.  * None.
  2141.  *
  2142.  * Side effects:
  2143.  * Adds entries to the passed hashtable.
  2144.  *
  2145.  *----------------------------------------------------------------------
  2146.  */
  2147. static void
  2148. TkWmStackorderToplevelWrapperMap(winPtr, display, table)
  2149.     TkWindow *winPtr; /* TkWindow to recurse on */
  2150.     Display *display;                          /* X display of parent window */
  2151.     Tcl_HashTable *table; /* Table to maps HWND to TkWindow */
  2152. {
  2153.     TkWindow *childPtr;
  2154.     Tcl_HashEntry *hPtr;
  2155.     HWND wrapper;
  2156.     int newEntry;
  2157.     if (Tk_IsMapped(winPtr) && Tk_IsTopLevel(winPtr) &&
  2158.             !Tk_IsEmbedded(winPtr) && (winPtr->display == display)) {
  2159.         wrapper = TkWinGetWrapperWindow((Tk_Window) winPtr);
  2160.         /*fprintf(stderr, "Mapped HWND %d to %x (%s)n", wrapper,
  2161.   winPtr, winPtr->pathName);*/
  2162.         hPtr = Tcl_CreateHashEntry(table,
  2163.             (char *) wrapper, &newEntry);
  2164.         Tcl_SetHashValue(hPtr, winPtr);
  2165.     }
  2166.     for (childPtr = winPtr->childList; childPtr != NULL;
  2167.             childPtr = childPtr->nextPtr) {
  2168.         TkWmStackorderToplevelWrapperMap(childPtr, display, table);
  2169.     }
  2170. }
  2171. /*
  2172.  *----------------------------------------------------------------------
  2173.  *
  2174.  * TkWmStackorderToplevel --
  2175.  *
  2176.  * This procedure returns the stack order of toplevel windows.
  2177.  *
  2178.  * Results:
  2179.  * An array of pointers to tk window objects in stacking order
  2180.  * or else NULL if there was an error.
  2181.  *
  2182.  * Side effects:
  2183.  * None.
  2184.  *
  2185.  *----------------------------------------------------------------------
  2186.  */
  2187. TkWindow **
  2188. TkWmStackorderToplevel(parentPtr)
  2189.     TkWindow *parentPtr; /* Parent toplevel window. */
  2190. {
  2191.     TkWmStackorderToplevelPair pair;
  2192.     TkWindow **windows;
  2193.     Tcl_HashTable table;
  2194.     Tcl_HashEntry *hPtr;
  2195.     Tcl_HashSearch search;
  2196.     /*
  2197.      * Map HWND ids to a TkWindow of the wrapped toplevel.
  2198.      */
  2199.     Tcl_InitHashTable(&table, TCL_ONE_WORD_KEYS);
  2200.     TkWmStackorderToplevelWrapperMap(parentPtr, parentPtr->display, &table);
  2201.     windows = (TkWindow **) ckalloc((table.numEntries+1)
  2202.         * sizeof(TkWindow *));
  2203.     /*
  2204.      * Special cases: If zero or one toplevels were mapped
  2205.      * there is no need to call EnumWindows.
  2206.      */
  2207.     switch (table.numEntries) {
  2208.     case 0:
  2209.         windows[0] = NULL;
  2210.         goto done;
  2211.     case 1:
  2212.         hPtr = Tcl_FirstHashEntry(&table, &search);
  2213.         windows[0] = (TkWindow *) Tcl_GetHashValue(hPtr);
  2214.         windows[1] = NULL;
  2215.         goto done;
  2216.     }
  2217.     /*
  2218.      * We will be inserting into the array starting at the end
  2219.      * and working our way to the beginning since EnumWindows
  2220.      * returns windows in highest to lowest order.
  2221.      */
  2222.     pair.table = &table;
  2223.     pair.window_ptr = windows + table.numEntries;
  2224.     *pair.window_ptr-- = NULL;
  2225.     if (EnumWindows((WNDENUMPROC) TkWmStackorderToplevelEnumProc,
  2226.     (LPARAM) &pair) == 0) {
  2227.         ckfree((char *) windows);
  2228.         windows = NULL;
  2229.     } else {
  2230.         if (pair.window_ptr != (windows-1))
  2231.             Tcl_Panic("num matched toplevel windows does not equal num children");
  2232.     }
  2233.     done:
  2234.     Tcl_DeleteHashTable(&table);
  2235.     return windows;
  2236. }
  2237. /*
  2238.  *----------------------------------------------------------------------
  2239.  *
  2240.  * TkWmRestackToplevel --
  2241.  *
  2242.  * This procedure restacks a top-level window.
  2243.  *
  2244.  * Results:
  2245.  * None.
  2246.  *
  2247.  * Side effects:
  2248.  * WinPtr gets restacked  as specified by aboveBelow and otherPtr.
  2249.  * This procedure doesn't return until the restack has taken
  2250.  * effect and the ConfigureNotify event for it has been received.
  2251.  *
  2252.  *----------------------------------------------------------------------
  2253.  */
  2254. void
  2255. TkWmRestackToplevel(winPtr, aboveBelow, otherPtr)
  2256.     TkWindow *winPtr; /* Window to restack. */
  2257.     int aboveBelow; /* Gives relative position for restacking;
  2258.  * must be Above or Below. */
  2259.     TkWindow *otherPtr; /* Window relative to which to restack;
  2260.  * if NULL, then winPtr gets restacked
  2261.  * above or below *all* siblings. */
  2262. {
  2263.     HWND hwnd, insertAfter;
  2264.     /*
  2265.      * Can't set stacking order properly until the window is on the
  2266.      * screen (mapping it may give it a reparent window).
  2267.      */
  2268.     if (winPtr->window == None) {
  2269. Tk_MakeWindowExist((Tk_Window) winPtr);
  2270.     }
  2271.     if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2272. TkWmMapWindow(winPtr);
  2273.     }
  2274.     hwnd = (winPtr->wmInfoPtr->wrapper != NULL)
  2275. ? winPtr->wmInfoPtr->wrapper : Tk_GetHWND(winPtr->window);
  2276.     if (otherPtr != NULL) {
  2277. if (otherPtr->window == None) {
  2278.     Tk_MakeWindowExist((Tk_Window) otherPtr);
  2279. }
  2280. if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2281.     TkWmMapWindow(otherPtr);
  2282. }
  2283. insertAfter = (otherPtr->wmInfoPtr->wrapper != NULL)
  2284.     ? otherPtr->wmInfoPtr->wrapper : Tk_GetHWND(otherPtr->window);
  2285.     } else {
  2286. insertAfter = NULL;
  2287.     }
  2288.     TkWinSetWindowPos(hwnd, insertAfter, aboveBelow);
  2289. }
  2290. /*
  2291.  *----------------------------------------------------------------------
  2292.  *
  2293.  * TkWmAddToColormapWindows --
  2294.  *
  2295.  * This procedure is called to add a given window to the
  2296.  * WM_COLORMAP_WINDOWS property for its top-level, if it
  2297.  * isn't already there.  It is invoked by the Tk code that
  2298.  * creates a new colormap, in order to make sure that colormap
  2299.  * information is propagated to the window manager by default.
  2300.  *
  2301.  * Results:
  2302.  * None.
  2303.  *
  2304.  * Side effects:
  2305.  * WinPtr's window gets added to the WM_COLORMAP_WINDOWS
  2306.  * property of its nearest top-level ancestor, unless the
  2307.  * colormaps have been set explicitly with the
  2308.  * "wm colormapwindows" command.
  2309.  *
  2310.  *----------------------------------------------------------------------
  2311.  */
  2312. void
  2313. TkWmAddToColormapWindows(winPtr)
  2314.     TkWindow *winPtr; /* Window with a non-default colormap.
  2315.  * Should not be a top-level window. */
  2316. {
  2317.     TkWindow *topPtr;
  2318.     TkWindow **oldPtr, **newPtr;
  2319.     int count, i;
  2320.     if (winPtr->window == None) {
  2321. return;
  2322.     }
  2323.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  2324. if (topPtr == NULL) {
  2325.     /*
  2326.      * Window is being deleted.  Skip the whole operation.
  2327.      */
  2328.     return;
  2329. }
  2330. if (topPtr->flags & TK_TOP_HIERARCHY) {
  2331.     break;
  2332. }
  2333.     }
  2334.     if (topPtr->wmInfoPtr == NULL) {
  2335. return;
  2336.     }
  2337.     if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
  2338. return;
  2339.     }
  2340.     /*
  2341.      * Make sure that the window isn't already in the list.
  2342.      */
  2343.     count = topPtr->wmInfoPtr->cmapCount;
  2344.     oldPtr = topPtr->wmInfoPtr->cmapList;
  2345.     for (i = 0; i < count; i++) {
  2346. if (oldPtr[i] == winPtr) {
  2347.     return;
  2348. }
  2349.     }
  2350.     /*
  2351.      * Make a new bigger array and use it to reset the property.
  2352.      * Automatically add the toplevel itself as the last element
  2353.      * of the list.
  2354.      */
  2355.     newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
  2356.     if (count > 0) {
  2357. memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
  2358.     }
  2359.     if (count == 0) {
  2360. count++;
  2361.     }
  2362.     newPtr[count-1] = winPtr;
  2363.     newPtr[count] = topPtr;
  2364.     if (oldPtr != NULL) {
  2365. ckfree((char *) oldPtr);
  2366.     }
  2367.     topPtr->wmInfoPtr->cmapList = newPtr;
  2368.     topPtr->wmInfoPtr->cmapCount = count+1;
  2369.     /*
  2370.      * Now we need to force the updated colormaps to be installed.
  2371.      */
  2372.     if (topPtr->wmInfoPtr == winPtr->dispPtr->foregroundWmPtr) {
  2373. InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_QUERYNEWPALETTE, 1);
  2374.     } else {
  2375. InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_PALETTECHANGED, 0);
  2376.     }
  2377. }
  2378. /*
  2379.  *----------------------------------------------------------------------
  2380.  *
  2381.  * TkWmRemoveFromColormapWindows --
  2382.  *
  2383.  * This procedure is called to remove a given window from the
  2384.  * WM_COLORMAP_WINDOWS property for its top-level.  It is invoked
  2385.  * when windows are deleted.
  2386.  *
  2387.  * Results:
  2388.  * None.
  2389.  *
  2390.  * Side effects:
  2391.  * WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
  2392.  * property of its nearest top-level ancestor, unless the
  2393.  * top-level itself is being deleted too.
  2394.  *
  2395.  *----------------------------------------------------------------------
  2396.  */
  2397. void
  2398. TkWmRemoveFromColormapWindows(winPtr)
  2399.     TkWindow *winPtr; /* Window that may be present in
  2400.  * WM_COLORMAP_WINDOWS property for its
  2401.  * top-level.  Should not be a top-level
  2402.  * window. */
  2403. {
  2404.     TkWindow *topPtr;
  2405.     TkWindow **oldPtr;
  2406.     int count, i, j;
  2407.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  2408. if (topPtr == NULL) {
  2409.     /*
  2410.      * Ancestors have been deleted, so skip the whole operation.
  2411.      * Seems like this can't ever happen?
  2412.      */
  2413.     return;
  2414. }
  2415. if (topPtr->flags & TK_TOP_LEVEL) {
  2416.     break;
  2417. }
  2418.     }
  2419.     if (topPtr->flags & TK_ALREADY_DEAD) {
  2420. /*
  2421.  * Top-level is being deleted, so there's no need to cleanup
  2422.  * the WM_COLORMAP_WINDOWS property.
  2423.  */
  2424. return;
  2425.     }
  2426.     if (topPtr->wmInfoPtr == NULL) {
  2427. return;
  2428.     }
  2429.     /*
  2430.      * Find the window and slide the following ones down to cover
  2431.      * it up.
  2432.      */
  2433.     count = topPtr->wmInfoPtr->cmapCount;
  2434.     oldPtr = topPtr->wmInfoPtr->cmapList;
  2435.     for (i = 0; i < count; i++) {
  2436. if (oldPtr[i] == winPtr) {
  2437.     for (j = i ; j < count-1; j++) {
  2438. oldPtr[j] = oldPtr[j+1];
  2439.     }
  2440.     topPtr->wmInfoPtr->cmapCount = count-1;
  2441.     break;
  2442. }
  2443.     }
  2444. }
  2445. /*
  2446.  *----------------------------------------------------------------------
  2447.  *
  2448.  * TkWinSetMenu--
  2449.  *
  2450.  * Associcates a given HMENU to a window.
  2451.  *
  2452.  * Results:
  2453.  * None.
  2454.  *
  2455.  * Side effects:
  2456.  * The menu will end up being drawn in the window, and the geometry
  2457.  * of the window will have to be changed.
  2458.  *
  2459.  *----------------------------------------------------------------------
  2460.  */
  2461. void
  2462. TkWinSetMenu(tkwin, hMenu)
  2463.     Tk_Window tkwin; /* the window to put the menu in */
  2464.     HMENU hMenu; /* the menu to set */
  2465. {
  2466.     TkWindow *winPtr = (TkWindow *) tkwin;
  2467.     WmInfo *wmPtr = winPtr->wmInfoPtr;
  2468.     wmPtr->hMenu = hMenu;
  2469.     if (!(wmPtr->flags & TK_EMBEDDED)) {
  2470. if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2471.     int syncPending = wmPtr->flags & WM_SYNC_PENDING;
  2472.     wmPtr->flags |= WM_SYNC_PENDING;
  2473.     SetMenu(wmPtr->wrapper, hMenu);
  2474.     if (!syncPending) {
  2475. wmPtr->flags &= ~WM_SYNC_PENDING;
  2476.     }
  2477. }
  2478. if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2479.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2480.     wmPtr->flags |= WM_UPDATE_PENDING|WM_MOVE_PENDING;
  2481. }
  2482.     }
  2483. }
  2484. /*
  2485.  *----------------------------------------------------------------------
  2486.  *
  2487.  * ConfigureTopLevel --
  2488.  *
  2489.  * Generate a ConfigureNotify event based on the current position
  2490.  * information.  This procedure is called by TopLevelProc.
  2491.  *
  2492.  * Results:
  2493.  * None.
  2494.  *
  2495.  * Side effects:
  2496.  * Queues a new event.
  2497.  *
  2498.  *----------------------------------------------------------------------
  2499.  */
  2500. static void
  2501. ConfigureTopLevel(pos)
  2502.     WINDOWPOS *pos;
  2503. {
  2504.     TkWindow *winPtr = GetTopLevel(pos->hwnd);
  2505.     WmInfo *wmPtr;
  2506.     int state; /* Current window state. */
  2507.     RECT rect;
  2508.     WINDOWPLACEMENT windowPos;
  2509.     if (winPtr == NULL) {
  2510. return;
  2511.     }
  2512.     wmPtr = winPtr->wmInfoPtr;
  2513.     /*
  2514.      * Determine the current window state.
  2515.      */
  2516.     if (!IsWindowVisible(wmPtr->wrapper)) {
  2517. state = WithdrawnState;
  2518.     } else {
  2519. windowPos.length = sizeof(WINDOWPLACEMENT);
  2520. GetWindowPlacement(wmPtr->wrapper, &windowPos);
  2521. switch (windowPos.showCmd) {
  2522.     case SW_SHOWMAXIMIZED:
  2523. state = ZoomState;
  2524. break;
  2525.     case SW_SHOWMINIMIZED:
  2526. state = IconicState;
  2527. break;
  2528.     case SW_SHOWNORMAL:
  2529. state = NormalState;
  2530. break;
  2531. }
  2532.     }
  2533.     /*
  2534.      * If the state of the window just changed, be sure to update the
  2535.      * child window information.
  2536.      */
  2537.     if (wmPtr->hints.initial_state != state) {
  2538. wmPtr->hints.initial_state = state;
  2539. switch (state) {
  2540.     case WithdrawnState:
  2541.     case IconicState:
  2542. XUnmapWindow(winPtr->display, winPtr->window);
  2543. break;
  2544.     case NormalState:
  2545. /*
  2546.  * Schedule a geometry update.  Since we ignore geometry
  2547.  * requests while in any other state, the geometry info
  2548.  * may be stale.
  2549.  */
  2550. if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
  2551.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2552.     wmPtr->flags |= WM_UPDATE_PENDING;
  2553. }
  2554. /* fall through */
  2555.     case ZoomState:
  2556. XMapWindow(winPtr->display, winPtr->window);
  2557. pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
  2558. break;
  2559. }
  2560.     }
  2561.     /*
  2562.      * Don't report geometry changes in the Iconic or Withdrawn states.
  2563.      */
  2564.     if (state == WithdrawnState || state == IconicState) {
  2565. return;
  2566.     }
  2567.     /*
  2568.      * Compute the current geometry of the client area, reshape the
  2569.      * Tk window and generate a ConfigureNotify event.
  2570.      */
  2571.     GetClientRect(wmPtr->wrapper, &rect);
  2572.     winPtr->changes.x = pos->x;
  2573.     winPtr->changes.y = pos->y;
  2574.     winPtr->changes.width = rect.right - rect.left;
  2575.     winPtr->changes.height = rect.bottom - rect.top;
  2576.     wmPtr->borderHeight = pos->cy - winPtr->changes.height;
  2577.     MoveWindow(Tk_GetHWND(winPtr->window), 0, 0,
  2578.     winPtr->changes.width, winPtr->changes.height, TRUE);
  2579.     GenerateConfigureNotify(winPtr);
  2580.     /*
  2581.      * Update window manager geometry info if needed.
  2582.      */
  2583.     if (state == NormalState) {
  2584. /*
  2585.  * Update size information from the event.  There are a couple of
  2586.  * tricky points here:
  2587.  *
  2588.  * 1. If the user changed the size externally then set wmPtr->width
  2589.  *    and wmPtr->height just as if a "wm geometry" command had been
  2590.  *    invoked with the same information.
  2591.  * 2. However, if the size is changing in response to a request
  2592.  *    coming from us (sync is set), then don't set
  2593.  *    wmPtr->width or wmPtr->height (otherwise the window will stop
  2594.  *    tracking geometry manager requests).
  2595.  */
  2596. if (!(wmPtr->flags & WM_SYNC_PENDING)) {
  2597.     if (!(pos->flags & SWP_NOSIZE)) {
  2598. if ((wmPtr->width == -1)
  2599. && (winPtr->changes.width == winPtr->reqWidth)) {
  2600.     /*
  2601.      * Don't set external width, since the user didn't
  2602.      * change it from what the widgets asked for.
  2603.      */
  2604. } else {
  2605.     if (wmPtr->gridWin != NULL) {
  2606. wmPtr->width = wmPtr->reqGridWidth
  2607.     + (winPtr->changes.width - winPtr->reqWidth)
  2608.     / wmPtr->widthInc;
  2609. if (wmPtr->width < 0) {
  2610.     wmPtr->width = 0;
  2611. }
  2612.     } else {
  2613. wmPtr->width = winPtr->changes.width;
  2614.     }
  2615. }
  2616. if ((wmPtr->height == -1)
  2617. && (winPtr->changes.height == winPtr->reqHeight)) {
  2618.     /*
  2619.      * Don't set external height, since the user didn't change
  2620.      * it from what the widgets asked for.
  2621.      */
  2622. } else {
  2623.     if (wmPtr->gridWin != NULL) {
  2624. wmPtr->height = wmPtr->reqGridHeight
  2625.     + (winPtr->changes.height - winPtr->reqHeight)
  2626.     / wmPtr->heightInc;
  2627. if (wmPtr->height < 0) {
  2628.     wmPtr->height = 0;
  2629. }
  2630.     } else {
  2631. wmPtr->height = winPtr->changes.height;
  2632.     }
  2633. }
  2634. wmPtr->configWidth = winPtr->changes.width;
  2635. wmPtr->configHeight = winPtr->changes.height;
  2636.     }
  2637.     /*
  2638.      * If the user moved the window, we should switch back
  2639.      * to normal coordinates.
  2640.      */
  2641.     if (!(pos->flags & SWP_NOMOVE)) {
  2642. wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  2643.     }
  2644. }
  2645. /*
  2646.  * Update the wrapper window location information.
  2647.  */
  2648. if (wmPtr->flags & WM_NEGATIVE_X) {
  2649.     wmPtr->x = DisplayWidth(winPtr->display, winPtr->screenNum)
  2650. - winPtr->changes.x - (winPtr->changes.width
  2651. + wmPtr->borderWidth);
  2652. } else {
  2653.     wmPtr->x = winPtr->changes.x;
  2654. }
  2655. if (wmPtr->flags & WM_NEGATIVE_Y) {
  2656.     wmPtr->y = DisplayHeight(winPtr->display, winPtr->screenNum)
  2657. - winPtr->changes.y - (winPtr->changes.height
  2658. + wmPtr->borderHeight);
  2659. } else {
  2660.     wmPtr->y = winPtr->changes.y;
  2661. }
  2662.     }
  2663. }
  2664. /*
  2665.  *----------------------------------------------------------------------
  2666.  *
  2667.  * GenerateConfigureNotify --
  2668.  *
  2669.  * Generate a ConfigureNotify event from the current geometry
  2670.  * information for the specified toplevel window.
  2671.  *
  2672.  * Results:
  2673.  * None.
  2674.  *
  2675.  * Side effects:
  2676.  * Sends an X event.
  2677.  *
  2678.  *----------------------------------------------------------------------
  2679.  */
  2680. static void
  2681. GenerateConfigureNotify(winPtr)
  2682.     TkWindow *winPtr;
  2683. {
  2684.     XEvent event;
  2685.     /*
  2686.      * Generate a ConfigureNotify event.
  2687.      */
  2688.     event.type = ConfigureNotify;
  2689.     event.xconfigure.serial = winPtr->display->request;
  2690.     event.xconfigure.send_event = False;
  2691.     event.xconfigure.display = winPtr->display;
  2692.     event.xconfigure.event = winPtr->window;
  2693.     event.xconfigure.window = winPtr->window;
  2694.     event.xconfigure.border_width = winPtr->changes.border_width;
  2695.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  2696.     event.xconfigure.x = winPtr->changes.x;
  2697.     event.xconfigure.y = winPtr->changes.y;
  2698.     event.xconfigure.width = winPtr->changes.width;
  2699.     event.xconfigure.height = winPtr->changes.height;
  2700.     event.xconfigure.above = None;
  2701.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  2702. }
  2703. /*
  2704.  *----------------------------------------------------------------------
  2705.  *
  2706.  * InstallColormaps --
  2707.  *
  2708.  * Installs the colormaps associated with the toplevel which is
  2709.  * currently active.
  2710.  *
  2711.  * Results:
  2712.  * None.
  2713.  *
  2714.  * Side effects:
  2715.  * May change the system palette and generate damage.
  2716.  *
  2717.  *----------------------------------------------------------------------
  2718.  */
  2719. static int
  2720. InstallColormaps(hwnd, message, isForemost)
  2721.     HWND hwnd; /* Toplevel wrapper window whose colormaps
  2722.  * should be installed. */
  2723.     int message; /* Either WM_PALETTECHANGED or
  2724.  * WM_QUERYNEWPALETTE */
  2725.     int isForemost; /* 1 if window is foremost, else 0 */
  2726. {
  2727.     int i;
  2728.     HDC dc;
  2729.     HPALETTE oldPalette;
  2730.     TkWindow *winPtr = GetTopLevel(hwnd);
  2731.     WmInfo *wmPtr;
  2732.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  2733.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  2734.     if (winPtr == NULL || (winPtr->flags & TK_ALREADY_DEAD) ) {
  2735. return 0;
  2736.     }
  2737.     wmPtr = winPtr->wmInfoPtr;
  2738.     if (message == WM_QUERYNEWPALETTE) {
  2739. /*
  2740.  * Case 1: This window is about to become the foreground window, so we
  2741.  * need to install the primary palette. If the system palette was
  2742.  * updated, then Windows will generate a WM_PALETTECHANGED message.
  2743.  * Otherwise, we have to synthesize one in order to ensure that the
  2744.  * secondary palettes are installed properly.
  2745.  */
  2746. winPtr->dispPtr->foregroundWmPtr = wmPtr;
  2747. if (wmPtr->cmapCount > 0) {
  2748.     winPtr = wmPtr->cmapList[0];
  2749. }
  2750. tsdPtr->systemPalette = TkWinGetPalette(winPtr->atts.colormap);
  2751. dc = GetDC(hwnd);
  2752. oldPalette = SelectPalette(dc, tsdPtr->systemPalette, FALSE);
  2753. if (RealizePalette(dc)) {
  2754.     RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
  2755. } else if (wmPtr->cmapCount > 1) {
  2756.     SelectPalette(dc, oldPalette, TRUE);
  2757.     RealizePalette(dc);
  2758.     ReleaseDC(hwnd, dc);
  2759.     SendMessage(hwnd, WM_PALETTECHANGED, (WPARAM)hwnd,
  2760.     (LPARAM)NULL);
  2761.     return TRUE;
  2762. }
  2763.     } else {
  2764. /*
  2765.  * Window is being notified of a change in the system palette.
  2766.  * If this window is the foreground window, then we should only
  2767.  * install the secondary palettes, since the primary was installed
  2768.  * in response to the WM_QUERYPALETTE message.  Otherwise, install
  2769.  * all of the palettes.
  2770.  */
  2771. if (!isForemost) {
  2772.     if (wmPtr->cmapCount > 0) {
  2773. winPtr = wmPtr->cmapList[0];
  2774.     }
  2775.     i = 1;
  2776. } else {
  2777.     if (wmPtr->cmapCount <= 1) {
  2778. return TRUE;
  2779.     }
  2780.     winPtr = wmPtr->cmapList[1];
  2781.     i = 2;
  2782. }
  2783. dc = GetDC(hwnd);
  2784. oldPalette = SelectPalette(dc,
  2785. TkWinGetPalette(winPtr->atts.colormap), TRUE);
  2786. if (RealizePalette(dc)) {
  2787.     RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
  2788. }
  2789. for (; i < wmPtr->cmapCount; i++) {
  2790.     winPtr = wmPtr->cmapList[i];
  2791.     SelectPalette(dc, TkWinGetPalette(winPtr->atts.colormap), TRUE);
  2792.     if (RealizePalette(dc)) {
  2793. RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
  2794.     }
  2795. }
  2796.     }
  2797.     SelectPalette(dc, oldPalette, TRUE);
  2798.     RealizePalette(dc);
  2799.     ReleaseDC(hwnd, dc);
  2800.     return TRUE;
  2801. }
  2802. /*
  2803.  *----------------------------------------------------------------------
  2804.  *
  2805.  * RefreshColormap --
  2806.  *
  2807.  * This function is called to force all of the windows that use
  2808.  * a given colormap to redraw themselves.  The quickest way to
  2809.  * do this is to iterate over the toplevels, looking in the
  2810.  * cmapList for matches.  This will quickly eliminate subtrees
  2811.  * that don't use a given colormap.
  2812.  *
  2813.  * Results:
  2814.  * None.
  2815.  *
  2816.  * Side effects:
  2817.  * Causes damage events to be generated.
  2818.  *
  2819.  *----------------------------------------------------------------------
  2820.  */
  2821. static void
  2822. RefreshColormap(colormap, dispPtr)
  2823.     Colormap colormap;
  2824.     TkDisplay *dispPtr;
  2825. {
  2826.     WmInfo *wmPtr;
  2827.     int i;
  2828.     for (wmPtr = dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
  2829. if (wmPtr->cmapCount > 0) {
  2830.     for (i = 0; i < wmPtr->cmapCount; i++) {
  2831. if ((wmPtr->cmapList[i]->atts.colormap == colormap)
  2832. && Tk_IsMapped(wmPtr->cmapList[i])) {
  2833.     InvalidateSubTree(wmPtr->cmapList[i], colormap);
  2834. }
  2835.     }
  2836. } else if ((wmPtr->winPtr->atts.colormap == colormap)
  2837. && Tk_IsMapped(wmPtr->winPtr)) {
  2838.     InvalidateSubTree(wmPtr->winPtr, colormap);
  2839. }
  2840.     }
  2841. }
  2842. /*
  2843.  *----------------------------------------------------------------------
  2844.  *
  2845.  * InvalidateSubTree --
  2846.  *
  2847.  * This function recursively generates damage for a window and
  2848.  * all of its mapped children that belong to the same toplevel and
  2849.  * are using the specified colormap.
  2850.  *
  2851.  * Results:
  2852.  * None.
  2853.  *
  2854.  * Side effects:
  2855.  * Generates damage for the specified subtree.
  2856.  *
  2857.  *----------------------------------------------------------------------
  2858.  */
  2859. static void
  2860. InvalidateSubTree(winPtr, colormap)
  2861.     TkWindow *winPtr;
  2862.     Colormap colormap;
  2863. {
  2864.     TkWindow *childPtr;
  2865.     /*
  2866.      * Generate damage for the current window if it is using the
  2867.      * specified colormap.
  2868.      */
  2869.     if (winPtr->atts.colormap == colormap) {
  2870. InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
  2871.     }
  2872.     for (childPtr = winPtr->childList; childPtr != NULL;
  2873.     childPtr = childPtr->nextPtr) {
  2874. /*
  2875.  * We can stop the descent when we hit an unmapped or
  2876.  * toplevel window.
  2877.  */
  2878. if (!Tk_TopWinHierarchy(childPtr) && Tk_IsMapped(childPtr)) {
  2879.     InvalidateSubTree(childPtr, colormap);
  2880. }
  2881.     }
  2882. }
  2883. /*
  2884.  *----------------------------------------------------------------------
  2885.  *
  2886.  * InvalidateSubTreeDepth --
  2887.  *
  2888.  * This function recursively updates depth info for a window and
  2889.  * all of its children that belong to the same toplevel.
  2890.  *
  2891.  * Results:
  2892.  * None.
  2893.  *
  2894.  * Side effects:
  2895.  * Sets the depth of each window to that of the display.
  2896.  *
  2897.  *----------------------------------------------------------------------
  2898.  */
  2899. static void
  2900. InvalidateSubTreeDepth(winPtr)
  2901.     TkWindow *winPtr;
  2902. {
  2903.     Display *display = Tk_Display(winPtr);
  2904.     int screenNum = Tk_ScreenNumber(winPtr);
  2905.     TkWindow *childPtr;
  2906.     winPtr->depth = DefaultDepth(display, screenNum);
  2907. #if 0
  2908.     /*
  2909.      * XXX: What other elements may require changes?  Changing just
  2910.      * the depth works for standard windows and 16/24/32-bpp changes.
  2911.      * I suspect 8-bit (palettized) displays may require colormap and/or
  2912.      * visual changes as well.
  2913.      */
  2914.     if (winPtr->window) {
  2915. InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
  2916.     }
  2917.     winPtr->visual = DefaultVisual(display, screenNum);
  2918.     winPtr->atts.colormap = DefaultColormap(display, screenNum);
  2919.     winPtr->dirtyAtts |= CWColormap;
  2920. #endif
  2921.     for (childPtr = winPtr->childList; childPtr != NULL;
  2922.  childPtr = childPtr->nextPtr) {
  2923. /*
  2924.  * We can stop the descent when we hit a toplevel window, as it
  2925.  * should get its own message.
  2926.  */
  2927. if (!Tk_TopWinHierarchy(childPtr)) {
  2928.     InvalidateSubTreeDepth(childPtr);
  2929. }
  2930.     }
  2931. }
  2932. /*
  2933.  *----------------------------------------------------------------------
  2934.  *
  2935.  * TkWinGetSystemPalette --
  2936.  *
  2937.  * Retrieves the currently installed foreground palette.
  2938.  *
  2939.  * Results:
  2940.  * Returns the global foreground palette, if there is one.
  2941.  * Otherwise, returns NULL.
  2942.  *
  2943.  * Side effects:
  2944.  * None.
  2945.  *
  2946.  *----------------------------------------------------------------------
  2947.  */
  2948. HPALETTE
  2949. TkWinGetSystemPalette()
  2950. {
  2951.     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  2952.             Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  2953.     return tsdPtr->systemPalette;
  2954. }
  2955. /*
  2956.  *----------------------------------------------------------------------
  2957.  *
  2958.  * GetMinSize --
  2959.  *
  2960.  * This procedure computes the current minWidth and minHeight
  2961.  * values for a window, taking into account the possibility
  2962.  * that they may be defaulted.
  2963.  *
  2964.  * Results:
  2965.  * The values at *minWidthPtr and *minHeightPtr are filled
  2966.  * in with the minimum allowable dimensions of wmPtr's window,
  2967.  * in grid units.  If the requested minimum is smaller than the
  2968.  * system required minimum, then this procedure computes the
  2969.  * smallest size that will satisfy both the system and the
  2970.  * grid constraints.
  2971.  *
  2972.  * Side effects:
  2973.  * None.
  2974.  *
  2975.  *----------------------------------------------------------------------
  2976.  */
  2977. static void
  2978. GetMinSize(wmPtr, minWidthPtr, minHeightPtr)
  2979.     WmInfo *wmPtr; /* Window manager information for the
  2980.  * window. */
  2981.     int *minWidthPtr; /* Where to store the current minimum
  2982.  * width of the window. */
  2983.     int *minHeightPtr; /* Where to store the current minimum
  2984.  * height of the window. */
  2985. {
  2986.     int tmp, base;
  2987.     TkWindow *winPtr = wmPtr->winPtr;
  2988.     /*
  2989.      * Compute the minimum width by taking the default client size
  2990.      * and rounding it up to the nearest grid unit.  Return the greater
  2991.      * of the default minimum and the specified minimum.
  2992.      */
  2993.     tmp = wmPtr->defMinWidth - wmPtr->borderWidth;
  2994.     if (tmp < 0) {
  2995. tmp = 0;
  2996.     }
  2997.     if (wmPtr->gridWin != NULL) {
  2998. base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
  2999. if (base < 0) {
  3000.     base = 0;
  3001. }
  3002. tmp = ((tmp - base) + wmPtr->widthInc - 1)/wmPtr->widthInc;
  3003.     }
  3004.     if (tmp < wmPtr->minWidth) {
  3005. tmp = wmPtr->minWidth;
  3006.     }
  3007.     *minWidthPtr = tmp;
  3008.     /*
  3009.      * Compute the minimum height in a similar fashion.
  3010.      */
  3011.     tmp = wmPtr->defMinHeight - wmPtr->borderHeight;
  3012.     if (tmp < 0) {
  3013. tmp = 0;
  3014.     }
  3015.     if (wmPtr->gridWin != NULL) {
  3016. base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
  3017. if (base < 0) {
  3018.     base = 0;
  3019. }
  3020. tmp = ((tmp - base) + wmPtr->heightInc - 1)/wmPtr->heightInc;
  3021.     }
  3022.     if (tmp < wmPtr->minHeight) {
  3023. tmp = wmPtr->minHeight;
  3024.     }
  3025.     *minHeightPtr = tmp;
  3026. }
  3027. /*
  3028.  *----------------------------------------------------------------------
  3029.  *
  3030.  * GetMaxSize --
  3031.  *
  3032.  * This procedure computes the current maxWidth and maxHeight
  3033.  * values for a window, taking into account the possibility
  3034.  * that they may be defaulted.
  3035.  *
  3036.  * Results:
  3037.  * The values at *maxWidthPtr and *maxHeightPtr are filled
  3038.  * in with the maximum allowable dimensions of wmPtr's window,
  3039.  * in grid units.  If no maximum has been specified for the
  3040.  * window, then this procedure computes the largest sizes that
  3041.  * will fit on the screen.
  3042.  *
  3043.  * Side effects:
  3044.  * None.
  3045.  *
  3046.  *----------------------------------------------------------------------
  3047.  */
  3048. static void
  3049. GetMaxSize(wmPtr, maxWidthPtr, maxHeightPtr)
  3050.     WmInfo *wmPtr; /* Window manager information for the
  3051.  * window. */
  3052.     int *maxWidthPtr; /* Where to store the current maximum
  3053.  * width of the window. */
  3054.     int *maxHeightPtr; /* Where to store the current maximum
  3055.  * height of the window. */
  3056. {
  3057.     int tmp;
  3058.     if (wmPtr->maxWidth > 0) {
  3059. *maxWidthPtr = wmPtr->maxWidth;
  3060.     } else {
  3061. /*
  3062.  * Must compute a default width.  Fill up the display, leaving a
  3063.  * bit of extra space for the window manager's borders.
  3064.  */
  3065. tmp = wmPtr->defMaxWidth - wmPtr->borderWidth;
  3066. if (wmPtr->gridWin != NULL) {
  3067.     /*
  3068.      * Gridding is turned on;  convert from pixels to grid units.
  3069.      */
  3070.     tmp = wmPtr->reqGridWidth
  3071.     + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
  3072. }
  3073. *maxWidthPtr = tmp;
  3074.     }
  3075.     if (wmPtr->maxHeight > 0) {
  3076. *maxHeightPtr = wmPtr->maxHeight;
  3077.     } else {
  3078. tmp = wmPtr->defMaxHeight - wmPtr->borderHeight;
  3079. if (wmPtr->gridWin != NULL) {
  3080.     tmp = wmPtr->reqGridHeight
  3081.     + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
  3082. }
  3083. *maxHeightPtr = tmp;
  3084.     }
  3085. }
  3086. /*
  3087.  *----------------------------------------------------------------------
  3088.  *
  3089.  * TopLevelProc --
  3090.  *
  3091.  * Callback from Windows whenever an event occurs on a top level
  3092.  * window.
  3093.  *
  3094.  * Results:
  3095.  * Standard Windows return value.
  3096.  *
  3097.  * Side effects:
  3098.  * Default window behavior.
  3099.  *
  3100.  *----------------------------------------------------------------------
  3101.  */
  3102. static LRESULT CALLBACK
  3103. TopLevelProc(hwnd, message, wParam, lParam)
  3104.     HWND hwnd;
  3105.     UINT message;
  3106.     WPARAM wParam;
  3107.     LPARAM lParam;
  3108. {
  3109.     if (message == WM_WINDOWPOSCHANGED) {
  3110. WINDOWPOS *pos = (WINDOWPOS *) lParam;
  3111. TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(pos->hwnd);
  3112. if (winPtr == NULL) {
  3113.     return 0;
  3114. }
  3115. /*
  3116.  * Update the shape of the contained window.
  3117.  */
  3118. if (!(pos->flags & SWP_NOSIZE)) {
  3119.     winPtr->changes.width = pos->cx;
  3120.     winPtr->changes.height = pos->cy;
  3121. }
  3122. if (!(pos->flags & SWP_NOMOVE)) {
  3123.     winPtr->changes.x = pos->x;
  3124.     winPtr->changes.y = pos->y;
  3125. }
  3126. GenerateConfigureNotify(winPtr);
  3127. Tcl_ServiceAll();
  3128. return 0;
  3129.     }
  3130.     return TkWinChildProc(hwnd, message, wParam, lParam);
  3131. }
  3132. /*
  3133.  *----------------------------------------------------------------------
  3134.  *
  3135.  * WmProc --
  3136.  *
  3137.  * Callback from Windows whenever an event occurs on the decorative
  3138.  * frame.
  3139.  *
  3140.  * Results:
  3141.  * Standard Windows return value.
  3142.  *
  3143.  * Side effects:
  3144.  * Default window behavior.
  3145.  *
  3146.  *----------------------------------------------------------------------
  3147.  */
  3148. static LRESULT CALLBACK
  3149. WmProc(hwnd, message, wParam, lParam)
  3150.     HWND hwnd;
  3151.     UINT message;
  3152.     WPARAM wParam;
  3153.     LPARAM lParam;
  3154. {
  3155.     static int inMoveSize = 0;
  3156.     static int oldMode; /* This static is set upon entering move/size mode
  3157.  * and is used to reset the service mode after
  3158.  * leaving move/size mode.  Note that this mechanism
  3159.  * assumes move/size is only one level deep. */
  3160.     LRESULT result;
  3161.     TkWindow *winPtr = NULL;
  3162.     if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, &result)) {
  3163. goto done;
  3164.     }
  3165.     switch (message) {
  3166. case WM_KILLFOCUS:
  3167. case WM_ERASEBKGND:
  3168.     result = 0;
  3169.     goto done;
  3170. case WM_ENTERSIZEMOVE:
  3171.     inMoveSize = 1;
  3172.     /*
  3173.      * Cancel any current mouse timer.  If the mouse timer
  3174.      * fires during the size/move mouse capture, it will
  3175.      * release the capture, which is wrong.
  3176.      */
  3177.     TkWinCancelMouseTimer();
  3178.     oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  3179.     break;
  3180. case WM_ACTIVATE:
  3181. case WM_EXITSIZEMOVE:
  3182.     if (inMoveSize) {
  3183. inMoveSize = 0;
  3184. Tcl_SetServiceMode(oldMode);
  3185.     }
  3186.     break;
  3187. case WM_GETMINMAXINFO:
  3188.     SetLimits(hwnd, (MINMAXINFO *) lParam);
  3189.     result = 0;
  3190.     goto done;
  3191. case WM_DISPLAYCHANGE:
  3192.     /* display and/or color resolution changed */
  3193.     winPtr = GetTopLevel(hwnd);
  3194.     if (winPtr) {
  3195. Screen *screen = Tk_Screen(winPtr);
  3196. if (screen->root_depth != (int) wParam) {
  3197.     /*
  3198.      * Color resolution changed, so do extensive rebuild of
  3199.      * display parameters.  This will affect the display for
  3200.      * all Tk windows.  We will receive this event for each
  3201.      * toplevel, but this check makes us update only once, for
  3202.      * the first toplevel that receives the message.
  3203.      */
  3204.     TkWinDisplayChanged(Tk_Display(winPtr));
  3205. } else {
  3206.     HDC dc = GetDC(NULL);
  3207.     screen->width   = LOWORD(lParam); /* horizontal res */
  3208.     screen->height  = HIWORD(lParam); /* vertical res */
  3209.     screen->mwidth  = MulDiv(screen->width, 254,
  3210.     GetDeviceCaps(dc, LOGPIXELSX) * 10);
  3211.     screen->mheight = MulDiv(screen->height, 254,
  3212.     GetDeviceCaps(dc, LOGPIXELSY) * 10);
  3213.     ReleaseDC(NULL, dc);
  3214. }
  3215. if (Tk_Depth(winPtr) != (int) wParam) {
  3216.     /*
  3217.      * Defer the window depth check to here so that each
  3218.      * toplevel will properly update depth info.
  3219.      */
  3220.     InvalidateSubTreeDepth(winPtr);
  3221. }
  3222.     }
  3223.     result = 0;
  3224.     goto done;
  3225. case WM_SYSCOLORCHANGE:
  3226.     /*
  3227.      * XXX: Called when system color changes.  We need to
  3228.      * update any widgets that use a system color.
  3229.      */
  3230.     break;
  3231. case WM_PALETTECHANGED:
  3232.     result = InstallColormaps(hwnd, WM_PALETTECHANGED,
  3233.     hwnd == (HWND)wParam);
  3234.     goto done;
  3235. case WM_QUERYNEWPALETTE:
  3236.     result = InstallColormaps(hwnd, WM_QUERYNEWPALETTE, TRUE);
  3237.     goto done;
  3238. case WM_WINDOWPOSCHANGED:
  3239.     ConfigureTopLevel((WINDOWPOS *) lParam);
  3240.     result = 0;
  3241.     goto done;
  3242. case WM_NCHITTEST: {
  3243.     winPtr = GetTopLevel(hwnd);
  3244.     if (winPtr && (TkGrabState(winPtr) == TK_GRAB_EXCLUDED)) {
  3245. /*
  3246.  * This window is outside the grab heirarchy, so don't let any
  3247.  * of the normal non-client processing occur.  Note that this
  3248.  * implementation is not strictly correct because the grab
  3249.  * might change between now and when the event would have been
  3250.  * processed by Tk, but it's close enough.
  3251.  */
  3252. result = HTCLIENT;
  3253. goto done;
  3254.     }
  3255.     break;
  3256. }
  3257. case WM_MOUSEACTIVATE: {
  3258.     ActivateEvent *eventPtr;
  3259.     winPtr = GetTopLevel((HWND) wParam);
  3260.     if (winPtr && (TkGrabState(winPtr) != TK_GRAB_EXCLUDED)) {
  3261. /*
  3262.  * This allows us to pass the message onto the
  3263.  * native menus [Bug: 2272]
  3264.  */
  3265. result = (*tkWinProcs->defWindowProc)(hwnd, message,
  3266. wParam, lParam);
  3267. goto done;
  3268.     }
  3269.     /*
  3270.      * Don't activate the window yet since there is a grab
  3271.      * that takes precedence.  Instead we need to queue
  3272.      * an event so we can check the grab state right before we
  3273.      * handle the mouse event.
  3274.      */
  3275.     if (winPtr) {
  3276. eventPtr = (ActivateEvent *)ckalloc(sizeof(ActivateEvent));
  3277. eventPtr->ev.proc = ActivateWindow;
  3278. eventPtr->winPtr = winPtr;
  3279. Tcl_QueueEvent((Tcl_Event*)eventPtr, TCL_QUEUE_TAIL);
  3280.     }
  3281.     result = MA_NOACTIVATE;
  3282.     goto done;
  3283. }
  3284. case WM_QUERYENDSESSION: {
  3285.     XEvent event;
  3286.     winPtr = GetTopLevel(hwnd);
  3287.     event.xclient.message_type =
  3288. Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS");
  3289.     event.xclient.data.l[0] =
  3290. Tk_InternAtom((Tk_Window) winPtr, "WM_SAVE_YOURSELF");
  3291.     TkWmProtocolEventProc(winPtr, &event);
  3292.     break;
  3293. }
  3294. default:
  3295.     break;
  3296.     }
  3297.     winPtr = GetTopLevel(hwnd);
  3298.     if (winPtr && winPtr->window) {
  3299. HWND child = Tk_GetHWND(winPtr->window);
  3300. if (message == WM_SETFOCUS) {
  3301.     SetFocus(child);
  3302.     result = 0;
  3303. } else if (!Tk_TranslateWinEvent(child, message, wParam, lParam,
  3304. &result)) {
  3305.     result = (*tkWinProcs->defWindowProc)(hwnd, message,
  3306.     wParam, lParam);
  3307. }
  3308.     } else {
  3309. result = (*tkWinProcs->defWindowProc)(hwnd, message, wParam, lParam);
  3310.     }
  3311.     done:
  3312.     Tcl_ServiceAll();
  3313.     return result;
  3314. }
  3315. /*
  3316.  *----------------------------------------------------------------------
  3317.  *
  3318.  * TkpMakeMenuWindow --
  3319.  *
  3320.  * Configure the window to be either a pull-down (or pop-up)
  3321.  * menu, or as a toplevel (torn-off) menu or palette.
  3322.  *
  3323.  * Results:
  3324.  * None.
  3325.  *
  3326.  * Side effects:
  3327.  * Changes the style bit used to create a new toplevel.
  3328.  *
  3329.  *----------------------------------------------------------------------
  3330.  */
  3331. void
  3332. TkpMakeMenuWindow(tkwin, transient)
  3333.     Tk_Window tkwin; /* New window. */
  3334.     int transient; /* 1 means menu is only posted briefly as
  3335.  * a popup or pulldown or cascade.  0 means
  3336.  * menu is always visible, e.g. as a torn-off
  3337.  * menu.  Determines whether save_under and
  3338.  * override_redirect should be set. */
  3339. {
  3340.     XSetWindowAttributes atts;
  3341.     if (transient) {
  3342. atts.override_redirect = True;
  3343. atts.save_under = True;
  3344.     } else {
  3345. atts.override_redirect = False;
  3346. atts.save_under = False;
  3347.     }
  3348.     if ((atts.override_redirect != Tk_Attributes(tkwin)->override_redirect)
  3349.     || (atts.save_under != Tk_Attributes(tkwin)->save_under)) {
  3350. Tk_ChangeWindowAttributes(tkwin,
  3351. CWOverrideRedirect|CWSaveUnder, &atts);
  3352.     }
  3353. }
  3354. /*
  3355.  *----------------------------------------------------------------------
  3356.  *
  3357.  * TkWinGetWrapperWindow --
  3358.  *
  3359.  * Gets the Windows HWND for a given window.
  3360.  *
  3361.  * Results:
  3362.  * Returns the wrapper window for a Tk window.
  3363.  *
  3364.  * Side effects:
  3365.  * None.
  3366.  *
  3367.  *----------------------------------------------------------------------
  3368.  */
  3369. HWND
  3370. TkWinGetWrapperWindow(
  3371.     Tk_Window tkwin) /* The window we need the wrapper from */
  3372. {
  3373.     TkWindow *winPtr = (TkWindow *)tkwin;
  3374.     return (winPtr->wmInfoPtr->wrapper);
  3375. }
  3376. /*
  3377.  *----------------------------------------------------------------------
  3378.  *
  3379.  * TkWmFocusToplevel --
  3380.  *
  3381.  * This is a utility procedure invoked by focus-management code. It
  3382.  * exists because of the extra wrapper windows that exist under
  3383.  * Unix; its job is to map from wrapper windows to the
  3384.  * corresponding toplevel windows.  On PCs and Macs there are no
  3385.  * wrapper windows so no mapping is necessary;  this procedure just
  3386.  * determines whether a window is a toplevel or not.
  3387.  *
  3388.  * Results:
  3389.  * If winPtr is a toplevel window, returns the pointer to the
  3390.  * window; otherwise returns NULL.
  3391.  *
  3392.  * Side effects:
  3393.  * None.
  3394.  *
  3395.  *----------------------------------------------------------------------
  3396.  */
  3397. TkWindow *
  3398. TkWmFocusToplevel(winPtr)
  3399.     TkWindow *winPtr; /* Window that received a focus-related
  3400.  * event. */
  3401. {
  3402.     if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
  3403. return NULL;
  3404.     }
  3405.     return winPtr;
  3406. }
  3407.  
  3408. /*
  3409.  *----------------------------------------------------------------------
  3410.  *
  3411.  * TkpGetWrapperWindow --
  3412.  *
  3413.  * This is a utility procedure invoked by focus-management code. It
  3414.  * maps to the wrapper for a top-level, which is just the same
  3415.  * as the top-level on Macs and PCs.
  3416.  *
  3417.  * Results:
  3418.  * If winPtr is a toplevel window, returns the pointer to the
  3419.  * window; otherwise returns NULL.
  3420.  *
  3421.  * Side effects:
  3422.  * None.
  3423.  *
  3424.  *----------------------------------------------------------------------
  3425.  */
  3426. TkWindow *
  3427. TkpGetWrapperWindow(
  3428.     TkWindow *winPtr) /* Window that received a focus-related
  3429.  * event. */
  3430. {
  3431.     if (!(winPtr->flags & TK_TOP_HIERARCHY)) {
  3432. return NULL;
  3433.     }
  3434.     return winPtr;
  3435. }
  3436. /*
  3437.  *----------------------------------------------------------------------
  3438.  *
  3439.  * ActivateWindow --
  3440.  *
  3441.  * This function is called when an ActivateEvent is processed.
  3442.  *
  3443.  * Results:
  3444.  * Returns 1 to indicate that the event was handled, else 0.
  3445.  *
  3446.  * Side effects:
  3447.  * May activate the toplevel window associated with the event.
  3448.  *
  3449.  *----------------------------------------------------------------------
  3450.  */
  3451. static int
  3452. ActivateWindow(
  3453.     Tcl_Event *evPtr, /* Pointer to ActivateEvent. */
  3454.     int flags) /* Notifier event mask. */
  3455. {
  3456.     TkWindow *winPtr;
  3457.     if (! (flags & TCL_WINDOW_EVENTS)) {
  3458. return 0;
  3459.     }
  3460.     winPtr = ((ActivateEvent *) evPtr)->winPtr;
  3461.     /*
  3462.      * If the window is excluded by a grab, call SetFocus on the
  3463.      * grabbed window instead. [Bug 220908]
  3464.      */
  3465.     if (winPtr) {
  3466. if (TkGrabState(winPtr) != TK_GRAB_EXCLUDED) {
  3467.     SetFocus(Tk_GetHWND(winPtr->window));
  3468. } else {
  3469.     SetFocus(Tk_GetHWND(winPtr->dispPtr->grabWinPtr->window));
  3470. }
  3471.     }
  3472.     return 1;
  3473. }
  3474. /*
  3475.  *----------------------------------------------------------------------
  3476.  *
  3477.  * TkWinSetForegroundWindow --
  3478.  *
  3479.  * This function is a wrapper for SetForegroundWindow, calling
  3480.  *      it on the wrapper window because it has no affect on child
  3481.  *      windows.
  3482.  *
  3483.  * Results:
  3484.  * none
  3485.  *
  3486.  * Side effects:
  3487.  * May activate the toplevel window.
  3488.  *
  3489.  *----------------------------------------------------------------------
  3490.  */
  3491. void
  3492. TkWinSetForegroundWindow(winPtr)
  3493.     TkWindow *winPtr;
  3494. {
  3495.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  3496.     if (wmPtr->wrapper != NULL) {
  3497. SetForegroundWindow(wmPtr->wrapper);
  3498.     } else {
  3499. SetForegroundWindow(Tk_GetHWND(winPtr->window));
  3500.     }
  3501. }