diff options
Diffstat (limited to 'generic')
58 files changed, 1847 insertions, 721 deletions
diff --git a/generic/tk.h b/generic/tk.h index 4a655a4..9403f31 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -17,8 +17,8 @@ #define _TK #include <tcl.h> -#if (TCL_MAJOR_VERSION != 8) || (TCL_MINOR_VERSION < 6) -# error Tk 8.6 must be compiled with tcl.h from Tcl 8.6 or better +#if (TCL_MAJOR_VERSION < 8) || (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 6) +# error Tk 8.7 must be compiled with tcl.h from Tcl 8.6 or better #endif #ifndef CONST84 @@ -59,8 +59,8 @@ extern "C" { * and update the version numbers: * * library/tk.tcl (1 LOC patch) - * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch) - * win/configure.in (as above) + * unix/configure.ac (2 LOC Major, 2 LOC minor, 1 LOC patch) + * win/configure.ac (as above) * README (sections 0 and 1) * macosx/Tk-Common.xcconfig (not patchlevel) 1 LOC * win/README (not patchlevel) @@ -73,12 +73,12 @@ extern "C" { */ #define TK_MAJOR_VERSION 8 -#define TK_MINOR_VERSION 6 -#define TK_RELEASE_LEVEL TCL_FINAL_RELEASE -#define TK_RELEASE_SERIAL 4 +#define TK_MINOR_VERSION 7 +#define TK_RELEASE_LEVEL TCL_ALPHA_RELEASE +#define TK_RELEASE_SERIAL 0 -#define TK_VERSION "8.6" -#define TK_PATCH_LEVEL "8.6.4" +#define TK_VERSION "8.7" +#define TK_PATCH_LEVEL "8.7a0" /* * A special definition used to allow this header file to be included from diff --git a/generic/tkBind.c b/generic/tkBind.c index 9cd3b7b..bb95fa9 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -2868,7 +2868,7 @@ GetAllVirtualEvents( * Any other fields in eventPtr which are not specified by the pattern * string or the optional arguments, are set to 0. * - * The event may be handled sychronously or asynchronously, depending on + * The event may be handled synchronously or asynchronously, depending on * the value specified by the optional "-when" option. The default * setting is synchronous. * @@ -3460,7 +3460,7 @@ HandleEventGenerate( Tcl_DoWhenIdle(DoWarp, dispPtr); dispPtr->flags |= TK_DISPLAY_IN_WARP; } - dispPtr->warpWindow = Tk_IdToWindow(Tk_Display(mainWin), + dispPtr->warpWindow = Tk_IdToWindow(dispPtr->display, event.general.xmotion.window); dispPtr->warpMainwin = mainWin; dispPtr->warpX = event.general.xmotion.x; @@ -3535,8 +3535,20 @@ DoWarp( { TkDisplay *dispPtr = clientData; - TkpWarpPointer(dispPtr); - XForceScreenSaver(dispPtr->display, ScreenSaverReset); + /* + * DoWarp was scheduled only if the window was mapped. It needs to be + * still mapped at the time the present idle callback is executed. Also + * one needs to guard against window destruction in the meantime. + * Finally, the case warpWindow == NULL is special in that it means + * the whole screen. + */ + + if ((dispPtr->warpWindow == NULL) || + (Tk_IsMapped(dispPtr->warpWindow) + && (Tk_WindowId(dispPtr->warpWindow) != None))) { + TkpWarpPointer(dispPtr); + XForceScreenSaver(dispPtr->display, ScreenSaverReset); + } dispPtr->flags &= ~TK_DISPLAY_IN_WARP; } @@ -3937,7 +3949,7 @@ ParseEventDescription( p = GetField(p, field, FIELD_SIZE); } if (*field != '\0') { - if ((*field >= '1') && (*field <= '5') && (field[1] == '\0')) { + if ((*field >= '1') && (*field <= '9') && (field[1] == '\0')) { if (eventFlags == 0) { patPtr->eventType = ButtonPress; eventMask = ButtonPressMask; diff --git a/generic/tkBusy.c b/generic/tkBusy.c index 65248a2..b36d453 100644 --- a/generic/tkBusy.c +++ b/generic/tkBusy.c @@ -433,6 +433,10 @@ MakeTransparentWindowExist( TkpMakeTransparentWindowExist(tkwin, parent); + if (winPtr->window == None) { + return; /* Platform didn't make Window. */ + } + dispPtr = winPtr->dispPtr; hPtr = Tcl_CreateHashEntry(&dispPtr->winTable, (char *) winPtr->window, ¬Used); diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 8e14852..9c4d60a 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2447,6 +2447,19 @@ DisplayCanvas( goto done; } +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + canvasPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif + /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked). diff --git a/generic/tkDecls.h b/generic/tkDecls.h index 64c32cd..eaaaf6c 100644 --- a/generic/tkDecls.h +++ b/generic/tkDecls.h @@ -1721,6 +1721,9 @@ extern const TkStubs *tkStubsPtr; #undef Tk_SafeInit #undef Tk_CreateConsoleWindow +#undef Tk_FreeXId +#define Tk_FreeXId(display,xid) + #if defined(_WIN32) && defined(UNICODE) # define Tk_MainEx Tk_MainExW EXTERN void Tk_MainExW(int argc, wchar_t **argv, diff --git a/generic/tkEntry.c b/generic/tkEntry.c index 3ad9acd..acfdd31 100644 --- a/generic/tkEntry.c +++ b/generic/tkEntry.c @@ -133,7 +133,7 @@ static const Tk_OptionSpec entryOptSpec[] = { 0, DEF_ENTRY_SELECT_BD_MONO, 0}, {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr), - TK_CONFIG_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0}, + TK_OPTION_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0}, {TK_OPTION_STRING, "-show", "show", "Show", DEF_ENTRY_SHOW, -1, Tk_Offset(Entry, showChar), TK_OPTION_NULL_OK, 0, 0}, @@ -279,23 +279,23 @@ static const Tk_OptionSpec sbOptSpec[] = { 0, DEF_ENTRY_SELECT_BD_MONO, 0}, {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr), - TK_CONFIG_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0}, + TK_OPTION_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0}, {TK_OPTION_STRING_TABLE, "-state", "state", "State", DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state), 0, stateStrings, 0}, {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus), - TK_CONFIG_NULL_OK, 0, 0}, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName), - TK_CONFIG_NULL_OK, 0, 0}, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_DOUBLE, "-to", "to", "To", DEF_SPINBOX_TO, -1, Tk_Offset(Spinbox, toValue), 0, 0, 0}, {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate", DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate), 0, validateStrings, 0}, {TK_OPTION_STRING, "-validatecommand", "validateCommand","ValidateCommand", - NULL, -1, Tk_Offset(Entry, validateCmd), TK_CONFIG_NULL_OK, 0, 0}, + NULL, -1, Tk_Offset(Entry, validateCmd), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-values", "values", "Values", DEF_SPINBOX_VALUES, -1, Tk_Offset(Spinbox, valueStr), TK_OPTION_NULL_OK, 0, 0}, @@ -307,7 +307,7 @@ static const Tk_OptionSpec sbOptSpec[] = { DEF_SPINBOX_WRAP, -1, Tk_Offset(Spinbox, wrap), 0, 0, 0}, {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd), - TK_CONFIG_NULL_OK, 0, 0}, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0} }; @@ -390,8 +390,8 @@ static const char *const selElementNames[] = { */ static int ConfigureEntry(Tcl_Interp *interp, Entry *entryPtr, - int objc, Tcl_Obj *const objv[], int flags); -static void DeleteChars(Entry *entryPtr, int index, int count); + int objc, Tcl_Obj *const objv[]); +static int DeleteChars(Entry *entryPtr, int index, int count); static void DestroyEntry(void *memPtr); static void DisplayEntry(ClientData clientData); static void EntryBlinkProc(ClientData clientData); @@ -417,7 +417,7 @@ static int EntryValidateChange(Entry *entryPtr, const char *change, static void ExpandPercents(Entry *entryPtr, const char *before, const char *change, const char *newStr, int index, int type, Tcl_DString *dsPtr); -static void EntryValueChanged(Entry *entryPtr, +static int EntryValueChanged(Entry *entryPtr, const char *newValue); static void EntryVisibleRange(Entry *entryPtr, double *firstPtr, double *lastPtr); @@ -427,7 +427,7 @@ static int EntryWidgetObjCmd(ClientData clientData, static void EntryWorldChanged(ClientData instanceData); static int GetEntryIndex(Tcl_Interp *interp, Entry *entryPtr, const char *string, int *indexPtr); -static void InsertChars(Entry *entryPtr, int index, const char *string); +static int InsertChars(Entry *entryPtr, int index, const char *string); /* * These forward declarations are the spinbox specific ones: @@ -554,7 +554,7 @@ Tk_EntryObjCmd( if ((Tk_InitOptions(interp, (char *) entryPtr, optionTable, tkwin) != TCL_OK) || - (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK)) { + (ConfigureEntry(interp, entryPtr, objc-2, objv+2) != TCL_OK)) { Tk_DestroyWindow(entryPtr->tkwin); return TCL_ERROR; } @@ -659,12 +659,12 @@ EntryWidgetObjCmd( } Tcl_SetObjResult(interp, objPtr); } else { - result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0); + result = ConfigureEntry(interp, entryPtr, objc-2, objv+2); } break; case COMMAND_DELETE: { - int first, last; + int first, last, code; if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?"); @@ -681,7 +681,10 @@ EntryWidgetObjCmd( goto error; } if ((last >= first) && (entryPtr->state == STATE_NORMAL)) { - DeleteChars(entryPtr, first, last - first); + code = DeleteChars(entryPtr, first, last - first); + if (code != TCL_OK) { + goto error; + } } break; } @@ -722,7 +725,7 @@ EntryWidgetObjCmd( } case COMMAND_INSERT: { - int index; + int index, code; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "index text"); @@ -733,7 +736,10 @@ EntryWidgetObjCmd( goto error; } if (entryPtr->state == STATE_NORMAL) { - InsertChars(entryPtr, index, Tcl_GetString(objv[3])); + code = InsertChars(entryPtr, index, Tcl_GetString(objv[3])); + if (code != TCL_OK) { + goto error; + } } break; } @@ -1082,8 +1088,7 @@ ConfigureEntry( Entry *entryPtr, /* Information about widget; may or may not * already have values for some fields. */ int objc, /* Number of valid entries in argv. */ - Tcl_Obj *const objv[], /* Argument objects. */ - int flags) /* Flags to pass to Tk_ConfigureWidget. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { Tk_SavedOptions savedOptions; Tk_3DBorder border; @@ -1098,6 +1103,7 @@ ConfigureEntry( int valuesChanged = 0; /* lint initialization */ double oldFrom = 0.0; /* lint initialization */ double oldTo = 0.0; /* lint initialization */ + int code; /* * Eliminate any existing trace on a variable monitored by the entry. @@ -1170,13 +1176,15 @@ ConfigureEntry( if (entryPtr->type == TK_SPINBOX) { if (sbPtr->fromValue > sbPtr->toValue) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "-to value must be greater than -from value", - -1)); - Tcl_SetErrorCode(interp, "TK", "SPINBOX", "RANGE_SANITY", - NULL); - continue; - } + /* + * Swap -from and -to values. + */ + + double tmpFromTo = sbPtr->fromValue; + + sbPtr->fromValue = sbPtr->toValue; + sbPtr->toValue = tmpFromTo; + } if (sbPtr->reqFormat && (oldFormat != sbPtr->reqFormat)) { /* @@ -1305,6 +1313,17 @@ ConfigureEntry( value = Tcl_GetVar2(interp, entryPtr->textVarName, NULL, TCL_GLOBAL_ONLY); if (value == NULL) { + + /* + * Since any trace on the textvariable was eliminated above, + * the only possible reason for EntryValueChanged to return + * an error is that the textvariable lives in a namespace + * that does not (yet) exist. Indeed, namespaces are not + * automatically created as needed. Don't trap this error + * here, better do it below when attempting to trace the + * variable. + */ + EntryValueChanged(entryPtr, NULL); } else { EntrySetValue(entryPtr, value); @@ -1323,7 +1342,13 @@ ConfigureEntry( */ Tcl_ListObjIndex(interp, sbPtr->listObj, 0, &objPtr); - EntryValueChanged(entryPtr, Tcl_GetString(objPtr)); + + /* + * No check for error return here as well, because any possible + * error will be trapped below when attempting tracing. + */ + + EntryValueChanged(entryPtr, Tcl_GetString(objPtr)); } else if ((sbPtr->valueStr == NULL) && !DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue) && (!DOUBLES_EQ(sbPtr->fromValue, oldFrom) @@ -1346,6 +1371,12 @@ ConfigureEntry( dvalue = sbPtr->fromValue; } sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue); + + /* + * No check for error return here as well, because any possible + * error will be trapped below when attempting tracing. + */ + EntryValueChanged(entryPtr, sbPtr->formatBuf); } } @@ -1357,10 +1388,13 @@ ConfigureEntry( if ((entryPtr->textVarName != NULL) && !(entryPtr->flags & ENTRY_VAR_TRACED)) { - Tcl_TraceVar2(interp, entryPtr->textVarName, + code = Tcl_TraceVar2(interp, entryPtr->textVarName, NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, EntryTextVarProc, entryPtr); - entryPtr->flags |= ENTRY_VAR_TRACED; + if (code != TCL_OK) { + return TCL_ERROR; + } + entryPtr->flags |= ENTRY_VAR_TRACED; } EntryWorldChanged(entryPtr); @@ -1680,7 +1714,7 @@ DisplayEntry( Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &cursorX, NULL, NULL, NULL); cursorX += entryPtr->layoutX; - cursorX -= (entryPtr->insertWidth)/2; + cursorX -= (entryPtr->insertWidth == 1) ? 1 : (entryPtr->insertWidth)/2; Tk_SetCaretPos(entryPtr->tkwin, cursorX, baseY - fm.ascent, fm.ascent + fm.descent); if (entryPtr->insertPos >= entryPtr->leftIndex && cursorX < xBound) { @@ -1892,8 +1926,8 @@ EntryComputeGeometry( */ if (entryPtr->showChar != NULL) { - Tcl_UniChar ch; - char buf[TCL_UTF_MAX]; + int ch; + char buf[6]; int size; /* @@ -1903,15 +1937,16 @@ EntryComputeGeometry( * resulting string. */ - Tcl_UtfToUniChar(entryPtr->showChar, &ch); - size = Tcl_UniCharToUtf(ch, buf); + TkUtfToUniChar(entryPtr->showChar, &ch); + size = TkUniCharToUtf(ch, buf); entryPtr->numDisplayBytes = entryPtr->numChars * size; p = ckalloc(entryPtr->numDisplayBytes + 1); entryPtr->displayString = p; for (i = entryPtr->numChars; --i >= 0; ) { - p += Tcl_UniCharToUtf(ch, p); + memcpy(p, buf, size); + p += size; } *p = '\0'; } @@ -1993,7 +2028,8 @@ EntryComputeGeometry( * Add new characters to an entry widget. * * Results: - * None. + * A standard Tcl result. If an error occurred then an error message is + * left in the interp's result. * * Side effects: * New information gets added to entryPtr; it will be redisplayed soon, @@ -2002,12 +2038,12 @@ EntryComputeGeometry( *---------------------------------------------------------------------- */ -static void +static int InsertChars( Entry *entryPtr, /* Entry that is to get the new elements. */ int index, /* Add the new elements before this character * index. */ - const char *value) /* New characters to add (NULL-terminated + const char *value) /* New characters to add (NULL-terminated * string). */ { ptrdiff_t byteIndex; @@ -2020,7 +2056,7 @@ InsertChars( byteIndex = Tcl_UtfAtIndex(string, index) - string; byteCount = strlen(value); if (byteCount == 0) { - return; + return TCL_OK; } newByteCount = entryPtr->numBytes + byteCount + 1; @@ -2034,7 +2070,7 @@ InsertChars( EntryValidateChange(entryPtr, value, newStr, index, VALIDATE_INSERT) != TCL_OK) { ckfree(newStr); - return; + return TCL_OK; } ckfree((char *)string); @@ -2082,7 +2118,7 @@ InsertChars( if (entryPtr->insertPos >= index) { entryPtr->insertPos += charsAdded; } - EntryValueChanged(entryPtr, NULL); + return EntryValueChanged(entryPtr, NULL); } /* @@ -2093,7 +2129,8 @@ InsertChars( * Remove one or more characters from an entry widget. * * Results: - * None. + * A standard Tcl result. If an error occurred then an error message is + * left in the interp's result. * * Side effects: * Memory gets freed, the entry gets modified and (eventually) @@ -2102,7 +2139,7 @@ InsertChars( *---------------------------------------------------------------------- */ -static void +static int DeleteChars( Entry *entryPtr, /* Entry widget to modify. */ int index, /* Index of first character to delete. */ @@ -2116,7 +2153,7 @@ DeleteChars( count = entryPtr->numChars - index; } if (count <= 0) { - return; + return TCL_OK; } string = entryPtr->string; @@ -2138,7 +2175,7 @@ DeleteChars( VALIDATE_DELETE) != TCL_OK) { ckfree(newStr); ckfree(toDelete); - return; + return TCL_OK; } ckfree(toDelete); @@ -2197,7 +2234,7 @@ DeleteChars( entryPtr->insertPos = index; } } - EntryValueChanged(entryPtr, NULL); + return EntryValueChanged(entryPtr, NULL); } /* @@ -2210,7 +2247,8 @@ DeleteChars( * is one, and does other bookkeeping such as arranging for redisplay. * * Results: - * None. + * A standard Tcl result. If an error occurred then an error message is + * left in the interp's result. * * Side effects: * None. @@ -2218,7 +2256,7 @@ DeleteChars( *---------------------------------------------------------------------- */ -static void +static int EntryValueChanged( Entry *entryPtr, /* Entry whose value just changed. */ const char *newValue) /* If this value is not NULL, we first force @@ -2232,7 +2270,7 @@ EntryValueChanged( newValue = NULL; } else { newValue = Tcl_SetVar2(entryPtr->interp, entryPtr->textVarName, - NULL, entryPtr->string, TCL_GLOBAL_ONLY); + NULL, entryPtr->string, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG); } if ((newValue != NULL) && (strcmp(newValue, entryPtr->string) != 0)) { @@ -2254,6 +2292,19 @@ EntryValueChanged( EntryComputeGeometry(entryPtr); EventuallyRedraw(entryPtr); } + + /* + * An error may have happened when setting the textvariable in case there + * is a trace on that variable and the trace proc triggered an error. + * Another possibility is that the textvariable is in a namespace that + * does not (yet) exist. + * Signal this error. + */ + + if ((entryPtr->textVarName != NULL) && (newValue == NULL)) { + return TCL_ERROR; + } + return TCL_OK; } /* @@ -3363,7 +3414,7 @@ ExpandPercents( * list element. */ int number, length; register const char *string; - Tcl_UniChar ch; + int ch; char numStorage[2*TCL_INTEGER_SPACE]; while (1) { @@ -3396,7 +3447,7 @@ ExpandPercents( before++; /* skip over % */ if (*before != '\0') { - before += Tcl_UtfToUniChar(before, &ch); + before += TkUtfToUniChar(before, &ch); } else { ch = '%'; } @@ -3416,7 +3467,7 @@ ExpandPercents( string = Tk_PathName(entryPtr->tkwin); break; default: - length = Tcl_UniCharToUtf(ch, numStorage); + length = TkUniCharToUtf(ch, numStorage); numStorage[length] = '\0'; string = numStorage; break; @@ -3476,7 +3527,7 @@ ExpandPercents( string = Tk_PathName(entryPtr->tkwin); break; default: - length = Tcl_UniCharToUtf(ch, numStorage); + length = TkUniCharToUtf(ch, numStorage); numStorage[length] = '\0'; string = numStorage; break; @@ -3611,7 +3662,7 @@ Tk_SpinboxObjCmd( Tk_DestroyWindow(entryPtr->tkwin); return TCL_ERROR; } - if (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK) { + if (ConfigureEntry(interp, entryPtr, objc-2, objv+2) != TCL_OK) { goto error; } @@ -3719,12 +3770,12 @@ SpinboxWidgetObjCmd( } Tcl_SetObjResult(interp, objPtr); } else { - result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0); + result = ConfigureEntry(interp, entryPtr, objc-2, objv+2); } break; case SB_CMD_DELETE: { - int first, last; + int first, last, code; if ((objc < 3) || (objc > 4)) { Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?"); @@ -3743,7 +3794,10 @@ SpinboxWidgetObjCmd( } } if ((last >= first) && (entryPtr->state == STATE_NORMAL)) { - DeleteChars(entryPtr, first, last - first); + code = DeleteChars(entryPtr, first, last - first); + if (code != TCL_OK) { + goto error; + } } break; } @@ -3803,7 +3857,7 @@ SpinboxWidgetObjCmd( } case SB_CMD_INSERT: { - int index; + int index, code; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "index text"); @@ -3814,7 +3868,10 @@ SpinboxWidgetObjCmd( goto error; } if (entryPtr->state == STATE_NORMAL) { - InsertChars(entryPtr, index, Tcl_GetString(objv[3])); + code = InsertChars(entryPtr, index, Tcl_GetString(objv[3])); + if (code != TCL_OK) { + goto error; + } } break; } @@ -4024,16 +4081,22 @@ SpinboxWidgetObjCmd( break; } - case SB_CMD_SET: + case SB_CMD_SET: { + int code = TCL_OK; + if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, "?string?"); goto error; } if (objc == 3) { - EntryValueChanged(entryPtr, Tcl_GetString(objv[2])); + code = EntryValueChanged(entryPtr, Tcl_GetString(objv[2])); + if (code != TCL_OK) { + goto error; + } } Tcl_SetObjResult(interp, Tcl_NewStringObj(entryPtr->string, -1)); break; + } case SB_CMD_VALIDATE: { int code; @@ -4174,7 +4237,7 @@ GetSpinboxElement( * TCL_OK. * * Side effects: - * An background error condition may arise when invoking the callback. + * A background error condition may arise when invoking the callback. * The widget value may change. * *-------------------------------------------------------------- @@ -4205,6 +4268,7 @@ SpinboxInvoke( return TCL_OK; } + code = TCL_OK; if (fabs(sbPtr->increment) > MIN_DBL_VAL) { if (sbPtr->listObj != NULL) { Tcl_Obj *objPtr; @@ -4250,7 +4314,7 @@ SpinboxInvoke( } } Tcl_ListObjIndex(interp, sbPtr->listObj, sbPtr->eIndex, &objPtr); - EntryValueChanged(entryPtr, Tcl_GetString(objPtr)); + code = EntryValueChanged(entryPtr, Tcl_GetString(objPtr)); } else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) { double dvalue; @@ -4297,9 +4361,12 @@ SpinboxInvoke( } } sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue); - EntryValueChanged(entryPtr, sbPtr->formatBuf); + code = EntryValueChanged(entryPtr, sbPtr->formatBuf); } } + if (code != TCL_OK) { + return TCL_ERROR; + } if (sbPtr->command != NULL) { Tcl_DStringInit(&script); diff --git a/generic/tkEvent.c b/generic/tkEvent.c index bcc6d98..95aeda1 100644 --- a/generic/tkEvent.c +++ b/generic/tkEvent.c @@ -2039,6 +2039,12 @@ TkFinalize( { ExitHandler *exitPtr; +#if defined(_WIN32) && !defined(STATIC_BUILD) + if (!tclStubsPtr) { + return; + } +#endif + Tcl_DeleteExitHandler(TkFinalize, NULL); Tcl_MutexLock(&exitMutex); diff --git a/generic/tkFont.c b/generic/tkFont.c index 447f9e1..7f2715b 100644 --- a/generic/tkFont.c +++ b/generic/tkFont.c @@ -497,7 +497,7 @@ Tk_FontObjCmd( const char *s; Tk_Font tkfont; Tcl_Obj *optPtr, *charPtr, *resultPtr; - Tcl_UniChar uniChar = 0; + int uniChar = 0; const TkFontAttributes *faPtr; TkFontAttributes fa; @@ -562,17 +562,19 @@ Tk_FontObjCmd( */ if (charPtr != NULL) { - if (Tcl_GetCharLength(charPtr) != 1) { + const char *string = Tcl_GetString(charPtr); + int len = TkUtfToUniChar(string, &uniChar); + + if (len != charPtr->length) { resultPtr = Tcl_NewStringObj( "expected a single character but got \"", -1); - Tcl_AppendLimitedToObj(resultPtr, Tcl_GetString(charPtr), + Tcl_AppendLimitedToObj(resultPtr, string, -1, 40, "..."); Tcl_AppendToObj(resultPtr, "\"", -1); Tcl_SetObjResult(interp, resultPtr); Tcl_SetErrorCode(interp, "TK", "VALUE", "FONT_SAMPLE", NULL); return TCL_ERROR; } - uniChar = Tcl_GetUniChar(charPtr, 0); } /* @@ -1694,7 +1696,7 @@ Tk_PostscriptFontName( } else if (strcasecmp(family, "ZapfDingbats") == 0) { family = "ZapfDingbats"; } else { - Tcl_UniChar ch; + int ch; /* * Inline, capitalize the first letter of each word, lowercase the @@ -1712,14 +1714,14 @@ Tk_PostscriptFontName( src++; upper = 1; } - src += Tcl_UtfToUniChar(src, &ch); + src += TkUtfToUniChar(src, &ch); if (upper) { ch = Tcl_UniCharToUpper(ch); upper = 0; } else { ch = Tcl_UniCharToLower(ch); } - dest += Tcl_UniCharToUtf(ch, dest); + dest += TkUniCharToUtf(ch, dest); } *dest = '\0'; Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr)); @@ -2067,14 +2069,14 @@ Tk_ComputeTextLayout( NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX, baseline)->numDisplayChars = -1; start++; + curX = newX; + flags &= ~TK_AT_LEAST_ONE; if ((start < end) && ((wrapLength <= 0) || (newX <= wrapLength))) { /* * More chars can still fit on this line. */ - curX = newX; - flags &= ~TK_AT_LEAST_ONE; continue; } } else { @@ -3249,7 +3251,7 @@ Tk_TextLayoutToPostscript( int i, j, len; const char *p, *glyphname; char uindex[5], c, *ps; - Tcl_UniChar ch; + int ch; Tcl_AppendToObj(psObj, "[(", -1); for (i = 0; i < layoutPtr->numChunks; i++, chunkPtr++) { @@ -3272,7 +3274,7 @@ Tk_TextLayoutToPostscript( * international postscript fonts. */ - p += Tcl_UtfToUniChar(p, &ch); + p += TkUtfToUniChar(p, &ch); if ((ch == '(') || (ch == ')') || (ch == '\\') || (ch < 0x20)) { /* * Tricky point: the "03" is necessary in the sprintf below, @@ -3298,6 +3300,9 @@ Tk_TextLayoutToPostscript( * use the full glyph name. */ + if (ch > 0xffff) { + goto noMapping; + } sprintf(uindex, "%04X", ch); /* endianness? */ glyphname = Tcl_GetVar2(interp, "::tk::psglyphs", uindex, 0); if (glyphname) { @@ -3318,6 +3323,7 @@ Tk_TextLayoutToPostscript( * No known mapping for the character into the space of * PostScript glyphs. Ignore it. :-( */ +noMapping: ; #ifdef TK_DEBUG_POSTSCRIPT_OUTPUT fprintf(stderr, "Warning: no mapping to PostScript " diff --git a/generic/tkFrame.c b/generic/tkFrame.c index 057b4b8..0f1a1b3 100644 --- a/generic/tkFrame.c +++ b/generic/tkFrame.c @@ -447,6 +447,29 @@ TkCreateFrame( return result; } +int +TkListCreateFrame( + ClientData clientData, /* Either NULL or pointer to option table. */ + Tcl_Interp *interp, /* Current interpreter. */ + Tcl_Obj *listObj, /* List of arguments. */ + int toplevel, /* Non-zero means create a toplevel window, + * zero means create a frame. */ + Tcl_Obj *nameObj) /* Should only be non-NULL if there is no main + * window associated with the interpreter. + * Gives the base name to use for the new + * application. */ +{ + int objc; + Tcl_Obj **objv; + + if (TCL_OK != Tcl_ListObjGetElements(interp, listObj, &objc, &objv)) { + return TCL_ERROR; + } + return CreateFrame(clientData, interp, objc, objv, + toplevel ? TYPE_TOPLEVEL : TYPE_FRAME, + nameObj ? Tcl_GetString(nameObj) : NULL); +} + static int CreateFrame( ClientData clientData, /* NULL. */ diff --git a/generic/tkGC.c b/generic/tkGC.c index 5663ede..c424e30 100644 --- a/generic/tkGC.c +++ b/generic/tkGC.c @@ -314,7 +314,6 @@ Tk_FreeGC( gcPtr = Tcl_GetHashValue(idHashPtr); gcPtr->refCount--; if (gcPtr->refCount == 0) { - Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc)); XFreeGC(gcPtr->display, gcPtr->gc); Tcl_DeleteHashEntry(gcPtr->valueHashPtr); Tcl_DeleteHashEntry(idHashPtr); @@ -351,12 +350,6 @@ TkGCCleanup( entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { gcPtr = Tcl_GetHashValue(entryPtr); - /* - * This call is not needed, as it is only used on Unix to restore the - * Id to the stack pool, and we don't want to use them anymore. - * Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc)); - */ - XFreeGC(gcPtr->display, gcPtr->gc); Tcl_DeleteHashEntry(gcPtr->valueHashPtr); Tcl_DeleteHashEntry(entryPtr); diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index 27de486..1c28b54 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -393,7 +393,8 @@ FileReadGIF( * image being read. */ { int fileWidth, fileHeight, imageWidth, imageHeight; - int nBytes, index = 0, argc = 0, i, result = TCL_ERROR; + unsigned int nBytes; + int index = 0, argc = 0, i, result = TCL_ERROR; Tcl_Obj **objv; unsigned char buf[100]; unsigned char *trashBuffer = NULL; @@ -410,6 +411,7 @@ FileReadGIF( * source and not a file. */ + memset(colorMap, 0, MAXCOLORMAPSIZE*4); memset(gifConfPtr, 0, sizeof(GIFImageConfig)); if (fileName == INLINE_DATA_BINARY || fileName == INLINE_DATA_BASE64) { gifConfPtr->fromData = fileName; @@ -425,8 +427,9 @@ FileReadGIF( return TCL_ERROR; } for (i = 1; i < argc; i++) { + int optionIdx; if (Tcl_GetIndexFromObjStruct(interp, objv[i], optionStrings, - sizeof(char *), "option name", 0, &nBytes) != TCL_OK) { + sizeof(char *), "option name", 0, &optionIdx) != TCL_OK) { return TCL_ERROR; } if (i == (argc-1)) { @@ -590,8 +593,14 @@ FileReadGIF( */ if (trashBuffer == NULL) { + if (fileWidth > (int)((UINT_MAX/3)/fileHeight)) { + goto error; + } nBytes = fileWidth * fileHeight * 3; trashBuffer = ckalloc(nBytes); + if (trashBuffer) { + memset(trashBuffer, 0, nBytes); + } } /* @@ -675,9 +684,18 @@ FileReadGIF( block.offset[1] = 1; block.offset[2] = 2; block.offset[3] = (transparent>=0) ? 3 : 0; + if (imageWidth > INT_MAX/block.pixelSize) { + goto error; + } block.pitch = block.pixelSize * imageWidth; + if (imageHeight > (int)(UINT_MAX/block.pitch)) { + goto error; + } nBytes = block.pitch * imageHeight; block.pixelPtr = ckalloc(nBytes); + if (block.pixelPtr) { + memset(block.pixelPtr, 0, nBytes); + } if (ReadImage(gifConfPtr, interp, block.pixelPtr, chan, imageWidth, imageHeight, colorMap, srcX, srcY, BitSet(buf[8], INTERLACE), diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c index 8a740d2..c6e3029 100644 --- a/generic/tkImgPNG.c +++ b/generic/tkImgPNG.c @@ -10,6 +10,7 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#include "assert.h" #include "tkInt.h" #define PNG_INT32(a,b,c,d) \ @@ -334,7 +335,7 @@ InitPNGImage( if (Tcl_ZlibStreamInit(NULL, dir, TCL_ZLIB_FORMAT_ZLIB, TCL_ZLIB_COMPRESS_DEFAULT, NULL, &pngPtr->stream) != TCL_OK) { - if (interp) { + if (interp) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "zlib initialization failed", -1)); Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "ZLIB_INIT", NULL); @@ -1846,6 +1847,13 @@ DecodeLine( if (UnfilterLine(interp, pngPtr) == TCL_ERROR) { return TCL_ERROR; } + if (pngPtr->currentLine >= pngPtr->block.height) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "PNG image data overflow")); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "DATA_OVERFLOW", NULL); + return TCL_ERROR; + } + if (pngPtr->interlace) { switch (pngPtr->phase) { @@ -2175,10 +2183,13 @@ ReadIDAT( /* * Try to read another line of pixels out of the buffer - * immediately. + * immediately, but don't allow write past end of block. */ - goto getNextLine; + if (pngPtr->currentLine < pngPtr->block.height) { + goto getNextLine; + } + } /* @@ -3345,7 +3356,7 @@ EncodePNG( pngPtr->colorType = PNG_COLOR_RGBA; pngPtr->bytesPerPixel = 4; } else { - pngPtr->colorType = PNG_COLOR_RGBA; + pngPtr->colorType = PNG_COLOR_RGB; pngPtr->bytesPerPixel = 3; } } else { diff --git a/generic/tkImgPhInstance.c b/generic/tkImgPhInstance.c index 666a9b0..bd152f2 100644 --- a/generic/tkImgPhInstance.c +++ b/generic/tkImgPhInstance.c @@ -404,6 +404,9 @@ TkImgPhotoGet( * * Note that Win32 pre-defines those operations that we really need. * + * Note that on MacOS, if the background comes from a Retina display + * then it will be twice as wide and twice as high as the photoimage. + * *---------------------------------------------------------------------- */ @@ -433,7 +436,16 @@ BlendComplexAlpha( unsigned long pixel; unsigned char r, g, b, alpha, unalpha, *masterPtr; unsigned char *alphaAr = iPtr->masterPtr->pix32; - +#if defined(MAC_OSX_TK) + /* Background "pixels" are actually 2^pp x 2^pp blocks of subpixels. Each + * block gets blended with the color of one image pixel. Since we iterate + * over the background subpixels, we reset the width and height to the + * subpixel dimensions of the background image we are using. + */ + int pp = bgImg->pixelpower; + width = width << pp; + height = height << pp; +#endif /* * This blending is an integer version of the Source-Over compositing rule * (see Porter&Duff, "Compositing Digital Images", proceedings of SIGGRAPH @@ -532,9 +544,16 @@ BlendComplexAlpha( #endif /* !_WIN32 && !MAC_OSX_TK */ for (y = 0; y < height; y++) { +# if !defined(MAC_OSX_TK) line = (y + yOffset) * iPtr->masterPtr->width; for (x = 0; x < width; x++) { masterPtr = alphaAr + ((line + x + xOffset) * 4); +#else + /* Repeat each image row and column 2^pp times. */ + line = ((y>>pp) + yOffset) * iPtr->masterPtr->width; + for (x = 0; x < width; x++) { + masterPtr = alphaAr + ((line + (x>>pp) + xOffset) * 4); +#endif alpha = masterPtr[3]; /* @@ -635,7 +654,9 @@ TkImgPhotoDisplay( (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); if (bgImg == NULL) { Tk_DeleteErrorHandler(handler); - /* We failed to get the image so draw without blending alpha. It's the best we can do */ + /* We failed to get the image, so draw without blending alpha. + * It's the best we can do. + */ goto fallBack; } diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c index 9527c93..3e03f3d 100644 --- a/generic/tkImgPhoto.c +++ b/generic/tkImgPhoto.c @@ -886,6 +886,19 @@ ImgPhotoCmd( break; } dataWidth = listObjc; + /* + * Memory allocation overflow protection. + * May not be able to trigger/ demo / test this. + */ + + if (dataWidth > (int)((UINT_MAX/3) / dataHeight)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "photo image dimensions exceed Tcl memory limits", -1)); + Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO", + "OVERFLOW", NULL); + break; + } + pixelPtr = ckalloc(dataWidth * dataHeight * 3); block.pixelPtr = pixelPtr; } else if (listObjc != dataWidth) { @@ -2051,8 +2064,8 @@ static int ToggleComplexAlphaIfNeeded( PhotoMaster *mPtr) { - size_t len = MAX(mPtr->userWidth, mPtr->width) * - MAX(mPtr->userHeight, mPtr->height) * 4; + size_t len = (size_t)MAX(mPtr->userWidth, mPtr->width) * + (size_t)MAX(mPtr->userHeight, mPtr->height) * 4; unsigned char *c = mPtr->pix32; unsigned char *end = c + len; @@ -2062,6 +2075,9 @@ ToggleComplexAlphaIfNeeded( */ mPtr->flags &= ~COMPLEX_ALPHA; + if (c == NULL) { + return 0; + } c += 3; /* Start at first alpha byte. */ for (; c < end; c += 4) { if (*c && *c != 255) { @@ -2192,6 +2208,10 @@ ImgPhotoSetSize( height = masterPtr->userHeight; } + if (width > INT_MAX / 4) { + /* Pitch overflows int */ + return TCL_ERROR; + } pitch = width * 4; /* @@ -2201,11 +2221,12 @@ ImgPhotoSetSize( if ((width != masterPtr->width) || (height != masterPtr->height) || (masterPtr->pix32 == NULL)) { - /* - * Not a u-long, but should be one. - */ + unsigned newPixSize; - unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch); + if (pitch && height > (int)(UINT_MAX / pitch)) { + return TCL_ERROR; + } + newPixSize = height * pitch; /* * Some mallocs() really hate allocating zero bytes. [Bug 619544] @@ -2257,14 +2278,14 @@ ImgPhotoSetSize( if ((masterPtr->pix32 != NULL) && ((width == masterPtr->width) || (width == validBox.width))) { if (validBox.y > 0) { - memset(newPix32, 0, (size_t) (validBox.y * pitch)); + memset(newPix32, 0, ((size_t) validBox.y * pitch)); } h = validBox.y + validBox.height; if (h < height) { - memset(newPix32 + h*pitch, 0, (size_t) ((height - h) * pitch)); + memset(newPix32 + h*pitch, 0, ((size_t) (height - h) * pitch)); } } else { - memset(newPix32, 0, (size_t) (height * pitch)); + memset(newPix32, 0, ((size_t)height * pitch)); } if (masterPtr->pix32 != NULL) { @@ -2281,7 +2302,7 @@ ImgPhotoSetSize( offset = validBox.y * pitch; memcpy(newPix32 + offset, masterPtr->pix32 + offset, - (size_t) (validBox.height * pitch)); + ((size_t)validBox.height * pitch)); } else if ((validBox.width > 0) && (validBox.height > 0)) { /* @@ -2292,7 +2313,7 @@ ImgPhotoSetSize( srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width + validBox.x) * 4; for (h = validBox.height; h > 0; h--) { - memcpy(destPtr, srcPtr, (size_t) (validBox.width * 4)); + memcpy(destPtr, srcPtr, ((size_t)validBox.width * 4)); destPtr += width * 4; srcPtr += masterPtr->width * 4; } @@ -2772,7 +2793,7 @@ Tk_PhotoPutBlock( && (blockPtr->pitch == pitch))) && (compRule == TK_PHOTO_COMPOSITE_SET)) { memmove(destLinePtr, blockPtr->pixelPtr + blockPtr->offset[0], - (size_t) (height * width * 4)); + ((size_t)height * width * 4)); /* * We know there's an alpha offset and we're setting the data, so skip @@ -2804,7 +2825,7 @@ Tk_PhotoPutBlock( && (blueOffset == 2) && (alphaOffset == 3) && (width <= blockPtr->width) && compRuleSet) { - memcpy(destLinePtr, srcLinePtr, (size_t) (width * 4)); + memcpy(destLinePtr, srcLinePtr, ((size_t)width * 4)); srcLinePtr += blockPtr->pitch; destLinePtr += pitch; continue; @@ -3454,7 +3475,7 @@ Tk_PhotoBlank( */ memset(masterPtr->pix32, 0, - (size_t) (masterPtr->width * masterPtr->height * 4)); + ((size_t)masterPtr->width * masterPtr->height * 4)); for (instancePtr = masterPtr->instancePtr; instancePtr != NULL; instancePtr = instancePtr->nextPtr) { TkImgResetDither(instancePtr); @@ -3683,6 +3704,9 @@ ImgGetPhoto( break; } } + if (!alphaOffset) { + blockPtr->offset[3]= -1; /* Tell caller alpha need not be read */ + } greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; if (((optPtr->options & OPT_BACKGROUND) && alphaOffset) || @@ -3696,6 +3720,10 @@ ImgGetPhoto( if ((greenOffset||blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) { newPixelSize += 2; } + + if (blockPtr->height > (int)((UINT_MAX/newPixelSize)/blockPtr->width)) { + return NULL; + } data = attemptckalloc(newPixelSize*blockPtr->width*blockPtr->height); if (data == NULL) { return NULL; @@ -3803,9 +3831,6 @@ ImgGetPhoto( blockPtr->offset[2] = 0; blockPtr->offset[3]= 1; } - if (!alphaOffset) { - blockPtr->offset[3]= -1; - } return data; } return NULL; @@ -3835,32 +3860,30 @@ ImgStringWrite( Tk_PhotoImageBlock *blockPtr) { int greenOffset, blueOffset; - Tcl_DString data; + Tcl_Obj *data; greenOffset = blockPtr->offset[1] - blockPtr->offset[0]; blueOffset = blockPtr->offset[2] - blockPtr->offset[0]; - Tcl_DStringInit(&data); + data = Tcl_NewObj(); if ((blockPtr->width > 0) && (blockPtr->height > 0)) { - char *line = ckalloc((8 * blockPtr->width) + 2); int row, col; for (row=0; row<blockPtr->height; row++) { + Tcl_Obj *line = Tcl_NewObj(); unsigned char *pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] + row * blockPtr->pitch; - char *linePtr = line; for (col=0; col<blockPtr->width; col++) { - sprintf(linePtr, " #%02x%02x%02x", *pixelPtr, + Tcl_AppendPrintfToObj(line, "%s#%02x%02x%02x", + col ? " " : "", *pixelPtr, pixelPtr[greenOffset], pixelPtr[blueOffset]); pixelPtr += blockPtr->pixelSize; - linePtr += 8; } - Tcl_DStringAppendElement(&data, line+1); + Tcl_ListObjAppendElement(NULL, data, line); } - ckfree(line); } - Tcl_DStringResult(interp, &data); + Tcl_SetObjResult(interp, data); return TCL_OK; } diff --git a/generic/tkInt.decls b/generic/tkInt.decls index ebbadba..586b407 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -1017,6 +1017,9 @@ declare 50 aqua { declare 51 aqua { void TkGenWMDestroyEvent(Tk_Window tkwin) } +declare 52 aqua { + void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag) +} # removed duplicate from tkPlat table (tk.decls) #declare 52 aqua { diff --git a/generic/tkInt.h b/generic/tkInt.h index b644c5b..1615a81 100644 --- a/generic/tkInt.h +++ b/generic/tkInt.h @@ -1196,7 +1196,7 @@ MODULE_SCOPE void TkUnderlineCharsInContext(Display *display, const char *string, int numBytes, int x, int y, int firstByte, int lastByte); MODULE_SCOPE void TkpGetFontAttrsForChar(Tk_Window tkwin, Tk_Font tkfont, - Tcl_UniChar c, struct TkFontAttributes *faPtr); + int c, struct TkFontAttributes *faPtr); MODULE_SCOPE Tcl_Obj * TkNewWindowObj(Tk_Window tkwin); MODULE_SCOPE void TkpShowBusyWindow(TkBusy busy); MODULE_SCOPE void TkpHideBusyWindow(TkBusy busy); @@ -1208,7 +1208,7 @@ MODULE_SCOPE void TkpCreateBusy(Tk_FakeWin *winPtr, Tk_Window tkRef, MODULE_SCOPE int TkBackgroundEvalObjv(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv, int flags); MODULE_SCOPE void TkSendVirtualEvent(Tk_Window tgtWin, - const char *eventName); + const char *eventName, Tcl_Obj *detail); MODULE_SCOPE Tcl_Command TkMakeEnsemble(Tcl_Interp *interp, const char *nsname, const char *name, ClientData clientData, const TkEnsemble *map); @@ -1217,6 +1217,9 @@ MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp, MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp, ClientData clientData); MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr); +MODULE_SCOPE int TkListCreateFrame(ClientData clientData, + Tcl_Interp *interp, Tcl_Obj *listObj, + int toplevel, Tcl_Obj *nameObj); #ifdef _WIN32 #define TkParseColor XParseColor @@ -1229,6 +1232,14 @@ MODULE_SCOPE Status TkParseColor (Display * display, MODULE_SCOPE void TkUnixSetXftClipRegion(TkRegion clipRegion); #endif +#if TCL_UTF_MAX > 4 +# define TkUtfToUniChar Tcl_UtfToUniChar +# define TkUniCharToUtf Tcl_UniCharToUtf +#else + MODULE_SCOPE int TkUtfToUniChar(const char *, int *); + MODULE_SCOPE int TkUniCharToUtf(int, char *); +#endif + /* * Unsupported commands. */ diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h index 3a2a8aa..e48e803 100644 --- a/generic/tkIntPlatDecls.h +++ b/generic/tkIntPlatDecls.h @@ -250,7 +250,8 @@ EXTERN int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state); /* 51 */ EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin); -/* Slot 52 is reserved */ +/* 52 */ +EXTERN void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); /* 53 */ EXTERN unsigned long TkpGetMS(void); /* 54 */ @@ -395,7 +396,7 @@ typedef struct TkIntPlatStubs { Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */ void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */ - void (*reserved52)(void); + void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */ unsigned long (*tkpGetMS) (void); /* 53 */ void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */ int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */ @@ -621,7 +622,8 @@ extern const TkIntPlatStubs *tkIntPlatStubsPtr; (tkIntPlatStubsPtr->tkGenerateButtonEvent) /* 50 */ #define TkGenWMDestroyEvent \ (tkIntPlatStubsPtr->tkGenWMDestroyEvent) /* 51 */ -/* Slot 52 is reserved */ +#define TkMacOSXSetDrawingEnabled \ + (tkIntPlatStubsPtr->tkMacOSXSetDrawingEnabled) /* 52 */ #define TkpGetMS \ (tkIntPlatStubsPtr->tkpGetMS) /* 53 */ #define TkMacOSXDrawable \ diff --git a/generic/tkListbox.c b/generic/tkListbox.c index 437973a..b059727 100644 --- a/generic/tkListbox.c +++ b/generic/tkListbox.c @@ -90,14 +90,14 @@ typedef struct { * display. */ int topIndex; /* Index of top-most element visible in * window. */ - int fullLines; /* Number of lines that fit are completely + int fullLines; /* Number of lines that are completely * visible in window. There may be one * additional line at the bottom that is * partially visible. */ int partialLine; /* 0 means that the window holds exactly * fullLines lines. 1 means that there is one * additional line that is partially - * visble. */ + * visible. */ int setGrid; /* Non-zero means pass gridding information to * window manager. */ @@ -114,7 +114,8 @@ typedef struct { int xOffset; /* The left edge of each string in the listbox * is offset to the left by this many pixels * (0 means no offset, positive means there is - * an offset). */ + * an offset). This is x scrolling information + * is not linked to justification. */ /* * Information about what's selected or active, if any. @@ -131,7 +132,7 @@ typedef struct { int active; /* Index of "active" element (the one that has * been selected by keyboard traversal). -1 * means none. */ - int activeStyle; /* style in which to draw the active element. + int activeStyle; /* Style in which to draw the active element. * One of: underline, none, dotbox */ /* @@ -165,6 +166,7 @@ typedef struct { Pixmap gray; /* Pixmap for displaying disabled text. */ int flags; /* Various flag bits: see below for * definitions. */ + Tk_Justify justify; /* Justification. */ } Listbox; /* @@ -197,7 +199,7 @@ typedef struct { * be updated. * GOT_FOCUS: Non-zero means this widget currently has the * input focus. - * MAXWIDTH_IS_STALE: Stored maxWidth may be out-of-date + * MAXWIDTH_IS_STALE: Stored maxWidth may be out-of-date. * LISTBOX_DELETED: This listbox has been effectively destroyed. */ @@ -275,6 +277,8 @@ static const Tk_OptionSpec optionSpecs[] = { {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_LISTBOX_HIGHLIGHT_WIDTH, -1, Tk_Offset(Listbox, highlightWidth), 0, 0, 0}, + {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", + DEF_LISTBOX_JUSTIFY, -1, Tk_Offset(Listbox, justify), 0, 0, 0}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", DEF_LISTBOX_RELIEF, -1, Tk_Offset(Listbox, relief), 0, 0, 0}, {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", @@ -285,7 +289,7 @@ static const Tk_OptionSpec optionSpecs[] = { Tk_Offset(Listbox, selBorderWidth), 0, 0, 0}, {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", DEF_LISTBOX_SELECT_FG_COLOR, -1, Tk_Offset(Listbox, selFgColorPtr), - TK_CONFIG_NULL_OK, DEF_LISTBOX_SELECT_FG_MONO, 0}, + TK_OPTION_NULL_OK, DEF_LISTBOX_SELECT_FG_MONO, 0}, {TK_OPTION_STRING, "-selectmode", "selectMode", "SelectMode", DEF_LISTBOX_SELECT_MODE, -1, Tk_Offset(Listbox, selectMode), TK_OPTION_NULL_OK, 0, 0}, @@ -313,7 +317,7 @@ static const Tk_OptionSpec optionSpecs[] = { /* * The itemAttrOptionSpecs table defines the valid configuration options for - * listbox items + * listbox items. */ static const Tk_OptionSpec itemAttrOptionSpecs[] = { @@ -340,7 +344,7 @@ static const Tk_OptionSpec itemAttrOptionSpecs[] = { }; /* - * The following tables define the listbox widget commands (and sub- commands) + * The following tables define the listbox widget commands (and sub-commands) * and map the indexes into the string tables into enumerated types used to * dispatch the listbox widget command. */ @@ -386,7 +390,7 @@ enum indices { static void ChangeListboxOffset(Listbox *listPtr, int offset); static void ChangeListboxView(Listbox *listPtr, int index); static int ConfigureListbox(Tcl_Interp *interp, Listbox *listPtr, - int objc, Tcl_Obj *const objv[], int flags); + int objc, Tcl_Obj *const objv[]); static int ConfigureListboxItem(Tcl_Interp *interp, Listbox *listPtr, ItemAttr *attrs, int objc, Tcl_Obj *const objv[], int index); @@ -408,6 +412,7 @@ static void ListboxEventProc(ClientData clientData, static int ListboxFetchSelection(ClientData clientData, int offset, char *buffer, int maxBytes); static void ListboxLostSelection(ClientData clientData); +static void GenerateListboxSelectEvent(Listbox *listPtr); static void EventuallyRedrawRange(Listbox *listPtr, int first, int last); static void ListboxScanTo(Listbox *listPtr, int x, int y); @@ -435,6 +440,7 @@ static char * ListboxListVarProc(ClientData clientData, const char *name2, int flags); static void MigrateHashEntries(Tcl_HashTable *table, int first, int last, int offset); +static int GetMaxOffset(Listbox *listPtr); /* * The structure below defines button class behavior by means of procedures @@ -545,6 +551,7 @@ Tk_ListboxObjCmd( listPtr->cursor = None; listPtr->state = STATE_NORMAL; listPtr->gray = None; + listPtr->justify = TK_JUSTIFY_LEFT; /* * Keep a hold of the associated tkwin until we destroy the listbox, @@ -566,7 +573,7 @@ Tk_ListboxObjCmd( return TCL_ERROR; } - if (ConfigureListbox(interp, listPtr, objc-2, objv+2, 0) != TCL_OK) { + if (ConfigureListbox(interp, listPtr, objc-2, objv+2) != TCL_OK) { Tk_DestroyWindow(listPtr->tkwin); return TCL_ERROR; } @@ -612,7 +619,7 @@ ListboxWidgetObjCmd( /* * Parse the command by looking up the second argument in the list of - * valid subcommand names + * valid subcommand names. */ result = Tcl_GetIndexFromObj(interp, objv[1], commandNames, @@ -697,7 +704,7 @@ ListboxWidgetObjCmd( Tcl_SetObjResult(interp, objPtr); result = TCL_OK; } else { - result = ConfigureListbox(interp, listPtr, objc-2, objv+2, 0); + result = ConfigureListbox(interp, listPtr, objc-2, objv+2); } break; @@ -1075,6 +1082,7 @@ ListboxBboxSubCmd( Listbox *listPtr, /* Information about the listbox */ int index) /* Index of the element to get bbox info on */ { + register Tk_Window tkwin = listPtr->tkwin; int lastVisibleIndex; /* @@ -1110,7 +1118,15 @@ ListboxBboxSubCmd( Tk_GetFontMetrics(listPtr->tkfont, &fm); pixelWidth = Tk_TextWidth(listPtr->tkfont, stringRep, stringLen); - x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset; + if (listPtr->justify == TK_JUSTIFY_LEFT) { + x = (listPtr->inset + listPtr->selBorderWidth) - listPtr->xOffset; + } else if (listPtr->justify == TK_JUSTIFY_RIGHT) { + x = Tk_Width(tkwin) - (listPtr->inset + listPtr->selBorderWidth) + - pixelWidth - listPtr->xOffset + GetMaxOffset(listPtr); + } else { + x = (Tk_Width(tkwin) - pixelWidth)/2 + - listPtr->xOffset + GetMaxOffset(listPtr)/2; + } y = ((index - listPtr->topIndex)*listPtr->lineHeight) + listPtr->inset + listPtr->selBorderWidth; results[0] = Tcl_NewIntObj(x); @@ -1542,8 +1558,7 @@ ConfigureListbox( register Listbox *listPtr, /* Information about widget; may or may not * already have values for some fields. */ int objc, /* Number of valid entries in argv. */ - Tcl_Obj *const objv[], /* Arguments. */ - int flags) /* Flags to pass to Tk_ConfigureWidget. */ + Tcl_Obj *const objv[]) /* Arguments. */ { Tk_SavedOptions savedOptions; Tcl_Obj *oldListObj = NULL; @@ -1837,6 +1852,7 @@ DisplayListbox( * or right edge of the listbox is * off-screen. */ Pixmap pixmap; + int textWidth; listPtr->flags &= ~REDRAW_PENDING; if (listPtr->flags & LISTBOX_DELETED) { @@ -2016,7 +2032,7 @@ DisplayListbox( } else { /* * If there is an item attributes record for this item, draw - * the background box and set the foreground color accordingly + * the background box and set the foreground color accordingly. */ if (entry != NULL) { @@ -2056,12 +2072,24 @@ DisplayListbox( * Draw the actual text of this item. */ + Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement); + stringRep = Tcl_GetStringFromObj(curElement, &stringLen); + textWidth = Tk_TextWidth(listPtr->tkfont, stringRep, stringLen); + Tk_GetFontMetrics(listPtr->tkfont, &fm); y += fm.ascent + listPtr->selBorderWidth; - x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset; - Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement); - stringRep = Tcl_GetStringFromObj(curElement, &stringLen); - Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont, + + if (listPtr->justify == TK_JUSTIFY_LEFT) { + x = (listPtr->inset + listPtr->selBorderWidth) - listPtr->xOffset; + } else if (listPtr->justify == TK_JUSTIFY_RIGHT) { + x = Tk_Width(tkwin) - (listPtr->inset + listPtr->selBorderWidth) + - textWidth - listPtr->xOffset + GetMaxOffset(listPtr); + } else { + x = (Tk_Width(tkwin) - textWidth)/2 + - listPtr->xOffset + GetMaxOffset(listPtr)/2; + } + + Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont, stringRep, stringLen, x, y); /* @@ -2458,7 +2486,7 @@ ListboxDeleteSubCmd( /* * Check width of the element. We only have to check if widthChanged * has not already been set to 1, because we only need one maxWidth - * element to disappear for us to have to recompute the width + * element to disappear for us to have to recompute the width. */ if (widthChanged == 0) { @@ -2735,7 +2763,11 @@ GetListboxIndex( stringRep = Tcl_GetString(indexObj); if (stringRep[0] == '@') { - /* @x,y index */ + + /* + * @x,y index + */ + int y; const char *start; char *end; @@ -2844,9 +2876,7 @@ ChangeListboxOffset( */ offset += listPtr->xScrollUnit / 2; - maxOffset = listPtr->maxWidth - (Tk_Width(listPtr->tkwin) - - 2*listPtr->inset - 2*listPtr->selBorderWidth) - + listPtr->xScrollUnit - 1; + maxOffset = GetMaxOffset(listPtr); if (offset > maxOffset) { offset = maxOffset; } @@ -2887,9 +2917,7 @@ ListboxScanTo( int newTopIndex, newOffset, maxIndex, maxOffset; maxIndex = listPtr->nElements - listPtr->fullLines; - maxOffset = listPtr->maxWidth + (listPtr->xScrollUnit - 1) - - (Tk_Width(listPtr->tkwin) - 2*listPtr->inset - - 2*listPtr->selBorderWidth - listPtr->xScrollUnit); + maxOffset = GetMaxOffset(listPtr); /* * Compute new top line for screen by amplifying the difference between @@ -3170,12 +3198,37 @@ ListboxLostSelection( if ((listPtr->exportSelection) && (listPtr->nElements > 0)) { ListboxSelect(listPtr, 0, listPtr->nElements-1, 0); + GenerateListboxSelectEvent(listPtr); } } /* *---------------------------------------------------------------------- * + * GenerateListboxSelectEvent -- + * + * Send an event that the listbox selection was updated. This is + * equivalent to event generate $listboxWidget <<ListboxSelect>> + * + * Results: + * None + * + * Side effects: + * Any side effect possible, depending on bindings to this event. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateListboxSelectEvent( + Listbox *listPtr) /* Information about widget. */ +{ + TkSendVirtualEvent(listPtr->tkwin, "ListboxSelect", NULL); +} + +/* + *---------------------------------------------------------------------- + * * EventuallyRedrawRange -- * * Ensure that a given range of elements is eventually redrawn on the @@ -3431,7 +3484,7 @@ ListboxListVarProc( /* * If the list length has decreased, then we should clean up selection and - * attributes information for elements past the end of the new list + * attributes information for elements past the end of the new list. */ oldLength = listPtr->nElements; @@ -3549,6 +3602,42 @@ MigrateHashEntries( } /* + *---------------------------------------------------------------------- + * + * GetMaxOffset -- + * + * Passing in a listbox pointer, returns the maximum offset for the box, + * i.e. the maximum possible horizontal scrolling value (in pixels). + * + * Results: + * Listbox's maxOffset. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- +*/ +static int GetMaxOffset( + register Listbox *listPtr) +{ + int maxOffset; + + maxOffset = listPtr->maxWidth - + (Tk_Width(listPtr->tkwin) - 2*listPtr->inset - + 2*listPtr->selBorderWidth) + listPtr->xScrollUnit - 1; + if (maxOffset < 0) { + + /* + * Listbox is larger in width than its largest width item. + */ + + maxOffset = 0; + } + maxOffset -= maxOffset % listPtr->xScrollUnit; + + return maxOffset; +} +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tkMain.c b/generic/tkMain.c index f6f4013..1b21223 100644 --- a/generic/tkMain.c +++ b/generic/tkMain.c @@ -55,7 +55,16 @@ extern int TkCygwinMainEx(int, char **, Tcl_AppInitProc *, Tcl_Interp *); * to strcmp here. */ #ifdef _WIN32 -# include "tclInt.h" +/* Little hack to eliminate the need for "tclInt.h" here: + Just copy a small portion of TclIntPlatStubs, just + enough to make it work. See [600b72bfbc] */ +typedef struct { + int magic; + void *hooks; + void (*dummy[16]) (void); /* dummy entries 0-15, not used */ + int (*tclpIsAtty) (int fd); /* 16 */ +} TclIntPlatStubs; +extern const TclIntPlatStubs *tclIntPlatStubsPtr; # include "tkWinInt.h" #else # define TCHAR char @@ -108,9 +117,9 @@ static int WinIsTty(int fd) { */ #if !defined(STATIC_BUILD) - if (tclStubsPtr->reserved9 && TclpIsAtty) { + if (tclStubsPtr->reserved9 && tclIntPlatStubsPtr->tclpIsAtty) { /* We are running on Cygwin */ - return TclpIsAtty(fd); + return tclIntPlatStubsPtr->tclpIsAtty(fd); } #endif handle = GetStdHandle(STD_INPUT_HANDLE + fd); diff --git a/generic/tkMenu.c b/generic/tkMenu.c index 354d329..7f5389c 100644 --- a/generic/tkMenu.c +++ b/generic/tkMenu.c @@ -38,7 +38,7 @@ * implemented using menu clones. Menu clones are full menus in their own * right; they have a Tk window and pathname associated with them; they have a * TkMenu structure and array of entries. However, they are linked with the - * original menu that they were cloned from. The reflect the attributes of the + * original menu that they were cloned from. They reflect the attributes of the * original, or "master", menu. So if an item is added to a menu, and that * menu has clones, then the item must be added to all of its clones also. * Menus are cloned when a menu is torn-off or when a menu is assigned as a @@ -885,9 +885,14 @@ MenuWidgetObjCmd( * Tearoff menus are posted differently on Mac and Windows than * non-tearoffs. TkpPostMenu does not actually map the menu's window * on those platforms, and popup menus have to be handled specially. + * Also, menubar menues are not intended to be posted (bug 1567681, + * 2160206). */ - if (menuPtr->menuType != TEAROFF_MENU) { + if (menuPtr->menuType == MENUBAR) { + Tcl_AppendResult(interp, "a menubar menu cannot be posted", NULL); + return TCL_ERROR; + } else if (menuPtr->menuType != TEAROFF_MENU) { result = TkpPostMenu(interp, menuPtr, x, y); } else { result = TkPostTearoffMenu(interp, menuPtr, x, y); diff --git a/generic/tkOldConfig.c b/generic/tkOldConfig.c index d2d864f..920d93e 100644 --- a/generic/tkOldConfig.c +++ b/generic/tkOldConfig.c @@ -113,6 +113,10 @@ Tk_ConfigureWidget( staticSpecs = GetCachedSpecs(interp, specs); + for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) { + specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; + } + /* * Pass one: scan through all of the arguments, processing those that * match entries in the specs. @@ -167,7 +171,6 @@ Tk_ConfigureWidget( if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED) || (specPtr->argvName == NULL) || (specPtr->type == TK_CONFIG_SYNONYM)) { - specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; continue; } if (((specPtr->specFlags & needFlags) != needFlags) @@ -1126,7 +1129,6 @@ GetCachedSpecs( specPtr->defValue = Tk_GetUid(specPtr->defValue); } } - specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED; } } else { cachedSpecs = Tcl_GetHashValue(entryPtr); diff --git a/generic/tkOption.c b/generic/tkOption.c index 75dc3b9..24e7fb3 100644 --- a/generic/tkOption.c +++ b/generic/tkOption.c @@ -560,7 +560,7 @@ Tk_GetOption( count -= levelPtr[-1].bases[currentStack]; } - if (currentStack && CLASS) { + if (currentStack & CLASS) { nodeId = winClassId; } else { nodeId = winNameId; @@ -1080,7 +1080,7 @@ ReadOptionFile( * TK_MAX_PRIO. */ { const char *realName; - char *buffer; + Tcl_Obj *buffer; int result, bufferSize; Tcl_Channel chan; Tcl_DString newName; @@ -1108,24 +1108,10 @@ ReadOptionFile( return TCL_ERROR; } - /* - * Compute size of file by seeking to the end of the file. This will - * overallocate if we are performing CRLF translation. - */ - - bufferSize = (int) Tcl_Seek(chan, (Tcl_WideInt) 0, SEEK_END); - Tcl_Seek(chan, (Tcl_WideInt) 0, SEEK_SET); - - if (bufferSize < 0) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "error seeking to end of file \"%s\": %s", - fileName, Tcl_PosixError(interp))); - Tcl_Close(NULL, chan); - return TCL_ERROR; - } - - buffer = ckalloc(bufferSize + 1); - bufferSize = Tcl_Read(chan, buffer, bufferSize); + buffer = Tcl_NewObj(); + Tcl_IncrRefCount(buffer); + Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); + bufferSize = Tcl_ReadChars(chan, buffer, -1, 0); if (bufferSize < 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "error reading file \"%s\": %s", @@ -1134,9 +1120,8 @@ ReadOptionFile( return TCL_ERROR; } Tcl_Close(NULL, chan); - buffer[bufferSize] = 0; - result = AddFromString(interp, tkwin, buffer, priority); - ckfree(buffer); + result = AddFromString(interp, tkwin, Tcl_GetString(buffer), priority); + Tcl_DecrRefCount(buffer); return result; } diff --git a/generic/tkPanedWindow.c b/generic/tkPanedWindow.c index 733610e..f350d0a 100644 --- a/generic/tkPanedWindow.c +++ b/generic/tkPanedWindow.c @@ -147,6 +147,10 @@ typedef struct PanedWindow { GC gc; /* Graphics context for copying from * off-screen pixmap onto screen. */ int proxyx, proxyy; /* Proxy x,y coordinates. */ + Tk_3DBorder proxyBackground;/* Background color used to draw proxy. If NULL, use background. */ + Tcl_Obj *proxyBorderWidthPtr; /* Tcl_Obj rep for proxyBorderWidth */ + int proxyBorderWidth; /* Borderwidth used to draw proxy. */ + int proxyRelief; /* Relief used to draw proxy, if TK_RELIEF_NULL then use relief. */ Slave **slaves; /* Pointer to array of Slaves. */ int numSlaves; /* Number of slaves. */ int sizeofSlaves; /* Number of elements in the slaves array. */ @@ -203,6 +207,8 @@ static void PanedWindowReqProc(ClientData clientData, static void ArrangePanes(ClientData clientData); static void Unlink(Slave *slavePtr); static Slave * GetPane(PanedWindow *pwPtr, Tk_Window tkwin); +static void GetFirstLastVisiblePane(PanedWindow *pwPtr, + int *firstPtr, int *lastPtr); static void SlaveStructureProc(ClientData clientData, XEvent *eventPtr); static int PanedWindowSashCommand(PanedWindow *pwPtr, @@ -296,6 +302,15 @@ static const Tk_OptionSpec optionSpecs[] = { {TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", DEF_PANEDWINDOW_ORIENT, -1, Tk_Offset(PanedWindow, orient), 0, orientStrings, GEOMETRY}, + {TK_OPTION_BORDER, "-proxybackground", "proxyBackground", "ProxyBackground", + 0, -1, Tk_Offset(PanedWindow, proxyBackground), TK_OPTION_NULL_OK, + (ClientData) DEF_PANEDWINDOW_BG_MONO}, + {TK_OPTION_PIXELS, "-proxyborderwidth", "proxyBorderWidth", "ProxyBorderWidth", + DEF_PANEDWINDOW_PROXYBORDER, Tk_Offset(PanedWindow, proxyBorderWidthPtr), + Tk_Offset(PanedWindow, proxyBorderWidth), 0, 0, GEOMETRY}, + {TK_OPTION_RELIEF, "-proxyrelief", "proxyRelief", "Relief", + 0, -1, Tk_Offset(PanedWindow, proxyRelief), + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", DEF_PANEDWINDOW_RELIEF, -1, Tk_Offset(PanedWindow, relief), 0, 0, 0}, {TK_OPTION_CURSOR, "-sashcursor", "sashCursor", "Cursor", @@ -682,6 +697,15 @@ PanedWindowWidgetObjCmd( if (objc <= 4) { tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]), pwPtr->tkwin); + if (tkwin == NULL) { + /* + * Just a plain old bad window; Tk_NameToWindow filled in an + * error message for us. + */ + + result = TCL_ERROR; + break; + } for (i = 0; i < pwPtr->numSlaves; i++) { if (pwPtr->slaves[i]->tkwin == tkwin) { resultObj = Tk_GetOptionInfo(interp, @@ -1329,6 +1353,7 @@ PanedWindowEventProc( XEvent *eventPtr) /* Information about event. */ { PanedWindow *pwPtr = clientData; + int i; if (eventPtr->type == Expose) { if (pwPtr->tkwin != NULL && !(pwPtr->flags & REDRAW_PENDING)) { @@ -1343,6 +1368,18 @@ PanedWindowEventProc( } } else if (eventPtr->type == DestroyNotify) { DestroyPanedWindow(pwPtr); + } else if (eventPtr->type == UnmapNotify) { + for (i = 0; i < pwPtr->numSlaves; i++) { + if (!pwPtr->slaves[i]->hide) { + Tk_UnmapWindow(pwPtr->slaves[i]->tkwin); + } + } + } else if (eventPtr->type == MapNotify) { + for (i = 0; i < pwPtr->numSlaves; i++) { + if (!pwPtr->slaves[i]->hide) { + Tk_MapWindow(pwPtr->slaves[i]->tkwin); + } + } } } @@ -1411,6 +1448,7 @@ DisplayPanedWindow( Tk_Window tkwin = pwPtr->tkwin; int i, sashWidth, sashHeight; const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL); + int first, last; pwPtr->flags &= ~REDRAW_PENDING; if ((pwPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { @@ -1457,9 +1495,10 @@ DisplayPanedWindow( * Draw the sashes. */ + GetFirstLastVisiblePane(pwPtr, &first, &last); for (i = 0; i < pwPtr->numSlaves - 1; i++) { slavePtr = pwPtr->slaves[i]; - if (slavePtr->hide) { + if (slavePtr->hide || i == last) { continue; } if (sashWidth > 0 && sashHeight > 0) { @@ -1705,17 +1744,10 @@ ArrangePanes( Tcl_Preserve(pwPtr); /* - * Find index of last visible pane. + * Find index of first and last visible panes. */ - for (i = 0, last = 0, first = -1; i < pwPtr->numSlaves; i++) { - if (pwPtr->slaves[i]->hide == 0) { - if (first < 0) { - first = i; - } - last = i; - } - } + GetFirstLastVisiblePane(pwPtr, &first, &last); /* * First pass; compute sizes @@ -2053,6 +2085,41 @@ GetPane( } /* + *---------------------------------------------------------------------- + * + * GetFirstLastVisiblePane -- + * + * Given panedwindow, find the index of the first and last visible panes + * of that paned window. + * + * Results: + * Index of the first and last visible panes. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetFirstLastVisiblePane( + PanedWindow *pwPtr, /* Pointer to the paned window info. */ + int *firstPtr, /* Returned index for first. */ + int *lastPtr) /* Returned index for last. */ +{ + int i; + + for (i = 0, *lastPtr = 0, *firstPtr = -1; i < pwPtr->numSlaves; i++) { + if (pwPtr->slaves[i]->hide == 0) { + if (*firstPtr < 0) { + *firstPtr = i; + } + *lastPtr = i; + } + } +} + +/* *-------------------------------------------------------------- * * SlaveStructureProc -- @@ -2553,7 +2620,7 @@ MoveSash( slavePtr->paneWidth = slavePtr->width = slavePtr->sashx - sashOffset - slavePtr->x - (2 * slavePtr->padx); } else { - slavePtr->paneWidth = slavePtr->height = slavePtr->sashy + slavePtr->paneHeight = slavePtr->height = slavePtr->sashy - sashOffset - slavePtr->y - (2 * slavePtr->pady); } } @@ -2726,8 +2793,10 @@ DisplayProxyWindow( * Redraw the widget's background and border. */ - Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, 0, 0, - Tk_Width(tkwin), Tk_Height(tkwin), 2, pwPtr->sashRelief); + Tk_Fill3DRectangle(tkwin, pixmap, + pwPtr->proxyBackground ? pwPtr->proxyBackground : pwPtr->background, + 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), pwPtr->proxyBorderWidth, + (pwPtr->proxyRelief != TK_RELIEF_NULL) ? pwPtr->proxyRelief : pwPtr->sashRelief); #ifndef TK_NO_DOUBLE_BUFFERING /* @@ -2771,6 +2840,7 @@ PanedWindowProxyCommand( PROXY_COORD, PROXY_FORGET, PROXY_PLACE }; int index, x, y, sashWidth, sashHeight; + int internalBW, pwWidth, pwHeight; Tcl_Obj *coords[2]; if (objc < 3) { @@ -2820,11 +2890,16 @@ PanedWindowProxyCommand( return TCL_ERROR; } + internalBW = Tk_InternalBorderWidth(pwPtr->tkwin); if (pwPtr->orient == ORIENT_HORIZONTAL) { if (x < 0) { x = 0; } - y = Tk_InternalBorderWidth(pwPtr->tkwin); + pwWidth = Tk_Width(pwPtr->tkwin) - (2 * internalBW); + if (x > pwWidth) { + x = pwWidth; + } + y = Tk_InternalBorderWidth(pwPtr->tkwin); sashWidth = pwPtr->sashWidth; sashHeight = Tk_Height(pwPtr->tkwin) - (2 * Tk_InternalBorderWidth(pwPtr->tkwin)); @@ -2832,6 +2907,10 @@ PanedWindowProxyCommand( if (y < 0) { y = 0; } + pwHeight = Tk_Height(pwPtr->tkwin) - (2 * internalBW); + if (y > pwHeight) { + y = pwHeight; + } x = Tk_InternalBorderWidth(pwPtr->tkwin); sashHeight = pwPtr->sashWidth; sashWidth = Tk_Width(pwPtr->tkwin) - @@ -2966,6 +3045,7 @@ PanedWindowIdentifyCoords( { int i, sashHeight, sashWidth, thisx, thisy; int found, isHandle, lpad, rpad, tpad, bpad; + int first, last; if (pwPtr->orient == ORIENT_HORIZONTAL) { if (Tk_IsMapped(pwPtr->tkwin)) { @@ -3005,10 +3085,11 @@ PanedWindowIdentifyCoords( lpad = rpad = 0; } + GetFirstLastVisiblePane(pwPtr, &first, &last); isHandle = 0; found = -1; for (i = 0; i < pwPtr->numSlaves - 1; i++) { - if (pwPtr->slaves[i]->hide) { + if (pwPtr->slaves[i]->hide || i == last) { continue; } thisx = pwPtr->slaves[i]->sashx; diff --git a/generic/tkScale.c b/generic/tkScale.c index cc7c294..cbc5202 100644 --- a/generic/tkScale.c +++ b/generic/tkScale.c @@ -303,6 +303,12 @@ Tk_ScaleObjCmd( return TCL_ERROR; } + /* + * The widget was just created, no command callback must be invoked. + */ + + scalePtr->flags &= ~INVOKE_COMMAND; + Tcl_SetObjResult(interp, TkNewWindowObj(scalePtr->tkwin)); return TCL_OK; } @@ -1268,7 +1274,14 @@ TkScaleSetValue( return; } scalePtr->value = value; - if (invokeCommand) { + + /* + * Schedule command callback invocation only if there is such a command + * already registered, otherwise the callback would trigger later when + * configuring the widget -command option even if the value did not change. + */ + + if ((invokeCommand) && (scalePtr->command != NULL)) { scalePtr->flags |= INVOKE_COMMAND; } TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); diff --git a/generic/tkScrollbar.c b/generic/tkScrollbar.c index d453187..5017d30 100644 --- a/generic/tkScrollbar.c +++ b/generic/tkScrollbar.c @@ -622,6 +622,8 @@ TkScrollbarEventProc( TkScrollbarEventuallyRedraw(scrollPtr); } } + } else if (eventPtr->type == MapNotify) { + TkScrollbarEventuallyRedraw(scrollPtr); } } diff --git a/generic/tkSelect.c b/generic/tkSelect.c index ab9018a..74b3964 100644 --- a/generic/tkSelect.c +++ b/generic/tkSelect.c @@ -26,7 +26,7 @@ typedef struct { int charOffset; /* The offset of the next char to retrieve. */ int byteOffset; /* The expected byte offset of the next * chunk. */ - char buffer[TCL_UTF_MAX]; /* A buffer to hold part of a UTF character + char buffer[4]; /* A buffer to hold part of a UTF character * that is split across chunks. */ char command[1]; /* Command to invoke. Actual space is * allocated as large as necessary. This must diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index f621d82..21e6a68 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -38,6 +38,15 @@ MODULE_SCOPE const TkStubs tkStubs; */ #undef Tk_MainEx +#undef Tk_FreeXId + +static void +doNothing(void) +{ + /* dummy implementation, no need to do anything */ +} + +#define Tk_FreeXId ((void (*)(Display *, XID)) doNothing) #ifdef _WIN32 @@ -556,7 +565,7 @@ static const TkIntPlatStubs tkIntPlatStubs = { TkGetTransientMaster, /* 49 */ TkGenerateButtonEvent, /* 50 */ TkGenWMDestroyEvent, /* 51 */ - 0, /* 52 */ + TkMacOSXSetDrawingEnabled, /* 52 */ TkpGetMS, /* 53 */ TkMacOSXDrawable, /* 54 */ TkpScanWindowId, /* 55 */ diff --git a/generic/tkTest.c b/generic/tkTest.c index fa9e073..faba89d 100644 --- a/generic/tkTest.c +++ b/generic/tkTest.c @@ -227,7 +227,7 @@ Tktest_Init( { static int initialized = 0; - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { + if (Tcl_InitStubs(interp, "8.6", 0) == NULL) { return TCL_ERROR; } if (Tk_InitStubs(interp, TK_VERSION, 0) == NULL) { @@ -239,7 +239,7 @@ Tktest_Init( */ if (Tcl_PkgProvideEx(interp, "Tktest", TK_PATCH_LEVEL, NULL) == TCL_ERROR) { - return TCL_ERROR; + return TCL_ERROR; } Tcl_CreateObjCommand(interp, "square", SquareObjCmd, NULL, NULL); diff --git a/generic/tkText.c b/generic/tkText.c index 0d06233..8ae17a5 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -122,7 +122,8 @@ static const Tk_ObjCustomOption lineOption = { static const Tk_OptionSpec optionSpecs[] = { {TK_OPTION_BOOLEAN, "-autoseparators", "autoSeparators", "AutoSeparators", DEF_TEXT_AUTO_SEPARATORS, -1, - Tk_Offset(TkText, autoSeparators), 0, 0, 0}, + Tk_Offset(TkText, autoSeparators), + TK_OPTION_DONT_SET_DEFAULT, 0, 0}, {TK_OPTION_BORDER, "-background", "background", "Background", DEF_TEXT_BG_COLOR, -1, Tk_Offset(TkText, border), 0, DEF_TEXT_BG_MONO, 0}, @@ -193,7 +194,8 @@ static const Tk_OptionSpec optionSpecs[] = { DEF_TEXT_INSERT_WIDTH, -1, Tk_Offset(TkText, insertWidth), 0, 0, 0}, {TK_OPTION_INT, "-maxundo", "maxUndo", "MaxUndo", - DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo), 0, 0, 0}, + DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo), + TK_OPTION_DONT_SET_DEFAULT, 0, 0}, {TK_OPTION_PIXELS, "-padx", "padX", "Pad", DEF_TEXT_PADX, -1, Tk_Offset(TkText, padX), 0, 0, TK_TEXT_LINE_GEOMETRY}, @@ -211,18 +213,18 @@ static const Tk_OptionSpec optionSpecs[] = { TK_OPTION_NULL_OK, DEF_TEXT_SELECT_BD_MONO, 0}, {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", DEF_TEXT_SELECT_FG_COLOR, -1, Tk_Offset(TkText, selFgColorPtr), - TK_CONFIG_NULL_OK, DEF_TEXT_SELECT_FG_MONO, 0}, + TK_OPTION_NULL_OK, DEF_TEXT_SELECT_FG_MONO, 0}, {TK_OPTION_BOOLEAN, "-setgrid", "setGrid", "SetGrid", DEF_TEXT_SET_GRID, -1, Tk_Offset(TkText, setGrid), 0, 0, 0}, {TK_OPTION_PIXELS, "-spacing1", "spacing1", "Spacing", DEF_TEXT_SPACING1, -1, Tk_Offset(TkText, spacing1), - TK_OPTION_DONT_SET_DEFAULT, 0 , TK_TEXT_LINE_GEOMETRY }, + 0, 0 , TK_TEXT_LINE_GEOMETRY }, {TK_OPTION_PIXELS, "-spacing2", "spacing2", "Spacing", DEF_TEXT_SPACING2, -1, Tk_Offset(TkText, spacing2), - TK_OPTION_DONT_SET_DEFAULT, 0 , TK_TEXT_LINE_GEOMETRY }, + 0, 0 , TK_TEXT_LINE_GEOMETRY }, {TK_OPTION_PIXELS, "-spacing3", "spacing3", "Spacing", DEF_TEXT_SPACING3, -1, Tk_Offset(TkText, spacing3), - TK_OPTION_DONT_SET_DEFAULT, 0 , TK_TEXT_LINE_GEOMETRY }, + 0, 0 , TK_TEXT_LINE_GEOMETRY }, {TK_OPTION_CUSTOM, "-startline", NULL, NULL, NULL, -1, Tk_Offset(TkText, start), TK_OPTION_NULL_OK, &lineOption, TK_TEXT_LINE_RANGE}, @@ -239,7 +241,8 @@ static const Tk_OptionSpec optionSpecs[] = { DEF_TEXT_TAKE_FOCUS, -1, Tk_Offset(TkText, takeFocus), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_BOOLEAN, "-undo", "undo", "Undo", - DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo), 0, 0 , 0}, + DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo), + TK_OPTION_DONT_SET_DEFAULT, 0 , 0}, {TK_OPTION_INT, "-width", "width", "Width", DEF_TEXT_WIDTH, -1, Tk_Offset(TkText, width), 0, 0, TK_TEXT_LINE_GEOMETRY}, @@ -401,7 +404,9 @@ static Tcl_Obj * TextGetText(const TkText *textPtr, const TkTextIndex *index1, const TkTextIndex *index2, int visibleOnly); static void GenerateModifiedEvent(TkText *textPtr); +static void GenerateUndoStackEvent(TkText *textPtr); static void UpdateDirtyFlag(TkSharedText *sharedPtr); +static void RunAfterSyncCmd(ClientData clientData); static void TextPushUndoAction(TkText *textPtr, Tcl_Obj *undoString, int insert, const TkTextIndex *index1Ptr, @@ -542,7 +547,7 @@ CreateWidget( Tcl_InitHashTable(&sharedPtr->windowTable, TCL_STRING_KEYS); Tcl_InitHashTable(&sharedPtr->imageTable, TCL_STRING_KEYS); sharedPtr->undoStack = TkUndoInitStack(interp,0); - sharedPtr->undo = 1; + sharedPtr->undo = 0; sharedPtr->isDirty = 0; sharedPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL; sharedPtr->autoSeparators = 1; @@ -580,14 +585,6 @@ CreateWidget( textPtr->end = NULL; } - /* - * Register with the B-tree. In some sense it would be best if we could do - * this later (after configuration options), so that any changes to - * start,end do not require a total recalculation. - */ - - TkBTreeAddClient(sharedPtr->tree, textPtr, textPtr->charHeight); - textPtr->state = TK_TEXT_STATE_NORMAL; textPtr->relief = TK_RELIEF_FLAT; textPtr->cursor = None; @@ -598,6 +595,14 @@ CreateWidget( textPtr->prevHeight = Tk_Height(newWin); /* + * Register with the B-tree. In some sense it would be best if we could do + * this later (after configuration options), so that any changes to + * start,end do not require a total recalculation. + */ + + TkBTreeAddClient(sharedPtr->tree, textPtr, textPtr->charHeight); + + /* * This will add refCounts to textPtr. */ @@ -702,15 +707,16 @@ TextWidgetObjCmd( static const char *const optionStrings[] = { "bbox", "cget", "compare", "configure", "count", "debug", "delete", "dlineinfo", "dump", "edit", "get", "image", "index", "insert", - "mark", "peer", "replace", "scan", "search", "see", "tag", "window", - "xview", "yview", NULL + "mark", "peer", "pendingsync", "replace", "scan", "search", + "see", "sync", "tag", "window", "xview", "yview", NULL }; enum options { TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT, TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT, TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK, - TEXT_PEER, TEXT_REPLACE, TEXT_SCAN, TEXT_SEARCH, TEXT_SEE, - TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, TEXT_YVIEW + TEXT_PEER, TEXT_PENDINGSYNC, TEXT_REPLACE, TEXT_SCAN, + TEXT_SEARCH, TEXT_SEE, TEXT_SYNC, TEXT_TAG, TEXT_WINDOW, + TEXT_XVIEW, TEXT_YVIEW }; if (objc < 2) { @@ -917,43 +923,43 @@ TextWidgetObjCmd( * We're going to count up all display lines in the logical * line of 'indexFromPtr' up to, but not including the logical * line of 'indexToPtr' (except if this line is elided), and - * then subtract off what came in too much from elided lines, - * also subtract off what we didn't want from 'from' and add + * then subtract off what came in too much from elided lines, + * also subtract off what we didn't want from 'from' and add * on what we didn't count from 'to'. */ - while (TkTextIndexCmp(&index,indexToPtr) < 0) { + while (TkTextIndexCmp(&index,indexToPtr) < 0) { value += TkTextUpdateOneLine(textPtr, index.linePtr, - 0, &index, 0); + 0, &index, 0); } - index2 = index; - - /* - * Now we need to adjust the count to: - * - subtract off the number of display lines between - * indexToPtr and index2, since we might have skipped past - * indexToPtr, if we have several logical lines in a - * single display line - * - subtract off the number of display lines overcounted - * in the first logical line - * - add on the number of display lines in the last logical - * line - * This logic is still ok if both indexFromPtr and indexToPtr - * are in the same logical line. - */ - - index = *indexToPtr; - index.byteIndex = 0; - while (TkTextIndexCmp(&index,&index2) < 0) { - value -= TkTextUpdateOneLine(textPtr, index.linePtr, - 0, &index, 0); - } + index2 = index; + + /* + * Now we need to adjust the count to: + * - subtract off the number of display lines between + * indexToPtr and index2, since we might have skipped past + * indexToPtr, if we have several logical lines in a + * single display line + * - subtract off the number of display lines overcounted + * in the first logical line + * - add on the number of display lines in the last logical + * line + * This logic is still ok if both indexFromPtr and indexToPtr + * are in the same logical line. + */ + + index = *indexToPtr; + index.byteIndex = 0; + while (TkTextIndexCmp(&index,&index2) < 0) { + value -= TkTextUpdateOneLine(textPtr, index.linePtr, + 0, &index, 0); + } index.linePtr = indexFromPtr->linePtr; index.byteIndex = 0; while (1) { TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL); - if (TkTextIndexCmp(&index,indexFromPtr) >= 0) { + if (TkTextIndexCmp(&index,indexFromPtr) >= 0) { break; } TkTextIndexForwBytes(textPtr, &index, 1, &index); @@ -965,7 +971,7 @@ TextWidgetObjCmd( index.byteIndex = 0; while (1) { TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL); - if (TkTextIndexCmp(&index,indexToPtr) >= 0) { + if (TkTextIndexCmp(&index,indexToPtr) >= 0) { break; } TkTextIndexForwBytes(textPtr, &index, 1, &index); @@ -1392,6 +1398,16 @@ TextWidgetObjCmd( case TEXT_PEER: result = TextPeerCmd(textPtr, interp, objc, objv); break; + case TEXT_PENDINGSYNC: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + result = TCL_ERROR; + goto done; + } + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(TkTextPendingsync(textPtr))); + break; + } case TEXT_REPLACE: { const TkTextIndex *indexFromPtr, *indexToPtr; @@ -1506,6 +1522,39 @@ TextWidgetObjCmd( case TEXT_SEE: result = TkTextSeeCmd(textPtr, interp, objc, objv); break; + case TEXT_SYNC: { + if (objc == 4) { + Tcl_Obj *cmd = objv[3]; + const char *option = Tcl_GetString(objv[2]); + if (strncmp(option, "-command", objv[2]->length)) { + Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL); + result = TCL_ERROR; + goto done; + } + Tcl_IncrRefCount(cmd); + if (TkTextPendingsync(textPtr)) { + if (textPtr->afterSyncCmd) { + Tcl_DecrRefCount(textPtr->afterSyncCmd); + } + textPtr->afterSyncCmd = cmd; + } else { + textPtr->afterSyncCmd = cmd; + Tcl_DoWhenIdle(RunAfterSyncCmd, (ClientData) textPtr); + } + break; + } else if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); + result = TCL_ERROR; + goto done; + } + if (textPtr->afterSyncCmd) { + Tcl_DecrRefCount(textPtr->afterSyncCmd); + } + textPtr->afterSyncCmd = NULL; + TkTextUpdateLineMetrics(textPtr, 1, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); + break; + } case TEXT_TAG: result = TkTextTagCmd(textPtr, interp, objc, objv); break; @@ -1995,6 +2044,10 @@ DestroyText( textPtr->tkwin = NULL; textPtr->refCount--; Tcl_DeleteCommandFromToken(textPtr->interp, textPtr->widgetCmd); + if (textPtr->afterSyncCmd){ + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = NULL; + } if (textPtr->refCount == 0) { ckfree(textPtr); } @@ -2044,7 +2097,7 @@ ConfigureText( textPtr->sharedTextPtr->maxUndo = textPtr->maxUndo; textPtr->sharedTextPtr->autoSeparators = textPtr->autoSeparators; - TkUndoSetDepth(textPtr->sharedTextPtr->undoStack, + TkUndoSetMaxDepth(textPtr->sharedTextPtr->undoStack, textPtr->sharedTextPtr->maxUndo); /* @@ -2142,10 +2195,10 @@ ConfigureText( * Also, clamp the insert and current (unshared) marks to the new * -startline/-endline range limits of the widget. All other (shared) * marks are unchanged. - * The return value of TkTextMarkNameToIndex does not need to be - * checked: "insert" and "current" marks always exist, and the - * purpose of the code below precisely is to move them inside the - * -startline/-endline range. + * The return value of TkTextMarkNameToIndex does not need to be + * checked: "insert" and "current" marks always exist, and the + * purpose of the code below precisely is to move them inside the + * -startline/-endline range. */ textPtr->sharedTextPtr->stateEpoch++; @@ -2204,12 +2257,20 @@ ConfigureText( * replaced in the widget record. */ - textPtr->selTagPtr->border = textPtr->selBorder; + if (textPtr->selTagPtr->selBorder == NULL) { + textPtr->selTagPtr->border = textPtr->selBorder; + } else { + textPtr->selTagPtr->selBorder = textPtr->selBorder; + } if (textPtr->selTagPtr->borderWidthPtr != textPtr->selBorderWidthPtr) { textPtr->selTagPtr->borderWidthPtr = textPtr->selBorderWidthPtr; textPtr->selTagPtr->borderWidth = textPtr->selBorderWidth; } - textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr; + if (textPtr->selTagPtr->selFgColor == NULL) { + textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr; + } else { + textPtr->selTagPtr->selFgColor = textPtr->selFgColorPtr; + } textPtr->selTagPtr->affectsDisplay = 0; textPtr->selTagPtr->affectsDisplayGeometry = 0; if ((textPtr->selTagPtr->elideString != NULL) @@ -2228,12 +2289,18 @@ ConfigureText( textPtr->selTagPtr->affectsDisplayGeometry = 1; } if ((textPtr->selTagPtr->border != NULL) + || (textPtr->selTagPtr->selBorder != NULL) || (textPtr->selTagPtr->reliefString != NULL) || (textPtr->selTagPtr->bgStipple != None) || (textPtr->selTagPtr->fgColor != NULL) + || (textPtr->selTagPtr->selFgColor != NULL) || (textPtr->selTagPtr->fgStipple != None) || (textPtr->selTagPtr->overstrikeString != NULL) - || (textPtr->selTagPtr->underlineString != NULL)) { + || (textPtr->selTagPtr->overstrikeColor != NULL) + || (textPtr->selTagPtr->underlineString != NULL) + || (textPtr->selTagPtr->underlineColor != NULL) + || (textPtr->selTagPtr->lMarginColor != NULL) + || (textPtr->selTagPtr->rMarginColor != NULL)) { textPtr->selTagPtr->affectsDisplay = 1; } TkTextRedrawTag(NULL, textPtr, NULL, NULL, textPtr->selTagPtr, 1); @@ -2344,6 +2411,7 @@ TextWorldChanged( { Tk_FontMetrics fm; int border; + int oldCharHeight = textPtr->charHeight; textPtr->charWidth = Tk_TextWidth(textPtr->tkfont, "0", 1); if (textPtr->charWidth <= 0) { @@ -2355,6 +2423,9 @@ TextWorldChanged( if (textPtr->charHeight <= 0) { textPtr->charHeight = 1; } + if (textPtr->charHeight != oldCharHeight) { + TkBTreeClientRangeChanged(textPtr, textPtr->charHeight); + } border = textPtr->borderWidth + textPtr->highlightWidth; Tk_GeometryRequest(textPtr->tkwin, textPtr->width * textPtr->charWidth + 2*textPtr->padX + 2*border, @@ -2702,6 +2773,10 @@ TextPushUndoAction( /* Index describing second location. */ { TkUndoSubAtom *iAtom, *dAtom; + int canUndo, canRedo; + char lMarkName[20] = "tk::undoMarkL"; + char rMarkName[20] = "tk::undoMarkR"; + char stringUndoMarkId[7] = ""; /* * Create the helpers. @@ -2712,6 +2787,10 @@ TextPushUndoAction( Tcl_Obj *markSet2InsertObj = NULL; Tcl_Obj *insertCmdObj = Tcl_NewObj(); Tcl_Obj *deleteCmdObj = Tcl_NewObj(); + Tcl_Obj *markSetLUndoMarkCmdObj = Tcl_NewObj(); + Tcl_Obj *markSetRUndoMarkCmdObj = NULL; + Tcl_Obj *markGravityLUndoMarkCmdObj = Tcl_NewObj(); + Tcl_Obj *markGravityRUndoMarkCmdObj = NULL; /* * Get the index positions. @@ -2761,6 +2840,40 @@ TextPushUndoAction( Tcl_ListObjAppendElement(NULL, deleteCmdObj, index1Obj); Tcl_ListObjAppendElement(NULL, deleteCmdObj, index2Obj); + Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj, + Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1)); + Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj, + Tcl_NewStringObj("mark", 4)); + Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj, + Tcl_NewStringObj("set", 3)); + markSetRUndoMarkCmdObj = Tcl_DuplicateObj(markSetLUndoMarkCmdObj); + textPtr->sharedTextPtr->undoMarkId++; + sprintf(stringUndoMarkId, "%d", textPtr->sharedTextPtr->undoMarkId); + strcat(lMarkName, stringUndoMarkId); + strcat(rMarkName, stringUndoMarkId); + Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj, + Tcl_NewStringObj(lMarkName, -1)); + Tcl_ListObjAppendElement(NULL, markSetRUndoMarkCmdObj, + Tcl_NewStringObj(rMarkName, -1)); + Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj, index1Obj); + Tcl_ListObjAppendElement(NULL, markSetRUndoMarkCmdObj, index2Obj); + + Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj, + Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1)); + Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj, + Tcl_NewStringObj("mark", 4)); + Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj, + Tcl_NewStringObj("gravity", 7)); + markGravityRUndoMarkCmdObj = Tcl_DuplicateObj(markGravityLUndoMarkCmdObj); + Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj, + Tcl_NewStringObj(lMarkName, -1)); + Tcl_ListObjAppendElement(NULL, markGravityRUndoMarkCmdObj, + Tcl_NewStringObj(rMarkName, -1)); + Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj, + Tcl_NewStringObj("left", 4)); + Tcl_ListObjAppendElement(NULL, markGravityRUndoMarkCmdObj, + Tcl_NewStringObj("right", 5)); + /* * Note: we don't wish to use textPtr->widgetCmd in these callbacks * because if we delete the textPtr, but peers still exist, we will then @@ -2778,16 +2891,27 @@ TextPushUndoAction( insertCmdObj, NULL); TkUndoMakeCmdSubAtom(NULL, markSet2InsertObj, iAtom); TkUndoMakeCmdSubAtom(NULL, seeInsertObj, iAtom); + TkUndoMakeCmdSubAtom(NULL, markSetLUndoMarkCmdObj, iAtom); + TkUndoMakeCmdSubAtom(NULL, markSetRUndoMarkCmdObj, iAtom); + TkUndoMakeCmdSubAtom(NULL, markGravityLUndoMarkCmdObj, iAtom); + TkUndoMakeCmdSubAtom(NULL, markGravityRUndoMarkCmdObj, iAtom); dAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, textPtr->sharedTextPtr, deleteCmdObj, NULL); TkUndoMakeCmdSubAtom(NULL, markSet1InsertObj, dAtom); TkUndoMakeCmdSubAtom(NULL, seeInsertObj, dAtom); + TkUndoMakeCmdSubAtom(NULL, markSetLUndoMarkCmdObj, dAtom); + TkUndoMakeCmdSubAtom(NULL, markSetRUndoMarkCmdObj, dAtom); + TkUndoMakeCmdSubAtom(NULL, markGravityLUndoMarkCmdObj, dAtom); + TkUndoMakeCmdSubAtom(NULL, markGravityRUndoMarkCmdObj, dAtom); Tcl_DecrRefCount(seeInsertObj); Tcl_DecrRefCount(index1Obj); Tcl_DecrRefCount(index2Obj); + canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack); + canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack); + /* * Depending whether the action is to insert or delete, we provide the * appropriate second and third arguments to TkUndoPushAction. (The first @@ -2799,6 +2923,10 @@ TextPushUndoAction( } else { TkUndoPushAction(textPtr->sharedTextPtr->undoStack, dAtom, iAtom); } + + if (!canUndo || canRedo) { + GenerateUndoStackEvent(textPtr); + } } /* @@ -2963,7 +3091,7 @@ CountIndices( * If 'viewUpdate' is true, we may adjust the window contents' * y-position, and scrollbar setting. * - * If 'viewUpdate' is false, true we can guarantee that textPtr->topIndex + * If 'viewUpdate' is true we can guarantee that textPtr->topIndex * points to a valid TkTextLine after this function returns. However, if * 'viewUpdate' is false, then there is no such guarantee (since * topIndex.linePtr can be garbage). The caller is expected to take @@ -3023,12 +3151,15 @@ DeleteIndexRange( * dummy empty line at the end of the text. If the final newline of the * file (just before the dummy line) is being deleted, then back up index * to just before the newline. If there is a newline just before the first - * character being deleted, then back up the first index too, so that an - * even number of lines gets deleted. Furthermore, remove any tags that - * are present on the newline that isn't going to be deleted after all - * (this simulates deleting the newline and then adding a "clean" one back - * again). Note that index1 and index2 might now be equal again which - * means that no text will be deleted but tags might be removed. + * character being deleted, then back up the first index too. The idea is + * that a deletion involving a range starting at a line start and + * including the final \n (i.e. index2 is "end") is an attempt to delete + * complete lines, so the \n before the deleted block shall become the new + * final \n. Furthermore, remove any tags that are present on the newline + * that isn't going to be deleted after all (this simulates deleting the + * newline and then adding a "clean" one back again). Note that index1 and + * index2 might now be equal again which means that no text will be + * deleted but tags might be removed. */ line1 = TkBTreeLinesTo(textPtr, index1.linePtr); @@ -3132,11 +3263,11 @@ DeleteIndexRange( resetView = 1; line = line1; byteIndex = tPtr->topIndex.byteIndex; - } else { - /* - * Deletion range starts after the top line. This peers's view - * will not need to be reset. Nothing to do. - */ + } else { + /* + * Deletion range starts after the top line. This peers's view + * will not need to be reset. Nothing to do. + */ } } else if (index2.linePtr == tPtr->topIndex.linePtr) { /* @@ -3153,11 +3284,11 @@ DeleteIndexRange( } else { byteIndex -= (index2.byteIndex - index1.byteIndex); } - } else { - /* - * Deletion range ends before the top line. This peers's view - * will not need to be reset. Nothing to do. - */ + } else { + /* + * Deletion range ends before the top line. This peers's view + * will not need to be reset. Nothing to do. + */ } if (resetView) { lineAndByteIndex[resetViewCount] = line; @@ -3202,43 +3333,43 @@ DeleteIndexRange( TkTextIndex indexTmp; if (tPtr == textPtr) { - if (viewUpdate) { - /* - * line cannot be before -startline of textPtr because - * this line corresponds to an index which is necessarily - * between "1.0" and "end" relative to textPtr. - * Therefore no need to clamp line to the -start/-end - * range. - */ + if (viewUpdate) { + /* + * line cannot be before -startline of textPtr because + * this line corresponds to an index which is necessarily + * between "1.0" and "end" relative to textPtr. + * Therefore no need to clamp line to the -start/-end + * range. + */ TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, line, byteIndex, &indexTmp); TkTextSetYView(tPtr, &indexTmp, 0); } } else { - TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, line, + TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, line, byteIndex, &indexTmp); - /* - * line may be before -startline of tPtr and must be - * clamped to -startline before providing it to - * TkTextSetYView otherwise lines before -startline - * would be displayed. - * There is no need to worry about -endline however, - * because the view will only be reset if the deletion - * involves the TOP line of the screen - */ - - if (tPtr->start != NULL) { - int start; - TkTextIndex indexStart; - - start = TkBTreeLinesTo(NULL, tPtr->start); - TkTextMakeByteIndex(sharedTextPtr->tree, NULL, start, + /* + * line may be before -startline of tPtr and must be + * clamped to -startline before providing it to + * TkTextSetYView otherwise lines before -startline + * would be displayed. + * There is no need to worry about -endline however, + * because the view will only be reset if the deletion + * involves the TOP line of the screen + */ + + if (tPtr->start != NULL) { + int start; + TkTextIndex indexStart; + + start = TkBTreeLinesTo(NULL, tPtr->start); + TkTextMakeByteIndex(sharedTextPtr->tree, NULL, start, 0, &indexStart); - if (TkTextIndexCmp(&indexTmp, &indexStart) < 0) { - indexTmp = indexStart; - } - } + if (TkTextIndexCmp(&indexTmp, &indexStart) < 0) { + indexTmp = indexStart; + } + } TkTextSetYView(tPtr, &indexTmp, 0); } } @@ -3484,16 +3615,7 @@ TkTextSelectionEvent( * event generate $textWidget <<Selection>> */ - union {XEvent general; XVirtualEvent virtual;} event; - - memset(&event, 0, sizeof(event)); - event.general.xany.type = VirtualEvent; - event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); - event.general.xany.send_event = False; - event.general.xany.window = Tk_WindowId(textPtr->tkwin); - event.general.xany.display = Tk_Display(textPtr->tkwin); - event.virtual.name = Tk_GetUid("Selection"); - Tk_HandleEvent(&event.general); + TkSendVirtualEvent(textPtr->tkwin, "Selection", NULL); } /* @@ -4240,7 +4362,11 @@ TextSearchFoundMatch( matchOffset += Tcl_NumUtfChars(segPtr->body.chars, -1); } } else { - leftToScan -= segPtr->size; + if (searchSpecPtr->exact) { + leftToScan -= segPtr->size; + } else { + leftToScan -= Tcl_NumUtfChars(segPtr->body.chars, -1); + } } curIndex.byteIndex += segPtr->size; } @@ -4382,7 +4508,7 @@ TkTextGetTabs( Tcl_Obj **objv; TkTextTabArray *tabArrayPtr; TkTextTab *tabPtr; - Tcl_UniChar ch; + int ch; double prevStop, lastStop; /* * Map these strings to TkTextTabAlign values. @@ -4489,7 +4615,7 @@ TkTextGetTabs( * There may be a more efficient way of getting this. */ - Tcl_UtfToUniChar(Tcl_GetString(objv[i+1]), &ch); + TkUtfToUniChar(Tcl_GetString(objv[i+1]), &ch); if (!Tcl_UniCharIsAlpha(ch)) { continue; } @@ -4992,6 +5118,8 @@ TextEditUndo( TkText *textPtr) /* Overall information about text widget. */ { int status; + Tcl_Obj *cmdObj; + int code; if (!textPtr->sharedTextPtr->undo) { return TCL_OK; @@ -5015,6 +5143,22 @@ TextEditUndo( } textPtr->sharedTextPtr->undo = 1; + /* + * Convert undo/redo temporary marks set by TkUndoRevert() into + * indices left in the interp result. + */ + + cmdObj = Tcl_ObjPrintf("::tk::TextUndoRedoProcessMarks %s", + Tk_PathName(textPtr->tkwin)); + Tcl_IncrRefCount(cmdObj); + code = Tcl_EvalObjEx(textPtr->interp, cmdObj, TCL_EVAL_GLOBAL); + if (code != TCL_OK) { + Tcl_AddErrorInfo(textPtr->interp, + "\n (on undoing)"); + Tcl_BackgroundException(textPtr->interp, code); + } + Tcl_DecrRefCount(cmdObj); + return status; } @@ -5040,6 +5184,8 @@ TextEditRedo( TkText *textPtr) /* Overall information about text widget. */ { int status; + Tcl_Obj *cmdObj; + int code; if (!textPtr->sharedTextPtr->undo) { return TCL_OK; @@ -5062,6 +5208,23 @@ TextEditRedo( textPtr->sharedTextPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL; } textPtr->sharedTextPtr->undo = 1; + + /* + * Convert undo/redo temporary marks set by TkUndoApply() into + * indices left in the interp result. + */ + + cmdObj = Tcl_ObjPrintf("::tk::TextUndoRedoProcessMarks %s", + Tk_PathName(textPtr->tkwin)); + Tcl_IncrRefCount(cmdObj); + code = Tcl_EvalObjEx(textPtr->interp, cmdObj, TCL_EVAL_GLOBAL); + if (code != TCL_OK) { + Tcl_AddErrorInfo(textPtr->interp, + "\n (on undoing)"); + Tcl_BackgroundException(textPtr->interp, code); + } + Tcl_DecrRefCount(cmdObj); + return status; } @@ -5090,11 +5253,16 @@ TextEditCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { int index, setModified, oldModified; + int canRedo = 0; + int canUndo = 0; + static const char *const editOptionStrings[] = { - "modified", "redo", "reset", "separator", "undo", NULL + "canundo", "canredo", "modified", "redo", "reset", "separator", + "undo", NULL }; enum editOptions { - EDIT_MODIFIED, EDIT_REDO, EDIT_RESET, EDIT_SEPARATOR, EDIT_UNDO + EDIT_CANUNDO, EDIT_CANREDO, EDIT_MODIFIED, EDIT_REDO, EDIT_RESET, + EDIT_SEPARATOR, EDIT_UNDO }; if (objc < 3) { @@ -5108,6 +5276,26 @@ TextEditCmd( } switch ((enum editOptions) index) { + case EDIT_CANREDO: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + if (textPtr->sharedTextPtr->undo) { + canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack); + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canRedo)); + break; + case EDIT_CANUNDO: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 3, objv, NULL); + return TCL_ERROR; + } + if (textPtr->sharedTextPtr->undo) { + canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack); + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canUndo)); + break; case EDIT_MODIFIED: if (objc == 3) { Tcl_SetObjResult(interp, @@ -5149,18 +5337,28 @@ TextEditCmd( Tcl_WrongNumArgs(interp, 3, objv, NULL); return TCL_ERROR; } + canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack); if (TextEditRedo(textPtr)) { Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to redo", -1)); Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_REDO", NULL); return TCL_ERROR; } + canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack); + if (!canUndo || !canRedo) { + GenerateUndoStackEvent(textPtr); + } break; case EDIT_RESET: if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, NULL); return TCL_ERROR; } + canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack); + canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack); TkUndoClearStacks(textPtr->sharedTextPtr->undoStack); + if (canUndo || canRedo) { + GenerateUndoStackEvent(textPtr); + } break; case EDIT_SEPARATOR: if (objc != 3) { @@ -5174,11 +5372,16 @@ TextEditCmd( Tcl_WrongNumArgs(interp, 3, objv, NULL); return TCL_ERROR; } + canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack); if (TextEditUndo(textPtr)) { Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to undo", -1)); Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_UNDO", NULL); return TCL_ERROR; } + canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack); + if (!canRedo || !canUndo) { + GenerateUndoStackEvent(textPtr); + } break; } return TCL_OK; @@ -5273,6 +5476,7 @@ TextGetText( * * Send an event that the text was modified. This is equivalent to: * event generate $textWidget <<Modified>> + * for all peers of $textWidget. * * Results: * None @@ -5287,21 +5491,41 @@ static void GenerateModifiedEvent( TkText *textPtr) /* Information about text widget. */ { - union { - XEvent general; - XVirtualEvent virtual; - } event; - - Tk_MakeWindowExist(textPtr->tkwin); - - memset(&event, 0, sizeof(event)); - event.general.xany.type = VirtualEvent; - event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); - event.general.xany.send_event = False; - event.general.xany.window = Tk_WindowId(textPtr->tkwin); - event.general.xany.display = Tk_Display(textPtr->tkwin); - event.virtual.name = Tk_GetUid("Modified"); - Tk_HandleEvent(&event.general); + for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL; + textPtr = textPtr->next) { + Tk_MakeWindowExist(textPtr->tkwin); + TkSendVirtualEvent(textPtr->tkwin, "Modified", NULL); + } +} + +/* + *---------------------------------------------------------------------- + * + * GenerateUndoStackEvent -- + * + * Send an event that the undo or redo stack became empty or unempty. + * This is equivalent to: + * event generate $textWidget <<UndoStack>> + * for all peers of $textWidget. + * + * Results: + * None + * + * Side effects: + * May force the text window (and all peers) into existence. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateUndoStackEvent( + TkText *textPtr) /* Information about text widget. */ +{ + for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL; + textPtr = textPtr->next) { + Tk_MakeWindowExist(textPtr->tkwin); + TkSendVirtualEvent(textPtr->tkwin, "UndoStack", NULL); + } } /* @@ -5325,7 +5549,6 @@ UpdateDirtyFlag( TkSharedText *sharedTextPtr)/* Information about text widget. */ { int oldDirtyFlag; - TkText *textPtr; /* * If we've been forced to be dirty, we stay dirty (until explicitly @@ -5356,11 +5579,54 @@ UpdateDirtyFlag( } if (sharedTextPtr->isDirty == 0 || oldDirtyFlag == 0) { - for (textPtr = sharedTextPtr->peers; textPtr != NULL; - textPtr = textPtr->next) { - GenerateModifiedEvent(textPtr); + GenerateModifiedEvent(sharedTextPtr->peers); + } +} + +/* + *---------------------------------------------------------------------- + * + * RunAfterSyncCmd -- + * + * This function is called by the event loop and executes the command + * scheduled by [.text sync -command $cmd]. + * + * Results: + * None. + * + * Side effects: + * Anything may happen, depending on $cmd contents. + * + *---------------------------------------------------------------------- + */ + +static void +RunAfterSyncCmd( + ClientData clientData) /* Information about text widget. */ +{ + register TkText *textPtr = (TkText *) clientData; + int code; + + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + /* + * The widget has been deleted. Don't do anything. + */ + + if (--textPtr->refCount == 0) { + ckfree((char *) textPtr); } + return; + } + + Tcl_Preserve((ClientData) textPtr->interp); + code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); + if (code == TCL_ERROR) { + Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); + Tcl_BackgroundError(textPtr->interp); } + Tcl_Release((ClientData) textPtr->interp); + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = NULL; } /* @@ -5700,7 +5966,7 @@ SearchCore( CLANG_ASSERT(pattern); do { - Tcl_UniChar ch; + int ch; const char *p; int lastFullLine = lastOffset; @@ -5930,7 +6196,7 @@ SearchCore( } } else { firstOffset = p - startOfLine + - Tcl_UtfToUniChar(startOfLine+matchOffset,&ch); + TkUtfToUniChar(startOfLine+matchOffset,&ch); } } } while (searchSpecPtr->all); diff --git a/generic/tkText.h b/generic/tkText.h index 99a4888..430c96b 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -168,7 +168,7 @@ typedef struct TkTextSegment { int size; /* Size of this segment (# of bytes of index * space it occupies). */ union { - char chars[1]; /* Characters that make up character info. + char chars[2]; /* Characters that make up character info. * Actual length varies to hold as many * characters as needed.*/ TkTextToggle toggle; /* Information about tag toggle. */ @@ -347,6 +347,9 @@ typedef struct TkTextTag { int lMargin2; /* Left margin for second and later display * lines of each text line, in pixels. Only * valid if lMargin2String is non-NULL. */ + Tk_3DBorder lMarginColor; /* Used for drawing background in left margins. + * This is used for both lmargin1 and lmargin2. + * NULL means no value specified here. */ char *offsetString; /* -offset option string (malloc-ed). NULL * means option not specified. */ int offset; /* Vertical offset of text's baseline from @@ -358,10 +361,18 @@ typedef struct TkTextTag { int overstrike; /* Non-zero means draw horizontal line through * middle of text. Only valid if * overstrikeString is non-NULL. */ + XColor *overstrikeColor; /* Color for the overstrike. NULL means same + * color as foreground. */ char *rMarginString; /* -rmargin option string (malloc-ed). NULL * means option not specified. */ int rMargin; /* Right margin for text, in pixels. Only * valid if rMarginString is non-NULL. */ + Tk_3DBorder rMarginColor; /* Used for drawing background in right margin. + * NULL means no value specified here. */ + Tk_3DBorder selBorder; /* Used for drawing background for selected text. + * NULL means no value specified here. */ + XColor *selFgColor; /* Foreground color for selected text. NULL means + * no value specified here. */ char *spacing1String; /* -spacing1 option string (malloc-ed). NULL * means option not specified. */ int spacing1; /* Extra spacing above first display line for @@ -389,6 +400,8 @@ typedef struct TkTextTag { int underline; /* Non-zero means draw underline underneath * text. Only valid if underlineString is * non-NULL. */ + XColor *underlineColor; /* Color for the underline. NULL means same + * color as foreground. */ TkWrapMode wrapMode; /* How to handle wrap-around for this tag. * Must be TEXT_WRAPMODE_CHAR, * TEXT_WRAPMODE_NONE, TEXT_WRAPMODE_WORD, or @@ -567,6 +580,8 @@ typedef struct TkSharedText { * statements. */ int autoSeparators; /* Non-zero means the separators will be * inserted automatically. */ + int undoMarkId; /* Counts undo marks temporarily used during + undo and redo operations. */ int isDirty; /* Flag indicating the 'dirtyness' of the * text widget. If the flag is not zero, * unsaved modifications have been applied to @@ -785,6 +800,8 @@ typedef struct TkText { * statements. */ int autoSeparators; /* Non-zero means the separators will be * inserted automatically. */ + Tcl_Obj *afterSyncCmd; /* Command to be executed when lines are up to + * date */ } TkText; /* @@ -1109,6 +1126,7 @@ MODULE_SCOPE int TkTextMarkNameToIndex(TkText *textPtr, MODULE_SCOPE void TkTextMarkSegToIndex(TkText *textPtr, TkTextSegment *markPtr, TkTextIndex *indexPtr); MODULE_SCOPE void TkTextEventuallyRepick(TkText *textPtr); +MODULE_SCOPE Bool TkTextPendingsync(TkText *textPtr); MODULE_SCOPE void TkTextPickCurrent(TkText *textPtr, XEvent *eventPtr); MODULE_SCOPE void TkTextPixelIndex(TkText *textPtr, int x, int y, TkTextIndex *indexPtr, int *nearest); diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c index 7383d21..0fdc280 100644 --- a/generic/tkTextBTree.c +++ b/generic/tkTextBTree.c @@ -1112,7 +1112,7 @@ TkBTreeInsertChars( /* * I don't believe it's possible for either of the two lines passed to * this function to be the last line of text, but the function is robust - * to that case anyway. (We must never re-calculated the line height of + * to that case anyway. (We must never re-calculate the line height of * the last line). */ diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 01ec22d..eb917cf 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -136,11 +136,15 @@ typedef struct StyleValues { * line of each text line. */ int lMargin2; /* Left margin, in pixels, for second and * later display lines of each text line. */ + Tk_3DBorder lMarginColor; /* Color of left margins (1 and 2). */ int offset; /* Offset in pixels of baseline, relative to * baseline of line. */ int overstrike; /* Non-zero means draw overstrike through * text. */ + XColor *overstrikeColor; /* Foreground color for overstrike through + * text. */ int rMargin; /* Right margin, in pixels. */ + Tk_3DBorder rMarginColor; /* Color of right margin. */ int spacing1; /* Spacing above first dline in text line. */ int spacing2; /* Spacing between lines of dline. */ int spacing3; /* Spacing below last dline in text line. */ @@ -149,6 +153,8 @@ typedef struct StyleValues { int tabStyle; /* One of TABULAR or WORDPROCESSOR. */ int underline; /* Non-zero means draw underline underneath * text. */ + XColor *underlineColor; /* Foreground color for underline underneath + * text. */ int elide; /* Zero means draw text, otherwise not. */ TkWrapMode wrapMode; /* How to handle wrap-around for this tag. * One of TEXT_WRAPMODE_CHAR, @@ -167,6 +173,8 @@ typedef struct TextStyle { GC bgGC; /* Graphics context for background. None means * use widget background. */ GC fgGC; /* Graphics context for foreground. */ + GC ulGC; /* Graphics context for underline. */ + GC ovGC; /* Graphics context for overstrike. */ StyleValues *sValuePtr; /* Raw information from which GCs were * derived. */ Tcl_HashEntry *hPtr; /* Pointer to entry in styleTable. Used to @@ -234,6 +242,14 @@ typedef struct DLine { int spaceBelow; /* How much extra space was added to the * bottom of the line because of spacing * options. This is included in height. */ + Tk_3DBorder lMarginColor; /* Background color of the area corresponding + * to the left margin of the display line. */ + int lMarginWidth; /* Pixel width of the area corresponding to + * the left margin. */ + Tk_3DBorder rMarginColor; /* Background color of the area corresponding + * to the right margin of the display line. */ + int rMarginWidth; /* Pixel width of the area corresponding to + * the right margin. */ int length; /* Total length of line, in pixels. */ TkTextDispChunk *chunkPtr; /* Pointer to first chunk in list of all of * those that are displayed on this line of @@ -591,9 +607,10 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp, Tcl_Obj *const objv[], double *dblPtr, int *intPtr); static void AsyncUpdateLineMetrics(ClientData clientData); +static void GenerateWidgetViewSyncEvent(TkText *textPtr, Bool InSync); static void AsyncUpdateYScrollbar(ClientData clientData); static int IsStartOfNotMergedLine(TkText *textPtr, - CONST TkTextIndex *indexPtr); + const TkTextIndex *indexPtr); /* * Result values returned by TextGetScrollInfoObj: @@ -659,17 +676,8 @@ TkTextCreateDInfo( dInfoPtr->metricEpoch = -1; dInfoPtr->metricIndex.textPtr = NULL; dInfoPtr->metricIndex.linePtr = NULL; - - /* - * Add a refCount for each of the idle call-backs. - */ - - textPtr->refCount++; - dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(0, - AsyncUpdateLineMetrics, textPtr); - textPtr->refCount++; - dInfoPtr->scrollbarTimer = Tcl_CreateTimerHandler(200, - AsyncUpdateYScrollbar, textPtr); + dInfoPtr->lineUpdateTimer = NULL; + dInfoPtr->scrollbarTimer = NULL; textPtr->dInfoPtr = dInfoPtr; } @@ -756,6 +764,7 @@ GetStyle( TextStyle *stylePtr; Tcl_HashEntry *hPtr; int numTags, isNew, i; + int isSelected; XGCValues gcValues; unsigned long mask; /* @@ -766,6 +775,7 @@ GetStyle( int fgPrio, fontPrio, fgStipplePrio; int underlinePrio, elidePrio, justifyPrio, offsetPrio; int lMargin1Prio, lMargin2Prio, rMarginPrio; + int lMarginColorPrio, rMarginColorPrio; int spacing1Prio, spacing2Prio, spacing3Prio; int overstrikePrio, tabPrio, tabStylePrio, wrapPrio; @@ -780,11 +790,14 @@ GetStyle( fgPrio = fontPrio = fgStipplePrio = -1; underlinePrio = elidePrio = justifyPrio = offsetPrio = -1; lMargin1Prio = lMargin2Prio = rMarginPrio = -1; + lMarginColorPrio = rMarginColorPrio = -1; spacing1Prio = spacing2Prio = spacing3Prio = -1; overstrikePrio = tabPrio = tabStylePrio = wrapPrio = -1; memset(&styleValues, 0, sizeof(StyleValues)); styleValues.relief = TK_RELIEF_FLAT; styleValues.fgColor = textPtr->fgColor; + styleValues.underlineColor = textPtr->fgColor; + styleValues.overstrikeColor = textPtr->fgColor; styleValues.tkfont = textPtr->tkfont; styleValues.justify = TK_JUSTIFY_LEFT; styleValues.spacing1 = textPtr->spacing1; @@ -794,12 +807,22 @@ GetStyle( styleValues.tabStyle = textPtr->tabStyle; styleValues.wrapMode = textPtr->wrapMode; styleValues.elide = 0; + isSelected = 0; + + for (i = 0 ; i < numTags; i++) { + if (textPtr->selTagPtr == tagPtrs[i]) { + isSelected = 1; + break; + } + } for (i = 0 ; i < numTags; i++) { Tk_3DBorder border; + XColor *fgColor; tagPtr = tagPtrs[i]; border = tagPtr->border; + fgColor = tagPtr->fgColor; /* * If this is the selection tag, and inactiveSelBorder is NULL (the @@ -819,6 +842,14 @@ GetStyle( border = textPtr->inactiveSelBorder; } + if ((tagPtr->selBorder != NULL) && (isSelected)) { + border = tagPtr->selBorder; + } + + if ((tagPtr->selFgColor != None) && (isSelected)) { + fgColor = tagPtr->selFgColor; + } + if ((border != NULL) && (tagPtr->priority > borderPrio)) { styleValues.border = border; borderPrio = tagPtr->priority; @@ -842,8 +873,8 @@ GetStyle( styleValues.bgStipple = tagPtr->bgStipple; bgStipplePrio = tagPtr->priority; } - if ((tagPtr->fgColor != None) && (tagPtr->priority > fgPrio)) { - styleValues.fgColor = tagPtr->fgColor; + if ((fgColor != None) && (tagPtr->priority > fgPrio)) { + styleValues.fgColor = fgColor; fgPrio = tagPtr->priority; } if ((tagPtr->tkfont != None) && (tagPtr->priority > fontPrio)) { @@ -870,6 +901,11 @@ GetStyle( styleValues.lMargin2 = tagPtr->lMargin2; lMargin2Prio = tagPtr->priority; } + if ((tagPtr->lMarginColor != NULL) + && (tagPtr->priority > lMarginColorPrio)) { + styleValues.lMarginColor = tagPtr->lMarginColor; + lMarginColorPrio = tagPtr->priority; + } if ((tagPtr->offsetString != NULL) && (tagPtr->priority > offsetPrio)) { styleValues.offset = tagPtr->offset; @@ -879,12 +915,22 @@ GetStyle( && (tagPtr->priority > overstrikePrio)) { styleValues.overstrike = tagPtr->overstrike; overstrikePrio = tagPtr->priority; + if (tagPtr->overstrikeColor != None) { + styleValues.overstrikeColor = tagPtr->overstrikeColor; + } else if (fgColor != None) { + styleValues.overstrikeColor = fgColor; + } } if ((tagPtr->rMarginString != NULL) && (tagPtr->priority > rMarginPrio)) { styleValues.rMargin = tagPtr->rMargin; rMarginPrio = tagPtr->priority; } + if ((tagPtr->rMarginColor != NULL) + && (tagPtr->priority > rMarginColorPrio)) { + styleValues.rMarginColor = tagPtr->rMarginColor; + rMarginColorPrio = tagPtr->priority; + } if ((tagPtr->spacing1String != NULL) && (tagPtr->priority > spacing1Prio)) { styleValues.spacing1 = tagPtr->spacing1; @@ -914,6 +960,11 @@ GetStyle( && (tagPtr->priority > underlinePrio)) { styleValues.underline = tagPtr->underline; underlinePrio = tagPtr->priority; + if (tagPtr->underlineColor != None) { + styleValues.underlineColor = tagPtr->underlineColor; + } else if (fgColor != None) { + styleValues.underlineColor = fgColor; + } } if ((tagPtr->elideString != NULL) && (tagPtr->priority > elidePrio)) { @@ -970,6 +1021,11 @@ GetStyle( mask |= GCStipple|GCFillStyle; } stylePtr->fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); + mask = GCForeground; + gcValues.foreground = styleValues.underlineColor->pixel; + stylePtr->ulGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); + gcValues.foreground = styleValues.overstrikeColor->pixel; + stylePtr->ovGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); stylePtr->sValuePtr = (StyleValues *) Tcl_GetHashKey(&textPtr->dInfoPtr->styleTable, hPtr); stylePtr->hPtr = hPtr; @@ -1010,6 +1066,12 @@ FreeStyle( if (stylePtr->fgGC != None) { Tk_FreeGC(textPtr->display, stylePtr->fgGC); } + if (stylePtr->ulGC != None) { + Tk_FreeGC(textPtr->display, stylePtr->ulGC); + } + if (stylePtr->ovGC != None) { + Tk_FreeGC(textPtr->display, stylePtr->ovGC); + } Tcl_DeleteHashEntry(stylePtr->hPtr); ckfree(stylePtr); } @@ -1121,6 +1183,10 @@ LayoutDLine( dlPtr->nextPtr = NULL; dlPtr->flags = NEW_LAYOUT | OLD_Y_INVALID; dlPtr->logicalLinesMerged = 0; + dlPtr->lMarginColor = NULL; + dlPtr->lMarginWidth = 0; + dlPtr->rMarginColor = NULL; + dlPtr->rMarginWidth = 0; /* * This is not necessarily totally correct, where we have merged logical @@ -1395,6 +1461,7 @@ LayoutDLine( x = chunkPtr->stylePtr->sValuePtr->lMargin2; } + dlPtr->lMarginWidth = x; if (wrapMode == TEXT_WRAPMODE_NONE) { maxX = -1; } else { @@ -1648,7 +1715,7 @@ LayoutDLine( * Make one more pass over the line to recompute various things like its * height, length, and total number of bytes. Also modify the x-locations * of chunks to reflect justification. If we're not wrapping, I'm not sure - * what is the best way to handle left and center justification: should + * what is the best way to handle right and center justification: should * the total length, for purposes of justification, be (a) the window * width, (b) the length of the longest line in the window, or (c) the * length of the longest line in the text? (c) isn't available, (b) seems @@ -1706,6 +1773,11 @@ LayoutDLine( } dlPtr->height += dlPtr->spaceAbove + dlPtr->spaceBelow; dlPtr->baseline += dlPtr->spaceAbove; + dlPtr->lMarginColor = sValuePtr->lMarginColor; + dlPtr->rMarginColor = sValuePtr->rMarginColor; + if (wrapMode != TEXT_WRAPMODE_NONE) { + dlPtr->rMarginWidth = rMargin; + } /* * Recompute line length: may have changed because of justification. @@ -2226,7 +2298,7 @@ UpdateDisplayInfo( * Here's a problem: see the tests textDisp-29.2.1-4 * * If the widget is being created, but has not yet been configured it will - * have a maxY of 1 above, and we we won't have examined all the lines + * have a maxY of 1 above, and we won't have examined all the lines * (just the first line, in fact), and so maxOffset will not be a true * reflection of the widget's lines. Therefore we must not overwrite the * original newXPixelOffset in this case. @@ -2392,12 +2464,26 @@ DisplayDLine( Tk_Width(textPtr->tkwin), dlPtr->height, 0, TK_RELIEF_FLAT); /* - * Next, draw background information for the whole line. + * Second, draw background information for the whole line. */ DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap); /* + * Third, draw the background color of the left and right margins. + */ + if (dlPtr->lMarginColor != NULL) { + Tk_Fill3DRectangle(textPtr->tkwin, pixmap, dlPtr->lMarginColor, 0, y, + dlPtr->lMarginWidth + dInfoPtr->x - dInfoPtr->curXPixelOffset, + dlPtr->height, 0, TK_RELIEF_FLAT); + } + if (dlPtr->rMarginColor != NULL) { + Tk_Fill3DRectangle(textPtr->tkwin, pixmap, dlPtr->rMarginColor, + dInfoPtr->maxX - dlPtr->rMarginWidth + dInfoPtr->curXPixelOffset, + y, dlPtr->rMarginWidth, dlPtr->height, 0, TK_RELIEF_FLAT); + } + + /* * Make another pass through all of the chunks to redraw the insertion * cursor, if it is visible on this line. Must do it here rather than in * the foreground pass below because otherwise a wide insertion cursor @@ -2541,7 +2627,7 @@ DisplayLineBackground( * current x coordinate? */ int matchRight; /* Does line's style match its neighbor just * to the right of the current x-coord? */ - int minX, maxX, xOffset; + int minX, maxX, xOffset, bw; StyleValues *sValuePtr; Display *display; #ifndef TK_NO_DOUBLE_BUFFERING @@ -2612,16 +2698,25 @@ DisplayLineBackground( rightX = leftX + 32767; } + /* + * Prevent the borders from leaking on adjacent characters, + * which would happen for too large border width. + */ + + bw = sValuePtr->borderWidth; + if (leftX + sValuePtr->borderWidth > rightX) { + bw = rightX - leftX; + } + XFillRectangle(display, pixmap, chunkPtr->stylePtr->bgGC, leftX + xOffset, y, (unsigned int) (rightX - leftX), (unsigned int) dlPtr->height); if (sValuePtr->relief != TK_RELIEF_FLAT) { Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - leftX + xOffset, y, sValuePtr->borderWidth, - dlPtr->height, 1, sValuePtr->relief); + leftX + xOffset, y, bw, dlPtr->height, 1, + sValuePtr->relief); Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX - sValuePtr->borderWidth + xOffset, - y, sValuePtr->borderWidth, dlPtr->height, 0, + rightX - bw + xOffset, y, bw, dlPtr->height, 0, sValuePtr->relief); } } @@ -2718,22 +2813,29 @@ DisplayLineBackground( matchRight = (nextPtr2 != NULL) && SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr); if (matchLeft && !matchRight) { + bw = sValuePtr->borderWidth; + if (rightX2 - sValuePtr->borderWidth < leftX) { + bw = rightX2 - leftX; + } if (sValuePtr->relief != TK_RELIEF_FLAT) { Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 - sValuePtr->borderWidth + xOffset, y, - sValuePtr->borderWidth, sValuePtr->borderWidth, 0, - sValuePtr->relief); + rightX2 - bw + xOffset, y, bw, + sValuePtr->borderWidth, 0, sValuePtr->relief); } - leftX = rightX2 - sValuePtr->borderWidth; + leftX = rightX2 - bw; leftXIn = 0; } else if (!matchLeft && matchRight && (sValuePtr->relief != TK_RELIEF_FLAT)) { + bw = sValuePtr->borderWidth; + if (rightX2 + sValuePtr->borderWidth > rightX) { + bw = rightX - rightX2; + } Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 + xOffset, y, sValuePtr->borderWidth, - sValuePtr->borderWidth, 1, sValuePtr->relief); + rightX2 + xOffset, y, bw, sValuePtr->borderWidth, + 1, sValuePtr->relief); Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - leftX + xOffset, y, rightX2 + sValuePtr->borderWidth - - leftX, sValuePtr->borderWidth, leftXIn, 0, 1, + leftX + xOffset, y, rightX2 + bw - leftX, + sValuePtr->borderWidth, leftXIn, 0, 1, sValuePtr->relief); } @@ -2765,7 +2867,7 @@ DisplayLineBackground( chunkPtr2 = NULL; if (dlPtr->nextPtr != NULL && dlPtr->nextPtr->chunkPtr != NULL) { /* - * Find the chunk in the previous line that covers leftX. + * Find the chunk in the next line that covers leftX. */ nextPtr2 = dlPtr->nextPtr->chunkPtr; @@ -2821,26 +2923,33 @@ DisplayLineBackground( matchRight = (nextPtr2 != NULL) && SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr); if (matchLeft && !matchRight) { + bw = sValuePtr->borderWidth; + if (rightX2 - sValuePtr->borderWidth < leftX) { + bw = rightX2 - leftX; + } if (sValuePtr->relief != TK_RELIEF_FLAT) { Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 - sValuePtr->borderWidth + xOffset, + rightX2 - bw + xOffset, y + dlPtr->height - sValuePtr->borderWidth, - sValuePtr->borderWidth, sValuePtr->borderWidth, 0, - sValuePtr->relief); + bw, sValuePtr->borderWidth, 0, sValuePtr->relief); } - leftX = rightX2 - sValuePtr->borderWidth; + leftX = rightX2 - bw; leftXIn = 1; } else if (!matchLeft && matchRight && (sValuePtr->relief != TK_RELIEF_FLAT)) { + bw = sValuePtr->borderWidth; + if (rightX2 + sValuePtr->borderWidth > rightX) { + bw = rightX - rightX2; + } Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - rightX2 + xOffset, y + dlPtr->height - - sValuePtr->borderWidth, sValuePtr->borderWidth, + rightX2 + xOffset, + y + dlPtr->height - sValuePtr->borderWidth, bw, sValuePtr->borderWidth, 1, sValuePtr->relief); Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border, - leftX + xOffset, y + dlPtr->height - - sValuePtr->borderWidth, rightX2 + sValuePtr->borderWidth - - leftX, sValuePtr->borderWidth, leftXIn, 1, 0, - sValuePtr->relief); + leftX + xOffset, + y + dlPtr->height - sValuePtr->borderWidth, + rightX2 + bw - leftX, sValuePtr->borderWidth, leftXIn, + 1, 0, sValuePtr->relief); } nextChunk2b: @@ -2890,9 +2999,10 @@ AsyncUpdateLineMetrics( dInfoPtr->lineUpdateTimer = NULL; - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED) + || !Tk_IsMapped(textPtr->tkwin)) { /* - * The widget has been deleted. Don't do anything. + * The widget has been deleted, or is not mapped. Don't do anything. */ if (--textPtr->refCount == 0) { @@ -2926,6 +3036,8 @@ AsyncUpdateLineMetrics( lineNum = TkTextUpdateLineMetrics(textPtr, lineNum, dInfoPtr->lastMetricUpdateLine, 256); + dInfoPtr->currentMetricUpdateLine = lineNum; + if (tkTextDebug) { char buffer[2 * TCL_INTEGER_SPACE + 1]; @@ -2943,16 +3055,37 @@ AsyncUpdateLineMetrics( /* * We have looped over all lines, so we're done. We must release our * refCount on the widget (the timer token was already set to NULL - * above). + * above). If there is a registered aftersync command, run that first. */ + if (textPtr->afterSyncCmd) { + int code; + Tcl_Preserve((ClientData) textPtr->interp); + code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, + TCL_EVAL_GLOBAL); + if (code == TCL_ERROR) { + Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); + Tcl_BackgroundError(textPtr->interp); + } + Tcl_Release((ClientData) textPtr->interp); + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = NULL; + } + + /* + * Fire the <<WidgetViewSync>> event since the widget view is in sync + * with its internal data (actually it will be after the next trip + * through the event loop, because the widget redraws at idle-time). + */ + + GenerateWidgetViewSyncEvent(textPtr, 1); + textPtr->refCount--; if (textPtr->refCount == 0) { ckfree(textPtr); } return; } - dInfoPtr->currentMetricUpdateLine = lineNum; /* * Re-arm the timer. We already have a refCount on the text widget so no @@ -2966,6 +3099,36 @@ AsyncUpdateLineMetrics( /* *---------------------------------------------------------------------- * + * GenerateWidgetViewSyncEvent -- + * + * Send the <<WidgetViewSync>> event related to the text widget + * line metrics asynchronous update. + * This is equivalent to: + * event generate $textWidget <<WidgetViewSync>> -data $s + * where $s is the sync status: true (when the widget view is in + * sync with its internal data) or false (when it is not). + * + * Results: + * None + * + * Side effects: + * If corresponding bindings are present, they will trigger. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateWidgetViewSyncEvent( + TkText *textPtr, /* Information about text widget. */ + Bool InSync) /* true if in sync, false otherwise */ +{ + TkSendVirtualEvent(textPtr->tkwin, "WidgetViewSync", + Tcl_NewBooleanObj(InSync)); +} + +/* + *---------------------------------------------------------------------- + * * TkTextUpdateLineMetrics -- * * This function updates the pixel height calculations of a range of @@ -3338,6 +3501,7 @@ TextInvalidateLineMetrics( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, textPtr); + GenerateWidgetViewSyncEvent(textPtr, 0); } } @@ -3948,6 +4112,18 @@ DisplayText( * warnings. */ Tcl_Interp *interp; +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + dInfoPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* @@ -3964,14 +4140,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x) || (dInfoPtr->maxY <= dInfoPtr->y)) { UpdateDisplayInfo(textPtr); @@ -3983,14 +4151,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked, hence the preserve/release calls and the loop, @@ -5046,6 +5206,7 @@ TkTextRelayoutWindow( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, textPtr); + GenerateWidgetViewSyncEvent(textPtr, 0); } } } @@ -5157,7 +5318,10 @@ TkTextSetYView( dInfoPtr->newTopPixelOffset = 0; goto scheduleUpdate; - } + } + /* + * The line is already on screen, with no need to scroll. + */ return; } } @@ -5220,6 +5384,15 @@ TkTextSetYView( } /* + * If the window height is smaller than the line height, prefer to make + * the top of the line visible. + */ + + if (dInfoPtr->maxY - dInfoPtr->y < lineHeight) { + bottomY = lineHeight; + } + + /* * Our job now is to arrange the display so that indexPtr appears as low * on the screen as possible but with its bottom no lower than bottomY. * BottomY is the bottom of the window if the desired line is just below @@ -6039,6 +6212,35 @@ TkTextYviewCmd( /* *-------------------------------------------------------------- * + * TkTextPendingsync -- + * + * This function checks if any line heights are not up-to-date. + * + * Results: + * Returns a boolean true if it is the case, or false if all line + * heights are up-to-date. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +Bool +TkTextPendingsync( + TkText *textPtr) /* Information about text widget. */ +{ + TextDInfo *dInfoPtr = textPtr->dInfoPtr; + + return ( + ((dInfoPtr->metricEpoch == -1) && + (dInfoPtr->lastMetricUpdateLine == dInfoPtr->currentMetricUpdateLine)) ? + 0 : 1); +} + +/* + *-------------------------------------------------------------- + * * TkTextScanCmd -- * * This function is invoked to process the "scan" option for the widget @@ -6582,6 +6784,7 @@ FindDLine( const TkTextIndex *indexPtr)/* Index of desired character. */ { DLine *dlPtrPrev; + TkTextIndex indexPtr2; if (dlPtr == NULL) { return NULL; @@ -6606,24 +6809,58 @@ FindDLine( dlPtrPrev = dlPtr; dlPtr = dlPtr->nextPtr; if (dlPtr == NULL) { - TkTextIndex indexPtr2; /* * We're past the last display line, either because the desired * index lies past the visible text, or because the desired index - * is on the last display line showing the last logical line. + * is on the last display line. */ indexPtr2 = dlPtrPrev->index; TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount, &indexPtr2); if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) { + /* + * The desired index is on the last display line. + * --> return this display line. + */ dlPtr = dlPtrPrev; - break; } else { - return NULL; + /* + * The desired index is past the visible text. There is no + * display line displaying something at the desired index. + * --> return NULL. + */ } + break; } if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) { - dlPtr = dlPtrPrev; + /* + * If we're here then we would normally expect that: + * dlPtrPrev->index <= indexPtr < dlPtr->index + * i.e. we have found the searched display line being dlPtr. + * However it is possible that some DLines were unlinked + * previously, leading to a situation where going through + * the list of display lines skips display lines that did + * exist just a moment ago. + */ + indexPtr2 = dlPtrPrev->index; + TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount, + &indexPtr2); + if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) { + /* + * Confirmed: + * dlPtrPrev->index <= indexPtr < dlPtr->index + * --> return dlPtrPrev. + */ + dlPtr = dlPtrPrev; + } else { + /* + * The last (rightmost) index shown by dlPtrPrev is still + * before the desired index. This may be because there was + * previously a display line between dlPtrPrev and dlPtr + * and this display line has been unlinked. + * --> return dlPtr. + */ + } break; } } @@ -6653,7 +6890,7 @@ FindDLine( static int IsStartOfNotMergedLine( TkText *textPtr, /* Widget record for text widget. */ - CONST TkTextIndex *indexPtr) /* Index to check. */ + const TkTextIndex *indexPtr) /* Index to check. */ { TkTextIndex indexPtr2; @@ -7029,7 +7266,7 @@ TkTextIndexBbox( dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr); - /* + /* * Two cases shall be trapped here because the logic later really * needs dlPtr to be the display line containing indexPtr: * 1. if no display line contains the desired index (NULL dlPtr) @@ -7173,7 +7410,7 @@ TkTextDLineInfo( dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr); - /* + /* * Two cases shall be trapped here because the logic later really * needs dlPtr to be the display line containing indexPtr: * 1. if no display line contains the desired index (NULL dlPtr) @@ -7344,8 +7581,8 @@ TkTextCharLayoutProc( if (bytesThatFit < maxBytes) { if ((bytesThatFit == 0) && noCharsYet) { - Tcl_UniChar ch; - int chLen = Tcl_UtfToUniChar(p, &ch); + int ch; + int chLen = TkUtfToUniChar(p, &ch); #if TK_LAYOUT_WITH_BASE_CHUNKS bytesThatFit = CharChunkMeasureChars(chunkPtr, line, @@ -7693,7 +7930,7 @@ CharDisplayProc( y + baseline - sValuePtr->offset); if (sValuePtr->underline) { - TkUnderlineCharsInContext(display, dst, stylePtr->fgGC, + TkUnderlineCharsInContext(display, dst, stylePtr->ulGC, sValuePtr->tkfont, string, numBytes, ciPtr->baseChunkPtr->x + xDisplacement, y + baseline - sValuePtr->offset, @@ -7703,7 +7940,7 @@ CharDisplayProc( Tk_FontMetrics fm; Tk_GetFontMetrics(sValuePtr->tkfont, &fm); - TkUnderlineCharsInContext(display, dst, stylePtr->fgGC, + TkUnderlineCharsInContext(display, dst, stylePtr->ovGC, sValuePtr->tkfont, string, numBytes, ciPtr->baseChunkPtr->x + xDisplacement, y + baseline - sValuePtr->offset @@ -7720,7 +7957,7 @@ CharDisplayProc( Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string, numBytes, offsetX, y + baseline - sValuePtr->offset); if (sValuePtr->underline) { - Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, + Tk_UnderlineChars(display, dst, stylePtr->ulGC, sValuePtr->tkfont, string, offsetX, y + baseline - sValuePtr->offset, 0, numBytes); @@ -7730,7 +7967,7 @@ CharDisplayProc( Tk_FontMetrics fm; Tk_GetFontMetrics(sValuePtr->tkfont, &fm); - Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, + Tk_UnderlineChars(display, dst, stylePtr->ovGC, sValuePtr->tkfont, string, offsetX, y + baseline - sValuePtr->offset - fm.descent - (fm.ascent * 3) / 10, diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c index 70f74fb..7aebc84 100644 --- a/generic/tkTextIndex.c +++ b/generic/tkTextIndex.c @@ -40,9 +40,9 @@ static const char * StartEnd(TkText *textPtr, const char *string, static int GetIndex(Tcl_Interp *interp, TkSharedText *sharedPtr, TkText *textPtr, const char *string, TkTextIndex *indexPtr, int *canCachePtr); -static int IndexCountBytesOrdered(CONST TkText *textPtr, - CONST TkTextIndex *indexPtr1, - CONST TkTextIndex *indexPtr2); +static int IndexCountBytesOrdered(const TkText *textPtr, + const TkTextIndex *indexPtr1, + const TkTextIndex *indexPtr2); /* * The "textindex" Tcl_Obj definition: @@ -1636,9 +1636,9 @@ TkTextIndexForwChars( int TkTextIndexCountBytes( - CONST TkText *textPtr, - CONST TkTextIndex *indexPtr1, /* Index describing one location. */ - CONST TkTextIndex *indexPtr2) /* Index describing second location. */ + const TkText *textPtr, + const TkTextIndex *indexPtr1, /* Index describing one location. */ + const TkTextIndex *indexPtr2) /* Index describing second location. */ { int compare = TkTextIndexCmp(indexPtr1, indexPtr2); @@ -1653,11 +1653,11 @@ TkTextIndexCountBytes( static int IndexCountBytesOrdered( - CONST TkText *textPtr, - CONST TkTextIndex *indexPtr1, + const TkText *textPtr, + const TkTextIndex *indexPtr1, /* Index describing location of character from * which to count. */ - CONST TkTextIndex *indexPtr2) + const TkTextIndex *indexPtr2) /* Index describing location of last character * at which to stop the count. */ { @@ -1683,7 +1683,7 @@ IndexCountBytesOrdered( byteCount += segPtr->size; } - linePtr = indexPtr1->linePtr->nextPtr; + linePtr = TkBTreeNextLine(textPtr, indexPtr1->linePtr); while (linePtr != indexPtr2->linePtr) { for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { @@ -2205,7 +2205,7 @@ StartEnd( TkText *textPtr, /* Information about text widget. */ const char *string, /* String to parse for additional info about * modifier (count and units). Points to first - * character of modifer word. */ + * character of modifier word. */ TkTextIndex *indexPtr) /* Index to modify based on string. */ { const char *p; @@ -2298,9 +2298,9 @@ StartEnd( int chSize = 1; if (segPtr->typePtr == &tkTextCharType) { - Tcl_UniChar ch; + int ch; - chSize = Tcl_UtfToUniChar(segPtr->body.chars + offset, &ch); + chSize = TkUtfToUniChar(segPtr->body.chars + offset, &ch); if (!Tcl_UniCharIsWordChar(ch)) { break; } @@ -2327,7 +2327,7 @@ StartEnd( int offset; if (modifier == TKINDEX_DISPLAY) { - TkTextIndexForwChars(NULL, indexPtr, 0, indexPtr, + TkTextIndexForwChars(textPtr, indexPtr, 0, indexPtr, COUNT_DISPLAY_INDICES); } @@ -2343,9 +2343,9 @@ StartEnd( int chSize = 1; if (segPtr->typePtr == &tkTextCharType) { - Tcl_UniChar ch; - Tcl_UtfToUniChar(segPtr->body.chars + offset, &ch); + int ch; + TkUtfToUniChar(segPtr->body.chars + offset, &ch); if (!Tcl_UniCharIsWordChar(ch)) { break; } @@ -2356,11 +2356,20 @@ StartEnd( } firstChar = 0; } - offset -= chSize; - indexPtr->byteIndex -= chSize; + if (offset == 0) { + if (modifier == TKINDEX_DISPLAY) { + TkTextIndexBackChars(textPtr, indexPtr, 1, indexPtr, + COUNT_DISPLAY_INDICES); + } else { + TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, + COUNT_INDICES); + } + } else { + indexPtr->byteIndex -= chSize; + } + offset -= chSize; if (offset < 0) { - if (indexPtr->byteIndex < 0) { - indexPtr->byteIndex = 0; + if (indexPtr->byteIndex == 0) { goto done; } segPtr = TkTextIndexToSeg(indexPtr, &offset); diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c index af3f235..dd3127d 100644 --- a/generic/tkTextTag.c +++ b/generic/tkTextTag.c @@ -30,7 +30,7 @@ static const char *const wrapStrings[] = { /* * The 'TkTextTabStyle' enum in tkText.h is used to define a type for the * -tabstyle option of the Text widget. These values are used as indices into - * the string table below. Tags are allowed an empty wrap value, but the + * the string table below. Tags are allowed an empty tabstyle value, but the * widget as a whole is not. */ @@ -44,11 +44,11 @@ static const Tk_OptionSpec tagOptionSpecs[] = { {TK_OPTION_BITMAP, "-bgstipple", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, bgStipple), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_PIXELS, "-borderwidth", NULL, NULL, - "0", Tk_Offset(TkTextTag, borderWidthPtr), Tk_Offset(TkTextTag, borderWidth), - TK_OPTION_DONT_SET_DEFAULT|TK_OPTION_NULL_OK, 0, 0}, + NULL, Tk_Offset(TkTextTag, borderWidthPtr), Tk_Offset(TkTextTag, borderWidth), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0}, {TK_OPTION_STRING, "-elide", NULL, NULL, - "0", -1, Tk_Offset(TkTextTag, elideString), - TK_OPTION_DONT_SET_DEFAULT|TK_OPTION_NULL_OK, 0, 0}, + NULL, -1, Tk_Offset(TkTextTag, elideString), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0}, {TK_OPTION_BITMAP, "-fgstipple", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, fgStipple), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_FONT, "-font", NULL, NULL, @@ -61,15 +61,26 @@ static const Tk_OptionSpec tagOptionSpecs[] = { NULL, -1, Tk_Offset(TkTextTag, lMargin1String), TK_OPTION_NULL_OK,0,0}, {TK_OPTION_STRING, "-lmargin2", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, lMargin2String), TK_OPTION_NULL_OK,0,0}, + {TK_OPTION_BORDER, "-lmargincolor", NULL, NULL, + NULL, -1, Tk_Offset(TkTextTag, lMarginColor), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-offset", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, offsetString), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-overstrike", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, overstrikeString), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-overstrikefg", NULL, NULL, + NULL, -1, Tk_Offset(TkTextTag, overstrikeColor), + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-relief", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, reliefString), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-rmargin", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, rMarginString), TK_OPTION_NULL_OK, 0,0}, + {TK_OPTION_BORDER, "-rmargincolor", NULL, NULL, + NULL, -1, Tk_Offset(TkTextTag, rMarginColor), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BORDER, "-selectbackground", NULL, NULL, + NULL, -1, Tk_Offset(TkTextTag, selBorder), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-selectforeground", NULL, NULL, + NULL, -1, Tk_Offset(TkTextTag, selFgColor), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-spacing1", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, spacing1String), TK_OPTION_NULL_OK,0,0}, {TK_OPTION_STRING, "-spacing2", NULL, NULL, @@ -84,6 +95,9 @@ static const Tk_OptionSpec tagOptionSpecs[] = { {TK_OPTION_STRING, "-underline", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, underlineString), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_COLOR, "-underlinefg", NULL, NULL, + NULL, -1, Tk_Offset(TkTextTag, underlineColor), + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING_TABLE, "-wrap", NULL, NULL, NULL, -1, Tk_Offset(TkTextTag, wrapMode), TK_OPTION_NULL_OK, wrapStrings, 0}, @@ -484,10 +498,18 @@ TkTextTagCmd( */ if (tagPtr == textPtr->selTagPtr) { - textPtr->selBorder = tagPtr->border; + if (tagPtr->selBorder == NULL) { + textPtr->selBorder = tagPtr->border; + } else { + textPtr->selBorder = tagPtr->selBorder; + } textPtr->selBorderWidth = tagPtr->borderWidth; textPtr->selBorderWidthPtr = tagPtr->borderWidthPtr; - textPtr->selFgColorPtr = tagPtr->fgColor; + if (tagPtr->selFgColor == NULL) { + textPtr->selFgColorPtr = tagPtr->fgColor; + } else { + textPtr->selFgColorPtr = tagPtr->selFgColor; + } } tagPtr->affectsDisplay = 0; @@ -509,12 +531,18 @@ TkTextTagCmd( tagPtr->affectsDisplayGeometry = 1; } if ((tagPtr->border != NULL) + || (tagPtr->selBorder != NULL) || (tagPtr->reliefString != NULL) || (tagPtr->bgStipple != None) || (tagPtr->fgColor != NULL) + || (tagPtr->selFgColor != NULL) || (tagPtr->fgStipple != None) || (tagPtr->overstrikeString != NULL) - || (tagPtr->underlineString != NULL)) { + || (tagPtr->overstrikeColor != NULL) + || (tagPtr->underlineString != NULL) + || (tagPtr->underlineColor != NULL) + || (tagPtr->lMarginColor != NULL) + || (tagPtr->rMarginColor != NULL)) { tagPtr->affectsDisplay = 1; } if (!newTag) { @@ -1011,12 +1039,17 @@ TkTextCreateTag( tagPtr->lMargin1 = 0; tagPtr->lMargin2String = NULL; tagPtr->lMargin2 = 0; + tagPtr->lMarginColor = NULL; tagPtr->offsetString = NULL; tagPtr->offset = 0; tagPtr->overstrikeString = NULL; tagPtr->overstrike = 0; + tagPtr->overstrikeColor = NULL; tagPtr->rMarginString = NULL; tagPtr->rMargin = 0; + tagPtr->rMarginColor = NULL; + tagPtr->selBorder = NULL; + tagPtr->selFgColor = NULL; tagPtr->spacing1String = NULL; tagPtr->spacing1 = 0; tagPtr->spacing2String = NULL; @@ -1028,6 +1061,7 @@ TkTextCreateTag( tagPtr->tabStyle = TK_TEXT_TABSTYLE_NONE; tagPtr->underlineString = NULL; tagPtr->underline = 0; + tagPtr->underlineColor = NULL; tagPtr->elideString = NULL; tagPtr->elide = 0; tagPtr->wrapMode = TEXT_WRAPMODE_NULL; diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c index bd61d75..c9fc20f 100644 --- a/generic/tkTextWind.c +++ b/generic/tkTextWind.c @@ -1134,6 +1134,16 @@ TkTextEmbWinDisplayProc( &lineX, &windowY, &width, &height); windowX = lineX - chunkPtr->x + x; + /* + * Mark the window as displayed so that it won't get unmapped. + * This needs to be done before the next instruction block because + * Tk_MaintainGeometry/Tk_MapWindow will run event handlers, in + * particular for the <Map> event, and if the bound script deletes + * the embedded window its clients will get freed. + */ + + client->displayed = 1; + if (textPtr->tkwin == Tk_Parent(tkwin)) { if ((windowX != Tk_X(tkwin)) || (windowY != Tk_Y(tkwin)) || (Tk_ReqWidth(tkwin) != Tk_Width(tkwin)) @@ -1145,12 +1155,6 @@ TkTextEmbWinDisplayProc( Tk_MaintainGeometry(tkwin, textPtr->tkwin, windowX, windowY, width, height); } - - /* - * Mark the window as displayed so that it won't get unmapped. - */ - - client->displayed = 1; } /* diff --git a/generic/tkUndo.c b/generic/tkUndo.c index 8359e0a..c66905d 100644 --- a/generic/tkUndo.c +++ b/generic/tkUndo.c @@ -353,7 +353,7 @@ TkUndoInitStack( /* *---------------------------------------------------------------------- * - * TkUndoSetDepth -- + * TkUndoSetMaxDepth -- * * Set the maximum depth of stack. * @@ -368,7 +368,7 @@ TkUndoInitStack( */ void -TkUndoSetDepth( +TkUndoSetMaxDepth( TkUndoRedoStack *stack, /* An Undo/Redo stack */ int maxdepth) /* The maximum stack depth */ { @@ -478,6 +478,52 @@ TkUndoFreeStack( /* *---------------------------------------------------------------------- * + * TkUndoCanRedo -- + * + * Returns true if redo is possible, i.e. if the redo stack is not empty. + * + * Results: + * A boolean. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkUndoCanRedo( + TkUndoRedoStack *stack) /* An Undo/Redo stack */ +{ + return stack->redoStack != NULL; +} + +/* + *---------------------------------------------------------------------- + * + * TkUndoCanUndo -- + * + * Returns true if undo is possible, i.e. if the undo stack is not empty. + * + * Results: + * A boolean. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkUndoCanUndo( + TkUndoRedoStack *stack) /* An Undo/Redo stack */ +{ + return stack->undoStack != NULL; +} + +/* + *---------------------------------------------------------------------- + * * TkUndoInsertUndoSeparator -- * * Insert a separator on the undo stack, indicating a border for an @@ -498,7 +544,7 @@ TkUndoInsertUndoSeparator( { if (TkUndoInsertSeparator(&stack->undoStack)) { stack->depth++; - TkUndoSetDepth(stack, stack->maxdepth); + TkUndoSetMaxDepth(stack, stack->maxdepth); } } diff --git a/generic/tkUndo.h b/generic/tkUndo.h index e63aac4..490ede9 100644 --- a/generic/tkUndo.h +++ b/generic/tkUndo.h @@ -96,9 +96,11 @@ MODULE_SCOPE void TkUndoClearStack(TkUndoAtom **stack); */ MODULE_SCOPE TkUndoRedoStack *TkUndoInitStack(Tcl_Interp *interp, int maxdepth); -MODULE_SCOPE void TkUndoSetDepth(TkUndoRedoStack *stack, int maxdepth); +MODULE_SCOPE void TkUndoSetMaxDepth(TkUndoRedoStack *stack, int maxdepth); MODULE_SCOPE void TkUndoClearStacks(TkUndoRedoStack *stack); MODULE_SCOPE void TkUndoFreeStack(TkUndoRedoStack *stack); +MODULE_SCOPE int TkUndoCanRedo(TkUndoRedoStack *stack); +MODULE_SCOPE int TkUndoCanUndo(TkUndoRedoStack *stack); MODULE_SCOPE void TkUndoInsertUndoSeparator(TkUndoRedoStack *stack); MODULE_SCOPE TkUndoSubAtom *TkUndoMakeCmdSubAtom(Tcl_Command command, Tcl_Obj *actionScript, TkUndoSubAtom *subAtomList); diff --git a/generic/tkUtil.c b/generic/tkUtil.c index 7ff9ecb..d89282f 100644 --- a/generic/tkUtil.c +++ b/generic/tkUtil.c @@ -1162,7 +1162,8 @@ TkMakeEnsemble( * TkSendVirtualEvent -- * * Send a virtual event notification to the specified target window. - * Equivalent to "event generate $target <<$eventName>>" + * Equivalent to: + * "event generate $target <<$eventName>> -data $detail" * * Note that we use Tk_QueueWindowEvent, not Tk_HandleEvent, so this * routine does not reenter the interpreter. @@ -1173,7 +1174,8 @@ TkMakeEnsemble( void TkSendVirtualEvent( Tk_Window target, - const char *eventName) + const char *eventName, + Tcl_Obj *detail) { union {XEvent general; XVirtualEvent virtual;} event; @@ -1184,9 +1186,92 @@ TkSendVirtualEvent( event.general.xany.window = Tk_WindowId(target); event.general.xany.display = Tk_Display(target); event.virtual.name = Tk_GetUid(eventName); + if (detail != NULL) { + event.virtual.user_data = detail; + } Tk_QueueWindowEvent(&event.general, TCL_QUEUE_TAIL); } + +#if TCL_UTF_MAX <= 4 +/* + *--------------------------------------------------------------------------- + * + * TkUtfToUniChar -- + * + * Almost the same as Tcl_UtfToUniChar but using int instead of Tcl_UniChar. + * This function is capable of collapsing a upper/lower surrogate pair to a + * single unicode character. So, up to 6 bytes might be consumed. + * + * Results: + * *chPtr is filled with the Tcl_UniChar, and the return value is the + * number of bytes from the UTF-8 string that were consumed. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TkUtfToUniChar( + const char *src, /* The UTF-8 string. */ + int *chPtr) /* Filled with the Tcl_UniChar represented by + * the UTF-8 string. */ +{ + Tcl_UniChar uniChar = 0; + + int len = Tcl_UtfToUniChar(src, &uniChar); + if ((uniChar & 0xfc00) == 0xd800) { + Tcl_UniChar high = uniChar; + /* This can only happen if Tcl is compiled with TCL_UTF_MAX=4, + * or when a high surrogate character is detected in UTF-8 form */ + int len2 = Tcl_UtfToUniChar(src+len, &uniChar); + if ((uniChar & 0xfc00) == 0xdc00) { + *chPtr = (((high & 0x3ff) << 10) | (uniChar & 0x3ff)) + 0x10000; + len += len2; + } else { + *chPtr = high; + } + } else { + *chPtr = uniChar; + } + return len; +} + +/* + *--------------------------------------------------------------------------- + * + * TkUniCharToUtf -- + * + * Almost the same as Tcl_UniCharToUtf but producing surrogates if + * TCL_UTF_MAX==3. So, up to 6 bytes might be produced. + * + * Results: + * *buf is filled with the UTF-8 string, and the return value is the + * number of bytes produced. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int TkUniCharToUtf(int ch, char *buf) +{ + int size = Tcl_UniCharToUtf(ch, buf); + if ((ch > 0xffff) && (ch <= 0x10ffff) && (size < 4)) { + /* Hey, this is wrong, we must be running TCL_UTF_MAX==3 + * The best thing we can do is spit out 2 surrogates */ + ch -= 0x10000; + size = Tcl_UniCharToUtf(((ch >> 10) | 0xd800), buf); + size += Tcl_UniCharToUtf(((ch & 0x3ff) | 0xdc00), buf+size); + } + return size; +} + + +#endif /* * Local Variables: * mode: c diff --git a/generic/tkWindow.c b/generic/tkWindow.c index b5cbbab..5855b7c 100644 --- a/generic/tkWindow.c +++ b/generic/tkWindow.c @@ -54,12 +54,6 @@ typedef struct ThreadSpecificData { static Tcl_ThreadDataKey dataKey; /* - * The Mutex below is used to lock access to the Tk_Uid structs above. - */ - -TCL_DECLARE_MUTEX(windowMutex) - -/* * Default values for "changes" and "atts" fields of TkWindows. Note that Tk * always requests all events for all windows, except StructureNotify events * on internal windows: these events are generated internally. @@ -206,40 +200,6 @@ static const TkCmd commands[] = { }; /* - * The variables and table below are used to parse arguments from the "argv" - * variable in Tk_Init. - */ - -static int synchronize = 0; -static char *name = NULL; -static char *display = NULL; -static char *geometry = NULL; -static char *colormap = NULL; -static char *use = NULL; -static char *visual = NULL; -static int rest = 0; - -static const Tk_ArgvInfo argTable[] = { - {"-colormap", TK_ARGV_STRING, NULL, (char *) &colormap, - "Colormap for main window"}, - {"-display", TK_ARGV_STRING, NULL, (char *) &display, - "Display to use"}, - {"-geometry", TK_ARGV_STRING, NULL, (char *) &geometry, - "Initial geometry for window"}, - {"-name", TK_ARGV_STRING, NULL, (char *) &name, - "Name to use for application"}, - {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize, - "Use synchronous mode for display server"}, - {"-visual", TK_ARGV_STRING, NULL, (char *) &visual, - "Visual for main window"}, - {"-use", TK_ARGV_STRING, NULL, (char *) &use, - "Id of window in which to embed application"}, - {"--", TK_ARGV_REST, (char *) 1, (char *) &rest, - "Pass all remaining arguments through to script"}, - {NULL, TK_ARGV_END, NULL, NULL, NULL} -}; - -/* * Forward declarations to functions defined later in this file: */ @@ -2391,6 +2351,9 @@ Tk_IdToWindow( break; } } + if (window == None) { + return NULL; + } hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window); if (hPtr == NULL) { @@ -3028,16 +2991,51 @@ MODULE_SCOPE const TkStubs tkStubs; */ static int +CopyValue( + ClientData dummy, + Tcl_Obj *objPtr, + void *dstPtr) +{ + *(Tcl_Obj **)dstPtr = objPtr; + return 1; +} + +static int Initialize( Tcl_Interp *interp) /* Interpreter to initialize. */ { - char *p; - int argc, code; - const char **argv; - const char *args[20]; - const char *argString = NULL; - Tcl_DString class; + int code = TCL_OK; ThreadSpecificData *tsdPtr; + Tcl_Obj *value = NULL; + Tcl_Obj *cmd; + + Tcl_Obj *nameObj = NULL; + Tcl_Obj *classObj = NULL; + Tcl_Obj *displayObj = NULL; + Tcl_Obj *colorMapObj = NULL; + Tcl_Obj *useObj = NULL; + Tcl_Obj *visualObj = NULL; + Tcl_Obj *geometryObj = NULL; + + int sync = 0; + + const Tcl_ArgvInfo table[] = { + {TCL_ARGV_CONSTANT, "-sync", INT2PTR(1), &sync, + "Use synchronous mode for display server", NULL}, + {TCL_ARGV_FUNC, "-colormap", CopyValue, &colorMapObj, + "Colormap for main window", NULL}, + {TCL_ARGV_FUNC, "-display", CopyValue, &displayObj, + "Display to use", NULL}, + {TCL_ARGV_FUNC, "-geometry", CopyValue, &geometryObj, + "Initial geometry for window", NULL}, + {TCL_ARGV_FUNC, "-name", CopyValue, &nameObj, + "Name to use for application", NULL}, + {TCL_ARGV_FUNC, "-visual", CopyValue, &visualObj, + "Visual for main window", NULL}, + {TCL_ARGV_FUNC, "-use", CopyValue, &useObj, + "Id of window in which to embed application", NULL}, + TCL_ARGV_AUTO_REST, TCL_ARGV_AUTO_HELP, TCL_ARGV_TABLE_END + }; /* * Ensure that we are getting a compatible version of Tcl. @@ -3056,23 +3054,6 @@ Initialize( tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); /* - * Start by initializing all the static variables to default acceptable - * values so that no information is leaked from a previous run of this - * code. - */ - - Tcl_MutexLock(&windowMutex); - synchronize = 0; - name = NULL; - display = NULL; - geometry = NULL; - colormap = NULL; - use = NULL; - visual = NULL; - rest = 0; - argv = NULL; - - /* * We start by resetting the result because it might not be clean. */ @@ -3084,8 +3065,6 @@ Initialize( * master. */ - Tcl_DString ds; - /* * Step 1 : find the master and construct the interp name (could be a * function if new APIs were ok). We could also construct the path @@ -3095,18 +3074,13 @@ Initialize( Tcl_Interp *master = interp; - while (1) { + while (Tcl_IsSafe(master)) { master = Tcl_GetMaster(master); if (master == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "no controlling master interpreter", -1)); Tcl_SetErrorCode(interp, "TK", "SAFE", "NO_MASTER", NULL); - code = TCL_ERROR; - goto done; - } - if (!Tcl_IsSafe(master)) { - /* Found the trusted master. */ - break; + return TCL_ERROR; } } @@ -3116,39 +3090,30 @@ Initialize( code = Tcl_GetInterpPath(master, interp); if (code != TCL_OK) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "error in Tcl_GetInterpPath", -1)); - Tcl_SetErrorCode(interp, "TK", "SAFE", "FAILED", NULL); - goto done; + Tcl_Panic("Tcl_GetInterpPath broken!"); } /* - * Build the string to eval. + * Build the command to eval in trusted master. */ - Tcl_DStringInit(&ds); - Tcl_DStringAppendElement(&ds, "::safe::TkInit"); - Tcl_DStringAppendElement(&ds, Tcl_GetString(Tcl_GetObjResult(master))); + cmd = Tcl_NewListObj(2, NULL); + Tcl_ListObjAppendElement(NULL, cmd, + Tcl_NewStringObj("::safe::TkInit", -1)); + Tcl_ListObjAppendElement(NULL, cmd, Tcl_GetObjResult(master)); /* * Step 2 : Eval in the master. The argument is the *reversed* interp * path of the slave. */ - code = Tcl_EvalEx(master, Tcl_DStringValue(&ds), -1, 0); + Tcl_IncrRefCount(cmd); + code = Tcl_EvalObjEx(master, cmd, 0); + Tcl_DecrRefCount(cmd); + Tcl_TransferResult(master, code, interp); if (code != TCL_OK) { - /* - * We might want to transfer the error message or not. We don't. - * (No API to do it and maybe security reasons). - */ - - Tcl_DStringFree(&ds); - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "not allowed to start Tk by master's safe::TkInit", -1)); - Tcl_SetErrorCode(interp, "TK", "SAFE", "FAILED", NULL); - goto done; + return code; } - Tcl_DStringFree(&ds); /* * Use the master's result as argv. Note: We don't use the Obj @@ -3156,7 +3121,7 @@ Initialize( * changing the code below. */ - argString = Tcl_GetString(Tcl_GetObjResult(master)); + value = Tcl_GetObjResult(interp); } else { /* * If there is an "argv" variable, get its value, extract out relevant @@ -3164,50 +3129,67 @@ Initialize( * that we used. */ - argString = Tcl_GetVar2(interp, "argv", NULL, TCL_GLOBAL_ONLY); + value = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY); } - if (argString != NULL) { - char buffer[TCL_INTEGER_SPACE]; - if (Tcl_SplitList(interp, argString, &argc, &argv) != TCL_OK) { - argError: + if (value) { + int objc; + Tcl_Obj **objv, **rest; + Tcl_Obj *parseList = Tcl_NewListObj(1, NULL); + + Tcl_ListObjAppendElement(NULL, parseList, Tcl_NewObj()); + + Tcl_IncrRefCount(value); + if (TCL_OK != Tcl_ListObjAppendList(interp, parseList, value) || + TCL_OK != Tcl_ListObjGetElements(NULL, parseList, &objc, &objv) || + TCL_OK != Tcl_ParseArgsObjv(interp, table, &objc, objv, &rest)) { Tcl_AddErrorInfo(interp, "\n (processing arguments in argv variable)"); code = TCL_ERROR; - goto done; } - if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, - argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS) - != TCL_OK) { - goto argError; + if (code == TCL_OK) { + Tcl_SetVar2Ex(interp, "argv", NULL, + Tcl_NewListObj(objc-1, rest+1), TCL_GLOBAL_ONLY); + Tcl_SetVar2Ex(interp, "argc", NULL, + Tcl_NewIntObj(objc-1), TCL_GLOBAL_ONLY); + ckfree(rest); + } + Tcl_DecrRefCount(parseList); + if (code != TCL_OK) { + goto done; } - p = Tcl_Merge(argc, argv); - Tcl_SetVar2(interp, "argv", NULL, p, TCL_GLOBAL_ONLY); - sprintf(buffer, "%d", argc); - Tcl_SetVar2(interp, "argc", NULL, buffer, TCL_GLOBAL_ONLY); - ckfree(p); } /* * Figure out the application's name and class. */ - Tcl_DStringInit(&class); - if (name == NULL) { - int offset; + /* + * If we got no -name argument, fetch from TkpGetAppName(). + */ - TkpGetAppName(interp, &class); - offset = Tcl_DStringLength(&class)+1; - Tcl_DStringSetLength(&class, offset); - Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1); - name = Tcl_DStringValue(&class) + offset; - } else { - Tcl_DStringAppend(&class, name, -1); + if (nameObj == NULL) { + Tcl_DString nameDS; + + Tcl_DStringInit(&nameDS); + TkpGetAppName(interp, &nameDS); + nameObj = Tcl_NewStringObj(Tcl_DStringValue(&nameDS), + Tcl_DStringLength(&nameDS)); + Tcl_DStringFree(&nameDS); } - p = Tcl_DStringValue(&class); - if (*p) { - Tcl_UtfToTitle(p); + /* + * The -class argument is always the ToTitle of the -name + */ + + { + int numBytes; + const char *bytes = Tcl_GetStringFromObj(nameObj, &numBytes); + + classObj = Tcl_NewStringObj(bytes, numBytes); + + numBytes = Tcl_UtfToTitle(Tcl_GetString(classObj)); + Tcl_SetObjLength(classObj, numBytes); } /* @@ -3215,15 +3197,14 @@ Initialize( * information parsed from argv, if any. */ - args[0] = "toplevel"; - args[1] = "."; - args[2] = "-class"; - args[3] = Tcl_DStringValue(&class); - argc = 4; - if (display != NULL) { - args[argc] = "-screen"; - args[argc+1] = display; - argc += 2; + cmd = Tcl_NewStringObj("toplevel . -class", -1); + + Tcl_ListObjAppendElement(NULL, cmd, classObj); + classObj = NULL; + + if (displayObj) { + Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-screen", -1)); + Tcl_ListObjAppendElement(NULL, cmd, displayObj); /* * If this is the first application for this process, save the display @@ -3232,36 +3213,35 @@ Initialize( */ if (tsdPtr->numMainWindows == 0) { - Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY); + Tcl_SetVar2Ex(interp, "env", "DISPLAY", displayObj, TCL_GLOBAL_ONLY); } + displayObj = NULL; } - if (colormap != NULL) { - args[argc] = "-colormap"; - args[argc+1] = colormap; - argc += 2; - colormap = NULL; + if (colorMapObj) { + Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-colormap", -1)); + Tcl_ListObjAppendElement(NULL, cmd, colorMapObj); + colorMapObj = NULL; } - if (use != NULL) { - args[argc] = "-use"; - args[argc+1] = use; - argc += 2; - use = NULL; + if (useObj) { + Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-use", -1)); + Tcl_ListObjAppendElement(NULL, cmd, useObj); + useObj = NULL; } - if (visual != NULL) { - args[argc] = "-visual"; - args[argc+1] = visual; - argc += 2; - visual = NULL; + if (visualObj) { + Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-visual", -1)); + Tcl_ListObjAppendElement(NULL, cmd, visualObj); + visualObj = NULL; } - args[argc] = NULL; - code = TkCreateFrame(NULL, interp, argc, args, 1, name); - Tcl_DStringFree(&class); + code = TkListCreateFrame(NULL, interp, cmd, 1, nameObj); + + Tcl_DecrRefCount(cmd); + if (code != TCL_OK) { goto done; } Tcl_ResetResult(interp); - if (synchronize) { + if (sync) { XSynchronize(Tk_Display(Tk_MainWindow(interp)), True); } @@ -3270,19 +3250,19 @@ Initialize( * geometry into the "geometry" variable. */ - if (geometry != NULL) { - Tcl_DString buf; + if (geometryObj) { + + Tcl_SetVar2Ex(interp, "geometry", NULL, geometryObj, TCL_GLOBAL_ONLY); - Tcl_SetVar2(interp, "geometry", NULL, geometry, TCL_GLOBAL_ONLY); - Tcl_DStringInit(&buf); - Tcl_DStringAppend(&buf, "wm geometry . ", -1); - Tcl_DStringAppend(&buf, geometry, -1); - code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); - Tcl_DStringFree(&buf); + cmd = Tcl_NewStringObj("wm geometry .", -1); + Tcl_ListObjAppendElement(NULL, cmd, geometryObj); + Tcl_IncrRefCount(cmd); + code = Tcl_EvalObjEx(interp, cmd, 0); + Tcl_DecrRefCount(cmd); + geometryObj = NULL; if (code != TCL_OK) { goto done; } - geometry = NULL; } /* @@ -3319,10 +3299,6 @@ Initialize( * console window interpreter. */ - Tcl_MutexUnlock(&windowMutex); - if (argv != NULL) { - ckfree(argv); - } code = TkpInit(interp); if (code == TCL_OK) { @@ -3355,12 +3331,10 @@ tkInit", -1, 0); TkCreateThreadExitHandler(DeleteWindowsExitProc, tsdPtr); } - return code; - done: - Tcl_MutexUnlock(&windowMutex); - if (argv != NULL) { - ckfree(argv); + if (value) { + Tcl_DecrRefCount(value); + value = NULL; } return code; } diff --git a/generic/ttk/ttkButton.c b/generic/ttk/ttkButton.c index 2954184..c00754b 100644 --- a/generic/ttk/ttkButton.c +++ b/generic/ttk/ttkButton.c @@ -136,6 +136,15 @@ BaseCleanup(void *recordPtr) TtkFreeImageSpec(basePtr->base.imageSpec); } +static void +BaseImageChanged( + ClientData clientData, int x, int y, int width, int height, + int imageWidth, int imageHeight) +{ + Base *basePtr = (Base *)clientData; + TtkResizeWidget(&basePtr->core); +} + static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Base *basePtr = recordPtr; @@ -149,8 +158,8 @@ static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask) } if (basePtr->base.imageObj) { - imageSpec = TtkGetImageSpec( - interp, basePtr->core.tkwin, basePtr->base.imageObj); + imageSpec = TtkGetImageSpecEx( + interp, basePtr->core.tkwin, basePtr->base.imageObj, BaseImageChanged, basePtr); if (!imageSpec) { goto error; } @@ -413,8 +422,8 @@ typedef struct static Tk_OptionSpec CheckbuttonOptionSpecs[] = { {TK_OPTION_STRING, "-variable", "variable", "Variable", - "", Tk_Offset(Checkbutton, checkbutton.variableObj), -1, - TK_OPTION_DONT_SET_DEFAULT,0,0}, + NULL, Tk_Offset(Checkbutton, checkbutton.variableObj), -1, + TK_OPTION_NULL_OK,0,0}, {TK_OPTION_STRING, "-onvalue", "onValue", "OnValue", "1", Tk_Offset(Checkbutton, checkbutton.onValueObj), -1, 0,0,0}, diff --git a/generic/ttk/ttkClamTheme.c b/generic/ttk/ttkClamTheme.c index 15ebcb7..b44eeb5 100644 --- a/generic/ttk/ttkClamTheme.c +++ b/generic/ttk/ttkClamTheme.c @@ -7,8 +7,8 @@ #include <tk.h> #include "ttkTheme.h" -/* - * Under windows, the Tk-provided XDrawLine and XDrawArc have an +/* + * Under windows, the Tk-provided XDrawLine and XDrawArc have an * off-by-one error in the end point. This is especially apparent with this * theme. Defining this macro as true handles this case. */ @@ -123,8 +123,8 @@ static Ttk_ElementOptionSpec BorderElementOptions[] = { /* * <<NOTE-BORDERWIDTH>>: -borderwidth is only partially supported: * in this theme, borders are always exactly 2 pixels thick. - * With -borderwidth 0, border is not drawn at all; - * otherwise a 2-pixel border is used. For -borderwidth > 2, + * With -borderwidth 0, border is not drawn at all; + * otherwise a 2-pixel border is used. For -borderwidth > 2, * the excess is used as padding. */ @@ -402,7 +402,7 @@ typedef struct { static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] = { { "-arrowsize", TK_OPTION_PIXELS, - Tk_Offset(MenuIndicatorElement,sizeObj), + Tk_Offset(MenuIndicatorElement,sizeObj), STR(MENUBUTTON_ARROW_SIZE)}, { "-arrowcolor",TK_OPTION_COLOR, Tk_Offset(MenuIndicatorElement,colorObj), @@ -630,7 +630,7 @@ static void ThumbElementDraw( Tcl_GetIntFromObj(NULL, sb->gripCountObj, &gripCount); lightGC = Ttk_GCForColor(tkwin,sb->lightColorObj,d); darkGC = Ttk_GCForColor(tkwin,sb->borderColorObj,d); - + if (orient == TTK_ORIENT_HORIZONTAL) { dx = 1; dy = 0; x1 = x2 = b.x + b.width / 2 - gripCount; @@ -710,12 +710,12 @@ static void PbarElementDraw( Drawable d, Ttk_Box b, unsigned state) { ScrollbarElement *sb = elementRecord; - + b = Ttk_PadBox(b, Ttk_UniformPadding(2)); if (b.width > 4 && b.height > 4) { DrawSmoothBorder(tkwin, d, b, sb->borderColorObj, sb->lightColorObj, sb->darkColorObj); - XFillRectangle(Tk_Display(tkwin), d, + XFillRectangle(Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj), b.x+2, b.y+2, b.width-4, b.height-4); } @@ -780,8 +780,8 @@ static Ttk_ElementSpec ArrowElementSpec = { /*------------------------------------------------------------------------ * +++ Notebook elements. - * - * Note: Tabs, except for the rightmost, overlap the neighbor to + * + * Note: Tabs, except for the rightmost, overlap the neighbor to * their right by one pixel. */ diff --git a/generic/ttk/ttkClassicTheme.c b/generic/ttk/ttkClassicTheme.c index 2fbcd76..d16cb85 100644 --- a/generic/ttk/ttkClassicTheme.c +++ b/generic/ttk/ttkClassicTheme.c @@ -68,7 +68,7 @@ static Ttk_ElementSpec HighlightElementSpec = /*------------------------------------------------------------------------ * +++ Button Border element: - * + * * The Motif-style button border on X11 consists of (from outside-in): * * + focus indicator (controlled by -highlightcolor and -highlightthickness), @@ -85,13 +85,13 @@ typedef struct { static Ttk_ElementOptionSpec ButtonBorderElementOptions[] = { - { "-background", TK_OPTION_BORDER, + { "-background", TK_OPTION_BORDER, Tk_Offset(ButtonBorderElement,borderObj), DEFAULT_BACKGROUND }, - { "-borderwidth", TK_OPTION_PIXELS, + { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(ButtonBorderElement,borderWidthObj), DEFAULT_BORDERWIDTH }, - { "-relief", TK_OPTION_RELIEF, + { "-relief", TK_OPTION_RELIEF, Tk_Offset(ButtonBorderElement,reliefObj), "flat" }, - { "-default", TK_OPTION_ANY, + { "-default", TK_OPTION_ANY, Tk_Offset(ButtonBorderElement,defaultStateObj), "disabled" }, { NULL, 0, 0, NULL } }; @@ -115,7 +115,7 @@ static void ButtonBorderElementSize( /* * (@@@ Note: ButtonBorderElement still still still buggy: - * padding for default ring is drawn in the wrong color + * padding for default ring is drawn in the wrong color * when the button is active.) */ static void ButtonBorderElementDraw( @@ -281,19 +281,19 @@ static Ttk_ElementSpec ArrowElementSpec = /*------------------------------------------------------------------------ * +++ Sash element (for ttk::panedwindow) * - * NOTES: + * NOTES: * * panedwindows with -orient horizontal use vertical sashes, and vice versa. * * Interpretation of -sashrelief 'groove' and 'ridge' are * swapped wrt. the core panedwindow, which (I think) has them backwards. * - * Default -sashrelief is sunken; the core panedwindow has default + * Default -sashrelief is sunken; the core panedwindow has default * -sashrelief raised, but that looks wrong to me. */ static Ttk_Orient SashClientData[] = { - TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL + TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL }; typedef struct { @@ -306,13 +306,13 @@ typedef struct { } SashElement; static Ttk_ElementOptionSpec SashOptions[] = { - { "-background", TK_OPTION_BORDER, + { "-background", TK_OPTION_BORDER, Tk_Offset(SashElement,borderObj), DEFAULT_BACKGROUND }, - { "-sashrelief", TK_OPTION_RELIEF, + { "-sashrelief", TK_OPTION_RELIEF, Tk_Offset(SashElement,sashReliefObj), "sunken" }, { "-sashthickness", TK_OPTION_PIXELS, Tk_Offset(SashElement,sashThicknessObj), "6" }, - { "-sashpad", TK_OPTION_PIXELS, + { "-sashpad", TK_OPTION_PIXELS, Tk_Offset(SashElement,sashPadObj), "2" }, { "-handlesize", TK_OPTION_PIXELS, Tk_Offset(SashElement,handleSizeObj), "8" }, @@ -367,10 +367,10 @@ static void SashElementDraw( gc1 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC); break; - case TK_RELIEF_SOLID: + case TK_RELIEF_SOLID: gc1 = gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); break; - case TK_RELIEF_FLAT: + case TK_RELIEF_FLAT: default: gc1 = gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC); break; @@ -398,7 +398,7 @@ static void SashElementDraw( hb = Ttk_StickBox(b, handleSize, handleSize, TTK_STICK_N); hb.y += handlePad; } - Tk_Fill3DRectangle(tkwin, d, border, + Tk_Fill3DRectangle(tkwin, d, border, hb.x, hb.y, hb.width, hb.height, 1, TK_RELIEF_RAISED); } } @@ -495,7 +495,7 @@ MODULE_SCOPE int TtkClassicTheme_Init(Tcl_Interp *interp) Ttk_RegisterElement(interp, theme, "arrow", &ArrowElementSpec, &ArrowElements[0]); - Ttk_RegisterElement(interp, theme, "hsash", + Ttk_RegisterElement(interp, theme, "hsash", &SashElementSpec, &SashClientData[0]); Ttk_RegisterElement(interp, theme, "vsash", &SashElementSpec, &SashClientData[1]); diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c index f395649..a25574a 100644 --- a/generic/ttk/ttkEntry.c +++ b/generic/ttk/ttkEntry.c @@ -282,15 +282,16 @@ static char *EntryDisplayString(const char *showChar, int numChars) { char *displayString, *p; int size; - Tcl_UniChar ch; - char buf[TCL_UTF_MAX]; + int ch; + char buf[6]; - Tcl_UtfToUniChar(showChar, &ch); - size = Tcl_UniCharToUtf(ch, buf); + TkUtfToUniChar(showChar, &ch); + size = TkUniCharToUtf(ch, buf); p = displayString = ckalloc(numChars * size + 1); while (numChars--) { - p += Tcl_UniCharToUtf(ch, p); + memcpy(p, buf, size); + p += size; } *p = '\0'; @@ -405,7 +406,7 @@ ExpandPercents( int number, length; const char *string; int stringLength; - Tcl_UniChar ch; + int ch; char numStorage[2*TCL_INTEGER_SPACE]; while (*template) { @@ -429,7 +430,7 @@ ExpandPercents( */ ++template; /* skip over % */ if (*template != '\0') { - template += Tcl_UtfToUniChar(template, &ch); + template += TkUtfToUniChar(template, &ch); } else { ch = '%'; } @@ -479,7 +480,7 @@ ExpandPercents( string = Tk_PathName(entryPtr->core.tkwin); break; default: - length = Tcl_UniCharToUtf(ch, numStorage); + length = TkUniCharToUtf(ch, numStorage); numStorage[length] = '\0'; string = numStorage; break; diff --git a/generic/ttk/ttkGenStubs.tcl b/generic/ttk/ttkGenStubs.tcl index 56ba2fa..8047e3f 100644 --- a/generic/ttk/ttkGenStubs.tcl +++ b/generic/ttk/ttkGenStubs.tcl @@ -18,8 +18,6 @@ # + Allow trailing semicolon in function declarations # -package require Tcl 8.4 - namespace eval genStubs { # libraryName -- # diff --git a/generic/ttk/ttkImage.c b/generic/ttk/ttkImage.c index a5a3a52..e403e2d 100644 --- a/generic/ttk/ttkImage.c +++ b/generic/ttk/ttkImage.c @@ -25,6 +25,8 @@ struct TtkImageSpec { int mapCount; /* #state-specific overrides */ Ttk_StateSpec *states; /* array[mapCount] of states ... */ Tk_Image *images; /* ... per-state images to use */ + Tk_ImageChangedProc *imageChanged; + ClientData imageChangedClientData; }; /* NullImageChanged -- @@ -34,15 +36,41 @@ static void NullImageChanged(ClientData clientData, int x, int y, int width, int height, int imageWidth, int imageHeight) { /* No-op */ } +/* ImageSpecImageChanged -- + * Image changes should trigger a repaint. + */ +static void ImageSpecImageChanged(ClientData clientData, + int x, int y, int width, int height, int imageWidth, int imageHeight) +{ + Ttk_ImageSpec *imageSpec = (Ttk_ImageSpec *)clientData; + if (imageSpec->imageChanged != NULL) { + imageSpec->imageChanged(imageSpec->imageChangedClientData, + x, y, width, height, + imageWidth, imageHeight); + } +} + /* TtkGetImageSpec -- * Constructs a Ttk_ImageSpec * from a Tcl_Obj *. * Result must be released using TtkFreeImageSpec. * - * TODO: Need a variant of this that takes a user-specified ImageChanged proc */ Ttk_ImageSpec * TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr) { + return TtkGetImageSpecEx(interp, tkwin, objPtr, NULL, NULL); +} + +/* TtkGetImageSpecEx -- + * Constructs a Ttk_ImageSpec * from a Tcl_Obj *. + * Result must be released using TtkFreeImageSpec. + * imageChangedProc will be called when not NULL when + * the image changes to allow widgets to repaint. + */ +Ttk_ImageSpec * +TtkGetImageSpecEx(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr, + Tk_ImageChangedProc *imageChangedProc, ClientData imageChangedClientData) +{ Ttk_ImageSpec *imageSpec = 0; int i = 0, n = 0, objc; Tcl_Obj **objv; @@ -52,6 +80,8 @@ TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr) imageSpec->mapCount = 0; imageSpec->states = 0; imageSpec->images = 0; + imageSpec->imageChanged = imageChangedProc; + imageSpec->imageChangedClientData = imageChangedClientData; if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) { goto error; @@ -74,7 +104,7 @@ TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr) /* Get base image: */ imageSpec->baseImage = Tk_GetImage( - interp, tkwin, Tcl_GetString(objv[0]), NullImageChanged, NULL); + interp, tkwin, Tcl_GetString(objv[0]), ImageSpecImageChanged, imageSpec); if (!imageSpec->baseImage) { goto error; } diff --git a/generic/ttk/ttkLabel.c b/generic/ttk/ttkLabel.c index 1037840..b8b7f29 100644 --- a/generic/ttk/ttkLabel.c +++ b/generic/ttk/ttkLabel.c @@ -139,7 +139,7 @@ static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b) gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); gc2 = Tk_GetGC(tkwin, GCFont | GCForeground, &gcValues); - /* + /* * Place text according to -anchor: */ Tk_GetAnchorFromObj(NULL, text->anchorObj, &anchor); @@ -342,15 +342,15 @@ static void ImageDraw( Tk_RedrawImage(image->tkimg, 0,0, width, height, d, b.x, b.y); - /* If we're disabled there's no state-specific 'disabled' image, + /* If we're disabled there's no state-specific 'disabled' image, * stipple the image. * @@@ Possibly: Don't do disabled-stippling at all; * @@@ it's ugly and out of fashion. - * Do not stipple at all under Aqua, just draw the image: it shows up + * Do not stipple at all under Aqua, just draw the image: it shows up * as a white rectangle otherwise. */ - + if (state & TTK_STATE_DISABLED) { if (TtkSelectImage(image->imageSpec, 0ul) == image->tkimg) { #ifndef MAC_OSX_TK @@ -577,7 +577,7 @@ static void LabelElementSize( if (label->compound != TTK_COMPOUND_IMAGE) textReqWidth = TextReqWidth(&label->text); - switch (label->compound) + switch (label->compound) { case TTK_COMPOUND_TEXT: *widthPtr = textReqWidth; @@ -588,11 +588,11 @@ static void LabelElementSize( case TTK_COMPOUND_TOP: case TTK_COMPOUND_BOTTOM: case TTK_COMPOUND_CENTER: - *widthPtr = MAX(label->image.width, textReqWidth); + *widthPtr = MAX(label->image.width, textReqWidth); break; case TTK_COMPOUND_LEFT: case TTK_COMPOUND_RIGHT: - *widthPtr = label->image.width + textReqWidth + label->space; + *widthPtr = label->image.width + textReqWidth + label->space; break; case TTK_COMPOUND_NONE: break; /* Can't happen */ diff --git a/generic/ttk/ttkManager.c b/generic/ttk/ttkManager.c index 24a0fb1..031fdec 100644 --- a/generic/ttk/ttkManager.c +++ b/generic/ttk/ttkManager.c @@ -320,7 +320,7 @@ void Ttk_GeometryRequestProc(ClientData clientData, Tk_Window slaveWindow) int reqHeight= Tk_ReqHeight(slaveWindow); if (mgr->managerSpec->SlaveRequest( - mgr->managerData, slaveIndex, reqWidth, reqHeight)) + mgr->managerData, slaveIndex, reqWidth, reqHeight)) { ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED); } diff --git a/generic/ttk/ttkManager.h b/generic/ttk/ttkManager.h index d22ff98..07fcea1 100644 --- a/generic/ttk/ttkManager.h +++ b/generic/ttk/ttkManager.h @@ -22,7 +22,7 @@ typedef struct TtkManager_ Ttk_Manager; * SlaveRemoved() is called immediately before a slave is removed. * NB: the associated slave window may have been destroyed when this * routine is called. - * + * * SlaveRequest() is called when a slave requests a size change. * It should return 1 if the request should propagate, 0 otherwise. */ diff --git a/generic/ttk/ttkNotebook.c b/generic/ttk/ttkNotebook.c index 16a8bfe..81a8b64 100644 --- a/generic/ttk/ttkNotebook.c +++ b/generic/ttk/ttkNotebook.c @@ -901,7 +901,7 @@ static int NotebookAddCommand( if (tab->state == TAB_STATE_HIDDEN) { tab->state = TAB_STATE_NORMAL; } - if (ConfigureTab(interp, nb, tab, slaveWindow, objc-4,objv+4) != TCL_OK) { + if (ConfigureTab(interp, nb, tab, slaveWindow, objc-3,objv+3) != TCL_OK) { return TCL_ERROR; } diff --git a/generic/ttk/ttkProgress.c b/generic/ttk/ttkProgress.c index 4dc50a2..eed90ec 100644 --- a/generic/ttk/ttkProgress.c +++ b/generic/ttk/ttkProgress.c @@ -398,7 +398,7 @@ static int ProgressbarStepCommand( { Progressbar *pb = recordPtr; double value = 0.0, stepAmount = 1.0; - Tcl_Obj *newValueObj; + Tcl_Obj *newValueObj; if (objc == 3) { if (Tcl_GetDoubleFromObj(interp, objv[2], &stepAmount) != TCL_OK) { @@ -424,7 +424,7 @@ static int ProgressbarStepCommand( TtkRedisplayWidget(&pb->core); - /* Update value by setting the linked -variable, if there is one: + /* Update value by setting the linked -variable, if there is one: */ if (pb->progress.variableTrace) { return Tcl_ObjSetVar2( @@ -444,7 +444,7 @@ static int ProgressbarStepCommand( } /* $sb start|stop ?args? -- - * Change [$sb $cmd ...] to [ttk::progressbar::$cmd ...] + * Change [$sb $cmd ...] to [ttk::progressbar::$cmd ...] * and pass to interpreter. */ static int ProgressbarStartStopCommand( diff --git a/generic/ttk/ttkScale.c b/generic/ttk/ttkScale.c index 69753d1..95824af 100644 --- a/generic/ttk/ttkScale.c +++ b/generic/ttk/ttkScale.c @@ -46,14 +46,14 @@ typedef struct static Tk_OptionSpec ScaleOptionSpecs[] = { {TK_OPTION_STRING, "-command", "command", "Command", "", - Tk_Offset(Scale,scale.commandObj), -1, + Tk_Offset(Scale,scale.commandObj), -1, TK_OPTION_NULL_OK,0,0}, {TK_OPTION_STRING, "-variable", "variable", "Variable", "", - Tk_Offset(Scale,scale.variableObj), -1, + Tk_Offset(Scale,scale.variableObj), -1, 0,0,0}, {TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "horizontal", Tk_Offset(Scale,scale.orientObj), - Tk_Offset(Scale,scale.orient), 0, + Tk_Offset(Scale,scale.orient), 0, (ClientData)ttkOrientStrings, STYLE_CHANGED }, {TK_OPTION_DOUBLE, "-from", "from", "From", "0", @@ -63,7 +63,7 @@ static Tk_OptionSpec ScaleOptionSpecs[] = {TK_OPTION_DOUBLE, "-value", "value", "Value", "0", Tk_Offset(Scale,scale.valueObj), -1, 0, 0, 0}, {TK_OPTION_PIXELS, "-length", "length", "Length", - DEF_SCALE_LENGTH, Tk_Offset(Scale,scale.lengthObj), -1, 0, 0, + DEF_SCALE_LENGTH, Tk_Offset(Scale,scale.lengthObj), -1, 0, 0, GEOMETRY_CHANGED}, WIDGET_TAKEFOCUS_TRUE, @@ -76,7 +76,7 @@ static double PointToValue(Scale *scalePtr, int x, int y); /* ScaleVariableChanged -- * Variable trace procedure for scale -variable; * Updates the scale's value. - * If the linked variable is not a valid double, + * If the linked variable is not a valid double, * sets the 'invalid' state. */ static void ScaleVariableChanged(void *recordPtr, const char *value) @@ -172,7 +172,7 @@ static int ScalePostConfigure( /* ScaleGetLayout -- * getLayout hook. */ -static Ttk_Layout +static Ttk_Layout ScaleGetLayout(Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr) { Scale *scalePtr = recordPtr; @@ -236,7 +236,7 @@ static double ScaleFraction(Scale *scalePtr, double value) } /* $scale get ?x y? -- - * Returns the current value of the scale widget, or if $x and + * Returns the current value of the scale widget, or if $x and * $y are specified, the value represented by point @x,y. */ static int diff --git a/generic/ttk/ttkScrollbar.c b/generic/ttk/ttkScrollbar.c index 5b0c212..9d99ea5 100644 --- a/generic/ttk/ttkScrollbar.c +++ b/generic/ttk/ttkScrollbar.c @@ -22,7 +22,7 @@ typedef struct double first; /* top fraction */ double last; /* bottom fraction */ - Ttk_Box troughBox; /* trough parcel */ + Ttk_Box troughBox; /* trough parcel */ int minSize; /* minimum size of thumb */ } ScrollbarPart; @@ -50,7 +50,7 @@ static Tk_OptionSpec ScrollbarOptionSpecs[] = * +++ Widget hooks. */ -static void +static void ScrollbarInitialize(Tcl_Interp *interp, void *recordPtr) { Scrollbar *sb = recordPtr; @@ -241,7 +241,7 @@ ScrollbarDeltaCommand( /* $sb fraction $x $y -- * Returns a real number between 0 and 1 indicating where the - * point given by x and y lies in the trough area of the scrollbar. + * point given by x and y lies in the trough area of the scrollbar. */ static int ScrollbarFractionCommand( diff --git a/generic/ttk/ttkSquare.c b/generic/ttk/ttkSquare.c index d002f2f..7837310 100644 --- a/generic/ttk/ttkSquare.c +++ b/generic/ttk/ttkSquare.c @@ -56,24 +56,24 @@ static Tk_OptionSpec SquareOptionSpecs[] = {TK_OPTION_BORDER, "-foreground", "foreground", "Foreground", DEFAULT_BACKGROUND, Tk_Offset(Square,square.foregroundObj), -1, 0, 0, 0}, - + {TK_OPTION_PIXELS, "-width", "width", "Width", "50", Tk_Offset(Square,square.widthObj), -1, 0, 0, GEOMETRY_CHANGED}, {TK_OPTION_PIXELS, "-height", "height", "Height", "50", Tk_Offset(Square,square.heightObj), -1, 0, 0, GEOMETRY_CHANGED}, - + {TK_OPTION_STRING, "-padding", "padding", "Pad", NULL, - Tk_Offset(Square,square.paddingObj), -1, + Tk_Offset(Square,square.paddingObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, - + {TK_OPTION_RELIEF, "-relief", "relief", "Relief", NULL, Tk_Offset(Square,square.reliefObj), -1, TK_OPTION_NULL_OK, 0, 0}, - + {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", NULL, Tk_Offset(Square,square.anchorObj), -1, TK_OPTION_NULL_OK, 0, 0}, - + WIDGET_TAKEFOCUS_TRUE, WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs) }; @@ -138,7 +138,7 @@ static const Ttk_Ensemble SquareCommands[] = { }; /* - * The Widget specification structure holds all the implementation + * The Widget specification structure holds all the implementation * information about this widget and this is what must be registered * with Tk in the package initialization code (see bottom). */ @@ -159,7 +159,7 @@ static WidgetSpec SquareWidgetSpec = TtkWidgetDisplay /* displayProc */ }; -/* ---------------------------------------------------------------------- +/* ---------------------------------------------------------------------- * Square element * * In this section we demonstrate what is required to create a new themed @@ -176,7 +176,7 @@ typedef struct Tcl_Obj *heightObj; } SquareElement; -static Ttk_ElementOptionSpec SquareElementOptions[] = +static Ttk_ElementOptionSpec SquareElementOptions[] = { { "-background", TK_OPTION_BORDER, Tk_Offset(SquareElement,borderObj), DEFAULT_BACKGROUND }, @@ -248,7 +248,7 @@ static Ttk_ElementSpec SquareElementSpec = * engine is similar to the Tk pack geometry manager. Read the documentation * for the details. In this example we just need to have the square element * that has been defined for this widget placed on a background. We will - * also need some padding to keep it away from the edges. + * also need some padding to keep it away from the edges. */ TTK_BEGIN_LAYOUT(SquareLayout) @@ -257,12 +257,12 @@ TTK_BEGIN_LAYOUT(SquareLayout) TTK_NODE("Square.square", 0)) TTK_END_LAYOUT -/* ---------------------------------------------------------------------- +/* ---------------------------------------------------------------------- * * Widget initialization. * * This file defines a new element and a new widget. We need to register - * the element with the themes that will need it. In this case we will + * the element with the themes that will need it. In this case we will * register with the default theme that is the root of the theme inheritance * tree. This means all themes will find this element. * We then need to register the widget class style. This is the layout @@ -287,10 +287,10 @@ TtkSquareWidget_Init(Tcl_Interp *interp) /* register the new elements for this theme engine */ Ttk_RegisterElement(interp, theme, "square", &SquareElementSpec, NULL); - + /* register the layout for this theme */ Ttk_RegisterLayout(theme, "TSquare", SquareLayout); - + /* register the widget */ RegisterWidget(interp, "ttk::square", &SquareWidgetSpec); diff --git a/generic/ttk/ttkStubLib.c b/generic/ttk/ttkStubLib.c index 2c07b9d..c17f1e9 100644 --- a/generic/ttk/ttkStubLib.c +++ b/generic/ttk/ttkStubLib.c @@ -67,7 +67,7 @@ error: "Error loading ", packageName, " package", " (requested version '", version, "', loaded version '", actualVersion, "'): ", - errMsg, + errMsg, NULL); return NULL; } diff --git a/generic/ttk/ttkTagSet.c b/generic/ttk/ttkTagSet.c index f2108b9..31798ea 100644 --- a/generic/ttk/ttkTagSet.c +++ b/generic/ttk/ttkTagSet.c @@ -188,7 +188,7 @@ int Ttk_TagSetAdd(Ttk_TagSet tagset, Ttk_Tag tag) return 0; } } - tagset->tags = ckrealloc(tagset->tags, + tagset->tags = ckrealloc(tagset->tags, (tagset->nTags+1)*sizeof(tagset->tags[0])); tagset->tags[tagset->nTags++] = tag; return 1; diff --git a/generic/ttk/ttkTheme.h b/generic/ttk/ttkTheme.h index 7bf2a7f..9251dea 100644 --- a/generic/ttk/ttkTheme.h +++ b/generic/ttk/ttkTheme.h @@ -372,6 +372,8 @@ MODULE_SCOPE void Ttk_RegisterNamedColor(Ttk_ResourceCache, const char *, XColor typedef struct TtkImageSpec Ttk_ImageSpec; TTKAPI Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *); +TTKAPI Ttk_ImageSpec *TtkGetImageSpecEx(Tcl_Interp *, Tk_Window, Tcl_Obj *, + Tk_ImageChangedProc *, ClientData); TTKAPI void TtkFreeImageSpec(Ttk_ImageSpec *); TTKAPI Tk_Image TtkSelectImage(Ttk_ImageSpec *, Ttk_State); diff --git a/generic/ttk/ttkTrace.c b/generic/ttk/ttkTrace.c index ba66db4..c0f17cf 100644 --- a/generic/ttk/ttkTrace.c +++ b/generic/ttk/ttkTrace.c @@ -3,7 +3,7 @@ * * Simplified interface to Tcl_TraceVariable. * - * PROBLEM: Can't distinguish "variable does not exist" (which is OK) + * PROBLEM: Can't distinguish "variable does not exist" (which is OK) * from other errors (which are not). */ diff --git a/generic/ttk/ttkWidget.h b/generic/ttk/ttkWidget.h index e4dd712..798bcce 100644 --- a/generic/ttk/ttkWidget.h +++ b/generic/ttk/ttkWidget.h @@ -111,8 +111,8 @@ MODULE_SCOPE int TtkWidgetConstructorObjCmd( /* WIDGET_TAKEFOCUS_TRUE -- * WIDGET_TAKEFOCUS_FALSE -- - * Add one or the other of these to each OptionSpecs table - * to indicate whether the widget should take focus + * Add one or the other of these to each OptionSpecs table + * to indicate whether the widget should take focus * during keyboard traversal. */ #define WIDGET_TAKEFOCUS_TRUE \ |