#!/bin/sh # This is `snmp2.27' (part 27 of snmp2). # Do not concatenate these parts, unpack them in order with `/bin/sh'. # File `snmp2/snmptcl/htext2.c' is being continued... # touch -am 1231235999 $$.touch >/dev/null 2>&1 if test ! -f 1231235999 && test -f $$.touch; then shar_touch=touch else shar_touch=: echo echo 'WARNING: not restoring timestamps. Consider getting and' echo "installing GNU \`touch', distributed in GNU File Utilities..." echo fi rm -f 1231235999 $$.touch # if test ! -r _sharseq.tmp; then echo 'Please unpack part 1 first!' exit 1 fi shar_sequence=`cat _sharseq.tmp` if test "$shar_sequence" != 27; then echo "Please unpack part $shar_sequence next!" exit 1 fi if test ! -f _sharnew.tmp; then echo 'x - still skipping snmp2/snmptcl/htext2.c' else echo 'x - continuing file snmp2/snmptcl/htext2.c' sed 's/^X//' << 'SHAR_EOF' >> 'snmp2/snmptcl/htext2.c' && X " should be append, configure, childconfigure, ", X "gotoline, map, unmap, xview, or yview", NULL); X goto error; X } X Tk_Release ((ClientData) textPtr); X return result; X X redisplay: X EventuallyRedraw (textPtr); X Tk_Release ((ClientData) textPtr); X return TCL_OK; X X error: X Tk_Release ((ClientData) textPtr); X return TCL_ERROR; } X /* X * ---------------------------------------------------------------------- X * X * CreateText -- X * X * This procedure creates and initializes a new hypertext widget. X * X * Results: X * The return value is a pointer to a structure describing the new X * widget. If an error occurred, then the return value is NULL and X * an error message is left in interp->result. X * X * Side effects: X * Memory is allocated, a Tk_Window is created, etc. X * X * ---------------------------------------------------------------------- X */ X static Hypertext * CreateText (interp, tkwin, pathName) X Tcl_Interp *interp; /* Used for error reporting. */ X Tk_Window tkwin; /* Window to use for resolving pathName. */ X char *pathName; /* Name for new window. */ { X register Hypertext *textPtr; X Tk_Window new; X X /* X * Create the new window. X */ X new = Tk_CreateWindowFromPath (interp, tkwin, pathName, (char *)NULL); X if (new == NULL) { X return (NULL); X } X Tk_SetClass (new, "Hypertext"); X X /* X * Initialize the data structure for the Hypertext. X */ X textPtr = (Hypertext *) calloc (1, sizeof (Hypertext)); X if (textPtr == NULL) { X return (NULL); X } X textPtr->tkwin = new; X textPtr->interp = interp; X textPtr->numLines = textPtr->arraySize = 0; X X Tk_CreateEventHandler (new, ExposureMask | StructureNotifyMask, X TextEventProc, (ClientData) textPtr); X Tcl_CreateCommand (interp, pathName, TextWidgetCmd, (ClientData) textPtr, X (Tcl_CmdDeleteProc *) NULL); X return textPtr; } X /* X * ---------------------------------------------------------------------- X * X * DestroyText -- X * X * This procedure is invoked by Tk_EventuallyFree or Tk_Release X * to clean up the internal structure of a Hypertext at a safe time X * (when no-one is using it anymore). X * X * Results: X * None. X * X * Side effects: X * Everything associated with the widget is freed up. X * X * ---------------------------------------------------------------------- X */ static void DestroyText (clientData) X ClientData clientData; /* Info about hypertext widget. */ { X register Hypertext *textPtr = (Hypertext *) clientData; X X /* Free allocated memory for the following: */ X if (textPtr->gc != None) /* Graphics context */ X Tk_FreeGC (textPtr->gc); X if (textPtr->border) /* 3D Border */ X Tk_Free3DBorder (textPtr->border); X if (textPtr->normalFg) /* Foreground color */ X Tk_FreeColor (textPtr->normalFg); X if (textPtr->geometry) /* Geometry */ X ckfree (textPtr->geometry); X if (textPtr->yScrollCmd) /* Y scroll command */ X ckfree (textPtr->yScrollCmd); X if (textPtr->xScrollCmd) /* X scroll command */ X ckfree (textPtr->xScrollCmd); X if (textPtr->fontPtr) /* Font */ X Tk_FreeFontStruct (textPtr->fontPtr); X if (textPtr->fileName) /* Filename */ X ckfree (textPtr->fileName); X if (textPtr->text != NULL) /* Text string */ X ckfree (textPtr->text); X if (textPtr->cursor != None) /* Cursor */ X Tk_FreeCursor (textPtr->cursor); X FreeLines (textPtr); X ckfree ((char *)textPtr);/* */ } X /* X * ---------------------------------------------------------------------- X * X * ConfigureText -- X * X * This procedure is called to process an argv/argc list, plus X * the Tk option database, in order to configure (or reconfigure) X * a hypertext widget. X * X * The layout of the text must be calculated (by ComputeLayout) X * whenever particular options change; -font, -filename, -linespacing X * and -text options. If the user has changes one of these options, X * it must be detected so that the layout can be recomputed. Since the X * coordinates of the layout are virtual, there is no need to adjust X * them if physical window attributes (window size, etc.) X * change. X * X * Results: X * The return value is a standard Tcl result. If TCL_ERROR is X * returned, then interp->result contains an error message. X * X * Side effects: X * Configuration information, such as text string, colors, font, X * etc. get set for textPtr; old resources get freed, if there were any. X * The hypertext is redisplayed. X * X * ---------------------------------------------------------------------- X */ X static int ConfigureText (interp, textPtr, argc, argv, flags) X Tcl_Interp *interp; /* Used for error reporting. */ X Hypertext *textPtr; /* Information about widget; may or may not X * already have values for some fields. */ X int argc; /* Number of valid entries in argv. */ X char **argv; /* Arguments. */ X int flags; /* Flags to pass to Tk_ConfigureWidget. */ { X XGCValues gcValues; X unsigned long valueMask; X GC newGC; X Tk_Window tkwin = textPtr->tkwin; X X if (Tk_ConfigureWidget (interp, tkwin, configSpecs, argc, argv, X (char *)textPtr, flags) != TCL_OK) { X return TCL_ERROR; X } X Tk_SetBackgroundFromBorder (tkwin, textPtr->border); X if (OptionChanged (Tk_Offset (Hypertext, fontPtr), configSpecs) || X OptionChanged (Tk_Offset (Hypertext, lineSpacing), configSpecs)) { X textPtr->flags |= LAYOUT_NEEDED; X } X gcValues.font = textPtr->fontPtr->fid; X gcValues.foreground = textPtr->normalFg->pixel; X X valueMask = GCForeground | GCFont; X newGC = Tk_GetGC (tkwin, valueMask, &gcValues); X if (textPtr->gc != None) X Tk_FreeGC (textPtr->gc); X textPtr->gc = newGC; X X /* Kill the -file option, if the -text option exists */ X if (textPtr->text != NULL) { X if (textPtr->fileName != NULL) X ckfree (textPtr->fileName); X textPtr->fileName = NULL; X } else if (OptionChanged (Tk_Offset (Hypertext, fileName), configSpecs)) { X if (ReadFile (interp, textPtr) != TCL_OK) X return (TCL_ERROR); X } X /* If new text is available, read it into the widget */ X if (textPtr->text != NULL) { X if (ParseText (interp, textPtr) != TCL_OK) X return (TCL_ERROR); X textPtr->flags |= LAYOUT_NEEDED; /* Mark for layout update */ X } X if (textPtr->geometry != NULL) { X int height, width; X X if (sscanf (textPtr->geometry, "%dx%d", &width, &height) != 2) { X Tcl_AppendResult (interp, "bad geometry \"", textPtr->geometry, X "\": expected widthxheight", (char *)NULL); X return (TCL_ERROR); X } X Tk_GeometryRequest (tkwin, width, height); X } X /* Lastly, arrange for the hypertext to be redisplayed. */ X EventuallyRedraw (textPtr); X return TCL_OK; } X /* X * -------------------------------------------------------------- X * X * TextEventProc -- X * X * This procedure is invoked by the Tk dispatcher for various X * events on hypertext widgets. X * X * Results: X * None. X * X * Side effects: X * When the window gets deleted, internal structures get X * cleaned up. When it gets exposed, it is redisplayed. X * X * -------------------------------------------------------------- X */ X static void TextEventProc (clientData, eventPtr) X ClientData clientData; /* Information about window. */ X XEvent *eventPtr; /* Information about event. */ { X Hypertext *textPtr = (Hypertext *) clientData; X X switch (eventPtr->type) { X X case ConfigureNotify: X textPtr->flags |= VIEWPORT_RESIZED; X EventuallyRedraw (textPtr); X break; X X case Expose: X if (eventPtr->xexpose.send_event) { X textPtr->flags ^= IGNORE_EXPOSURES; X return; X } X if ((eventPtr->xexpose.count == 0) && X !(textPtr->flags & IGNORE_EXPOSURES)) { X EventuallyRedraw (textPtr); X } X break; X X case DestroyNotify: X Tcl_DeleteCommand (textPtr->interp, Tk_PathName (textPtr->tkwin)); X textPtr->tkwin = NULL; X if (textPtr->flags & REDRAW_PENDING) X Tk_CancelIdleCall (DisplayText, (ClientData) textPtr); X Tk_EventuallyFree ((ClientData) textPtr, DestroyText); X break; X X } } X /* X *---------------------------------------------------------------------- X * X * EventuallyRedraw -- X * X * Ensure that an entry is eventually redrawn on the display. X * X * Results: X * None. X * X * Side effects: X * Information gets redisplayed. Right now we don't do selective X * redisplays: the whole window will be redrawn. This doesn't X * seem to hurt performance noticeably, but if it does then this X * could be changed. X * X *---------------------------------------------------------------------- X */ X static void EventuallyRedraw (textPtr) X register Hypertext *textPtr; /* Information about widget. */ { X if ((textPtr->tkwin != NULL) && (Tk_IsMapped (textPtr->tkwin)) && X !(textPtr->flags & REDRAW_PENDING)) { X textPtr->flags |= REDRAW_PENDING; X Tk_DoWhenIdle (DisplayText, (ClientData) textPtr); X } } X /* X *---------------------------------------------------------------------- X * X * TextScanTo -- X * X * Given a XY coordinates (presumably of the curent mouse location) X * drag the view in the window to implement the scan operation. X * X * Results: X * None. X * X * Side effects: X * The view in the window may change and the window redrawn. X * X *---------------------------------------------------------------------- X */ X static void TextScanTo (textPtr, x, y) X register Hypertext *textPtr; /* Information about widget. */ X int x, y; /* Coordinate to use for scan operation. */ { X int newX, newY; X X /* Amplify X distance from point to mark by step of horizontal units */ X newX = textPtr->scanPtX - (x - textPtr->scanMarkX) * textPtr->xScrollUnits; X /* Amplify Y distance from point to mark by 10x vertical units */ X newY = (textPtr->scanPtY - (10 * (y - textPtr->scanMarkY)) * X textPtr->yScrollUnits); X if (newX < 0) { X newX = textPtr->scanPtX = 0; X textPtr->scanMarkX = x; X } else if (newX >= textPtr->width) { X newX = textPtr->scanPtX = textPtr->width - textPtr->xScrollUnits; X textPtr->scanMarkX = x; X } X if (newY < 0) { X newY = textPtr->scanPtY = 0; X textPtr->scanMarkY = y; X } else if (newY >= textPtr->height) { X newY = textPtr->scanPtY = textPtr->height - textPtr->yScrollUnits; X textPtr->scanMarkY = y; X } X if (newY != textPtr->newY || newX != textPtr->newX) { X textPtr->newX = newX, textPtr->newY = newY; X textPtr->flags |= VIEWPORT_MOVED; X EventuallyRedraw (textPtr); X } } X /* X * ---------------------------------------------------------------------- X * X * GetLine -- X * X * This procedure creates and initializes a new line of text. X * X * Results: X * The return value is a pointer to a structure describing the new X * line of text. If an error occurred, then the return value is NULL X * and an error message is left in interp->result. X * X * Side effects: X * Memory is allocated. X * X * ---------------------------------------------------------------------- X */ static Line * GetLine (textPtr) X Hypertext *textPtr; { X Line *linePtr; X X if (textPtr->numLines >= textPtr->arraySize) { X Line **newPtr; X X /* reallocate the array of lines */ X if (textPtr->arraySize == 0) { X textPtr->arraySize = LINES_ALLOC_CHUNK; X } else { X /* Double the size of the array */ X textPtr->arraySize += textPtr->arraySize; X } X newPtr = (Line **) reallocate ((char *)textPtr->lineArr, X textPtr->arraySize * sizeof (Line *), X textPtr->numLines * sizeof (Line *)); X textPtr->lineArr = newPtr; X } X /* Create new line entry and add to table */ X linePtr = (Line *) calloc (1, sizeof (Line)); X if (linePtr == NULL) { X Tcl_AppendResult (textPtr->interp, "calloc: ", sys_errlist[errno], X ": Can't allocate new line ", NULL); X return (NULL); X } X textPtr->lineArr[textPtr->numLines++] = linePtr; X return (linePtr); } X /* X * ---------------------------------------------------------------------- X * X * DestroyLine -- X * X * This procedure is invoked by FreeLines to clean up the X * internal structure of a line. X * X * Results: None. X * X * Side effects: X * Everything associated with the line (text and children) is X * freed up. X * X * ---------------------------------------------------------------------- X */ X static void DestroyLine (linePtr) X register Line *linePtr; { X register Child *childPtr = linePtr->children; X register Child *oldPtr; X X /* Free the list of child structures */ X while (childPtr != NULL) { X oldPtr = childPtr; X childPtr = childPtr->nextPtr; X DestroyChild (oldPtr); X } X /* Deallocate the text array */ X if (linePtr->text != NULL) X ckfree (linePtr->text); X ckfree ((char *)linePtr); } X /* X * ---------------------------------------------------------------------- X * X * AppendChild -- X * X * This procedure creates and initializes a new hyper text child. X * X * Results: X * The return value is a standard Tcl result. X * X * Side effects: X * Memory is allocated. Child gets configured. X * X * ---------------------------------------------------------------------- X */ X static int AppendChild (textPtr, childName, argc, argv) X register Hypertext *textPtr; X char *childName; X int argc; /* Number of arguments. */ X char **argv; /* Argument strings. */ { X Line *linePtr; X Child *childPtr; X X childPtr = CreateChild (textPtr->interp, textPtr, childName); X if (childPtr == NULL) X return TCL_ERROR; X if (ConfigureChild (textPtr, childPtr, argc, argv, 0) != TCL_OK) X return (TCL_ERROR); X X /* Append child to list of subwindows of the last line */ X /* Check that there is a line to append the window */ X if (textPtr->numLines == 0) X GetLine (textPtr); X linePtr = textPtr->lineArr[textPtr->numLines - 1]; X if (linePtr->children == NULL) { X linePtr->lastChild = linePtr->children = childPtr; X } else { X linePtr->lastChild->nextPtr = childPtr; X linePtr->lastChild = childPtr; X } X linePtr->width += childPtr->width; X childPtr->precedingTextEnd = linePtr->textLength; X textPtr->flags |= LAYOUT_NEEDED; X X return (TCL_OK); } X /* X * ---------------------------------------------------------------------- X * X * CreateChild -- X * X * This procedure creates and initializes a new child subwindow X * in the hyper text widget. X * X * Results: X * The return value is a pointer to a structure describing the X * new child. If an error occurred, then the return value is X * NULL and an error message is left in interp->result. X * X * Side effects: X * Memory is allocated. Child window is mapped. Callbacks are set X * up for subwindow resizes and geometry requests. X * X * ---------------------------------------------------------------------- X */ X static Child * CreateChild (interp, textPtr, childName) X Tcl_Interp *interp; /* Used for error reporting. */ X Hypertext *textPtr; /* Hypertext widget */ X char *childName; /* Name of child window */ { X register Child *childPtr; X Tk_Window tkwin; X char buf[BUFSIZ]; X X if (*childName != '.') { /* Relative path, make absolute */ X sprintf (buf, "%s.%s", Tk_PathName (textPtr->tkwin), childName); X childName = buf; X } X /* Get the Tk window and parent Tk window associated with the child */ X tkwin = Tk_NameToWindow (interp, childName, textPtr->tkwin); X if (tkwin == NULL) { X Tcl_AppendResult (interp, "Can't find a window \"", childName, NULL); X return (NULL); X } X if (FindChild (interp, textPtr, childName) != NULL) { X Tcl_AppendResult (interp, "\"", childName, X "\" is already appended to ", X Tk_PathName (textPtr->tkwin)); X return (NULL); X } X if (textPtr->tkwin != Tk_Parent (tkwin)) { X Tcl_AppendResult (interp, "\"", childName, "\" is not a child of `%s'", X Tk_PathName (textPtr->tkwin)); X return (NULL); X } X childPtr = (Child *) calloc (1, sizeof (Child)); X if (childPtr == NULL) { X Tcl_AppendResult (interp, "calloc: ", sys_errlist[errno], X ": Can't create child structure", NULL); X return (NULL); X } X childPtr->tkwin = tkwin; X childPtr->parent = textPtr; X X /* Map the window so that we can query its width and height */ X Tk_MapWindow (tkwin); X childPtr->width = Tk_ReqWidth (tkwin); X childPtr->height = Tk_ReqHeight (tkwin); X X /* Set up callbacks for geometry requests and window structure changes */ X Tk_ManageGeometry (tkwin, ChildGeometryProc, (ClientData) childPtr); X Tk_CreateEventHandler (tkwin, StructureNotifyMask, ChildStructureProc, X (ClientData) childPtr); X return (childPtr); } X /* X * ---------------------------------------------------------------------- X * X * DestroyChild -- X * X * This procedure is invoked by DestroyLine to clean up the X * internal structure of a child. X * X * Results: X * None. X * X * Side effects: X * Everything associated with the widget is freed up. X * X * ---------------------------------------------------------------------- X */ X static void DestroyChild (childPtr) X register Child *childPtr; { X /* Destroy the child window if it still exists */ X if (childPtr->tkwin != NULL) X Tk_DestroyWindow (childPtr->tkwin); X free ((char *)childPtr); } X /* X * ---------------------------------------------------------------------- X * X * ConfigureChild -- X * X * This procedure is called to process an argv/argc list, plus X * the Tk option database, in order to configure (or reconfigure) X * a hypertext child. X * X * Results: X * The return value is a standard Tcl result. If TCL_ERROR is X * returned, then interp->result contains an error message. X * X * Side effects: X * Configuration information, such as text string, colors, font, X * etc. get set for the child; old resources get freed, if there X * were any. The child marked for redisplay. X * X * ---------------------------------------------------------------------- X */ X static int ConfigureChild (textPtr, childPtr, argc, argv, flags) X Hypertext *textPtr; /* Parent hypertext widget. */ X Child *childPtr; /* Information about child; may or may not X * already have values for some fields. */ X int argc; /* Number of valid entries in argv. */ X char **argv; /* Arguments. */ X int flags; { X int oldAnchor; X int oldPadX, oldPadY; X X oldAnchor = childPtr->anchor; X oldPadX = childPtr->padX; X oldPadY = childPtr->padY; X X if (Tk_ConfigureWidget (textPtr->interp, textPtr->tkwin, childConfigSpecs, X argc, argv, (char *)childPtr, flags) != TCL_OK) X return (TCL_ERROR); X /* If non-zero use the user-defined space constraints. */ X childPtr->width = (childPtr->widthWanted > 0) X ? childPtr->widthWanted : Tk_ReqWidth (childPtr->tkwin); X childPtr->height = (childPtr->heightWanted > 0) X ? childPtr->heightWanted : Tk_ReqHeight (childPtr->tkwin); X X /* X * If the requested new width or height of the child is different from X * the current, we need to recompute the layout. X */ X if (childPtr->width != Tk_Width (childPtr->tkwin) || X childPtr->height != Tk_Height (childPtr->tkwin) || X childPtr->padX != oldPadX || childPtr->padY != oldPadY || X childPtr->anchor != oldAnchor) X textPtr->flags |= LAYOUT_NEEDED; X return (TCL_OK); } X /* X * -------------------------------------------------------------- X * X * TextEventProc -- X * X * This procedure is invoked by the Tk dispatcher for various X * events on hypertext widgets. X * X * Results: X * None. X * X * Side effects: X * When the window gets deleted, internal structures get X * cleaned up. When it gets exposed, it is redisplayed. X * X * -------------------------------------------------------------- X */ X static void ChildStructureProc (clientData, eventPtr) X ClientData clientData; /* Information about window. */ X XEvent *eventPtr; /* Information about event. */ { X register Child *childPtr = (Child *) clientData; X X if (childPtr != NULL && childPtr->tkwin != NULL) { X Hypertext *textPtr; X X textPtr = childPtr->parent; X X switch (eventPtr->type) { X case DestroyNotify: X X /* X * Mark the child as deleted by dereferencing the Tk window X * pointer. Zero out the height and width to collapse the area X * used by the child. Redraw the screen only if the child is X * currently visible and mapped. X */ X childPtr->tkwin = NULL; X childPtr->width = childPtr->height = 0; X childPtr->parent->flags |= LAYOUT_NEEDED; X if ((childPtr->flags & (VISIBLE | MAPPED)) == (VISIBLE | MAPPED)) { X EventuallyRedraw (textPtr); X } X break; X X case ConfigureNotify: X X /* X * Children can't request new XY positions by themselves, so X * worry only about resizing. X */ X if (childPtr->width != Tk_Width (childPtr->tkwin) || X childPtr->height != Tk_Height (childPtr->tkwin)) { X EventuallyRedraw (textPtr); X textPtr->flags |= LAYOUT_NEEDED; X } X break; X } X } } X /* X *---------------------------------------------------------------------- X * X * ComputeLayout -- X * X * This procedure computes the total width and height needed X * to contain the text and children from all the lines of text. X * It merely sums the heights and finds the maximum width of X * all the lines. The width and height are needed for scrolling. X * X * Results: X * None. X * X *---------------------------------------------------------------------- X */ X static void ComputeLayout (textPtr, layoutWidth, layoutHeight) X Hypertext *textPtr; X int *layoutWidth; X int *layoutHeight; X { X register int cnt; X register Line *linePtr; X register int height, width; X X width = height = 0; X for (cnt = 0; cnt < textPtr->numLines; cnt++) { X linePtr = textPtr->lineArr[cnt]; X linePtr->offset = height; X GetLineExtents (textPtr, linePtr); X height += linePtr->height; X if (linePtr->width > width) X width = linePtr->width; X } X /* Save new height and width */ X *layoutHeight = height; X *layoutWidth = width; X X textPtr->flags &= ~LAYOUT_NEEDED; X /* Indicate if new layout changed size of world */ X if (height != textPtr->height || width != textPtr->width) X textPtr->flags |= LAYOUT_CHANGED; } X /* X *---------------------------------------------------------------------- X * X * GetLineExtents -- X * X * This procedure computes the total width and height needed X * to contain the text and children for a particular line. X * It also calculates the baseline of the text on the line with X * respect to the other children on the line. X * X * Results: X * None. X * X *---------------------------------------------------------------------- X */ X static void GetLineExtents (textPtr, linePtr) X Hypertext *textPtr; X Line *linePtr; { X register Child *childPtr; X register int width; X register int baseline; X int textLength; X int maxAscent, maxDescent, maxHeight; X int ascent, descent, height; X register int curPos = 0; X int median; /* Difference of font ascent/descent values */ X X /* X * Pass 1: Determine the maximum ascent (baseline) and descent needed for X * the line. We'll need this for figuring the top/bottom/center anchors. X */ X X /* Initialize line defaults */ X maxAscent = textPtr->fontPtr->ascent; X maxDescent = textPtr->fontPtr->descent; X baseline = textPtr->fontPtr->ascent; X median = textPtr->fontPtr->ascent - textPtr->fontPtr->descent; X X for (childPtr = linePtr->children; X childPtr != NULL; childPtr = childPtr->nextPtr) { X X height = childPtr->height + 2 * childPtr->padY; X switch (childPtr->anchor) { X case TK_ANCHOR_N: X case TK_ANCHOR_NE: X case TK_ANCHOR_NW: X ascent = textPtr->fontPtr->ascent + childPtr->padY; X descent = height - textPtr->fontPtr->ascent; X break; X case TK_ANCHOR_E: X case TK_ANCHOR_W: X case TK_ANCHOR_CENTER: X ascent = (height + median) / 2; X descent = (height - median) / 2; X break; X case TK_ANCHOR_S: X case TK_ANCHOR_SE: X case TK_ANCHOR_SW: X ascent = height - textPtr->fontPtr->descent; X descent = textPtr->fontPtr->descent; X break; X } X if (descent > maxDescent) X maxDescent = descent; X if (ascent > maxAscent) X maxAscent = ascent; X } X X baseline = maxAscent + linePtr->offset; X maxHeight = maxAscent + maxDescent + textPtr->lineSpacing; X width = 0; /* Always starts from x=0 */ X X /* X * Pass 2: Find the placements of the text and children along each line. X */ X for (childPtr = linePtr->children; childPtr != NULL; X childPtr = childPtr->nextPtr) { X X /* Get the width of the text leading to the child */ X textLength = (childPtr->precedingTextEnd - curPos); X if (textLength > 0) { X int newWidth = 0; X X /* Text extents of normal text */ X TkMeasureChars (textPtr->fontPtr, linePtr->text + curPos, X textLength, width, 10000, X TK_PARTIAL_OK | TK_AT_LEAST_ONE, &newWidth); X childPtr->precedingTextWidth = newWidth - width; X width = newWidth; X } X width += childPtr->padX; X X /* Save the world XY coordinates of the child */ X childPtr->x = width; X switch (childPtr->anchor) { X case TK_ANCHOR_N: X case TK_ANCHOR_NE: X case TK_ANCHOR_NW: X childPtr->y = baseline - textPtr->fontPtr->ascent; X break; X case TK_ANCHOR_E: X case TK_ANCHOR_W: X case TK_ANCHOR_CENTER: X childPtr->y = baseline - (childPtr->height + median) / 2; X break; X case TK_ANCHOR_S: X case TK_ANCHOR_SE: X case TK_ANCHOR_SW: X childPtr->y = (baseline - X (childPtr->height - textPtr->fontPtr->descent)); X break; X } X width += childPtr->width + childPtr->padX; X curPos = childPtr->precedingTextEnd; X } X X /* X * This may be piece of line after last child and will also pick up the X * entire line if no children occured on it X */ X textLength = (linePtr->textLength - curPos); X if (textLength > 0) { X int newWidth = 0; X X /* Text extents of normal text */ X TkMeasureChars (textPtr->fontPtr, linePtr->text + curPos, textLength, X width, 10000, TK_PARTIAL_OK | TK_AT_LEAST_ONE, X &newWidth); X width = newWidth; X } X /* Update line parameters */ X linePtr->width = width; X linePtr->height = maxHeight; X linePtr->baseline = maxAscent; } X /* X * ---------------------------------------------------------------------- X * X * DisplayText -- X * X * This procedure is invoked to display a hypertext widget. X * Many of the operations which might ordinarily be performed X * elsewhere (e.g. in a configuration routine) are done here X * because of the somewhat unusual interactions occuring between X * the parent and child windows. X * X * Recompute the layout of the text if necessary. This is X * necessary if the world coordinate system has changed. X * Specifically, the following may have occurred: X * X * - a text attribute has changed (font, linespacing, etc.). X * - child option changed (anchor, width, height). X * - actual child window was resized. X * - new text string or file. X * X * This is defered to the display routine since potentially X * many of these may occur (especially child window changes). X * X * Set the vertical and horizontal scrollbars (if they are X * designated) by issuing a Tcl command. Done here since X * the text window width and height are needed. X * X * If the viewport position or contents have changed in the X * vertical direction, the now out-of-view child windows X * must be moved off the viewport. Since child windows will X * obscure the text window, it is imperative that the children X * are moved off before we try to redraw text in the same area. X * This is necessary only for vertical movements. Horizontal X * child window movements are handled automatically in the X * page drawing routine. X * X * Get the new first and last line numbers for the viewport. X * These line numbers may have changed because either a) X * the viewport changed size or position, or b) the text X * (child window sizes or text attributes) have changed. X * X * If the viewport has changed vertically (i.e. the first or X * last line numbers have changed), move the now out-of-view X * child windows off the viewport. X * X * Potentially many expose events may be generated when the X * the individual child windows are moved and/or resized. X * These events need to be ignored. Since (I think) expose X * events are guarenteed to happen in order, we can bracket X * them by sending phony events (via XSendEvent). The phony X * event turn on and off flags which indicate if the events X * should be ignored. X * X * Finally, the page drawing routine is called. X * X * Results: X * None. X * X * Side effects: X * Commands are output to X to display the hypertext in its X * current mode. X * X * ---------------------------------------------------------------------- X */ X static void DisplayText (clientData) X ClientData clientData; /* Information about widget. */ { X Hypertext *textPtr = (Hypertext *) clientData; X register Tk_Window tkwin; X int oldFirst; /* First line of old viewport */ X int oldLast; /* Last line of old viewport */ X int deltaY; /* Change in viewport in Y direction */ X X textPtr->flags &= ~REDRAW_PENDING; X X tkwin = textPtr->tkwin; X if ((tkwin == NULL) || !Tk_IsMapped (tkwin) || (textPtr->numLines <= 0)) { X return; X } X X /* X * Recalculate the layout. Do this when child positions or sizes have X * changed, or the text attributes (font, linespacing, etc) have changed. X * And when a initially using new file or text string, the child X * positions can't be trusted. X */ X if (textPtr->flags & LAYOUT_NEEDED) { X int width, height; X X ComputeLayout (textPtr, &width, &height); X textPtr->width = width, textPtr->height = height; X } X /* Is there a pending gotoline request? */ X if (textPtr->flags & GOTO_PENDING) { X textPtr->newY = textPtr->lineArr[textPtr->lineRequested]->offset; X textPtr->flags &= ~GOTO_PENDING; X } X deltaY = textPtr->newY - textPtr->y; X oldFirst = textPtr->first, oldLast = textPtr->last; X X /* X * If the viewport has changed size or position, or the text and/or child X * subwindows have changed, adjust the scrollbars to new positions. X */ X if (textPtr->flags & (VIEWPORT_MOVED | VIEWPORT_RESIZED | LAYOUT_CHANGED)) { X /* Reset viewport origin and world extents */ X textPtr->x = textPtr->newX, textPtr->y = textPtr->newY; X /* Horizontal scrollbar */ X if (!NULLSTR (textPtr->xScrollCmd)) X TextUpdateScrollBar (textPtr->interp, textPtr->xScrollCmd, X textPtr->width, Tk_Width (tkwin), textPtr->x, X textPtr->xScrollUnits); X /* Vertical scrollbar */ X if (!NULLSTR (textPtr->yScrollCmd)) X TextUpdateScrollBar (textPtr->interp, textPtr->yScrollCmd, X textPtr->height, Tk_Height (tkwin), X textPtr->y, textPtr->yScrollUnits); X /* X * Given a new viewport or text height, find the first and last line X * numbers of the new viewport. X */ X GetVisibleLines (textPtr); X } X X /* X * (This is a kludge.) Send an expose event before and after drawing the X * page of text. Since moving and resizing of the subwindows will cause X * redundant expose events in the parent window, the phony events will X * bracket them indicating no action should be taken. X */ X SendExposeEvent (tkwin); X X /* X * If either the position of the viewport has changed or the size of X * width or height of the entire text have changed, move the children X * from the previous viewport out of the current viewport. Worry only X * about the vertical child window movements. The horizontal moves are X * handled by the when drawing the page of text. X */ X if (textPtr->first != oldFirst || textPtr->last != oldLast) { X register int cnt; X int first, last; X register Child *childPtr; X X /* Figure out which lines are now *out* of the viewport */ X if (textPtr->first > oldFirst && textPtr->first <= oldLast) X first = oldFirst, last = textPtr->first; X else if (textPtr->last < oldLast && textPtr->last >= oldFirst) X first = textPtr->last, last = oldLast; X else X first = oldFirst, last = oldLast; X for (cnt = first; cnt <= last; cnt++) { X for (childPtr = textPtr->lineArr[cnt]->children; X childPtr != NULL; childPtr = childPtr->nextPtr) { X MoveChild (childPtr, textPtr->x, textPtr->y); X childPtr->flags &= ~VISIBLE; X } X } X } X DrawPage (textPtr, deltaY); X SendExposeEvent (tkwin); X X /* Reset flags */ X textPtr->flags &= ~(VIEWPORT_RESIZED | VIEWPORT_MOVED | LAYOUT_CHANGED); } X /* X * ---------------------------------------------------------------------- X * X * DrawPage -- X * X * This procedure displays the lines of text and moves the child X * windows to their new positions. It draws lines with regard to X * the direction of the scrolling. The idea here is to make the X * text and buttons appear to move together. Otherwise you will X * get a "jiggling" effect where the window appear to bump into X * the next line before that line is moved. At worst case, where X * every line has a bottom you can get an aquarium effect (lines X * appear to ripple up). X * X * The text area may start between line boundaries (to accommodate ` X * both variable height lines and constant scrolling). Subtract the X * difference of the page offset and the line offset from the starting X * coordinates. For horizontal scrolling, simply substract the offset X * of the viewport. The window will clip the top of the first line, X * the bottom of the last line, whatever text extends to the left X * or right of the viewport on any line. X * X * Results: X * None. X * X * Side effects: X * Commands are output to X to display the line in its current X * mode. X * X * ---------------------------------------------------------------------- X */ X static void DrawPage (textPtr, deltaY) X Hypertext *textPtr; X int deltaY; /* Change from previous Y coordinate */ { X Line *linePtr; X Child *childPtr; X Tk_Window tkwin = textPtr->tkwin; X int textLength; X int curPos; X int baseline; X Pixmap pixMap; X int forceCopy = FALSE; X register int cnt; X int curLine, lastY; X register int x, y; X X /* Setup: Clear the display */ X /* Create an off-screen pixmap for semi-smooth scrolling. */ X pixMap = XCreatePixmap (Tk_Display (tkwin), Tk_WindowId (tkwin), X Tk_Width (tkwin), Tk_Height (tkwin), X DefaultDepthOfScreen (Tk_Screen (tkwin))); X Tk_Fill3DRectangle (Tk_Display (tkwin), pixMap, textPtr->border, X 0, 0, Tk_Width (tkwin), Tk_Height (tkwin), X 0, TK_RELIEF_FLAT); X X x = -(textPtr->x); X y = -(textPtr->y); X X if (deltaY >= 0) { X y += textPtr->lineArr[textPtr->first]->offset; X curLine = textPtr->first; X lastY = 0; X } else { X y += textPtr->lineArr[textPtr->last]->offset; X curLine = textPtr->last; X lastY = Tk_Height (tkwin); X } X forceCopy = FALSE; X /* Draw each line */ X for (cnt = textPtr->first; cnt <= textPtr->last; cnt++) { X X /* Initialize character position in text buffer to start */ X curPos = 0; X /* Initialize X position */ X x = -(textPtr->x); X X linePtr = textPtr->lineArr[curLine]; X baseline = y + linePtr->baseline; /* Base line in screen X * coordinates */ X X for (childPtr = linePtr->children; childPtr != NULL; X childPtr = childPtr->nextPtr) { X X MoveChild (childPtr, textPtr->x, textPtr->y); X childPtr->flags |= VISIBLE; X X textLength = (childPtr->precedingTextEnd - curPos); X if (textLength > 0) { X TkDisplayChars (Tk_Display (tkwin), pixMap, textPtr->gc, X textPtr->fontPtr, linePtr->text + curPos, X textLength, x, baseline, 0); X x += childPtr->precedingTextWidth; X } X curPos = childPtr->precedingTextEnd; X x += childPtr->width + 2 * childPtr->padX; X forceCopy++; X } X X /* X * This may be the text trailing the last child or the entire line if X * no children occur on it. X */ X textLength = (linePtr->textLength - curPos); X if (textLength > 0) { X TkDisplayChars (Tk_Display (tkwin), pixMap, textPtr->gc, X textPtr->fontPtr, linePtr->text + curPos, X textLength, x, baseline, 0); X } X /* Go to the top of the next line */ X if (deltaY >= 0) { X y += textPtr->lineArr[curLine++]->height; X } X if (forceCopy > 0 && !(textPtr->flags & VIEWPORT_RESIZED)) { X if (deltaY >= 0) { X XCopyArea (Tk_Display (tkwin), pixMap, Tk_WindowId (tkwin), X textPtr->gc, 0, lastY, Tk_Width (tkwin), y - lastY, X 0, lastY); X } else { X XCopyArea (Tk_Display (tkwin), pixMap, Tk_WindowId (tkwin), X textPtr->gc, 0, y, Tk_Width (tkwin), lastY - y, X 0, y); X } X forceCopy = 0; /* Reset drawing flag */ X lastY = y; /* Record last Y position */ X } X if ((deltaY < 0) && (curLine > 0)) { X y -= textPtr->lineArr[--curLine]->height; X } X } X /* Prologue */ X if (textPtr->flags & VIEWPORT_RESIZED) { X XCopyArea (Tk_Display (tkwin), pixMap, Tk_WindowId (tkwin), X textPtr->gc, 0, 0, Tk_Width (tkwin), Tk_Height (tkwin), 0, 0); X } else if (lastY != y) { X if (deltaY >= 0) { X XCopyArea (Tk_Display (tkwin), pixMap, Tk_WindowId (tkwin), X textPtr->gc, 0, lastY, Tk_Width (tkwin), X Tk_Height (tkwin) - lastY, 0, lastY); X } else { X XCopyArea (Tk_Display (tkwin), pixMap, Tk_WindowId (tkwin), X textPtr->gc, 0, 0, Tk_Width (tkwin), lastY, 0, 0); X } X } X XFreePixmap (Tk_Display (tkwin), pixMap); } X /* X * ---------------------------------------------------------------------- X * X * MoveChild -- X * X * Move a child subwindow to a new location in the hypertext X * parent window. If the window has no geometry (i.e. width, X * or height is 0), simply unmap to window. X * X * Results: X * None. X * X * Side effects: X * Each subwindow is moved to its new location, generating X * Expose events in the parent for each child window moved. X * X * ---------------------------------------------------------------------- X */ X static void MoveChild (childPtr, newX, newY) X register Child *childPtr; X int newX; /* X-coordinate from left of text */ X int newY; /* Y-coordinate from top of text */ { X register Tk_Window tkwin = childPtr->tkwin; X X if (tkwin == NULL) X return; X X if (childPtr->width > 0 && childPtr->height > 0) { X register int x, y; X X x = childPtr->x - newX, y = childPtr->y - newY; X X if (x != Tk_X (tkwin) || y != Tk_Y (tkwin) || X childPtr->width != Tk_Width (tkwin) || X childPtr->height != Tk_Height (tkwin)) { X Tk_MoveResizeWindow (tkwin, x, y, X (unsigned int)childPtr->width, X (unsigned int)childPtr->height); X if (!Tk_IsMapped (tkwin)) { X Tk_MapWindow (tkwin); X childPtr->flags |= MAPPED; X } X } X } else { X if (Tk_IsMapped (tkwin)) { X Tk_UnmapWindow (tkwin); X childPtr->flags &= ~MAPPED; X } X } } X /* X * ---------------------------------------------------------------------- X * X * GetVisibleLines -- X * X * Calculates which lines are visible using the height X * of the viewport and y offset from the top of the text. X * X * Results: X * None. X * X * Side effects: X * Only those line between first and last inclusive are X * redrawn. X * X * ---------------------------------------------------------------------- X */ X static int GetVisibleLines (textPtr) X Hypertext *textPtr; { X int first, last; X int top, bottom; X X top = textPtr->newY; X X /* First line */ X first = LineSearch (textPtr, top, 0, textPtr->numLines - 1); X if (first < 0) { X /* This can't be. The newY offset must be corrupted. */ X fprintf (stderr, "First position not found `%d'", top); X return (TCL_ERROR); X } X textPtr->first = first; X X /* X * If there is less text than window space, the bottom line is the last X * line of text. Otherwise search for the line located at the bottom of X * the window. X */ X bottom = top + Tk_Height (textPtr->tkwin) - 1; X if (bottom > textPtr->height) { X last = textPtr->numLines - 1; X } else { X last = LineSearch (textPtr, bottom, first, textPtr->numLines - 1); X } X if (last < 0) { X /* This can't be. The newY offset must be corrupted. */ X fprintf (stderr, "Last position not found `%d'", bottom); X return (TCL_ERROR); X } X textPtr->last = last; X return (TCL_OK); } X /* X * ---------------------------------------------------------------------- X * X * LineSearch -- X * X * Performs a binary search for the line located at some world X * Y coordinate. The search is limited to those lines between X * *low* and *high* inclusive. X * X * Results: X * Returns the line number at the given Y coordinate. If *position* X * does not correspond to any of the lines in the given the set, X * -1 is returned. X * X * ---------------------------------------------------------------------- X */ static int LineSearch (textPtr, position, low, high) X Hypertext *textPtr; X int position; X register int low; X register int high; { X register int mid; X register Line *linePtr; X X while (low <= high) { X mid = (low + high) >> 1; X linePtr = textPtr->lineArr[mid]; X X if (position < linePtr->offset) X high = mid - 1; X else if (position >= (linePtr->offset + linePtr->height)) X low = mid + 1; X else X return (mid); X } X return (-1); } X /* X * ---------------------------------------------------------------------- X * X * TextUpdateScrollBar -- X * X * Invoke a Tcl command to the scrollbar, defining the new position X * and length of the scroll. See the Tk documentation for further X * information on the scrollbar. It is assumed the scrollbar command X * prefix is valid. X * X * Results: X * None. X * X * Side Effects: X * Scrollbar is commanded to change position and/or size. X * ---------------------------------------------------------------------- X */ static void TextUpdateScrollBar (interp, command, total, window, first, units) X Tcl_Interp *interp; X char *command; /* scrollbar command */ X int total; /* Total distance */ X int window; /* Window distance */ X int first; /* Position of viewport */ X int units; /* Unit distance */ { X char cmdbuf[BUFSIZ]; X int totalUnits, windowUnits; X int firstUnit, lastUnit; X X totalUnits = (total / units) + 1; X windowUnits = window / units; X firstUnit = first / units; X lastUnit = (firstUnit + windowUnits); X if (firstUnit >= totalUnits) X firstUnit = totalUnits; X if (lastUnit > totalUnits) X lastUnit = totalUnits; X sprintf (cmdbuf, "%s %d %d %d %d", command, totalUnits, windowUnits, X firstUnit, lastUnit); X if (Tcl_Eval (interp, cmdbuf, 0, NULL) != TCL_OK) { X TkBindError (interp); X } } X /* X * ---------------------------------------------------------------------- X * X * ParseText -- X * X * Parse the characters in the text field of the hypertext structure X * into an array of lines. X * X * Results: X * Returns TCL_OK or error depending if the file was read correctly. X * X * ---------------------------------------------------------------------- X */ static int ParseText (interp, textPtr) X Tcl_Interp *interp; X Hypertext *textPtr; { X register Line *linePtr; X int c; X #define HUGE_LINE_SIZE 1024 X char buf[HUGE_LINE_SIZE]; X #define HUGE_COMMAND_SIZE 10000 X char cmdBuf[HUGE_COMMAND_SIZE]; X int curPos; X register int cnt; X register int state; X int result = TCL_ERROR; X X FreeLines (textPtr); /* Delete any previous lines */ X CreateTraces (textPtr); /* Create variable traces */ X X linePtr = GetLine (textPtr); X if (linePtr == NULL) X goto error; /* Error allocating line */ X X state = cnt = 0; X curPos = 0; X while ((c = textPtr->text[curPos++]) != '\0') { X if (c == textPtr->specChar) { X state++; X } else if (c == '\n') { X state = -1; X } else if ((state == 0) && (c == '\\')) { X state = 3; X } else { X state = 0; X } X X switch (state) { X case 2: /* Tcl Command block found */ X cnt--; X if (GetTclCommand (textPtr, &curPos, cmdBuf) == NULL) X goto error; X linePtr->textLength = cnt; X if (Tcl_Eval (interp, cmdBuf, 0, NULL) != TCL_OK) X goto error; X state = 0; X break; X X case 4: /* Escaped block designator */ X buf[cnt - 1] = c; X state = 0; X break; X X case -1: /* End of text line */ X buf[cnt] = '\0'; X SetLineText (linePtr, buf, cnt); X linePtr = GetLine (textPtr); X if (linePtr == NULL) X goto error; X cnt = state = 0; X break; X X default: /* Default action, add to text buffer */ X buf[cnt++] = c; X break; X } X if (cnt == HUGE_LINE_SIZE) { X interp->result = "Text line is too long"; X goto error; X } X } X if (cnt > 0) { X buf[cnt] = '\0'; X SetLineText (linePtr, buf, cnt); X } X result = TCL_OK; X error: X if (textPtr->text != NULL) X free (textPtr->text); X textPtr->text = NULL; X DeleteTraces (textPtr); X if (result == TCL_ERROR) { X FreeLines (textPtr); X return (TCL_ERROR); X } else { X AdjustLinesAllocated (textPtr); X X textPtr->first = 0; X textPtr->last = textPtr->numLines - 1; X textPtr->newX = textPtr->newY = 0; X textPtr->width = textPtr->height = textPtr->x = textPtr->y = 0; X return (TCL_OK); X } } X X static int ReadFile (interp, textPtr) X Tcl_Interp *interp; X Hypertext *textPtr; { X FILE *fp; X register int arraySize = BUFSIZ; X register int numBytes = 0; X register char *charArr; X int numBytesRead = 0; X X fp = fopen (textPtr->fileName, "r"); X if (fp == NULL) { X Tcl_AppendResult (interp, "fopen: ", sys_errlist[errno], X ": Can't open \"", textPtr->fileName, X "\" for reading", NULL); X return (TCL_ERROR); X } X charArr = malloc (arraySize); X if (charArr == NULL) { X Tcl_AppendResult (interp, "malloc: ", sys_errlist[errno], X ": Can't alloc space for \"", textPtr->fileName, X "\" charArr", NULL); X return (TCL_ERROR); X } X for (;;) { X /* Read in next block of text */ X numBytes = fread (&charArr[numBytesRead], sizeof (char), BUFSIZ, fp); X X if (numBytes < 0) X goto error; X else if (numBytes == 0) X break; X numBytesRead += numBytes; X if (numBytesRead == arraySize) { X /* Reallocate with double the buffer size */ X arraySize += arraySize; X charArr = reallocate (charArr, arraySize, numBytesRead); X if (charArr == NULL) X goto error; X } X } X charArr[numBytesRead] = '\0'; X textPtr->text = charArr; X fclose (fp); X return (TCL_OK); X error: X fclose (fp); X return (TCL_ERROR); } X X static char * GetTclCommand (textPtr, curPos, newCommand) X Hypertext *textPtr; X int *curPos; X char *newCommand; { X register int c; X register int state; X register int src, dest; X X state = 0; X dest = 0; X src = *curPos; X X /* Simply collect the all the characters until %% into a buffer */ X while ((c = textPtr->text[src++]) != '\0') { X if (c == textPtr->specChar) { X state++; X } else if ((state == 0) && (c == '\\')) { X state = 3; X } else { X state = 0; X } X X switch (state) { X case 2: /* End of command block found */ X newCommand[dest - 1] = '\0'; X *curPos = src; X return (newCommand); X X case 4: /* Escaped block designator */ X newCommand[dest] = c; X state = 0; X break; X X default: /* Add to command buffer */ SHAR_EOF : || echo 'restore of snmp2/snmptcl/htext2.c failed' fi echo 'End of snmp2 part 27' echo 'File snmp2/snmptcl/htext2.c is continued in part 28' echo 28 > _sharseq.tmp exit 0