diff options
Diffstat (limited to 'tk8.6/generic/tkTextMark.c')
-rw-r--r-- | tk8.6/generic/tkTextMark.c | 1027 |
1 files changed, 0 insertions, 1027 deletions
diff --git a/tk8.6/generic/tkTextMark.c b/tk8.6/generic/tkTextMark.c deleted file mode 100644 index 6a41c77..0000000 --- a/tk8.6/generic/tkTextMark.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * tkTextMark.c -- - * - * This file contains the functions that implement marks for text - * widgets. - * - * Copyright (c) 1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * - * See the file "license.terms" for information on usage and redistribution of - * this file, and for a DISCLAIMER OF ALL WARRANTIES. - */ - -#include "tkInt.h" -#include "tkText.h" -#include "tk3d.h" - -/* - * Macro that determines the size of a mark segment: - */ - -#define MSEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \ - + sizeof(TkTextMark))) - -/* - * Forward references for functions defined in this file: - */ - -static Tcl_Obj * GetMarkName(TkText *textPtr, TkTextSegment *segPtr); -static void InsertUndisplayProc(TkText *textPtr, - TkTextDispChunk *chunkPtr); -static int MarkDeleteProc(TkTextSegment *segPtr, - TkTextLine *linePtr, int treeGone); -static TkTextSegment * MarkCleanupProc(TkTextSegment *segPtr, - TkTextLine *linePtr); -static void MarkCheckProc(TkTextSegment *segPtr, - TkTextLine *linePtr); -static int MarkLayoutProc(TkText *textPtr, TkTextIndex *indexPtr, - TkTextSegment *segPtr, int offset, int maxX, - int maxChars, int noCharsYet, TkWrapMode wrapMode, - TkTextDispChunk *chunkPtr); -static int MarkFindNext(Tcl_Interp *interp, - TkText *textPtr, Tcl_Obj *markName); -static int MarkFindPrev(Tcl_Interp *interp, - TkText *textPtr, Tcl_Obj *markName); - - -/* - * The following structures declare the "mark" segment types. There are - * actually two types for marks, one with left gravity and one with right - * gravity. They are identical except for their gravity property. - */ - -const Tk_SegType tkTextRightMarkType = { - "mark", /* name */ - 0, /* leftGravity */ - NULL, /* splitProc */ - MarkDeleteProc, /* deleteProc */ - MarkCleanupProc, /* cleanupProc */ - NULL, /* lineChangeProc */ - MarkLayoutProc, /* layoutProc */ - MarkCheckProc /* checkProc */ -}; - -const Tk_SegType tkTextLeftMarkType = { - "mark", /* name */ - 1, /* leftGravity */ - NULL, /* splitProc */ - MarkDeleteProc, /* deleteProc */ - MarkCleanupProc, /* cleanupProc */ - NULL, /* lineChangeProc */ - MarkLayoutProc, /* layoutProc */ - MarkCheckProc /* checkProc */ -}; - -/* - *-------------------------------------------------------------- - * - * TkTextMarkCmd -- - * - * This function is invoked to process the "mark" options of the widget - * command for text widgets. See the user documentation for details on - * what it does. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *-------------------------------------------------------------- - */ - -int -TkTextMarkCmd( - register TkText *textPtr, /* Information about text widget. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. Someone else has already - * parsed this command enough to know that - * objv[1] is "mark". */ -{ - Tcl_HashEntry *hPtr; - TkTextSegment *markPtr; - Tcl_HashSearch search; - TkTextIndex index; - const Tk_SegType *newTypePtr; - int optionIndex; - static const char *const markOptionStrings[] = { - "gravity", "names", "next", "previous", "set", "unset", NULL - }; - enum markOptions { - MARK_GRAVITY, MARK_NAMES, MARK_NEXT, MARK_PREVIOUS, MARK_SET, - MARK_UNSET - }; - - if (objc < 3) { - Tcl_WrongNumArgs(interp, 2, objv, "option ?arg ...?"); - return TCL_ERROR; - } - if (Tcl_GetIndexFromObjStruct(interp, objv[2], markOptionStrings, - sizeof(char *), "mark option", 0, &optionIndex) != TCL_OK) { - return TCL_ERROR; - } - - switch ((enum markOptions) optionIndex) { - case MARK_GRAVITY: { - char c; - int length; - const char *str; - - if (objc < 4 || objc > 5) { - Tcl_WrongNumArgs(interp, 3, objv, "markName ?gravity?"); - return TCL_ERROR; - } - str = Tcl_GetStringFromObj(objv[3], &length); - if (length == 6 && !strcmp(str, "insert")) { - markPtr = textPtr->insertMarkPtr; - } else if (length == 7 && !strcmp(str, "current")) { - markPtr = textPtr->currentMarkPtr; - } else { - hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->markTable, str); - if (hPtr == NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "there is no mark named \"%s\"", str)); - Tcl_SetErrorCode(interp, "TK", "LOOKUP", "TEXT_MARK", str, - NULL); - return TCL_ERROR; - } - markPtr = Tcl_GetHashValue(hPtr); - } - if (objc == 4) { - const char *typeStr; - - if (markPtr->typePtr == &tkTextRightMarkType) { - typeStr = "right"; - } else { - typeStr = "left"; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj(typeStr, -1)); - return TCL_OK; - } - str = Tcl_GetStringFromObj(objv[4],&length); - c = str[0]; - if ((c == 'l') && (strncmp(str, "left", (unsigned) length) == 0)) { - newTypePtr = &tkTextLeftMarkType; - } else if ((c == 'r') && - (strncmp(str, "right", (unsigned) length) == 0)) { - newTypePtr = &tkTextRightMarkType; - } else { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad mark gravity \"%s\": must be left or right", str)); - Tcl_SetErrorCode(interp, "TK", "VALUE", "MARK_GRAVITY", NULL); - return TCL_ERROR; - } - TkTextMarkSegToIndex(textPtr, markPtr, &index); - TkBTreeUnlinkSegment(markPtr, markPtr->body.mark.linePtr); - markPtr->typePtr = newTypePtr; - TkBTreeLinkSegment(markPtr, &index); - break; - } - case MARK_NAMES: { - Tcl_Obj *resultObj; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 3, objv, NULL); - return TCL_ERROR; - } - resultObj = Tcl_NewObj(); - Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( - "insert", -1)); - Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( - "current", -1)); - for (hPtr = Tcl_FirstHashEntry(&textPtr->sharedTextPtr->markTable, - &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( - Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, hPtr), - -1)); - } - Tcl_SetObjResult(interp, resultObj); - break; - } - case MARK_NEXT: - if (objc != 4) { - Tcl_WrongNumArgs(interp, 3, objv, "index"); - return TCL_ERROR; - } - return MarkFindNext(interp, textPtr, objv[3]); - case MARK_PREVIOUS: - if (objc != 4) { - Tcl_WrongNumArgs(interp, 3, objv, "index"); - return TCL_ERROR; - } - return MarkFindPrev(interp, textPtr, objv[3]); - case MARK_SET: - if (objc != 5) { - Tcl_WrongNumArgs(interp, 3, objv, "markName index"); - return TCL_ERROR; - } - if (TkTextGetObjIndex(interp, textPtr, objv[4], &index) != TCL_OK) { - return TCL_ERROR; - } - TkTextSetMark(textPtr, Tcl_GetString(objv[3]), &index); - return TCL_OK; - case MARK_UNSET: { - int i; - - for (i = 3; i < objc; i++) { - hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->markTable, - Tcl_GetString(objv[i])); - if (hPtr != NULL) { - markPtr = Tcl_GetHashValue(hPtr); - - /* - * Special case not needed with peer widgets. - */ - - if ((markPtr == textPtr->insertMarkPtr) - || (markPtr == textPtr->currentMarkPtr)) { - continue; - } - TkBTreeUnlinkSegment(markPtr, markPtr->body.mark.linePtr); - Tcl_DeleteHashEntry(hPtr); - ckfree(markPtr); - } - } - break; - } - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * TkTextSetMark -- - * - * Set a mark to a particular position, creating a new mark if one - * doesn't already exist. - * - * Results: - * The return value is a pointer to the mark that was just set. - * - * Side effects: - * A new mark is created, or an existing mark is moved. - * - *---------------------------------------------------------------------- - */ - -TkTextSegment * -TkTextSetMark( - TkText *textPtr, /* Text widget in which to create mark. */ - const char *name, /* Name of mark to set. */ - TkTextIndex *indexPtr) /* Where to set mark. */ -{ - Tcl_HashEntry *hPtr = NULL; - TkTextSegment *markPtr; - TkTextIndex insertIndex; - int isNew, widgetSpecific; - - if (!strcmp(name, "insert")) { - widgetSpecific = 1; - markPtr = textPtr->insertMarkPtr; - isNew = (markPtr == NULL ? 1 : 0); - } else if (!strcmp(name, "current")) { - widgetSpecific = 2; - markPtr = textPtr->currentMarkPtr; - isNew = (markPtr == NULL ? 1 : 0); - } else { - widgetSpecific = 0; - hPtr = Tcl_CreateHashEntry(&textPtr->sharedTextPtr->markTable, name, - &isNew); - markPtr = Tcl_GetHashValue(hPtr); - } - if (!isNew) { - /* - * If this is the insertion point that's being moved, be sure to force - * a display update at the old position. Also, don't let the insertion - * cursor be after the final newline of the file. - */ - - if (markPtr == textPtr->insertMarkPtr) { - TkTextIndex index, index2; - int nblines; - - TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - TkTextIndexForwChars(NULL, &index, 1, &index2, COUNT_INDICES); - - /* - * While we wish to redisplay, no heights have changed, so no need - * to call TkTextInvalidateLineMetrics. - */ - - TkTextChanged(NULL, textPtr, &index, &index2); - - /* - * The number of lines in the widget is zero if and only if it is - * a partial peer with -startline == -endline, i.e. an empty - * peer. In this case the mark shall be set exactly at the given - * index, and not one character backwards (bug 3487407). - */ - - nblines = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr); - if ((TkBTreeLinesTo(textPtr, indexPtr->linePtr) == nblines) - && (nblines > 0)) { - TkTextIndexBackChars(NULL,indexPtr, 1, &insertIndex, - COUNT_INDICES); - indexPtr = &insertIndex; - } - } - TkBTreeUnlinkSegment(markPtr, markPtr->body.mark.linePtr); - } else { - markPtr = ckalloc(MSEG_SIZE); - markPtr->typePtr = &tkTextRightMarkType; - markPtr->size = 0; - markPtr->body.mark.textPtr = textPtr; - markPtr->body.mark.linePtr = indexPtr->linePtr; - markPtr->body.mark.hPtr = hPtr; - if (widgetSpecific == 0) { - Tcl_SetHashValue(hPtr, markPtr); - } else if (widgetSpecific == 1) { - textPtr->insertMarkPtr = markPtr; - } else { - textPtr->currentMarkPtr = markPtr; - } - } - TkBTreeLinkSegment(markPtr, indexPtr); - - /* - * If the mark is the insertion cursor, then update the screen at the - * mark's new location. - */ - - if (markPtr == textPtr->insertMarkPtr) { - TkTextIndex index2; - - TkTextIndexForwChars(NULL, indexPtr, 1, &index2, COUNT_INDICES); - - /* - * While we wish to redisplay, no heights have changed, so no need to - * call TkTextInvalidateLineMetrics - */ - - TkTextChanged(NULL, textPtr, indexPtr, &index2); - } - return markPtr; -} - -/* - *-------------------------------------------------------------- - * - * TkTextMarkSegToIndex -- - * - * Given a segment that is a mark, create an index that refers to the - * next text character (or other text segment with non-zero size) after - * the mark. - * - * Results: - * *IndexPtr is filled in with index information. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -void -TkTextMarkSegToIndex( - TkText *textPtr, /* Text widget containing mark. */ - TkTextSegment *markPtr, /* Mark segment. */ - TkTextIndex *indexPtr) /* Index information gets stored here. */ -{ - TkTextSegment *segPtr; - - indexPtr->tree = textPtr->sharedTextPtr->tree; - indexPtr->linePtr = markPtr->body.mark.linePtr; - indexPtr->byteIndex = 0; - for (segPtr = indexPtr->linePtr->segPtr; segPtr != markPtr; - segPtr = segPtr->nextPtr) { - indexPtr->byteIndex += segPtr->size; - } -} - -/* - *-------------------------------------------------------------- - * - * TkTextMarkNameToIndex -- - * - * Given the name of a mark, return an index corresponding to the mark - * name. - * - * Results: - * The return value is TCL_OK if "name" exists as a mark in the text - * widget and is located within its -starline/-endline range. In this - * case *indexPtr is filled in with the next segment who is after the - * mark whose size is non-zero. TCL_ERROR is returned if the mark - * doesn't exist in the text widget, or if it is out of its -starline/ - * -endline range. In this latter case *indexPtr still contains valid - * information, in particular TkTextMarkNameToIndex called with the - * "insert" or "current" mark name may return TCL_ERROR, but *indexPtr - * contains the correct index of this mark before -startline or after - * -endline. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -int -TkTextMarkNameToIndex( - TkText *textPtr, /* Text widget containing mark. */ - const char *name, /* Name of mark. */ - TkTextIndex *indexPtr) /* Index information gets stored here. */ -{ - TkTextSegment *segPtr; - TkTextIndex index; - int start, end; - - if (textPtr == NULL) { - return TCL_ERROR; - } - - if (!strcmp(name, "insert")) { - segPtr = textPtr->insertMarkPtr; - } else if (!strcmp(name, "current")) { - segPtr = textPtr->currentMarkPtr; - } else { - Tcl_HashEntry *hPtr = - Tcl_FindHashEntry(&textPtr->sharedTextPtr->markTable, name); - - if (hPtr == NULL) { - return TCL_ERROR; - } - segPtr = Tcl_GetHashValue(hPtr); - } - TkTextMarkSegToIndex(textPtr, segPtr, indexPtr); - - /* If indexPtr refers to somewhere outside the -startline/-endline - * range limits of the widget, error out since the mark indeed is not - * reachable from this text widget (it may be reachable from a peer) - * (bug 1630271). - */ - - if (textPtr->start != NULL) { - start = TkBTreeLinesTo(NULL, textPtr->start); - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, start, 0, - &index); - if (TkTextIndexCmp(indexPtr, &index) < 0) { - return TCL_ERROR; - } - } - if (textPtr->end != NULL) { - end = TkBTreeLinesTo(NULL, textPtr->end); - TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, NULL, end, 0, - &index); - if (TkTextIndexCmp(indexPtr, &index) > 0) { - return TCL_ERROR; - } - } - return TCL_OK; -} - -/* - *-------------------------------------------------------------- - * - * MarkDeleteProc -- - * - * This function is invoked by the text B-tree code whenever a mark lies - * in a range of characters being deleted. - * - * Results: - * Returns 1 to indicate that deletion has been rejected. - * - * Side effects: - * None (even if the whole tree is being deleted we don't free up the - * mark; it will be done elsewhere). - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static int -MarkDeleteProc( - TkTextSegment *segPtr, /* Segment being deleted. */ - TkTextLine *linePtr, /* Line containing segment. */ - int treeGone) /* Non-zero means the entire tree is being - * deleted, so everything must get cleaned - * up. */ -{ - return 1; -} - -/* - *-------------------------------------------------------------- - * - * MarkCleanupProc -- - * - * This function is invoked by the B-tree code whenever a mark segment is - * moved from one line to another. - * - * Results: - * None. - * - * Side effects: - * The linePtr field of the segment gets updated. - * - *-------------------------------------------------------------- - */ - -static TkTextSegment * -MarkCleanupProc( - TkTextSegment *markPtr, /* Mark segment that's being moved. */ - TkTextLine *linePtr) /* Line that now contains segment. */ -{ - markPtr->body.mark.linePtr = linePtr; - return markPtr; -} - -/* - *-------------------------------------------------------------- - * - * MarkLayoutProc -- - * - * This function is the "layoutProc" for mark segments. - * - * Results: - * If the mark isn't the insertion cursor then the return value is -1 to - * indicate that this segment shouldn't be displayed. If the mark is the - * insertion character then 1 is returned and the chunkPtr structure is - * filled in. - * - * Side effects: - * None, except for filling in chunkPtr. - * - *-------------------------------------------------------------- - */ - -static int -MarkLayoutProc( - TkText *textPtr, /* Text widget being layed out. */ - TkTextIndex *indexPtr, /* Identifies first character in chunk. */ - TkTextSegment *segPtr, /* Segment corresponding to indexPtr. */ - int offset, /* Offset within segPtr corresponding to - * indexPtr (always 0). */ - int maxX, /* Chunk must not occupy pixels at this - * position or higher. */ - int maxChars, /* Chunk must not include more than this many - * characters. */ - int noCharsYet, /* Non-zero means no characters have been - * assigned to this line yet. */ - TkWrapMode wrapMode, /* Not used. */ - register TkTextDispChunk *chunkPtr) - /* Structure to fill in with information about - * this chunk. The x field has already been - * set by the caller. */ -{ - if (segPtr != textPtr->insertMarkPtr) { - return -1; - } - - chunkPtr->displayProc = TkTextInsertDisplayProc; - chunkPtr->undisplayProc = InsertUndisplayProc; - chunkPtr->measureProc = NULL; - chunkPtr->bboxProc = NULL; - chunkPtr->numBytes = 0; - chunkPtr->minAscent = 0; - chunkPtr->minDescent = 0; - chunkPtr->minHeight = 0; - chunkPtr->width = 0; - - /* - * Note: can't break a line after the insertion cursor: this prevents the - * insertion cursor from being stranded at the end of a line. - */ - - chunkPtr->breakIndex = -1; - chunkPtr->clientData = textPtr; - return 1; -} - -/* - *-------------------------------------------------------------- - * - * TkTextInsertDisplayProc -- - * - * This function is called to display the insertion cursor. - * - * Results: - * None. - * - * Side effects: - * Graphics are drawn. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -TkTextInsertDisplayProc( - TkText *textPtr, /* The current text widget. */ - TkTextDispChunk *chunkPtr, /* Chunk that is to be drawn. */ - int x, /* X-position in dst at which to draw this - * chunk (may differ from the x-position in - * the chunk because of scrolling). */ - int y, /* Y-position at which to draw this chunk in - * dst (x-position is in the chunk itself). */ - int height, /* Total height of line. */ - int baseline, /* Offset of baseline from y. */ - Display *display, /* Display to use for drawing. */ - Drawable dst, /* Pixmap or window in which to draw chunk. */ - int screenY) /* Y-coordinate in text window that - * corresponds to y. */ -{ - /* - * We have no need for the clientData. - */ - - /* TkText *textPtr = chunkPtr->clientData; */ - TkTextIndex index; - int halfWidth = textPtr->insertWidth/2; - int rightSideWidth; - int ix = 0, iy = 0, iw = 0, ih = 0, charWidth = 0; - - if (textPtr->insertCursorType) { - TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - TkTextIndexBbox(textPtr, &index, &ix, &iy, &iw, &ih, &charWidth); - rightSideWidth = charWidth + halfWidth; - } else { - rightSideWidth = halfWidth; - } - - if ((x + rightSideWidth) < 0) { - /* - * The insertion cursor is off-screen. Indicate caret at 0,0 and - * return. - */ - - Tk_SetCaretPos(textPtr->tkwin, 0, 0, height); - return; - } - - Tk_SetCaretPos(textPtr->tkwin, x - halfWidth, screenY, height); - - /* - * As a special hack to keep the cursor visible on mono displays (or - * anywhere else that the selection and insertion cursors have the same - * color) write the default background in the cursor area (instead of - * nothing) when the cursor isn't on. Otherwise the selection might hide - * the cursor. - */ - - if (textPtr->flags & GOT_FOCUS) { - if (textPtr->flags & INSERT_ON) { - Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder, - x - halfWidth, y, charWidth + textPtr->insertWidth, - height, textPtr->insertBorderWidth, TK_RELIEF_RAISED); - } else if (textPtr->selBorder == textPtr->insertBorder) { - Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->border, - x - halfWidth, y, charWidth + textPtr->insertWidth, - height, 0, TK_RELIEF_FLAT); - } - } else if (textPtr->insertUnfocussed == TK_TEXT_INSERT_NOFOCUS_HOLLOW) { - if (textPtr->insertBorderWidth < 1) { - /* - * Hack to work around the fact that a "solid" border always - * paints in black. - */ - - TkBorder *borderPtr = (TkBorder *) textPtr->insertBorder; - - XDrawRectangle(Tk_Display(textPtr->tkwin), dst, borderPtr->bgGC, - x - halfWidth, y, charWidth + textPtr->insertWidth - 1, - height - 1); - } else { - Tk_Draw3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder, - x - halfWidth, y, charWidth + textPtr->insertWidth, - height, textPtr->insertBorderWidth, TK_RELIEF_RAISED); - } - } else if (textPtr->insertUnfocussed == TK_TEXT_INSERT_NOFOCUS_SOLID) { - Tk_Fill3DRectangle(textPtr->tkwin, dst, textPtr->insertBorder, - x - halfWidth, y, charWidth + textPtr->insertWidth, height, - textPtr->insertBorderWidth, TK_RELIEF_RAISED); - } -} - -/* - *-------------------------------------------------------------- - * - * InsertUndisplayProc -- - * - * This function is called when the insertion cursor is no longer at a - * visible point on the display. It does nothing right now. - * - * Results: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - - /* ARGSUSED */ -static void -InsertUndisplayProc( - TkText *textPtr, /* Overall information about text widget. */ - TkTextDispChunk *chunkPtr) /* Chunk that is about to be freed. */ -{ - return; -} - -/* - *-------------------------------------------------------------- - * - * MarkCheckProc -- - * - * This function is invoked by the B-tree code to perform consistency - * checks on mark segments. - * - * Results: - * None. - * - * Side effects: - * The function panics if it detects anything wrong with - * the mark. - * - *-------------------------------------------------------------- - */ - -static void -MarkCheckProc( - TkTextSegment *markPtr, /* Segment to check. */ - TkTextLine *linePtr) /* Line containing segment. */ -{ - Tcl_HashSearch search; - Tcl_HashEntry *hPtr; - - if (markPtr->body.mark.linePtr != linePtr) { - Tcl_Panic("MarkCheckProc: markPtr->body.mark.linePtr bogus"); - } - - /* - * These two marks are not in the hash table - */ - - if (markPtr->body.mark.textPtr->insertMarkPtr == markPtr) { - return; - } - if (markPtr->body.mark.textPtr->currentMarkPtr == markPtr) { - return; - } - - /* - * Make sure that the mark is still present in the text's mark hash table. - */ - - for (hPtr = Tcl_FirstHashEntry( - &markPtr->body.mark.textPtr->sharedTextPtr->markTable, - &search); hPtr != markPtr->body.mark.hPtr; - hPtr = Tcl_NextHashEntry(&search)) { - if (hPtr == NULL) { - Tcl_Panic("MarkCheckProc couldn't find hash table entry for mark"); - } - } -} - -/* - *-------------------------------------------------------------- - * - * MarkFindNext -- - * - * This function searches forward for the next mark. - * - * Results: - * A standard Tcl result, which is a mark name or an empty string. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -MarkFindNext( - Tcl_Interp *interp, /* For error reporting */ - TkText *textPtr, /* The widget */ - Tcl_Obj *obj) /* The starting index or mark name */ -{ - TkTextIndex index; - Tcl_HashEntry *hPtr; - register TkTextSegment *segPtr; - int offset; - const char *string = Tcl_GetString(obj); - - if (!strcmp(string, "insert")) { - segPtr = textPtr->insertMarkPtr; - TkTextMarkSegToIndex(textPtr, segPtr, &index); - segPtr = segPtr->nextPtr; - } else if (!strcmp(string, "current")) { - segPtr = textPtr->currentMarkPtr; - TkTextMarkSegToIndex(textPtr, segPtr, &index); - segPtr = segPtr->nextPtr; - } else { - hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->markTable, string); - if (hPtr != NULL) { - /* - * If given a mark name, return the next mark in the list of - * segments, even if it happens to be at the same character - * position. - */ - - segPtr = Tcl_GetHashValue(hPtr); - TkTextMarkSegToIndex(textPtr, segPtr, &index); - segPtr = segPtr->nextPtr; - } else { - /* - * For non-mark name indices we want to return any marks that are - * right at the index. - */ - - if (TkTextGetObjIndex(interp, textPtr, obj, &index) != TCL_OK) { - return TCL_ERROR; - } - for (offset = 0, segPtr = index.linePtr->segPtr; - segPtr != NULL && offset < index.byteIndex; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - /* Empty loop body */ ; - } - } - } - - while (1) { - /* - * segPtr points at the first possible candidate, or NULL if we ran - * off the end of the line. - */ - - for ( ; segPtr != NULL ; segPtr = segPtr->nextPtr) { - if (segPtr->typePtr == &tkTextRightMarkType || - segPtr->typePtr == &tkTextLeftMarkType) { - Tcl_Obj *markName = GetMarkName(textPtr, segPtr); - - if (markName != NULL) { - Tcl_SetObjResult(interp, markName); - return TCL_OK; - } - } - } - index.linePtr = TkBTreeNextLine(textPtr, index.linePtr); - if (index.linePtr == NULL) { - return TCL_OK; - } - index.byteIndex = 0; - segPtr = index.linePtr->segPtr; - } -} - -/* - *-------------------------------------------------------------- - * - * MarkFindPrev -- - * - * This function searches backwards for the previous mark. - * - * Results: - * A standard Tcl result, which is a mark name or an empty string. - * - * Side effects: - * None. - * - *-------------------------------------------------------------- - */ - -static int -MarkFindPrev( - Tcl_Interp *interp, /* For error reporting */ - TkText *textPtr, /* The widget */ - Tcl_Obj *obj) /* The starting index or mark name */ -{ - TkTextIndex index; - Tcl_HashEntry *hPtr; - register TkTextSegment *segPtr, *seg2Ptr, *prevPtr; - int offset; - const char *string = Tcl_GetString(obj); - - if (!strcmp(string, "insert")) { - segPtr = textPtr->insertMarkPtr; - TkTextMarkSegToIndex(textPtr, segPtr, &index); - } else if (!strcmp(string, "current")) { - segPtr = textPtr->currentMarkPtr; - TkTextMarkSegToIndex(textPtr, segPtr, &index); - } else { - hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->markTable, string); - if (hPtr != NULL) { - /* - * If given a mark name, return the previous mark in the list of - * segments, even if it happens to be at the same character - * position. - */ - - segPtr = Tcl_GetHashValue(hPtr); - TkTextMarkSegToIndex(textPtr, segPtr, &index); - } else { - /* - * For non-mark name indices we do not return any marks that are - * right at the index. - */ - - if (TkTextGetObjIndex(interp, textPtr, obj, &index) != TCL_OK) { - return TCL_ERROR; - } - for (offset = 0, segPtr = index.linePtr->segPtr; - segPtr != NULL && offset < index.byteIndex; - offset += segPtr->size, segPtr = segPtr->nextPtr) { - /* Empty loop body */ - } - } - } - - while (1) { - /* - * segPtr points just past the first possible candidate, or at the - * beginning of the line. - */ - - for (prevPtr = NULL, seg2Ptr = index.linePtr->segPtr; - seg2Ptr != NULL && seg2Ptr != segPtr; - seg2Ptr = seg2Ptr->nextPtr) { - if (seg2Ptr->typePtr == &tkTextRightMarkType || - seg2Ptr->typePtr == &tkTextLeftMarkType) { - if (seg2Ptr->body.mark.hPtr == NULL) { - if (seg2Ptr != textPtr->currentMarkPtr && - seg2Ptr != textPtr->insertMarkPtr) { - /* - * This is an insert or current mark from a - * peer of textPtr. - */ - continue; - } - } - prevPtr = seg2Ptr; - } - } - if (prevPtr != NULL) { - Tcl_Obj *markName = GetMarkName(textPtr, prevPtr); - - if (markName != NULL) { - Tcl_SetObjResult(interp, markName); - return TCL_OK; - } - } - index.linePtr = TkBTreePreviousLine(textPtr, index.linePtr); - if (index.linePtr == NULL) { - return TCL_OK; - } - segPtr = NULL; - } -} - -/* - * ------------------------------------------------------------------------ - * - * GetMarkName -- - * Returns the name of the mark that is the given text segment, or NULL - * if it is unnamed (i.e., a widget-specific mark that isn't "current" or - * "insert"). - * - * ------------------------------------------------------------------------ - */ - -static Tcl_Obj * -GetMarkName( - TkText *textPtr, - TkTextSegment *segPtr) -{ - const char *markName; - - if (segPtr == textPtr->currentMarkPtr) { - markName = "current"; - } else if (segPtr == textPtr->insertMarkPtr) { - markName = "insert"; - } else if (segPtr->body.mark.hPtr == NULL) { - /* - * Ignore widget-specific marks for the other widgets. This is either - * an insert or a current mark (markPtr->body.mark.hPtr actually - * receives NULL for these marks in TkTextSetMark). The insert and - * current marks for textPtr having already been tested above, the - * current segment is an insert or current mark from a peer of - * textPtr, which we don't want to return. - */ - - return NULL; - } else { - markName = Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, - segPtr->body.mark.hPtr); - } - return Tcl_NewStringObj(markName, -1); -} - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * End: - */ |