From 2b61fda7660e28461b6dfe55f422c70aa390483d Mon Sep 17 00:00:00 2001 From: pspjuth Date: Wed, 19 Aug 2009 23:01:59 +0000 Subject: Give an error if grid and pack are used in the same master. [Patch 2475855] --- ChangeLog | 13 +++ generic/tk.h | 3 +- generic/tkGeometry.c | 81 ++++++++++++++++++- generic/tkGrid.c | 49 ++++++++++- generic/tkInt.h | 8 +- generic/tkPack.c | 49 ++++++++++- generic/tkWindow.c | 7 +- tests/grid.test | 4 +- tests/packgrid.test | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++ tests/textIndex.test | 4 +- 10 files changed, 431 insertions(+), 10 deletions(-) create mode 100644 tests/packgrid.test diff --git a/ChangeLog b/ChangeLog index 5b08e80..a60818b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2009-08-19 Peter Spjuth + + * generic/tk.h + * generic/tkGeometry.c + * generic/tkGrid.c + * generic/tkInt.h + * generic/tkPack.c + * generic/tkWindow.c + * tests/grid.test + * tests/packgrid.test + * tests/textIndex.test: Give an error if grid and pack are used in the + same master. [Patch 2475855] + 2009-08-14 Daniel Steffen * macosx/tkMacOSXDraw.c: Avoid exception in XCopyArea() when copying diff --git a/generic/tk.h b/generic/tk.h index 0ebd36b..167da5a 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tk.h,v 1.130 2009/06/29 14:35:01 das Exp $ + * RCS: @(#) $Id: tk.h,v 1.131 2009/08/19 23:02:00 pspjuth Exp $ */ #ifndef _TK @@ -791,6 +791,7 @@ typedef struct Tk_FakeWin { int internalBorderBottom; int minReqWidth; int minReqHeight; + char *dummy20; /* geometryMaster */ } Tk_FakeWin; /* diff --git a/generic/tkGeometry.c b/generic/tkGeometry.c index 53bd140..b5a1654 100644 --- a/generic/tkGeometry.c +++ b/generic/tkGeometry.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkGeometry.c,v 1.14 2008/11/08 18:44:40 dkf Exp $ + * RCS: @(#) $Id: tkGeometry.c,v 1.15 2009/08/19 23:02:00 pspjuth Exp $ */ #include "tkInt.h" @@ -306,6 +306,85 @@ Tk_SetMinimumRequestSize( /* *---------------------------------------------------------------------- * + * TkSetGeometryMaster -- + * + * Set a geometry master for this window. Only one master may own + * a window at any time. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * The geometry master is recorded for the window. + * + *---------------------------------------------------------------------- + */ + +int +TkSetGeometryMaster( + Tcl_Interp *interp, /* Current interpreter, for error. */ + Tk_Window tkwin, /* Window that will have geometry master set. */ + const char *master) /* The master identity. */ +{ + register TkWindow *winPtr = (TkWindow *) tkwin; + + if (winPtr->geometryMaster != NULL && + strcmp(winPtr->geometryMaster, master) == 0) { + return TCL_OK; + } + if (winPtr->geometryMaster != NULL) { + if (interp != NULL) { + Tcl_AppendResult(interp, "cannot use geometry manager ", master, + " inside ", Tk_PathName(tkwin), + " which already has slaves managed by ", + winPtr->geometryMaster, NULL); + } + return TCL_ERROR; + } + + winPtr->geometryMaster = ckalloc(strlen(master) + 1); + strcpy(winPtr->geometryMaster, master); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkFreeGeometryMaster -- + * + * Remove a geometry master for this window. Only one master may own + * a window at any time. + * + * Results: + * None. + * + * Side effects: + * The geometry master is cleared for the window. + * + *---------------------------------------------------------------------- + */ + +void +TkFreeGeometryMaster( + Tk_Window tkwin, /* Window that will have geometry master cleared. */ + const char *master) /* The master identity. */ +{ + register TkWindow *winPtr = (TkWindow *) tkwin; + + if (winPtr->geometryMaster != NULL && + strcmp(winPtr->geometryMaster, master) != 0) { + Tcl_Panic("Trying to free %s from geometry manager %s.", + winPtr->geometryMaster, master); + } + if (winPtr->geometryMaster != NULL) { + ckfree(winPtr->geometryMaster); + winPtr->geometryMaster = NULL; + } +} + +/* + *---------------------------------------------------------------------- + * * Tk_MaintainGeometry -- * * This procedure is invoked by geometry managers to handle slaves whose diff --git a/generic/tkGrid.c b/generic/tkGrid.c index b4392f3..6dbe9a3 100644 --- a/generic/tkGrid.c +++ b/generic/tkGrid.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkGrid.c,v 1.52 2009/02/03 23:55:47 nijtmans Exp $ + * RCS: @(#) $Id: tkGrid.c,v 1.53 2009/08/19 23:02:00 pspjuth Exp $ */ #include "tkInt.h" @@ -242,10 +242,13 @@ typedef struct UniformGroup { * size. 0 means if this window is a master then * Tk will set its requested size to fit the * needs of its slaves. + * ALLOCED_MASTER 1 means that Grid has allocated itself as + * geometry master for this window. */ #define REQUESTED_RELAYOUT 1 #define DONT_PROPAGATE 2 +#define ALLOCED_MASTER 4 /* * Prototypes for procedures used only in this file: @@ -875,8 +878,22 @@ GridPropagateCommand( old = !(masterPtr->flags & DONT_PROPAGATE); if (propagate != old) { if (propagate) { + /* + * If we have slaves, we need to register as geometry master. + */ + + if (masterPtr->slavePtr != NULL) { + if (TkSetGeometryMaster(interp, master, "grid") != TCL_OK) { + return TCL_ERROR; + } + masterPtr->flags |= ALLOCED_MASTER; + } masterPtr->flags &= ~DONT_PROPAGATE; } else { + if (masterPtr->flags & ALLOCED_MASTER) { + TkFreeGeometryMaster(master, "grid"); + masterPtr->flags &= ~ALLOCED_MASTER; + } masterPtr->flags |= DONT_PROPAGATE; } @@ -2724,6 +2741,16 @@ Unlink( SetGridSize(slavePtr->masterPtr); slavePtr->masterPtr = NULL; + + /* + * If we have emptied this master from slaves it means we are no longer + * handling it and should mark it as free. + */ + + if ((masterPtr->slavePtr == NULL) && (masterPtr->flags & ALLOCED_MASTER)) { + TkFreeGeometryMaster(masterPtr->tkwin, "grid"); + masterPtr->flags &= ~ALLOCED_MASTER; + } } /* @@ -3262,6 +3289,15 @@ ConfigureSlaves( Tk_ManageGeometry(slave, &gridMgrType, slavePtr); + if (!(masterPtr->flags & DONT_PROPAGATE)) { + if (TkSetGeometryMaster(interp, masterPtr->tkwin, "grid") + != TCL_OK) { + Tk_ManageGeometry(slave, NULL, NULL); + return TCL_ERROR; + } + masterPtr->flags |= ALLOCED_MASTER; + } + /* * Assign default position information. */ @@ -3386,6 +3422,17 @@ ConfigureSlaves( return TCL_ERROR; } SetGridSize(masterPtr); + + /* + * If we have emptied this master from slaves it means we are no longer + * handling it and should mark it as free. + */ + + if (masterPtr->slavePtr == NULL && masterPtr->flags & ALLOCED_MASTER) { + TkFreeGeometryMaster(masterPtr->tkwin, "grid"); + masterPtr->flags &= ~ALLOCED_MASTER; + } + return TCL_OK; } diff --git a/generic/tkInt.h b/generic/tkInt.h index 430d51e..958695e 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: $Id: tkInt.h,v 1.106 2009/07/02 10:34:32 patthoyts Exp $ + * RCS: $Id: tkInt.h,v 1.107 2009/08/19 23:02:00 pspjuth Exp $ */ #ifndef _TKINT @@ -851,6 +851,7 @@ typedef struct TkWindow { int minReqWidth; /* Minimum requested width. */ int minReqHeight; /* Minimum requested height. */ + char *geometryMaster; } TkWindow; /* @@ -1164,6 +1165,11 @@ MODULE_SCOPE int Tk_WmObjCmd(ClientData clientData, Tcl_Interp *interp, MODULE_SCOPE int Tk_GetDoublePixelsFromObj(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, double *doublePtr); +MODULE_SCOPE int TkSetGeometryMaster(Tcl_Interp *interp, + Tk_Window tkwin, const char *master); +MODULE_SCOPE void TkFreeGeometryMaster(Tk_Window tkwin, + const char *master); + MODULE_SCOPE void TkEventInit(void); MODULE_SCOPE void TkRegisterObjTypes(void); MODULE_SCOPE int TkCreateMenuCmd(Tcl_Interp *interp); diff --git a/generic/tkPack.c b/generic/tkPack.c index 334afdb..c113e6f 100644 --- a/generic/tkPack.c +++ b/generic/tkPack.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkPack.c,v 1.33 2009/02/03 23:55:47 nijtmans Exp $ + * RCS: @(#) $Id: tkPack.c,v 1.34 2009/08/19 23:02:00 pspjuth Exp $ */ #include "tkInt.h" @@ -89,6 +89,8 @@ typedef struct Packer { * size. 0 means if this window is a master then * Tk will set its requested size to fit the * needs of its slaves. + * ALLOCED_MASTER 1 means that Pack has allocated itself as + * geometry master for this window. */ #define REQUESTED_REPACK 1 @@ -97,6 +99,7 @@ typedef struct Packer { #define EXPAND 8 #define OLD_STYLE 16 #define DONT_PROPAGATE 32 +#define ALLOCED_MASTER 64 /* * The following structure is the official type record for the packer: @@ -385,6 +388,16 @@ Tk_PackObjCmd( return TCL_ERROR; } if (propagate) { + /* + * If we have slaves, we need to register as geometry master. + */ + + if (masterPtr->slavePtr != NULL) { + if (TkSetGeometryMaster(interp, master, "pack") != TCL_OK) { + return TCL_ERROR; + } + masterPtr->flags |= ALLOCED_MASTER; + } masterPtr->flags &= ~DONT_PROPAGATE; /* @@ -400,6 +413,10 @@ Tk_PackObjCmd( Tcl_DoWhenIdle(ArrangePacking, masterPtr); } } else { + if (masterPtr->flags & ALLOCED_MASTER) { + TkFreeGeometryMaster(master, "pack"); + masterPtr->flags &= ~ALLOCED_MASTER; + } masterPtr->flags |= DONT_PROPAGATE; } break; @@ -1239,6 +1256,15 @@ PackAfter( prevPtr->nextPtr = packPtr; } Tk_ManageGeometry(tkwin, &packerType, packPtr); + + if (!(masterPtr->flags & DONT_PROPAGATE)) { + if (TkSetGeometryMaster(interp, masterPtr->tkwin, "pack") + != TCL_OK) { + Tk_ManageGeometry(tkwin, NULL, NULL); + return TCL_ERROR; + } + masterPtr->flags |= ALLOCED_MASTER; + } } } @@ -1304,6 +1330,17 @@ Unlink( } packPtr->masterPtr = NULL; + + /* + * If we have emptied this master from slaves it means we are no longer + * handling it and should mark it as free. + */ + + if (masterPtr->slavePtr == NULL && masterPtr->flags & ALLOCED_MASTER) { + TkFreeGeometryMaster(masterPtr->tkwin, "pack"); + masterPtr->flags &= ~ALLOCED_MASTER; + } + } /* @@ -1740,6 +1777,7 @@ ConfigureSlaves( } Unlink(slavePtr); } + slavePtr->masterPtr = masterPtr; if (prevPtr == NULL) { slavePtr->nextPtr = masterPtr->slavePtr; @@ -1751,6 +1789,15 @@ ConfigureSlaves( Tk_ManageGeometry(slave, &packerType, slavePtr); prevPtr = slavePtr; + if (!(masterPtr->flags & DONT_PROPAGATE)) { + if (TkSetGeometryMaster(interp, masterPtr->tkwin, "pack") + != TCL_OK) { + Tk_ManageGeometry(slave, NULL, NULL); + return TCL_ERROR; + } + masterPtr->flags |= ALLOCED_MASTER; + } + /* * Arrange for the master to be re-packed at the first idle moment. */ diff --git a/generic/tkWindow.c b/generic/tkWindow.c index 8c2d435..70c8472 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWindow.c,v 1.103 2009/02/27 23:04:39 patthoyts Exp $ + * RCS: @(#) $Id: tkWindow.c,v 1.104 2009/08/19 23:02:00 pspjuth Exp $ */ #include "tkInt.h" @@ -709,6 +709,7 @@ TkAllocWindow( winPtr->internalBorderBottom = 0; winPtr->minReqWidth = 0; winPtr->minReqHeight = 0; + winPtr->geometryMaster = NULL; return winPtr; } @@ -1485,6 +1486,10 @@ Tk_DestroyWindow( TkOptionDeadWindow(winPtr); TkSelDeadWindow(winPtr); TkGrabDeadWindow(winPtr); + if (winPtr->geometryMaster != NULL) { + ckfree(winPtr->geometryMaster); + winPtr->geometryMaster = NULL; + } if (winPtr->mainPtr != NULL) { if (winPtr->pathName != NULL) { Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable, diff --git a/tests/grid.test b/tests/grid.test index bb89096..62e4eb3 100644 --- a/tests/grid.test +++ b/tests/grid.test @@ -5,7 +5,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: grid.test,v 1.34 2008/08/27 18:08:02 pspjuth Exp $ +# RCS: @(#) $Id: grid.test,v 1.35 2009/08/19 23:02:00 pspjuth Exp $ package require tcltest 2.2 eval tcltest::configure $argv @@ -1483,7 +1483,7 @@ test grid-15.2 {lost slave} -body { button .b grid .b -in .f set a [grid slaves .f] - pack .b + pack .b -in .f lappend a [grid slaves .f] grid .b -in .f lappend a [grid slaves .f] diff --git a/tests/packgrid.test b/tests/packgrid.test new file mode 100644 index 0000000..cbbb6f0 --- /dev/null +++ b/tests/packgrid.test @@ -0,0 +1,223 @@ +# This file is a Tcl script to test out interaction between Tk's "pack" and +# "grid" commands. +# It is organized in the standard fashion for Tcl tests. +# +# Copyright (c) 2008 Peter Spjuth +# All rights reserved. +# +# RCS: @(#) $Id: packgrid.test,v 1.1 2009/08/19 23:02:00 pspjuth Exp $ +# + +package require tcltest 2.2 +eval tcltest::configure $argv +tcltest::loadTestedCommands +namespace import -force tcltest::* + +test packgrid-1.1 {pack and grid in same master} -setup { + grid propagate . true + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Basic conflict + grid .g + pack .p +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager pack inside . which already has slaves managed by grid} + +test packgrid-1.2 {pack and grid in same master} -setup { + grid propagate . true + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Basic conflict + pack .p + grid .g +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager grid inside . which already has slaves managed by pack} + +test packgrid-1.3 {pack and grid in same master} -setup { + grid propagate . false + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Ok if one is non-propagating + grid .g + pack .p +} -cleanup { + destroy .p + destroy .g +} -result {} + +test packgrid-1.4 {pack and grid in same master} -setup { + grid propagate . false + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Ok if one is non-propagating + pack .p + grid .g +} -cleanup { + destroy .p + destroy .g +} -result {} + +test packgrid-1.5 {pack and grid in same master} -setup { + grid propagate . true + pack propagate . false + label .p -text PACK + label .g -text GRID +} -body { + # Ok if one is non-propagating + grid .g + pack .p +} -cleanup { + destroy .p + destroy .g +} -result {} + +test packgrid-1.6 {pack and grid in same master} -setup { + grid propagate . true + pack propagate . false + label .p -text PACK + label .g -text GRID +} -body { + # Ok if one is non-propagating + pack .p + grid .g +} -cleanup { + destroy .p + destroy .g +} -result {} + +test packgrid-2.1 {pack and grid in same master, change propagation} -setup { + grid propagate . false + pack propagate . true + label .p -text PACK + label .g -text GRID + pack .p + grid .g + update +} -body { + grid propagate . true +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager grid inside . which already has slaves managed by pack} + +test packgrid-2.2 {pack and grid in same master, change propagation} -setup { + grid propagate . true + pack propagate . false + label .p -text PACK + label .g -text GRID + pack .p + grid .g + update +} -body { + pack propagate . true +} -returnCodes error -cleanup { + destroy .p + update + destroy .g +} -result {cannot use geometry manager pack inside . which already has slaves managed by grid} + +test packgrid-2.3 {pack and grid in same master, change propagation} -setup { + grid propagate . false + pack propagate . false + label .p -text PACK + label .g -text GRID + pack .p + grid .g + update +} -body { + grid propagate . true + update + pack propagate . true +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager pack inside . which already has slaves managed by grid} + +test packgrid-2.4 {pack and grid in same master, change propagation} -setup { + grid propagate . false + pack propagate . false + label .p -text PACK + label .g -text GRID + pack .p + grid .g + update +} -body { + pack propagate . true + grid propagate . true +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager grid inside . which already has slaves managed by pack} + +test packgrid-3.1 {stealing slave} -setup { + grid propagate . true + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Ok to steal if the other one is emptied + grid .g + pack .g +} -cleanup { + destroy .p + destroy .g +} -result {} + +test packgrid-3.2 {stealing slave} -setup { + grid propagate . true + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Ok to steal if the other one is emptied + pack .g + grid .g +} -cleanup { + destroy .p + destroy .g +} -result {} + +test packgrid-3.3 {stealing slave} -setup { + grid propagate . true + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Not ok to steal if the other one is not emptied + grid .g + grid .p + pack .g +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager pack inside . which already has slaves managed by grid} + +test packgrid-3.4 {stealing slave} -setup { + grid propagate . true + pack propagate . true + label .p -text PACK + label .g -text GRID +} -body { + # Not ok to steal if the other one is not emptied + pack .g + pack .p + grid .g +} -returnCodes error -cleanup { + destroy .p + destroy .g +} -result {cannot use geometry manager grid inside . which already has slaves managed by pack} + +cleanupTests +return diff --git a/tests/textIndex.test b/tests/textIndex.test index 1546973..3b417d0 100644 --- a/tests/textIndex.test +++ b/tests/textIndex.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: textIndex.test,v 1.18 2005/07/18 22:12:05 vincentdarley Exp $ +# RCS: @(#) $Id: textIndex.test,v 1.19 2009/08/19 23:02:00 pspjuth Exp $ package require tcltest 2.1 eval tcltest::configure $argv @@ -784,7 +784,7 @@ test textIndex-19.12 {Display lines} { } {2.20} test textIndex-19.13 {Display lines} { - destroy .t + destroy {*}[pack slaves .] text .txt -height 1 -wrap word -yscroll ".sbar set" -width 400 scrollbar .sbar -command ".txt yview" grid .txt .sbar -sticky news -- cgit v0.12