Esempio n. 1
0
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 = (TkTextSegment *) 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;

            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);
            if (TkBTreeLinesTo(textPtr, indexPtr->linePtr) ==
                    TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr))  {
                TkTextIndexBackChars(NULL,indexPtr, 1, &insertIndex,
                                     COUNT_INDICES);
                indexPtr = &insertIndex;
            }
        }
        TkBTreeUnlinkSegment(markPtr, markPtr->body.mark.linePtr);
    } else {
        markPtr = (TkTextSegment *) 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;
}
Esempio n. 2
0
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 *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 arg ...?");
        return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[2], markOptionStrings, "mark option",
                            0, &optionIndex) != TCL_OK) {
        return TCL_ERROR;
    }

    switch ((enum markOptions) optionIndex) {
    case MARK_GRAVITY: {
        char c;
        int length;
        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_AppendResult(interp, "there is no mark named \"",
                                 Tcl_GetString(objv[3]), "\"", NULL);
                return TCL_ERROR;
            }
            markPtr = (TkTextSegment *) Tcl_GetHashValue(hPtr);
        }
        if (objc == 4) {
            if (markPtr->typePtr == &tkTextRightMarkType) {
                Tcl_SetResult(interp, "right", TCL_STATIC);
            } else {
                Tcl_SetResult(interp, "left", TCL_STATIC);
            }
            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_AppendResult(interp, "bad mark gravity \"", str,
                             "\": must be left or right", NULL);
            return TCL_ERROR;
        }
        TkTextMarkSegToIndex(textPtr, markPtr, &index);
        TkBTreeUnlinkSegment(markPtr, markPtr->body.mark.linePtr);
        markPtr->typePtr = newTypePtr;
        TkBTreeLinkSegment(markPtr, &index);
        break;
    }
    case MARK_NAMES:
        if (objc != 3) {
            Tcl_WrongNumArgs(interp, 3, objv, NULL);
            return TCL_ERROR;
        }
        Tcl_AppendElement(interp, "insert");
        Tcl_AppendElement(interp, "current");
        for (hPtr = Tcl_FirstHashEntry(&textPtr->sharedTextPtr->markTable,
                                       &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
            Tcl_AppendElement(interp,
                              Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, hPtr));
        }
        break;
    case MARK_NEXT:
        if (objc != 4) {
            Tcl_WrongNumArgs(interp, 3, objv, "index");
            return TCL_ERROR;
        }
        return MarkFindNext(interp, textPtr, Tcl_GetString(objv[3]));
    case MARK_PREVIOUS:
        if (objc != 4) {
            Tcl_WrongNumArgs(interp, 3, objv, "index");
            return TCL_ERROR;
        }
        return MarkFindPrev(interp, textPtr, Tcl_GetString(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 = (TkTextSegment *) 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((char *) markPtr);
            }
        }
        break;
    }
    }
    return TCL_OK;
}
Esempio n. 3
0
int
TkTextWindowCmd(
    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 "window". */
{
    int optionIndex;
    static const char *const windOptionStrings[] = {
	"cget", "configure", "create", "names", NULL
    };
    enum windOptions {
	WIND_CGET, WIND_CONFIGURE, WIND_CREATE, WIND_NAMES
    };
    register TkTextSegment *ewPtr;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "option ?arg ...?");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[2], windOptionStrings,
	    "window option", 0, &optionIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    switch ((enum windOptions) optionIndex) {
    case WIND_CGET: {
	TkTextIndex index;
	TkTextSegment *ewPtr;
	Tcl_Obj *objPtr;
	TkTextEmbWindowClient *client;

	if (objc != 5) {
	    Tcl_WrongNumArgs(interp, 3, objv, "index option");
	    return TCL_ERROR;
	}
	if (TkTextGetObjIndex(interp, textPtr, objv[3], &index) != TCL_OK) {
	    return TCL_ERROR;
	}
	ewPtr = TkTextIndexToSeg(&index, NULL);
	if (ewPtr->typePtr != &tkTextEmbWindowType) {
	    Tcl_AppendResult(interp, "no embedded window at index \"",
		    Tcl_GetString(objv[3]), "\"", NULL);
	    return TCL_ERROR;
	}

	/*
	 * Copy over client specific value before querying.
	 */

	client = EmbWinGetClient(textPtr, ewPtr);
	if (client != NULL) {
	    ewPtr->body.ew.tkwin = client->tkwin;
	} else {
	    ewPtr->body.ew.tkwin = NULL;
	}

	objPtr = Tk_GetOptionValue(interp, (char *) &ewPtr->body.ew,
		ewPtr->body.ew.optionTable, objv[4], textPtr->tkwin);
	if (objPtr == NULL) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, objPtr);
	return TCL_OK;
    }
    case WIND_CONFIGURE: {
	TkTextIndex index;
	TkTextSegment *ewPtr;

	if (objc < 4) {
	    Tcl_WrongNumArgs(interp, 3, objv, "index ?-option value ...?");
	    return TCL_ERROR;
	}
	if (TkTextGetObjIndex(interp, textPtr, objv[3], &index) != TCL_OK) {
	    return TCL_ERROR;
	}
	ewPtr = TkTextIndexToSeg(&index, NULL);
	if (ewPtr->typePtr != &tkTextEmbWindowType) {
	    Tcl_AppendResult(interp, "no embedded window at index \"",
		    Tcl_GetString(objv[3]), "\"", NULL);
	    return TCL_ERROR;
	}
	if (objc <= 5) {
	    TkTextEmbWindowClient *client;
	    Tcl_Obj *objPtr;

	    /*
	     * Copy over client specific value before querying.
	     */

	    client = EmbWinGetClient(textPtr, ewPtr);
	    if (client != NULL) {
		ewPtr->body.ew.tkwin = client->tkwin;
	    } else {
		ewPtr->body.ew.tkwin = NULL;
	    }

	    objPtr = Tk_GetOptionInfo(interp, (char *) &ewPtr->body.ew,
		    ewPtr->body.ew.optionTable, (objc == 5) ? objv[4] : NULL,
		    textPtr->tkwin);
	    if (objPtr == NULL) {
		return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, objPtr);
	    return TCL_OK;
	} else {
	    TkTextChanged(textPtr->sharedTextPtr, NULL, &index, &index);

	    /*
	     * It's probably not true that all window configuration can change
	     * the line height, so we could be more efficient here and only
	     * call this when necessary.
	     */

	    TkTextInvalidateLineMetrics(textPtr->sharedTextPtr, NULL,
		    index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY);
	    return EmbWinConfigure(textPtr, ewPtr, objc-4, objv+4);
	}
    }
    case WIND_CREATE: {
	TkTextIndex index;
	int lineIndex;
	TkTextEmbWindowClient *client;
	int res;

	/*
	 * Add a new window. Find where to put the new window, and mark that
	 * position for redisplay.
	 */

	if (objc < 4) {
	    Tcl_WrongNumArgs(interp, 3, objv, "index ?-option value ...?");
	    return TCL_ERROR;
	}
	if (TkTextGetObjIndex(interp, textPtr, objv[3], &index) != TCL_OK) {
	    return TCL_ERROR;
	}

	/*
	 * Don't allow insertions on the last (dummy) line of the text.
	 */

	lineIndex = TkBTreeLinesTo(textPtr, index.linePtr);
	if (lineIndex == TkBTreeNumLines(textPtr->sharedTextPtr->tree,
		textPtr)) {
	    lineIndex--;
	    TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr,
		    lineIndex, 1000000, &index);
	}

	/*
	 * Create the new window segment and initialize it.
	 */

	ewPtr = (TkTextSegment *) ckalloc(EW_SEG_SIZE);
	ewPtr->typePtr = &tkTextEmbWindowType;
	ewPtr->size = 1;
	ewPtr->body.ew.sharedTextPtr = textPtr->sharedTextPtr;
	ewPtr->body.ew.linePtr = NULL;
	ewPtr->body.ew.tkwin = NULL;
	ewPtr->body.ew.create = NULL;
	ewPtr->body.ew.align = ALIGN_CENTER;
	ewPtr->body.ew.padX = ewPtr->body.ew.padY = 0;
	ewPtr->body.ew.stretch = 0;
	ewPtr->body.ew.optionTable = Tk_CreateOptionTable(interp, optionSpecs);

	client = (TkTextEmbWindowClient *)
		ckalloc(sizeof(TkTextEmbWindowClient));
	client->next = NULL;
	client->textPtr = textPtr;
	client->tkwin = NULL;
	client->chunkCount = 0;
	client->displayed = 0;
	client->parent = ewPtr;
	ewPtr->body.ew.clients = client;

	/*
	 * Link the segment into the text widget, then configure it (delete it
	 * again if the configuration fails).
	 */

	TkTextChanged(textPtr->sharedTextPtr, NULL, &index, &index);
	TkBTreeLinkSegment(ewPtr, &index);
	res = EmbWinConfigure(textPtr, ewPtr, objc-4, objv+4);
	client->tkwin = ewPtr->body.ew.tkwin;
	if (res != TCL_OK) {
	    TkTextIndex index2;

	    TkTextIndexForwChars(NULL, &index, 1, &index2, COUNT_INDICES);
	    TkBTreeDeleteIndexRange(textPtr->sharedTextPtr->tree, &index,
		    &index2);
	    return TCL_ERROR;
	}
	TkTextInvalidateLineMetrics(textPtr->sharedTextPtr, NULL,
		index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY);
	break;
    }
    case WIND_NAMES: {
	Tcl_HashSearch search;
	Tcl_HashEntry *hPtr;

	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	for (hPtr = Tcl_FirstHashEntry(&textPtr->sharedTextPtr->windowTable,
		&search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
	    Tcl_AppendElement(interp,
		    Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, hPtr));
	}
	break;
    }
    }
    return TCL_OK;
}