summaryrefslogtreecommitdiffstats
path: root/generic/tkTextWind.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tkTextWind.c')
-rw-r--r--generic/tkTextWind.c1365
1 files changed, 954 insertions, 411 deletions
diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c
index c9fc20f..372725d 100644
--- a/generic/tkTextWind.c
+++ b/generic/tkTextWind.c
@@ -7,6 +7,7 @@
*
* Copyright (c) 1994 The Regents of the University of California.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
+ * Copyright (c) 2015-2017 Gregor Cramer
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -14,16 +15,36 @@
#include "tkPort.h"
#include "tkText.h"
+#include "tkTextTagSet.h"
+#include "tkTextUndo.h"
+#include "tkAlloc.h"
+#include <assert.h>
+
+#ifdef NDEBUG
+# define DEBUG(expr)
+#else
+# define DEBUG(expr) expr
+#endif
+
+/*
+ * Support of tk8.5.
+ */
+#ifdef CONST
+# undef CONST
+#endif
+#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 5
+# define CONST
+#else
+# define CONST const
+#endif
/*
* The following structure is the official type record for the embedded window
* geometry manager:
*/
-static void EmbWinRequestProc(ClientData clientData,
- Tk_Window tkwin);
-static void EmbWinLostSlaveProc(ClientData clientData,
- Tk_Window tkwin);
+static void EmbWinRequestProc(ClientData clientData, Tk_Window tkwin);
+static void EmbWinLostSlaveProc(ClientData clientData, Tk_Window tkwin);
static const Tk_GeomMgr textGeomType = {
"text", /* name */
@@ -32,39 +53,87 @@ static const Tk_GeomMgr textGeomType = {
};
/*
- * Macro that determines the size of an embedded window segment:
- */
-
-#define EW_SEG_SIZE ((unsigned) (Tk_Offset(TkTextSegment, body) \
- + sizeof(TkTextEmbWindow)))
-
-/*
* Prototypes for functions defined in this file:
*/
-static TkTextSegment * EmbWinCleanupProc(TkTextSegment *segPtr,
- TkTextLine *linePtr);
-static void EmbWinCheckProc(TkTextSegment *segPtr,
- TkTextLine *linePtr);
+static void EmbWinCheckProc(const TkSharedText *sharedTextPtr, const TkTextSegment *segPtr);
+static Tcl_Obj * EmbWinInspectProc(const TkSharedText *sharedTextPtr,
+ const TkTextSegment *segPtr);
static void EmbWinBboxProc(TkText *textPtr,
TkTextDispChunk *chunkPtr, int index, int y,
int lineHeight, int baseline, int *xPtr,int *yPtr,
int *widthPtr, int *heightPtr);
-static int EmbWinConfigure(TkText *textPtr, TkTextSegment *ewPtr,
+static int EmbWinConfigure(TkText *textPtr, TkTextSegment *ewPtr, bool undoable,
int objc, Tcl_Obj *const objv[]);
static void EmbWinDelayedUnmap(ClientData clientData);
-static int EmbWinDeleteProc(TkTextSegment *segPtr,
- TkTextLine *linePtr, int treeGone);
-static int EmbWinLayoutProc(TkText *textPtr,
- TkTextIndex *indexPtr, TkTextSegment *segPtr,
- int offset, int maxX, int maxChars,int noCharsYet,
- TkWrapMode wrapMode, TkTextDispChunk *chunkPtr);
-static void EmbWinStructureProc(ClientData clientData,
- XEvent *eventPtr);
-static void EmbWinUndisplayProc(TkText *textPtr,
- TkTextDispChunk *chunkPtr);
-static TkTextEmbWindowClient *EmbWinGetClient(const TkText *textPtr,
- TkTextSegment *ewPtr);
+static bool EmbWinDeleteProc(TkSharedText *sharedTextPtr, TkTextSegment *segPtr, int flags);
+static bool EmbWinRestoreProc(TkSharedText *sharedTextPtr, TkTextSegment *segPtr);
+static int EmbWinLayoutProc(const TkTextIndex *indexPtr, TkTextSegment *segPtr,
+ int offset, int maxX, int maxChars, bool noCharsYet,
+ TkWrapMode wrapMode, TkTextSpaceMode spaceMode, TkTextDispChunk *chunkPtr);
+static void EmbWinStructureProc(ClientData clientData, XEvent *eventPtr);
+static void EmbWinDisplayProc(TkText *textPtr, TkTextDispChunk *chunkPtr,
+ int x, int y, int lineHeight, int baseline, Display *display,
+ Drawable dst, int screenY);
+static void EmbWinUndisplayProc(TkText *textPtr, TkTextDispChunk *chunkPtr);
+static TkTextEmbWindowClient *EmbWinGetClient(const TkText *textPtr, TkTextSegment *ewPtr);
+static TkTextSegment * MakeWindow(TkText *textPtr);
+static void ReleaseEmbeddedWindow(TkTextSegment *ewPtr);
+static void DestroyOrUnmapWindow(TkTextSegment *ewPtr);
+
+static const TkTextDispChunkProcs layoutWindowProcs = {
+ TEXT_DISP_WINDOW, /* type */
+ EmbWinDisplayProc, /* displayProc */
+ EmbWinUndisplayProc, /* undisplayProc */
+ NULL, /* measureProc */
+ EmbWinBboxProc, /* bboxProc */
+};
+
+/*
+ * We need some private undo/redo stuff.
+ */
+
+static void UndoLinkSegmentPerform(TkSharedText *, TkTextUndoInfo *, TkTextUndoInfo *, bool);
+static void RedoLinkSegmentPerform(TkSharedText *, TkTextUndoInfo *, TkTextUndoInfo *, bool);
+static void UndoLinkSegmentDestroy(TkSharedText *, TkTextUndoToken *, bool);
+static void UndoLinkSegmentGetRange(const TkSharedText *, const TkTextUndoToken *,
+ TkTextIndex *, TkTextIndex *);
+static void RedoLinkSegmentGetRange(const TkSharedText *, const TkTextUndoToken *,
+ TkTextIndex *, TkTextIndex *);
+static Tcl_Obj *UndoLinkSegmentGetCommand(const TkSharedText *, const TkTextUndoToken *);
+static Tcl_Obj *UndoLinkSegmentInspect(const TkSharedText *, const TkTextUndoToken *);
+static Tcl_Obj *RedoLinkSegmentInspect(const TkSharedText *, const TkTextUndoToken *);
+
+static const Tk_UndoType undoTokenLinkSegmentType = {
+ TK_TEXT_UNDO_WINDOW, /* action */
+ UndoLinkSegmentGetCommand, /* commandProc */
+ UndoLinkSegmentPerform, /* undoProc */
+ UndoLinkSegmentDestroy, /* destroyProc */
+ UndoLinkSegmentGetRange, /* rangeProc */
+ UndoLinkSegmentInspect /* inspectProc */
+};
+
+static const Tk_UndoType redoTokenLinkSegmentType = {
+ TK_TEXT_REDO_WINDOW, /* action */
+ UndoLinkSegmentGetCommand, /* commandProc */
+ RedoLinkSegmentPerform, /* undoProc */
+ UndoLinkSegmentDestroy, /* destroyProc */
+ RedoLinkSegmentGetRange, /* rangeProc */
+ RedoLinkSegmentInspect /* inspectProc */
+};
+
+typedef struct UndoTokenLinkSegment {
+ const Tk_UndoType *undoType;
+ TkTextSegment *segPtr;
+ TkTextEmbWindowClient *client;
+} UndoTokenLinkSegment;
+
+typedef struct RedoTokenLinkSegment {
+ const Tk_UndoType *undoType;
+ TkTextSegment *segPtr;
+ TkTextEmbWindowClient *client;
+ TkTextUndoIndex index;
+} RedoTokenLinkSegment;
/*
* The following structure declares the "embedded window" segment type.
@@ -72,20 +141,20 @@ static TkTextEmbWindowClient *EmbWinGetClient(const TkText *textPtr,
const Tk_SegType tkTextEmbWindowType = {
"window", /* name */
- 0, /* leftGravity */
- NULL, /* splitProc */
+ SEG_GROUP_WINDOW, /* group */
+ GRAVITY_NEUTRAL, /* leftGravity */
EmbWinDeleteProc, /* deleteProc */
- EmbWinCleanupProc, /* cleanupProc */
- NULL, /* lineChangeProc */
+ EmbWinRestoreProc, /* restoreProc */
EmbWinLayoutProc, /* layoutProc */
- EmbWinCheckProc /* checkProc */
+ EmbWinCheckProc, /* checkProc */
+ EmbWinInspectProc /* inspectProc */
};
/*
* Definitions for alignment values:
*/
-static const char *const alignStrings[] = {
+static const char *CONST alignStrings[] = {
"baseline", "bottom", "center", "top", NULL
};
@@ -99,20 +168,200 @@ typedef enum {
static const Tk_OptionSpec optionSpecs[] = {
{TK_OPTION_STRING_TABLE, "-align", NULL, NULL,
- "center", -1, Tk_Offset(TkTextEmbWindow, align),
- 0, alignStrings, 0},
+ "center", -1, Tk_Offset(TkTextEmbWindow, align), 0, alignStrings, 0},
{TK_OPTION_STRING, "-create", NULL, NULL,
NULL, -1, Tk_Offset(TkTextEmbWindow, create), TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_BOOLEAN, "-owner", NULL, NULL,
+ "1", -1, Tk_Offset(TkTextEmbWindow, isOwner), 0, 0, 0},
{TK_OPTION_PIXELS, "-padx", NULL, NULL,
"0", -1, Tk_Offset(TkTextEmbWindow, padX), 0, 0, 0},
{TK_OPTION_PIXELS, "-pady", NULL, NULL,
"0", -1, Tk_Offset(TkTextEmbWindow, padY), 0, 0, 0},
{TK_OPTION_BOOLEAN, "-stretch", NULL, NULL,
"0", -1, Tk_Offset(TkTextEmbWindow, stretch), 0, 0, 0},
+ {TK_OPTION_STRING, "-tags", NULL, NULL,
+ NULL, -1, -1, TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_WINDOW, "-window", NULL, NULL,
NULL, -1, Tk_Offset(TkTextEmbWindow, tkwin), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0}
};
+
+DEBUG_ALLOC(extern unsigned tkTextCountNewSegment);
+DEBUG_ALLOC(extern unsigned tkTextCountNewUndoToken);
+
+/*
+ * Some useful helpers.
+ */
+
+static void
+TextChanged(
+ TkTextIndex *indexPtr)
+{
+ assert(indexPtr->textPtr);
+
+ TkTextChanged(NULL, indexPtr->textPtr, indexPtr, indexPtr);
+
+ /*
+ * TODO: 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(NULL, indexPtr->textPtr,
+ TkTextIndexGetLine(indexPtr), 0, TK_TEXT_INVALIDATE_ONLY);
+}
+
+/*
+ * Some functions for the undo/redo mechanism.
+ */
+
+static void
+GetIndex(
+ const TkSharedText *sharedTextPtr,
+ TkTextSegment *segPtr,
+ TkTextIndex *indexPtr)
+{
+ TkTextIndexClear2(indexPtr, NULL, sharedTextPtr->tree);
+ TkTextIndexSetSegment(indexPtr, segPtr);
+}
+
+static Tcl_Obj *
+UndoLinkSegmentGetCommand(
+ const TkSharedText *sharedTextPtr,
+ const TkTextUndoToken *item)
+{
+ Tcl_Obj *objPtr = Tcl_NewObj();
+ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj("window", -1));
+ return objPtr;
+}
+
+static Tcl_Obj *
+UndoLinkSegmentInspect(
+ const TkSharedText *sharedTextPtr,
+ const TkTextUndoToken *item)
+{
+ const UndoTokenLinkSegment *token = (const UndoTokenLinkSegment *) item;
+ Tcl_Obj *objPtr = UndoLinkSegmentGetCommand(sharedTextPtr, item);
+ char buf[TK_POS_CHARS];
+ TkTextIndex index;
+
+ GetIndex(sharedTextPtr, token->segPtr, &index);
+ TkTextIndexPrint(sharedTextPtr, NULL, &index, buf);
+ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj(buf, -1));
+ return objPtr;
+}
+
+static void
+UndoLinkSegmentPerform(
+ TkSharedText *sharedTextPtr,
+ TkTextUndoInfo *undoInfo,
+ TkTextUndoInfo *redoInfo,
+ bool isRedo)
+{
+ const UndoTokenLinkSegment *token = (const UndoTokenLinkSegment *) undoInfo->token;
+ TkTextSegment *segPtr = token->segPtr;
+ TkTextIndex index;
+
+ if (redoInfo) {
+ RedoTokenLinkSegment *redoToken;
+ redoToken = malloc(sizeof(RedoTokenLinkSegment));
+ redoToken->undoType = &redoTokenLinkSegmentType;
+ redoToken->client = token->client;
+ TkBTreeMakeUndoIndex(sharedTextPtr, segPtr, &redoToken->index);
+ redoInfo->token = (TkTextUndoToken *) redoToken;
+ (redoToken->segPtr = segPtr)->refCount += 1;
+ DEBUG_ALLOC(tkTextCountNewUndoToken++);
+ }
+
+ GetIndex(sharedTextPtr, segPtr, &index);
+ index.textPtr = token->client->textPtr;
+ TextChanged(&index);
+ TkBTreeUnlinkSegment(sharedTextPtr, segPtr);
+ EmbWinDeleteProc(sharedTextPtr, segPtr, 0);
+ TK_BTREE_DEBUG(TkBTreeCheck(sharedTextPtr->tree));
+}
+
+static void
+UndoLinkSegmentDestroy(
+ TkSharedText *sharedTextPtr,
+ TkTextUndoToken *item,
+ bool reused)
+{
+ UndoTokenLinkSegment *token = (UndoTokenLinkSegment *) item;
+
+ assert(!reused);
+
+ if (--token->segPtr->refCount == 0) {
+ ReleaseEmbeddedWindow(token->segPtr);
+ }
+}
+
+static void
+UndoLinkSegmentGetRange(
+ const TkSharedText *sharedTextPtr,
+ const TkTextUndoToken *item,
+ TkTextIndex *startIndex,
+ TkTextIndex *endIndex)
+{
+ const UndoTokenLinkSegment *token = (const UndoTokenLinkSegment *) item;
+
+ GetIndex(sharedTextPtr, token->segPtr, startIndex);
+ *endIndex = *startIndex;
+}
+
+static Tcl_Obj *
+RedoLinkSegmentInspect(
+ const TkSharedText *sharedTextPtr,
+ const TkTextUndoToken *item)
+{
+ const RedoTokenLinkSegment *token = (const RedoTokenLinkSegment *) item;
+ Tcl_Obj *objPtr = EmbWinInspectProc(sharedTextPtr, token->segPtr);
+ char buf[TK_POS_CHARS];
+ TkTextIndex index;
+ Tcl_Obj *idxPtr;
+
+ TkBTreeUndoIndexToIndex(sharedTextPtr, &token->index, &index);
+ TkTextIndexPrint(sharedTextPtr, NULL, &index, buf);
+ idxPtr = Tcl_NewStringObj(buf, -1);
+ Tcl_ListObjReplace(NULL, objPtr, 1, 0, 1, &idxPtr);
+ return objPtr;
+}
+
+static void
+RedoLinkSegmentPerform(
+ TkSharedText *sharedTextPtr,
+ TkTextUndoInfo *undoInfo,
+ TkTextUndoInfo *redoInfo,
+ bool isRedo)
+{
+ RedoTokenLinkSegment *token = (RedoTokenLinkSegment *) undoInfo->token;
+ TkTextIndex index;
+
+ TkBTreeReInsertSegment(sharedTextPtr, &token->index, token->segPtr);
+
+ if (redoInfo) {
+ redoInfo->token = undoInfo->token;
+ token->undoType = &undoTokenLinkSegmentType;
+ }
+
+ GetIndex(sharedTextPtr, token->segPtr, &index);
+ index.textPtr = token->client->textPtr;
+ TextChanged(&index);
+ token->segPtr->refCount += 1;
+ TK_BTREE_DEBUG(TkBTreeCheck(sharedTextPtr->tree));
+}
+
+static void
+RedoLinkSegmentGetRange(
+ const TkSharedText *sharedTextPtr,
+ const TkTextUndoToken *item,
+ TkTextIndex *startIndex,
+ TkTextIndex *endIndex)
+{
+ const RedoTokenLinkSegment *token = (const RedoTokenLinkSegment *) item;
+ TkBTreeUndoIndexToIndex(sharedTextPtr, &token->index, startIndex);
+ *endIndex = *startIndex;
+}
/*
*--------------------------------------------------------------
@@ -131,9 +380,26 @@ static const Tk_OptionSpec optionSpecs[] = {
*--------------------------------------------------------------
*/
+static bool
+MatchTagsOption(
+ const char *opt)
+{
+ static const char *pattern = "-tags";
+ const char *p = pattern;
+ const char *start = opt;
+
+ for ( ; *opt; ++p, ++opt) {
+ if (*p != *opt) {
+ return opt > start && *p == '\0';
+ }
+ }
+
+ return true;
+}
+
int
TkTextWindowCmd(
- register TkText *textPtr, /* Information about text widget. */
+ 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
@@ -147,16 +413,19 @@ TkTextWindowCmd(
enum windOptions {
WIND_CGET, WIND_CONFIGURE, WIND_CREATE, WIND_NAMES
};
- register TkTextSegment *ewPtr;
+ TkTextSegment *ewPtr;
+
+ assert(textPtr);
if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "option ?arg ...?");
+ Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObjStruct(interp, objv[2], windOptionStrings,
sizeof(char *), "window option", 0, &optionIndex) != TCL_OK) {
return TCL_ERROR;
}
+
switch ((enum windOptions) optionIndex) {
case WIND_CGET: {
TkTextIndex index;
@@ -168,14 +437,13 @@ TkTextWindowCmd(
Tcl_WrongNumArgs(interp, 3, objv, "index option");
return TCL_ERROR;
}
- if (TkTextGetObjIndex(interp, textPtr, objv[3], &index) != TCL_OK) {
+ if (!TkTextGetIndexFromObj(interp, textPtr, objv[3], &index)) {
return TCL_ERROR;
}
- ewPtr = TkTextIndexToSeg(&index, NULL);
+ ewPtr = TkTextIndexGetContentSegment(&index, NULL);
if (ewPtr->typePtr != &tkTextEmbWindowType) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "no embedded window at index \"%s\"",
- Tcl_GetString(objv[3])));
+ "no embedded window at index \"%s\"", Tcl_GetString(objv[3])));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_WINDOW", NULL);
return TCL_ERROR;
}
@@ -184,19 +452,22 @@ TkTextWindowCmd(
* Copy over client specific value before querying.
*/
- client = EmbWinGetClient(textPtr, ewPtr);
- if (client != NULL) {
+ if ((client = EmbWinGetClient(textPtr, ewPtr))) {
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;
+ if (MatchTagsOption(Tcl_GetString(objv[4]))) {
+ TkTextFindTags(interp, textPtr, ewPtr, true);
+ } else {
+ objPtr = Tk_GetOptionValue(interp, (char *) &ewPtr->body.ew,
+ ewPtr->body.ew.optionTable, objv[4], textPtr->tkwin);
+ if (!objPtr) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, objPtr);
}
- Tcl_SetObjResult(interp, objPtr);
return TCL_OK;
}
case WIND_CONFIGURE: {
@@ -204,60 +475,69 @@ TkTextWindowCmd(
TkTextSegment *ewPtr;
if (objc < 4) {
- Tcl_WrongNumArgs(interp, 3, objv, "index ?-option value ...?");
+ Tcl_WrongNumArgs(interp, 3, objv, "index ?option value ...?");
return TCL_ERROR;
}
- if (TkTextGetObjIndex(interp, textPtr, objv[3], &index) != TCL_OK) {
+ if (!TkTextGetIndexFromObj(interp, textPtr, objv[3], &index)) {
return TCL_ERROR;
}
- ewPtr = TkTextIndexToSeg(&index, NULL);
+ ewPtr = TkTextIndexGetContentSegment(&index, NULL);
if (ewPtr->typePtr != &tkTextEmbWindowType) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "no embedded window at index \"%s\"",
- Tcl_GetString(objv[3])));
+ "no embedded window at index \"%s\"", Tcl_GetString(objv[3])));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_WINDOW", NULL);
return TCL_ERROR;
}
if (objc <= 5) {
TkTextEmbWindowClient *client;
Tcl_Obj *objPtr;
+ Tcl_Obj **objs;
+ int objn = 0, i;
/*
* Copy over client specific value before querying.
*/
- client = EmbWinGetClient(textPtr, ewPtr);
- if (client != NULL) {
+ if ((client = EmbWinGetClient(textPtr, ewPtr))) {
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,
+ objPtr = Tk_GetOptionInfo(
+ interp,
+ (char *) &ewPtr->body.ew,
+ ewPtr->body.ew.optionTable,
+ objc == 5 ? objv[4] : NULL,
textPtr->tkwin);
- if (objPtr == NULL) {
+ if (!objPtr) {
return TCL_ERROR;
}
+ Tcl_ListObjGetElements(NULL, objPtr, &objn, &objs);
+ for (i = 0; i < objn; ++i) {
+ Tcl_Obj **objv;
+ int objc = 0;
+
+ Tcl_ListObjGetElements(NULL, objs[i], &objc, &objv);
+ if (objc == 5 && strcmp(Tcl_GetString(objv[0]), "-tags") == 0) {
+ Tcl_Obj *valuePtr;
+
+ /* { argvName, dbName, dbClass, defValue, current value } */
+ TkTextFindTags(interp, textPtr, ewPtr, true);
+ valuePtr = Tcl_GetObjResult(interp);
+ Tcl_ListObjReplace(NULL, objs[i], 4, 1, 1, &valuePtr);
+ }
+ }
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);
+ TextChanged(&index);
+ return EmbWinConfigure(textPtr, ewPtr, true, objc - 4, objv + 4);
}
}
case WIND_CREATE: {
+ TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
TkTextIndex index;
- int lineIndex;
TkTextEmbWindowClient *client;
int res;
@@ -267,69 +547,67 @@ TkTextWindowCmd(
*/
if (objc < 4) {
- Tcl_WrongNumArgs(interp, 3, objv, "index ?-option value ...?");
+ Tcl_WrongNumArgs(interp, 3, objv, "index ?option value ...?");
return TCL_ERROR;
}
- if (TkTextGetObjIndex(interp, textPtr, objv[3], &index) != TCL_OK) {
+ if (!TkTextGetIndexFromObj(interp, textPtr, objv[3], &index)) {
+ return TCL_ERROR;
+ }
+
+ if (textPtr->state == TK_TEXT_STATE_DISABLED &&
+ TkTextAttemptToModifyDisabledWidget(interp) != TCL_OK) {
return TCL_ERROR;
}
/*
- * Don't allow insertions on the last (dummy) line of the text.
+ * Don't allow insertions on the last 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);
+ if (!TkTextIndexEnsureBeforeLastChar(&index)) {
+ return TkTextAttemptToModifyDeadWidget(interp);
}
/*
* Create the new window segment and initialize it.
*/
- ewPtr = 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 = 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;
+ ewPtr = MakeWindow(textPtr);
+ client = ewPtr->body.ew.clients;
/*
* 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);
+ TkBTreeLinkSegment(sharedTextPtr, ewPtr, &index);
+ res = EmbWinConfigure(textPtr, ewPtr, false, 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);
+ TkBTreeUnlinkSegment(sharedTextPtr, ewPtr);
+ TkTextWinFreeClient(NULL, client);
+ ewPtr->body.ew.clients = NULL;
+ ReleaseEmbeddedWindow(ewPtr);
return TCL_ERROR;
}
- TkTextInvalidateLineMetrics(textPtr->sharedTextPtr, NULL,
- index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY);
+ TextChanged(&index);
+
+ if (!TkTextUndoStackIsFull(sharedTextPtr->undoStack)) {
+ UndoTokenLinkSegment *token;
+
+ assert(sharedTextPtr->undoStack);
+ assert(ewPtr->typePtr == &tkTextEmbWindowType);
+
+ token = malloc(sizeof(UndoTokenLinkSegment));
+ token->undoType = &undoTokenLinkSegmentType;
+ token->segPtr = ewPtr;
+ token->client = client;
+ ewPtr->refCount += 1;
+ DEBUG_ALLOC(tkTextCountNewUndoToken++);
+
+ TkTextPushUndoToken(sharedTextPtr, token, 0);
+ }
+
+ TkTextUpdateAlteredFlag(sharedTextPtr);
break;
}
case WIND_NAMES: {
@@ -342,11 +620,11 @@ TkTextWindowCmd(
return TCL_ERROR;
}
resultObj = Tcl_NewObj();
- for (hPtr = Tcl_FirstHashEntry(&textPtr->sharedTextPtr->windowTable,
- &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
+ for (hPtr = Tcl_FirstHashEntry(&textPtr->sharedTextPtr->windowTable, &search);
+ hPtr;
+ hPtr = Tcl_NextHashEntry(&search)) {
Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
- Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, hPtr),
- -1));
+ Tcl_GetHashKey(&textPtr->sharedTextPtr->markTable, hPtr), -1));
}
Tcl_SetObjResult(interp, resultObj);
break;
@@ -358,6 +636,109 @@ TkTextWindowCmd(
/*
*--------------------------------------------------------------
*
+ * MakeWindow --
+ *
+ * This function is called to create a window segment.
+ *
+ * Results:
+ * The return value is the newly created window.
+ *
+ * Side effects:
+ * Some memory will be allocated.
+ *
+ *--------------------------------------------------------------
+ */
+
+static TkTextSegment *
+MakeWindow(
+ TkText *textPtr) /* Information about text widget that contains embedded image. */
+{
+ TkTextSegment *ewPtr;
+ TkTextEmbWindowClient *client;
+
+ ewPtr = calloc(1, SEG_SIZE(TkTextEmbWindow));
+ NEW_SEGMENT(ewPtr);
+ ewPtr->typePtr = &tkTextEmbWindowType;
+ ewPtr->size = 1;
+ ewPtr->refCount = 1;
+ ewPtr->body.ew.sharedTextPtr = textPtr->sharedTextPtr;
+ ewPtr->body.ew.align = ALIGN_CENTER;
+ ewPtr->body.ew.isOwner = true;
+ ewPtr->body.ew.optionTable = Tk_CreateOptionTable(textPtr->interp, optionSpecs);
+ DEBUG_ALLOC(tkTextCountNewSegment++);
+
+ client = calloc(1, sizeof(TkTextEmbWindowClient));
+ client->textPtr = textPtr;
+ client->parent = ewPtr;
+ ewPtr->body.ew.clients = client;
+
+ return ewPtr;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * TkTextMakeWindow --
+ *
+ * This function is called to create a window segment.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If TCL_ERROR is returned,
+ * then the interp's result contains an error message.
+ *
+ * Side effects:
+ * Some memory will be allocated.
+ *
+ *--------------------------------------------------------------
+ */
+
+TkTextSegment *
+TkTextMakeWindow(
+ TkText *textPtr, /* Information about text widget that contains embedded window. */
+ Tcl_Obj *options) /* Options for this window. */
+{
+ TkTextSegment *ewPtr;
+ Tcl_Obj **objv;
+ Tcl_Obj **argv;
+ int objc, i;
+
+ assert(options);
+
+ if (Tcl_ListObjGetElements(textPtr->interp, options, &objc, &objv) != TCL_OK) {
+ return NULL;
+ }
+
+ argv = malloc(objc*sizeof(argv[0]));
+ memcpy(argv, objv, objc*sizeof(argv[0]));
+ for (i = 0; i < objc; i += 2) {
+ if (strncmp(Tcl_GetString(argv[i]), "-w", 2) == 0) {
+ if (!Tk_NameToWindow(textPtr->interp, Tcl_GetString(argv[i + 1]), textPtr->tkwin)) {
+ /*
+ * The specified window (given with option -window) does not exist, so
+ * set the value to NULL.
+ */
+ argv[i + 1] = NULL;
+ }
+ }
+ }
+
+ ewPtr = MakeWindow(textPtr);
+
+ if (EmbWinConfigure(textPtr, ewPtr, false, objc, argv) == TCL_OK) {
+ Tcl_ResetResult(textPtr->interp);
+ } else {
+ TkTextWinFreeClient(NULL, ewPtr->body.ew.clients);
+ ewPtr->body.ew.clients = NULL;
+ ReleaseEmbeddedWindow(ewPtr);
+ ewPtr = NULL;
+ }
+
+ return ewPtr;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
* EmbWinConfigure --
*
* This function is called to handle configuration options for an
@@ -379,56 +760,96 @@ TkTextWindowCmd(
*--------------------------------------------------------------
*/
+static bool
+IsPreservedWindow(
+ const TkTextEmbWindowClient *client)
+{
+ return client && !client->hPtr;
+}
+
+static void
+TriggerWatchCmd(
+ TkText *textPtr,
+ TkTextSegment *ewPtr,
+ Tk_Window tkwin,
+ const char *arg1,
+ const char *arg2)
+{
+ if (!(textPtr->flags & DESTROYED)) {
+ TkTextIndex index;
+ char buf[TK_POS_CHARS];
+
+ TkTextIndexClear(&index, textPtr);
+ TkTextIndexSetSegment(&index, ewPtr);
+ TkTextPrintIndex(textPtr, &index, buf);
+ TkTextTriggerWatchCmd(textPtr, "window", buf, buf, Tk_PathName(tkwin), arg1, arg2, false);
+ }
+}
+
static int
EmbWinConfigure(
TkText *textPtr, /* Information about text widget that contains
* embedded window. */
TkTextSegment *ewPtr, /* Embedded window to be configured. */
+ bool undoable, /* Replacement of tags is undoable? */
int objc, /* Number of strings in objv. */
- Tcl_Obj *const objv[]) /* Array of objects describing configuration
- * options. */
+ Tcl_Obj *const objv[]) /* Array of objects describing configuration options. */
{
Tk_Window oldWindow;
TkTextEmbWindowClient *client;
+ int i;
+
+ assert(textPtr);
/*
* Copy over client specific value before querying or setting.
*/
client = EmbWinGetClient(textPtr, ewPtr);
- if (client != NULL) {
- ewPtr->body.ew.tkwin = client->tkwin;
- } else {
- ewPtr->body.ew.tkwin = NULL;
- }
-
+ ewPtr->body.ew.tkwin = client ? client->tkwin : NULL;
oldWindow = ewPtr->body.ew.tkwin;
+
if (Tk_SetOptions(textPtr->interp, (char *) &ewPtr->body.ew,
- ewPtr->body.ew.optionTable, objc, objv, textPtr->tkwin, NULL,
- NULL) != TCL_OK) {
+ ewPtr->body.ew.optionTable, objc, objv, textPtr->tkwin, NULL, NULL) != TCL_OK) {
return TCL_ERROR;
}
- if (oldWindow != ewPtr->body.ew.tkwin) {
- if (oldWindow != NULL) {
- Tcl_DeleteHashEntry(Tcl_FindHashEntry(
- &textPtr->sharedTextPtr->windowTable,
- Tk_PathName(oldWindow)));
- Tk_DeleteEventHandler(oldWindow, StructureNotifyMask,
- EmbWinStructureProc, client);
+ for (i = 0; i + 1 < objc; i += 2) {
+ if (MatchTagsOption(Tcl_GetString(objv[i]))) {
+ TkTextReplaceTags(textPtr, ewPtr, undoable, objv[i + 1]);
+ }
+ }
+
+ if (oldWindow != ewPtr->body.ew.tkwin && (!oldWindow || !IsPreservedWindow(client))) {
+ if (oldWindow) {
+ Tcl_HashEntry *hPtr;
+
+ textPtr->sharedTextPtr->numWindows -= 1;
+ hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->windowTable, Tk_PathName(oldWindow));
+ assert(hPtr);
+ Tcl_DeleteHashEntry(hPtr);
+ Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, EmbWinStructureProc, client);
Tk_ManageGeometry(oldWindow, NULL, NULL);
if (textPtr->tkwin != Tk_Parent(oldWindow)) {
Tk_UnmaintainGeometry(oldWindow, textPtr->tkwin);
} else {
Tk_UnmapWindow(oldWindow);
}
+ if (textPtr->watchCmd) {
+ textPtr->refCount += 1;
+ TriggerWatchCmd(textPtr, ewPtr, oldWindow, NULL, NULL);
+ if (TkTextDecrRefCountAndTestIfDestroyed(textPtr)) {
+ return TCL_OK;
+ }
+ }
}
- if (client != NULL) {
+ if (client) {
client->tkwin = NULL;
+ client->hPtr = NULL;
}
- if (ewPtr->body.ew.tkwin != NULL) {
+ if (ewPtr->body.ew.tkwin) {
Tk_Window ancestor, parent;
- Tcl_HashEntry *hPtr;
+ bool cantEmbed = false;
int isNew;
/*
@@ -443,36 +864,31 @@ EmbWinConfigure(
break;
}
if (Tk_TopWinHierarchy(ancestor)) {
- badMaster:
- Tcl_SetObjResult(textPtr->interp, Tcl_ObjPrintf(
- "can't embed %s in %s",
- Tk_PathName(ewPtr->body.ew.tkwin),
- Tk_PathName(textPtr->tkwin)));
- Tcl_SetErrorCode(textPtr->interp, "TK", "GEOMETRY",
- "HIERARCHY", NULL);
- ewPtr->body.ew.tkwin = NULL;
- if (client != NULL) {
- client->tkwin = NULL;
- }
- return TCL_ERROR;
+ cantEmbed = true;
+ break;
}
}
- if (Tk_TopWinHierarchy(ewPtr->body.ew.tkwin)
+ if (cantEmbed
+ || Tk_TopWinHierarchy(ewPtr->body.ew.tkwin)
|| (ewPtr->body.ew.tkwin == textPtr->tkwin)) {
- goto badMaster;
+ Tcl_SetObjResult(textPtr->interp, Tcl_ObjPrintf("can't embed %s in %s",
+ Tk_PathName(ewPtr->body.ew.tkwin), Tk_PathName(textPtr->tkwin)));
+ Tcl_SetErrorCode(textPtr->interp, "TK", "GEOMETRY", "HIERARCHY", NULL);
+ ewPtr->body.ew.tkwin = NULL;
+ if (client) {
+ client->tkwin = NULL;
+ }
+ return TCL_ERROR;
}
- if (client == NULL) {
+ if (!client) {
/*
* Have to make the new client.
*/
- client = ckalloc(sizeof(TkTextEmbWindowClient));
+ client = calloc(1, sizeof(TkTextEmbWindowClient));
client->next = ewPtr->body.ew.clients;
client->textPtr = textPtr;
- client->tkwin = NULL;
- client->chunkCount = 0;
- client->displayed = 0;
client->parent = ewPtr;
ewPtr->body.ew.clients = client;
}
@@ -488,15 +904,18 @@ EmbWinConfigure(
EmbWinStructureProc, client);
/*
- * Special trick! Must enter into the hash table *after* calling
+ * Special trick! Must enter into the hash table *after* calling
* Tk_ManageGeometry: if the window was already managed elsewhere
* in this text, the Tk_ManageGeometry call will cause the entry
* to be removed, which could potentially lose the new entry.
*/
- hPtr = Tcl_CreateHashEntry(&textPtr->sharedTextPtr->windowTable,
- Tk_PathName(ewPtr->body.ew.tkwin), &isNew);
- Tcl_SetHashValue(hPtr, ewPtr);
+ client->hPtr = Tcl_CreateHashEntry(
+ &textPtr->sharedTextPtr->windowTable,
+ Tk_PathName(ewPtr->body.ew.tkwin),
+ &isNew);
+ Tcl_SetHashValue(client->hPtr, ewPtr);
+ textPtr->sharedTextPtr->numWindows += 1;
}
}
return TCL_OK;
@@ -527,32 +946,34 @@ EmbWinStructureProc(
XEvent *eventPtr) /* Describes what just happened. */
{
TkTextEmbWindowClient *client = clientData;
- TkTextSegment *ewPtr = client->parent;
- TkTextIndex index;
- Tcl_HashEntry *hPtr;
+ TkTextSegment *ewPtr;
+ Tk_Window tkwin;
- if (eventPtr->type != DestroyNotify) {
+ if (eventPtr->type != DestroyNotify || !client->hPtr) {
return;
}
- hPtr = Tcl_FindHashEntry(&ewPtr->body.ew.sharedTextPtr->windowTable,
- Tk_PathName(client->tkwin));
- if (hPtr != NULL) {
- /*
- * This may not exist if the entire widget is being deleted.
- */
+ ewPtr = client->parent;
+ tkwin = client->tkwin;
- Tcl_DeleteHashEntry(hPtr);
- }
+ assert(ewPtr->typePtr);
+ assert(client->hPtr == Tcl_FindHashEntry(&ewPtr->body.ew.sharedTextPtr->windowTable,
+ Tk_PathName(tkwin)));
+
+ /*
+ * This may not exist if the entire widget is being deleted.
+ */
+ Tcl_DeleteHashEntry(client->hPtr);
+ ewPtr->body.ew.sharedTextPtr->numWindows -= 1;
ewPtr->body.ew.tkwin = NULL;
client->tkwin = NULL;
- index.tree = ewPtr->body.ew.sharedTextPtr->tree;
- index.linePtr = ewPtr->body.ew.linePtr;
- index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr);
- TkTextChanged(ewPtr->body.ew.sharedTextPtr, NULL, &index, &index);
- TkTextInvalidateLineMetrics(ewPtr->body.ew.sharedTextPtr, NULL,
- index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY);
+ client->hPtr = NULL;
+ EmbWinRequestProc(client, NULL);
+
+ if (client->textPtr->watchCmd) {
+ TriggerWatchCmd(client->textPtr, ewPtr, tkwin, NULL, NULL);
+ }
}
/*
@@ -573,7 +994,6 @@ EmbWinStructureProc(
*--------------------------------------------------------------
*/
- /* ARGSUSED */
static void
EmbWinRequestProc(
ClientData clientData, /* Pointer to record for window item. */
@@ -583,12 +1003,14 @@ EmbWinRequestProc(
TkTextSegment *ewPtr = client->parent;
TkTextIndex index;
- index.tree = ewPtr->body.ew.sharedTextPtr->tree;
- index.linePtr = ewPtr->body.ew.linePtr;
- index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr);
- TkTextChanged(ewPtr->body.ew.sharedTextPtr, NULL, &index, &index);
- TkTextInvalidateLineMetrics(ewPtr->body.ew.sharedTextPtr, NULL,
- index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY);
+ assert(ewPtr->typePtr);
+
+ if (ewPtr->sectionPtr) {
+ assert(ewPtr->sectionPtr);
+ TkTextIndexClear(&index, client->textPtr);
+ TkTextIndexSetSegment(&index, ewPtr);
+ TextChanged(&index);
+ }
}
/*
@@ -613,26 +1035,26 @@ EmbWinRequestProc(
static void
EmbWinLostSlaveProc(
ClientData clientData, /* Pointer to record describing window item. */
- Tk_Window tkwin) /* Window that was claimed away by another
- * geometry manager. */
+ Tk_Window tkwin) /* Window that was claimed away by another geometry manager. */
{
TkTextEmbWindowClient *client = clientData;
TkTextSegment *ewPtr = client->parent;
+ TkText *textPtr = client->textPtr;
TkTextIndex index;
- Tcl_HashEntry *hPtr;
TkTextEmbWindowClient *loop;
- Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask,
- EmbWinStructureProc, client);
+ assert(!IsPreservedWindow(client));
+
+ assert(client->tkwin);
+ client->displayed = false;
+ Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask, EmbWinStructureProc, client);
Tcl_CancelIdleCall(EmbWinDelayedUnmap, client);
- if (client->textPtr->tkwin != Tk_Parent(tkwin)) {
- Tk_UnmaintainGeometry(tkwin, client->textPtr->tkwin);
- } else {
- Tk_UnmapWindow(tkwin);
+ EmbWinDelayedUnmap(client);
+ if (client->hPtr) {
+ ewPtr->body.ew.sharedTextPtr->numWindows -= 1;
+ Tcl_DeleteHashEntry(client->hPtr);
+ client->hPtr = NULL;
}
- hPtr = Tcl_FindHashEntry(&ewPtr->body.ew.sharedTextPtr->windowTable,
- Tk_PathName(client->tkwin));
- Tcl_DeleteHashEntry(hPtr);
client->tkwin = NULL;
ewPtr->body.ew.tkwin = NULL;
@@ -649,14 +1071,15 @@ EmbWinLostSlaveProc(
}
loop->next = client->next;
}
- ckfree(client);
-
- index.tree = ewPtr->body.ew.sharedTextPtr->tree;
- index.linePtr = ewPtr->body.ew.linePtr;
- index.byteIndex = TkTextSegToOffset(ewPtr, ewPtr->body.ew.linePtr);
- TkTextChanged(ewPtr->body.ew.sharedTextPtr, NULL, &index, &index);
- TkTextInvalidateLineMetrics(ewPtr->body.ew.sharedTextPtr, NULL,
- index.linePtr, 0, TK_TEXT_INVALIDATE_ONLY);
+ free(client);
+
+ TkTextIndexClear(&index, textPtr);
+ TkTextIndexSetSegment(&index, ewPtr);
+ TextChanged(&index);
+
+ if (textPtr->watchCmd) {
+ TriggerWatchCmd(textPtr, ewPtr, tkwin, NULL, NULL);
+ }
}
/*
@@ -682,19 +1105,18 @@ EmbWinLostSlaveProc(
void
TkTextWinFreeClient(
- Tcl_HashEntry *hPtr, /* Hash entry corresponding to this client, or
- * NULL */
+ Tcl_HashEntry *hPtr, /* Hash entry corresponding to this client, or NULL */
TkTextEmbWindowClient *client)
- /* Client data structure, with the 'tkwin'
- * field to be cleaned up. */
+ /* Client data structure, with the 'tkwin' field to be cleaned up. */
{
- if (hPtr != NULL) {
+ if (hPtr) {
/*
* (It's possible for there to be no hash table entry for this window,
* if an error occurred while creating the window segment but before
* the window got added to the table)
*/
+ client->parent->body.ew.sharedTextPtr->numWindows -= 1;
Tcl_DeleteHashEntry(hPtr);
}
@@ -704,10 +1126,11 @@ TkTextWinFreeClient(
* everything that it would have done, and it will just get confused).
*/
- if (client->tkwin != NULL) {
- Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask,
- EmbWinStructureProc, client);
- Tk_DestroyWindow(client->tkwin);
+ if (client->tkwin) {
+ Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask, EmbWinStructureProc, client);
+ if (client->parent->body.ew.isOwner) {
+ Tk_DestroyWindow(client->tkwin);
+ }
}
Tcl_CancelIdleCall(EmbWinDelayedUnmap, client);
@@ -715,88 +1138,223 @@ TkTextWinFreeClient(
* Free up this client.
*/
- ckfree(client);
+ free(client);
}
/*
*--------------------------------------------------------------
*
- * EmbWinDeleteProc --
+ * EmbWinInspectProc --
*
- * This function is invoked by the text B-tree code whenever an embedded
- * window lies in a range of characters being deleted.
+ * This function is invoked to build the information for
+ * "inspect".
*
* Results:
- * Returns 0 to indicate that the deletion has been accepted.
+ * Return a TCL object containing the information for
+ * "inspect".
*
* Side effects:
- * The embedded window is deleted, if it exists, and any resources
+ * Storage is allocated.
+ *
+ *--------------------------------------------------------------
+ */
+
+static Tcl_Obj *
+EmbWinInspectProc(
+ const TkSharedText *sharedTextPtr,
+ const TkTextSegment *segPtr)
+{
+ Tcl_Obj *objPtr = Tcl_NewObj();
+ Tcl_Obj *objPtr2 = Tcl_NewObj();
+ TkTextTag **tagLookup = sharedTextPtr->tagLookup;
+ const TkTextTagSet *tagInfoPtr = segPtr->tagInfoPtr;
+ unsigned i = TkTextTagSetFindFirst(tagInfoPtr);
+ Tcl_DString opts;
+
+ assert(sharedTextPtr->peers);
+
+ for ( ; i != TK_TEXT_TAG_SET_NPOS; i = TkTextTagSetFindNext(tagInfoPtr, i)) {
+ const TkTextTag *tagPtr = tagLookup[i];
+ Tcl_ListObjAppendElement(NULL, objPtr2, Tcl_NewStringObj(tagPtr->name, -1));
+ }
+
+ Tcl_DStringInit(&opts);
+ TkTextInspectOptions(sharedTextPtr->peers, &segPtr->body.ew, segPtr->body.ew.optionTable,
+ &opts, 0);
+
+ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj(segPtr->typePtr->name, -1));
+ Tcl_ListObjAppendElement(NULL, objPtr, objPtr2);
+ Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewStringObj(Tcl_DStringValue(&opts),
+ Tcl_DStringLength(&opts)));
+
+ Tcl_DStringFree(&opts);
+ return objPtr;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ReleaseEmbeddedWindow --
+ *
+ * Free embedded window
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The embedded window is deleted, and any resources
* associated with it are released.
*
*--------------------------------------------------------------
*/
- /* ARGSUSED */
-static int
-EmbWinDeleteProc(
- TkTextSegment *ewPtr, /* 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. */
+static void
+ReleaseEmbeddedWindow(
+ TkTextSegment *ewPtr)
{
- TkTextEmbWindowClient *client;
- client = ewPtr->body.ew.clients;
+ TkTextEmbWindowClient *client = ewPtr->body.ew.clients;
- while (client != NULL) {
- TkTextEmbWindowClient *next = client->next;
- Tcl_HashEntry *hPtr = NULL;
+ assert(ewPtr->typePtr);
- if (client->tkwin != NULL) {
- hPtr = Tcl_FindHashEntry(
- &ewPtr->body.ew.sharedTextPtr->windowTable,
- Tk_PathName(client->tkwin));
+ while (client) {
+ TkTextEmbWindowClient *next = client->next;
+ if (client->hPtr) {
+ TkTextWinFreeClient(client->hPtr, client);
}
- TkTextWinFreeClient(hPtr, client);
client = next;
}
ewPtr->body.ew.clients = NULL;
+ Tk_FreeConfigOptions((char *) &ewPtr->body.ew, ewPtr->body.ew.optionTable, NULL);
+ TkBTreeFreeSegment(ewPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * DestroyOrUnmapWindow --
+ *
+ * Unmap all clients of given window.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Either destroy or only unmap the embedded window.
+ *
+ *--------------------------------------------------------------
+ */
- Tk_FreeConfigOptions((char *) &ewPtr->body.ew, ewPtr->body.ew.optionTable,
- NULL);
+static void
+DestroyOrUnmapWindow(
+ TkTextSegment *ewPtr)
+{
+ TkTextEmbWindowClient *client = ewPtr->body.ew.clients;
- /*
- * Free up all memory allocated.
- */
+ assert(ewPtr->typePtr);
+ assert(ewPtr->refCount > 0);
+
+ for ( ; client; client = client->next) {
+ if (client->hPtr) {
+ client->parent->body.ew.sharedTextPtr->numWindows -= 1;
+ Tcl_DeleteHashEntry(client->hPtr);
+ client->hPtr = NULL;
+ client->displayed = false;
+ }
+ Tcl_CancelIdleCall(EmbWinDelayedUnmap, client);
+ if (client->tkwin && ewPtr->body.ew.create) {
+ Tk_DeleteEventHandler(client->tkwin, StructureNotifyMask, EmbWinStructureProc, client);
+ if (ewPtr->body.ew.isOwner) {
+ Tk_DestroyWindow(client->tkwin);
+ }
+ client->tkwin = NULL;
+ ewPtr->body.ew.tkwin = NULL;
+ } else {
+ EmbWinDelayedUnmap(client);
+ }
+ }
+}
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinDeleteProc --
+ *
+ * This function is invoked by the text B-tree code whenever an embedded
+ * window lies in a range of characters being deleted.
+ *
+ * Results:
+ * Returns true to indicate that the deletion has been accepted.
+ *
+ * Side effects:
+ * Depends on the action, see ReleaseEmbeddedWindow and DestroyOrUnmapWindow.
+ *
+ *--------------------------------------------------------------
+ */
+
+static bool
+EmbWinDeleteProc(
+ TkSharedText *sharedTextPtr,/* Handle to shared text resource. */
+ TkTextSegment *ewPtr, /* Segment being deleted. */
+ int flags) /* Flags controlling the deletion. */
+{
+ assert(ewPtr->typePtr);
+ assert(ewPtr->refCount > 0);
- ckfree(ewPtr);
- return 0;
+ if (ewPtr->refCount == 1) {
+ ReleaseEmbeddedWindow(ewPtr);
+ } else {
+ ewPtr->refCount -= 1;
+ DestroyOrUnmapWindow(ewPtr);
+ }
+ return true;
}
/*
*--------------------------------------------------------------
*
- * EmbWinCleanupProc --
+ * EmbWinRestoreProc --
*
- * This function is invoked by the B-tree code whenever a segment
- * containing an embedded window is moved from one line to another.
+ * This function is called when a window segment will be restored
+ * from the undo chain.
*
* Results:
* None.
*
* Side effects:
- * The linePtr field of the segment gets updated.
+ * The name of the mark will be freed, and the mark will be
+ * re-entered into the hash table.
*
*--------------------------------------------------------------
*/
-static TkTextSegment *
-EmbWinCleanupProc(
- TkTextSegment *ewPtr, /* Mark segment that's being moved. */
- TkTextLine *linePtr) /* Line that now contains segment. */
+static bool
+EmbWinRestoreProc(
+ TkSharedText *sharedTextPtr,/* Handle to shared text resource. */
+ TkTextSegment *ewPtr) /* Segment to reuse. */
{
- ewPtr->body.ew.linePtr = linePtr;
- return ewPtr;
+ int isNew;
+
+ if (ewPtr->body.ew.create) {
+ /*
+ * EmbWinLayoutProc is doing the creation of the window.
+ */
+ assert(!ewPtr->body.ew.tkwin);
+ } else {
+ TkTextEmbWindowClient *client = ewPtr->body.ew.clients;
+
+ for ( ; client; client = client->next) {
+ if (client->tkwin && !client->hPtr) {
+ client->hPtr = Tcl_CreateHashEntry(
+ &ewPtr->body.ew.sharedTextPtr->windowTable,
+ Tk_PathName(client->tkwin),
+ &isNew);
+ assert(isNew);
+ Tcl_SetHashValue(client->hPtr, ewPtr);
+ ewPtr->body.ew.sharedTextPtr->numWindows += 1;
+ }
+ }
+ }
+
+ return true;
}
/*
@@ -816,49 +1374,39 @@ EmbWinCleanupProc(
*--------------------------------------------------------------
*/
- /*ARGSUSED*/
static int
EmbWinLayoutProc(
- TkText *textPtr, /* Text widget being layed out. */
- TkTextIndex *indexPtr, /* Identifies first character in chunk. */
+ const TkTextIndex *indexPtr,/* Identifies first character in chunk. */
TkTextSegment *ewPtr, /* 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, /* Wrap mode to use for line:
- * TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_NONE, or
- * TEXT_WRAPMODE_WORD. */
- register TkTextDispChunk *chunkPtr)
- /* Structure to fill in with information about
- * this chunk. The x field has already been
- * set by the caller. */
+ 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. */
+ bool noCharsYet, /* 'true' means no characters have been assigned to this line yet. */
+ TkWrapMode wrapMode, /* Wrap mode to use for line: TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_NONE,
+ * TEXT_WRAPMODE_WORD, or TEXT_WRAPMODE_CODEPOINT. */
+ TkTextSpaceMode spaceMode, /* Not used. */
+ TkTextDispChunk *chunkPtr) /* Structure to fill in with information about this chunk. The x
+ * field has already been set by the caller. This argument may be
+ * NULL. */
{
int width, height;
TkTextEmbWindowClient *client;
+ TkText *textPtr = indexPtr->textPtr;
+ bool cantEmbed = false;
+ int x;
- if (offset != 0) {
- Tcl_Panic("Non-zero offset in EmbWinLayoutProc");
- }
+ assert(indexPtr->textPtr);
+ assert(offset == 0);
client = EmbWinGetClient(textPtr, ewPtr);
- if (client == NULL) {
- ewPtr->body.ew.tkwin = NULL;
- } else {
- ewPtr->body.ew.tkwin = client->tkwin;
- }
+ ewPtr->body.ew.tkwin = client ? client->tkwin : NULL;
- if ((ewPtr->body.ew.tkwin == NULL) && (ewPtr->body.ew.create != NULL)) {
- int code, isNew;
+ if (!ewPtr->body.ew.tkwin && ewPtr->body.ew.create) {
+ int code;
+ int isNew;
Tk_Window ancestor;
- Tcl_HashEntry *hPtr;
const char *before, *string;
- Tcl_DString buf, *dsPtr = NULL;
- Tcl_Obj *nameObj;
+ Tcl_DString name, buf, *dsPtr = NULL;
before = ewPtr->body.ew.create;
@@ -869,8 +1417,8 @@ EmbWinLayoutProc(
string = before;
while (*string != 0) {
- if ((*string == '%') && (string[1] == '%' || string[1] == 'W')) {
- if (dsPtr == NULL) {
+ if (string[0] == '%' && (string[1] == '%' || string[1] == 'W')) {
+ if (!dsPtr) {
Tcl_DStringInit(&buf);
dsPtr = &buf;
}
@@ -897,9 +1445,9 @@ EmbWinLayoutProc(
Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
}
before += 2;
- string++;
+ string += 1;
}
- string++;
+ string += 1;
}
/*
@@ -909,8 +1457,8 @@ EmbWinLayoutProc(
* ourselves as the geometry manager for the window.
*/
- if (dsPtr != NULL) {
- Tcl_DStringAppend(dsPtr, before, (int) (string-before));
+ if (dsPtr) {
+ Tcl_DStringAppend(dsPtr, before, string - before);
code = Tcl_EvalEx(textPtr->interp, Tcl_DStringValue(dsPtr), -1, TCL_EVAL_GLOBAL);
Tcl_DStringFree(dsPtr);
} else {
@@ -920,13 +1468,12 @@ EmbWinLayoutProc(
Tcl_BackgroundException(textPtr->interp, code);
goto gotWindow;
}
- nameObj = Tcl_GetObjResult(textPtr->interp);
- Tcl_IncrRefCount(nameObj);
+ Tcl_DStringInit(&name);
+ Tcl_DStringAppend(&name, Tcl_GetStringResult(textPtr->interp), -1);
Tcl_ResetResult(textPtr->interp);
- ewPtr->body.ew.tkwin = Tk_NameToWindow(textPtr->interp,
- Tcl_GetString(nameObj), textPtr->tkwin);
- Tcl_DecrRefCount(nameObj);
- if (ewPtr->body.ew.tkwin == NULL) {
+ ewPtr->body.ew.tkwin = Tk_NameToWindow(textPtr->interp, Tcl_DStringValue(&name), textPtr->tkwin);
+ Tcl_DStringFree(&name);
+ if (!ewPtr->body.ew.tkwin) {
Tcl_BackgroundException(textPtr->interp, TCL_ERROR);
goto gotWindow;
}
@@ -936,43 +1483,37 @@ EmbWinLayoutProc(
break;
}
if (Tk_TopWinHierarchy(ancestor)) {
- goto badMaster;
+ cantEmbed = true;
+ break;
}
}
- if (Tk_TopWinHierarchy(ewPtr->body.ew.tkwin)
- || (textPtr->tkwin == ewPtr->body.ew.tkwin)) {
- badMaster:
- Tcl_SetObjResult(textPtr->interp, Tcl_ObjPrintf(
- "can't embed %s relative to %s",
- Tk_PathName(ewPtr->body.ew.tkwin),
- Tk_PathName(textPtr->tkwin)));
- Tcl_SetErrorCode(textPtr->interp, "TK", "GEOMETRY", "HIERARCHY",
- NULL);
+ if (cantEmbed
+ || Tk_TopWinHierarchy(ewPtr->body.ew.tkwin)
+ || textPtr->tkwin == ewPtr->body.ew.tkwin) {
+ Tcl_SetObjResult(textPtr->interp, Tcl_ObjPrintf("can't embed %s relative to %s",
+ Tk_PathName(ewPtr->body.ew.tkwin), Tk_PathName(textPtr->tkwin)));
+ Tcl_SetErrorCode(textPtr->interp, "TK", "GEOMETRY", "HIERARCHY", NULL);
Tcl_BackgroundException(textPtr->interp, TCL_ERROR);
ewPtr->body.ew.tkwin = NULL;
goto gotWindow;
}
- if (client == NULL) {
+ if (!client) {
/*
* We just used a '-create' script to make a new window, which we
* now need to add to our client list.
*/
- client = ckalloc(sizeof(TkTextEmbWindowClient));
+ client = calloc(1, sizeof(TkTextEmbWindowClient));
client->next = ewPtr->body.ew.clients;
client->textPtr = textPtr;
- client->tkwin = NULL;
- client->chunkCount = 0;
- client->displayed = 0;
client->parent = ewPtr;
ewPtr->body.ew.clients = client;
}
client->tkwin = ewPtr->body.ew.tkwin;
Tk_ManageGeometry(client->tkwin, &textGeomType, client);
- Tk_CreateEventHandler(client->tkwin, StructureNotifyMask,
- EmbWinStructureProc, client);
+ Tk_CreateEventHandler(client->tkwin, StructureNotifyMask, EmbWinStructureProc, client);
/*
* Special trick! Must enter into the hash table *after* calling
@@ -981,9 +1522,10 @@ EmbWinLayoutProc(
* removed, which could potentially lose the new entry.
*/
- hPtr = Tcl_CreateHashEntry(&textPtr->sharedTextPtr->windowTable,
- Tk_PathName(client->tkwin), &isNew);
- Tcl_SetHashValue(hPtr, ewPtr);
+ client->hPtr = Tcl_CreateHashEntry(
+ &textPtr->sharedTextPtr->windowTable, Tk_PathName(client->tkwin), &isNew);
+ Tcl_SetHashValue(client->hPtr, ewPtr);
+ ewPtr->body.ew.sharedTextPtr->numWindows += 1;
}
/*
@@ -991,43 +1533,51 @@ EmbWinLayoutProc(
*/
gotWindow:
- if (ewPtr->body.ew.tkwin == NULL) {
+ if (!ewPtr->body.ew.tkwin) {
width = 0;
height = 0;
} else {
width = Tk_ReqWidth(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padX;
height = Tk_ReqHeight(ewPtr->body.ew.tkwin) + 2*ewPtr->body.ew.padY;
}
- if ((width > (maxX - chunkPtr->x))
- && !noCharsYet && (textPtr->wrapMode != TEXT_WRAPMODE_NONE)) {
+
+ x = chunkPtr ? chunkPtr->x : 0;
+
+ if (width > maxX - x && !noCharsYet && textPtr->wrapMode != TEXT_WRAPMODE_NONE) {
return 0;
}
- /*
- * Fill in the chunk structure.
- */
+ if (chunkPtr) {
+ /*
+ * Fill in the chunk structure.
+ */
- chunkPtr->displayProc = TkTextEmbWinDisplayProc;
- chunkPtr->undisplayProc = EmbWinUndisplayProc;
- chunkPtr->measureProc = NULL;
- chunkPtr->bboxProc = EmbWinBboxProc;
- chunkPtr->numBytes = 1;
- if (ewPtr->body.ew.align == ALIGN_BASELINE) {
- chunkPtr->minAscent = height - ewPtr->body.ew.padY;
- chunkPtr->minDescent = ewPtr->body.ew.padY;
- chunkPtr->minHeight = 0;
- } else {
- chunkPtr->minAscent = 0;
- chunkPtr->minDescent = 0;
- chunkPtr->minHeight = height;
+ chunkPtr->layoutProcs = &layoutWindowProcs;
+ chunkPtr->numBytes = 1;
+ if (ewPtr->body.ew.align == ALIGN_BASELINE) {
+ chunkPtr->minAscent = height - ewPtr->body.ew.padY;
+ chunkPtr->minDescent = ewPtr->body.ew.padY;
+ chunkPtr->minHeight = 0;
+ } else {
+ chunkPtr->minAscent = 0;
+ chunkPtr->minDescent = 0;
+ chunkPtr->minHeight = height;
+ }
+ chunkPtr->width = width;
+ chunkPtr->breakIndex = (wrapMode == TEXT_WRAPMODE_NONE) ? -1 : 1;
+ chunkPtr->clientData = ewPtr;
}
- chunkPtr->width = width;
- chunkPtr->breakIndex = -1;
- chunkPtr->breakIndex = 1;
- chunkPtr->clientData = ewPtr;
- if (client != NULL) {
+
+ if (client) {
client->chunkCount += 1;
+
+ if (!chunkPtr) {
+ TkTextDispChunk chunk;
+ chunk.clientData = ewPtr;
+ EmbWinUndisplayProc(textPtr, &chunk);
+ }
}
+
return 1;
}
@@ -1051,10 +1601,10 @@ EmbWinLayoutProc(
static void
EmbWinCheckProc(
- TkTextSegment *ewPtr, /* Segment to check. */
- TkTextLine *linePtr) /* Line containing segment. */
+ const TkSharedText *sharedTextPtr, /* Handle to shared text resource. */
+ const TkTextSegment *ewPtr) /* Segment to check. */
{
- if (ewPtr->nextPtr == NULL) {
+ if (!ewPtr->nextPtr) {
Tcl_Panic("EmbWinCheckProc: embedded window is last segment in line");
}
if (ewPtr->size != 1) {
@@ -1065,7 +1615,7 @@ EmbWinCheckProc(
/*
*--------------------------------------------------------------
*
- * TkTextEmbWinDisplayProc --
+ * EmbWinDisplayProc --
*
* This function is invoked by the text displaying code when it is time
* to actually draw an embedded window chunk on the screen.
@@ -1080,8 +1630,8 @@ EmbWinCheckProc(
*--------------------------------------------------------------
*/
-void
-TkTextEmbWinDisplayProc(
+static void
+EmbWinDisplayProc(
TkText *textPtr, /* Information about text widget. */
TkTextDispChunk *chunkPtr, /* Chunk that is to be drawn. */
int x, /* X-position in dst at which to draw this
@@ -1093,35 +1643,25 @@ TkTextEmbWinDisplayProc(
int lineHeight, /* Total height of line. */
int baseline, /* Offset of baseline from y. */
Display *display, /* Display to use for drawing (unused). */
- Drawable dst, /* Pixmap or window in which to draw
- * (unused). */
- int screenY) /* Y-coordinate in text window that
- * corresponds to y. */
+ Drawable dst, /* Pixmap or window in which to draw (unused). */
+ int screenY) /* Y-coordinate in text window that corresponds to y. */
{
int lineX, windowX, windowY, width, height;
Tk_Window tkwin;
TkTextSegment *ewPtr = chunkPtr->clientData;
TkTextEmbWindowClient *client = EmbWinGetClient(textPtr, ewPtr);
- if (client == NULL) {
+ if (!client || !(tkwin = client->tkwin)) {
return;
}
- tkwin = client->tkwin;
- if (tkwin == NULL) {
- return;
- }
-
- if ((x + chunkPtr->width) <= 0) {
+ if (x + chunkPtr->width <= 0) {
/*
* The window is off-screen; just unmap it.
*/
- if (textPtr->tkwin != Tk_Parent(tkwin)) {
- Tk_UnmaintainGeometry(tkwin, textPtr->tkwin);
- } else {
- Tk_UnmapWindow(tkwin);
- }
+ client->displayed = false;
+ EmbWinDelayedUnmap(client);
return;
}
@@ -1142,19 +1682,34 @@ TkTextEmbWinDisplayProc(
* 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))
- || (height != Tk_Height(tkwin))) {
+ if (windowX != Tk_X(tkwin)
+ || windowY != Tk_Y(tkwin)
+ || Tk_ReqWidth(tkwin) != Tk_Width(tkwin)
+ || height != Tk_Height(tkwin)) {
Tk_MoveResizeWindow(tkwin, windowX, windowY, width, height);
+
+ if (textPtr->watchCmd && Tk_IsMapped(tkwin)) {
+ char w[100], h[100];
+
+ snprintf(h, sizeof(h), "%d", Tk_Height(tkwin));
+ snprintf(w, sizeof(w), "%d", Tk_Width(tkwin));
+
+ TriggerWatchCmd(textPtr, ewPtr, tkwin, w, h);
+ }
+ }
+ if (!Tk_IsMapped(tkwin)) {
+ Tk_MapWindow(tkwin);
+
+ if (textPtr->watchCmd) {
+ TriggerWatchCmd(textPtr, ewPtr, tkwin, NULL, NULL);
+ }
}
- Tk_MapWindow(tkwin);
} else {
- Tk_MaintainGeometry(tkwin, textPtr->tkwin, windowX, windowY,
- width, height);
+ Tk_MaintainGeometry(tkwin, textPtr->tkwin, windowX, windowY, width, height);
}
+
+ client->displayed = true;
}
/*
@@ -1183,12 +1738,7 @@ EmbWinUndisplayProc(
TkTextSegment *ewPtr = chunkPtr->clientData;
TkTextEmbWindowClient *client = EmbWinGetClient(textPtr, ewPtr);
- if (client == NULL) {
- return;
- }
-
- client->chunkCount--;
- if (client->chunkCount == 0) {
+ if (client && --client->chunkCount == 0) {
/*
* Don't unmap the window immediately, since there's a good chance
* that it will immediately be redisplayed, perhaps even in the same
@@ -1197,7 +1747,7 @@ EmbWinUndisplayProc(
* the unmap becomes unnecessary.
*/
- client->displayed = 0;
+ client->displayed = false;
Tcl_DoWhenIdle(EmbWinDelayedUnmap, client);
}
}
@@ -1228,30 +1778,20 @@ static void
EmbWinBboxProc(
TkText *textPtr, /* Information about text widget. */
TkTextDispChunk *chunkPtr, /* Chunk containing desired char. */
- int index, /* Index of desired character within the
- * chunk. */
- int y, /* Topmost pixel in area allocated for this
- * line. */
+ int index, /* Index of desired character within the chunk. */
+ int y, /* Topmost pixel in area allocated for this line. */
int lineHeight, /* Total height of line. */
- int baseline, /* Location of line's baseline, in pixels
- * measured down from y. */
- int *xPtr, int *yPtr, /* Gets filled in with coords of character's
- * upper-left pixel. */
- int *widthPtr, /* Gets filled in with width of window, in
- * pixels. */
- int *heightPtr) /* Gets filled in with height of window, in
- * pixels. */
+ int baseline, /* Location of line's baseline, in pixels measured down from y. */
+ int *xPtr, int *yPtr, /* Gets filled in with coords of character's upper-left pixel. */
+ int *widthPtr, /* Gets filled in with width of window, in pixels. */
+ int *heightPtr) /* Gets filled in with height of window, in pixels. */
{
Tk_Window tkwin;
TkTextSegment *ewPtr = chunkPtr->clientData;
TkTextEmbWindowClient *client = EmbWinGetClient(textPtr, ewPtr);
- if (client == NULL) {
- tkwin = NULL;
- } else {
- tkwin = client->tkwin;
- }
- if (tkwin != NULL) {
+ tkwin = client ? client->tkwin : NULL;
+ if (tkwin) {
*widthPtr = Tk_ReqWidth(tkwin);
*heightPtr = Tk_ReqHeight(tkwin);
} else {
@@ -1307,12 +1847,18 @@ EmbWinDelayedUnmap(
{
TkTextEmbWindowClient *client = clientData;
- if (!client->displayed && (client->tkwin != NULL)) {
+ if (!client->displayed && client->tkwin) {
if (client->textPtr->tkwin != Tk_Parent(client->tkwin)) {
Tk_UnmaintainGeometry(client->tkwin, client->textPtr->tkwin);
} else {
Tk_UnmapWindow(client->tkwin);
}
+
+ assert(client->textPtr);
+
+ if (client->textPtr->watchCmd) {
+ TriggerWatchCmd(client->textPtr, client->parent, client->tkwin, NULL, NULL);
+ }
}
}
@@ -1325,8 +1871,8 @@ EmbWinDelayedUnmap(
* index corresponding to the window's position in the text.
*
* Results:
- * The return value is 1 if there is an embedded window by the given name
- * in the text widget, 0 otherwise. If the window exists, *indexPtr is
+ * The return value is true if there is an embedded window by the given name
+ * in the text widget, false otherwise. If the window exists, *indexPtr is
* filled in with its index.
*
* Side effects:
@@ -1335,7 +1881,7 @@ EmbWinDelayedUnmap(
*--------------------------------------------------------------
*/
-int
+bool
TkTextWindowIndex(
TkText *textPtr, /* Text widget containing window. */
const char *name, /* Name of window. */
@@ -1344,20 +1890,16 @@ TkTextWindowIndex(
Tcl_HashEntry *hPtr;
TkTextSegment *ewPtr;
- if (textPtr == NULL) {
- return 0;
- }
+ assert(textPtr);
- hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->windowTable, name);
- if (hPtr == NULL) {
- return 0;
+ if (!(hPtr = Tcl_FindHashEntry(&textPtr->sharedTextPtr->windowTable, name))) {
+ return false;
}
ewPtr = Tcl_GetHashValue(hPtr);
- indexPtr->tree = textPtr->sharedTextPtr->tree;
- indexPtr->linePtr = ewPtr->body.ew.linePtr;
- indexPtr->byteIndex = TkTextSegToOffset(ewPtr, indexPtr->linePtr);
- return 1;
+ TkTextIndexClear(indexPtr, textPtr);
+ TkTextIndexSetSegment(indexPtr, ewPtr);
+ return true;
}
/*
@@ -1391,7 +1933,7 @@ EmbWinGetClient(
{
TkTextEmbWindowClient *client = ewPtr->body.ew.clients;
- while (client != NULL) {
+ while (client) {
if (client->textPtr == textPtr) {
return client;
}
@@ -1404,6 +1946,7 @@ EmbWinGetClient(
* Local Variables:
* mode: c
* c-basic-offset: 4
- * fill-column: 78
+ * fill-column: 105
* End:
+ * vi:set ts=8 sw=4:
*/