diff options
Diffstat (limited to 'tk/unix/tkUnixWm.c')
-rw-r--r-- | tk/unix/tkUnixWm.c | 458 |
1 files changed, 339 insertions, 119 deletions
diff --git a/tk/unix/tkUnixWm.c b/tk/unix/tkUnixWm.c index 4251c52ab23..98e4861f044 100644 --- a/tk/unix/tkUnixWm.c +++ b/tk/unix/tkUnixWm.c @@ -8,7 +8,6 @@ * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -267,21 +266,10 @@ typedef struct TkWmInfo { /* * This module keeps a list of all top-level windows, primarily to - * simplify the job of Tk_CoordsToWindow. + * simplify the job of Tk_CoordsToWindow. The list is called + * firstWmPtr and is stored in the TkDisplay structure. */ -static WmInfo *firstWmPtr = NULL; /* Points to first top-level window. */ - - -/* - * The variable below is used to enable or disable tracing in this - * module. If tracing is enabled, then information is printed on - * standard output about interesting interactions with the window - * manager. - */ - -static int wmTracing = 0; - /* * The following structures are the official type records for geometry * management of top-level and menubar windows. @@ -337,6 +325,7 @@ static void ReparentEvent _ANSI_ARGS_((WmInfo *wmPtr, XReparentEvent *eventPtr)); static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy, Tk_Window tkwin)); +static void UpdateCommand _ANSI_ARGS_((TkWindow *winPtr)); static void UpdateGeometryInfo _ANSI_ARGS_(( ClientData clientData)); static void UpdateHints _ANSI_ARGS_((TkWindow *winPtr)); @@ -378,6 +367,7 @@ TkWmNewWindow(winPtr) TkWindow *winPtr; /* Newly-created top-level window. */ { register WmInfo *wmPtr; + TkDisplay *dispPtr = winPtr->dispPtr; wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo)); wmPtr->winPtr = winPtr; @@ -433,8 +423,8 @@ TkWmNewWindow(winPtr) wmPtr->cmdArgv = NULL; wmPtr->clientMachine = NULL; wmPtr->flags = WM_NEVER_MAPPED; - wmPtr->nextPtr = firstWmPtr; - firstWmPtr = wmPtr; + wmPtr->nextPtr = (WmInfo *) dispPtr->firstWmPtr; + dispPtr->firstWmPtr = wmPtr; winPtr->wmInfoPtr = wmPtr; UpdateVRootGeometry(wmPtr); @@ -480,6 +470,8 @@ TkWmMapWindow(winPtr) char *string; if (wmPtr->flags & WM_NEVER_MAPPED) { + Tcl_DString ds; + wmPtr->flags &= ~WM_NEVER_MAPPED; /* @@ -498,16 +490,22 @@ TkWmMapWindow(winPtr) */ string = (wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid; - if (XStringListToTextProperty(&string, 1, &textProp) != 0) { + Tcl_UtfToExternalDString(NULL, string, -1, &ds); + string = Tcl_DStringValue(&ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, + &textProp) != 0) { XSetWMName(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } - + Tcl_DStringFree(&ds); + TkWmSetClass(winPtr); if (wmPtr->iconName != NULL) { + Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, - wmPtr->iconName); + Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); } if (wmPtr->master != None) { @@ -519,16 +517,17 @@ TkWmMapWindow(winPtr) UpdateHints(winPtr); UpdateWmProtocols(wmPtr); if (wmPtr->cmdArgv != NULL) { - XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, - wmPtr->cmdArgv, wmPtr->cmdArgc); + UpdateCommand(winPtr); } if (wmPtr->clientMachine != NULL) { - if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp) - != 0) { + Tcl_UtfToExternalDString(NULL, wmPtr->clientMachine, -1, &ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, + &textProp) != 0) { XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } + Tcl_DStringFree(&ds); } } if (wmPtr->hints.initial_state == WithdrawnState) { @@ -630,12 +629,13 @@ TkWmDeadWindow(winPtr) if (wmPtr == NULL) { return; } - if (firstWmPtr == wmPtr) { - firstWmPtr = wmPtr->nextPtr; + if ((WmInfo *) winPtr->dispPtr->firstWmPtr == wmPtr) { + winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr; } else { register WmInfo *prevPtr; - for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) { + for (prevPtr = (WmInfo *) winPtr->dispPtr->firstWmPtr; ; + prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { panic("couldn't unlink window in TkWmDeadWindow"); } @@ -740,13 +740,18 @@ TkWmSetClass(winPtr) if (winPtr->classUid != NULL) { XClassHint *classPtr; + Tcl_DString name, class; + Tcl_UtfToExternalDString(NULL, winPtr->nameUid, -1, &name); + Tcl_UtfToExternalDString(NULL, winPtr->classUid, -1, &class); classPtr = XAllocClassHint(); - classPtr->res_name = winPtr->nameUid; - classPtr->res_class = winPtr->classUid; + classPtr->res_name = Tcl_DStringValue(&name); + classPtr->res_class = Tcl_DStringValue(&class); XSetClassHint(winPtr->display, winPtr->wmInfoPtr->wrapperPtr->window, classPtr); XFree((char *) classPtr); + Tcl_DStringFree(&name); + Tcl_DStringFree(&class); } } @@ -781,6 +786,7 @@ Tk_WmCmd(clientData, interp, argc, argv) register WmInfo *wmPtr; int c; size_t length; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; if (argc < 2) { wrongNumArgs: @@ -798,10 +804,11 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 2) { - interp->result = (wmTracing) ? "on" : "off"; + Tcl_SetResult(interp, ((dispPtr->wmTracing) ? "on" : "off"), + TCL_STATIC); return TCL_OK; } - return Tcl_GetBoolean(interp, argv[2], &wmTracing); + return Tcl_GetBoolean(interp, argv[2], &dispPtr->wmTracing); } if (argc < 3) { @@ -828,9 +835,12 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & PAspect) { - sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x, wmPtr->minAspect.y, wmPtr->maxAspect.x, wmPtr->maxAspect.y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -845,7 +855,8 @@ Tk_WmCmd(clientData, interp, argc, argv) } if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || (denom2 <= 0)) { - interp->result = "aspect number can't be <= 0"; + Tcl_SetResult(interp, "aspect number can't be <= 0", + TCL_STATIC); return TCL_ERROR; } wmPtr->minAspect.x = numer1; @@ -866,7 +877,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->clientMachine != NULL) { - interp->result = wmPtr->clientMachine; + Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC); } return TCL_OK; } @@ -890,12 +901,16 @@ Tk_WmCmd(clientData, interp, argc, argv) strcpy(wmPtr->clientMachine, argv[3]); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { XTextProperty textProp; - if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp) - != 0) { + Tcl_DString ds; + + Tcl_UtfToExternalDString(NULL, wmPtr->clientMachine, -1, &ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, + &textProp) != 0) { XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } + Tcl_DStringFree(&ds); } } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0) && (length >= 3)) { @@ -985,8 +1000,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->cmdArgv != NULL) { - interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv); - interp->freeProc = TCL_DYNAMIC; + Tcl_SetResult(interp, + Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv), + TCL_DYNAMIC); } return TCL_OK; } @@ -1010,8 +1026,7 @@ Tk_WmCmd(clientData, interp, argc, argv) wmPtr->cmdArgc = cmdArgc; wmPtr->cmdArgv = cmdArgv; if (!(wmPtr->flags & WM_NEVER_MAPPED)) { - XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, - cmdArgv, cmdArgc); + UpdateCommand(winPtr); } } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) { if (argc != 3) { @@ -1041,7 +1056,8 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - interp->result = wmPtr->hints.input ? "passive" : "active"; + Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"), + TCL_STATIC); return TCL_OK; } c = argv[3][0]; @@ -1059,6 +1075,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0) && (length >= 2)) { Window window; + char buf[TCL_INTEGER_SPACE]; if (argc != 3) { Tcl_AppendResult(interp, "wrong # arguments: must be \"", @@ -1069,7 +1086,8 @@ Tk_WmCmd(clientData, interp, argc, argv) if (window == None) { window = Tk_WindowId((Tk_Window) winPtr); } - sprintf(interp->result, "0x%x", (unsigned int) window); + sprintf(buf, "0x%x", (unsigned int) window); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0) && (length >= 2)) { char xSign, ySign; @@ -1082,6 +1100,8 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { + char buf[16 + TCL_INTEGER_SPACE * 4]; + xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+'; ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+'; if (wmPtr->gridWin != NULL) { @@ -1093,8 +1113,9 @@ Tk_WmCmd(clientData, interp, argc, argv) width = winPtr->changes.width; height = winPtr->changes.height; } - sprintf(interp->result, "%dx%d%c%d%c%d", width, height, - xSign, wmPtr->x, ySign, wmPtr->y); + sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x, + ySign, wmPtr->y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if (*argv[3] == '\0') { @@ -1115,9 +1136,12 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & PBaseSize) { - sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth, + char buf[TCL_INTEGER_SPACE * 4]; + + sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth, wmPtr->reqGridHeight, wmPtr->widthInc, wmPtr->heightInc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -1144,19 +1168,19 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (reqWidth < 0) { - interp->result = "baseWidth can't be < 0"; + Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC); return TCL_ERROR; } if (reqHeight < 0) { - interp->result = "baseHeight can't be < 0"; + Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC); return TCL_ERROR; } if (widthInc < 0) { - interp->result = "widthInc can't be < 0"; + Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC); return TCL_ERROR; } if (heightInc < 0) { - interp->result = "heightInc can't be < 0"; + Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC); return TCL_ERROR; } Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc, @@ -1177,7 +1201,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & WindowGroupHint) { - interp->result = wmPtr->leaderName; + Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC); } return TCL_OK; } @@ -1204,6 +1228,9 @@ Tk_WmCmd(clientData, interp, argc, argv) if (wmPtr2->wrapperPtr == NULL) { CreateWrapper(wmPtr2); } + if (wmPtr->leaderName != NULL) { + ckfree(wmPtr->leaderName); + } wmPtr->hints.window_group = Tk_WindowId(wmPtr2->wrapperPtr); wmPtr->hints.flags |= WindowGroupHint; wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1)); @@ -1222,8 +1249,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & IconPixmapHint) { - interp->result = Tk_NameOfBitmap(winPtr->display, - wmPtr->hints.icon_pixmap); + Tcl_SetResult(interp, + Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_pixmap), + TCL_STATIC); } return TCL_OK; } @@ -1277,8 +1305,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } else { if (XIconifyWindow(winPtr->display, wmPtr->wrapperPtr->window, winPtr->screenNum) == 0) { - interp->result = - "couldn't send iconify message to window manager"; + Tcl_SetResult(interp, + "couldn't send iconify message to window manager", + TCL_STATIC); return TCL_ERROR; } WaitForMapNotify(winPtr, 0); @@ -1295,8 +1324,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & IconMaskHint) { - interp->result = Tk_NameOfBitmap(winPtr->display, - wmPtr->hints.icon_mask); + Tcl_SetResult(interp, + Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask), + TCL_STATIC); } return TCL_OK; } @@ -1322,17 +1352,23 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : ""; + Tcl_SetResult(interp, + ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""), + TCL_STATIC); return TCL_OK; } else { if (wmPtr->iconName != NULL) { - ckfree(wmPtr->iconName); + ckfree((char *) wmPtr->iconName); } wmPtr->iconName = ckalloc((unsigned) (strlen(argv[3]) + 1)); strcpy(wmPtr->iconName, argv[3]); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { + Tcl_DString ds; + + Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, - wmPtr->iconName); + Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); } } } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0) @@ -1347,8 +1383,11 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->hints.flags & IconPositionHint) { - sprintf(interp->result, "%d %d", wmPtr->hints.icon_x, + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->hints.icon_x, wmPtr->hints.icon_y); + Tcl_SetResult(interp, buf, TCL_VOLATILE); } return TCL_OK; } @@ -1378,7 +1417,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->icon != NULL) { - interp->result = Tk_PathName(wmPtr->icon); + Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC); } return TCL_OK; } @@ -1447,8 +1486,9 @@ Tk_WmCmd(clientData, interp, argc, argv) if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(wmPtr2->wrapperPtr), Tk_ScreenNumber(tkwin2)) == 0) { - interp->result = - "couldn't send withdraw message to window manager"; + Tcl_SetResult(interp, + "couldn't send withdraw message to window manager", + TCL_STATIC); return TCL_ERROR; } WaitForMapNotify((TkWindow *) tkwin2, 0); @@ -1464,8 +1504,11 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { + char buf[TCL_INTEGER_SPACE * 2]; + GetMaxSize(wmPtr, &width, &height); - sprintf(interp->result, "%d %d", width, height); + sprintf(buf, "%d %d", width, height); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) @@ -1485,8 +1528,10 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", wmPtr->minWidth, - wmPtr->minHeight); + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", wmPtr->minWidth, wmPtr->minHeight); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) @@ -1499,7 +1544,7 @@ Tk_WmCmd(clientData, interp, argc, argv) goto updateGeom; } else if ((c == 'o') && (strncmp(argv[1], "overrideredirect", length) == 0)) { - int boolean; + int boolean, curValue; XSetWindowAttributes atts; if ((argc != 3) && (argc != 4)) { @@ -1508,24 +1553,27 @@ Tk_WmCmd(clientData, interp, argc, argv) (char *) NULL); return TCL_ERROR; } + curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect; if (argc == 3) { - if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { - interp->result = "1"; - } else { - interp->result = "0"; - } + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue); return TCL_OK; } if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) { return TCL_ERROR; } - atts.override_redirect = (boolean) ? True : False; - Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect, - &atts); - if (winPtr->wmInfoPtr->wrapperPtr != NULL) { - Tk_ChangeWindowAttributes( + if (curValue != boolean) { + /* + * Only do this if we are really changing value, because it + * causes some funky stuff to occur + */ + atts.override_redirect = (boolean) ? True : False; + Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect, + &atts); + if (winPtr->wmInfoPtr->wrapperPtr != NULL) { + Tk_ChangeWindowAttributes( (Tk_Window) winPtr->wmInfoPtr->wrapperPtr, CWOverrideRedirect, &atts); + } } } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0) && (length >= 2)) { @@ -1537,9 +1585,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & USPosition) { - interp->result = "user"; + Tcl_SetResult(interp, "user", TCL_STATIC); } else if (wmPtr->sizeHintsFlags & PPosition) { - interp->result = "program"; + Tcl_SetResult(interp, "program", TCL_STATIC); } return TCL_OK; } @@ -1593,7 +1641,7 @@ Tk_WmCmd(clientData, interp, argc, argv) for (protPtr = wmPtr->protPtr; protPtr != NULL; protPtr = protPtr->nextPtr) { if (protPtr->protocol == protocol) { - interp->result = protPtr->command; + Tcl_SetResult(interp, protPtr->command, TCL_STATIC); return TCL_OK; } } @@ -1640,9 +1688,12 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - sprintf(interp->result, "%d %d", + char buf[TCL_INTEGER_SPACE * 2]; + + sprintf(buf, "%d %d", (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1, (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1); + Tcl_SetResult(interp, buf, TCL_VOLATILE); return TCL_OK; } if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK) @@ -1671,9 +1722,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->sizeHintsFlags & USSize) { - interp->result = "user"; + Tcl_SetResult(interp, "user", TCL_STATIC); } else if (wmPtr->sizeHintsFlags & PSize) { - interp->result = "program"; + Tcl_SetResult(interp, "program", TCL_STATIC); } return TCL_OK; } @@ -1699,21 +1750,95 @@ Tk_WmCmd(clientData, interp, argc, argv) goto updateGeom; } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0) && (length >= 2)) { - if (argc != 3) { + if ((argc < 3) || (argc > 4)) { Tcl_AppendResult(interp, "wrong # arguments: must be \"", - argv[0], " state window\"", (char *) NULL); + argv[0], " state window ?state?\"", (char *) NULL); return TCL_ERROR; } - if (wmPtr->iconFor != NULL) { - interp->result = "icon"; - } else if (wmPtr->withdrawn) { - interp->result = "withdrawn"; - } else if (Tk_IsMapped((Tk_Window) winPtr) - || ((wmPtr->flags & WM_NEVER_MAPPED) - && (wmPtr->hints.initial_state == NormalState))) { - interp->result = "normal"; + if (argc == 4) { + if (wmPtr->iconFor != NULL) { + Tcl_AppendResult(interp, "can't change state of ", argv[2], + ": it is an icon for ", Tk_PathName(wmPtr->iconFor), + (char *) NULL); + return TCL_ERROR; + } + + c = argv[3][0]; + length = strlen(argv[3]); + + if ((c == 'n') && (strncmp(argv[3], "normal", length) == 0)) { + wmPtr->hints.initial_state = NormalState; + wmPtr->withdrawn = 0; + if (wmPtr->flags & WM_NEVER_MAPPED) { + return TCL_OK; + } + UpdateHints(winPtr); + Tk_MapWindow((Tk_Window) winPtr); + } else if ((c == 'i') + && (strncmp(argv[3], "iconic", length) == 0)) { + if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { + Tcl_AppendResult(interp, "can't iconify \"", + winPtr->pathName, + "\": override-redirect flag is set", + (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->master != None) { + Tcl_AppendResult(interp, "can't iconify \"", + winPtr->pathName, + "\": it is a transient", (char *) NULL); + return TCL_ERROR; + } + wmPtr->hints.initial_state = IconicState; + if (wmPtr->flags & WM_NEVER_MAPPED) { + return TCL_OK; + } + if (wmPtr->withdrawn) { + UpdateHints(winPtr); + Tk_MapWindow((Tk_Window) winPtr); + wmPtr->withdrawn = 0; + } else { + if (XIconifyWindow(winPtr->display, + wmPtr->wrapperPtr->window, + winPtr->screenNum) == 0) { + Tcl_SetResult(interp, "couldn't send iconify message to window manager", TCL_STATIC); + return TCL_ERROR; + } + WaitForMapNotify(winPtr, 0); + } + } else if ((c == 'w') + && (strncmp(argv[3], "withdrawn", length) == 0)) { + wmPtr->hints.initial_state = WithdrawnState; + wmPtr->withdrawn = 1; + if (wmPtr->flags & WM_NEVER_MAPPED) { + return TCL_OK; + } + if (XWithdrawWindow(winPtr->display, wmPtr->wrapperPtr->window, + winPtr->screenNum) == 0) { + Tcl_SetResult(interp, + "couldn't send withdraw message to window manager", + TCL_STATIC); + return TCL_ERROR; + } + WaitForMapNotify(winPtr, 0); + } else { + Tcl_AppendResult(interp, "bad argument \"", argv[3], + "\": must be normal, iconic or withdrawn", + (char *) NULL); + return TCL_ERROR; + } } else { - interp->result = "iconic"; + if (wmPtr->iconFor != NULL) { + Tcl_SetResult(interp, "icon", TCL_STATIC); + } else if (wmPtr->withdrawn) { + Tcl_SetResult(interp, "withdrawn", TCL_STATIC); + } else if (Tk_IsMapped((Tk_Window) winPtr) + || ((wmPtr->flags & WM_NEVER_MAPPED) + && (wmPtr->hints.initial_state == NormalState))) { + Tcl_SetResult(interp, "normal", TCL_STATIC); + } else { + Tcl_SetResult(interp, "iconic", TCL_STATIC); + } } } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0) && (length >= 2)) { @@ -1723,24 +1848,28 @@ Tk_WmCmd(clientData, interp, argc, argv) return TCL_ERROR; } if (argc == 3) { - interp->result = (wmPtr->title != NULL) ? wmPtr->title - : winPtr->nameUid; + Tcl_SetResult(interp, + ((wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid), + TCL_STATIC); return TCL_OK; } else { if (wmPtr->title != NULL) { - ckfree(wmPtr->title); + ckfree((char *) wmPtr->title); } wmPtr->title = ckalloc((unsigned) (strlen(argv[3]) + 1)); strcpy(wmPtr->title, argv[3]); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { XTextProperty textProp; + Tcl_DString ds; - if (XStringListToTextProperty(&wmPtr->title, 1, + Tcl_UtfToExternalDString(NULL, wmPtr->title, -1, &ds); + if (XStringListToTextProperty(&(Tcl_DStringValue(&ds)), 1, &textProp) != 0) { XSetWMName(winPtr->display, wmPtr->wrapperPtr->window, &textProp); XFree((char *) textProp.value); } + Tcl_DStringFree(&ds); } } } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0) @@ -1755,7 +1884,7 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (argc == 3) { if (wmPtr->master != None) { - interp->result = wmPtr->masterWindowName; + Tcl_SetResult(interp, wmPtr->masterWindowName, TCL_STATIC); } return TCL_OK; } @@ -1783,6 +1912,9 @@ Tk_WmCmd(clientData, interp, argc, argv) CreateWrapper(wmPtr2); } wmPtr->master = Tk_WindowId(wmPtr2->wrapperPtr); + if (wmPtr->masterWindowName != NULL) { + ckfree((char *) wmPtr->masterWindowName); + } wmPtr->masterWindowName = ckalloc((unsigned) (strlen(argv[3])+1)); strcpy(wmPtr->masterWindowName, argv[3]); } @@ -1810,8 +1942,9 @@ Tk_WmCmd(clientData, interp, argc, argv) } if (XWithdrawWindow(winPtr->display, wmPtr->wrapperPtr->window, winPtr->screenNum) == 0) { - interp->result = - "couldn't send withdraw message to window manager"; + Tcl_SetResult(interp, + "couldn't send withdraw message to window manager", + TCL_STATIC); return TCL_ERROR; } WaitForMapNotify(winPtr, 0); @@ -2029,6 +2162,8 @@ ConfigureEvent(wmPtr, configEventPtr) { TkWindow *wrapperPtr = wmPtr->wrapperPtr; TkWindow *winPtr = wmPtr->winPtr; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; + Tk_ErrorHandler handler; /* * Update size information from the event. There are a couple of @@ -2046,7 +2181,7 @@ ConfigureEvent(wmPtr, configEventPtr) if (((wrapperPtr->changes.width != configEventPtr->width) || (wrapperPtr->changes.height != configEventPtr->height)) && !(wmPtr->flags & WM_SYNC_PENDING)){ - if (wmTracing) { + if (dispPtr->wmTracing) { printf("TopLevelEventProc: user changed %s size to %dx%d\n", winPtr->pathName, configEventPtr->width, configEventPtr->height); @@ -2110,7 +2245,7 @@ ConfigureEvent(wmPtr, configEventPtr) wmPtr->configHeight = configEventPtr->height; } - if (wmTracing) { + if (dispPtr->wmTracing) { printf("ConfigureEvent: %s x = %d y = %d, width = %d, height = %d", winPtr->pathName, configEventPtr->x, configEventPtr->y, configEventPtr->width, configEventPtr->height); @@ -2156,12 +2291,15 @@ ConfigureEvent(wmPtr, configEventPtr) /* * Make sure that the toplevel and menubar are properly positioned within - * the wrapper. + * the wrapper. If the menuHeight happens to be zero, we'll get a + * BadValue X error that we want to ignore [Bug: 3377] */ - + handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1, + (Tk_ErrorProc *) NULL, (ClientData) NULL); XMoveResizeWindow(winPtr->display, winPtr->window, 0, wmPtr->menuHeight, (unsigned) wrapperPtr->changes.width, (unsigned) (wrapperPtr->changes.height - wmPtr->menuHeight)); + Tk_DeleteErrorHandler(handler); if ((wmPtr->menubar != NULL) && ((Tk_Width(wmPtr->menubar) != wrapperPtr->changes.width) || (Tk_Height(wmPtr->menubar) != wmPtr->menuHeight))) { @@ -2213,6 +2351,7 @@ ReparentEvent(wmPtr, reparentEventPtr) unsigned long numItems, bytesAfter; unsigned int dummy; Tk_ErrorHandler handler; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; /* * Identify the root window for wrapperPtr. This is tricky because of @@ -2238,7 +2377,7 @@ ReparentEvent(wmPtr, reparentEventPtr) && (actualType == XA_WINDOW))) { if ((actualFormat == 32) && (numItems == 1)) { vRoot = wmPtr->vRoot = *virtualRootPtr; - } else if (wmTracing) { + } else if (dispPtr->wmTracing) { printf("%s format %d numItems %ld\n", "ReparentEvent got bogus VROOT property:", actualFormat, numItems); @@ -2247,7 +2386,7 @@ ReparentEvent(wmPtr, reparentEventPtr) } Tk_DeleteErrorHandler(handler); - if (wmTracing) { + if (dispPtr->wmTracing) { printf("ReparentEvent: %s reparented to 0x%x, vRoot = 0x%x\n", wmPtr->winPtr->pathName, (unsigned int) reparentEventPtr->parent, (unsigned int) vRoot); @@ -2344,6 +2483,7 @@ ComputeReparentGeometry(wmPtr) Window dummy2; Status status; Tk_ErrorHandler handler; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); @@ -2410,7 +2550,7 @@ ComputeReparentGeometry(wmPtr) wmPtr->wrapperPtr->changes.x = x + wmPtr->xInParent; wmPtr->wrapperPtr->changes.y = y + wmPtr->yInParent; - if (wmTracing) { + if (dispPtr->wmTracing) { printf("wrapperPtr coords %d,%d, wmPtr coords %d,%d, offsets %d %d\n", wrapperPtr->changes.x, wrapperPtr->changes.y, wmPtr->x, wmPtr->y, wmPtr->xInParent, wmPtr->yInParent); @@ -2443,6 +2583,7 @@ WrapperEventProc(clientData, eventPtr) { WmInfo *wmPtr = (WmInfo *) clientData; XEvent mapEvent; + TkDisplay *dispPtr = wmPtr->winPtr->dispPtr; wmPtr->flags |= WM_VROOT_OFFSET_STALE; if (eventPtr->type == DestroyNotify) { @@ -2462,7 +2603,7 @@ WrapperEventProc(clientData, eventPtr) Tk_DestroyWindow((Tk_Window) wmPtr->winPtr); Tk_DeleteErrorHandler(handler); } - if (wmTracing) { + if (dispPtr->wmTracing) { printf("TopLevelEventProc: %s deleted\n", wmPtr->winPtr->pathName); } } else if (eventPtr->type == ConfigureNotify) { @@ -2725,7 +2866,7 @@ UpdateGeometryInfo(clientData) } wmPtr->configWidth = width; wmPtr->configHeight = height; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n", x, y, width, height); } @@ -2746,7 +2887,7 @@ UpdateGeometryInfo(clientData) } wmPtr->configWidth = width; wmPtr->configHeight = height; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("UpdateGeometryInfo resizing to %d x %d\n", width, height); } XResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, @@ -2947,7 +3088,7 @@ WaitForConfigureNotify(winPtr, serial) ConfigureNotify, &event); wmPtr->flags &= ~WM_SYNC_PENDING; if (code != TCL_OK) { - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForConfigureNotify giving up on %s\n", winPtr->pathName); } @@ -2959,7 +3100,7 @@ WaitForConfigureNotify(winPtr, serial) } } wmPtr->flags &= ~WM_MOVE_PENDING; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForConfigureNotify finished with %s, serial %ld\n", winPtr->pathName, serial); } @@ -3135,14 +3276,14 @@ WaitForMapNotify(winPtr, mapped) * just quit. */ - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForMapNotify giving up on %s\n", winPtr->pathName); } break; } } wmPtr->flags &= ~WM_MOVE_PENDING; - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("WaitForMapNotify finished with %s\n", winPtr->pathName); } } @@ -3188,7 +3329,7 @@ UpdateHints(winPtr) * * Results: * A standard Tcl return value, plus an error message in - * interp->result if an error occurs. + * the interp's result if an error occurs. * * Side effects: * The size and/or location of winPtr may change. @@ -3441,6 +3582,8 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) int x, y, childX, childY, tmpx, tmpy, bd; WmInfo *wmPtr; TkWindow *winPtr, *childPtr, *nextPtr; + TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; + Tk_ErrorHandler handler = NULL; /* * Step 1: scan the list of toplevel windows to see if there is a @@ -3452,7 +3595,7 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) parent = window = RootWindowOfScreen(Tk_Screen(tkwin)); x = rootX; y = rootY; - for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { + for (wmPtr = (WmInfo *) dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { if (Tk_Screen(wmPtr->winPtr) != Tk_Screen(tkwin)) { continue; } @@ -3479,15 +3622,24 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) * the toplevel. */ + handler = Tk_CreateErrorHandler(Tk_Display(tkwin), -1, -1, -1, + (Tk_ErrorProc *) NULL, (ClientData) NULL); while (1) { if (XTranslateCoordinates(Tk_Display(tkwin), parent, window, x, y, &childX, &childY, &child) == False) { - panic("Tk_CoordsToWindow got False return from XTranslateCoordinates"); + /* + * We can end up here when the window is in the middle of + * being deleted + */ + Tk_DeleteErrorHandler(handler); + return NULL; } if (child == None) { + Tk_DeleteErrorHandler(handler); return NULL; } - for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) { + for (wmPtr = (WmInfo *) dispPtr->firstWmPtr; wmPtr != NULL; + wmPtr = wmPtr->nextPtr) { if (wmPtr->reparent == child) { goto gotToplevel; } @@ -3506,6 +3658,14 @@ Tk_CoordsToWindow(rootX, rootY, tkwin) } gotToplevel: + if (handler) { + /* + * Check value of handler, because we can reach this label + * from above or below + */ + Tk_DeleteErrorHandler(handler); + handler = NULL; + } winPtr = wmPtr->winPtr; if (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr) { return NULL; @@ -3644,7 +3804,7 @@ UpdateVRootGeometry(wmPtr) (unsigned int *) &wmPtr->vRootWidth, (unsigned int *) &wmPtr->vRootHeight, (unsigned int *) &bd, &dummy); - if (wmTracing) { + if (winPtr->dispPtr->wmTracing) { printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ", wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth); printf("height = %d, status = %d\n", wmPtr->vRootHeight, status); @@ -4818,3 +4978,63 @@ TkpGetWrapperWindow(winPtr) return wmPtr->wrapperPtr; } + +/* + *---------------------------------------------------------------------- + * + * UpdateCommand -- + * + * Update the WM_COMMAND property, taking care to translate + * the command strings into the external encoding. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateCommand(winPtr) + TkWindow *winPtr; +{ + register WmInfo *wmPtr = winPtr->wmInfoPtr; + Tcl_DString cmds, ds; + int i, *offsets; + char **cmdArgv; + + /* + * Translate the argv strings into the external encoding. To avoid + * allocating lots of memory, the strings are appended to a buffer + * with nulls between each string. + * + * This code is tricky because we need to pass and array of pointers + * to XSetCommand. However, we can't compute the pointers as we go + * because the DString buffer space could get reallocated. So, store + * offsets for each element as we go, then compute pointers from the + * offsets once the entire DString is done. + */ + + cmdArgv = (char **) ckalloc(sizeof(char *) * wmPtr->cmdArgc); + offsets = (int *) ckalloc( sizeof(int) * wmPtr->cmdArgc); + Tcl_DStringInit(&cmds); + for (i = 0; i < wmPtr->cmdArgc; i++) { + Tcl_UtfToExternalDString(NULL, wmPtr->cmdArgv[i], -1, &ds); + offsets[i] = Tcl_DStringLength(&cmds); + Tcl_DStringAppend(&cmds, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds)+1); + Tcl_DStringFree(&ds); + } + cmdArgv[0] = Tcl_DStringValue(&cmds); + for (i = 1; i < wmPtr->cmdArgc; i++) { + cmdArgv[i] = cmdArgv[0] + offsets[i]; + } + + XSetCommand(winPtr->display, wmPtr->wrapperPtr->window, + cmdArgv, wmPtr->cmdArgc); + Tcl_DStringFree(&cmds); + ckfree((char *) cmdArgv); + ckfree((char *) offsets); +} |