diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | tests/unixWm.test | 10 | ||||
-rw-r--r-- | tests/wm.test | 6 | ||||
-rw-r--r-- | unix/tkUnixWm.c | 246 |
4 files changed, 185 insertions, 89 deletions
@@ -1,3 +1,15 @@ +2005-01-14 Joe English <jenglish@users.sourceforge.net> + * unix/tkUnixWm.c: Sync with CVS HEAD (r1.47): + Fixes: #959973 "wm title bug" (support Unicode titles) + Fixes: #742882 "Potential division by zero in gridded wm geometry" + Use Tcl_GetTime instead of TclpGetTime [#874745] + Use Tcl_Panic() instead of "panic" [#865264] + Fixes: #632816 "cannot remove transient" + Fixes: #568861 "Fix for wm minsize and maxsize commands" + * tests/unixWm.test, tests/wm.test: Updated test suite for + #632816 (unixWm-37.3, unixWm-37.4, wm-grid-1.11, wm-grid-1.12) + and #742882 (unixWm-20.9, unixWm-20.11). + 2005-01-11 Donal K. Fellows <donal.k.fellows@man.ac.uk> * generic/tkObj.c (TkParsePadAmount): diff --git a/tests/unixWm.test b/tests/unixWm.test index 2985d65..bca1f5e 100644 --- a/tests/unixWm.test +++ b/tests/unixWm.test @@ -7,7 +7,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: unixWm.test,v 1.29.2.3 2004/10/05 22:27:27 hobbs Exp $ +# RCS: @(#) $Id: unixWm.test,v 1.29.2.4 2005/01/14 21:09:47 jenglish Exp $ package require tcltest 2.2 namespace import -force tcltest::configure @@ -733,13 +733,13 @@ test unixWm-20.8 {Tk_WmCmd procedure, "grid" option} unix { } {1 {expected integer but got "bar"}} test unixWm-20.9 {Tk_WmCmd procedure, "grid" option} unix { list [catch {wm grid .t 10 11 -2 13} msg] $msg -} {1 {widthInc can't be < 0}} +} {1 {widthInc can't be <= 0}} test unixWm-20.10 {Tk_WmCmd procedure, "grid" option} unix { list [catch {wm grid .t 10 11 12 bogus} msg] $msg } {1 {expected integer but got "bogus"}} test unixWm-20.11 {Tk_WmCmd procedure, "grid" option} unix { list [catch {wm grid .t 10 11 12 -1} msg] $msg -} {1 {heightInc can't be < 0}} +} {1 {heightInc can't be <= 0}} catch {destroy .t} catch {destroy .icon} @@ -1232,7 +1232,7 @@ test unixWm-37.3 {Tk_WmCmd procedure, "transient" option} {unix testwrapper} { [testprop [testwrapper .t2] WM_TRANSIENT_FOR] destroy .t2 set result -} {{} {} .t 0 {} 0x0} +} {{} {} .t 0 {} {}} test unixWm-37.4 {TkWmDeadWindow, destroy on master should clear transient} {unix testwrapper} { catch {destroy .t2} toplevel .t2 @@ -1243,7 +1243,7 @@ test unixWm-37.4 {TkWmDeadWindow, destroy on master should clear transient} {uni destroy .t3 update list [wm transient .t2] [testprop [testwrapper .t2] WM_TRANSIENT_FOR] -} {{} 0x0} +} {{} {}} test unixWm-37.5 {Tk_WmCmd procedure, "transient" option, create master wrapper} {unix testwrapper} { catch {destroy .t2} catch {destroy .t3} diff --git a/tests/wm.test b/tests/wm.test index 215f4df..60462e8 100644 --- a/tests/wm.test +++ b/tests/wm.test @@ -7,7 +7,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: wm.test,v 1.21.2.3 2004/10/29 22:34:06 mdejong Exp $ +# RCS: @(#) $Id: wm.test,v 1.21.2.4 2005/01/14 21:09:48 jenglish Exp $ # This file tests window manager interactions that work across # platforms. Window manager tests that only work on a specific @@ -404,11 +404,11 @@ test wm-grid-1.10 {usage} { test wm-grid-1.11 {usage} { list [catch {wm grid . 13 14 -1 16} msg] $msg -} {1 {widthInc can't be < 0}} +} {1 {widthInc can't be <= 0}} test wm-grid-1.12 {usage} { list [catch {wm grid . 13 14 15 -1} msg] $msg -} {1 {heightInc can't be < 0}} +} {1 {heightInc can't be <= 0}} test wm-grid-2.1 {setting and reading values} { set result {} diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c index 6f89bc2..87c22b8 100644 --- a/unix/tkUnixWm.c +++ b/unix/tkUnixWm.c @@ -12,13 +12,12 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixWm.c,v 1.36.2.4 2004/10/27 17:34:36 dgp Exp $ + * RCS: @(#) $Id: tkUnixWm.c,v 1.36.2.5 2005/01/14 21:09:46 jenglish Exp $ */ #include "tkPort.h" #include "tkInt.h" #include "tkUnixInt.h" -#include <errno.h> /* * A data structure of the following type holds information for @@ -108,9 +107,9 @@ typedef struct TkWmInfo { * window is gridded; otherwise it isn't * gridded. */ int minWidth, minHeight; /* Minimum dimensions of window, in - * grid units, not pixels. */ + * pixels or grid units. */ int maxWidth, maxHeight; /* Maximum dimensions of window, in - * grid units, not pixels. */ + * pixels or grid units. 0 to default.*/ Tk_Window gridWin; /* Identifies the window that controls * gridding for this top-level, or NULL if * the top-level isn't currently gridded. */ @@ -131,7 +130,7 @@ typedef struct TkWmInfo { */ int width, height; /* Desired dimensions of window, specified - * in grid units. These values are + * in pixels or grid units. These values are * set by the "wm geometry" command and by * ConfigureNotify events (for when wm * resizes window). -1 means user hasn't @@ -334,7 +333,9 @@ static void UpdateCommand _ANSI_ARGS_((TkWindow *winPtr)); static void UpdateGeometryInfo _ANSI_ARGS_(( ClientData clientData)); static void UpdateHints _ANSI_ARGS_((TkWindow *winPtr)); -static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr)); +static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr, + int newWidth, int newHeight)); +static void UpdateTitle _ANSI_ARGS_((TkWindow *winPtr)); static void UpdatePhotoIcon _ANSI_ARGS_((TkWindow *winPtr)); static void UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr)); static void UpdateWmProtocols _ANSI_ARGS_((WmInfo *wmPtr)); @@ -550,13 +551,15 @@ TkWmNewWindow(winPtr) wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0; wmPtr->hints.icon_mask = None; wmPtr->hints.window_group = None; - wmPtr->minWidth = wmPtr->minHeight = 1; /* * Default the maximum dimensions to the size of the display, minus * a guess about how space is needed for window manager decorations. */ + wmPtr->gridWin = NULL; + wmPtr->minWidth = wmPtr->minHeight = 1; + wmPtr->maxWidth = wmPtr->maxHeight = 0; wmPtr->widthInc = wmPtr->heightInc = 1; wmPtr->minAspect.x = wmPtr->minAspect.y = 1; wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1; @@ -618,7 +621,6 @@ TkWmMapWindow(winPtr) { register WmInfo *wmPtr = winPtr->wmInfoPtr; XTextProperty textProp; - Tk_Uid string; if (wmPtr->flags & WM_NEVER_MAPPED) { Tcl_DString ds; @@ -640,26 +642,10 @@ TkWmMapWindow(winPtr) * window. */ - string = (wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid; - 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); + UpdateTitle(winPtr); UpdatePhotoIcon(winPtr); - if (wmPtr->iconName != NULL) { - Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); - XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, - Tcl_DStringValue(&ds)); - Tcl_DStringFree(&ds); - } - if (wmPtr->masterPtr != NULL) { /* * Don't map a transient if the master is not mapped. @@ -798,7 +784,7 @@ TkWmDeadWindow(winPtr) for (prevPtr = (WmInfo *) winPtr->dispPtr->firstWmPtr; ; prevPtr = prevPtr->nextPtr) { if (prevPtr == NULL) { - panic("couldn't unlink window in TkWmDeadWindow"); + Tcl_Panic("couldn't unlink window in TkWmDeadWindow"); } if (prevPtr->nextPtr == wmPtr) { prevPtr->nextPtr = wmPtr->nextPtr; @@ -880,8 +866,8 @@ TkWmDeadWindow(winPtr) WmWaitMapProc, (ClientData) wmPtr2->winPtr); wmPtr2->masterPtr = NULL; if (!(wmPtr2->flags & WM_NEVER_MAPPED)) { - XSetTransientForHint(wmPtr2->winPtr->display, - wmPtr2->wrapperPtr->window, None); + XDeleteProperty(winPtr->display, wmPtr2->wrapperPtr->window, + Tk_InternAtom((Tk_Window) winPtr, "WM_TRANSIENT_FOR")); /* FIXME: Need a call like Win32's UpdateWrapper() so we can recreate the wrapper and get rid of the transient window decorations. */ @@ -889,7 +875,7 @@ TkWmDeadWindow(winPtr) } } if (wmPtr->numTransients != 0) - panic("numTransients should be 0"); + Tcl_Panic("numTransients should be 0"); if (wmPtr->masterPtr != NULL) { wmPtr2 = wmPtr->masterPtr->wmInfoPtr; @@ -1748,12 +1734,12 @@ WmGridCmd(tkwin, winPtr, interp, objc, objv) Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC); return TCL_ERROR; } - if (widthInc < 0) { - Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC); + if (widthInc <= 0) { + Tcl_SetResult(interp, "widthInc can't be <= 0", TCL_STATIC); return TCL_ERROR; } - if (heightInc < 0) { - Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC); + if (heightInc <= 0) { + Tcl_SetResult(interp, "heightInc can't be <= 0", TCL_STATIC); return TCL_ERROR; } Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc, @@ -2065,12 +2051,7 @@ WmIconnameCmd(tkwin, winPtr, interp, objc, objv) wmPtr->iconName = ckalloc((unsigned) (length + 1)); strcpy(wmPtr->iconName, argv3); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { - Tcl_DString ds; - - Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); - XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, - Tcl_DStringValue(&ds)); - Tcl_DStringFree(&ds); + UpdateTitle(winPtr); } } return TCL_OK; @@ -2882,7 +2863,7 @@ WmStackorderCmd(tkwin, winPtr, interp, objc, objv) if (objc == 3) { windows = TkWmStackorderToplevel(winPtr); if (windows == NULL) { - panic("TkWmStackorderToplevel failed"); + Tcl_Panic("TkWmStackorderToplevel failed"); } else { for (window_ptr = windows; *window_ptr ; window_ptr++) { Tcl_AppendElement(interp, (*window_ptr)->pathName); @@ -2937,9 +2918,9 @@ WmStackorderCmd(tkwin, winPtr, interp, objc, objv) index2 = (window_ptr - windows); } if (index1 == -1) - panic("winPtr window not found"); + Tcl_Panic("winPtr window not found"); if (index2 == -1) - panic("winPtr2 window not found"); + Tcl_Panic("winPtr2 window not found"); ckfree((char *) windows); } @@ -3104,17 +3085,7 @@ WmTitleCmd(tkwin, winPtr, interp, objc, objv) strcpy(wmPtr->title, argv3); if (!(wmPtr->flags & WM_NEVER_MAPPED)) { - XTextProperty textProp; - Tcl_DString ds; - - 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); + UpdateTitle(winPtr); } } return TCL_OK; @@ -3250,10 +3221,13 @@ WmTransientCmd(tkwin, winPtr, interp, objc, objv) return TCL_ERROR; } } else { - Window xwin = (wmPtr->masterPtr == NULL) ? None : - wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window; - XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window, - xwin); + if (wmPtr->masterPtr != NULL) { + XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window, + wmPtr->masterPtr->wmInfoPtr->wrapperPtr->window); + } else { + XDeleteProperty(winPtr->display, wmPtr->wrapperPtr->window, + Tk_InternAtom((Tk_Window)winPtr, "WM_TRANSIENT_FOR")); + } } } return TCL_OK; @@ -3382,6 +3356,16 @@ Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc) register WmInfo *wmPtr; /* + * Ensure widthInc and heightInc are greater than 0 + */ + if (widthInc <= 0) { + widthInc = 1; + } + if (heightInc <= 0) { + heightInc = 1; + } + + /* * Find the top-level window for tkwin, plus the window manager * information. */ @@ -4124,7 +4108,7 @@ UpdateGeometryInfo(clientData) { register TkWindow *winPtr = (TkWindow *) clientData; register WmInfo *wmPtr = winPtr->wmInfoPtr; - int x, y, width, height; + int x, y, width, height, min, max; unsigned long serial; wmPtr->flags &= ~WM_UPDATE_PENDING; @@ -4135,9 +4119,10 @@ UpdateGeometryInfo(clientData) * requested depends on (a) the size requested internally * by the window's widgets, (b) the size requested by the * user in a "wm geometry" command or via wm-based interactive - * resizing (if any), and (c) whether or not the window is - * gridded. Don't permit sizes <= 0 because this upsets - * the X server. + * resizing (if any), (c) whether or not the window is + * gridded, and (d) the current min or max size for + * the toplevel. Don't permit sizes <= 0 because this + * upsets the X server. */ if (wmPtr->width == -1) { @@ -4151,6 +4136,28 @@ UpdateGeometryInfo(clientData) if (width <= 0) { width = 1; } + /* + * Account for window max/min width + */ + if (wmPtr->gridWin != NULL) { + min = winPtr->reqWidth + + (wmPtr->minWidth - wmPtr->reqGridWidth)*wmPtr->widthInc; + if (wmPtr->maxWidth > 0) { + max = winPtr->reqWidth + + (wmPtr->maxWidth - wmPtr->reqGridWidth)*wmPtr->widthInc; + } else { + max = 0; + } + } else { + min = wmPtr->minWidth; + max = wmPtr->maxWidth; + } + if (width < min) { + width = min; + } else if ((max > 0) && (width > max)) { + width = max; + } + if (wmPtr->height == -1) { height = winPtr->reqHeight; } else if (wmPtr->gridWin != NULL) { @@ -4162,6 +4169,27 @@ UpdateGeometryInfo(clientData) if (height <= 0) { height = 1; } + /* + * Account for window max/min height + */ + if (wmPtr->gridWin != NULL) { + min = winPtr->reqHeight + + (wmPtr->minHeight - wmPtr->reqGridHeight)*wmPtr->heightInc; + if (wmPtr->maxHeight > 0) { + max = winPtr->reqHeight + + (wmPtr->maxHeight - wmPtr->reqGridHeight)*wmPtr->heightInc; + } else { + max = 0; + } + } else { + min = wmPtr->minHeight; + max = wmPtr->maxHeight; + } + if (height < min) { + height = min; + } else if ((max > 0) && (height > max)) { + height = max; + } /* * Compute the new position for the upper-left pixel of the window's @@ -4198,7 +4226,7 @@ UpdateGeometryInfo(clientData) wmPtr->flags |= WM_UPDATE_SIZE_HINTS; } if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) { - UpdateSizeHints(winPtr); + UpdateSizeHints(winPtr, width, height); } /* @@ -4332,8 +4360,10 @@ UpdateGeometryInfo(clientData) */ static void -UpdateSizeHints(winPtr) +UpdateSizeHints(winPtr, newWidth, newHeight) TkWindow *winPtr; + int newWidth; + int newHeight; { register WmInfo *wmPtr = winPtr->wmInfoPtr; XSizeHints *hintsPtr; @@ -4395,22 +4425,13 @@ UpdateSizeHints(winPtr) */ if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) { - if (wmPtr->width >= 0) { - hintsPtr->min_width = wmPtr->width; - } else { - hintsPtr->min_width = winPtr->reqWidth; - } - hintsPtr->max_width = hintsPtr->min_width; - hintsPtr->flags |= PMaxSize; + hintsPtr->max_width = hintsPtr->min_width = newWidth; + hintsPtr->flags |= PMaxSize; } if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) { - if (wmPtr->height >= 0) { - hintsPtr->min_height = wmPtr->height; - } else { - hintsPtr->min_height = winPtr->reqHeight + wmPtr->menuHeight; - } - hintsPtr->max_height = hintsPtr->min_height; - hintsPtr->flags |= PMaxSize; + hintsPtr->max_height = hintsPtr->min_height = + newHeight + wmPtr->menuHeight; + hintsPtr->flags |= PMaxSize; } XSetWMNormalHints(winPtr->display, wmPtr->wrapperPtr->window, hintsPtr); @@ -4421,6 +4442,69 @@ UpdateSizeHints(winPtr) /* *-------------------------------------------------------------- * + * UpdateTitle -- + * + * This procedure is called to update the window title and + * icon name. It sets the ICCCM-defined properties WM_NAME + * and WM_ICON_NAME for older window managers, and the + * freedesktop.org-defined _NET_WM_NAME and _NET_WM_ICON_NAME + * properties for newer ones. The ICCCM properties are + * stored in the system encoding, the newer properties + * are stored in UTF-8. + * + * NOTE: the ICCCM specifies that WM_NAME and WM_ICON_NAME are + * stored in ISO-Latin-1. Tk has historically used the default + * system encoding (since 8.1). It's not clear whether this is + * correct or not. + * + * Side effects: + * Properties get changed for winPtr. + * + *-------------------------------------------------------------- + */ +static void +UpdateTitle(winPtr) + TkWindow *winPtr; +{ + WmInfo *wmPtr = winPtr->wmInfoPtr; + Atom XA_UTF8_STRING = Tk_InternAtom((Tk_Window) winPtr, "UTF8_STRING"); + const char *string; + Tcl_DString ds; + + /* + * Set window title: + */ + string = (wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid; + Tcl_UtfToExternalDString(NULL, string, -1, &ds); + XStoreName(winPtr->display, wmPtr->wrapperPtr->window, + Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); + + XChangeProperty(winPtr->display, wmPtr->wrapperPtr->window, + Tk_InternAtom((Tk_Window) winPtr, "_NET_WM_NAME"), + XA_UTF8_STRING, 8, PropModeReplace, + (const unsigned char*)string, (signed int)strlen(string)); + + /* + * Set icon name: + */ + if (wmPtr->iconName != NULL) { + Tcl_UtfToExternalDString(NULL, wmPtr->iconName, -1, &ds); + XSetIconName(winPtr->display, wmPtr->wrapperPtr->window, + Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); + + XChangeProperty(winPtr->display, wmPtr->wrapperPtr->window, + Tk_InternAtom((Tk_Window) winPtr, "_NET_WM_ICON_NAME"), + XA_UTF8_STRING, 8, PropModeReplace, + (const unsigned char*)wmPtr->iconName, + (signed int)strlen(wmPtr->iconName)); + } +} + +/* + *-------------------------------------------------------------- + * * UpdatePhotoIcon -- * * This procedure is called to update the window ohoto icon. @@ -4589,7 +4673,7 @@ WaitForEvent(display, wmInfoPtr, type, eventPtr) oldRestrictProc = Tk_RestrictEvents(WaitRestrictProc, (ClientData) &info, &oldRestrictData); - TclpGetTime(&timeout); + Tcl_GetTime(&timeout); timeout.sec += 2; while (!info.foundEvent) { @@ -5353,7 +5437,7 @@ Tk_MoveToplevelWindow(tkwin, x, y) register WmInfo *wmPtr = winPtr->wmInfoPtr; if (!(winPtr->flags & TK_TOP_LEVEL)) { - panic("Tk_MoveToplevelWindow called with non-toplevel window"); + Tcl_Panic("Tk_MoveToplevelWindow called with non-toplevel window"); } wmPtr->x = x; wmPtr->y = y; @@ -5633,7 +5717,7 @@ TkWmStackorderToplevel(parentPtr) } } if ((window_ptr - windows) != table.numEntries) - panic("num matched toplevel windows does not equal num children"); + Tcl_Panic("num matched toplevel windows does not equal num children"); *window_ptr = NULL; if (numChildren) { XFree((char *) children); @@ -6278,7 +6362,7 @@ TkUnixSetMenubar(tkwin, menubar) } else { if ((menubarPtr->flags & TK_TOP_LEVEL) || (Tk_Screen(menubar) != Tk_Screen(tkwin))) { - panic("TkUnixSetMenubar got bad menubar"); + Tcl_Panic("TkUnixSetMenubar got bad menubar"); } wmPtr->menuHeight = Tk_ReqHeight(menubar); if (wmPtr->menuHeight == 0) { |