diff options
author | gcramer <remarcg@gmx.net> | 2017-02-26 16:59:20 (GMT) |
---|---|---|
committer | gcramer <remarcg@gmx.net> | 2017-02-26 16:59:20 (GMT) |
commit | 35bf8cdc33fc89fb1e28a4110b4e43943aaf66af (patch) | |
tree | b0cb2718b37a114aa80cf23a5f340b68c57b7011 /generic | |
parent | 0b8cbd9b07fd2c36c526e302d2d4f9f852ea25d9 (diff) | |
download | tk-35bf8cdc33fc89fb1e28a4110b4e43943aaf66af.zip tk-35bf8cdc33fc89fb1e28a4110b4e43943aaf66af.tar.gz tk-35bf8cdc33fc89fb1e28a4110b4e43943aaf66af.tar.bz2 |
(1) Some memory problems fixed, with the help of a fine granulated valgrind test
(2) 'char* reliefString' changed to 'Tcl_Obj *reliefPtr', required for fine granulated valgrind test
(3) Severe bug in embedded window handling fixed
(4) Minor display problem with selected text fixed (function MakeStyle)
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkAlloc.h | 56 | ||||
-rw-r--r-- | generic/tkBitField.h | 5 | ||||
-rw-r--r-- | generic/tkText.c | 33 | ||||
-rw-r--r-- | generic/tkText.h | 5 | ||||
-rw-r--r-- | generic/tkTextBTree.c | 140 | ||||
-rw-r--r-- | generic/tkTextDisp.c | 23 | ||||
-rw-r--r-- | generic/tkTextImage.c | 15 | ||||
-rw-r--r-- | generic/tkTextIndex.c | 4 | ||||
-rw-r--r-- | generic/tkTextMark.c | 1 | ||||
-rw-r--r-- | generic/tkTextPriv.h | 2 | ||||
-rw-r--r-- | generic/tkTextTag.c | 36 | ||||
-rw-r--r-- | generic/tkTextWind.c | 17 |
12 files changed, 229 insertions, 108 deletions
diff --git a/generic/tkAlloc.h b/generic/tkAlloc.h index 9b68be6..93e0c5d 100644 --- a/generic/tkAlloc.h +++ b/generic/tkAlloc.h @@ -19,24 +19,70 @@ #ifndef _TK_ALLOC #define _TK_ALLOC -#include "tcl.h" +#include <tcl.h> +#include <tclDecls.h> /* needed for the Tcl_Alloc macros */ #include <stdlib.h> -#if TK_VALGRIND -/* enables compiler check that these functions will not be used */ +#if TK_VALGRIND /* ===========================================================*/ + +/* + * Ensure that the Tcl allocation suite will not be used, because a mix + * of ckalloc and malloc must be avoided. When valgrind mode is activated + * then the functions malloc/realloc/free will be used directly, in this + * way the fine granulated memory check of valgrind can be used. This is + * not possible when using the Tcl allocation suite, because these + * functions are bypassing the fine granulated check. (Valgrind is replacing + * malloc/realloc/free with his own memory functions.) + */ + # undef ckalloc # undef ckrealloc # undef ckfree -#else /* if !TK_VALGRIND */ +# ifdef Tcl_Alloc +# undef Tcl_Alloc +# undef Tcl_Realloc +# undef Tcl_Free +# undef Tcl_AttemptAlloc +# undef Tcl_AttemptRealloc +# undef Tcl_DbCkalloc +# undef Tcl_DbCkrealloc +# undef Tcl_DbCkfree +# endif + +# define Tcl_Alloc -- +# define Tcl_Realloc -- +# define Tcl_Free -- +# define Tcl_AttemptAlloc -- +# define Tcl_AttemptRealloc -- +# define Tcl_DbCkalloc -- +# define Tcl_DbCkrealloc -- +# define Tcl_DbCkfree -- + +#else /* if !TK_VALGRIND ==================================================== */ + +/* + * If valgrind mode is disabled, then we use the Tcl allocations functions. + * This means that malloc/realloc/free are simply wrappers to the Tcl + * functions ckalloc/ckrealloc/ckfree. + */ /* the main reason for these definitions is portability to 8.5 */ # define malloc(size) ((void *) (ckalloc(size))) # define realloc(ptr, size) ((void *) (ckrealloc((char *) (ptr), size))) # define free(ptr) ckfree((char *) (ptr)) -#endif /* TK_VALGRIND */ +#endif /* TK_VALGRIND ======================================================= */ + + +/* + * The following functions/macros are not supported with this memory + * allocation scheme. + */ + +# undef attemptckalloc +# undef attemptckrealloc #endif /* _TK_ALLOC */ /* vi:set ts=8 sw=4: */ diff --git a/generic/tkBitField.h b/generic/tkBitField.h index a9dcb8d..5691bba 100644 --- a/generic/tkBitField.h +++ b/generic/tkBitField.h @@ -12,11 +12,8 @@ #ifndef _TKBITFIELD #define _TKBITFIELD -#ifndef _TK #include "tk.h" -#endif - -#include "tkInt.h" /* required for inline support */ +#include "tkInt.h" /* needed for inline support */ #include "tkBool.h" #include <stdint.h> diff --git a/generic/tkText.c b/generic/tkText.c index adca223..fef8263 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -21,6 +21,7 @@ #include "tkTextUndo.h" #include "tkTextTagSet.h" #include "tkBitField.h" +#include "tkAlloc.h" #include <stdlib.h> #include <ctype.h> #include <assert.h> @@ -1129,9 +1130,6 @@ CreateWidget( */ textPtr->selTagPtr = TkTextCreateTag(textPtr, "sel", NULL); - textPtr->selTagPtr->reliefString = malloc(strlen(DEF_TEXT_SELECT_RELIEF) + 1); - strcpy(textPtr->selTagPtr->reliefString, DEF_TEXT_SELECT_RELIEF); - Tk_GetRelief(interp, DEF_TEXT_SELECT_RELIEF, &textPtr->selTagPtr->relief); textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &startIndex); textPtr->currentMarkPtr = TkTextSetMark(textPtr, "current", &startIndex); textPtr->currentMarkIndex = startIndex; @@ -4970,6 +4968,7 @@ InsertChars( if (undoInfoPtr) { const TkTextUndoSubAtom *subAtom; bool triggerStackEvent = false; + bool pushToken; assert(undoInfo.byteSize == 0); @@ -4978,10 +4977,19 @@ InsertChars( TkTextUndoPushSeparator(sharedTextPtr->undoStack, true); sharedTextPtr->lastUndoTokenType = -1; } - if (sharedTextPtr->lastUndoTokenType != TK_TEXT_UNDO_INSERT + + pushToken = sharedTextPtr->lastUndoTokenType != TK_TEXT_UNDO_INSERT || !((subAtom = TkTextUndoGetLastUndoSubAtom(sharedTextPtr->undoStack)) && (triggerStackEvent = TkBTreeJoinUndoInsert( - subAtom->item, subAtom->size, undoInfo.token, undoInfo.byteSize)))) { + subAtom->item, subAtom->size, undoInfo.token, undoInfo.byteSize))); + + assert(undoInfo.token->undoType->rangeProc); + sharedTextPtr->prevUndoStartIndex = ((TkTextUndoTokenRange *) undoInfo.token)->startIndex; + sharedTextPtr->prevUndoEndIndex = ((TkTextUndoTokenRange *) undoInfo.token)->endIndex; + sharedTextPtr->lastUndoTokenType = TK_TEXT_UNDO_INSERT; + sharedTextPtr->lastEditMode = TK_TEXT_EDIT_INSERT; + + if (pushToken) { TkTextPushUndoToken(sharedTextPtr, undoInfo.token, undoInfo.byteSize); } else { assert(!undoInfo.token->undoType->destroyProc); @@ -4991,11 +4999,6 @@ InsertChars( if (triggerStackEvent) { sharedTextPtr->undoStackEvent = true; /* TkBTreeJoinUndoInsert didn't trigger */ } - assert(undoInfo.token->undoType->rangeProc); - sharedTextPtr->prevUndoStartIndex = ((TkTextUndoTokenRange *) undoInfo.token)->startIndex; - sharedTextPtr->prevUndoEndIndex = ((TkTextUndoTokenRange *) undoInfo.token)->endIndex; - sharedTextPtr->lastUndoTokenType = TK_TEXT_UNDO_INSERT; - sharedTextPtr->lastEditMode = TK_TEXT_EDIT_INSERT; } *index2Ptr = *index1Ptr; @@ -7432,7 +7435,7 @@ DumpLine( TkBTreeMoveBackward(&index, 1); segPtr = TkTextIndexGetContentSegment(&index, NULL); assert(segPtr); - tagPtr = TkBTreeGetSegmentTags(textPtr->sharedTextPtr, segPtr, textPtr); + tagPtr = TkBTreeGetSegmentTags(textPtr->sharedTextPtr, segPtr, textPtr, NULL); for (tPtr = tagPtr; tPtr; tPtr = tPtr->nextPtr) { tPtr->flag = epoch; /* mark as open */ } @@ -7467,7 +7470,7 @@ DumpLine( if (offset + MAX(1, currentSize) > startByte) { if ((what & TK_DUMP_TAG) && segPtr->tagInfoPtr) { - TkTextTag *tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr); + TkTextTag *tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr, NULL); unsigned epoch = sharedTextPtr->inspectEpoch; unsigned nextEpoch = epoch + 1; TkTextTag *tPtr; @@ -8355,7 +8358,7 @@ TextInspectCmd( type = "break"; printTags = !!(what & TK_DUMP_TAG); tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, - segPtr->sectionPtr->linePtr->lastPtr, textPtr); + segPtr->sectionPtr->linePtr->lastPtr, textPtr, NULL); nextPtr = segPtr; /* repeat this mark */ } else { nextPtr = NULL; /* finished */ @@ -8387,7 +8390,7 @@ TextInspectCmd( tagPtr = prevTagPtr; segPtr->body.chars[segPtr->size - 1] = '\n'; } else if (type && printTags) { - tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr); + tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr, NULL); } } else { type = "text"; @@ -8397,7 +8400,7 @@ TextInspectCmd( } value = segPtr->body.chars; if (printTags) { - tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr); + tagPtr = TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr, NULL); } } } else if (!nextPtr) { diff --git a/generic/tkText.h b/generic/tkText.h index 868d514..0b35eca 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -25,7 +25,6 @@ #include "tkTextUndo.h" #include "tkQTree.h" #include "tkBool.h" -#include "tkAlloc.h" #include <stdint.h> #ifdef MAC_OSX_TK @@ -804,7 +803,7 @@ typedef struct TkTextTag { Tk_3DBorder border; /* Used for drawing background. NULL means no value specified here. */ int borderWidth; /* Width of 3-D border for background. */ Tcl_Obj *borderWidthPtr; /* Width of 3-D border for background. */ - char *reliefString; /* -relief option string (malloc-ed). NULL means option not specified. */ + Tcl_Obj *reliefPtr; /* -relief option object. NULL means option not specified. */ int relief; /* 3-D relief for background. */ Pixmap bgStipple; /* Stipple bitmap for background. None means no value specified here. */ char *indentBgString; /* Background will be indented accordingly to the -lmargin1, and @@ -1737,7 +1736,7 @@ MODULE_SCOPE TkTextSegment * TkBTreeFindEndOfElidedRange(const TkSharedText *sha const TkText *textPtr, const TkTextSegment *segPtr); inline TkTextTag * TkBTreeGetTags(const TkTextIndex *indexPtr); MODULE_SCOPE TkTextTag * TkBTreeGetSegmentTags(const TkSharedText *sharedTextPtr, - const TkTextSegment *segPtr, const TkText *textPtr); + const TkTextSegment *segPtr, const TkText *textPtr, bool *containsSelection); MODULE_SCOPE const char * TkBTreeGetLang(const TkText *textPtr, const TkTextSegment *segPtr); MODULE_SCOPE void TkBTreeInsertChars(TkTextBTree tree, TkTextIndex *indexPtr, const char *string, STRUCT TkTextTagSet *tagInfoPtr, TkTextTag *hyphenTagPtr, diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c index 78a12c7..7709b38 100644 --- a/generic/tkTextBTree.c +++ b/generic/tkTextBTree.c @@ -17,6 +17,7 @@ #include "tkText.h" #include "tkTextPriv.h" #include "tkTextTagSet.h" +#include "tkAlloc.h" #include <assert.h> #ifndef MIN @@ -253,7 +254,7 @@ static bool UndoIndexIsEqual(const TkTextUndoIndex *indexPtr1, static void AddTagToNode(Node *nodePtr, TkTextTag *tag, bool setTagoff); static void RemoveTagFromNode(Node *nodePtr, TkTextTag *tag); static void UpdateElideInfo(TkSharedText *sharedTextPtr, TkTextTag *tagPtr, - TkTextSegment *firstSegPtr, TkTextSegment *lastSegPtr, unsigned reason); + TkTextSegment **firstSegPtr, TkTextSegment **lastSegPtr, unsigned reason); static bool SegmentIsElided(const TkSharedText *sharedTextPtr, const TkTextSegment *segPtr, const TkText *textPtr); static TkTextLine * GetStartLine(const TkSharedText *sharedTextPtr, const TkText *textPtr); @@ -1335,6 +1336,7 @@ UndoDeletePerform( if (prevSegPtr) { if ((prevSegPtr = CleanupCharSegments(sharedTextPtr, prevSegPtr))->nextPtr != segPtr) { segPtr = prevSegPtr; + lastPtr = lastPtr->nextPtr; } } @@ -1416,7 +1418,9 @@ UndoDeletePerform( */ CleanupSplitPoint(firstPtr, sharedTextPtr); - CleanupSplitPoint(lastPtr, sharedTextPtr); + if (firstPtr != lastPtr) { + CleanupSplitPoint(lastPtr, sharedTextPtr); + } /* * Prevent that the destroy function will delete these segments. @@ -1524,6 +1528,7 @@ RedoDeletePerform( DeleteRange(sharedTextPtr, segPtr1, segPtr2, flags, redoInfo); + assert(segPtr1 != segPtr2); segPtr1->protectionFlag = true; segPtr2->protectionFlag = true; CleanupSplitPoint(segPtr1, sharedTextPtr); @@ -1848,12 +1853,14 @@ UndoClearTagsPerform( RecomputeLineTagInfo(linePtr, NULL, sharedTextPtr); UpdateNodeTags(sharedTextPtr, linePtr->parentPtr); if (updateElideInfo) { - UpdateElideInfo(sharedTextPtr, NULL, firstSegPtr, lastSegPtr, ELISION_HAS_BEEN_CHANGED); + UpdateElideInfo(sharedTextPtr, NULL, &firstSegPtr, &lastSegPtr, ELISION_HAS_BEEN_CHANGED); } firstSegPtr->protectionFlag = true; lastSegPtr->protectionFlag = true; CleanupSplitPoint(firstSegPtr, sharedTextPtr); - CleanupSplitPoint(lastSegPtr, sharedTextPtr); + if (firstSegPtr != lastSegPtr) { + CleanupSplitPoint(lastSegPtr, sharedTextPtr); + } TkBTreeIncrEpoch(sharedTextPtr->tree); TkTextRedrawTag(sharedTextPtr, NULL, &startIndex, &endIndex, NULL, affectsDisplayGeometry); @@ -3180,7 +3187,7 @@ SegmentIsElided( assert(segPtr->tagInfoPtr); return TkTextTagSetIntersectsBits(segPtr->tagInfoPtr, sharedTextPtr->elisionTags) - && TestIfElided(TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr)); + && TestIfElided(TkBTreeGetSegmentTags(sharedTextPtr, segPtr, textPtr, NULL)); } /* @@ -4200,7 +4207,6 @@ TkBTreeInsertChars( TkTextTagSet *myTagInfoPtr; TkTextTag *tagPtr; TkTextTag *hyphenElideTagPtr = NULL; - TkTextIndex index; UndoTokenInsert *undoToken = NULL; BTree *treePtr = (BTree *) tree; bool split = true; @@ -4230,7 +4236,6 @@ TkBTreeInsertChars( info.offset = -1; info.tagInfoPtr = tagInfoPtr; firstLinePtr = linePtr = TkTextIndexGetLine(indexPtr); - index = *indexPtr; TkTextIndexGetByteIndex(indexPtr); /* we need byte offset */ changeToLineCount = 0; changeToLogicalLineCount = 0; @@ -4258,7 +4263,7 @@ TkBTreeInsertChars( if (hyphenTagPtr) { int highestPriority = -1; - TkText *textPtr = index.textPtr; + TkText *textPtr = indexPtr->textPtr; for (tagPtr = hyphenTagPtr; tagPtr; tagPtr = tagPtr->nextPtr) { if (!TkTextTagSetTest(linePtr->parentPtr->tagonPtr, tagPtr->index)) { @@ -4343,7 +4348,7 @@ TkBTreeInsertChars( } else { assert(!firstSegPtr); assert(!info.tagInfoPtr); - tagInfoPtr = segPtr->tagInfoPtr = MakeTagInfo(index.textPtr, segPtr); + tagInfoPtr = segPtr->tagInfoPtr = MakeTagInfo(indexPtr->textPtr, segPtr); info.tagInfoPtr = tagInfoPtr; } for (tagPtr = hyphenTagPtr; tagPtr; tagPtr = tagPtr->nextPtr) { @@ -4395,7 +4400,7 @@ TkBTreeInsertChars( if (segPtr->tagInfoPtr) { tagInfoPtr = segPtr->tagInfoPtr; } else { - tagInfoPtr = MakeTagInfo(index.textPtr, segPtr); + tagInfoPtr = MakeTagInfo(indexPtr->textPtr, segPtr); } info.tagInfoPtr = tagInfoPtr; } @@ -4566,7 +4571,7 @@ TkBTreeInsertChars( && TkTextTagSetIntersectsBits(tagInfoPtr, sharedTextPtr->elisionTags)) { int highestPriority = -1; TkTextTag *tagPtr = NULL; - TkText *textPtr = index.textPtr; + TkText *textPtr = indexPtr->textPtr; unsigned i = TkTextTagSetFindFirst(tagInfoPtr); /* @@ -4591,10 +4596,14 @@ TkBTreeInsertChars( firstSegPtr->protectionFlag = true; lastSegPtr->protectionFlag = true; - UpdateElideInfo(sharedTextPtr, tagPtr, firstSegPtr, lastSegPtr, ELISION_HAS_BEEN_ADDED); + UpdateElideInfo(sharedTextPtr, tagPtr, &firstSegPtr, &lastSegPtr, ELISION_HAS_BEEN_ADDED); - CleanupSplitPoint(firstSegPtr, sharedTextPtr); - CleanupSplitPoint(lastSegPtr, sharedTextPtr); + if (!hyphenElideTagPtr) { + CleanupSplitPoint(firstSegPtr, sharedTextPtr); + if (firstSegPtr != lastSegPtr) { + CleanupSplitPoint(lastSegPtr, sharedTextPtr); + } + } if (hyphenElideTagPtr == tagPtr) { hyphenElideTagPtr = NULL; @@ -4606,11 +4615,13 @@ TkBTreeInsertChars( firstSegPtr->protectionFlag = true; lastSegPtr->protectionFlag = true; - UpdateElideInfo(sharedTextPtr, hyphenElideTagPtr, firstSegPtr, lastSegPtr, + UpdateElideInfo(sharedTextPtr, hyphenElideTagPtr, &firstSegPtr, &lastSegPtr, ELISION_HAS_BEEN_ADDED); CleanupSplitPoint(firstSegPtr, sharedTextPtr); - CleanupSplitPoint(lastSegPtr, sharedTextPtr); + if (firstSegPtr != lastSegPtr) { + CleanupSplitPoint(lastSegPtr, sharedTextPtr); + } } TkTextIndexSetEpoch(indexPtr, TkBTreeIncrEpoch(tree)); @@ -5988,8 +5999,8 @@ SplitCharSegment( TkTextSegment *newPtr1, *newPtr2; assert(segPtr); - assert(segPtr->typePtr == &tkTextCharType); - assert(segPtr->sectionPtr); /* otherwise segment is freed */ + assert(segPtr->typePtr == &tkTextCharType); /* still unfreed? */ + assert(segPtr->sectionPtr); /* still hooked? */ assert(index > 0); assert((int) index < segPtr->size); @@ -6300,9 +6311,11 @@ SplitSeg( count = 0; } else { segPtr = TkTextIndexGetFirstSegment(indexPtr, &count); + TkTextIndexToByteIndex((TkTextIndex *) indexPtr); /* mutable due to concept */ } } else { segPtr = TkTextIndexGetFirstSegment(indexPtr, &count); + TkTextIndexToByteIndex((TkTextIndex *) indexPtr); /* mutable due to concept */ } for ( ; segPtr; segPtr = segPtr->nextPtr) { @@ -6345,7 +6358,7 @@ SplitSeg( return segPtr->prevPtr; } /* - * Actually a split of a char segment necessary. + * Actually a split of the char segment is necessary. */ segPtr = SplitCharSegment(segPtr, count); TkTextIndexToByteIndex((TkTextIndex *) indexPtr); /* mutable due to concept */ @@ -7312,6 +7325,7 @@ DeleteIndexRange( DeleteRange(sharedTextPtr, firstPtr, lastPtr, myFlags, redoInfo); + assert(segPtr1 != segPtr2); CleanupSplitPoint(segPtr1, sharedTextPtr); CleanupSplitPoint(segPtr2, sharedTextPtr); @@ -8186,8 +8200,8 @@ static void UpdateElideInfo( TkSharedText *sharedTextPtr, TkTextTag *tagPtr, /* can be NULL */ - TkTextSegment *firstSegPtr, - TkTextSegment *lastSegPtr, + TkTextSegment **firstSegPtr, + TkTextSegment **lastSegPtr, unsigned reason) { TkTextSegment *prevBranchPtr; @@ -8238,16 +8252,16 @@ UpdateElideInfo( * This function assumes that the start/end points are already protected. */ - assert(firstSegPtr->protectionFlag); - assert(lastSegPtr->protectionFlag); + assert((*firstSegPtr)->protectionFlag); + assert((*lastSegPtr)->protectionFlag); - linePtr = firstSegPtr->sectionPtr->linePtr; + linePtr = (*firstSegPtr)->sectionPtr->linePtr; prevBranchPtr = lastBranchPtr = newBranchPtr = NULL; deletedBranchPtr = deletedLinkPtr = NULL; prevLinkPtr = lastLinkPtr = NULL; anyChanges = false; oldTextPtr = textPtr = NULL; - lastLinePtr = lastSegPtr->sectionPtr->linePtr; + lastLinePtr = (*lastSegPtr)->sectionPtr->linePtr; changeToLogicalLineCount = 0; nodePtr = NULL; startLinePtr = NULL; @@ -8257,7 +8271,7 @@ UpdateElideInfo( * Ensure that the range will include final branches. */ - endSegPtr = lastSegPtr; + endSegPtr = *lastSegPtr; while (endSegPtr->size == 0) { endSegPtr = endSegPtr->nextPtr; assert(endSegPtr); @@ -8283,7 +8297,7 @@ UpdateElideInfo( * specified region. */ - startSegPtr = firstSegPtr; + startSegPtr = *firstSegPtr; do { if (!(startSegPtr = startSegPtr->prevPtr) && linePtr->prevPtr) { startSegPtr = linePtr->prevPtr->lastPtr; @@ -8300,7 +8314,7 @@ UpdateElideInfo( startSegPtr = startSegPtr->nextPtr; } if (!startSegPtr) { - startSegPtr = firstSegPtr->sectionPtr->linePtr->segPtr; + startSegPtr = (*firstSegPtr)->sectionPtr->linePtr->segPtr; } /* @@ -8321,7 +8335,7 @@ UpdateElideInfo( endSegPtr->protectionFlag = true; linePtr = startSegPtr->sectionPtr->linePtr; - lastLinePtr = lastSegPtr->sectionPtr->linePtr; + lastLinePtr = (*lastSegPtr)->sectionPtr->linePtr; segPtr = startSegPtr; SetLineHasChanged(sharedTextPtr, linePtr); @@ -8391,6 +8405,12 @@ UpdateElideInfo( assert(TkBTreeHaveElidedSegments(sharedTextPtr)); assert(prevBranchPtr->sectionPtr->linePtr->numBranches > 0); + if (prevBranchPtr == *firstSegPtr) { + (*firstSegPtr = (*firstSegPtr)->nextPtr)->protectionFlag = true; + } + if (prevBranchPtr == *lastSegPtr) { + (*lastSegPtr = (*lastSegPtr)->nextPtr)->protectionFlag = true; + } UnlinkSegmentAndCleanup(sharedTextPtr, prevBranchPtr); if (deletedBranchPtr) { TkBTreeFreeSegment(prevBranchPtr); @@ -8406,6 +8426,12 @@ UpdateElideInfo( * Remove expired link. */ + if (prevLinkPtr == *firstSegPtr) { + (*firstSegPtr = (*firstSegPtr)->nextPtr)->protectionFlag = true; + } + if (prevLinkPtr == *lastSegPtr) { + (*lastSegPtr = (*lastSegPtr)->nextPtr)->protectionFlag = true; + } UnlinkSegmentAndCleanup(sharedTextPtr, prevLinkPtr); if (deletedLinkPtr) { TkBTreeFreeSegment(prevLinkPtr); @@ -8440,7 +8466,7 @@ UpdateElideInfo( * The related branch is starting outside of this range, * so we have to search for it. */ - lastBranchPtr = TkBTreeFindStartOfElidedRange(sharedTextPtr, NULL, firstSegPtr); + lastBranchPtr = TkBTreeFindStartOfElidedRange(sharedTextPtr, NULL, *firstSegPtr); assert(lastBranchPtr->typePtr == &tkTextBranchType); } @@ -8499,7 +8525,7 @@ UpdateElideInfo( * so we have to search for it. */ - lastLinkPtr = FindNextLink(sharedTextPtr, lastSegPtr); + lastLinkPtr = FindNextLink(sharedTextPtr, *lastSegPtr); assert(lastLinkPtr); } else { if (deletedLinkPtr) { @@ -8534,7 +8560,7 @@ UpdateElideInfo( RebuildSections(sharedTextPtr, linePtr, true); } - if (endSegPtr != lastSegPtr) { + if (endSegPtr != *lastSegPtr) { CleanupSplitPoint(endSegPtr, sharedTextPtr); } @@ -8592,10 +8618,12 @@ TkBTreeUpdateElideInfo( firstSegPtr->protectionFlag = true; search.segPtr->protectionFlag = true; - UpdateElideInfo(sharedTextPtr, tagPtr, firstSegPtr, search.segPtr, ELISION_HAS_BEEN_CHANGED); + UpdateElideInfo(sharedTextPtr, tagPtr, &firstSegPtr, &search.segPtr, ELISION_HAS_BEEN_CHANGED); CleanupSplitPoint(firstSegPtr, sharedTextPtr); - CleanupSplitPoint(search.segPtr, sharedTextPtr); + if (firstSegPtr != search.segPtr) { + CleanupSplitPoint(search.segPtr, sharedTextPtr); + } } TkBTreeIncrEpoch(sharedTextPtr->tree); @@ -8851,6 +8879,7 @@ AddRemoveTag( if (prevPtr && TkTextTagSetIsEqual(segPtr->tagInfoPtr, prevPtr->tagInfoPtr)) { TkTextSegment *pPtr = prevPtr; + segPtr->refCount += 1; /* delay possible destruction */ prevPtr = JoinCharSegments(sharedTextPtr, prevPtr); if (data->firstSegPtr == segPtr) { data->firstOffset += prevPtr->size - segPtr->size; @@ -8868,6 +8897,7 @@ AddRemoveTag( || data->newTagInfoPtr == pPtr->tagInfoPtr) { data->newTagInfoPtr = prevPtr->tagInfoPtr; } + TkBTreeFreeSegment(segPtr); } else { prevPtr = segPtr; } @@ -9225,10 +9255,11 @@ FindSplitPoints( } if (needSplit1) { + TkTextIndexToByteIndex((TkTextIndex *) indexPtr1); /* mutable due to concept */ + TkTextIndexToByteIndex((TkTextIndex *) indexPtr2); /* mutable due to concept */ if ((*segPtr1 = SplitSeg(indexPtr1, NULL))) { SplitSection((*segPtr1)->sectionPtr); } - TkTextIndexToByteIndex((TkTextIndex *) indexPtr2); /* mutable due to concept */ } else { *segPtr1 = NULL; } @@ -9248,10 +9279,14 @@ FindSplitPoints( assert(!sharedTextPtr->protectionMark[0]->sectionPtr); /* this protection mark is unused? */ LinkSegment(linePtr1, (*segPtr1)->prevPtr, sharedTextPtr->protectionMark[0]); - if (!needSplit2) { + if (needSplit2) { + TkTextIndexToByteIndex((TkTextIndex *) indexPtr1); /* mutable due to concept */ + TkTextIndexToByteIndex((TkTextIndex *) indexPtr2); /* mutable due to concept */ + if ((*segPtr2 = SplitSeg(indexPtr2, NULL))) { + SplitSection((*segPtr2)->sectionPtr); + } + } else { *segPtr2 = NULL; - } else if ((*segPtr2 = SplitSeg(indexPtr2, NULL))) { - SplitSection((*segPtr2)->sectionPtr); } if (!*segPtr2) { *segPtr2 = TkTextIndexGetContentSegment(indexPtr2, NULL); @@ -9330,7 +9365,7 @@ TkBTreeTag( * so we are doing this before eliminating the tag. */ - UpdateElideInfo(sharedTextPtr, tagPtr, segPtr1, segPtr2, ELISION_WILL_BE_REMOVED); + UpdateElideInfo(sharedTextPtr, tagPtr, &segPtr1, &segPtr2, ELISION_WILL_BE_REMOVED); } if (undoInfo) { @@ -9375,7 +9410,7 @@ TkBTreeTag( * so we are doing this after the tag has been added. */ - UpdateElideInfo(sharedTextPtr, tagPtr, segPtr1, segPtr2, ELISION_HAS_BEEN_ADDED); + UpdateElideInfo(sharedTextPtr, tagPtr, &segPtr1, &segPtr2, ELISION_HAS_BEEN_ADDED); } if (undoInfo && (data.sizeOfLengths > 0 || data.currLength > 0)) { @@ -9475,7 +9510,9 @@ TkBTreeTag( assert(data.lengths == data.lengthsBuf); CleanupSplitPoint(segPtr1, sharedTextPtr); - CleanupSplitPoint(segPtr2, sharedTextPtr); + if (segPtr1 != segPtr2) { + CleanupSplitPoint(segPtr2, sharedTextPtr); + } TkBTreeIncrEpoch(sharedTextPtr->tree); TK_BTREE_DEBUG(TkBTreeCheck(indexPtr1->tree)); @@ -10181,7 +10218,7 @@ TkBTreeClearTags( rootPtr = TkBTreeGetRoot(sharedTextPtr->tree); /* we must start at top level */ if (TkBTreeHaveElidedSegments(sharedTextPtr)) { - UpdateElideInfo(sharedTextPtr, NULL, segPtr1, segPtr2, ELISION_WILL_BE_REMOVED); + UpdateElideInfo(sharedTextPtr, NULL, &segPtr1, &segPtr2, ELISION_WILL_BE_REMOVED); } if (wholeText) { @@ -10298,6 +10335,7 @@ TkBTreeClearTags( } } + assert(segPtr1 != segPtr2); CleanupSplitPoint(segPtr1, sharedTextPtr); CleanupSplitPoint(segPtr2, sharedTextPtr); @@ -12235,8 +12273,10 @@ TkTextTag * TkBTreeGetSegmentTags( const TkSharedText *sharedTextPtr, /* Handle to shared text resource. */ const TkTextSegment *segPtr, /* Get tags from this segment. */ - const TkText *textPtr) /* If non-NULL, then only return tags for this text widget + const TkText *textPtr, /* If non-NULL, then only return tags for this text widget * (when there are peer widgets). */ + bool *containsSelection) /* If non-NULL, return whether this chain contains the + * "sel" tag. */ { const TkTextTagSet *tagInfoPtr; TkTextTag *chainPtr = NULL; @@ -12245,6 +12285,10 @@ TkBTreeGetSegmentTags( tagInfoPtr = segPtr->tagInfoPtr; + if (containsSelection) { + *containsSelection = false; + } + if (tagInfoPtr != sharedTextPtr->emptyTagInfoPtr) { unsigned i = TkTextTagSetFindFirst(tagInfoPtr); @@ -12254,10 +12298,18 @@ TkBTreeGetSegmentTags( assert(tagPtr); assert(!tagPtr->isDisabled); - if (!textPtr || !tagPtr->textPtr || tagPtr->textPtr == textPtr) { + if (!textPtr || !tagPtr->textPtr) { + tagPtr->nextPtr = chainPtr; + tagPtr->epoch = 0; + chainPtr = tagPtr; + } else if (tagPtr->textPtr == textPtr) { tagPtr->nextPtr = chainPtr; tagPtr->epoch = 0; chainPtr = tagPtr; + + if (tagPtr == textPtr->selTagPtr && containsSelection) { + *containsSelection = true; + } } } } diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index d03d523..c4fed57 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -17,6 +17,7 @@ #include "tkText.h" #include "tkTextTagSet.h" #include "tkRangeList.h" +#include "tkAlloc.h" #include "tkInt.h" #ifdef _WIN32 @@ -1803,15 +1804,15 @@ TkTextResetDInfo( static TextStyle * MakeStyle( TkText *textPtr, - TkTextTag *tagPtr) + TkTextTag *tagPtr, + bool containsSelection) { StyleValues styleValues; TextStyle *stylePtr; Tcl_HashEntry *hPtr; - int isNew; - bool isSelected; XGCValues gcValues; unsigned long mask; + bool isNew; /* * The variables below keep track of the highest-priority specification @@ -1853,8 +1854,6 @@ MakeStyle( styleValues.lang = textPtr->lang; styleValues.hyphenRules = textPtr->hyphenRulesPtr ? textPtr->hyphenRules : TK_TEXT_HYPHEN_MASK; - isSelected = false; - for ( ; tagPtr; tagPtr = tagPtr->nextPtr) { Tk_3DBorder border; XColor *fgColor; @@ -1883,10 +1882,10 @@ MakeStyle( border = textPtr->inactiveSelBorder; } - if (tagPtr->selBorder && isSelected) { + if (tagPtr->selBorder && containsSelection) { border = tagPtr->selBorder; } - if (tagPtr->selFgColor != None && isSelected) { + if (tagPtr->selFgColor != None && containsSelection) { fgColor = tagPtr->selFgColor; } if (border && priority > borderPrio) { @@ -1899,7 +1898,7 @@ MakeStyle( styleValues.borderWidth = tagPtr->borderWidth; borderWidthPrio = priority; } - if (tagPtr->reliefString && priority > reliefPrio) { + if (tagPtr->reliefPtr && priority > reliefPrio) { if (!styleValues.border) { styleValues.border = textPtr->border; } @@ -2094,9 +2093,11 @@ GetStyle( { TextStyle *stylePtr; TkTextTag *tagPtr; + bool containsSelection; - if (segPtr && (tagPtr = TkBTreeGetSegmentTags(textPtr->sharedTextPtr, segPtr, textPtr))) { - stylePtr = MakeStyle(textPtr, tagPtr); + if (segPtr && (tagPtr = TkBTreeGetSegmentTags( + textPtr->sharedTextPtr, segPtr, textPtr, &containsSelection))) { + stylePtr = MakeStyle(textPtr, tagPtr, containsSelection); } else { /* * Take into account that this function can be called before UpdateDefaultStyle @@ -2133,7 +2134,7 @@ static void UpdateDefaultStyle( TkText *textPtr) { - TextStyle *stylePtr = MakeStyle(textPtr, NULL); + TextStyle *stylePtr = MakeStyle(textPtr, NULL, false); TextDInfo *dInfoPtr = textPtr->dInfoPtr; if (stylePtr != dInfoPtr->defaultStyle) { diff --git a/generic/tkTextImage.c b/generic/tkTextImage.c index 165f14e..482cad1 100644 --- a/generic/tkTextImage.c +++ b/generic/tkTextImage.c @@ -15,6 +15,7 @@ #include "tkText.h" #include "tkTextTagSet.h" #include "tkTextUndo.h" +#include "tkAlloc.h" #include <assert.h> #ifdef NDEBUG @@ -157,7 +158,6 @@ static const Tk_OptionSpec optionSpecs[] = { {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0} }; -DEBUG_ALLOC(extern unsigned tkTextCountDestroySegment); DEBUG_ALLOC(extern unsigned tkTextCountNewUndoToken); DEBUG_ALLOC(extern unsigned tkTextCountNewSegment); @@ -925,9 +925,7 @@ ReleaseImage( if (img->bbox) { free(img->bbox); } - TkTextTagSetDecrRefCount(eiPtr->tagInfoPtr); - FREE_SEGMENT(eiPtr); - DEBUG_ALLOC(tkTextCountDestroySegment++); + TkBTreeFreeSegment(eiPtr); } /* @@ -954,10 +952,13 @@ EmbImageDeleteProc( TkTextSegment *eiPtr, /* Segment being deleted. */ int flags) /* Flags controlling the deletion. */ { - TkTextEmbImage *img = &eiPtr->body.ei; + TkTextEmbImage *img; + assert(eiPtr->typePtr); assert(eiPtr->refCount > 0); + img = &eiPtr->body.ei; + if (img->hPtr) { img->sharedTextPtr->numImages -= 1; Tcl_DeleteHashEntry(img->hPtr); @@ -997,8 +998,10 @@ EmbImageDeleteProc( } } - if (--eiPtr->refCount == 0) { + if (eiPtr->refCount == 1) { ReleaseImage(eiPtr); + } else { + eiPtr->refCount -= 1; } return true; diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c index 4bd613d..5304f22 100644 --- a/generic/tkTextIndex.c +++ b/generic/tkTextIndex.c @@ -14,6 +14,7 @@ #include "default.h" #include "tkInt.h" #include "tkText.h" +#include "tkAlloc.h" #include <stdlib.h> #include <assert.h> @@ -1230,13 +1231,12 @@ TkTextIndexGetFirstSegment( assert(segPtr->sectionPtr->linePtr == indexPtr->priv.linePtr); if (myOffset == 0) { - TkTextIndex *iPtr; + TkTextIndex *iPtr = (TkTextIndex *) indexPtr; /* mutable due to concept */ while ((prevPtr = segPtr->prevPtr) && prevPtr->size == 0) { segPtr = prevPtr; } - iPtr = (TkTextIndex *) indexPtr; /* mutable due to concept */ iPtr->priv.segPtr = segPtr; iPtr->priv.isCharSegment = segPtr->typePtr == &tkTextCharType; } diff --git a/generic/tkTextMark.c b/generic/tkTextMark.c index b88646f..733f5c6 100644 --- a/generic/tkTextMark.c +++ b/generic/tkTextMark.c @@ -14,6 +14,7 @@ #include "tkInt.h" #include "tkText.h" +#include "tkAlloc.h" #include "tk3d.h" #include <assert.h> diff --git a/generic/tkTextPriv.h b/generic/tkTextPriv.h index 042ad52..015ba1b 100644 --- a/generic/tkTextPriv.h +++ b/generic/tkTextPriv.h @@ -638,7 +638,7 @@ TkBTreeGetTags( const TkTextIndex *indexPtr)/* Indicates a particular position in the B-tree. */ { const TkTextSegment *segPtr = TkTextIndexGetContentSegment(indexPtr, NULL); - return TkBTreeGetSegmentTags(TkTextIndexGetShared(indexPtr), segPtr, indexPtr->textPtr); + return TkBTreeGetSegmentTags(TkTextIndexGetShared(indexPtr), segPtr, indexPtr->textPtr, NULL); } /* diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c index cda91f4..cbbdcc3 100644 --- a/generic/tkTextTag.c +++ b/generic/tkTextTag.c @@ -19,6 +19,7 @@ #include "tkTextUndo.h" #include "tkTextTagSet.h" #include "tkBitField.h" +#include "tkAlloc.h" #include <assert.h> #include <stdlib.h> @@ -125,7 +126,7 @@ static const Tk_OptionSpec tagOptionSpecs[] = { TK_TEXT_DEPRECATED_OVERSTRIKE_FG}, #endif /* SUPPORT_DEPRECATED_TAG_OPTIONS */ {TK_OPTION_STRING, "-relief", NULL, NULL, - NULL, -1, Tk_Offset(TkTextTag, reliefString), TK_OPTION_NULL_OK, 0, 0}, + NULL, Tk_Offset(TkTextTag, reliefPtr), -1, 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, @@ -482,6 +483,8 @@ TkTextTagCmd( return TCL_ERROR; } for (i = 3; i < objc; i++) { + bool undo; + if (!(hPtr = Tcl_FindHashEntry(&sharedTextPtr->tagTable, Tcl_GetString(objv[i])))) { /* * Either this tag doesn't exist or it's the 'sel' tag (which is not in @@ -491,8 +494,9 @@ TkTextTagCmd( continue; } tagPtr = Tcl_GetHashValue(hPtr); + undo = tagPtr->undo; assert(tagPtr != textPtr->selTagPtr); - if (TkTextDeleteTag(textPtr, tagPtr, hPtr) && tagPtr->undo) { + if (TkTextDeleteTag(textPtr, tagPtr, hPtr) && undo) { anyChanges = true; } } @@ -943,7 +947,7 @@ TkTextUpdateTagDisplayFlags( tagPtr->affectsDisplayGeometry = true; } else if (tagPtr->border || tagPtr->selBorder - || tagPtr->reliefString + || tagPtr->reliefPtr || tagPtr->bgStipple != None || tagPtr->indentBgString || tagPtr->fgColor @@ -1059,8 +1063,8 @@ TkConfigureTag( return TCL_ERROR; } } - if (tagPtr->reliefString) { - if (Tk_GetRelief(interp, tagPtr->reliefString, &tagPtr->relief) != TCL_OK) { + if (tagPtr->reliefPtr) { + if (Tk_GetReliefFromObj(interp, tagPtr->reliefPtr, &tagPtr->relief) != TCL_OK) { return TCL_ERROR; } } @@ -1386,7 +1390,7 @@ FindTags( assert(segPtr); tagArray = malloc(textPtr->sharedTextPtr->numEnabledTags * sizeof(TkTextTag *)); - tagPtr = TkBTreeGetSegmentTags(textPtr->sharedTextPtr, segPtr, textPtr); + tagPtr = TkBTreeGetSegmentTags(textPtr->sharedTextPtr, segPtr, textPtr, NULL); for (count = 0; tagPtr; tagPtr = tagPtr->nextPtr) { if (!discardSelection || tagPtr != textPtr->selTagPtr) { @@ -1752,7 +1756,6 @@ TkTextCreateTag( tagPtr->name = name; tagPtr->index = index; tagPtr->priority = textPtr->sharedTextPtr->numEnabledTags; - tagPtr->relief = TK_RELIEF_FLAT; tagPtr->bgStipple = None; tagPtr->fgStipple = None; tagPtr->justify = TK_TEXT_JUSTIFY_LEFT; @@ -1764,18 +1767,35 @@ TkTextCreateTag( tagPtr->refCount = 1; DEBUG_ALLOC(tkTextCountNewTag++); + tagPtr->optionTable = Tk_CreateOptionTable(textPtr->interp, tagOptionSpecs); + assert(!tagPtr->reliefPtr); + textPtr->sharedTextPtr->numTags += 1; textPtr->sharedTextPtr->numEnabledTags += 1; + if (isSelTag) { tagPtr->textPtr = textPtr; + Tk_GetRelief(textPtr->interp, DEF_TEXT_SELECT_RELIEF, &tagPtr->relief); + /* check validty of default */ + assert(strcmp(Tk_NameOfRelief(tagPtr->relief), DEF_TEXT_SELECT_RELIEF) == 0); + assert(!tagPtr->reliefPtr); + Tcl_IncrRefCount(tagPtr->reliefPtr = Tcl_NewStringObj(DEF_TEXT_SELECT_RELIEF, -1)); +#if 0 /* TODO: this default value is not existing, although it should (?) */ + sscanf(DEF_TEXT_SELECT_BORDER_WIDTH, "%d", &tagPtr->borderWidth); + if (tagPtr->borderWidth) { + assert(!tagPtr->borderWidthPtr); + Tcl_IncrRefCount(tagPtr->borderWidthPtr = Tcl_NewIntObj(tagPtr->borderWidth)); + } +#endif textPtr->refCount += 1; TkBitSet(sharedTextPtr->selectionTags, index); TkBitSet(sharedTextPtr->dontUndoTags, index); } else { + tagPtr->relief = TK_RELIEF_FLAT; assert(hPtr); Tcl_SetHashValue(hPtr, tagPtr); } - tagPtr->optionTable = Tk_CreateOptionTable(textPtr->interp, tagOptionSpecs); + MarkIndex(sharedTextPtr, tagPtr, true); return tagPtr; } diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c index ff7e300..1ed8fe7 100644 --- a/generic/tkTextWind.c +++ b/generic/tkTextWind.c @@ -17,6 +17,7 @@ #include "tkText.h" #include "tkTextTagSet.h" #include "tkTextUndo.h" +#include "tkAlloc.h" #include <assert.h> #ifdef NDEBUG @@ -181,7 +182,6 @@ static const Tk_OptionSpec optionSpecs[] = { {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0} }; -DEBUG_ALLOC(extern unsigned tkTextCountDestroySegment); DEBUG_ALLOC(extern unsigned tkTextCountNewSegment); DEBUG_ALLOC(extern unsigned tkTextCountNewUndoToken); @@ -799,8 +799,7 @@ EmbWinConfigure( * Have to make the new client. */ - client = malloc(sizeof(TkTextEmbWindowClient)); - memset(client, 0, sizeof(TkTextEmbWindowClient)); + client = memset(malloc(sizeof(TkTextEmbWindowClient)), 0, sizeof(TkTextEmbWindowClient)); client->next = ewPtr->body.ew.clients; client->textPtr = textPtr; client->parent = ewPtr; @@ -956,6 +955,7 @@ EmbWinLostSlaveProc( assert(client->tkwin); client->displayed = false; Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask, EmbWinStructureProc, client); + Tcl_CancelIdleCall(EmbWinDelayedUnmap, client); EmbWinDelayedUnmap(client); if (client->hPtr) { ewPtr->body.ew.sharedTextPtr->numWindows -= 1; @@ -1128,9 +1128,7 @@ ReleaseWindow( } ewPtr->body.ew.clients = NULL; Tk_FreeConfigOptions((char *) &ewPtr->body.ew, ewPtr->body.ew.optionTable, NULL); - TkTextTagSetDecrRefCount(ewPtr->tagInfoPtr); - FREE_SEGMENT(ewPtr); - DEBUG_ALLOC(tkTextCountDestroySegment++); + TkBTreeFreeSegment(ewPtr); } /* @@ -1202,10 +1200,12 @@ EmbWinDeleteProc( int flags) /* Flags controlling the deletion. */ { assert(ewPtr->typePtr); + assert(ewPtr->refCount > 0); - if (--ewPtr->refCount == 0) { + if (ewPtr->refCount == 1) { ReleaseWindow(ewPtr); } else { + ewPtr->refCount -= 1; DestroyOrUnmapWindow(ewPtr); } return true; @@ -1402,8 +1402,7 @@ EmbWinLayoutProc( * now need to add to our client list. */ - client = malloc(sizeof(TkTextEmbWindowClient)); - memset(client, 0, sizeof(TkTextEmbWindowClient)); + client = memset(malloc(sizeof(TkTextEmbWindowClient)), 0, sizeof(TkTextEmbWindowClient)); client->next = ewPtr->body.ew.clients; client->textPtr = textPtr; client->parent = ewPtr; |