From 5bd07d431b00b86e30e2e0386df0b35132e0fe15 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 29 Aug 2024 22:11:29 +0000 Subject: [PATCH] Make a start with [610a73a179]: Canvas widget handles pixel objects incorrectly in Tk 9.0. WIP --- generic/tk.h | 2 +- generic/tkCanvArc.c | 2 +- generic/tkCanvLine.c | 2 +- generic/tkCanvPoly.c | 3 +-- generic/tkCanvUtil.c | 32 ++++++++++++++++++++------ generic/tkCanvas.c | 53 ++++++++++++++++++++++++++++--------------- generic/tkCanvas.h | 4 ++-- generic/tkOldConfig.c | 36 ++++++++++++++++++++++++++++- generic/tkRectOval.c | 4 ++-- tests/canvas.test | 2 +- 10 files changed, 104 insertions(+), 36 deletions(-) diff --git a/generic/tk.h b/generic/tk.h index ae4506a6a..01a08dced 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -1193,7 +1193,7 @@ typedef struct Tk_Outline { double width; /* Width of outline. */ double activeWidth; /* Width of outline. */ double disabledWidth; /* Width of outline. */ - int offset; /* Dash offset. */ + Tcl_Obj *offsetObj; /* Dash offset. */ Tk_Dash dash; /* Dash pattern. */ Tk_Dash activeDash; /* Dash pattern if state is active. */ Tk_Dash disabledDash; /* Dash pattern if state is disabled. */ diff --git a/generic/tkCanvArc.c b/generic/tkCanvArc.c index 82bf4394e..8a873b884 100644 --- a/generic/tkCanvArc.c +++ b/generic/tkCanvArc.c @@ -130,7 +130,7 @@ static const Tk_ConfigSpec configSpecs[] = { NULL, offsetof(ArcItem, outline.dash), TK_CONFIG_NULL_OK, &dashOption}, {TK_CONFIG_PIXELS, "-dashoffset", NULL, NULL, - "0", offsetof(ArcItem, outline.offset), TK_CONFIG_DONT_SET_DEFAULT, NULL}, + "0", offsetof(ArcItem, outline.offsetObj), TK_CONFIG_OBJS, NULL}, {TK_CONFIG_CUSTOM, "-disableddash", NULL, NULL, NULL, offsetof(ArcItem, outline.disabledDash), TK_CONFIG_NULL_OK, &dashOption}, diff --git a/generic/tkCanvLine.c b/generic/tkCanvLine.c index 311938566..7c01d9f5b 100644 --- a/generic/tkCanvLine.c +++ b/generic/tkCanvLine.c @@ -187,7 +187,7 @@ static const Tk_ConfigSpec configSpecs[] = { NULL, offsetof(LineItem, outline.dash), TK_CONFIG_NULL_OK, &dashOption}, {TK_CONFIG_PIXELS, "-dashoffset", NULL, NULL, - "0", offsetof(LineItem, outline.offset), TK_CONFIG_DONT_SET_DEFAULT, NULL}, + "0", offsetof(LineItem, outline.offsetObj), TK_CONFIG_OBJS, NULL}, {TK_CONFIG_CUSTOM, "-disableddash", NULL, NULL, NULL, offsetof(LineItem, outline.disabledDash), TK_CONFIG_NULL_OK, &dashOption}, diff --git a/generic/tkCanvPoly.c b/generic/tkCanvPoly.c index c018d08eb..dfb0c75a4 100644 --- a/generic/tkCanvPoly.c +++ b/generic/tkCanvPoly.c @@ -95,8 +95,7 @@ static const Tk_ConfigSpec configSpecs[] = { NULL, offsetof(PolygonItem, outline.dash), TK_CONFIG_NULL_OK, &dashOption}, {TK_CONFIG_PIXELS, "-dashoffset", NULL, NULL, - "0", offsetof(PolygonItem, outline.offset), - TK_CONFIG_DONT_SET_DEFAULT, NULL}, + "0", offsetof(PolygonItem, outline.offsetObj), TK_CONFIG_OBJS, NULL}, {TK_CONFIG_CUSTOM, "-disableddash", NULL, NULL, NULL, offsetof(PolygonItem, outline.disabledDash), TK_CONFIG_NULL_OK, &dashOption}, diff --git a/generic/tkCanvUtil.c b/generic/tkCanvUtil.c index 252bfb84a..e97cd9822 100644 --- a/generic/tkCanvUtil.c +++ b/generic/tkCanvUtil.c @@ -970,7 +970,7 @@ Tk_CreateOutline( outline->width = 1.0; outline->activeWidth = 0.0; outline->disabledWidth = 0.0; - outline->offset = 0; + outline->offsetObj = NULL; outline->dash.number = 0; outline->activeDash.number = 0; outline->disabledDash.number = 0; @@ -1140,7 +1140,10 @@ Tk_ConfigOutlineGC( } if (mask && (dash->number != 0)) { gcValues->line_style = LineOnOffDash; - gcValues->dash_offset = outline->offset; + if (!outline->offsetObj || Tk_GetPixelsFromObj(NULL, Canvas(canvas)->tkwin, + outline->offsetObj, &gcValues->dash_offset) != TCL_OK) { + gcValues->dash_offset = 0; + } if ((unsigned int)ABS(dash->number) > sizeof(char *)) { gcValues->dashes = dash->pattern.pt[0]; } else if (dash->number != 0) { @@ -1183,11 +1186,16 @@ Tk_ChangeOutlineGC( XColor *color; Pixmap stipple; Tk_State state = item->state; + int offset; width = outline->width; if (width < 1.0) { width = 1.0; } + if (!outline->offsetObj || Tk_GetPixelsFromObj(NULL, Canvas(canvas)->tkwin, + outline->offsetObj, &offset) != TCL_OK) { + offset = 0; + } dash = &(outline->dash); color = outline->color; stipple = outline->stipple; @@ -1233,13 +1241,13 @@ Tk_ChangeOutlineGC( p = (i > (int)sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; q = (char *)ckalloc(2 * i); i = DashConvert(q, p, i, width); - XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, q,i); + XSetDashes(Canvas(canvas)->display, outline->gc, offset, q,i); ckfree(q); } else if (dash->number>2 || (dash->number==2 && (dash->pattern.array[0]!=dash->pattern.array[1]))) { p = (dash->number > (int) sizeof(char *)) ? dash->pattern.pt : dash->pattern.array; - XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, p, + XSetDashes(Canvas(canvas)->display, outline->gc, offset, p, dash->number); } if (stipple!=None) { @@ -1301,11 +1309,16 @@ Tk_ResetOutlineGC( XColor *color; Pixmap stipple; Tk_State state = item->state; + int offset; width = outline->width; if (width < 1.0) { width = 1.0; } + if (!outline->offsetObj || Tk_GetPixelsFromObj(NULL, Canvas(canvas)->tkwin, + outline->offsetObj, &offset) != TCL_OK) { + offset = 0; + } dash = &(outline->dash); color = outline->color; stipple = outline->stipple; @@ -1353,7 +1366,7 @@ Tk_ResetOutlineGC( } else { dashList = (char) (4 * width + 0.5); } - XSetDashes(Canvas(canvas)->display, outline->gc, outline->offset, + XSetDashes(Canvas(canvas)->display, outline->gc, offset, &dashList , 1); } if (stipple != None) { @@ -1397,6 +1410,7 @@ Tk_CanvasPsOutline( Pixmap stipple = outline->stipple; Tk_State state = item->state; Tcl_Obj *psObj = GetPostscriptBuffer(interp); + int offset; if (state == TK_STATE_NULL) { state = Canvas(canvas)->canvas_state; @@ -1430,6 +1444,10 @@ Tk_CanvasPsOutline( } } + if (!outline->offsetObj || Tk_GetPixelsFromObj(NULL, Canvas(canvas)->tkwin, + outline->offsetObj, &offset) != TCL_OK) { + offset = 0; + } Tcl_AppendPrintfToObj(psObj, "%.15g setlinewidth\n", width); ptr = ((unsigned) ABS(dash->number) > sizeof(char *)) ? @@ -1449,7 +1467,7 @@ Tk_CanvasPsOutline( Tcl_AppendObjToObj(psObj, converted); } Tcl_DecrRefCount(converted); - Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", outline->offset); + Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", offset); } else if (dash->number < 0) { if (dash->number < -5) { lptr = (char *)ckalloc(1 - 2*dash->number); @@ -1462,7 +1480,7 @@ Tk_CanvasPsOutline( for (; --i>0 ;) { Tcl_AppendPrintfToObj(psObj, " %d", *p++ & 0xff); } - Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", outline->offset); + Tcl_AppendPrintfToObj(psObj, "] %d setdash\n", offset); } else { Tcl_AppendToObj(psObj, "] 0 setdash\n", TCL_INDEX_NONE); } diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 4b6793959..d8b3ec9e1 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -101,7 +101,7 @@ static const Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_SYNONYM, "-bd", "borderWidth", NULL, NULL, 0, 0, NULL}, {TK_CONFIG_SYNONYM, "-bg", "background", NULL, NULL, 0, 0, NULL}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", - DEF_CANVAS_BORDER_WIDTH, offsetof(TkCanvas, borderWidth), 0, NULL}, + DEF_CANVAS_BORDER_WIDTH, offsetof(TkCanvas, borderWidthObj), TK_CONFIG_OBJS, NULL}, {TK_CONFIG_DOUBLE, "-closeenough", "closeEnough", "CloseEnough", DEF_CANVAS_CLOSE_ENOUGH, offsetof(TkCanvas, closeEnough), 0, NULL}, {TK_CONFIG_BOOLEAN, "-confine", "confine", "Confine", @@ -117,7 +117,7 @@ static const Tk_ConfigSpec configSpecs[] = { DEF_CANVAS_HIGHLIGHT, offsetof(TkCanvas, highlightColorPtr), 0, NULL}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", - DEF_CANVAS_HIGHLIGHT_WIDTH, offsetof(TkCanvas, highlightWidth), 0, NULL}, + DEF_CANVAS_HIGHLIGHT_WIDTH, offsetof(TkCanvas, highlightWidthObj), TK_CONFIG_OBJS, NULL}, {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground", DEF_CANVAS_INSERT_BG, offsetof(TkCanvas, textInfo.insertBorder), 0, NULL}, {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth", @@ -678,10 +678,10 @@ Tk_CanvasObjCmd( CanvasCmdDeletedProc); canvasPtr->firstItemPtr = NULL; canvasPtr->lastItemPtr = NULL; - canvasPtr->borderWidth = 0; + canvasPtr->borderWidthObj = NULL; canvasPtr->bgBorder = NULL; canvasPtr->relief = TK_RELIEF_FLAT; - canvasPtr->highlightWidth = 0; + canvasPtr->highlightWidthObj = NULL; canvasPtr->highlightBgColorPtr = NULL; canvasPtr->highlightColorPtr = NULL; canvasPtr->inset = 0; @@ -2259,6 +2259,7 @@ ConfigureCanvas( XGCValues gcValues; GC newGC; Tk_State old_canvas_state=canvasPtr->canvas_state; + int borderWidth, highlightWidth; if (Tk_ConfigureWidget(interp, canvasPtr->tkwin, configSpecs, objc, objv, canvasPtr, @@ -2273,10 +2274,21 @@ ConfigureCanvas( Tk_SetBackgroundFromBorder(canvasPtr->tkwin, canvasPtr->bgBorder); - if (canvasPtr->highlightWidth < 0) { - canvasPtr->highlightWidth = 0; + Tk_GetPixelsFromObj(NULL, canvasPtr->tkwin, canvasPtr->borderWidthObj, &borderWidth); + Tk_GetPixelsFromObj(NULL, canvasPtr->tkwin, canvasPtr->highlightWidthObj, &highlightWidth); + if (borderWidth < 0) { + borderWidth = 0; + Tcl_DecrRefCount(canvasPtr->borderWidthObj); + canvasPtr->borderWidthObj = Tcl_NewIntObj(0); + Tcl_IncrRefCount(canvasPtr->borderWidthObj); } - canvasPtr->inset = canvasPtr->borderWidth + canvasPtr->highlightWidth; + if (highlightWidth < 0) { + highlightWidth = 0; + Tcl_DecrRefCount(canvasPtr->highlightWidthObj); + canvasPtr->highlightWidthObj = Tcl_NewIntObj(0); + Tcl_IncrRefCount(canvasPtr->highlightWidthObj); + } + canvasPtr->inset = borderWidth + highlightWidth; gcValues.function = GXcopy; gcValues.graphics_exposures = False; @@ -2992,6 +3004,7 @@ DisplayCanvas( Tk_Item *itemPtr; Pixmap pixmap; int screenX1, screenX2, screenY1, screenY2, width, height; + int borderWidth, highlightWidth; if (canvasPtr->tkwin == NULL) { return; @@ -3169,17 +3182,18 @@ DisplayCanvas( */ borders: + Tk_GetPixelsFromObj(NULL, canvasPtr->tkwin, canvasPtr->borderWidthObj, &borderWidth); + Tk_GetPixelsFromObj(NULL, canvasPtr->tkwin, canvasPtr->highlightWidthObj, &highlightWidth); if (canvasPtr->flags & REDRAW_BORDERS) { canvasPtr->flags &= ~REDRAW_BORDERS; - if (canvasPtr->borderWidth > 0) { + if (borderWidth > 0) { Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), - canvasPtr->bgBorder, canvasPtr->highlightWidth, - canvasPtr->highlightWidth, - Tk_Width(tkwin) - 2*canvasPtr->highlightWidth, - Tk_Height(tkwin) - 2*canvasPtr->highlightWidth, - canvasPtr->borderWidth, canvasPtr->relief); + canvasPtr->bgBorder, highlightWidth, highlightWidth, + Tk_Width(tkwin) - 2 * highlightWidth, + Tk_Height(tkwin) - 2 * highlightWidth, + borderWidth, canvasPtr->relief); } - if (canvasPtr->highlightWidth > 0) { + if (highlightWidth > 0) { GC fgGC, bgGC; bgGC = Tk_GCForColor(canvasPtr->highlightBgColorPtr, @@ -3188,10 +3202,10 @@ DisplayCanvas( fgGC = Tk_GCForColor(canvasPtr->highlightColorPtr, Tk_WindowId(tkwin)); Tk_DrawHighlightBorder(tkwin, fgGC, bgGC, - canvasPtr->highlightWidth, Tk_WindowId(tkwin)); + highlightWidth, Tk_WindowId(tkwin)); } else { Tk_DrawHighlightBorder(tkwin, bgGC, bgGC, - canvasPtr->highlightWidth, Tk_WindowId(tkwin)); + highlightWidth, Tk_WindowId(tkwin)); } } } @@ -5565,7 +5579,9 @@ CanvasFocusProc( int gotFocus) /* 1 means window is getting focus, 0 means * it's losing it. */ { - Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); + int highlightWidth; + + Tcl_DeleteTimerHandler(canvasPtr->insertBlinkHandler); if (gotFocus) { canvasPtr->textInfo.gotFocus = 1; canvasPtr->textInfo.cursorOn = 1; @@ -5579,7 +5595,8 @@ CanvasFocusProc( canvasPtr->insertBlinkHandler = NULL; } EventuallyRedrawItem(canvasPtr, canvasPtr->textInfo.focusItemPtr); - if (canvasPtr->highlightWidth > 0) { + Tk_GetPixelsFromObj(NULL, canvasPtr->tkwin, canvasPtr->highlightWidthObj, &highlightWidth); + if (highlightWidth > 0) { canvasPtr->flags |= REDRAW_BORDERS; if (!(canvasPtr->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(DisplayCanvas, canvasPtr); diff --git a/generic/tkCanvas.h b/generic/tkCanvas.h index 9e5b52b2c..0babf3607 100644 --- a/generic/tkCanvas.h +++ b/generic/tkCanvas.h @@ -60,11 +60,11 @@ typedef struct TkCanvas { * Information used when displaying widget: */ - int borderWidth; /* Width of 3-D border around window. */ + Tcl_Obj *borderWidthObj; /* Width of 3-D border around window. */ Tk_3DBorder bgBorder; /* Used for canvas background. */ int relief; /* Indicates whether window as a whole is * raised, sunken, or flat. */ - int highlightWidth; /* Width in pixels of highlight to draw around + Tcl_Obj *highlightWidthObj; /* Width in pixels of highlight to draw around * widget when it has the focus. <= 0 means * don't draw a highlight. */ XColor *highlightBgColorPtr; diff --git a/generic/tkOldConfig.c b/generic/tkOldConfig.c index e51cef20c..4ddc99e5e 100644 --- a/generic/tkOldConfig.c +++ b/generic/tkOldConfig.c @@ -351,6 +351,11 @@ DoConfig( nullValue = 1; } + if ((specPtr->specFlags & TK_CONFIG_OBJS) && (specPtr->type != TK_CONFIG_PIXELS)) { + /* Prevent surprises for other options than TK_CONFIG_PIXELS */ + Tcl_AppendResult(interp, "TK_CONFIG_OBJS not supported", (char *)NULL); + return TCL_ERROR; + } do { if (specPtr->offset < 0) { break; @@ -512,7 +517,24 @@ DoConfig( } break; case TK_CONFIG_PIXELS: - if (nullValue) { + if (specPtr->specFlags & TK_CONFIG_OBJS) { + int dummy; + if (nullValue) { + if (*(Tcl_Obj **)ptr != NULL) { + Tcl_DecrRefCount(*(Tcl_Obj **)ptr); + *(Tcl_Obj **)ptr = NULL; + } + } else if (Tk_GetPixelsFromObj(interp, tkwin, arg, &dummy) + != TCL_OK) { + return TCL_ERROR; + } else { + if (*(Tcl_Obj **)ptr != NULL) { + Tcl_DecrRefCount(*(Tcl_Obj **)ptr); + } + *(Tcl_Obj **)ptr = arg; + Tcl_IncrRefCount(*(Tcl_Obj **)ptr); + } + } else if (nullValue) { *(int *)ptr = INT_MIN; } else if (Tk_GetPixelsFromObj(interp, tkwin, arg, (int *)ptr) != TCL_OK) { @@ -766,6 +788,12 @@ FormatConfigValue( } ptr = (char *)widgRec + specPtr->offset; result = ""; + if (specPtr->specFlags & TK_CONFIG_OBJS) { + if (*(Tcl_Obj **)ptr != NULL) { + result = Tcl_GetString(*((Tcl_Obj **)ptr)); + } + return result; + } switch (specPtr->type) { case TK_CONFIG_BOOLEAN: if (*((int *)ptr) == 0) { @@ -1020,6 +1048,12 @@ Tk_FreeOptions( *((Tk_3DBorder *) ptr) = NULL; } break; + case TK_CONFIG_PIXELS: + if ((specPtr->specFlags & TK_CONFIG_OBJS) && (*((Tcl_Obj **)ptr) != NULL)) { + Tcl_DecrRefCount(*((Tcl_Obj **)ptr)); + *((Tcl_Obj **)ptr) = NULL; + } + break; case TK_CONFIG_CURSOR: case TK_CONFIG_ACTIVE_CURSOR: if (*((Tk_Cursor *) ptr) != NULL) { diff --git a/generic/tkRectOval.c b/generic/tkRectOval.c index a228f88a7..8f2e38500 100644 --- a/generic/tkRectOval.c +++ b/generic/tkRectOval.c @@ -79,8 +79,8 @@ static const Tk_ConfigSpec configSpecs[] = { NULL, offsetof(RectOvalItem, outline.dash), TK_CONFIG_NULL_OK, &dashOption}, {TK_CONFIG_PIXELS, "-dashoffset", NULL, NULL, - "0", offsetof(RectOvalItem, outline.offset), - TK_CONFIG_DONT_SET_DEFAULT, NULL}, + "0", offsetof(RectOvalItem, outline.offsetObj), + TK_CONFIG_OBJS, NULL}, {TK_CONFIG_CUSTOM, "-disableddash", NULL, NULL, NULL, offsetof(RectOvalItem, outline.disabledDash), TK_CONFIG_NULL_OK, &dashOption}, diff --git a/tests/canvas.test b/tests/canvas.test index 7b1e88353..de7d3c52f 100644 --- a/tests/canvas.test +++ b/tests/canvas.test @@ -44,7 +44,7 @@ test canvas-1.6 {configuration options: bad value for "bd"} -body { test canvas-1.7 {configuration options: good value for "borderwidth"} -body { .c configure -borderwidth 1.3 .c cget -borderwidth -} -result 1 +} -result 1.3 test canvas-1.8 {configuration options: bad value for "borderwidth"} -body { .c configure -borderwidth badValue } -returnCodes error -result {expected screen distance but got "badValue"}