Annotation of researchv9/X11/src/X.V11R1/lib/Xtk/Text.c, revision 1.1

1.1     ! root        1: #ifndef lint
        !             2: static char rcsid[] = "$Header: Text.c,v 1.4 87/09/13 23:32:44 newman Exp $";
        !             3: #endif lint
        !             4: 
        !             5: /*
        !             6:  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
        !             7:  * 
        !             8:  *                         All Rights Reserved
        !             9:  * 
        !            10:  * Permission to use, copy, modify, and distribute this software and its 
        !            11:  * documentation for any purpose and without fee is hereby granted, 
        !            12:  * provided that the above copyright notice appear in all copies and that
        !            13:  * both that copyright notice and this permission notice appear in 
        !            14:  * supporting documentation, and that the name of Digital Equipment
        !            15:  * Corporation not be used in advertising or publicity pertaining to
        !            16:  * distribution of the software without specific, written prior permission.  
        !            17:  * 
        !            18:  * 
        !            19:  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
        !            20:  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
        !            21:  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
        !            22:  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
        !            23:  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
        !            24:  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
        !            25:  * SOFTWARE.
        !            26:  */
        !            27: /* File: Text.c */
        !            28: 
        !            29: #include "Intrinsic.h"
        !            30: #include "Text.h"
        !            31: #include "TextP.h"
        !            32: #include "Scroll.h"
        !            33: #include "Atoms.h"
        !            34: #include <sys/file.h>
        !            35: #include <X11/Xutil.h>
        !            36: #include <strings.h>
        !            37: 
        !            38: extern void bcopy();
        !            39: 
        !            40: #define BufMax 1000
        !            41: #define abs(x) (((x) < 0) ? (-(x)) : (x))
        !            42: #define min(x,y)       ((x) < (y) ? (x) : (y))
        !            43: #define max(x,y)       ((x) > (y) ? (x) : (y))
        !            44: #define GETLASTPOS  (*(ctx->text.source->scan)) (ctx->text.source, 0, XtstFile, XtsdRight, 1, TRUE)
        !            45: #define BUTTONMASK 0x143d
        !            46: 
        !            47: #define  yMargin 2
        !            48: #define zeroPosition ((XtTextPosition) 0)
        !            49: 
        !            50: extern void BuildLineTable ();
        !            51: 
        !            52: /****************************************************************
        !            53:  *
        !            54:  * Full class record constant
        !            55:  *
        !            56:  ****************************************************************/
        !            57: 
        !            58: extern caddr_t defaultTextTranslations;
        !            59: 
        !            60: static XtResource resources[] = {
        !            61:     {XtNtextOptions, XtCTextOptions, XrmRInt, sizeof (int),
        !            62:         XtOffset(TextWidget, text.options), XrmRString, "0"},
        !            63:     {XtNdisplayPosition, XtCTextPosition, XrmRInt,
        !            64:         sizeof (XtTextPosition), XtOffset(TextWidget, text.lt.top), 
        !            65:         XrmRString, "0"},
        !            66:     {XtNinsertPosition, XtCTextPosition, XtRInt, 
        !            67:         sizeof(XtTextPosition), XtOffset(TextWidget, text.insertPos), 
        !            68:        XrmRString, "0"},
        !            69:     {XtNleftMargin, XtCMargin, XrmRInt, sizeof (int), 
        !            70:         XtOffset(TextWidget, text.leftmargin), XrmRString, "2"},
        !            71:     {XtNselectionArray, XtCSelectionArray, XrmRPointer, 
        !            72:         sizeof(SelectionArray), XtOffset(TextWidget, text.sarray), 
        !            73:        XrmRPointer, NULL},
        !            74:     {XtNtextSource, XtCTextSource, XrmRPointer, sizeof (caddr_t), 
        !            75:          XtOffset(TextWidget, text.source), XrmRPointer, NULL},
        !            76:     {XtNtextSink, XtCTextSink, XrmRPointer, sizeof (caddr_t),
        !            77:          XtOffset(TextWidget, text.sink), XrmRPointer, NULL},
        !            78:     {XtNselection, XtCSelection, XrmRPointer, sizeof(caddr_t),
        !            79:         XtOffset(TextWidget, text.s), XrmRPointer, NULL},
        !            80:     {XtNeventBindings, XtCEventBindings, XtRStringTable, 
        !            81:         sizeof(_XtTranslations), XtOffset(TextWidget, core.translations), 
        !            82:        XtRStringTable, (caddr_t)&defaultTextTranslations},
        !            83: };
        !            84: 
        !            85:   
        !            86: static void Initialize(request, new)
        !            87:  Widget request, new;
        !            88: {
        !            89:     TextWidget ctx = (TextWidget) new;
        !            90: 
        !            91:     if (ctx->core.width == 0)
        !            92:        ctx->core.width = 200;
        !            93:     if (ctx->core.height == 0)
        !            94:        ctx->core.height = 200;
        !            95: 
        !            96:     ctx->text.lt.lines = 0;
        !            97:     ctx->text.lt.info = NULL;
        !            98:     ctx->text.s.left = ctx->text.s.right = 0;
        !            99:     ctx->text.s.type = XtselectPosition;
        !           100:     ctx->text.sbar = ctx->text.outer = NULL;
        !           101:     ctx->text.sarray[0] = XtselectPosition;
        !           102:     ctx->text.sarray[1] = XtselectWord;
        !           103:     ctx->text.sarray[2] = XtselectLine;
        !           104:     ctx->text.sarray[3] = XtselectParagraph;
        !           105:     ctx->text.sarray[4] = XtselectAll;
        !           106:     ctx->text.sarray[5] = XtselectNull;
        !           107:     ctx->text.showposition = TRUE;
        !           108:     ctx->text.lastPos = GETLASTPOS;
        !           109:     ctx->text.dialog = NULL;
        !           110:     ctx->text.updateFrom = (XtTextPosition *) XtMalloc(1);
        !           111:     ctx->text.updateTo = (XtTextPosition *) XtMalloc(1);
        !           112:     ctx->text.numranges = ctx->text.maxranges = 0;
        !           113:     ctx->text.gc = DefaultGCOfScreen(XtScreen(ctx));
        !           114:     BuildLineTable(ctx, ctx->text.lt.top);
        !           115: /* what about this ugly scrollbar stuff?
        !           116:     if (ctx->text.options & scrollVertical) {
        !           117:        scrollMgrArgs[0].value =
        !           118:            scrollBarArgs[0].value = (caddr_t)(XtWindow(ctx));
        !           119:        ctx->text.outer = 
        !           120:           XtScrollMgrCreate(ctx->core.display, parent, scrollMgrArgs, XtNumber(scrollMgrArgs));
        !           121:        XtWindow(ctx) = XtScrollMgrGetChild(ctx->core.display, ctx->text.outer);
        !           122:        ctx->text.sbar =
        !           123:            XtCreateWidget("scrollbar", scrollbarWidgetClass, ctx->text.outer,
        !           124:               scrollBarArgs, XtNumber(scrollBarArgs));
        !           125:        XMapSubwindows(ctx->core.display, ctx->text.outer);
        !           126:        (void) XtSetEventHandler(ctx->core.display, ctx->text.outer, ProcessTextEvent,
        !           127:         StructureNotifyMask, (caddr_t) ctx);
        !           128:     }
        !           129: */
        !           130: }
        !           131: 
        !           132: static void Realize( w, valueMask, attributes )
        !           133:    Widget w;
        !           134:    Mask valueMask;
        !           135:    XSetWindowAttributes *attributes;
        !           136: {
        !           137:    TextWidget ctx = (TextWidget)w;
        !           138:    if (ctx->text.sbar) XtRealizeWidget(ctx->text.sbar);
        !           139:    ctx->core.window = 
        !           140:           XCreateWindow(
        !           141:                 XtDisplay(w), w->core.parent->core.window,
        !           142:                 w->core.x, w->core.y,
        !           143:                 w->core.width, w->core.height, w->core.border_width,
        !           144:                 w->core.depth, InputOutput, (Visual *)CopyFromParent,
        !           145:                 valueMask, attributes);
        !           146: }
        !           147: 
        !           148: /* Utility routines for support of Text */
        !           149: 
        !           150: 
        !           151: /*
        !           152:  * Procedure to manage insert cursor visibility for editable text.  It uses
        !           153:  * the value of ctx->insertPos and an implicit argument. In the event that
        !           154:  * position is immediately preceded by an eol graphic, then the insert cursor
        !           155:  * is displayed at the beginning of the next line.
        !           156: */
        !           157: static void InsertCursor (ctx, state)
        !           158:   TextWidget ctx;
        !           159:   InsertState state;
        !           160: {
        !           161:     Position x, y;
        !           162:     int dy, line, visible;
        !           163:     XtTextBlock text;
        !           164: 
        !           165:     if (ctx->text.lt.lines < 1) return;
        !           166:     visible = LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y);
        !           167:     if (line < ctx->text.lt.lines)
        !           168:        dy = (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
        !           169:     else
        !           170:        dy = (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
        !           171: 
        !           172:     /** If the insert position is just after eol then put it on next line **/
        !           173:     if (x > ctx->text.leftmargin &&
        !           174:        ctx->text.insertPos > 0 &&
        !           175:        ctx->text.insertPos >= ctx->text.lastPos) {
        !           176:           /* reading the source is bogus and this code should use scan */
        !           177:           (*(ctx->text.source->read)) (ctx->text.source, ctx->text.insertPos - 1, &text, 1);
        !           178:           if (text.ptr[0] == '\n') {
        !           179:               x = ctx->text.leftmargin;
        !           180:               y += dy;
        !           181:           }
        !           182:     }
        !           183:     y += dy;
        !           184:     if (visible)
        !           185:        (*(ctx->text.sink->insertCursor))(ctx, x, y, state);
        !           186: }
        !           187: 
        !           188: 
        !           189: /*
        !           190:  * Procedure to register a span of text that is no longer valid on the display
        !           191:  * It is used to avoid a number of small, and potentially overlapping, screen
        !           192:  * updates. [note: this is really a private procedure but is used in
        !           193:  * multiple modules].
        !           194: */
        !           195: _XtTextNeedsUpdating(ctx, left, right)
        !           196:   TextWidget ctx;
        !           197:   XtTextPosition left, right;
        !           198: {
        !           199:     int     i;
        !           200:     if (left < right) {
        !           201:        for (i = 0; i < ctx->text.numranges; i++) {
        !           202:            if (left <= ctx->text.updateTo[i] && right >= ctx->text.updateFrom[i]) {
        !           203:                ctx->text.updateFrom[i] = min(left, ctx->text.updateFrom[i]);
        !           204:                ctx->text.updateTo[i] = max(right, ctx->text.updateTo[i]);
        !           205:                return;
        !           206:            }
        !           207:        }
        !           208:        ctx->text.numranges++;
        !           209:        if (ctx->text.numranges > ctx->text.maxranges) {
        !           210:            ctx->text.maxranges = ctx->text.numranges;
        !           211:            i = ctx->text.maxranges * sizeof(XtTextPosition);
        !           212:            ctx->text.updateFrom = (XtTextPosition *) 
        !           213:                XtRealloc((char *)ctx->text.updateFrom, (unsigned) i);
        !           214:            ctx->text.updateTo = (XtTextPosition *) 
        !           215:                XtRealloc((char *)ctx->text.updateTo, (unsigned) i);
        !           216:        }
        !           217:        ctx->text.updateFrom[ctx->text.numranges - 1] = left;
        !           218:        ctx->text.updateTo[ctx->text.numranges - 1] = right;
        !           219:     }
        !           220: }
        !           221: 
        !           222: 
        !           223: /*
        !           224:  * Procedure to read a span of text in Ascii form. This is purely a hack and
        !           225:  * we probably need to add a function to sources to provide this functionality.
        !           226:  * [note: this is really a private procedure but is used in multiple modules].
        !           227: */
        !           228: char *_XtTextGetText(ctx, left, right)
        !           229:   TextWidget ctx;
        !           230:   XtTextPosition left, right;
        !           231: {
        !           232:     char   *result, *tempResult;
        !           233:     int length, resultLength;
        !           234:     XtTextBlock text;
        !           235:     XtTextPosition end, nend;
        !           236:     
        !           237:     resultLength = right - left + 10;  /* Bogus? %%% */
        !           238:     result = (char *)XtMalloc((unsigned) resultLength);
        !           239:     end = (*(ctx->text.source->read))(ctx->text.source, left, &text, right - left);
        !           240:     (void) strncpy(result, text.ptr, text.length);
        !           241:     length = text.length;
        !           242:     while (end < right) {
        !           243:         nend = (*(ctx->text.source->read))(ctx->text.source, end, &text, right - end);
        !           244:        tempResult = result + length;
        !           245:         (void) strncpy(tempResult, text.ptr, text.length);
        !           246:        length += text.length;
        !           247:         end = nend;
        !           248:     }
        !           249:     result[length] = 0;
        !           250:     return result;
        !           251: }
        !           252: 
        !           253: 
        !           254: 
        !           255: /* 
        !           256:  * This routine maps an x and y position in a window that is displaying text
        !           257:  * into the corresponding position in the source.
        !           258:  */
        !           259: static XtTextPosition PositionForXY (ctx, x, y)
        !           260:   TextWidget ctx;
        !           261:   Position x,y;
        !           262: {
        !           263:  /* it is illegal to call this routine unless there is a valid line table! */
        !           264:     int     width, fromx, line;
        !           265:     XtTextPosition position, resultstart, resultend;
        !           266: 
        !           267:     /*** figure out what line it is on ***/
        !           268:     for (line = 0; line < ctx->text.lt.lines - 1; line++) {
        !           269:        if (y <= ctx->text.lt.info[line + 1].y)
        !           270:            break;
        !           271:     }
        !           272:     position = ctx->text.lt.info[line].position;
        !           273:     if (position >= ctx->text.lastPos)
        !           274:        return ctx->text.lastPos;
        !           275:     fromx = ctx->text.lt.info[line].x; /* starting x in line */
        !           276:     width = x - fromx;                 /* num of pix from starting of line */
        !           277:     (*(ctx->text.sink->resolve)) (ctx, position, fromx, width,
        !           278:            &resultstart, &resultend);
        !           279:     if (resultstart >= ctx->text.lt.info[line + 1].position)
        !           280:        resultstart = (*(ctx->text.source->scan))(ctx->text.source,
        !           281:                ctx->text.lt.info[line + 1].position, XtstPositions, XtsdLeft, 1, TRUE);
        !           282:     return resultstart;
        !           283: }
        !           284: 
        !           285: /*
        !           286:  * This routine maps a source position in to the corresponding line number
        !           287:  * of the text that is displayed in the window.
        !           288: */
        !           289: int LineForPosition (ctx, position)
        !           290:   TextWidget ctx;
        !           291:   XtTextPosition position;
        !           292:   /* it is illegal to call this routine unless there is a valid line table!*/
        !           293: {
        !           294:     int     line;
        !           295: 
        !           296:     if (position <= ctx->text.lt.info[0].position)
        !           297:        return 0;
        !           298:     for (line = 0; line < ctx->text.lt.lines; line++)
        !           299:        if (position < ctx->text.lt.info[line + 1].position)
        !           300:            break;
        !           301:     return line;
        !           302: }
        !           303: 
        !           304: /*
        !           305:  * This routine maps a source position into the corresponding line number
        !           306:  * and the x, y coordinates of the text that is displayed in the window.
        !           307: */
        !           308: static int LineAndXYForPosition (ctx, pos, line, x, y)
        !           309:   TextWidget ctx;
        !           310:   XtTextPosition pos;
        !           311:   int *line;
        !           312:   Position *x, *y;
        !           313:   /* it is illegal to call this routine unless there is a valid line table!*/
        !           314: {
        !           315:     XtTextPosition linePos, endPos;
        !           316:     int     visible, realW, realH;
        !           317: 
        !           318:     *line = 0;
        !           319:     *x = ctx->text.leftmargin;
        !           320:     *y = yMargin;
        !           321:     visible = IsPositionVisible(ctx, pos);
        !           322:     if (visible) {
        !           323:        *line = LineForPosition(ctx, pos);
        !           324:        *y = ctx->text.lt.info[*line].y;
        !           325:        *x = ctx->text.lt.info[*line].x;
        !           326:        linePos = ctx->text.lt.info[*line].position;
        !           327:        (*(ctx->text.sink->findDistance))(ctx, linePos,
        !           328:                                      *x, pos, &realW, &endPos, &realH);
        !           329:        *x = *x + realW;
        !           330:     }
        !           331:     return visible;
        !           332: }
        !           333: 
        !           334: /*
        !           335:  * This routine builds a line table. It does this by starting at the
        !           336:  * specified position and measuring text to determine the staring position
        !           337:  * of each line to be displayed. It also determines and saves in the
        !           338:  * linetable all the required metrics for displaying a given line (e.g.
        !           339:  * x offset, y offset, line length, etc.).
        !           340: */
        !           341: static void BuildLineTable (ctx, position)
        !           342:   TextWidget ctx;
        !           343:   XtTextPosition position;
        !           344: {
        !           345:     Position x, y;
        !           346:     Dimension width, realW, realH;
        !           347:     int line, lines;
        !           348:     XtTextPosition startPos, endPos;
        !           349:     Boolean     rebuild;
        !           350: 
        !           351:     rebuild = (Boolean) (position != ctx->text.lt.top);
        !           352:     lines = (*(ctx->text.sink->maxLines))(ctx, ctx->core.height);
        !           353:     if (ctx->text.lt.info != NULL && lines != ctx->text.lt.lines) {
        !           354:        XtFree((char *) ctx->text.lt.info);
        !           355:        ctx->text.lt.info = NULL;
        !           356:     }
        !           357:     if (ctx->text.lt.info == NULL) {
        !           358:        ctx->text.lt.info = (LineTableEntry *)
        !           359:            XtMalloc((unsigned)sizeof(LineTableEntry) * (lines + 1));
        !           360:        for (line = 0; line < lines; line++) {
        !           361:            ctx->text.lt.info[line].position = 0;
        !           362:            ctx->text.lt.info[line].y = 0;
        !           363:        }
        !           364:        rebuild = TRUE;
        !           365:     }
        !           366:     else
        !           367:        lines = ctx->text.lt.lines;
        !           368:     if (rebuild) {
        !           369:        ctx->text.lt.top = position;
        !           370:        ctx->text.lt.lines = lines;
        !           371:        startPos = position;
        !           372:        y = yMargin;
        !           373:        for (line = 0; line <= ctx->text.lt.lines; line++) {
        !           374:            x = ctx->text.leftmargin;
        !           375:            ctx->text.lt.info[line].x = x;
        !           376:            ctx->text.lt.info[line].y = y;
        !           377:            ctx->text.lt.info[line].position = startPos;
        !           378:            if (startPos <= ctx->text.lastPos) {
        !           379:                width = (ctx->text.options & resizeWidth) ? 9999 : ctx->core.width - x;
        !           380:                (*(ctx->text.sink->findPosition))(ctx, 
        !           381:                         startPos, x,
        !           382:                        width, (ctx->text.options & wordBreak),
        !           383:                        &endPos, &realW, &realH);
        !           384:                if (!(ctx->text.options & wordBreak) && endPos < ctx->text.lastPos) {
        !           385:                    endPos = (*(ctx->text.source->scan))(ctx->text.source, startPos,
        !           386:                            XtstEOL, XtsdRight, 1, TRUE);
        !           387:                    if (endPos == startPos)
        !           388:                        endPos = ctx->text.lastPos + 1;
        !           389:                }
        !           390:                ctx->text.lt.info[line].endX = realW + x;
        !           391:                startPos = endPos;
        !           392:            }
        !           393:            else ctx->text.lt.info[line].endX = x;
        !           394:            y = y + realH;
        !           395:        }
        !           396:     }
        !           397: }
        !           398: 
        !           399: /*
        !           400:  * This routine is used to re-display the entire window, independent of
        !           401:  * its current state.
        !           402: */
        !           403: void ForceBuildLineTable(ctx)
        !           404:     TextWidget ctx;
        !           405: {
        !           406:     XtTextPosition position;
        !           407: 
        !           408:     position = ctx->text.lt.top;
        !           409:     ctx->text.lt.top++; /* ugly, but it works */
        !           410:     BuildLineTable(ctx, position);
        !           411: }
        !           412: 
        !           413: /*
        !           414:  * This routine is used by Text to notify an associated scrollbar of the
        !           415:  * correct metrics (position and shown fraction) for the text being currently
        !           416:  * displayed in the window.
        !           417: */
        !           418: static void SetScrollBar(ctx)
        !           419:     TextWidget ctx;
        !           420: {
        !           421:     float   first, last;
        !           422:     if (ctx->text.sbar) {
        !           423:        if ((ctx->text.lastPos > 0)  &&  (ctx->text.lt.lines > 0)) {
        !           424:            first = ctx->text.lt.top;
        !           425:            first /= ctx->text.lastPos; 
        !           426:                                        /* Just an approximation */
        !           427:            last = ctx->text.lt.info[ctx->text.lt.lines].position;
        !           428:            last /= ctx->text.lastPos;
        !           429:        }
        !           430:        else {
        !           431:            first = 0.0;
        !           432:            last = 1.0;
        !           433:        }
        !           434:        XtScrollBarSetThumb(ctx->text.sbar, first, last - first);
        !           435:     }
        !           436: }
        !           437: 
        !           438: 
        !           439: /*
        !           440:  * The routine will scroll the displayed text by lines.  If the arg  is
        !           441:  * positive, move up; otherwise, move down. [note: this is really a private
        !           442:  * procedure but is used in multiple modules].
        !           443: */
        !           444: _XtTextScroll(ctx, n)
        !           445:   TextWidget ctx;
        !           446:   int n;
        !           447: {
        !           448:     XtTextPosition top, target;
        !           449:     if (n >= 0) {
        !           450:        top = min(ctx->text.lt.info[n].position, ctx->text.lastPos);
        !           451:        BuildLineTable(ctx, top);
        !           452:        if (top >= ctx->text.lastPos)
        !           453:            DisplayTextWindow(ctx);
        !           454:        else {
        !           455:            XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
        !           456:                      0, ctx->text.lt.info[n].y,
        !           457:                      9999, (Dimension)ctx->core.height - ctx->text.lt.info[n].y,
        !           458:                      0, ctx->text.lt.info[0].y);
        !           459:            (*(ctx->text.sink->clearToBackground))(ctx, 0,
        !           460:                ctx->text.lt.info[0].y + ctx->core.height - ctx->text.lt.info[n].y,
        !           461:                9999, 9999);
        !           462:            if (n < ctx->text.lt.lines) n++;
        !           463:            _XtTextNeedsUpdating(ctx,
        !           464:                    ctx->text.lt.info[ctx->text.lt.lines - n].position, ctx->text.lastPos);
        !           465:            SetScrollBar(ctx);
        !           466:        }
        !           467:     } else {
        !           468:        Dimension tempHeight;
        !           469:        n = -n;
        !           470:        target = ctx->text.lt.top;
        !           471:        top = (*(ctx->text.source->scan))(ctx->text.source, target, XtstEOL,
        !           472:                                     XtsdLeft, n+1, FALSE);
        !           473:        tempHeight = ctx->text.lt.info[ctx->text.lt.lines-n].y;
        !           474:        BuildLineTable(ctx, top);
        !           475:        if (ctx->text.lt.info[n].position == target) {
        !           476:            XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
        !           477:                      0, ctx->text.lt.info[0].y, 9999, tempHeight,
        !           478:                      0, ctx->text.lt.info[n].y);
        !           479:            _XtTextNeedsUpdating(ctx, 
        !           480:                    ctx->text.lt.info[0].position, ctx->text.lt.info[n].position);
        !           481:            SetScrollBar(ctx);
        !           482:        } else if (ctx->text.lt.top != target) DisplayTextWindow(ctx);
        !           483:     }
        !           484: }
        !           485: 
        !           486: /*
        !           487:  * The routine will scroll the displayed text by pixels.  If the arg is
        !           488:  * positive, move up; otherwise, move down.
        !           489: */
        !           490: /*ARGSUSED*/ /* keep lint happy */
        !           491: static int ScrollUpDownProc (w, data, pix)
        !           492:   Widget w;
        !           493:   int data;
        !           494:   int pix;
        !           495: {
        !           496:     TextWidget ctx = (TextWidget)w;
        !           497:     int     apix, line;
        !           498:     _XtTextPrepareToUpdate(ctx);
        !           499:     apix = abs(pix);
        !           500:     for (line = 1;
        !           501:            line < ctx->text.lt.lines && apix > ctx->text.lt.info[line + 1].y;
        !           502:            line++);
        !           503:     if (pix >= 0)
        !           504:        _XtTextScroll(ctx, line);
        !           505:     else
        !           506:        _XtTextScroll(ctx, -line);
        !           507:     _XtTextExecuteUpdate(ctx);
        !           508: }
        !           509: 
        !           510: /*
        !           511:  * The routine "thumbs" the displayed text. Thumbing means reposition the
        !           512:  * displayed view of the source to a new position determined by a fraction
        !           513:  * of the way from beginning to end. Ideally, this should be determined by
        !           514:  * the number of displayable lines in the source. This routine does it as a
        !           515:  * fraction of the first position and last position and then normalizes to
        !           516:  * the start of the line containing the position.
        !           517: */
        !           518: /*ARGSUSED*/ /* keep lint happy */
        !           519: static int ThumbProc (w, data, where)
        !           520:   Widget w;
        !           521:   int data;
        !           522:   float where;
        !           523:   /* BUG/deficiency: The normalize to line portion of this routine will
        !           524:    * cause thumbing to always position to the start of the source.
        !           525:    */
        !           526: {
        !           527:   
        !           528:     TextWidget ctx= (TextWidget)w;
        !           529:     XtTextPosition position;
        !           530:     _XtTextPrepareToUpdate(ctx);
        !           531:     position = where * ctx->text.lastPos;
        !           532:     position = (*(ctx->text.source->scan))(ctx->text.source, position, XtstEOL, XtsdLeft,
        !           533:            1, FALSE);
        !           534:     BuildLineTable(ctx, position);
        !           535:     DisplayTextWindow(ctx);
        !           536:     _XtTextExecuteUpdate(ctx);
        !           537: }
        !           538: 
        !           539: 
        !           540: int _XtTextSetNewSelection(ctx, left, right)
        !           541:   TextWidget ctx;
        !           542:   XtTextPosition left, right;
        !           543: {
        !           544:     XtTextPosition pos;
        !           545: 
        !           546:     if (left < ctx->text.s.left) {
        !           547:        pos = min(right, ctx->text.s.left);
        !           548:        _XtTextNeedsUpdating(ctx, left, pos);
        !           549:     }
        !           550:     if (left > ctx->text.s.left) {
        !           551:        pos = min(left, ctx->text.s.right);
        !           552:        _XtTextNeedsUpdating(ctx, ctx->text.s.left, pos);
        !           553:     }
        !           554:     if (right < ctx->text.s.right) {
        !           555:        pos = max(right, ctx->text.s.left);
        !           556:        _XtTextNeedsUpdating(ctx, pos, ctx->text.s.right);
        !           557:     }
        !           558:     if (right > ctx->text.s.right) {
        !           559:        pos = max(left, ctx->text.s.right);
        !           560:        _XtTextNeedsUpdating(ctx, pos, right);
        !           561:     }
        !           562: 
        !           563:     ctx->text.s.left = left;
        !           564:     ctx->text.s.right = right;
        !           565: }
        !           566: 
        !           567: 
        !           568: 
        !           569: /*
        !           570:  * This internal routine deletes the text from pos1 to pos2 in a source and
        !           571:  * then inserts, at pos1, the text that was passed. As a side effect it
        !           572:  * "invalidates" that portion of the displayed text (if any).
        !           573: */
        !           574: int ReplaceText (ctx, pos1, pos2, text)
        !           575:   TextWidget ctx;
        !           576:   XtTextPosition pos1, pos2;
        !           577:   XtTextBlock *text;
        !           578: 
        !           579:  /* it is illegal to call this routine unless there is a valid line table!*/
        !           580: {
        !           581:     int i, line1, line2, visible, delta, error;
        !           582:     Position x, y;
        !           583:     Dimension realW, realH, width;
        !           584:     XtTextPosition startPos, endPos, updateFrom;
        !           585: 
        !           586:     /* the insertPos may not always be set to the right spot in XttextAppend */
        !           587:     if ((pos1 == ctx->text.insertPos) && 
        !           588:         ((*(ctx->text.source->editType))(ctx->text.source) == XttextAppend)) {
        !           589:       ctx->text.insertPos = GETLASTPOS;
        !           590:       pos2 = pos2 - pos1 + ctx->text.insertPos;
        !           591:       pos1 = ctx->text.insertPos;
        !           592:     }
        !           593:     updateFrom = (*(ctx->text.source->scan))(ctx->text.source, pos1, XtstWhiteSpace, XtsdLeft,
        !           594:            1, TRUE);
        !           595:     updateFrom = (*(ctx->text.source->scan))(ctx->text.source, updateFrom, XtstPositions, XtsdLeft,
        !           596:            1, TRUE);
        !           597:     startPos = max(updateFrom, ctx->text.lt.top);
        !           598:     visible = LineAndXYForPosition(ctx, startPos, &line1, &x, &y);
        !           599:     error = (*(ctx->text.source->replace))(ctx->text.source, pos1, pos2, text, &delta);
        !           600:     if (error) return error;
        !           601:     ctx->text.lastPos = GETLASTPOS;
        !           602:     if (ctx->text.lt.top >= ctx->text.lastPos) {
        !           603:        BuildLineTable(ctx, ctx->text.lastPos);
        !           604:        ClearWindow(ctx);
        !           605:        SetScrollBar(ctx);
        !           606:        return error;
        !           607:     }
        !           608:     if (delta < ctx->text.lastPos) {
        !           609:        for (i = 0; i < ctx->text.numranges; i++) {
        !           610:            if (ctx->text.updateFrom[i] > pos1)
        !           611:                ctx->text.updateFrom[i] += delta;
        !           612:            if (ctx->text.updateTo[i] >= pos1)
        !           613:                ctx->text.updateTo[i] += delta;
        !           614:        }
        !           615:     }
        !           616: 
        !           617:     line2 = LineForPosition(ctx, pos1);
        !           618:     /* 
        !           619:      * fixup all current line table entries to reflect edit.
        !           620:      * BUG: it is illegal to do arithmetic on positions. This code should
        !           621:      * either use scan or the source needs to provide a function for doing
        !           622:      * position arithmetic.
        !           623:     */
        !           624:     for (i = line2 + 1; i <= ctx->text.lt.lines; i++)
        !           625:        ctx->text.lt.info[i].position += delta;
        !           626: 
        !           627:     endPos = pos1;
        !           628:     /*
        !           629:      * Now process the line table and fixup in case edits caused
        !           630:      * changes in line breaks. If we are breaking on word boundaries,
        !           631:      * this code checks for moving words to and from lines.
        !           632:     */
        !           633:     if (visible) {
        !           634:        for (i = line1; i < ctx->text.lt.lines; i++) {/* fixup line table */
        !           635:            width = (ctx->text.options & resizeWidth) ? 9999 : ctx->core.width - x;
        !           636:            if (startPos <= ctx->text.lastPos) {
        !           637:                (*(ctx->text.sink->findPosition))(ctx, startPos, x,
        !           638:                        width, (ctx->text.options & wordBreak),
        !           639:                        &endPos, &realW, &realH);
        !           640:                if (!(ctx->text.options & wordBreak) && endPos < ctx->text.lastPos) {
        !           641:                    endPos = (*(ctx->text.source->scan))(ctx->text.source, startPos,
        !           642:                            XtstEOL, XtsdRight, 1, TRUE);
        !           643:                    if (endPos == startPos)
        !           644:                        endPos = ctx->text.lastPos + 1;
        !           645:                }
        !           646:                ctx->text.lt.info[i].endX = realW + x;
        !           647:                ctx->text.lt.info[i + 1].y = realH + ctx->text.lt.info[i].y;
        !           648:                if ((endPos > pos1) &&
        !           649:                        (endPos == ctx->text.lt.info[i + 1].position))
        !           650:                    break;
        !           651:                startPos = endPos;
        !           652:            }
        !           653:            if (startPos > ctx->text.lastPos)
        !           654:                ctx->text.lt.info[i + 1].endX = ctx->text.leftmargin;
        !           655:            ctx->text.lt.info[i + 1].position = startPos;
        !           656:            x = ctx->text.lt.info[i + 1].x;
        !           657:        }
        !           658:     }
        !           659:     if (delta >= ctx->text.lastPos)
        !           660:        endPos = ctx->text.lastPos;
        !           661:     if (delta >= ctx->text.lastPos || pos2 >= ctx->text.lt.top)
        !           662:        _XtTextNeedsUpdating(ctx, updateFrom, endPos);
        !           663:     SetScrollBar(ctx);
        !           664:     return error;
        !           665: }
        !           666: 
        !           667: 
        !           668: /*
        !           669:  * This routine will display text between two arbitrary source positions.
        !           670:  * In the event that this span contains highlighted text for the selection, 
        !           671:  * only that portion will be displayed highlighted.
        !           672:  */
        !           673: static void DisplayText(ctx, pos1, pos2)
        !           674:   TextWidget ctx;
        !           675:   XtTextPosition pos1, pos2;
        !           676:   /* it is illegal to call this routine unless there is a valid line table!*/
        !           677: {
        !           678:     Position x, y;
        !           679:     Dimension height;
        !           680:     int line, i, visible;
        !           681:     XtTextPosition startPos, endPos;
        !           682: 
        !           683:     if (pos1 < ctx->text.lt.top)
        !           684:        pos1 = ctx->text.lt.top;
        !           685:     if (pos2 > ctx->text.lastPos) 
        !           686:        pos2 = ctx->text.lastPos;
        !           687:     if (pos1 >= pos2) return;
        !           688:     visible = LineAndXYForPosition(ctx, pos1, &line, &x, &y);
        !           689:     if (!visible)
        !           690:        return;
        !           691:     startPos = pos1;
        !           692:     height = ctx->text.lt.info[1].y - ctx->text.lt.info[0].y;
        !           693:     for (i = line; i < ctx->text.lt.lines; i++) {
        !           694:        endPos = ctx->text.lt.info[i + 1].position;
        !           695:        if (endPos > pos2)
        !           696:            endPos = pos2;
        !           697:        if (endPos > startPos) {
        !           698:            if (x == ctx->text.leftmargin)
        !           699:                 (*(ctx->text.sink->clearToBackground))(ctx,
        !           700:                     0, y, ctx->text.leftmargin, height);
        !           701:            if (startPos >= ctx->text.s.right || endPos <= ctx->text.s.left) {
        !           702:                (*(ctx->text.sink->display))(ctx, x, y,
        !           703:                        startPos, endPos, FALSE);
        !           704:            } else if (startPos >= ctx->text.s.left && endPos <= ctx->text.s.right) {
        !           705:                (*(ctx->text.sink->display))(ctx, x, y,
        !           706:                        startPos, endPos, TRUE);
        !           707:            } else {
        !           708:                DisplayText(ctx, startPos, ctx->text.s.left);
        !           709:                DisplayText(ctx, max(startPos, ctx->text.s.left), 
        !           710:                        min(endPos, ctx->text.s.right));
        !           711:                DisplayText(ctx, ctx->text.s.right, endPos);
        !           712:            }
        !           713:        }
        !           714:        startPos = endPos;
        !           715:        height = ctx->text.lt.info[i + 1].y - ctx->text.lt.info[i].y;
        !           716:         (*(ctx->text.sink->clearToBackground))(ctx,
        !           717:            ctx->text.lt.info[i].endX, y, 999, height);
        !           718:        x = ctx->text.leftmargin;
        !           719:        y = ctx->text.lt.info[i + 1].y;
        !           720:        if ((endPos == pos2) && (endPos != ctx->text.lastPos))
        !           721:            break;
        !           722:     }
        !           723: }
        !           724: 
        !           725: /*
        !           726:  * This routine implements multi-click selection in a hardwired manner.
        !           727:  * It supports multi-click entity cycling (char, word, line, file) and mouse
        !           728:  * motion adjustment of the selected entitie (i.e. select a word then, with
        !           729:  * button still down, adjust wich word you really meant by moving the mouse).
        !           730:  * [NOTE: This routine is to be replaced by a set of procedures that
        !           731:  * will allows clients to implements a wide class of draw through and
        !           732:  * multi-click selection user interfaces.]
        !           733: */
        !           734: static void DoSelection (ctx, position, time, motion)
        !           735:   TextWidget ctx;
        !           736:   XtTextPosition position;
        !           737:   unsigned short time;
        !           738:   Boolean motion;
        !           739: {
        !           740:     int     delta;
        !           741:     XtTextPosition newLeft, newRight;
        !           742:     XtSelectType newType;
        !           743:     XtSelectType *sarray;
        !           744: 
        !           745:     delta = (time < ctx->text.lasttime) ?
        !           746:        ctx->text.lasttime - time : time - ctx->text.lasttime;
        !           747:     if (motion)
        !           748:        newType = ctx->text.s.type;
        !           749:     else {
        !           750:        if ((delta < 500) && ((position >= ctx->text.s.left)
        !           751:                    && (position <= ctx->text.s.right))) { /* multi-click event */
        !           752:            sarray = ctx->text.sarray;
        !           753:            for (sarray = ctx->text.sarray;
        !           754:                *sarray != XtselectNull && *sarray != ctx->text.s.type;
        !           755:                sarray++) ;
        !           756:            if (*sarray != XtselectNull) sarray++;
        !           757:            if (*sarray == XtselectNull) sarray = ctx->text.sarray;
        !           758:            newType = *sarray;
        !           759:        } else {                        /* single-click event */
        !           760:            newType = *(ctx->text.sarray);
        !           761:        }
        !           762:         ctx->text.lasttime = time;
        !           763:     }
        !           764:     switch (newType) {
        !           765:        case XtselectPosition: 
        !           766:             newLeft = newRight = position;
        !           767:            break;
        !           768:        case XtselectChar: 
        !           769:             newLeft = position;
        !           770:             newRight = (*(ctx->text.source->scan))(
        !           771:                     ctx->text.source, position, position, XtsdRight, 1, FALSE);
        !           772:            break;
        !           773:        case XtselectWord: 
        !           774:            newLeft = (*(ctx->text.source->scan))(
        !           775:                    ctx->text.source, position, XtstWhiteSpace, XtsdLeft, 1, FALSE);
        !           776:            newRight = (*(ctx->text.source->scan))(
        !           777:                    ctx->text.source, position, XtstWhiteSpace, XtsdRight, 1, FALSE);
        !           778:            break;
        !           779:        case XtselectLine: 
        !           780:        case XtselectParagraph:  /* need "para" scan mode to implement pargraph */
        !           781:            newLeft = (*(ctx->text.source->scan))(
        !           782:                    ctx->text.source, position, XtstEOL, XtsdLeft, 1, FALSE);
        !           783:            newRight = (*(ctx->text.source->scan))(
        !           784:                    ctx->text.source, position, XtstEOL, XtsdRight, 1, FALSE);
        !           785:            break;
        !           786:        case XtselectAll: 
        !           787:            newLeft = (*(ctx->text.source->scan))(
        !           788:                    ctx->text.source, position, XtstFile, XtsdLeft, 1, FALSE);
        !           789:            newRight = (*(ctx->text.source->scan))(
        !           790:                    ctx->text.source, position, XtstFile, XtsdRight, 1, FALSE);
        !           791:            break;
        !           792:     }
        !           793:     if ((newLeft != ctx->text.s.left) || (newRight != ctx->text.s.right)
        !           794:            || (newType != ctx->text.s.type)) {
        !           795:        _XtTextSetNewSelection(ctx, newLeft, newRight);
        !           796:        ctx->text.s.type = newType;
        !           797:        if (position - ctx->text.s.left < ctx->text.s.right - position)
        !           798:            ctx->text.insertPos = newLeft;
        !           799:        else 
        !           800:            ctx->text.insertPos = newRight;
        !           801:     }
        !           802:     if (!motion) { /* setup so we can freely mix select extend calls*/
        !           803:        ctx->text.origSel.type = ctx->text.s.type;
        !           804:        ctx->text.origSel.left = ctx->text.s.left;
        !           805:        ctx->text.origSel.right = ctx->text.s.right;
        !           806:        if (position >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
        !           807:            ctx->text.extendDir = XtsdRight;
        !           808:        else
        !           809:            ctx->text.extendDir = XtsdLeft;
        !           810:     }
        !           811: }
        !           812: 
        !           813: /*
        !           814:  * This routine implements extension of the currently selected text in
        !           815:  * the "current" mode (i.e. char word, line, etc.). It worries about
        !           816:  * extending from either end of the selection and handles the case when you
        !           817:  * cross through the "center" of the current selection (e.g. switch which
        !           818:  * end you are extending!).
        !           819:  * [NOTE: This routine will be replaced by a set of procedures that
        !           820:  * will allows clients to implements a wide class of draw through and
        !           821:  * multi-click selection user interfaces.]
        !           822: */
        !           823: static void ExtendSelection (ctx, position, motion)
        !           824:   TextWidget ctx;
        !           825:   XtTextPosition position;
        !           826:   Boolean motion;
        !           827: {
        !           828:     XtTextPosition newLeft, newRight;
        !           829:        
        !           830: 
        !           831:     if (!motion) {             /* setup for extending selection */
        !           832:        ctx->text.origSel.type = ctx->text.s.type;
        !           833:        ctx->text.origSel.left = ctx->text.s.left;
        !           834:        ctx->text.origSel.right = ctx->text.s.right;
        !           835:        if (position >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
        !           836:            ctx->text.extendDir = XtsdRight;
        !           837:        else
        !           838:            ctx->text.extendDir = XtsdLeft;
        !           839:     }
        !           840:     else /* check for change in extend direction */
        !           841:        if ((ctx->text.extendDir == XtsdRight && position < ctx->text.origSel.left) ||
        !           842:                (ctx->text.extendDir == XtsdLeft && position > ctx->text.origSel.right)) {
        !           843:            ctx->text.extendDir = (ctx->text.extendDir == XtsdRight)? XtsdLeft : XtsdRight;
        !           844:            _XtTextSetNewSelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
        !           845:        }
        !           846:     newLeft = ctx->text.s.left;
        !           847:     newRight = ctx->text.s.right;
        !           848:     switch (ctx->text.s.type) {
        !           849:        case XtselectPosition: 
        !           850:            if (ctx->text.extendDir == XtsdRight)
        !           851:                newRight = position;
        !           852:            else
        !           853:                newLeft = position;
        !           854:            break;
        !           855:        case XtselectWord: 
        !           856:            if (ctx->text.extendDir == XtsdRight)
        !           857:                newRight = position = (*(ctx->text.source->scan))(
        !           858:                        ctx->text.source, position, XtstWhiteSpace, XtsdRight, 1, FALSE);
        !           859:            else
        !           860:                newLeft = position = (*(ctx->text.source->scan))(
        !           861:                        ctx->text.source, position, XtstWhiteSpace, XtsdLeft, 1, FALSE);
        !           862:            break;
        !           863:         case XtselectLine:
        !           864:        case XtselectParagraph: /* need "para" scan mode to implement pargraph */
        !           865:            if (ctx->text.extendDir == XtsdRight)
        !           866:                newRight = position = (*(ctx->text.source->scan))(
        !           867:                        ctx->text.source, position, XtstEOL, XtsdRight, 1, TRUE);
        !           868:            else
        !           869:                newLeft = position = (*(ctx->text.source->scan))(
        !           870:                        ctx->text.source, position, XtstEOL, XtsdLeft, 1, FALSE);
        !           871:            break;
        !           872:        case XtselectAll: 
        !           873:            position = ctx->text.insertPos;
        !           874:            break;
        !           875:     }
        !           876:     _XtTextSetNewSelection(ctx, newLeft, newRight);
        !           877:     ctx->text.insertPos = position;
        !           878: }
        !           879: 
        !           880: 
        !           881: /*
        !           882:  * Clear the window to background color.
        !           883: */
        !           884: static ClearWindow (ctx)
        !           885:   TextWidget ctx;
        !           886: {
        !           887:     (*(ctx->text.sink->clearToBackground))(ctx, 0, 0, ctx->core.width, ctx->core.height);
        !           888: }
        !           889: 
        !           890: 
        !           891: /*
        !           892:  * Internal redisplay entire window.
        !           893: */
        !           894: DisplayTextWindow (w)
        !           895:   Widget w;
        !           896: {
        !           897:     TextWidget ctx = (TextWidget) w;
        !           898:     ClearWindow(ctx);
        !           899:     BuildLineTable(ctx, ctx->text.lt.top);
        !           900:     _XtTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
        !           901:     SetScrollBar(ctx);
        !           902: }
        !           903: 
        !           904: /*
        !           905:  * This routine checks to see if the window should be resized (grown or
        !           906:  * shrunk) or scrolled then text to be painted overflows to the right or
        !           907:  * the bottom of the window. It is used by the keyboard input routine.
        !           908: */
        !           909: CheckResizeOrOverflow(ctx)
        !           910:   TextWidget ctx;
        !           911: {
        !           912:     XtTextPosition posToCheck;
        !           913:     int     visible, line, width;
        !           914:     XtWidgetGeometry rbox;
        !           915:     if (ctx->text.options & resizeWidth) {
        !           916:        width = 0;
        !           917:        for (line=0 ; line<ctx->text.lt.lines ; line++)
        !           918:            if (width < ctx->text.lt.info[line].endX)
        !           919:                width = ctx->text.lt.info[line].endX;
        !           920:        width += ctx->text.leftmargin;
        !           921:        if (width > ctx->core.width) {
        !           922:            rbox.request_mode = CWWidth;
        !           923:            rbox.width = width;
        !           924:            if ( XtMakeGeometryRequest(ctx, &rbox, NULL) != XtGeometryNo) {
        !           925:              ctx->core.width = rbox.width;
        !           926:              }
        !           927:        }
        !           928:     }
        !           929:     if ((ctx->text.options & resizeHeight) || (ctx->text.options & scrollOnOverflow)) {
        !           930:        if (ctx->text.options & scrollOnOverflow)
        !           931:            posToCheck = ctx->text.insertPos;
        !           932:        else
        !           933:            posToCheck = ctx->text.lastPos;
        !           934:        visible = IsPositionVisible(ctx, posToCheck);
        !           935:        if (visible)
        !           936:            line = LineForPosition(ctx, posToCheck);
        !           937:        else
        !           938:            line = ctx->text.lt.lines;
        !           939:        if ((ctx->text.options & scrollOnOverflow) && (line + 1 > ctx->text.lt.lines)) {
        !           940:            BuildLineTable(ctx, ctx->text.lt.info[1].position);
        !           941:            XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), 
        !           942:                      ctx->text.gc, (Position)ctx->text.leftmargin, 
        !           943:                      ctx->text.lt.info[1].y, 9999, 9999,
        !           944:                      (Position)ctx->text.leftmargin, ctx->text.lt.info[0].y);
        !           945:        }
        !           946:        else
        !           947:            if ((ctx->text.options & resizeHeight) && (line + 1 != ctx->text.lt.lines)) {
        !           948:                rbox.request_mode = CWHeight;
        !           949:                rbox.height = (*(ctx->text.sink->maxHeight))
        !           950:                                (ctx, line + 1) + (2*yMargin)+2;
        !           951:                if (XtMakeGeometryRequest(ctx, &rbox, NULL) != XtGeometryNo) {
        !           952:                        ctx->core.width = rbox.height ;
        !           953:              };
        !           954:            }
        !           955:     }
        !           956: }
        !           957: 
        !           958: /*
        !           959:  * This routine is used to perform various selection functions. The goal is
        !           960:  * to be able to specify all the more popular forms of draw-through and
        !           961:  * multi-click selection user interfaces from the outside.
        !           962:  */
        !           963: void AlterSelection (ctx, mode, action)
        !           964:     TextWidget     ctx;
        !           965:     SelectionMode   mode;      /* {XtsmTextSelect, XtsmTextExtend}               */
        !           966:     SelectionAction action;    /* {XtactionStart, XtactionAdjust, XtactionEnd} */
        !           967: {
        !           968:     XtTextPosition position;
        !           969:     char   *ptr;
        !           970: 
        !           971:     position = PositionForXY (ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
        !           972:     if (action == XtactionStart) {
        !           973:        switch (mode) {
        !           974:        case XtsmTextSelect: 
        !           975:            DoSelection (ctx, position, ctx->text.time, FALSE);
        !           976:            break;
        !           977:        case XtsmTextExtend: 
        !           978:            ExtendSelection (ctx, position, FALSE);
        !           979:            break;
        !           980:        }
        !           981:     }
        !           982:     else {
        !           983:        switch (mode) {
        !           984:        case XtsmTextSelect: 
        !           985:            DoSelection (ctx, position, ctx->text.time, TRUE);
        !           986:            break;
        !           987:        case XtsmTextExtend: 
        !           988:            ExtendSelection (ctx, position, TRUE);
        !           989:            break;
        !           990:        }
        !           991:     }
        !           992:     if (action == XtactionEnd && ctx->text.s.left < ctx->text.s.right) {
        !           993:        ptr = _XtTextGetText (ctx, ctx->text.s.left, ctx->text.s.right);
        !           994:        XStoreBuffer (XtDisplay(ctx), ptr, min (strlen (ptr), MAXCUT), 0);
        !           995:        XtFree (ptr);
        !           996:     }
        !           997: }
        !           998: 
        !           999: /*
        !          1000:  * This routine processes all "expose region" XEvents. In general, its job
        !          1001:  * is to the best job at minimal re-paint of the text, displayed in the
        !          1002:  * window, that it can.
        !          1003: */
        !          1004: static void ProcessExposeRegion(w, event)
        !          1005:   Widget w;
        !          1006:   XEvent *event;
        !          1007: {
        !          1008:     TextWidget ctx = (TextWidget) w;
        !          1009:     XtTextPosition pos1, pos2, resultend;
        !          1010:     int line;
        !          1011:     int x = event->xexpose.x;
        !          1012:     int y = event->xexpose.y;
        !          1013:     int width = event->xexpose.width;
        !          1014:     int height = event->xexpose.height;
        !          1015:     LineTableEntryPtr info;
        !          1016: 
        !          1017:    _XtTextPrepareToUpdate(ctx);
        !          1018:     if (x < ctx->text.leftmargin) /* stomp on caret tracks */
        !          1019:         (*(ctx->text.sink->clearToBackground))(ctx, x, y, width, height);
        !          1020:    /* figure out starting line that was exposed */
        !          1021:     line = LineForPosition(ctx, PositionForXY(ctx, x, y));
        !          1022:     while (line < ctx->text.lt.lines && ctx->text.lt.info[line + 1].y < y)
        !          1023:        line++;
        !          1024:     while (line < ctx->text.lt.lines) {
        !          1025:        info = &(ctx->text.lt.info[line]);
        !          1026:        if (info->y >= y + height)
        !          1027:            break;
        !          1028:        (*(ctx->text.sink->resolve))(ctx, 
        !          1029:                                 info->position, info->x,
        !          1030:                                x - info->x, &pos1, &resultend);
        !          1031:        (*(ctx->text.sink->resolve))(ctx, 
        !          1032:                                 info->position, info->x,
        !          1033:                                x + width - info->x, &pos2, 
        !          1034:                                 &resultend);
        !          1035:        pos2 = (*(ctx->text.source->scan))(ctx->text.source, pos2, XtstPositions, 
        !          1036:                                       XtsdRight, 1, TRUE);
        !          1037:        _XtTextNeedsUpdating(ctx, pos1, pos2);
        !          1038:        line++;
        !          1039:     }
        !          1040:     _XtTextExecuteUpdate(ctx);
        !          1041: }
        !          1042: 
        !          1043: 
        !          1044: static int oldinsert = -1;
        !          1045: 
        !          1046: /*
        !          1047:  * This routine does all setup required to syncronize batched screen updates
        !          1048: */
        !          1049: int _XtTextPrepareToUpdate(ctx)
        !          1050:   TextWidget ctx;
        !          1051: {
        !          1052:     if (oldinsert < 0) {
        !          1053:        InsertCursor(ctx, XtisOff);
        !          1054:        ctx->text.numranges = 0;
        !          1055:        ctx->text.showposition = FALSE;
        !          1056:        oldinsert = ctx->text.insertPos;
        !          1057:     }
        !          1058: }
        !          1059: 
        !          1060: 
        !          1061: /*
        !          1062:  * This is a private utility routine used by _XtTextExecuteUpdate. It
        !          1063:  * processes all the outstanding update requests and merges update
        !          1064:  * ranges where possible.
        !          1065: */
        !          1066: static FlushUpdate(ctx)
        !          1067:   TextWidget ctx;
        !          1068: {
        !          1069:     int     i, w;
        !          1070:     XtTextPosition updateFrom, updateTo;
        !          1071:     while (ctx->text.numranges > 0) {
        !          1072:        updateFrom = ctx->text.updateFrom[0];
        !          1073:        w = 0;
        !          1074:        for (i=1 ; i<ctx->text.numranges ; i++) {
        !          1075:            if (ctx->text.updateFrom[i] < updateFrom) {
        !          1076:                updateFrom = ctx->text.updateFrom[i];
        !          1077:                w = i;
        !          1078:            }
        !          1079:        }
        !          1080:        updateTo = ctx->text.updateTo[w];
        !          1081:        ctx->text.numranges--;
        !          1082:        ctx->text.updateFrom[w] = ctx->text.updateFrom[ctx->text.numranges];
        !          1083:        ctx->text.updateTo[w] = ctx->text.updateTo[ctx->text.numranges];
        !          1084:        for (i=ctx->text.numranges-1 ; i>=0 ; i--) {
        !          1085:            while (ctx->text.updateFrom[i] <= updateTo && i < ctx->text.numranges) {
        !          1086:                updateTo = ctx->text.updateTo[i];
        !          1087:                ctx->text.numranges--;
        !          1088:                ctx->text.updateFrom[i] = ctx->text.updateFrom[ctx->text.numranges];
        !          1089:                ctx->text.updateTo[i] = ctx->text.updateTo[ctx->text.numranges];
        !          1090:            }
        !          1091:        }
        !          1092:        DisplayText(ctx, updateFrom, updateTo);
        !          1093:     }
        !          1094: }
        !          1095: 
        !          1096: 
        !          1097: /*
        !          1098:  * This is a private utility routine used by _XtTextExecuteUpdate. This routine
        !          1099:  * worries about edits causing new data or the insertion point becoming
        !          1100:  * invisible (off the screen). Currently it always makes it visible by
        !          1101:  * scrolling. It probably needs generalization to allow more options.
        !          1102: */
        !          1103: _XtTextShowPosition(ctx)
        !          1104:   TextWidget ctx;
        !          1105: {
        !          1106:     XtTextPosition top, first, second;
        !          1107:     if (ctx->text.insertPos < ctx->text.lt.top ||
        !          1108:        ctx->text.insertPos >= ctx->text.lt.info[ctx->text.lt.lines].position) {
        !          1109:        if (ctx->text.lt.lines > 0 && (ctx->text.insertPos < ctx->text.lt.top 
        !          1110:            || ctx->text.lt.info[ctx->text.lt.lines].position <= ctx->text.lastPos)) {
        !          1111:            first = ctx->text.lt.top;
        !          1112:            second = ctx->text.lt.info[1].position;
        !          1113:            if (ctx->text.insertPos < first)
        !          1114:                top = (*(ctx->text.source->scan))(
        !          1115:                        ctx->text.source, ctx->text.insertPos, XtstEOL,
        !          1116:                        XtsdLeft, 1, FALSE);
        !          1117:            else
        !          1118:                top = (*(ctx->text.source->scan))(
        !          1119:                        ctx->text.source, ctx->text.insertPos, XtstEOL,
        !          1120:                        XtsdLeft, ctx->text.lt.lines, FALSE);
        !          1121:            BuildLineTable(ctx, top);
        !          1122:            while (ctx->text.insertPos >= ctx->text.lt.info[ctx->text.lt.lines].position) {
        !          1123:                if (ctx->text.lt.info[ctx->text.lt.lines].position > ctx->text.lastPos)
        !          1124:                    break;
        !          1125:                BuildLineTable(ctx, ctx->text.lt.info[1].position);
        !          1126:            }
        !          1127:            if (ctx->text.lt.top == second) {
        !          1128:                BuildLineTable(ctx, first);
        !          1129:                _XtTextScroll(ctx, 1);
        !          1130:            } else if (ctx->text.lt.info[1].position == first) {
        !          1131:                BuildLineTable(ctx, first);
        !          1132:                _XtTextScroll(ctx, -1);
        !          1133:            } else {
        !          1134:                ctx->text.numranges = 0;
        !          1135:                if (ctx->text.lt.top != first)
        !          1136:                    DisplayTextWindow(ctx);
        !          1137:            }
        !          1138:        }
        !          1139:     }
        !          1140: }
        !          1141: 
        !          1142: 
        !          1143: 
        !          1144: /*
        !          1145:  * This routine causes all batched screen updates to be performed
        !          1146: */
        !          1147: _XtTextExecuteUpdate(ctx)
        !          1148:   TextWidget ctx;
        !          1149: {
        !          1150:     if (oldinsert >= 0) {
        !          1151:        if (oldinsert != ctx->text.insertPos || ctx->text.showposition)
        !          1152:            _XtTextShowPosition(ctx);
        !          1153:        FlushUpdate(ctx);
        !          1154:        InsertCursor(ctx, XtisOn);
        !          1155:        oldinsert = -1;
        !          1156:     }
        !          1157: }
        !          1158: 
        !          1159: 
        !          1160: static void TextDestroy(ctx)
        !          1161: TextWidget ctx;
        !          1162: {
        !          1163:     if (ctx->text.dialog)
        !          1164:        (void) XtDestroyWidget(ctx->text.dialog);
        !          1165:     if (ctx->text.outer)
        !          1166:        (void) XtDestroyWidget(ctx->text.outer);
        !          1167:     if (ctx->text.sbar)
        !          1168:        (void) XtDestroyWidget(ctx->text.sbar);
        !          1169:     XtFree((char *)ctx->text.updateFrom);
        !          1170:     XtFree((char *)ctx->text.updateTo);
        !          1171: }
        !          1172: 
        !          1173: 
        !          1174: static void Resize(w)
        !          1175:     Widget          w;
        !          1176: {
        !          1177:     TextWidget ctx = (TextWidget) w;
        !          1178:     _XtTextPrepareToUpdate(ctx);
        !          1179:     ForceBuildLineTable(ctx);
        !          1180:     _XtTextExecuteUpdate(ctx);
        !          1181: }
        !          1182: 
        !          1183: 
        !          1184: /*
        !          1185:  * This routine allow the application program to Set attributes.
        !          1186:  */
        !          1187: 
        !          1188: Boolean XtTextSetValues(current, request, new, last)
        !          1189: Widget current, request, new;
        !          1190: Boolean last;
        !          1191: {
        !          1192:     TextWidget oldtw = (TextWidget) current;
        !          1193:     TextWidget newtw = (TextWidget) new;
        !          1194:     Boolean    redisplay = FALSE;
        !          1195: 
        !          1196:     _XtTextPrepareToUpdate(oldtw);
        !          1197:     
        !          1198:     if (oldtw->text.sink != newtw->text.sink)
        !          1199:        redisplay = TRUE;
        !          1200: 
        !          1201:     if (oldtw->text.source != newtw->text.source) {
        !          1202:        ForceBuildLineTable(oldtw);
        !          1203:        redisplay = TRUE;
        !          1204:     }
        !          1205:     if (oldtw->text.insertPos != newtw->text.insertPos)
        !          1206:        oldtw->text.showposition = TRUE;
        !          1207: 
        !          1208:     if (oldtw->text.lt.top != newtw->text.lt.top)
        !          1209:        redisplay = TRUE;
        !          1210: 
        !          1211:     if (oldtw->text.leftmargin != newtw->text.leftmargin)
        !          1212:        redisplay = TRUE;
        !          1213: 
        !          1214:     if (redisplay) 
        !          1215:        DisplayTextWindow(oldtw);
        !          1216:     _XtTextExecuteUpdate(oldtw);
        !          1217:     return (FALSE);  /*  this needs looking at! */
        !          1218: }
        !          1219: 
        !          1220: 
        !          1221: 
        !          1222: void XtTextDisplay (w)
        !          1223:     Widget w;
        !          1224: {
        !          1225:     TextWidget ctx = (TextWidget) w;;
        !          1226: 
        !          1227:        _XtTextPrepareToUpdate(ctx);
        !          1228:        DisplayTextWindow(ctx);
        !          1229:        _XtTextExecuteUpdate(ctx);
        !          1230: }
        !          1231: 
        !          1232: /*******************************************************************
        !          1233: The following routines provide procedural interfaces to Text window state
        !          1234: setting and getting. They need to be redone so than the args code can use
        !          1235: them. I suggest we create a complete set that takes the context as an
        !          1236: argument and then have the public version lookup the context and call the
        !          1237: internal one. The major value of this set is that they have actual application
        !          1238: clients and therefore the functionality provided is required for any future
        !          1239: version of Text.
        !          1240: ********************************************************************/
        !          1241: 
        !          1242: void XtTextSetSelectionArray(w, sarray)
        !          1243:     Widget w;
        !          1244:     XtSelectType *sarray;
        !          1245: {
        !          1246:     TextWidget ctx = (TextWidget) w;
        !          1247:     XtSelectType *s2;
        !          1248: 
        !          1249:     s2 = ctx->text.sarray;
        !          1250:     while (XtselectNull != (*s2++ = *sarray++)) ;
        !          1251: }
        !          1252: 
        !          1253: void XtTextSetLastPos (w, lastPos)
        !          1254:     Widget w;
        !          1255:     XtTextPosition lastPos;
        !          1256: {
        !          1257:     TextWidget  ctx = (TextWidget) w;
        !          1258: 
        !          1259:        _XtTextPrepareToUpdate(ctx);
        !          1260:        (*(ctx->text.source->setLastPos))(ctx->text.source, lastPos);
        !          1261:        ctx->text.lastPos = GETLASTPOS;
        !          1262:        ForceBuildLineTable(ctx);
        !          1263:        DisplayTextWindow(ctx);
        !          1264:        _XtTextExecuteUpdate(ctx);
        !          1265: }
        !          1266: 
        !          1267: 
        !          1268: void XtTextGetSelectionPos(w, left, right)
        !          1269:   Widget w;
        !          1270:   XtTextPosition *left, *right;
        !          1271: {
        !          1272:     TextWidget ctx = (TextWidget) w;
        !          1273:     *left = ctx->text.s.left;
        !          1274:     *right = ctx->text.s.right;
        !          1275: }
        !          1276: 
        !          1277: 
        !          1278: void XtTextNewSource(w, source, startPos)
        !          1279:     Widget w;
        !          1280:     XtTextSource   *source;
        !          1281:     XtTextPosition startPos;
        !          1282: {
        !          1283:     TextWidget ctx = (TextWidget) w;
        !          1284: 
        !          1285:        ctx->text.source = source;
        !          1286:        ctx->text.lt.top = startPos;
        !          1287:        ctx->text.s.left = ctx->text.s.right = 0;
        !          1288:        ctx->text.insertPos = startPos;
        !          1289:        ctx->text.lastPos = GETLASTPOS;
        !          1290:        ForceBuildLineTable(ctx);
        !          1291:        _XtTextPrepareToUpdate(ctx);
        !          1292:        DisplayTextWindow(ctx);
        !          1293:        _XtTextExecuteUpdate(ctx);
        !          1294: }
        !          1295: 
        !          1296: /*
        !          1297:  * This public routine deletes the text from startPos to endPos in a source and
        !          1298:  * then inserts, at startPos, the text that was passed. As a side effect it
        !          1299:  * "invalidates" that portion of the displayed text (if any), so that things
        !          1300:  * will be repainted properly.
        !          1301:  */
        !          1302: int XtTextReplace(w, startPos, endPos, text)
        !          1303:     Widget         w;
        !          1304:     XtTextPosition  startPos, endPos;
        !          1305:     XtTextBlock     *text;
        !          1306: {
        !          1307:     TextWidget ctx = (TextWidget) w;
        !          1308:     int result;
        !          1309:     result = EDITERROR;
        !          1310:        _XtTextPrepareToUpdate(ctx);
        !          1311:        result = ReplaceText(ctx, startPos, endPos, text);
        !          1312:        _XtTextExecuteUpdate(ctx);
        !          1313:     return result;
        !          1314: }
        !          1315: 
        !          1316: 
        !          1317: XtTextPosition XtTextTopPosition(w)
        !          1318:     Widget         w;
        !          1319: {
        !          1320:     TextWidget ctx = (TextWidget) w;
        !          1321: 
        !          1322:      return ctx->text.lt.top;
        !          1323: }
        !          1324: 
        !          1325: 
        !          1326: void XtTextSetInsertionPoint(w, position)
        !          1327:     Widget         w;
        !          1328:     XtTextPosition position;
        !          1329: {
        !          1330:     TextWidget ctx = (TextWidget) w;
        !          1331: 
        !          1332:        _XtTextPrepareToUpdate(ctx);
        !          1333:        ctx->text.insertPos = position;
        !          1334:        ctx->text.showposition = TRUE;
        !          1335:        _XtTextExecuteUpdate(ctx);
        !          1336: }
        !          1337: 
        !          1338: 
        !          1339: XtTextPosition XtTextGetInsertionPoint(w)
        !          1340:     Widget         w;
        !          1341: {
        !          1342:     TextWidget ctx = (TextWidget) w;
        !          1343: 
        !          1344:     return(ctx->text.insertPos);
        !          1345: }
        !          1346: 
        !          1347: 
        !          1348: void XtTextUnsetSelection(w)
        !          1349:     Widget         w;
        !          1350: {
        !          1351:     TextWidget ctx = (TextWidget) w;
        !          1352: 
        !          1353:        _XtTextPrepareToUpdate(ctx);
        !          1354:        _XtTextSetNewSelection(ctx, zeroPosition, zeroPosition);
        !          1355:        _XtTextExecuteUpdate(ctx);
        !          1356: }
        !          1357: 
        !          1358: 
        !          1359: void XtTextChangeOptions(w, options)
        !          1360:     Widget         w;
        !          1361:     int    options;
        !          1362: {
        !          1363:     TextWidget ctx = (TextWidget) w;
        !          1364: 
        !          1365:        ctx->text.options = options;
        !          1366: }
        !          1367: 
        !          1368: 
        !          1369: int XtTextGetOptions(w)
        !          1370:     Widget         w;
        !          1371: {
        !          1372:     TextWidget ctx = (TextWidget) w;
        !          1373: 
        !          1374:        return ctx->text.options;
        !          1375: }
        !          1376: 
        !          1377: void XtTextSetNewSelection (w, left, right)
        !          1378:     Widget         w;
        !          1379:     XtTextPosition left, right;
        !          1380: {
        !          1381:     TextWidget ctx = (TextWidget) w;
        !          1382: 
        !          1383:        _XtTextPrepareToUpdate(ctx);
        !          1384:         _XtTextSetNewSelection(ctx, left, right);
        !          1385:        _XtTextExecuteUpdate(ctx);
        !          1386: }
        !          1387: 
        !          1388: void XtTextInvalidate(w, from, to)
        !          1389:     Widget         w;
        !          1390:     XtTextPosition from,to;
        !          1391: {
        !          1392:     TextWidget ctx = (TextWidget) w;
        !          1393: 
        !          1394:         ctx->text.lastPos = (*(ctx->text.source->getLastPos))(ctx->text.source);
        !          1395:         _XtTextPrepareToUpdate(ctx);
        !          1396:         _XtTextNeedsUpdating(ctx, from, to);
        !          1397:         ForceBuildLineTable(ctx);
        !          1398:         _XtTextExecuteUpdate(ctx);
        !          1399: }
        !          1400: 
        !          1401: 
        !          1402: /* Returns the window actually containing the text (which is not the same
        !          1403:    as the given window if the text window has scrollbars.) */
        !          1404: 
        !          1405: Window XtTextGetInnerWindow(w)
        !          1406:     Widget         w;
        !          1407: {
        !          1408:     TextWidget ctx = (TextWidget) w;
        !          1409:        return XtWindow(ctx);
        !          1410: }
        !          1411: 
        !          1412: /* The following used to be a separate file, TextActs.c, but
        !          1413:    is included here because textActionsTable can't be external
        !          1414:    to the file declaring textClassRec */
        !          1415: 
        !          1416: /* Misc. routines */
        !          1417: void TextAcceptFocus(w)
        !          1418:     Widget          w;
        !          1419: {
        !          1420:     TextWidget ctx = (TextWidget) w;
        !          1421:     if (!ctx->text.hasfocus)
        !          1422:        XSetInputFocus(XtDisplay(ctx), XtWindow(ctx), 
        !          1423:          RevertToPointerRoot,  CurrentTime);
        !          1424: }
        !          1425: 
        !          1426: static StartAction(ctx, event)
        !          1427:    TextWidget ctx;
        !          1428:    XEvent *event;
        !          1429: {
        !          1430:     _XtTextPrepareToUpdate(ctx);
        !          1431:     if (event->type == ButtonPress) TextAcceptFocus(ctx);
        !          1432: /* this code is wrong if actions bound to non-button events! */
        !          1433:     ctx->text.time = event->xbutton.time;
        !          1434:     ctx->text.ev_x = event->xbutton.x;
        !          1435:     ctx->text.ev_y = event->xbutton.y;
        !          1436: }
        !          1437: 
        !          1438: static EndAction(ctx)
        !          1439:    TextWidget ctx;
        !          1440: {
        !          1441:     CheckResizeOrOverflow(ctx);
        !          1442:     _XtTextExecuteUpdate(ctx);
        !          1443: }
        !          1444: 
        !          1445: /*ARGSUSED*/
        !          1446: static DoFeep(ctx)
        !          1447:     TextWidget ctx;
        !          1448: {
        !          1449:     XBell(XtDisplay(ctx), 50);
        !          1450: }
        !          1451: 
        !          1452: static DeleteOrKill(ctx, from, to, kill)
        !          1453:     TextWidget    ctx;
        !          1454:     XtTextPosition from, to;
        !          1455:     Boolean       kill;
        !          1456: {
        !          1457:     XtTextBlock text;
        !          1458:     char *ptr;
        !          1459: 
        !          1460:     if (kill && from < to) {
        !          1461:        ptr = _XtTextGetText(ctx, from, to);
        !          1462:        XStoreBuffer(XtDisplay(ctx), ptr, strlen(ptr), 1);
        !          1463:        XtFree(ptr);
        !          1464:     }
        !          1465:     text.length = 0;
        !          1466:     if (ReplaceText(ctx, from, to, &text)) {
        !          1467:        XBell(XtDisplay(ctx), 50);
        !          1468:        return;
        !          1469:     }
        !          1470:     _XtTextSetNewSelection(ctx, from, from);
        !          1471:     ctx->text.insertPos = from;
        !          1472:     ctx->text.showposition = TRUE;
        !          1473: }
        !          1474: 
        !          1475: 
        !          1476: StuffFromBuffer(ctx, buffer)
        !          1477:   TextWidget ctx;
        !          1478:   int buffer;
        !          1479: {
        !          1480:     extern char *XFetchBuffer();
        !          1481:     XtTextBlock text;
        !          1482:     text.ptr = XFetchBuffer(XtDisplay(ctx), &(text.length), buffer);
        !          1483:     if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
        !          1484:        XBell(XtDisplay(ctx), 50);
        !          1485:        return;
        !          1486:     }
        !          1487:     ctx->text.insertPos = ctx->text.source->scan(ctx->text.source, 
        !          1488:        ctx->text.insertPos, XtstPositions, XtsdRight, text.length, TRUE);
        !          1489:     _XtTextSetNewSelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
        !          1490:     XtFree(text.ptr);
        !          1491: }
        !          1492: 
        !          1493: 
        !          1494: static UnKill(ctx, event)
        !          1495:   TextWidget ctx;
        !          1496:    XEvent *event;
        !          1497: {
        !          1498:    StartAction(ctx, event);
        !          1499:     StuffFromBuffer(ctx, 1);
        !          1500:    EndAction(ctx);
        !          1501: }
        !          1502: 
        !          1503: static Stuff(ctx, event)
        !          1504:   TextWidget ctx;
        !          1505:    XEvent *event;
        !          1506: {
        !          1507:    StartAction(ctx, event);
        !          1508:     StuffFromBuffer(ctx, 0);
        !          1509:    EndAction(ctx);
        !          1510: }
        !          1511: 
        !          1512: 
        !          1513: static XtTextPosition NextPosition(ctx, position, kind, direction)
        !          1514:     TextWidget ctx;
        !          1515:     XtTextPosition position;
        !          1516:     ScanType kind;
        !          1517:     ScanDirection direction;
        !          1518: {
        !          1519:     XtTextPosition pos;
        !          1520: 
        !          1521:      pos = ctx->text.source->scan(
        !          1522:            ctx->text.source, position, kind, direction, 1, FALSE);
        !          1523:      if (pos == ctx->text.insertPos) 
        !          1524:          pos = ctx->text.source->scan(
        !          1525:             ctx->text.source, position, kind, direction, 2, FALSE);
        !          1526:      return pos;
        !          1527: }
        !          1528: 
        !          1529: /* routines for moving around */
        !          1530: 
        !          1531: static MoveForwardChar(ctx, event)
        !          1532:    TextWidget ctx;
        !          1533:    XEvent *event;
        !          1534: {
        !          1535:    StartAction(ctx, event);
        !          1536:    ctx->text.insertPos = ctx->text.source->scan(
        !          1537:         ctx->text.source, ctx->text.insertPos, XtstPositions, XtsdRight, 1, 
        !          1538:        TRUE);
        !          1539:    EndAction(ctx);
        !          1540: }
        !          1541: 
        !          1542: static MoveBackwardChar(ctx, event)
        !          1543:     TextWidget ctx;
        !          1544:    XEvent *event;
        !          1545: {
        !          1546:    StartAction(ctx, event);
        !          1547:     ctx->text.insertPos = ctx->text.source->scan(
        !          1548:             ctx->text.source, ctx->text.insertPos, XtstPositions, XtsdLeft,
        !          1549:            1, TRUE);
        !          1550:    EndAction(ctx);
        !          1551: }
        !          1552: 
        !          1553: static MoveForwardWord(ctx, event)
        !          1554:     TextWidget ctx;
        !          1555:    XEvent *event;
        !          1556: {
        !          1557:    StartAction(ctx, event);
        !          1558:     ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos, 
        !          1559:       XtstWhiteSpace, XtsdRight);
        !          1560:    EndAction(ctx);
        !          1561: }
        !          1562: 
        !          1563: static MoveBackwardWord(ctx, event)
        !          1564:     TextWidget ctx;
        !          1565:    XEvent *event;
        !          1566: {
        !          1567:    StartAction(ctx, event);
        !          1568:     ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos, 
        !          1569:       XtstWhiteSpace, XtsdLeft);
        !          1570:    EndAction(ctx);
        !          1571: }
        !          1572: 
        !          1573: static MoveBackwardParagraph(ctx, event)
        !          1574:     TextWidget ctx;
        !          1575:    XEvent *event;
        !          1576: {
        !          1577:    StartAction(ctx, event);
        !          1578:     ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos, 
        !          1579:       XtstEOL, XtsdLeft);
        !          1580:    EndAction(ctx);
        !          1581: }
        !          1582: 
        !          1583: static MoveForwardParagraph(ctx, event)
        !          1584:     TextWidget ctx;
        !          1585:    XEvent *event;
        !          1586: {
        !          1587:    StartAction(ctx, event);
        !          1588:     ctx->text.insertPos = NextPosition(ctx, ctx->text.insertPos, 
        !          1589:       XtstEOL, XtsdRight);
        !          1590:    EndAction(ctx);
        !          1591: }
        !          1592: 
        !          1593: 
        !          1594: static MoveToLineStart(ctx, event)
        !          1595:   TextWidget ctx;
        !          1596:    XEvent *event;
        !          1597: {
        !          1598:     int line;
        !          1599:    StartAction(ctx, event);
        !          1600:     _XtTextShowPosition(ctx);
        !          1601:     line = LineForPosition(ctx, ctx->text.insertPos);
        !          1602:     ctx->text.insertPos = ctx->text.lt.info[line].position;
        !          1603:    EndAction(ctx);
        !          1604: }
        !          1605: 
        !          1606: static MoveToLineEnd(ctx, event)
        !          1607:   TextWidget ctx;
        !          1608:    XEvent *event;
        !          1609: {
        !          1610:     int line;
        !          1611:     XtTextPosition next;
        !          1612:    StartAction(ctx, event);
        !          1613:     _XtTextShowPosition(ctx);
        !          1614:     line = LineForPosition(ctx, ctx->text.insertPos);
        !          1615:     next = ctx->text.lt.info[line+1].position;
        !          1616:     if (next > ctx->text.lastPos)
        !          1617:        next = ctx->text.lastPos;
        !          1618:     else
        !          1619:        next = ctx->text.source->scan(ctx->text.source, next, XtstPositions, 
        !          1620:          XtsdLeft, 1, TRUE);
        !          1621:     ctx->text.insertPos = next;
        !          1622:    EndAction(ctx);
        !          1623: }
        !          1624: 
        !          1625: 
        !          1626: static int LineLastWidth = 0;
        !          1627: static XtTextPosition LineLastPosition = 0;
        !          1628: 
        !          1629: static MoveNextLine(ctx, event)
        !          1630:   TextWidget ctx;
        !          1631:    XEvent *event;
        !          1632: {
        !          1633:     int     width, width2, height, line;
        !          1634:     XtTextPosition position, maxp;
        !          1635:    StartAction(ctx, event);
        !          1636:     _XtTextShowPosition(ctx);
        !          1637:     line = LineForPosition(ctx, ctx->text.insertPos);
        !          1638:     if (line == ctx->text.lt.lines - 1) {
        !          1639:        _XtTextScroll(ctx, 1);
        !          1640:        line = LineForPosition(ctx, ctx->text.insertPos);
        !          1641:     }
        !          1642:     if (LineLastPosition == ctx->text.insertPos)
        !          1643:        width = LineLastWidth;
        !          1644:     else
        !          1645:        ctx->text.sink->findDistance(ctx,
        !          1646:                ctx->text.lt.info[line].position, ctx->text.lt.info[line].x,
        !          1647:                ctx->text.insertPos, &width, &position, &height);
        !          1648:     line++;
        !          1649:     if (ctx->text.lt.info[line].position > ctx->text.lastPos) {
        !          1650:        ctx->text.insertPos = ctx->text.lastPos;
        !          1651:        EndAction(ctx);
        !          1652:        return;
        !          1653:     }
        !          1654:     ctx->text.sink->findPosition(ctx,
        !          1655:            ctx->text.lt.info[line].position, ctx->text.lt.info[line].x,
        !          1656:            width, FALSE, &position, &width2, &height);
        !          1657:     maxp = ctx->text.source->scan(ctx->text.source,
        !          1658:             ctx->text.lt.info[line+1].position,
        !          1659:            XtstPositions, XtsdLeft, 1, TRUE);
        !          1660:     if (position > maxp)
        !          1661:        position = maxp;
        !          1662:     ctx->text.insertPos = position;
        !          1663:     LineLastWidth = width;
        !          1664:     LineLastPosition = position;
        !          1665:    EndAction(ctx);
        !          1666: }
        !          1667: 
        !          1668: static MovePreviousLine(ctx, event)
        !          1669:   TextWidget ctx;
        !          1670:    XEvent *event;
        !          1671: {
        !          1672:     int     width, width2, height, line;
        !          1673:     XtTextPosition position, maxp;
        !          1674:    StartAction(ctx, event);
        !          1675:     _XtTextShowPosition(ctx);
        !          1676:     line = LineForPosition(ctx, ctx->text.insertPos);
        !          1677:     if (line == 0) {
        !          1678:        _XtTextScroll(ctx, -1);
        !          1679:        line = LineForPosition(ctx, ctx->text.insertPos);
        !          1680:     }
        !          1681:     if (line > 0) {
        !          1682:        if (LineLastPosition == ctx->text.insertPos)
        !          1683:            width = LineLastWidth;
        !          1684:        else
        !          1685:            ctx->text.sink->findDistance(ctx,
        !          1686:                    ctx->text.lt.info[line].position, 
        !          1687:                    ctx->text.lt.info[line].x,
        !          1688:                    ctx->text.insertPos, &width, &position, &height);
        !          1689:        line--;
        !          1690:        ctx->text.sink->findPosition(ctx,
        !          1691:                ctx->text.lt.info[line].position, ctx->text.lt.info[line].x,
        !          1692:                width, FALSE, &position, &width2, &height);
        !          1693:        maxp = ctx->text.source->scan(ctx->text.source, 
        !          1694:                ctx->text.lt.info[line+1].position,
        !          1695:                XtstPositions, XtsdLeft, 1, TRUE);
        !          1696:        if (position > maxp)
        !          1697:            position = maxp;
        !          1698:        ctx->text.insertPos = position;
        !          1699:        LineLastWidth = width;
        !          1700:        LineLastPosition = position;
        !          1701:     }
        !          1702:    EndAction(ctx);
        !          1703: }
        !          1704: 
        !          1705: 
        !          1706: 
        !          1707: static MoveBeginningOfFile(ctx, event)
        !          1708:   TextWidget ctx;
        !          1709:    XEvent *event;
        !          1710: {
        !          1711:    StartAction(ctx, event);
        !          1712:     ctx->text.insertPos = ctx->text.source->scan(ctx->text.source, 
        !          1713:        ctx->text.insertPos, XtstFile, XtsdLeft, 1, TRUE);
        !          1714:    EndAction(ctx);
        !          1715: }
        !          1716: 
        !          1717: 
        !          1718: static MoveEndOfFile(ctx, event)
        !          1719:   TextWidget ctx;
        !          1720:    XEvent *event;
        !          1721: {
        !          1722:    StartAction(ctx, event);
        !          1723:     ctx->text.insertPos = ctx->text.source->scan(ctx->text.source, 
        !          1724:        ctx->text.insertPos, XtstFile,  XtsdRight, 1, TRUE);
        !          1725:    EndAction(ctx);
        !          1726: }
        !          1727: 
        !          1728: static ScrollOneLineUp(ctx, event)
        !          1729:   TextWidget ctx;
        !          1730:    XEvent *event;
        !          1731: {
        !          1732:    StartAction(ctx, event);
        !          1733:     _XtTextScroll(ctx, 1);
        !          1734:    EndAction(ctx);
        !          1735: }
        !          1736: 
        !          1737: static ScrollOneLineDown(ctx, event)
        !          1738:   TextWidget ctx;
        !          1739:    XEvent *event;
        !          1740: {
        !          1741:    StartAction(ctx, event);
        !          1742:     _XtTextScroll(ctx, -1);
        !          1743:    EndAction(ctx);
        !          1744: }
        !          1745: 
        !          1746: static MoveNextPage(ctx, event)
        !          1747:   TextWidget ctx;
        !          1748:    XEvent *event;
        !          1749: {
        !          1750:    StartAction(ctx, event);
        !          1751:     _XtTextScroll(ctx, max(1, ctx->text.lt.lines - 2));
        !          1752:     ctx->text.insertPos = ctx->text.lt.top;
        !          1753:    EndAction(ctx);
        !          1754: }
        !          1755: 
        !          1756: static MovePreviousPage(ctx, event)
        !          1757:   TextWidget ctx;
        !          1758:    XEvent *event;
        !          1759: {
        !          1760:    StartAction(ctx, event);
        !          1761:     _XtTextScroll(ctx, -max(1, ctx->text.lt.lines - 2));
        !          1762:     ctx->text.insertPos = ctx->text.lt.top;
        !          1763:    EndAction(ctx);
        !          1764: }
        !          1765: 
        !          1766: 
        !          1767: 
        !          1768: 
        !          1769: /* delete routines */
        !          1770: 
        !          1771: static DeleteForwardChar(ctx, event)
        !          1772:     TextWidget ctx;
        !          1773:    XEvent *event;
        !          1774: {
        !          1775:     XtTextPosition next;
        !          1776: 
        !          1777:    StartAction(ctx, event);
        !          1778:     next = ctx->text.source->scan(
        !          1779:             ctx->text.source, ctx->text.insertPos, XtstPositions, 
        !          1780:            XtsdRight, 1, TRUE);
        !          1781:     DeleteOrKill(ctx, ctx->text.insertPos, next, FALSE);
        !          1782:    EndAction(ctx);
        !          1783: }
        !          1784: 
        !          1785: static DeleteBackwardChar(ctx, event)
        !          1786:     TextWidget ctx;
        !          1787:    XEvent *event;
        !          1788: {
        !          1789:     XtTextPosition next;
        !          1790: 
        !          1791:    StartAction(ctx, event);
        !          1792:     next = ctx->text.source->scan(
        !          1793:             ctx->text.source, ctx->text.insertPos, XtstPositions, 
        !          1794:            XtsdLeft, 1, TRUE);
        !          1795:     DeleteOrKill(ctx, next, ctx->text.insertPos, FALSE);
        !          1796:    EndAction(ctx);
        !          1797: }
        !          1798: 
        !          1799: static DeleteForwardWord(ctx, event)
        !          1800:     TextWidget ctx;
        !          1801:    XEvent *event;
        !          1802: {
        !          1803:     XtTextPosition next;
        !          1804: 
        !          1805:    StartAction(ctx, event);
        !          1806:     next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdRight);
        !          1807:     DeleteOrKill(ctx, ctx->text.insertPos, next, FALSE);
        !          1808:    EndAction(ctx);
        !          1809: }
        !          1810: 
        !          1811: static DeleteBackwardWord(ctx, event)
        !          1812:     TextWidget ctx;
        !          1813:    XEvent *event;
        !          1814: {
        !          1815:     XtTextPosition next;
        !          1816: 
        !          1817:    StartAction(ctx, event);
        !          1818:     next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdLeft);
        !          1819:     DeleteOrKill(ctx, next, ctx->text.insertPos, FALSE);
        !          1820:    EndAction(ctx);
        !          1821: }
        !          1822: 
        !          1823: static KillForwardWord(ctx, event)
        !          1824:     TextWidget ctx;
        !          1825:    XEvent *event;
        !          1826: {
        !          1827:     XtTextPosition next;
        !          1828: 
        !          1829:    StartAction(ctx, event);
        !          1830:     next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdRight);
        !          1831:     DeleteOrKill(ctx, ctx->text.insertPos, next, TRUE);
        !          1832:    EndAction(ctx);
        !          1833: }
        !          1834: 
        !          1835: static KillBackwardWord(ctx, event)
        !          1836:     TextWidget ctx;
        !          1837:    XEvent *event;
        !          1838: {
        !          1839:     XtTextPosition next;
        !          1840: 
        !          1841:    StartAction(ctx, event);
        !          1842:     next = NextPosition(ctx, ctx->text.insertPos, XtstWhiteSpace, XtsdLeft);
        !          1843:     DeleteOrKill(ctx, next, ctx->text.insertPos, TRUE);
        !          1844:    EndAction(ctx);
        !          1845: }
        !          1846: 
        !          1847: static KillCurrentSelection(ctx, event)
        !          1848:     TextWidget ctx;
        !          1849:    XEvent *event;
        !          1850: {
        !          1851:    StartAction(ctx, event);
        !          1852:     DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, TRUE);
        !          1853:    EndAction(ctx);
        !          1854: }
        !          1855: 
        !          1856: static DeleteCurrentSelection(ctx, event)
        !          1857:     TextWidget ctx;
        !          1858:    XEvent *event;
        !          1859: {
        !          1860:    StartAction(ctx, event);
        !          1861:     DeleteOrKill(ctx, ctx->text.s.left, ctx->text.s.right, FALSE);
        !          1862:    EndAction(ctx);
        !          1863: }
        !          1864: 
        !          1865: static KillToEndOfLine(ctx, event)
        !          1866:     TextWidget ctx;
        !          1867:    XEvent *event;
        !          1868: {
        !          1869:     int     line;
        !          1870:     XtTextPosition last, next;
        !          1871:    StartAction(ctx, event);
        !          1872:     _XtTextShowPosition(ctx);
        !          1873:     line = LineForPosition(ctx, ctx->text.insertPos);
        !          1874:     last = ctx->text.lt.info[line + 1].position;
        !          1875:     next = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
        !          1876:        XtstEOL, XtsdRight, 1, FALSE);
        !          1877:     if (last > ctx->text.lastPos)
        !          1878:        last = ctx->text.lastPos;
        !          1879:     if (last > next && ctx->text.insertPos < next)
        !          1880:        last = next;
        !          1881:     DeleteOrKill(ctx, ctx->text.insertPos, last, TRUE);
        !          1882:    EndAction(ctx);
        !          1883: }
        !          1884: 
        !          1885: static KillToEndOfParagraph(ctx, event)
        !          1886:     TextWidget ctx;
        !          1887:    XEvent *event;
        !          1888: {
        !          1889:     XtTextPosition next;
        !          1890: 
        !          1891:    StartAction(ctx, event);
        !          1892:     next = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos, XtstEOL, XtsdRight,
        !          1893:            1, FALSE);
        !          1894:     if (next == ctx->text.insertPos)
        !          1895:        next = ctx->text.source->scan(ctx->text.source, next, XtstEOL, XtsdRight, 1, TRUE);
        !          1896:     DeleteOrKill(ctx, ctx->text.insertPos, next, TRUE);
        !          1897:    EndAction(ctx);
        !          1898: }
        !          1899: 
        !          1900: static int InsertNewLineAndBackup(ctx, event)
        !          1901:   TextWidget ctx;
        !          1902:    XEvent *event;
        !          1903: {
        !          1904:    StartAction(ctx, event);
        !          1905:    InsertNewLineAndBackupInternal(ctx);
        !          1906:    EndAction(ctx);
        !          1907: }
        !          1908: 
        !          1909: static int InsertNewLineAndBackupInternal(ctx)
        !          1910:   TextWidget ctx;
        !          1911: {
        !          1912:     XtTextBlock text;
        !          1913:     text.length = 1;
        !          1914:     text.ptr = "\n";
        !          1915:     text.firstPos = 0;
        !          1916:     if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
        !          1917:        XBell( XtDisplay(ctx), 50);
        !          1918:        return(EDITERROR);
        !          1919:     }
        !          1920:     _XtTextSetNewSelection(ctx, (XtTextPosition) 0, (XtTextPosition) 0);
        !          1921:     ctx->text.showposition = TRUE;
        !          1922:     return(EDITDONE);
        !          1923: }
        !          1924: 
        !          1925: 
        !          1926: 
        !          1927: static int InsertNewLine(ctx, event)
        !          1928:     TextWidget ctx;
        !          1929:    XEvent *event;
        !          1930: {
        !          1931:     XtTextPosition next;
        !          1932: 
        !          1933:    StartAction(ctx, event);
        !          1934:     if (InsertNewLineAndBackupInternal(ctx))
        !          1935:        return(EDITERROR);
        !          1936:     next = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos,
        !          1937:            XtstPositions, XtsdRight, 1, TRUE);
        !          1938:     ctx->text.insertPos = next;
        !          1939:    EndAction(ctx);
        !          1940:     return(EDITDONE);
        !          1941: }
        !          1942: 
        !          1943: 
        !          1944: static InsertNewLineAndIndent(ctx, event)
        !          1945:   TextWidget ctx;
        !          1946:    XEvent *event;
        !          1947: {
        !          1948:     XtTextBlock text;
        !          1949:     XtTextPosition pos1, pos2;
        !          1950: 
        !          1951:    StartAction(ctx, event);
        !          1952:     pos1 = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos, 
        !          1953:        XtstEOL, XtsdLeft, 1, FALSE);
        !          1954:     pos2 = ctx->text.source->scan(ctx->text.source, pos1, XtstEOL, 
        !          1955:        XtsdLeft, 1, TRUE);
        !          1956:     pos2 = ctx->text.source->scan(ctx->text.source, pos2, XtstWhiteSpace, 
        !          1957:        XtsdRight, 1, TRUE);
        !          1958:     text.ptr = _XtTextGetText(ctx, pos1, pos2);
        !          1959:     text.length = strlen(text.ptr);
        !          1960:     if (InsertNewLine(ctx, event)) return;
        !          1961:     if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
        !          1962:        XBell(XtDisplay(ctx), 50);
        !          1963:        EndAction(ctx);
        !          1964:        return;
        !          1965:     }
        !          1966:     ctx->text.insertPos = ctx->text.source->scan(ctx->text.source, 
        !          1967:        ctx->text.insertPos, XtstPositions, XtsdRight, text.length, TRUE);
        !          1968:     XtFree(text.ptr);
        !          1969:    EndAction(ctx);
        !          1970: }
        !          1971: 
        !          1972: static NewSelection(ctx, l, r)
        !          1973:   TextWidget ctx;
        !          1974:   XtTextPosition l, r;
        !          1975: {
        !          1976:     char   *ptr;
        !          1977:     _XtTextSetNewSelection(ctx, l, r);
        !          1978:     if (l < r) {
        !          1979:        ptr = _XtTextGetText(ctx, l, r);
        !          1980:        XStoreBuffer(XtDisplay(ctx), ptr, min(strlen(ptr), MAXCUT), 0);
        !          1981:        XtFree(ptr);
        !          1982:     }
        !          1983: }
        !          1984: 
        !          1985: static SelectWord(ctx, event)
        !          1986:   TextWidget ctx;
        !          1987:    XEvent *event;
        !          1988: {
        !          1989:     XtTextPosition l, r;
        !          1990:    StartAction(ctx, event);
        !          1991:     l = ctx->text.source->scan(ctx->text.source, ctx->text.insertPos, 
        !          1992:        XtstWhiteSpace, XtsdLeft, 1, FALSE);
        !          1993:     r = ctx->text.source->scan(ctx->text.source, l, XtstWhiteSpace, 
        !          1994:        XtsdRight, 1, FALSE);
        !          1995:     NewSelection(ctx, l, r);
        !          1996:    EndAction(ctx);
        !          1997: }
        !          1998: 
        !          1999: 
        !          2000: static SelectAll(ctx, event)
        !          2001:   TextWidget ctx;
        !          2002:    XEvent *event;
        !          2003: {
        !          2004:    StartAction(ctx, event);
        !          2005:    NewSelection(ctx, (XtTextPosition) 0, ctx->text.lastPos);
        !          2006:    EndAction(ctx);
        !          2007: }
        !          2008: 
        !          2009: static SelectStart(ctx, event)
        !          2010:   TextWidget ctx;
        !          2011:    XEvent *event;
        !          2012: {
        !          2013:    StartAction(ctx, event);
        !          2014:     AlterSelection(ctx, XtsmTextSelect, XtactionStart);
        !          2015:    EndAction(ctx);
        !          2016: }
        !          2017: 
        !          2018: static SelectAdjust(ctx, event)
        !          2019:   TextWidget ctx;
        !          2020:    XEvent *event;
        !          2021: {
        !          2022:    StartAction(ctx, event);
        !          2023:     AlterSelection(ctx, XtsmTextSelect, XtactionAdjust);
        !          2024:    EndAction(ctx);
        !          2025: }
        !          2026: 
        !          2027: static SelectEnd(ctx, event)
        !          2028:   TextWidget ctx;
        !          2029:    XEvent *event;
        !          2030: {
        !          2031:    StartAction(ctx, event);
        !          2032:     AlterSelection(ctx, XtsmTextSelect, XtactionEnd);
        !          2033:    EndAction(ctx);
        !          2034: }
        !          2035: 
        !          2036: static ExtendStart(ctx, event)
        !          2037:   TextWidget ctx;
        !          2038:    XEvent *event;
        !          2039: {
        !          2040:    StartAction(ctx, event);
        !          2041:     AlterSelection(ctx, XtsmTextExtend, XtactionStart);
        !          2042:    EndAction(ctx);
        !          2043: }
        !          2044: 
        !          2045: static ExtendAdjust(ctx, event)
        !          2046:   TextWidget ctx;
        !          2047:    XEvent *event;
        !          2048: {
        !          2049:    StartAction(ctx, event);
        !          2050:     AlterSelection(ctx, XtsmTextExtend, XtactionAdjust);
        !          2051:    EndAction(ctx);
        !          2052: }
        !          2053: 
        !          2054: static ExtendEnd(ctx, event)
        !          2055:   TextWidget ctx;
        !          2056:    XEvent *event;
        !          2057: {
        !          2058:    StartAction(ctx, event);
        !          2059:     AlterSelection(ctx, XtsmTextExtend, XtactionEnd);
        !          2060:    EndAction(ctx);
        !          2061: }
        !          2062: 
        !          2063: 
        !          2064: static RedrawDisplay(ctx, event)
        !          2065:   TextWidget ctx;
        !          2066:    XEvent *event;
        !          2067: {
        !          2068:    StartAction(ctx, event);
        !          2069:     ForceBuildLineTable(ctx);
        !          2070:     DisplayTextWindow(ctx);
        !          2071:    EndAction(ctx);
        !          2072: }
        !          2073: 
        !          2074: 
        !          2075: _XtTextAbortDialog(ctx, event)
        !          2076:   TextWidget ctx;
        !          2077:    XEvent *event;
        !          2078: {
        !          2079:    StartAction(ctx, event);
        !          2080:     if (ctx->text.dialog) {
        !          2081:        XtDestroyWidget(ctx->text.dialog);
        !          2082:        ctx->text.dialog = NULL;
        !          2083:     }
        !          2084:    EndAction(ctx);
        !          2085: }
        !          2086: 
        !          2087: 
        !          2088: /* Insert a file of the given name into the text.  Returns 0 if file found, 
        !          2089:    -1 if not. */
        !          2090: 
        !          2091: static InsertFileNamed(ctx, str)
        !          2092:   TextWidget ctx;
        !          2093:   char *str;
        !          2094: {
        !          2095:     int fid;
        !          2096:     XtTextBlock text;
        !          2097:     char    buf[1000];
        !          2098:     XtTextPosition position;
        !          2099: 
        !          2100:     if (str == NULL || strlen(str) == 0) return -1;
        !          2101:     fid = open(str, O_RDONLY);
        !          2102:     if (fid <= 0) return -1;
        !          2103:     _XtTextPrepareToUpdate(ctx);
        !          2104:     position = ctx->text.insertPos;
        !          2105:     while ((text.length = read(fid, buf, 512)) > 0) {
        !          2106:        text.ptr = buf;
        !          2107:        (void) ReplaceText(ctx, position, position, &text);
        !          2108:        position = ctx->text.source->scan(ctx->text.source, position, 
        !          2109:                XtstPositions, XtsdRight, text.length, TRUE);
        !          2110:     }
        !          2111:     (void) close(fid);
        !          2112:     ctx->text.insertPos = position;
        !          2113:     _XtTextExecuteUpdate(ctx);
        !          2114:     return 0;
        !          2115: }
        !          2116: 
        !          2117: static DoInsert(ctx)
        !          2118:   TextWidget ctx;
        !          2119: {
        !          2120: /* can't do dialog boxes yet
        !          2121:     if (InsertFileNamed(ctx, XtDialogGetValueString(XtDisplay(ctx), ctx->text.dialog)))
        !          2122:        XBell(XtDisplay(ctx), 50);
        !          2123:     else
        !          2124:        _XtTextAbortDialog(ctx);
        !          2125: */
        !          2126: }
        !          2127: 
        !          2128: static TextFocusIn (ctx, event)
        !          2129:   TextWidget ctx;
        !          2130:    XEvent *event;
        !          2131: { ctx->text.hasfocus = TRUE; }
        !          2132: 
        !          2133: static void TextFocusOut(ctx, event)
        !          2134:   TextWidget ctx;
        !          2135:    XEvent *event;
        !          2136: { ctx->text.hasfocus = FALSE; }
        !          2137: 
        !          2138: #define STRBUFSIZE 100
        !          2139: 
        !          2140: static XComposeStatus compose_status = {NULL, 0};
        !          2141: static InsertChar(ctx, event)
        !          2142:   TextWidget ctx;
        !          2143:    XEvent *event;
        !          2144: {
        !          2145:    char strbuf[STRBUFSIZE];
        !          2146:    int     keycode;
        !          2147:    XtTextBlock text;
        !          2148:    text.length = XLookupString (event, strbuf, STRBUFSIZE,
        !          2149:                 &keycode, &compose_status);
        !          2150:    if (text.length==0) return;
        !          2151:    StartAction(ctx, event);
        !          2152:    text.ptr = &strbuf[0];;
        !          2153:    text.firstPos = 0;
        !          2154:    if (ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text)) {
        !          2155:        XBell(XtDisplay(ctx), 50);
        !          2156:        EndAction(ctx);
        !          2157:        return;
        !          2158:     }
        !          2159:     ctx->text.insertPos =
        !          2160:        (*(ctx->text.source->scan))(ctx->text.source, ctx->text.insertPos,
        !          2161:                            XtstPositions, XtsdRight, text.length, TRUE);
        !          2162:         _XtTextSetNewSelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
        !          2163: 
        !          2164:    EndAction(ctx);
        !          2165: }
        !          2166: 
        !          2167: static InsertFile(ctx, event)
        !          2168:   TextWidget ctx;
        !          2169:    XEvent *event;
        !          2170: {
        !          2171:     char *ptr;
        !          2172:     XtTextBlock text;
        !          2173: 
        !          2174: /* this depends on dialog boxes...
        !          2175: 
        !          2176:    StartAction(ctx, event);
        !          2177:     if (ctx->text.source->editType(ctx->text.source) != XttextEdit) {
        !          2178:        XBell(XtDisplay(ctx), 50);
        !          2179:        EndAction(ctx);
        !          2180:        return;
        !          2181:     }
        !          2182:     if (ctx->text.s.left < ctx->text.s.right) {
        !          2183:        ptr = _XtTextGetText(ctx, ctx->text.s.left, ctx->text.s.right);
        !          2184:        DeleteCurrentSelection(ctx);
        !          2185:        if (InsertFileNamed(ctx, ptr)) {
        !          2186:            XBell( XtDisplay(ctx), 50);
        !          2187:            text.ptr = ptr;
        !          2188:            text.length = strlen(ptr);
        !          2189:            (void) ReplaceText(ctx, ctx->text.insertPos, ctx->text.insertPos, &text);
        !          2190:            ctx->text.s.left = ctx->text.insertPos;
        !          2191:            ctx->text.s.right = ctx->text.insertPos = 
        !          2192:                ctx->text.source->scan(ctx->text.source, ctx->text.insertPos, 
        !          2193:                  XtstPositions, XtsdRight, text.length, TRUE);
        !          2194:        }
        !          2195:        XtFree(ptr);
        !          2196:        EndAction(ctx);
        !          2197:        return;
        !          2198:     }
        !          2199:     if (ctx->text.dialog)
        !          2200:        _XtTextAbortDialog(ctx);
        !          2201:     ctx->text.dialog = XtDialogCreate( XtDisplay(ctx), ctx->text.w, "Insert File:", "", (ArgList)NULL, 0);
        !          2202:     XtDialogAddButton( XtDisplay(ctx), ctx->text.dialog, "Abort", _XtTextAbortDialog, (caddr_t)ctx);
        !          2203:     XtDialogAddButton( XtDisplay(ctx), ctx->text.dialog, "DoIt", DoInsert, (caddr_t)ctx);
        !          2204:     XMapWindow( XtDisplay(ctx), ctx->text.dialog);
        !          2205:    EndAction(ctx);
        !          2206: */
        !          2207: }
        !          2208: 
        !          2209: /* Actions Table */
        !          2210: 
        !          2211: XtActionsRec textActionsTable [] = {
        !          2212: /* motion bindings */
        !          2213:   {"forward-character",        (caddr_t)MoveForwardChar},
        !          2214:   {"backward-character",       (caddr_t)MoveBackwardChar},
        !          2215:   {"forward-word",             (caddr_t)MoveForwardWord},
        !          2216:   {"backward-word",            (caddr_t)MoveBackwardWord},
        !          2217:   {"forward-paragraph",        (caddr_t)MoveForwardParagraph},
        !          2218:   {"backward-paragraph",       (caddr_t)MoveBackwardParagraph},
        !          2219:   {"beginning-of-line",        (caddr_t)MoveToLineStart},
        !          2220:   {"end-of-line",              (caddr_t)MoveToLineEnd},
        !          2221:   {"next-line",                (caddr_t)MoveNextLine},
        !          2222:   {"previous-line",            (caddr_t)MovePreviousLine},
        !          2223:   {"next-page",                (caddr_t)MoveNextPage},
        !          2224:   {"previous-page",            (caddr_t)MovePreviousPage},
        !          2225:   {"beginning-of-file",        (caddr_t)MoveBeginningOfFile},
        !          2226:   {"end-of-file",              (caddr_t)MoveEndOfFile},
        !          2227:   {"scroll-one-line-up",       (caddr_t)ScrollOneLineUp},
        !          2228:   {"scroll-one-line-down",     (caddr_t)ScrollOneLineDown},
        !          2229: /* delete bindings */
        !          2230:   {"delete-next-character",    (caddr_t)DeleteForwardChar},
        !          2231:   {"delete-previous-character", (caddr_t)DeleteBackwardChar},
        !          2232:   {"delete-next-word",                 (caddr_t)DeleteForwardWord},
        !          2233:   {"delete-previous-word",     (caddr_t)DeleteBackwardWord},
        !          2234:   {"delete-selection",                 (caddr_t)DeleteCurrentSelection},
        !          2235: /* kill bindings */
        !          2236:   {"kill-word",                (caddr_t)KillForwardWord},
        !          2237:   {"backward-kill-word",       (caddr_t)KillBackwardWord},
        !          2238:   {"kill-selection",           (caddr_t)KillCurrentSelection},
        !          2239:   {"kill-to-end-of-line",      (caddr_t)KillToEndOfLine},
        !          2240:   {"kill-to-end-of-paragraph",         (caddr_t)KillToEndOfParagraph},
        !          2241: /* unkill bindings */
        !          2242:   {"unkill",                   (caddr_t)UnKill},
        !          2243:   {"stuff",                    (caddr_t)Stuff},
        !          2244: /* new line stuff */
        !          2245:   {"newline-and-indent",       (caddr_t)InsertNewLineAndIndent},
        !          2246:   {"newline-and-backup",       (caddr_t)InsertNewLineAndBackup},
        !          2247:   {"newline",                  (caddr_t)InsertNewLine},
        !          2248: /* Selection stuff */
        !          2249:   {"select-word",              (caddr_t)SelectWord},
        !          2250:   {"select-all",               (caddr_t)SelectAll},
        !          2251:   {"select-start",             (caddr_t)SelectStart},
        !          2252:   {"select-adjust",            (caddr_t)SelectAdjust},
        !          2253:   {"select-end",               (caddr_t)SelectEnd},
        !          2254:   {"extend-start",             (caddr_t)ExtendStart},
        !          2255:   {"extend-adjust",            (caddr_t)ExtendAdjust},
        !          2256:   {"extend-end",               (caddr_t)ExtendEnd},
        !          2257: /* Miscellaneous */
        !          2258:   {"redraw-display",           (caddr_t)RedrawDisplay},
        !          2259:   {"insert-file",              (caddr_t)InsertFile},
        !          2260:   {"insert-char",              (caddr_t)InsertChar},
        !          2261:   {"focus-in",                         (caddr_t)TextFocusIn},
        !          2262:   {"focus-out",                (caddr_t)TextFocusOut},
        !          2263:   {NULL,NULL}
        !          2264: };
        !          2265: 
        !          2266: static char *defaultTextEventBindings[] = {
        !          2267: /* motion bindings */
        !          2268:     "Ctrl<Key>F:               forward-character()",
        !          2269:     "<Key>0xff53:      forward-character()", 
        !          2270:     "Ctrl<Key>B:               backward-character()",
        !          2271:     "<Key>0xff51:      backward-character()",
        !          2272:     "Meta<Key>F:               forward-word()",
        !          2273:     "Meta<Key>B:               backward-word()",
        !          2274:     "Meta<Key>]:               forward-paragraph()",
        !          2275:     "Ctrl<Key>[:               backward-paragraph()",
        !          2276:     "Ctrl<Key>A:               beginning-of-line()",
        !          2277:     "Ctrl<Key>E:               end-of-line()",
        !          2278:     "Ctrl<Key>N:           next-line()",
        !          2279:     "<Key>0xff54:      next-line()",
        !          2280:     "Ctrl<Key>P:               previous-line()",
        !          2281:     "<Key>0xff52:       previous-line()",
        !          2282:     "Ctrl<Key>V:               next-page()",
        !          2283:     "Meta<Key>V:               previous-page()",
        !          2284:     "Meta<Key>\\<:             beginning-of-file()",
        !          2285:     "Meta<Key>\\>:             end-of-file()",
        !          2286:     "Ctrl<Key>Z:               scroll-one-line-up()",
        !          2287:     "Meta<Key>Z:               scroll-one-line-down()",
        !          2288: /* delete binding*/
        !          2289:     "Ctrl<Key>D:               delete-next-character()",
        !          2290:     "Ctrl<Key>H:               delete-previous-character()",
        !          2291:     "<Key>0xff7f:      delete-previous-character()",
        !          2292:     "<Key>0xffff:      delete-previous-character()",
        !          2293:     "<Key>0xff08:      delete-previous-character()",
        !          2294:     "Meta<Key>D:               delete-next-word()",
        !          2295:     "Meta<Key>H:               delete-previous-word()",
        !          2296: /* kill bindings */
        !          2297:     "Shift Meta<Key>D:         kill-word()",
        !          2298:     "Shift Meta<Key>H:         backward-kill-word()",
        !          2299:     "Ctrl<Key>W:               kill-selection()",
        !          2300:     "Ctrl<Key>K:               kill-to-end-of-line()",
        !          2301:     "Meta<Key>K:               kill-to-end-of-paragraph()",
        !          2302: /* unkill bindings */
        !          2303:     "Ctrl<Key>Y:               unkill()",
        !          2304:     "Meta<Key>Y:               stuff()",
        !          2305: /* new line stuff */
        !          2306:     "Ctrl<Key>J:               newline-and-indent()",
        !          2307:     "<Key>0xff0a:      newline-and-indent()",
        !          2308:     "Ctrl<Key>O:               newline-and-backup()",
        !          2309:     "Ctrl<Key>M:               newline()",
        !          2310:     "<Key>0xff0d:      newline()",
        !          2311: /* Miscellaneous */
        !          2312:     "Ctrl<Key>L:               redraw-display()",
        !          2313:     "Meta<Key>I:               insert-file()",
        !          2314:    "<FocusIn>:         focus-in()",
        !          2315:    "<FocusOut>:                focus-out()",
        !          2316: /* selection stuff */
        !          2317:     "<Btn1Down>:       select-start()",
        !          2318:     "Button1<PtrMoved>:        extend-adjust()",
        !          2319:     "<Btn1Up>:         extend-end()",
        !          2320:     "<Btn2Down>:       stuff()",
        !          2321:     "<Btn3Down>:       extend-start()",
        !          2322:     "Button3<PtrMoved>:        extend-adjust()",
        !          2323:     "<Btn3Up>:         extend-end()",
        !          2324: /* default character handling */
        !          2325:     "<Key>:            insert-char()",
        !          2326:     
        !          2327:     NULL
        !          2328: };
        !          2329: 
        !          2330: /* grodyness needed because Xrm wants pointer to thing, not thing... */
        !          2331: caddr_t defaultTextTranslations = (caddr_t)defaultTextEventBindings;
        !          2332: 
        !          2333: TextClassRec textClassRec = {
        !          2334: /* core fields */
        !          2335:     /* superclass       */      (WidgetClass) &widgetClassRec,
        !          2336:     /* class_name       */      "Text",
        !          2337:     /* widget_size      */      sizeof(TextRec),
        !          2338:     /* class_initialize */      NULL,
        !          2339:     /* class_inited     */      FALSE,
        !          2340:     /* initialize       */      Initialize,
        !          2341:     /* realize          */      Realize,
        !          2342:     /* actions          */      textActionsTable,
        !          2343:     /* num_actions      */      XtNumber(textActionsTable),
        !          2344:     /* resources        */      resources,
        !          2345:     /* num_ resource    */      XtNumber(resources),
        !          2346:     /* xrm_class        */      NULLQUARK,
        !          2347:     /* compress_motion    */    TRUE,
        !          2348:     /* compress_exposure  */    FALSE,
        !          2349:     /* visible_interest */      FALSE,
        !          2350:     /* destroy          */      TextDestroy,
        !          2351:     /* resize           */      Resize,
        !          2352:     /* expose           */      ProcessExposeRegion,
        !          2353:     /* set_values       */      XtTextSetValues,
        !          2354:     /* accept_focus     */      TextAcceptFocus,
        !          2355: };
        !          2356: 
        !          2357: WidgetClass textWidgetClass = (WidgetClass)&textClassRec;
        !          2358: 
        !          2359:  

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.