Text.c

Go to the documentation of this file.
00001 /* $XConsortium: Text.c,v 1.197 95/06/14 15:07:27 kaleb Exp $ */
00002 
00003 /***********************************************************
00004 
00005 Copyright (c) 1987, 1988, 1994  X Consortium
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023 
00024 Except as contained in this notice, the name of the X Consortium shall not be
00025 used in advertising or otherwise to promote the sale, use or other dealings
00026 in this Software without prior written authorization from the X Consortium.
00027 
00028 
00029 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
00030 
00031                         All Rights Reserved
00032 
00033 Permission to use, copy, modify, and distribute this software and its 
00034 documentation for any purpose and without fee is hereby granted, 
00035 provided that the above copyright notice appear in all copies and that
00036 both that copyright notice and this permission notice appear in 
00037 supporting documentation, and that the name of Digital not be
00038 used in advertising or publicity pertaining to distribution of the
00039 software without specific, written prior permission.  
00040 
00041 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00042 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00043 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00044 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00045 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00046 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00047 SOFTWARE.
00048 
00049 ******************************************************************/
00050 
00051 #include <X11/IntrinsicP.h>
00052 #include <X11/StringDefs.h>
00053 #include <X11/Shell.h>
00054 #include <X11/Xatom.h>
00055 #include <X11/Xutil.h>
00056 #include "XawI18n.h"
00057 #include <stdio.h>
00058 
00059 #include <X11/Xmu/Atoms.h>
00060 #include <X11/Xmu/CharSet.h>
00061 #include <X11/Xmu/Converters.h>
00062 #include <X11/Xmu/StdSel.h>
00063 #include <X11/Xmu/Misc.h>
00064 
00065 #include <X11/Xaw3d/XawInit.h>
00066 #include <X11/Xaw3d/Cardinals.h>
00067 #include <X11/Xaw3d/Scrollbar.h>
00068 #include <X11/Xaw3d/TextP.h>
00069 #include <X11/Xaw3d/MultiSinkP.h>
00070 #include <X11/Xaw3d/XawImP.h>
00071 
00072 #include <X11/Xfuncs.h>
00073 #include <ctype.h>              /* for isprint() */
00074 
00075 #ifndef MAX_LEN_CT
00076 #define MAX_LEN_CT 6            /* for sequence: ESC $ ( A \xx \xx */
00077 #endif
00078 
00079 unsigned long FMT8BIT = 0L;
00080 unsigned long XawFmt8Bit = 0L;
00081 unsigned long XawFmtWide = 0L;
00082 
00083 #define SinkClearToBG          XawTextSinkClearToBackground
00084 
00085 #define SrcScan                XawTextSourceScan
00086 #define SrcRead                XawTextSourceRead
00087 #define SrcReplace             XawTextSourceReplace
00088 #define SrcSearch              XawTextSourceSearch
00089 #define SrcCvtSel              XawTextSourceConvertSelection
00090 #define SrcSetSelection        XawTextSourceSetSelection
00091 
00092 #define BIGNUM ((Dimension)32023)
00093 #define MULTI_CLICK_TIME 500L
00094 
00095 /*
00096  * Compute a the maximum length of a cut buffer that we can pass at any
00097  * time.  The 64 allows for the overhead of the Change Property request.
00098  */
00099 
00100 #define MAX_CUT_LEN(dpy)  (XMaxRequestSize(dpy) - 64)
00101 
00102 #define IsValidLine(ctx, num) ( ((num) == 0) || \
00103                                 ((ctx)->text.lt.info[(num)].position != 0) )
00104 
00105 /*
00106  * Defined in Text.c
00107  */
00108 static void UnrealizeScrollbars();
00109 static void VScroll(), VJump(), HScroll(), HJump(), ClearWindow(); 
00110 static void DisplayTextWindow(), ModifySelection(), PushCopyQueue();
00111 static void UpdateTextInLine(), UpdateTextInRectangle(), PopCopyQueue();
00112 static void FlushUpdate();
00113 static Boolean LineAndXYForPosition(), TranslateExposeRegion();
00114 static XawTextPosition FindGoodPosition(), _BuildLineTable();
00115 
00116 void _XawTextAlterSelection(), _XawTextExecuteUpdate();
00117 void _XawTextSetScrollBars(), _XawTextPrepareToUpdate();
00118 
00119 /****************************************************************
00120  *
00121  * Full class record constant
00122  *
00123  ****************************************************************/
00124 
00125 static XawTextSelectType defaultSelectTypes[] = {
00126   XawselectPosition, XawselectWord, XawselectLine, XawselectParagraph,
00127   XawselectAll,      XawselectNull,
00128 };
00129 
00130 static XPointer defaultSelectTypesPtr = (XPointer)defaultSelectTypes;
00131 extern char *_XawDefaultTextTranslations1, *_XawDefaultTextTranslations2,
00132   *_XawDefaultTextTranslations3, *_XawDefaultTextTranslations4;
00133 static Dimension defWidth = 100;
00134 static Dimension defHeight = DEFAULT_TEXT_HEIGHT;
00135 
00136 #define offset(field) XtOffsetOf(TextRec, field)
00137 static XtResource resources[] = {
00138   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
00139      offset(core.width), XtRDimension, (XtPointer)&defWidth},
00140   {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
00141      offset(simple.cursor), XtRString, "xterm"},
00142   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
00143      offset(core.height), XtRDimension, (XtPointer)&defHeight},
00144   {XtNdisplayPosition, XtCTextPosition, XtRInt, sizeof(XawTextPosition), 
00145      offset(text.lt.top), XtRImmediate, (XtPointer)0},
00146   {XtNinsertPosition, XtCTextPosition, XtRInt, sizeof(XawTextPosition),
00147      offset(text.insertPos), XtRImmediate,(XtPointer)0},
00148   {XtNleftMargin, XtCMargin, XtRPosition, sizeof (Position),
00149      offset(text.r_margin.left), XtRImmediate, (XtPointer)2},
00150   {XtNrightMargin, XtCMargin, XtRPosition, sizeof (Position),
00151      offset(text.r_margin.right), XtRImmediate, (XtPointer)4},
00152   {XtNtopMargin, XtCMargin, XtRPosition, sizeof (Position),
00153      offset(text.r_margin.top), XtRImmediate, (XtPointer)2},
00154   {XtNbottomMargin, XtCMargin, XtRPosition, sizeof (Position),
00155      offset(text.r_margin.bottom), XtRImmediate, (XtPointer)2},
00156   {XtNselectTypes, XtCSelectTypes, XtRPointer,
00157      sizeof(XawTextSelectType*), offset(text.sarray),
00158      XtRPointer, (XtPointer)&defaultSelectTypesPtr},
00159   {XtNtextSource, XtCTextSource, XtRWidget, sizeof (Widget),
00160      offset(text.source), XtRImmediate, NULL},
00161   {XtNtextSink, XtCTextSink, XtRWidget, sizeof (Widget),
00162      offset(text.sink), XtRImmediate, NULL},
00163   {XtNdisplayCaret, XtCOutput, XtRBoolean, sizeof(Boolean),
00164      offset(text.display_caret), XtRImmediate, (XtPointer)True},
00165   {XtNscrollVertical, XtCScroll, XtRScrollMode, sizeof(XawTextScrollMode),
00166      offset(text.scroll_vert), XtRImmediate, (XtPointer) XawtextScrollNever},
00167   {XtNscrollHorizontal, XtCScroll, XtRScrollMode, sizeof(XawTextScrollMode),
00168      offset(text.scroll_horiz), XtRImmediate, (XtPointer) XawtextScrollNever},
00169   {XtNwrap, XtCWrap, XtRWrapMode, sizeof(XawTextWrapMode),
00170      offset(text.wrap), XtRImmediate, (XtPointer) XawtextWrapNever},
00171   {XtNresize, XtCResize, XtRResizeMode, sizeof(XawTextResizeMode),
00172      offset(text.resize), XtRImmediate, (XtPointer) XawtextResizeNever},
00173   {XtNautoFill, XtCAutoFill, XtRBoolean, sizeof(Boolean),
00174      offset(text.auto_fill), XtRImmediate, (XtPointer) FALSE},
00175   {XtNunrealizeCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
00176      offset(text.unrealize_callbacks), XtRCallback, (XtPointer) NULL}
00177 };
00178 #undef offset
00179 
00180 /* ARGSUSED */
00181 static void 
00182 CvtStringToScrollMode(args, num_args, fromVal, toVal)
00183 XrmValuePtr args;               /* unused */
00184 Cardinal        *num_args;      /* unused */
00185 XrmValuePtr     fromVal;
00186 XrmValuePtr     toVal;
00187 {
00188   static XawTextScrollMode scrollMode;
00189   static  XrmQuark  QScrollNever, QScrollAlways, QScrollWhenNeeded;
00190   XrmQuark    q;
00191   char        lowerName[40];
00192   static Boolean inited = FALSE;
00193     
00194   if ( !inited ) {
00195     QScrollNever      = XrmPermStringToQuark(XtEtextScrollNever);
00196     QScrollWhenNeeded = XrmPermStringToQuark(XtEtextScrollWhenNeeded);
00197     QScrollAlways     = XrmPermStringToQuark(XtEtextScrollAlways);
00198     inited = TRUE;
00199   }
00200 
00201   if (strlen ((char*) fromVal->addr) < sizeof lowerName) {
00202     XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
00203     q = XrmStringToQuark(lowerName);
00204 
00205     if      (q == QScrollNever)          scrollMode = XawtextScrollNever;
00206     else if (q == QScrollWhenNeeded)     scrollMode = XawtextScrollWhenNeeded;
00207     else if (q == QScrollAlways)         scrollMode = XawtextScrollAlways;
00208     else {
00209       toVal->size = 0;
00210       toVal->addr = NULL;
00211       return;
00212     }
00213     toVal->size = sizeof scrollMode;
00214     toVal->addr = (XPointer) &scrollMode;
00215     return;
00216   }
00217   toVal->size = 0;
00218   toVal->addr = NULL;
00219 }
00220 
00221 /* ARGSUSED */
00222 static void 
00223 CvtStringToWrapMode(args, num_args, fromVal, toVal)
00224 XrmValuePtr args;               /* unused */
00225 Cardinal        *num_args;      /* unused */
00226 XrmValuePtr     fromVal;
00227 XrmValuePtr     toVal;
00228 {
00229   static XawTextWrapMode wrapMode;
00230   static  XrmQuark QWrapNever, QWrapLine, QWrapWord;
00231   XrmQuark    q;
00232   char        lowerName[BUFSIZ];
00233   static Boolean inited = FALSE;
00234     
00235   if ( !inited ) {
00236     QWrapNever = XrmPermStringToQuark(XtEtextWrapNever);
00237     QWrapLine  = XrmPermStringToQuark(XtEtextWrapLine);
00238     QWrapWord  = XrmPermStringToQuark(XtEtextWrapWord);
00239     inited = TRUE;
00240   }
00241 
00242   if (strlen ((char*) fromVal->addr) < sizeof lowerName) {
00243     XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
00244     q = XrmStringToQuark(lowerName);
00245 
00246     if      (q == QWrapNever)     wrapMode = XawtextWrapNever;
00247     else if (q == QWrapLine)      wrapMode = XawtextWrapLine;
00248     else if (q == QWrapWord)      wrapMode = XawtextWrapWord;
00249     else {
00250       toVal->size = 0;
00251       toVal->addr = NULL;
00252       return;
00253     }
00254     toVal->size = sizeof wrapMode;
00255     toVal->addr = (XPointer) &wrapMode;
00256     return;
00257   }
00258   toVal->size = 0;
00259   toVal->addr = NULL;
00260 }
00261 
00262 /* ARGSUSED */
00263 static void 
00264 CvtStringToResizeMode(args, num_args, fromVal, toVal)
00265 XrmValuePtr args;               /* unused */
00266 Cardinal        *num_args;      /* unused */
00267 XrmValuePtr     fromVal;
00268 XrmValuePtr     toVal;
00269 {
00270   static XawTextResizeMode resizeMode;
00271   static  XrmQuark  QResizeNever, QResizeWidth, QResizeHeight, QResizeBoth;
00272   XrmQuark    q;
00273   char        lowerName[40];
00274   static Boolean inited = FALSE;
00275     
00276   if ( !inited ) {
00277     QResizeNever      = XrmPermStringToQuark(XtEtextResizeNever);
00278     QResizeWidth      = XrmPermStringToQuark(XtEtextResizeWidth);
00279     QResizeHeight     = XrmPermStringToQuark(XtEtextResizeHeight);
00280     QResizeBoth       = XrmPermStringToQuark(XtEtextResizeBoth);
00281     inited = TRUE;
00282   }
00283 
00284   if (strlen ((char*) fromVal->addr) < sizeof lowerName) {
00285     XmuCopyISOLatin1Lowered (lowerName, (char *)fromVal->addr);
00286     q = XrmStringToQuark(lowerName);
00287 
00288     if      (q == QResizeNever)          resizeMode = XawtextResizeNever;
00289     else if (q == QResizeWidth)          resizeMode = XawtextResizeWidth;
00290     else if (q == QResizeHeight)         resizeMode = XawtextResizeHeight;
00291     else if (q == QResizeBoth)           resizeMode = XawtextResizeBoth;
00292     else {
00293       toVal->size = 0;
00294       toVal->addr = NULL;
00295       return;
00296     }
00297     toVal->size = sizeof resizeMode;
00298     toVal->addr = (XPointer) &resizeMode;
00299     return;
00300   }
00301   toVal->size = 0;
00302   toVal->addr = NULL;
00303 }
00304 
00305 static void 
00306 ClassInitialize()
00307 {
00308   int len1 = strlen (_XawDefaultTextTranslations1);
00309   int len2 = strlen (_XawDefaultTextTranslations2);
00310   int len3 = strlen (_XawDefaultTextTranslations3);
00311   int len4 = strlen (_XawDefaultTextTranslations4);
00312   char *buf = XtMalloc ((unsigned)(len1 + len2 + len3 + len4 + 1));
00313   char *cp = buf;
00314 
00315   if (!XawFmt8Bit)
00316     FMT8BIT = XawFmt8Bit = XrmPermStringToQuark("FMT8BIT");
00317   if (!XawFmtWide)
00318     XawFmtWide = XrmPermStringToQuark("FMTWIDE");
00319 
00320   XawInitializeWidgetSet();
00321 
00322 /* 
00323  * Set the number of actions.
00324  */
00325 
00326   textClassRec.core_class.num_actions = _XawTextActionsTableCount;
00327   
00328   (void) strcpy( cp, _XawDefaultTextTranslations1); cp += len1;
00329   (void) strcpy( cp, _XawDefaultTextTranslations2); cp += len2;
00330   (void) strcpy( cp, _XawDefaultTextTranslations3); cp += len3;
00331   (void) strcpy( cp, _XawDefaultTextTranslations4);
00332   textWidgetClass->core_class.tm_table = buf;
00333 
00334   XtAddConverter(XtRString, XtRScrollMode, CvtStringToScrollMode,
00335                         (XtConvertArgList)NULL, (Cardinal)0 );
00336   XtAddConverter(XtRString, XtRWrapMode,   CvtStringToWrapMode,
00337                         (XtConvertArgList)NULL, (Cardinal)0 );
00338   XtAddConverter(XtRString, XtRResizeMode, CvtStringToResizeMode,
00339                         (XtConvertArgList)NULL, (Cardinal)0 );
00340 }
00341 
00342 /*      Function Name: PositionHScrollBar.
00343  *      Description: Positions the Horizontal scrollbar.
00344  *      Arguments: ctx - the text widget.
00345  *      Returns: none
00346  */
00347 
00348 static void
00349 PositionHScrollBar(ctx)
00350 TextWidget ctx;
00351 {
00352   Widget vbar = ctx->text.vbar, hbar = ctx->text.hbar;
00353   Position top, left = 0;
00354 
00355   if (ctx->text.hbar == NULL) return;
00356 
00357   if (vbar != NULL)
00358     left += (Position) (vbar->core.width + vbar->core.border_width);
00359 
00360   XtResizeWidget( hbar, ctx->core.width - left, hbar->core.height,
00361                  hbar->core.border_width );
00362 
00363   left -= (Position) hbar->core.border_width;
00364   
00365   top = ctx->core.height - ( hbar->core.height + hbar->core.border_width);
00366   XtMoveWidget( hbar, left, top); 
00367 }
00368 
00369 /*      Function Name: PositionVScrollBar.
00370  *      Description: Positions the Vertical scrollbar.
00371  *      Arguments: ctx - the text widget.
00372  *      Returns: none.
00373  */
00374 
00375 static void
00376 PositionVScrollBar(ctx)
00377 TextWidget ctx;
00378 {
00379   Widget vbar = ctx->text.vbar;
00380   Dimension bw;
00381 
00382   if (vbar == NULL) return;
00383   bw = vbar->core.border_width;
00384 
00385   XtResizeWidget( vbar, vbar->core.width, ctx->core.height, bw);
00386   XtMoveWidget( vbar, -(Position)bw, -(Position)bw );
00387 }
00388 
00389 static void 
00390 CreateVScrollBar(ctx)
00391 TextWidget ctx;
00392 {
00393   Widget vbar;
00394 
00395   if (ctx->text.vbar != NULL) return;
00396 
00397   ctx->text.vbar = vbar =
00398     XtCreateWidget("vScrollbar", scrollbarWidgetClass, (Widget)ctx,
00399                 (ArgList) NULL, ZERO);
00400   XtAddCallback( vbar, XtNscrollProc, VScroll, (XtPointer)ctx );
00401   XtAddCallback( vbar, XtNjumpProc, VJump, (XtPointer)ctx );
00402   if (ctx->text.hbar == NULL)
00403       XtAddCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
00404                     (XtPointer) NULL);
00405 
00406   ctx->text.r_margin.left += vbar->core.width + vbar->core.border_width;
00407   ctx->text.margin.left = ctx->text.r_margin.left;
00408 
00409   PositionVScrollBar(ctx);
00410   PositionHScrollBar(ctx);      /* May modify location of Horiz. Bar. */
00411 
00412   if (XtIsRealized((Widget)ctx)) {
00413     XtRealizeWidget(vbar);
00414     XtMapWidget(vbar);
00415   }
00416 }
00417 
00418 /*      Function Name: DestroyVScrollBar
00419  *      Description: Removes a vertical ScrollBar.
00420  *      Arguments: ctx - the parent text widget.
00421  *      Returns: none.
00422  */
00423 
00424 static void
00425 DestroyVScrollBar(ctx)
00426 TextWidget ctx;
00427 {
00428   Widget vbar = ctx->text.vbar;
00429 
00430   if (vbar == NULL) return;
00431 
00432   ctx->text.r_margin.left -= vbar->core.width + vbar->core.border_width;
00433   ctx->text.margin.left = ctx->text.r_margin.left;
00434   if (ctx->text.hbar == NULL)
00435       XtRemoveCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
00436                        (XtPointer) NULL);
00437   XtDestroyWidget(vbar);
00438   ctx->text.vbar = NULL;
00439   PositionHScrollBar(ctx);
00440 }
00441   
00442 static void 
00443 CreateHScrollBar(ctx)
00444 TextWidget ctx;
00445 {
00446   Arg args[1];
00447   Widget hbar;
00448 
00449   if (ctx->text.hbar != NULL) return;
00450 
00451   XtSetArg(args[0], XtNorientation, XtorientHorizontal);
00452   ctx->text.hbar = hbar =
00453     XtCreateWidget("hScrollbar", scrollbarWidgetClass, (Widget)ctx, args, ONE);
00454   XtAddCallback( hbar, XtNscrollProc, HScroll, (XtPointer)ctx );
00455   XtAddCallback( hbar, XtNjumpProc, HJump, (XtPointer)ctx );
00456   if (ctx->text.vbar == NULL)
00457       XtAddCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
00458                     (XtPointer) NULL);
00459 
00460   PositionHScrollBar(ctx);
00461   if (XtIsRealized((Widget)ctx)) {
00462     XtRealizeWidget(hbar);
00463     XtMapWidget(hbar);
00464   }
00465 }
00466 
00467 /*      Function Name: DestroyHScrollBar
00468  *      Description: Removes a horizontal ScrollBar.
00469  *      Arguments: ctx - the parent text widget.
00470  *      Returns: none.
00471  */
00472 
00473 static void
00474 DestroyHScrollBar(ctx)
00475 TextWidget ctx;
00476 {
00477   Widget hbar = ctx->text.hbar;
00478 
00479   if (hbar == NULL) return;
00480 
00481 /*
00482   ctx->text.r_margin.bottom -= hbar->core.height + hbar->core.border_width;
00483   ctx->text.margin.bottom = ctx->text.r_margin.bottom;
00484 */
00485   if (ctx->text.vbar == NULL)
00486       XtRemoveCallback((Widget) ctx, XtNunrealizeCallback, UnrealizeScrollbars,
00487                        (XtPointer) NULL);
00488   XtDestroyWidget(hbar);
00489   ctx->text.hbar = NULL;
00490 }
00491 
00492 /* ARGSUSED */
00493 static void 
00494 Initialize(request, new, args, num_args)
00495 Widget request, new;
00496 ArgList args;                   /* unused */
00497 Cardinal *num_args;             /* unused */
00498 {
00499   TextWidget ctx = (TextWidget) new;
00500   char error_buf[BUFSIZ];
00501 
00502   ctx->text.lt.lines = 0;
00503   ctx->text.lt.info = NULL;
00504   (void) bzero((char *) &(ctx->text.origSel), sizeof(XawTextSelection));
00505   (void) bzero((char *) &(ctx->text.s), sizeof(XawTextSelection)); 
00506   ctx->text.s.type = XawselectPosition;
00507   ctx->text.salt = NULL;
00508   ctx->text.hbar = ctx->text.vbar = (Widget) NULL;
00509   ctx->text.lasttime = 0; /* ||| correct? */
00510   ctx->text.time = 0; /* ||| correct? */
00511   ctx->text.showposition = TRUE;
00512   ctx->text.lastPos = (ctx->text.source != NULL) ? GETLASTPOS : 0;
00513   ctx->text.file_insert = NULL;
00514   ctx->text.search = NULL;
00515   ctx->text.updateFrom = (XawTextPosition *) XtMalloc((unsigned) ONE);
00516   ctx->text.updateTo = (XawTextPosition *) XtMalloc((unsigned) ONE);
00517   ctx->text.numranges = ctx->text.maxranges = 0;
00518   ctx->text.gc = DefaultGCOfScreen(XtScreen(ctx)); 
00519   ctx->text.hasfocus = FALSE;
00520   ctx->text.margin = ctx->text.r_margin; /* Strucure copy. */
00521   ctx->text.update_disabled = FALSE;
00522   ctx->text.old_insert = -1;
00523   ctx->text.mult = 1;
00524   ctx->text.single_char = FALSE;
00525   ctx->text.copy_area_offsets = NULL;
00526   ctx->text.salt2 = NULL;
00527 
00528   if (ctx->core.height == DEFAULT_TEXT_HEIGHT) {
00529     ctx->core.height = VMargins(ctx);
00530     if (ctx->text.sink != NULL)
00531       ctx->core.height += XawTextSinkMaxHeight(ctx->text.sink, 1);
00532   }
00533 
00534   if (ctx->text.scroll_vert != XawtextScrollNever) 
00535     if ( (ctx->text.resize == XawtextResizeHeight) ||
00536          (ctx->text.resize == XawtextResizeBoth) ) {
00537       (void) sprintf(error_buf, "Xaw Text Widget %s:\n %s %s.", ctx->core.name,
00538               "Vertical scrolling not allowed with height resize.\n",
00539               "Vertical scrolling has been DEACTIVATED.");
00540       XtAppWarning(XtWidgetToApplicationContext(new), error_buf);
00541       ctx->text.scroll_vert = XawtextScrollNever;
00542     }
00543     else if (ctx->text.scroll_vert == XawtextScrollAlways)
00544       CreateVScrollBar(ctx);
00545 
00546   if (ctx->text.scroll_horiz != XawtextScrollNever) 
00547     if (ctx->text.wrap != XawtextWrapNever) {
00548       (void) sprintf(error_buf, "Xaw Text Widget %s:\n %s %s.", ctx->core.name,
00549               "Horizontal scrolling not allowed with wrapping active.\n",
00550               "Horizontal scrolling has been DEACTIVATED.");
00551       XtAppWarning(XtWidgetToApplicationContext(new), error_buf);
00552       ctx->text.scroll_horiz = XawtextScrollNever;
00553     }
00554     else if ( (ctx->text.resize == XawtextResizeWidth) ||
00555               (ctx->text.resize == XawtextResizeBoth) ) {
00556       (void) sprintf(error_buf, "Xaw Text Widget %s:\n %s %s.", ctx->core.name,
00557               "Horizontal scrolling not allowed with width resize.\n",
00558               "Horizontal scrolling has been DEACTIVATED.");
00559       XtAppWarning(XtWidgetToApplicationContext(new), error_buf);
00560       ctx->text.scroll_horiz = XawtextScrollNever;
00561     }
00562     else if (ctx->text.scroll_horiz == XawtextScrollAlways)
00563       CreateHScrollBar(ctx);
00564 }
00565 
00566 static void 
00567 Realize( w, valueMask, attributes )
00568 Widget w;
00569 Mask *valueMask;
00570 XSetWindowAttributes *attributes;
00571 {
00572   TextWidget ctx = (TextWidget)w;
00573   void _XawTextCheckResize();
00574 
00575   (*textClassRec.core_class.superclass->core_class.realize)
00576     (w, valueMask, attributes);
00577   
00578   if (ctx->text.hbar != NULL) {         /* Put up Hbar -- Must be first. */
00579     XtRealizeWidget(ctx->text.hbar);
00580     XtMapWidget(ctx->text.hbar);
00581   }
00582 
00583   if (ctx->text.vbar != NULL) {         /* Put up Vbar. */
00584     XtRealizeWidget(ctx->text.vbar);
00585     XtMapWidget(ctx->text.vbar);
00586   }
00587 
00588   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
00589   _XawTextSetScrollBars(ctx);
00590   _XawTextCheckResize(ctx);
00591 }
00592 
00593 /*ARGSUSED*/
00594 static void UnrealizeScrollbars(widget, client, call)
00595 Widget          widget;         /* Text widget */
00596 XtPointer       client;         /* unused */
00597 XtPointer       call;           /* unused */
00598 {
00599     TextWidget ctx = (TextWidget) widget;
00600     
00601     if (ctx->text.hbar)
00602         XtUnrealizeWidget(ctx->text.hbar);
00603     if (ctx->text.vbar)
00604         XtUnrealizeWidget(ctx->text.vbar);
00605 }
00606 
00607 /* Utility routines for support of Text */
00608 
00609 static void
00610 _CreateCutBuffers(d)
00611 Display *d;
00612 {
00613   static struct _DisplayRec {
00614     struct _DisplayRec *next;
00615     Display *dpy;
00616   } *dpy_list = NULL;
00617   struct _DisplayRec *dpy_ptr;
00618 
00619   for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next)
00620     if (dpy_ptr->dpy == d) return;
00621 
00622   dpy_ptr = XtNew(struct _DisplayRec);
00623   dpy_ptr->next = dpy_list;
00624   dpy_ptr->dpy = d;
00625   dpy_list = dpy_ptr;
00626 
00627 #define Create(buffer) \
00628     XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
00629                     PropModeAppend, NULL, 0 );
00630 
00631     Create( XA_CUT_BUFFER0 );
00632     Create( XA_CUT_BUFFER1 );
00633     Create( XA_CUT_BUFFER2 );
00634     Create( XA_CUT_BUFFER3 );
00635     Create( XA_CUT_BUFFER4 );
00636     Create( XA_CUT_BUFFER5 );
00637     Create( XA_CUT_BUFFER6 );
00638     Create( XA_CUT_BUFFER7 );
00639 
00640 #undef Create
00641 }
00642 
00643 /*
00644  * Procedure to manage insert cursor visibility for editable text.  It uses
00645  * the value of ctx->insertPos and an implicit argument. In the event that
00646  * position is immediately preceded by an eol graphic, then the insert cursor
00647  * is displayed at the beginning of the next line.
00648 */
00649 static void 
00650 InsertCursor (w, state)
00651 Widget w;
00652 XawTextInsertState state;
00653 {
00654   TextWidget ctx = (TextWidget)w;
00655   Position x, y;
00656   int line;
00657   
00658   if (ctx->text.lt.lines < 1) return;
00659 
00660   if ( LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y) ) {
00661     if (line < ctx->text.lt.lines)
00662       y += (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
00663     else
00664       y += (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
00665 
00666     if (ctx->text.display_caret)
00667       XawTextSinkInsertCursor(ctx->text.sink, x, y, state);
00668   }
00669   ctx->text.ev_x = x;
00670   ctx->text.ev_y = y;
00671 
00672   /* Keep Input Method up to speed  */
00673 
00674   if ( ctx->simple.international ) {
00675     Arg list[1];
00676 
00677     XtSetArg (list[0], XtNinsertPosition, ctx->text.insertPos);
00678     _XawImSetValues (w, list, 1);
00679   }
00680 }
00681 
00682 /*
00683  * Procedure to register a span of text that is no longer valid on the display
00684  * It is used to avoid a number of small, and potentially overlapping, screen
00685  * updates. 
00686 */
00687 
00688 void
00689 _XawTextNeedsUpdating(ctx, left, right)
00690 TextWidget ctx;
00691 XawTextPosition left, right;
00692 {
00693   int i;
00694   if (left < right) {
00695     for (i = 0; i < ctx->text.numranges; i++) {
00696       if (left <= ctx->text.updateTo[i] && right >= ctx->text.updateFrom[i]) {
00697         ctx->text.updateFrom[i] = Min(left, ctx->text.updateFrom[i]);
00698         ctx->text.updateTo[i] = Max(right, ctx->text.updateTo[i]);
00699         return;
00700       }
00701     }
00702     ctx->text.numranges++;
00703     if (ctx->text.numranges > ctx->text.maxranges) {
00704       ctx->text.maxranges = ctx->text.numranges;
00705       i = ctx->text.maxranges * sizeof(XawTextPosition);
00706       ctx->text.updateFrom = (XawTextPosition *) 
00707         XtRealloc((char *)ctx->text.updateFrom, (unsigned) i);
00708       ctx->text.updateTo = (XawTextPosition *) 
00709         XtRealloc((char *)ctx->text.updateTo, (unsigned) i);
00710     }
00711     ctx->text.updateFrom[ctx->text.numranges - 1] = left;
00712     ctx->text.updateTo[ctx->text.numranges - 1] = right;
00713   }
00714 }
00715 
00716 /*
00717  * Procedure to read a span of text in Ascii form. This is purely a hack and
00718  * we probably need to add a function to sources to provide this functionality.
00719  * [note: this is really a private procedure but is used in multiple modules].
00720  */
00721 
00722 char *
00723 _XawTextGetText(ctx, left, right)
00724 TextWidget ctx;
00725 XawTextPosition left, right;
00726 {
00727   char *result, *tempResult;
00728   XawTextBlock text;
00729   int bytes;
00730 
00731   if (_XawTextFormat(ctx) == XawFmt8Bit)
00732       bytes = sizeof(unsigned char);
00733   else if (_XawTextFormat(ctx) == XawFmtWide) 
00734       bytes = sizeof(wchar_t);
00735   else /* if there is another fomat, add here */
00736       bytes = 1;
00737 
00738   /* leave space for ZERO */
00739   tempResult=result=XtMalloc( (unsigned)(((Cardinal)(right-left))+ONE )* bytes);
00740   while (left < right) {
00741     left = SrcRead(ctx->text.source, left, &text, (int)(right - left));
00742     if (!text.length)
00743         break;
00744     memmove(tempResult, text.ptr, text.length * bytes);
00745     tempResult += text.length * bytes;
00746   }
00747 
00748   if (bytes == sizeof(wchar_t)) 
00749       *((wchar_t*)tempResult) = (wchar_t)0;
00750   else 
00751       *tempResult = '\0';
00752   return(result);
00753 }
00754 
00755 /* Like _XawTextGetText, but enforces ICCCM STRING type encoding.  This
00756 routine is currently used to put just the ASCII chars in the selection into a
00757 cut buffer. */
00758 
00759 char *
00760 _XawTextGetSTRING(ctx, left, right)
00761 TextWidget ctx;
00762 XawTextPosition left, right;
00763 {
00764   unsigned char *s;
00765   unsigned char c;
00766   long i, j, n;
00767   wchar_t *ws, wc;
00768 
00769   /* allow ESC in accordance with ICCCM */
00770   if (_XawTextFormat(ctx) == XawFmtWide) {
00771      MultiSinkObject sink = (MultiSinkObject) ctx->text.sink;
00772      ws = (wchar_t *)_XawTextGetText(ctx, left, right);
00773      n = wcslen(ws);
00774      for (j = 0, i = 0; j < n; j++) {
00775          wc = ws[j];
00776          if (XwcTextEscapement (sink->multi_sink.fontset, &wc, 1) || 
00777             (wc == _Xaw_atowc(XawTAB)) || (wc == _Xaw_atowc(XawLF)) || (wc == _Xaw_atowc(XawESC)))
00778             ws[i++] = wc;
00779      }
00780      ws[i] = (wchar_t)0;
00781      return (char *)ws;
00782   } else {
00783      s = (unsigned char *)_XawTextGetText(ctx, left, right);
00784      /* only HT and NL control chars are allowed, strip out others */
00785      n = strlen((char *)s);
00786      i = 0;
00787      for (j = 0; j < n; j++) {
00788         c = s[j];
00789         if (((c >= 0x20) && c <= 0x7f) ||
00790            (c >= 0xa0) || (c == XawTAB) || (c == XawLF) || (c == XawESC)) {
00791            s[i] = c;
00792            i++;
00793         }
00794      }
00795      s[i] = 0;
00796      return (char *)s;
00797   }
00798 #undef ESC
00799 
00800 }
00801 
00802 /* 
00803  * This routine maps an x and y position in a window that is displaying text
00804  * into the corresponding position in the source.
00805  *
00806  * NOTE: it is illegal to call this routine unless there is a valid line table!
00807  */
00808 
00809 /*** figure out what line it is on ***/
00810 
00811 static XawTextPosition
00812 PositionForXY (ctx, x, y)
00813 TextWidget ctx;
00814 Position x,y;
00815 {
00816   int fromx, line, width, height;
00817   XawTextPosition position;
00818 
00819   if (ctx->text.lt.lines == 0) return 0;
00820   
00821   for (line = 0; line < ctx->text.lt.lines - 1; line++) {
00822     if (y <= ctx->text.lt.info[line + 1].y)
00823       break;
00824   }
00825   position = ctx->text.lt.info[line].position;
00826   if (position >= ctx->text.lastPos)
00827     return(ctx->text.lastPos);
00828   fromx = (int) ctx->text.margin.left; 
00829   XawTextSinkFindPosition( ctx->text.sink, position, fromx, x - fromx,
00830                           FALSE, &position, &width, &height);
00831   if (position > ctx->text.lastPos) return(ctx->text.lastPos);
00832   if (position >= ctx->text.lt.info[line + 1].position)
00833     position = SrcScan(ctx->text.source, ctx->text.lt.info[line + 1].position,
00834                        XawstPositions, XawsdLeft, 1, TRUE);
00835   return(position);
00836 }
00837 
00838 /*
00839  * This routine maps a source position in to the corresponding line number
00840  * of the text that is displayed in the window.
00841  *
00842  * NOTE: It is illegal to call this routine unless there is a valid line table!
00843  */
00844 
00845 static int 
00846 LineForPosition (ctx, position)
00847 TextWidget ctx;
00848 XawTextPosition position;
00849 {
00850   int line;
00851   
00852   for (line = 0; line < ctx->text.lt.lines; line++)
00853     if (position < ctx->text.lt.info[line + 1].position)
00854       break;
00855   return(line);
00856 }
00857 
00858 /*
00859  * This routine maps a source position into the corresponding line number
00860  * and the x, y coordinates of the text that is displayed in the window.
00861  *
00862  * NOTE: It is illegal to call this routine unless there is a valid line table!
00863  */
00864 
00865 static Boolean
00866 LineAndXYForPosition (ctx, pos, line, x, y)
00867 TextWidget ctx;
00868 XawTextPosition pos;
00869 int *line;
00870 Position *x, *y;
00871 {
00872   XawTextPosition linePos, endPos;
00873   Boolean visible;
00874   int realW, realH;
00875 
00876   *line = 0;
00877   *x = ctx->text.margin.left;
00878   *y = ctx->text.margin.top;
00879   if ((visible = IsPositionVisible(ctx, pos))) {
00880     *line = LineForPosition(ctx, pos);
00881     *y = ctx->text.lt.info[*line].y;
00882     *x = ctx->text.margin.left;
00883     linePos = ctx->text.lt.info[*line].position;
00884     XawTextSinkFindDistance( ctx->text.sink, linePos,
00885                             *x, pos, &realW, &endPos, &realH);
00886     *x += realW;
00887   }
00888   return(visible);
00889 }
00890 
00891 /*
00892  * This routine builds a line table. It does this by starting at the
00893  * specified position and measuring text to determine the staring position
00894  * of each line to be displayed. It also determines and saves in the
00895  * linetable all the required metrics for displaying a given line (e.g.
00896  * x offset, y offset, line length, etc.).
00897  */
00898 
00899 void 
00900 #if NeedFunctionPrototypes
00901 _XawTextBuildLineTable (
00902     TextWidget ctx,
00903     XawTextPosition position,
00904     _XtBoolean force_rebuild)
00905 #else
00906 _XawTextBuildLineTable (ctx, position, force_rebuild)
00907     TextWidget ctx;
00908     XawTextPosition position;
00909     Boolean force_rebuild;
00910 #endif
00911 {
00912   Dimension height = 0;
00913   int lines = 0; 
00914   Cardinal size;
00915 
00916   if ((int)ctx->core.height > VMargins(ctx)) {
00917     height = ctx->core.height - VMargins(ctx);
00918     lines = XawTextSinkMaxLines(ctx->text.sink, height);
00919   }
00920   size = sizeof(XawTextLineTableEntry) * (lines + 1);
00921 
00922   if ( (lines != ctx->text.lt.lines) || (ctx->text.lt.info == NULL) ) {
00923     ctx->text.lt.info = (XawTextLineTableEntry *) XtRealloc((char *) ctx->text.
00924                                                             lt.info, size);
00925     ctx->text.lt.lines = lines;
00926     force_rebuild = TRUE;
00927   }
00928 
00929   if ( force_rebuild || (position != ctx->text.lt.top) ) {
00930     (void) bzero((char *) ctx->text.lt.info, size);
00931     (void) _BuildLineTable(ctx, ctx->text.lt.top = position, zeroPosition, 0);
00932   }
00933 }
00934 
00935 /*
00936  * This assumes that the line table does not change size.
00937  */
00938 
00939 static XawTextPosition
00940 _BuildLineTable(ctx, position, min_pos, line)
00941 TextWidget ctx;
00942 XawTextPosition position, min_pos;      
00943 int line;
00944 {
00945   XawTextLineTableEntry * lt = ctx->text.lt.info + line;
00946   XawTextPosition endPos;
00947   Position y;
00948   int count, width, realW, realH;
00949   Widget src = ctx->text.source;
00950 
00951   if ( ((ctx->text.resize == XawtextResizeWidth) ||
00952         (ctx->text.resize == XawtextResizeBoth)    ) ||
00953        (ctx->text.wrap == XawtextWrapNever) )
00954     width = BIGNUM;
00955   else 
00956     width = Max(0, ((int)ctx->core.width - (int)HMargins(ctx)));
00957 
00958   y = ( (line == 0) ? ctx->text.margin.top : lt->y );
00959 
00960   /* CONSTCOND */
00961   while ( TRUE ) {
00962     lt->y = y;
00963     lt->position = position;
00964     
00965     XawTextSinkFindPosition( ctx->text.sink, position, ctx->text.margin.left,
00966                             width, ctx->text.wrap == XawtextWrapWord,
00967                             &endPos, &realW, &realH);
00968     lt->textWidth = realW;
00969     y += realH;
00970 
00971     if (ctx->text.wrap == XawtextWrapNever) 
00972       endPos = SrcScan(src, position, XawstEOL, XawsdRight, 1, TRUE);
00973 
00974     if ( endPos == ctx->text.lastPos) { /* We have reached the end. */
00975       if(SrcScan(src, position, XawstEOL, XawsdRight, 1, FALSE) == endPos)
00976         break;
00977     }
00978 
00979     ++lt;
00980     ++line;
00981     if ( (line > ctx->text.lt.lines) ||
00982          ((lt->position == (position = endPos)) && (position > min_pos)) )
00983       return(position);
00984   }
00985 
00986 /*
00987  * If we are at the end of the buffer put two special lines in the table.
00988  *
00989  * a) Both have position > text.lastPos and lt->textWidth = 0.
00990  * b) The first has a real height, and the second has a height that
00991  *    is the rest of the screen.
00992  *
00993  * I could fill in the rest of the table with valid heights and a large
00994  * lastPos, but this method keeps the number of fill regions down to a 
00995  * minimum.
00996  *
00997  * One valid entry is needed at the end of the table so that the cursor
00998  * does not jump off the bottom of the window.
00999  */
01000 
01001   for ( count = 0; count < 2 ; count++) 
01002     if (line++ < ctx->text.lt.lines) { /* make sure not to run of the end. */
01003       (++lt)->y = (count == 0) ? y : ctx->core.height;
01004       lt->textWidth = 0;
01005       lt->position = ctx->text.lastPos + 100;
01006     }
01007 
01008   if (line < ctx->text.lt.lines) /* Clear out rest of table. */
01009     (void) bzero( (char *) (lt + 1), 
01010           (ctx->text.lt.lines - line) * sizeof(XawTextLineTableEntry) );
01011 
01012   ctx->text.lt.info[ctx->text.lt.lines].position = lt->position;
01013 
01014   return(endPos);
01015 }
01016 
01017 /*      Function Name: GetWidestLine
01018  *      Description: Returns the width (in pixels) of the widest line that
01019  *                   is currently visable.
01020  *      Arguments: ctx - the text widget.
01021  *      Returns: the width of the widest line.
01022  *
01023  * NOTE: This function requires a valid line table.
01024  */
01025 
01026 static Dimension
01027 GetWidestLine(ctx)
01028 TextWidget ctx;
01029 {
01030   int i;
01031   Dimension widest;
01032   XawTextLineTablePtr lt = &(ctx->text.lt);
01033 
01034   for (i = 0, widest = 1 ; i < lt->lines ; i++)
01035     if (widest < lt->info[i].textWidth)
01036       widest = lt->info[i].textWidth;
01037   
01038   return(widest);
01039 }
01040 
01041 static void
01042 CheckVBarScrolling(ctx)
01043 TextWidget ctx;
01044 {
01045   float first, last;
01046   Boolean temp = (ctx->text.vbar == NULL);
01047 
01048   if (ctx->text.scroll_vert == XawtextScrollNever) return;
01049 
01050   if ( (ctx->text.lastPos > 0) && (ctx->text.lt.lines > 0)) {
01051     first = ctx->text.lt.top;
01052     first /= (float) ctx->text.lastPos;
01053     last = ctx->text.lt.info[ctx->text.lt.lines].position;
01054     if ( ctx->text.lt.info[ctx->text.lt.lines].position < ctx->text.lastPos )
01055       last /= (float) ctx->text.lastPos;
01056     else 
01057       last = 1.0;
01058 
01059     if (ctx->text.scroll_vert == XawtextScrollWhenNeeded) {
01060       int line;
01061       XawTextPosition last_pos;
01062       Position y = ctx->core.height - ctx->text.margin.bottom;  
01063 
01064       if (ctx->text.hbar != NULL)
01065         y -= (ctx->text.hbar->core.height +
01066               2 * ctx->text.hbar->core.border_width);
01067 
01068       last_pos = PositionForXY(ctx, (Position) ctx->core.width, y);
01069       line = LineForPosition(ctx, last_pos);
01070 
01071       if ( (y < ctx->text.lt.info[line + 1].y) || ((last - first) < 1.0) )
01072         CreateVScrollBar(ctx);
01073       else 
01074         DestroyVScrollBar(ctx);
01075     }
01076   
01077     if (ctx->text.vbar != NULL) 
01078       XawScrollbarSetThumb(ctx->text.vbar, first, last - first);
01079   
01080     if ( (ctx->text.vbar == NULL) != temp) {
01081       _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
01082       if (ctx->text.vbar == NULL)
01083         _XawTextBuildLineTable (ctx, zeroPosition, FALSE);
01084     }
01085   }
01086   else if (ctx->text.vbar != NULL)
01087     if (ctx->text.scroll_vert == XawtextScrollWhenNeeded)
01088       DestroyVScrollBar(ctx);
01089     else if (ctx->text.scroll_vert == XawtextScrollAlways)
01090       XawScrollbarSetThumb(ctx->text.vbar, 0.0, 1.0);
01091 }
01092 
01093 /*
01094  * This routine is used by Text to notify an associated scrollbar of the
01095  * correct metrics (position and shown fraction) for the text being currently
01096  * displayed in the window.
01097  */
01098 
01099 void 
01100 _XawTextSetScrollBars(ctx)
01101 TextWidget ctx;
01102 {
01103   float first, last, widest;
01104   Boolean temp = (ctx->text.hbar == NULL);
01105   Boolean vtemp = (ctx->text.vbar == NULL);
01106   
01107   CheckVBarScrolling(ctx);
01108 
01109   if (ctx->text.scroll_horiz == XawtextScrollNever) return;
01110 
01111   if (ctx->text.vbar != NULL) 
01112     widest = (int)(ctx->core.width - ctx->text.vbar->core.width -
01113                    ctx->text.vbar->core.border_width);
01114   else
01115     widest = ctx->core.width;
01116   widest /= (last = GetWidestLine(ctx));
01117   if (ctx->text.scroll_horiz == XawtextScrollWhenNeeded) 
01118     if (widest < 1.0)
01119       CreateHScrollBar(ctx);
01120     else
01121       DestroyHScrollBar(ctx);
01122 
01123   if ( (ctx->text.hbar == NULL) != temp ) {
01124     _XawTextBuildLineTable (ctx, ctx->text.lt.top, TRUE);
01125     CheckVBarScrolling(ctx);    /* Recheck need for vbar, now that we added
01126                                    or removed the hbar.*/
01127   }
01128   
01129   if (ctx->text.hbar != NULL) {
01130     first = ctx->text.r_margin.left - ctx->text.margin.left;
01131     first /= last;
01132     XawScrollbarSetThumb(ctx->text.hbar, first, widest); 
01133   }
01134 
01135   if (((ctx->text.hbar == NULL) && (ctx->text.margin.left !=
01136                                    ctx->text.r_margin.left)) ||
01137       (ctx->text.vbar == NULL) != vtemp)
01138   {
01139     ctx->text.margin.left = ctx->text.r_margin.left;
01140     _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);      
01141     FlushUpdate(ctx);
01142   }
01143 }
01144 
01145 /*
01146  * The routine will scroll the displayed text by lines.  If the arg  is
01147  * positive, move up; otherwise, move down. [note: this is really a private
01148  * procedure but is used in multiple modules].
01149  */
01150 
01151 void
01152 _XawTextVScroll(ctx, n)
01153 TextWidget ctx;
01154 int n;                  
01155 {
01156   XawTextPosition top, target;
01157   int y;
01158   Arg list[1];
01159   XawTextLineTable * lt = &(ctx->text.lt);
01160 
01161   if (abs(n) > ctx->text.lt.lines) 
01162     n = (n > 0) ? ctx->text.lt.lines : -ctx->text.lt.lines;
01163 
01164   if (n == 0) return;
01165 
01166   if (n > 0) {
01167     if ( IsValidLine(ctx, n) )
01168       top = Min(lt->info[n].position, ctx->text.lastPos);
01169     else
01170       top = ctx->text.lastPos;
01171 
01172     y = IsValidLine(ctx, n) ? lt->info[n].y : ctx->core.height;
01173     _XawTextBuildLineTable(ctx, top, FALSE);
01174     if (top >= ctx->text.lastPos)
01175       DisplayTextWindow( (Widget) ctx);
01176     else {
01177       XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
01178                 0, y, (int)ctx->core.width, (int)ctx->core.height - y,
01179                 0, ctx->text.margin.top);
01180 
01181       PushCopyQueue(ctx, 0, (int) -y);
01182       SinkClearToBG(ctx->text.sink, 
01183                     (Position) 0,
01184                     (Position) (ctx->text.margin.top + ctx->core.height - y),
01185                    (Dimension) ctx->core.width, (Dimension) ctx->core.height);
01186 
01187       if (n < lt->lines) n++; /* update descenders at bottom */
01188       _XawTextNeedsUpdating(ctx, lt->info[lt->lines - n].position, 
01189                             ctx->text.lastPos);
01190       _XawTextSetScrollBars(ctx);
01191     }
01192   } 
01193   else {
01194     XawTextPosition updateTo;
01195     unsigned int height, clear_height;
01196 
01197     n = -n;
01198     target = lt->top;
01199     top = SrcScan(ctx->text.source, target, XawstEOL,
01200                   XawsdLeft, n+1, FALSE);
01201 
01202     _XawTextBuildLineTable(ctx, top, FALSE);
01203     y = IsValidLine(ctx, n) ? lt->info[n].y : ctx->core.height;
01204     updateTo = IsValidLine(ctx, n) ? lt->info[n].position : ctx->text.lastPos;
01205     if (IsValidLine(ctx, lt->lines - n))
01206       height = lt->info[lt->lines-n].y - ctx->text.margin.top;
01207     else if (ctx->core.height - HMargins(ctx))
01208       height = ctx->core.height - HMargins(ctx);
01209     else
01210       height = 0;
01211     if (y > (int) ctx->text.margin.top)
01212       clear_height = y - ctx->text.margin.top;
01213     else
01214       clear_height = 0;
01215 
01216     if ( updateTo == target ) {
01217       XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc, 
01218                 0, ctx->text.margin.top, (int) ctx->core.width, height, 0, y);
01219       PushCopyQueue(ctx, 0, (int) y);
01220       SinkClearToBG(ctx->text.sink, (Position) 0, ctx->text.margin.top,
01221                    (Dimension) ctx->core.width, (Dimension) clear_height);
01222       
01223       _XawTextNeedsUpdating(ctx, lt->info[0].position, updateTo);
01224       _XawTextSetScrollBars(ctx);
01225     } 
01226     else if (lt->top != target)
01227       DisplayTextWindow((Widget)ctx);
01228   }
01229   XtSetArg (list[0], XtNinsertPosition, ctx->text.lt.top+ctx->text.lt.lines);
01230   _XawImSetValues ((Widget) ctx, list, 1);
01231 }
01232 
01233 /*ARGSUSED*/
01234 static void 
01235 HScroll(w, closure, callData)
01236 Widget w;
01237 XtPointer closure;              /* TextWidget */
01238 XtPointer callData;             /* #pixels */
01239 {
01240   TextWidget ctx = (TextWidget) closure;
01241   Widget tw = (Widget) ctx;
01242   Position old_left, pixels = (Position)(int) callData;
01243   XRectangle rect, t_rect;
01244   
01245   _XawTextPrepareToUpdate(ctx);
01246 
01247   old_left = ctx->text.margin.left;
01248   ctx->text.margin.left -= pixels;
01249   if (ctx->text.margin.left > ctx->text.r_margin.left) {
01250     ctx->text.margin.left = ctx->text.r_margin.left;
01251     pixels = old_left - ctx->text.margin.left;
01252   }
01253   
01254   if (pixels > 0) {
01255     rect.width = (unsigned short) pixels + ctx->text.margin.right;
01256     rect.x = (short) ctx->core.width - (short) rect.width;
01257     rect.y = (short) ctx->text.margin.top;
01258     rect.height = (unsigned short) ctx->core.height - rect.y;
01259 
01260     XCopyArea(XtDisplay(tw), XtWindow(tw), XtWindow(tw), ctx->text.gc,
01261               pixels, (int) rect.y,
01262               (unsigned int) rect.x, (unsigned int) ctx->core.height,
01263               0, (int) rect.y);
01264 
01265     PushCopyQueue(ctx, (int) -pixels, 0);
01266   }
01267   else if (pixels < 0) {
01268     rect.x = 0;
01269 
01270     if (ctx->text.vbar != NULL)
01271       rect.x += (short) (ctx->text.vbar->core.width +
01272                          ctx->text.vbar->core.border_width);
01273 
01274     rect.width = (Position) - pixels;
01275     rect.y = ctx->text.margin.top;
01276     rect.height = ctx->core.height - rect.y;
01277 
01278     XCopyArea(XtDisplay(tw), XtWindow(tw), XtWindow(tw), ctx->text.gc,
01279               (int) rect.x, (int) rect.y,
01280               (unsigned int) ctx->core.width - rect.width,
01281               (unsigned int) rect.height,
01282               (int) rect.x + rect.width, (int) rect.y);
01283 
01284     PushCopyQueue(ctx, (int) rect.width, 0);
01285 
01286 /*
01287  * Redraw the line overflow marks.
01288  */
01289 
01290     t_rect.x = ctx->core.width - ctx->text.margin.right;
01291     t_rect.width = ctx->text.margin.right;
01292     t_rect.y = rect.y;
01293     t_rect.height = rect.height;
01294       
01295     SinkClearToBG(ctx->text.sink, (Position) t_rect.x, (Position) t_rect.y,
01296                   (Dimension) t_rect.width, (Dimension) t_rect.height);
01297     
01298     UpdateTextInRectangle(ctx, &t_rect);
01299   }
01300 
01301 /*  
01302  * Put in the text that just became visible.
01303  */
01304 
01305   if ( pixels != 0 ) {
01306     SinkClearToBG(ctx->text.sink, (Position) rect.x, (Position) rect.y,
01307                   (Dimension) rect.width, (Dimension) rect.height);
01308     
01309     UpdateTextInRectangle(ctx, &rect);
01310   }
01311   _XawTextExecuteUpdate(ctx);
01312   _XawTextSetScrollBars(ctx);
01313 }
01314 
01315 /*ARGSUSED*/
01316 static void 
01317 HJump(w, closure, callData)
01318 Widget w;
01319 XtPointer closure, callData; /* closure = TextWidget, callData = percent. */
01320 {
01321   TextWidget ctx = (TextWidget) closure;
01322   float * percent = (float *) callData;
01323   Position new_left, old_left = ctx->text.margin.left;
01324 
01325   long move; /*difference of Positions can be bigger than Position; lint err */
01326 
01327   new_left = ctx->text.r_margin.left;
01328   new_left -= (Position) (*percent * GetWidestLine(ctx));
01329   move = old_left - new_left;
01330 
01331   if (abs(move) < (int)ctx->core.width) {
01332     HScroll(w, (XtPointer) ctx, (XtPointer) move);
01333     return;
01334   }
01335   _XawTextPrepareToUpdate(ctx);
01336   ctx->text.margin.left = new_left;
01337   if (XtIsRealized((Widget) ctx)) DisplayTextWindow((Widget) ctx); 
01338   _XawTextExecuteUpdate(ctx);
01339 }
01340 
01341 /*      Function Name: UpdateTextInLine
01342  *      Description: Updates some text in a given line.
01343  *      Arguments: ctx - the text widget.
01344  *                 line - the line number (in the line table) of this line.
01345  *                 left, right - left and right pixel offsets of the
01346  *                               area to update.
01347  *      Returns: none.
01348  */
01349 
01350 static void
01351 UpdateTextInLine(ctx, line, left, right)
01352 TextWidget ctx;
01353 int line;
01354 Position left, right;
01355 {
01356   XawTextPosition pos1, pos2; 
01357   int width, height, local_left, local_width;
01358   XawTextLineTableEntry * lt = ctx->text.lt.info + line;
01359 
01360   if ( ((int)(lt->textWidth + ctx->text.margin.left) < left) ||
01361        ( ctx->text.margin.left > right ) )
01362     return;                     /* no need to update. */
01363 
01364   local_width = left - ctx->text.margin.left;
01365   XawTextSinkFindPosition(ctx->text.sink, lt->position,
01366                           (int) ctx->text.margin.left, 
01367                           local_width, FALSE, &pos1, &width, &height);
01368 
01369   if (right >= (Position) lt->textWidth - ctx->text.margin.left) 
01370     if ( (IsValidLine(ctx, line + 1)) &&
01371          (ctx->text.lt.info[line + 1].position <= ctx->text.lastPos) )
01372       pos2 = SrcScan( ctx->text.source, (lt + 1)->position, XawstPositions, 
01373                            XawsdLeft, 1, TRUE);
01374     else 
01375       pos2 = GETLASTPOS;
01376   else {
01377     XawTextPosition t_pos;
01378 
01379     local_left = ctx->text.margin.left + width;
01380     local_width = right  - local_left;
01381     XawTextSinkFindPosition(ctx->text.sink, pos1, local_left,
01382                             local_width, FALSE, &pos2, &width, &height);
01383     
01384     t_pos = SrcScan( ctx->text.source, pos2,
01385                      XawstPositions, XawsdRight, 1, TRUE);
01386     if (t_pos < (lt + 1)->position)
01387       pos2 = t_pos;
01388   }
01389 
01390   _XawTextNeedsUpdating(ctx, pos1, pos2);
01391 }
01392 
01393 /*
01394  * The routine will scroll the displayed text by pixels.  If the calldata is
01395  * positive, move up; otherwise, move down.
01396  */
01397 
01398 /*ARGSUSED*/
01399 static void 
01400 VScroll(w, closure, callData)
01401 Widget w;
01402 XtPointer closure;              /* TextWidget */
01403 XtPointer callData;             /* #pixels */
01404 {
01405   TextWidget ctx = (TextWidget)closure;
01406   int height, nlines, lines = (int) callData;
01407 
01408   height = ctx->core.height - VMargins(ctx);
01409   if (height < 1)
01410     height = 1;
01411   nlines = (int) (lines * (int) ctx->text.lt.lines) / height;
01412 #ifdef ARROW_SCROLLBAR
01413   if (nlines == 0 && lines != 0) 
01414     nlines = lines > 0 ? 1 : -1;
01415 #endif
01416   _XawTextPrepareToUpdate(ctx);
01417   _XawTextVScroll(ctx, nlines);
01418   _XawTextExecuteUpdate(ctx);
01419 }
01420 
01421 /*
01422  * The routine "thumbs" the displayed text. Thumbing means reposition the
01423  * displayed view of the source to a new position determined by a fraction
01424  * of the way from beginning to end. Ideally, this should be determined by
01425  * the number of displayable lines in the source. This routine does it as a
01426  * fraction of the first position and last position and then normalizes to
01427  * the start of the line containing the position.
01428  *
01429  * BUG/deficiency: The normalize to line portion of this routine will
01430  * cause thumbing to always position to the start of the source.
01431  */
01432 
01433 /*ARGSUSED*/
01434 static void 
01435 VJump(w, closure, callData)
01436 Widget w;
01437 XtPointer closure, callData; /* closuer = TextWidget, callData = percent. */
01438 {
01439   float * percent = (float *) callData;
01440   TextWidget ctx = (TextWidget)closure;
01441   XawTextPosition position, old_top, old_bot;
01442   XawTextLineTable * lt = &(ctx->text.lt);
01443 
01444   _XawTextPrepareToUpdate(ctx);
01445   old_top = lt->top;
01446   if ( (lt->lines > 0) && (IsValidLine(ctx, lt->lines - 1)) )
01447     old_bot = lt->info[lt->lines - 1].position;
01448   else
01449     old_bot = ctx->text.lastPos;
01450 
01451   position = (long) (*percent * (float) ctx->text.lastPos);
01452   position= SrcScan(ctx->text.source, position, XawstEOL, XawsdLeft, 1, FALSE);
01453   if ( (position >= old_top) && (position <= old_bot) ) {
01454     int line = 0;
01455     for (;(line < lt->lines) && (position > lt->info[line].position) ; line++);
01456     _XawTextVScroll(ctx, line);
01457   }
01458   else {
01459     XawTextPosition new_bot;
01460     _XawTextBuildLineTable(ctx, position, FALSE);
01461     new_bot = IsValidLine(ctx, lt->lines-1) ? lt->info[lt->lines-1].position 
01462                                             : ctx->text.lastPos;
01463 
01464     if ((old_top >= lt->top) && (old_top <= new_bot)) {
01465       int line = 0;
01466       for (;(line < lt->lines) && (old_top > lt->info[line].position); line++);
01467       _XawTextBuildLineTable(ctx, old_top, FALSE);
01468       _XawTextVScroll(ctx, -line);
01469     }
01470     else 
01471       DisplayTextWindow( (Widget) ctx);
01472   }
01473   _XawTextExecuteUpdate(ctx);
01474 }
01475 
01476 static Boolean
01477 MatchSelection(selection, s)
01478 Atom                selection;
01479 XawTextSelection    *s;
01480 {
01481     Atom    *match;
01482     int     count;
01483 
01484     for (count = 0, match = s->selections; count < s->atom_count; match++, count++)
01485         if (*match == selection)
01486             return True;
01487     return False;
01488 }
01489 
01490 static Boolean 
01491 ConvertSelection(w, selection, target, type, value, length, format)
01492 Widget w;
01493 Atom *selection, *target, *type;
01494 XtPointer *value;
01495 unsigned long *length;
01496 int *format;
01497 {
01498   Display* d = XtDisplay(w);
01499   TextWidget ctx = (TextWidget)w;
01500   Widget src = ctx->text.source;
01501   XawTextEditType edit_mode;
01502   Arg args[1];
01503 
01504   XawTextSelectionSalt  *salt = NULL;
01505   XawTextSelection      *s;
01506 
01507   if (*target == XA_TARGETS(d)) {
01508     Atom* targetP, * std_targets;
01509     unsigned long std_length;
01510 
01511     if ( SrcCvtSel(src, selection, target, type, value, length, format) ) 
01512         return True;
01513 
01514     XmuConvertStandardSelection(w, ctx->text.time, selection, 
01515                                 target, type, (XPointer*)&std_targets,
01516                                 &std_length, format);
01517     
01518     *value = XtMalloc((unsigned) sizeof(Atom)*(std_length + 7));
01519     targetP = *(Atom**)value;
01520     *length = std_length + 6;
01521     *targetP++ = XA_STRING;
01522     *targetP++ = XA_TEXT(d);
01523     *targetP++ = XA_COMPOUND_TEXT(d);
01524     *targetP++ = XA_LENGTH(d);
01525     *targetP++ = XA_LIST_LENGTH(d);
01526     *targetP++ = XA_CHARACTER_POSITION(d);
01527 
01528     XtSetArg(args[0], XtNeditType,&edit_mode);
01529     XtGetValues(src, args, ONE);
01530 
01531     if (edit_mode == XawtextEdit) {
01532       *targetP++ = XA_DELETE(d);
01533       (*length)++;
01534     }
01535     (void) memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
01536     XtFree((char*)std_targets);
01537     *type = XA_ATOM;
01538     *format = 32;
01539     return True;
01540   }
01541   
01542   if ( SrcCvtSel(src, selection, target, type, value, length, format) )
01543     return True;
01544 
01545   if (MatchSelection (*selection, &ctx->text.s))
01546     s = &ctx->text.s;
01547   else
01548   {
01549     for (salt = ctx->text.salt; salt; salt = salt->next)
01550         if (MatchSelection (*selection, &salt->s))
01551             break;
01552     if (!salt)
01553         return False;
01554     s = &salt->s;
01555   }
01556   if (*target == XA_STRING ||
01557       *target == XA_TEXT(d) ||
01558       *target == XA_COMPOUND_TEXT(d)) {
01559         if (*target == XA_TEXT(d)) {
01560             if (_XawTextFormat(ctx) == XawFmtWide)
01561                 *type = XA_COMPOUND_TEXT(d);
01562             else
01563                 *type = XA_STRING;
01564         } else {
01565             *type = *target;
01566         }
01567         /* 
01568          * If salt is True, the salt->contents stores CT string, 
01569          * its length is measured in bytes.
01570          * Refer to _XawTextSaltAwaySelection().
01571          *
01572          * by Li Yuhong, Mar. 20, 1991.
01573          */
01574         if (!salt) {
01575             *value = _XawTextGetSTRING(ctx, s->left, s->right);
01576             if (_XawTextFormat(ctx) == XawFmtWide) {
01577                 XTextProperty textprop;
01578                 if (XwcTextListToTextProperty(d, (wchar_t **)value, 1,
01579                                               XCompoundTextStyle, &textprop)
01580                         <  Success) {
01581                     XtFree(*value);
01582                     return False;
01583                 }
01584                 XtFree(*value);
01585                 *value = (XtPointer)textprop.value;
01586                 *length = textprop.nitems;
01587             } else {
01588                 *length = strlen(*value);
01589             }
01590         } else {
01591             *value = XtMalloc((salt->length + 1) * sizeof(unsigned char));
01592             strcpy (*value, salt->contents);
01593             *length = salt->length;
01594         }
01595         if (_XawTextFormat(ctx) == XawFmtWide && *type == XA_STRING) {
01596             XTextProperty textprop;
01597             wchar_t **wlist;
01598             int count;
01599             textprop.encoding = XA_COMPOUND_TEXT(d);
01600             textprop.value = (unsigned char *)*value;
01601             textprop.nitems = strlen(*value);
01602             textprop.format = 8;
01603             if (XwcTextPropertyToTextList(d, &textprop, (wchar_t ***)&wlist, &count)
01604                         < Success) {
01605                 XtFree(*value);
01606                 return False;
01607             }
01608             XtFree(*value);
01609             if (XwcTextListToTextProperty( d, (wchar_t **)wlist, 1,
01610                                           XStringStyle, &textprop) < Success) {
01611                 XwcFreeStringList( (wchar_t**) wlist );
01612                 return False;
01613             }
01614             *value = (XtPointer) textprop.value;
01615             *length = textprop.nitems;
01616             XwcFreeStringList( (wchar_t**) wlist );
01617         }
01618         *format = 8;
01619         return True;
01620   }
01621 
01622   if ( (*target == XA_LIST_LENGTH(d)) || (*target == XA_LENGTH(d)) ) {
01623     long * temp;
01624     
01625     temp = (long *) XtMalloc( (unsigned) sizeof(long) );
01626     if (*target == XA_LIST_LENGTH(d))
01627       *temp = 1L;
01628     else                        /* *target == XA_LENGTH(d) */
01629       *temp = (long) (s->right - s->left);
01630     
01631     *value = (XPointer) temp;
01632     *type = XA_INTEGER;
01633     *length = 1L;
01634     *format = 32;
01635     return True;
01636   }
01637 
01638   if (*target == XA_CHARACTER_POSITION(d)) {
01639     long * temp;
01640     
01641     temp = (long *) XtMalloc( (unsigned)( 2 * sizeof(long) ) );
01642     temp[0] = (long) (s->left + 1);
01643     temp[1] = s->right;
01644     *value = (XPointer) temp;
01645     *type = XA_SPAN(d);
01646     *length = 2L;
01647     *format = 32;
01648     return True;
01649   }
01650 
01651   if (*target == XA_DELETE(d)) {
01652     void _XawTextZapSelection(); /* From TextAction.c */
01653     
01654     if (!salt)
01655         _XawTextZapSelection( ctx, (XEvent *) NULL, TRUE);
01656     *value = NULL;
01657     *type = XA_NULL(d);
01658     *length = 0;
01659     *format = 32;
01660     return True;
01661   }
01662 
01663   if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
01664                                   (XPointer *)value, length, format))
01665     return True;
01666   
01667   /* else */
01668   return False;
01669 }
01670 
01671 /*      Function Name: GetCutBuffferNumber
01672  *      Description: Returns the number of the cut buffer.
01673  *      Arguments: atom - the atom to check.
01674  *      Returns: the number of the cut buffer representing this atom or
01675  *               NOT_A_CUT_BUFFER.
01676  */
01677 
01678 #define NOT_A_CUT_BUFFER -1
01679 
01680 static int
01681 GetCutBufferNumber(atom)
01682 Atom atom;
01683 {
01684   if (atom == XA_CUT_BUFFER0) return(0);
01685   if (atom == XA_CUT_BUFFER1) return(1);
01686   if (atom == XA_CUT_BUFFER2) return(2);
01687   if (atom == XA_CUT_BUFFER3) return(3);
01688   if (atom == XA_CUT_BUFFER4) return(4);
01689   if (atom == XA_CUT_BUFFER5) return(5);
01690   if (atom == XA_CUT_BUFFER6) return(6);
01691   if (atom == XA_CUT_BUFFER7) return(7);
01692   return(NOT_A_CUT_BUFFER);
01693 }
01694 
01695 static void 
01696 LoseSelection(w, selection)
01697 Widget w;
01698 Atom *selection;
01699 {
01700   TextWidget ctx = (TextWidget) w;
01701   Atom* atomP;
01702   int i;
01703   XawTextSelectionSalt  *salt, *prevSalt, *nextSalt;
01704 
01705   _XawTextPrepareToUpdate(ctx);
01706 
01707   atomP = ctx->text.s.selections;
01708   for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
01709     if ( (*selection == *atomP) || 
01710         (GetCutBufferNumber(*atomP) != NOT_A_CUT_BUFFER) )/* is a cut buffer */
01711       *atomP = (Atom)0;
01712 
01713   while (ctx->text.s.atom_count &&
01714          ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
01715     ctx->text.s.atom_count--;
01716 
01717 /*
01718  * Must walk the selection list in opposite order from UnsetSelection.
01719  */
01720 
01721   atomP = ctx->text.s.selections;
01722   for (i = 0 ; i < ctx->text.s.atom_count; i++, atomP++)
01723     if (*atomP == (Atom)0) {
01724       *atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
01725       while (ctx->text.s.atom_count &&
01726              ctx->text.s.selections[ctx->text.s.atom_count-1] == 0)
01727         ctx->text.s.atom_count--;
01728     }
01729   
01730   if (ctx->text.s.atom_count == 0)
01731     ModifySelection(ctx, ctx->text.insertPos, ctx->text.insertPos);
01732       
01733   if (ctx->text.old_insert >= 0) /* Update in progress. */
01734     _XawTextExecuteUpdate(ctx);
01735 
01736     prevSalt = 0;
01737     for (salt = ctx->text.salt; salt; salt = nextSalt)
01738     {
01739         atomP = salt->s.selections;
01740         nextSalt = salt->next;
01741         for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
01742             if (*selection == *atomP)
01743                 *atomP = (Atom)0;
01744         
01745         while (salt->s.atom_count &&
01746                salt->s.selections[salt->s.atom_count-1] == 0)
01747         {
01748             salt->s.atom_count--;
01749         }
01750         
01751         /*
01752          * Must walk the selection list in opposite order from UnsetSelection.
01753          */
01754         
01755         atomP = salt->s.selections;
01756         for (i = 0 ; i < salt->s.atom_count; i++, atomP++)
01757             if (*atomP == (Atom)0)
01758             {
01759               *atomP = salt->s.selections[--salt->s.atom_count];
01760               while (salt->s.atom_count &&
01761                      salt->s.selections[salt->s.atom_count-1] == 0)
01762                 salt->s.atom_count--;
01763             }
01764         if (salt->s.atom_count == 0)
01765         {
01766             XtFree ((char *) salt->s.selections);
01767             XtFree (salt->contents);
01768             if (prevSalt)
01769                 prevSalt->next = nextSalt;
01770             else
01771                 ctx->text.salt = nextSalt;
01772             XtFree ((char *) salt);
01773         }
01774         else
01775             prevSalt = salt;
01776     }
01777 }
01778 
01779 void
01780 _XawTextSaltAwaySelection (ctx, selections, num_atoms)
01781 TextWidget ctx;
01782 Atom* selections;
01783 int     num_atoms;
01784 {
01785     XawTextSelectionSalt    *salt;
01786     int                     i, j;
01787 
01788     for (i = 0; i < num_atoms; i++)
01789         LoseSelection ((Widget) ctx, selections + i);
01790     if (num_atoms == 0)
01791         return;
01792     salt = (XawTextSelectionSalt *)
01793                 XtMalloc( (unsigned) sizeof(XawTextSelectionSalt) );
01794     if (!salt)
01795         return;
01796     salt->s.selections = (Atom *)
01797          XtMalloc( (unsigned) ( num_atoms * sizeof (Atom) ) );
01798     if (!salt->s.selections)
01799     {
01800         XtFree ((char *) salt);
01801         return;
01802     }
01803     salt->s.left = ctx->text.s.left;
01804     salt->s.right = ctx->text.s.right;
01805     salt->s.type = ctx->text.s.type;
01806     salt->contents = _XawTextGetSTRING(ctx, ctx->text.s.left, ctx->text.s.right);
01807     if (_XawTextFormat(ctx) == XawFmtWide) {
01808         XTextProperty textprop;
01809         if (XwcTextListToTextProperty(XtDisplay((Widget)ctx),
01810                         (wchar_t**)(&(salt->contents)), 1, XCompoundTextStyle,
01811                         &textprop) < Success) {
01812             XtFree(salt->contents);
01813             salt->length = 0;
01814             return;
01815         }
01816         XtFree(salt->contents);
01817         salt->contents = (char *)textprop.value;
01818         salt->length = textprop.nitems;
01819     } else
01820        salt->length = strlen (salt->contents);
01821     salt->next = ctx->text.salt;
01822     ctx->text.salt = salt;
01823     j = 0;
01824     for (i = 0; i < num_atoms; i++)
01825     {
01826         if (GetCutBufferNumber (selections[i]) == NOT_A_CUT_BUFFER)
01827         {
01828             salt->s.selections[j++] = selections[i];
01829             XtOwnSelection ((Widget) ctx, selections[i], ctx->text.time,
01830                     ConvertSelection, LoseSelection, (XtSelectionDoneProc)NULL);
01831         }
01832     }
01833     salt->s.atom_count = j;
01834 }
01835 
01836 static void 
01837 _SetSelection(ctx, left, right, selections, count)
01838 TextWidget ctx;
01839 XawTextPosition left, right;
01840 Atom *selections;
01841 Cardinal count;
01842 {
01843   XawTextPosition pos;
01844   
01845   if (left < ctx->text.s.left) {
01846     pos = Min(right, ctx->text.s.left);
01847     _XawTextNeedsUpdating(ctx, left, pos);
01848   }
01849   if (left > ctx->text.s.left) {
01850     pos = Min(left, ctx->text.s.right);
01851     _XawTextNeedsUpdating(ctx, ctx->text.s.left, pos);
01852   }
01853   if (right < ctx->text.s.right) {
01854     pos = Max(right, ctx->text.s.left);
01855     _XawTextNeedsUpdating(ctx, pos, ctx->text.s.right);
01856   }
01857   if (right > ctx->text.s.right) {
01858     pos = Max(left, ctx->text.s.right);
01859     _XawTextNeedsUpdating(ctx, pos, right);
01860   }
01861   
01862   ctx->text.s.left = left;
01863   ctx->text.s.right = right;
01864 
01865   SrcSetSelection(ctx->text.source, left, right,
01866                   (count == 0) ? None : selections[0]);
01867 
01868   if (left < right) {
01869     Widget w = (Widget) ctx;
01870     int buffer;
01871     
01872     while (count) {
01873       Atom selection = selections[--count];
01874 
01875       if ((buffer = GetCutBufferNumber(selection)) != NOT_A_CUT_BUFFER) {
01876 
01877         unsigned char *ptr, *tptr;
01878         unsigned int amount, max_len = MAX_CUT_LEN(XtDisplay(w));
01879         unsigned long len;
01880 
01881         tptr= ptr= (unsigned char *) _XawTextGetSTRING(ctx, ctx->text.s.left, 
01882                                                        ctx->text.s.right);
01883         if (_XawTextFormat(ctx) == XawFmtWide) {
01884            /*
01885             * Only XA_STRING(Latin 1) is allowed in CUT_BUFFER,
01886             * so we get it from wchar string, then free the wchar string.
01887             */
01888             XTextProperty textprop;
01889             if (XwcTextListToTextProperty(XtDisplay(w), (wchar_t**)&ptr, 1,
01890                     XStringStyle, &textprop) <  Success) {
01891                 XtFree((char *)ptr);
01892                 return;
01893             }
01894             XtFree((char *)ptr);
01895             tptr = ptr = textprop.value;
01896         } 
01897         if (buffer == 0) {
01898           _CreateCutBuffers(XtDisplay(w));
01899           XRotateBuffers(XtDisplay(w), 1);
01900         }
01901         amount = Min ( (len = strlen((char *)ptr)), max_len);
01902         XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), selection, 
01903                         XA_STRING, 8, PropModeReplace, ptr, amount);
01904 
01905         while (len > max_len) {
01906             len -= max_len;
01907             tptr += max_len;
01908             amount = Min (len, max_len);
01909             XChangeProperty(XtDisplay(w), RootWindow(XtDisplay(w), 0), 
01910                             selection, XA_STRING, 8, PropModeAppend, 
01911                             tptr, amount);
01912         }
01913         XtFree ((char *)ptr);
01914       }
01915       else                      /* This is a real selection */
01916       XtOwnSelection(w, selection, ctx->text.time, ConvertSelection, 
01917                      LoseSelection, (XtSelectionDoneProc)NULL);
01918     }
01919   }
01920   else
01921     XawTextUnsetSelection((Widget)ctx);
01922 }
01923 
01924 /*
01925  * This internal routine deletes the text from pos1 to pos2 in a source and
01926  * then inserts, at pos1, the text that was passed. As a side effect it
01927  * "invalidates" that portion of the displayed text (if any).
01928  *
01929  * NOTE: It is illegal to call this routine unless there is a valid line table!
01930  */
01931 
01932 int 
01933 _XawTextReplace (ctx, pos1, pos2, text)
01934 TextWidget ctx;
01935 XawTextPosition pos1, pos2;
01936 XawTextBlock *text;
01937 {
01938   int i, line1, delta, error;
01939   XawTextPosition updateFrom, updateTo;
01940   Widget src = ctx->text.source;
01941   XawTextEditType edit_mode;
01942   Arg args[1];
01943   Boolean tmp = ctx->text.update_disabled;
01944 
01945   ctx->text.update_disabled = True; /* No redisplay during replacement. */
01946 
01947 /*
01948  * The insertPos may not always be set to the right spot in XawtextAppend 
01949  */
01950 
01951   XtSetArg(args[0], XtNeditType, &edit_mode);
01952   XtGetValues(src, args, ONE);
01953 
01954   if ((pos1 == ctx->text.insertPos) && (edit_mode == XawtextAppend)) {
01955     ctx->text.insertPos = ctx->text.lastPos;
01956     pos2 = SrcScan(src, ctx->text.insertPos, XawstPositions, XawsdRight,
01957                    (int)(ctx->text.insertPos - pos1), (Boolean)TRUE);
01958     pos1 = ctx->text.insertPos;
01959     if ( (pos1 == pos2) && (text->length == 0) ) {
01960       ctx->text.update_disabled = FALSE; /* rearm redisplay. */
01961       return( XawEditError );
01962     }
01963   }
01964 
01965   updateFrom = SrcScan(src, pos1, XawstWhiteSpace, XawsdLeft, 1, FALSE);
01966   updateFrom = Max(updateFrom, ctx->text.lt.top);
01967 
01968   line1 = LineForPosition(ctx, updateFrom);
01969   if ( (error = SrcReplace(src, pos1, pos2, text)) != 0) {
01970     ctx->text.update_disabled = tmp; /* restore redisplay */
01971     return(error);
01972   }
01973 
01974   XawTextUnsetSelection((Widget)ctx);
01975 
01976   ctx->text.lastPos = GETLASTPOS;
01977   if (ctx->text.lt.top >= ctx->text.lastPos) {
01978     _XawTextBuildLineTable(ctx, ctx->text.lastPos, FALSE);
01979     ClearWindow( (Widget) ctx);
01980     ctx->text.update_disabled = tmp; /* restore redisplay */
01981     return(0);                  /* Things are fine. */
01982   }
01983 
01984   ctx->text.single_char = (text->length <= 1 && pos2 - pos1 <= 1);
01985 
01986   delta = text->length - (pos2 - pos1);
01987 
01988   if (delta < ctx->text.lastPos) {
01989     for (pos2 += delta, i = 0; i < ctx->text.numranges; i++) {
01990       if (ctx->text.updateFrom[i] > pos1)
01991         ctx->text.updateFrom[i] += delta;
01992       if (ctx->text.updateTo[i] >= pos1)
01993         ctx->text.updateTo[i] += delta;
01994     }
01995   }
01996   
01997   /* 
01998    * fixup all current line table entries to reflect edit.
01999    * %%% it is not legal to do arithmetic on positions.
02000    * using Scan would be more proper.
02001    */ 
02002   if (delta != 0) {
02003     XawTextLineTableEntry *lineP;
02004     i = LineForPosition(ctx, pos1) + 1;
02005     for (lineP = ctx->text.lt.info + i; i <= ctx->text.lt.lines; i++, lineP++)
02006       lineP->position += delta;
02007   }
02008   
02009   /*
02010    * Now process the line table and fixup in case edits caused
02011    * changes in line breaks. If we are breaking on word boundaries,
02012    * this code checks for moving words to and from lines.
02013    */
02014   
02015   if (IsPositionVisible(ctx, updateFrom)) {
02016     updateTo = _BuildLineTable(ctx, 
02017                                ctx->text.lt.info[line1].position, pos1, line1);
02018     _XawTextNeedsUpdating(ctx, updateFrom, updateTo);
02019   }
02020 
02021   ctx->text.update_disabled = tmp; /* restore redisplay */
02022   return(0);                    /* Things are fine. */
02023 }
02024 
02025 /*
02026  * This routine will display text between two arbitrary source positions.
02027  * In the event that this span contains highlighted text for the selection, 
02028  * only that portion will be displayed highlighted.
02029  *
02030  * NOTE: it is illegal to call this routine unless there
02031  *       is a valid line table! 
02032  */
02033 
02034 static void 
02035 DisplayText(w, pos1, pos2)
02036 Widget w;
02037 XawTextPosition pos1, pos2;
02038 {
02039   TextWidget ctx = (TextWidget)w;
02040   Position x, y;
02041   int height, line, i, lastPos = ctx->text.lastPos;
02042   XawTextPosition startPos, endPos;
02043   Boolean clear_eol, done_painting;
02044 
02045   pos1 = (pos1 < ctx->text.lt.top) ? ctx->text.lt.top : pos1;
02046   pos2 = FindGoodPosition(ctx, pos2);
02047   if ( (pos1 >= pos2) || !LineAndXYForPosition(ctx, pos1, &line, &x, &y) )
02048     return;                     /* line not visible, or pos1 >= pos2. */
02049 
02050   for ( startPos = pos1, i = line; IsValidLine(ctx, i) && 
02051                                    (i < ctx->text.lt.lines) ; i++) {
02052 
02053     
02054     if ( (endPos = ctx->text.lt.info[i + 1].position) > pos2 ) {
02055       clear_eol = ((endPos = pos2) >= lastPos);
02056       done_painting = (!clear_eol || ctx->text.single_char);
02057     }
02058     else {
02059       clear_eol = TRUE;
02060       done_painting = FALSE;
02061     }
02062 
02063     height = ctx->text.lt.info[i + 1].y - ctx->text.lt.info[i].y;
02064 
02065     if ( (endPos > startPos) ) {
02066       if ( (x == (Position) ctx->text.margin.left) && (x > 0) )
02067          SinkClearToBG (ctx->text.sink,
02068                         (Position) 0, y, 
02069                         (Dimension) ctx->text.margin.left, (Dimension)height); 
02070 
02071       if ( (startPos >= ctx->text.s.right) || (endPos <= ctx->text.s.left) ) 
02072         XawTextSinkDisplayText(ctx->text.sink, x, y, startPos, endPos, FALSE);
02073       else if ((startPos >= ctx->text.s.left) && (endPos <= ctx->text.s.right))
02074         XawTextSinkDisplayText(ctx->text.sink, x, y, startPos, endPos, TRUE);
02075       else {
02076         DisplayText(w, startPos, ctx->text.s.left);
02077         DisplayText(w, Max(startPos, ctx->text.s.left),
02078                     Min(endPos, ctx->text.s.right));
02079         DisplayText(w, ctx->text.s.right, endPos);
02080       }
02081     }
02082     startPos = endPos;
02083     if (clear_eol) {
02084         SinkClearToBG(ctx->text.sink, 
02085                       (Position) (ctx->text.lt.info[i].textWidth +
02086                                   ctx->text.margin.left),
02087                       (Position) y, w->core.width, (Dimension) height);
02088 
02089         /*
02090          * We only get here if single character is true, and we need
02091          * to clear to the end of the screen.  We know that since there
02092          * was only one character deleted that this is the same
02093          * as clearing an extra line, so we do this, and are done.
02094          * 
02095          * This a performance hack, and a pretty gross one, but it works.
02096          *
02097          * Chris Peterson 11/13/89.
02098          */
02099 
02100         if (done_painting) {
02101             y += height;
02102             SinkClearToBG(ctx->text.sink, 
02103                           (Position) ctx->text.margin.left, (Position) y, 
02104                           w->core.width, (Dimension) height);
02105 
02106             break;              /* set single_char to FALSE and return. */
02107         }
02108     }
02109 
02110     x = (Position) ctx->text.margin.left;
02111     y = ctx->text.lt.info[i + 1].y;
02112     if ( done_painting
02113          || (y >= (int)(ctx->core.height - ctx->text.margin.bottom)) )
02114       break;
02115   }
02116   ctx->text.single_char = FALSE;
02117 }
02118 
02119 /*
02120  * This routine implements multi-click selection in a hardwired manner.
02121  * It supports multi-click entity cycling (char, word, line, file) and mouse
02122  * motion adjustment of the selected entitie (i.e. select a word then, with
02123  * button still down, adjust wich word you really meant by moving the mouse).
02124  * [NOTE: This routine is to be replaced by a set of procedures that
02125  * will allows clients to implements a wide class of draw through and
02126  * multi-click selection user interfaces.]
02127  */
02128 
02129 static void 
02130 DoSelection (ctx, pos, time, motion)
02131 TextWidget ctx;
02132 XawTextPosition pos;
02133 Time time;
02134 Boolean motion;
02135 {
02136   XawTextPosition newLeft, newRight;
02137   XawTextSelectType newType, *sarray;
02138   Widget src = ctx->text.source;
02139 
02140   if (motion)
02141     newType = ctx->text.s.type;
02142   else {
02143     if ( (abs((long) time - (long) ctx->text.lasttime) < MULTI_CLICK_TIME) &&
02144          ((pos >= ctx->text.s.left) && (pos <= ctx->text.s.right))) {
02145       sarray = ctx->text.sarray;
02146       for (;*sarray != XawselectNull && *sarray != ctx->text.s.type; sarray++);
02147 
02148       if (*sarray == XawselectNull)
02149         newType = *(ctx->text.sarray);
02150       else {
02151         newType = *(sarray + 1);
02152         if (newType == XawselectNull) 
02153           newType = *(ctx->text.sarray);
02154       }
02155     } 
02156     else                                              /* single-click event */
02157       newType = *(ctx->text.sarray);
02158 
02159     ctx->text.lasttime = time;
02160   }
02161   switch (newType) {
02162   case XawselectPosition: 
02163     newLeft = newRight = pos;
02164     break;
02165   case XawselectChar: 
02166     newLeft = pos;
02167     newRight = SrcScan(src, pos, XawstPositions, XawsdRight, 1, FALSE);
02168     break;
02169   case XawselectWord: 
02170   case XawselectParagraph: 
02171     {
02172       XawTextScanType stype;
02173 
02174       if (newType == XawselectWord)
02175         stype = XawstWhiteSpace;
02176       else
02177         stype = XawstParagraph;
02178 
02179       /*
02180        * Somewhat complicated, but basically I treat the space between
02181        * two objects as another object.  The object that I am currently
02182        * in then becomes the end of the selection.
02183        * 
02184        * Chris Peterson - 4/19/90.
02185        */
02186 
02187       newRight = SrcScan(ctx->text.source, pos, stype, XawsdRight, 1, FALSE);
02188       newRight =SrcScan(ctx->text.source, newRight,stype,XawsdLeft,1, FALSE);
02189 
02190       if (pos != newRight) 
02191         newLeft = SrcScan(ctx->text.source, pos, stype, XawsdLeft, 1, FALSE);
02192       else
02193         newLeft = pos;
02194 
02195       newLeft =SrcScan(ctx->text.source, newLeft, stype, XawsdRight,1,FALSE);
02196 
02197       if (newLeft > newRight) {
02198           XawTextPosition temp = newLeft;
02199           newLeft = newRight;
02200           newRight = temp;
02201       }
02202     }
02203     break;
02204   case XawselectLine: 
02205     newLeft = SrcScan(src, pos, XawstEOL, XawsdLeft, 1, FALSE);
02206     newRight = SrcScan(src, pos, XawstEOL, XawsdRight, 1, FALSE);
02207     break;
02208   case XawselectAll: 
02209     newLeft = SrcScan(src, pos, XawstAll, XawsdLeft, 1, FALSE);
02210     newRight = SrcScan(src, pos, XawstAll, XawsdRight, 1, FALSE);
02211     break;
02212   default:
02213     XtAppWarning(XtWidgetToApplicationContext((Widget) ctx),
02214                "Text Widget: empty selection array.");
02215     return;
02216   }
02217 
02218   if ( (newLeft != ctx->text.s.left) || (newRight != ctx->text.s.right)
02219       || (newType != ctx->text.s.type)) {
02220     ModifySelection(ctx, newLeft, newRight);
02221     if (pos - ctx->text.s.left < ctx->text.s.right - pos)
02222       ctx->text.insertPos = newLeft;
02223     else 
02224       ctx->text.insertPos = newRight;
02225     ctx->text.s.type = newType;
02226   }
02227   if (!motion) { /* setup so we can freely mix select extend calls*/
02228     ctx->text.origSel.type = ctx->text.s.type;
02229     ctx->text.origSel.left = ctx->text.s.left;
02230     ctx->text.origSel.right = ctx->text.s.right;
02231 
02232     if (pos >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
02233       ctx->text.extendDir = XawsdRight;
02234     else
02235       ctx->text.extendDir = XawsdLeft;
02236   }
02237 }
02238 
02239 /*
02240  * This routine implements extension of the currently selected text in
02241  * the "current" mode (i.e. char word, line, etc.). It worries about
02242  * extending from either end of the selection and handles the case when you
02243  * cross through the "center" of the current selection (e.g. switch which
02244  * end you are extending!).
02245  */
02246 
02247 static void 
02248 ExtendSelection (ctx, pos, motion)
02249 TextWidget ctx;
02250 XawTextPosition pos;
02251 Boolean motion;
02252 {
02253   XawTextScanDirection dir;
02254 
02255   if (!motion) {                /* setup for extending selection */
02256     if (ctx->text.s.left == ctx->text.s.right) /* no current selection. */
02257       ctx->text.s.left = ctx->text.s.right = ctx->text.insertPos;   
02258     else {
02259       ctx->text.origSel.left = ctx->text.s.left;
02260       ctx->text.origSel.right = ctx->text.s.right;
02261     }
02262       
02263     ctx->text.origSel.type = ctx->text.s.type;
02264 
02265     if (pos >= ctx->text.s.left + ((ctx->text.s.right - ctx->text.s.left) / 2))
02266         ctx->text.extendDir = XawsdRight;
02267     else
02268         ctx->text.extendDir = XawsdLeft;
02269   }
02270   else /* check for change in extend direction */
02271     if ((ctx->text.extendDir == XawsdRight && pos <= ctx->text.origSel.left) ||
02272         (ctx->text.extendDir == XawsdLeft && pos >= ctx->text.origSel.right)) {
02273       ctx->text.extendDir = (ctx->text.extendDir == XawsdRight) ?
02274                                                     XawsdLeft : XawsdRight;
02275       ModifySelection(ctx, ctx->text.origSel.left, ctx->text.origSel.right);
02276     }
02277 
02278   dir = ctx->text.extendDir;
02279   switch (ctx->text.s.type) {
02280   case XawselectWord: 
02281   case XawselectParagraph:
02282     {
02283       XawTextPosition left_pos, right_pos;
02284       XawTextScanType stype;
02285 
02286       if (ctx->text.s.type == XawselectWord)
02287         stype = XawstWhiteSpace;
02288       else
02289         stype = XawstParagraph;
02290 
02291       /*
02292        * Somewhat complicated, but basically I treat the space between
02293        * two objects as another object.  The object that I am currently
02294        * in then becomes the end of the selection.
02295        * 
02296        * Chris Peterson - 4/19/90.
02297        */
02298 
02299       right_pos = SrcScan(ctx->text.source, pos, stype, XawsdRight, 1, FALSE);
02300       right_pos =SrcScan(ctx->text.source, right_pos,stype,XawsdLeft,1, FALSE);
02301 
02302       if (pos != right_pos) 
02303         left_pos = SrcScan(ctx->text.source, pos, stype, XawsdLeft, 1, FALSE);
02304       else
02305         left_pos = pos;
02306 
02307       left_pos =SrcScan(ctx->text.source, left_pos, stype, XawsdRight,1,FALSE);
02308 
02309       if (dir == XawsdLeft)
02310         pos = Min(left_pos, right_pos);
02311       else /* dir == XawsdRight */
02312         pos = Max(left_pos, right_pos);
02313     }
02314     break;
02315   case XawselectLine:
02316     pos = SrcScan(ctx->text.source, pos, XawstEOL, dir, 1, dir == XawsdRight);
02317     break;
02318   case XawselectAll: 
02319     pos = ctx->text.insertPos;
02320   case XawselectPosition:       /* fall through. */
02321   default:
02322     break;
02323   }
02324   
02325   if (dir == XawsdRight)
02326     ModifySelection(ctx, ctx->text.s.left, pos);
02327   else
02328     ModifySelection(ctx, pos, ctx->text.s.right);
02329 
02330   ctx->text.insertPos = pos;
02331 }
02332 
02333 /*
02334  * Clear the window to background color.
02335  */
02336 
02337 static void
02338 ClearWindow (w)
02339 Widget w;
02340 {
02341   TextWidget ctx = (TextWidget) w;
02342 
02343   if (XtIsRealized(w))
02344     SinkClearToBG(ctx->text.sink, 
02345                   (Position) 0, (Position) 0, 
02346                   w->core.width, w->core.height);
02347 }
02348 
02349 /*      Function Name: _XawTextClearAndCenterDisplay
02350  *      Description: Redraws the display with the cursor in insert point
02351  *                   centered vertically.
02352  *      Arguments: ctx - the text widget.
02353  *      Returns: none.
02354  */
02355 
02356 void
02357 _XawTextClearAndCenterDisplay(ctx)
02358 TextWidget ctx;
02359 {
02360   int insert_line = LineForPosition(ctx, ctx->text.insertPos);
02361   int scroll_by = insert_line - ctx->text.lt.lines/2;
02362 
02363   _XawTextVScroll(ctx, scroll_by);
02364   DisplayTextWindow( (Widget) ctx);
02365 }
02366   
02367 /*
02368  * Internal redisplay entire window.
02369  * Legal to call only if widget is realized.
02370  */
02371 
02372 static void
02373 DisplayTextWindow (w)
02374 Widget w;
02375 {
02376   TextWidget ctx = (TextWidget) w;
02377   ClearWindow(w);
02378   _XawTextBuildLineTable(ctx, ctx->text.lt.top, FALSE);
02379   _XawTextNeedsUpdating(ctx, zeroPosition, ctx->text.lastPos);
02380   _XawTextSetScrollBars(ctx);
02381 }
02382 
02383 /*
02384  * This routine checks to see if the window should be resized (grown or
02385  * shrunk) when text to be painted overflows to the right or
02386  * the bottom of the window. It is used by the keyboard input routine.
02387  */
02388 
02389 void
02390 _XawTextCheckResize(ctx)
02391 TextWidget ctx;
02392 {
02393   Widget w = (Widget) ctx;
02394   int line = 0, old_height;
02395   XtWidgetGeometry rbox, return_geom;
02396 
02397   if ( (ctx->text.resize == XawtextResizeWidth) ||
02398        (ctx->text.resize == XawtextResizeBoth) ) {
02399     XawTextLineTableEntry *lt;
02400     rbox.width = 0;
02401     for (lt = ctx->text.lt.info; 
02402          IsValidLine(ctx, line) && (line < ctx->text.lt.lines);
02403          line++, lt++) {
02404       if ((int)(lt->textWidth + ctx->text.margin.left) > (int)rbox.width)
02405           rbox.width = lt->textWidth + ctx->text.margin.left;
02406     }
02407     
02408     rbox.width += ctx->text.margin.right;
02409     if (rbox.width > ctx->core.width) { /* Only get wider. */
02410       rbox.request_mode = CWWidth;
02411       if (XtMakeGeometryRequest(w, &rbox, &return_geom) == XtGeometryAlmost)
02412         (void) XtMakeGeometryRequest(w, &return_geom, (XtWidgetGeometry*) NULL);
02413     }
02414   }
02415 
02416   if ( !((ctx->text.resize == XawtextResizeHeight) ||
02417          (ctx->text.resize == XawtextResizeBoth)) )
02418       return;
02419 
02420   if (IsPositionVisible(ctx, ctx->text.lastPos))
02421     line = LineForPosition(ctx, ctx->text.lastPos);
02422   else
02423     line = ctx->text.lt.lines;
02424   
02425   if ( (line + 1) == ctx->text.lt.lines ) return;
02426   
02427   old_height = ctx->core.height;
02428   rbox.request_mode = CWHeight;
02429   rbox.height = XawTextSinkMaxHeight(ctx->text.sink, line + 1) + VMargins(ctx);
02430   
02431   if ((int)rbox.height < old_height) return; /* It will only get taller. */
02432 
02433   if (XtMakeGeometryRequest(w, &rbox, &return_geom) == XtGeometryAlmost)
02434     if (XtMakeGeometryRequest(w, &return_geom, (XtWidgetGeometry*)NULL) != XtGeometryYes)
02435       return;
02436   
02437   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
02438 }
02439 
02440 /*
02441  * Converts (params, num_params) to a list of atoms & caches the
02442  * list in the TextWidget instance.
02443  */
02444 
02445 Atom*
02446 _XawTextSelectionList(ctx, list, nelems)
02447 TextWidget ctx;
02448 String *list;
02449 Cardinal nelems;
02450 {
02451   Atom * sel = ctx->text.s.selections;
02452   Display *dpy = XtDisplay((Widget) ctx);
02453   int n;
02454 
02455   if (nelems > ctx->text.s.array_size) {
02456     sel = (Atom *) XtRealloc((char *) sel, sizeof(Atom) * nelems);
02457     ctx->text.s.array_size = nelems;
02458     ctx->text.s.selections = sel;
02459   }
02460   for (n=nelems; --n >= 0; sel++, list++)
02461     *sel = XInternAtom(dpy, *list, False);
02462 
02463   ctx->text.s.atom_count = nelems;
02464   return ctx->text.s.selections;
02465 }
02466 
02467 /*      Function Name: SetSelection
02468  *      Description: Sets the current selection.
02469  *      Arguments: ctx - the text widget.
02470  *                 defaultSel - the default selection.
02471  *                 l, r - the left and right ends of the selection.
02472  *                 list, nelems - the selection list (as strings).
02473  *      Returns: none.
02474  *
02475  *  NOTE: if (ctx->text.s.left >= ctx->text.s.right) then the selection
02476  *        is unset.
02477  */
02478 
02479 void
02480 _XawTextSetSelection(ctx, l, r, list, nelems)
02481 TextWidget ctx;
02482 XawTextPosition l, r;
02483 String *list;
02484 Cardinal nelems;
02485 {
02486   if (nelems == 1 && !strcmp (list[0], "none"))
02487     return;
02488   if (nelems == 0) {
02489     String defaultSel = "PRIMARY";
02490     list = &defaultSel;
02491     nelems = 1;
02492   }
02493   _SetSelection(ctx, l, r, _XawTextSelectionList(ctx, list, nelems), nelems);
02494 }
02495 
02496 
02497 /*      Function Name: ModifySelection
02498  *      Description: Modifies the current selection.
02499  *      Arguments: ctx - the text widget.
02500  *                 left, right - the left and right ends of the selection.
02501  *      Returns: none.
02502  *
02503  *  NOTE: if (ctx->text.s.left >= ctx->text.s.right) then the selection
02504  *        is unset.
02505  */
02506 
02507 static void
02508 ModifySelection(ctx, left, right)
02509 TextWidget ctx;
02510 XawTextPosition left, right;
02511 {
02512   if (left == right) 
02513     ctx->text.insertPos = left;
02514   _SetSelection( ctx, left, right, (Atom*) NULL, ZERO );
02515 }
02516 
02517 /*
02518  * This routine is used to perform various selection functions. The goal is
02519  * to be able to specify all the more popular forms of draw-through and
02520  * multi-click selection user interfaces from the outside.
02521  */
02522 
02523 void 
02524 _XawTextAlterSelection (ctx, mode, action, params, num_params)
02525 TextWidget ctx;
02526 XawTextSelectionMode mode;   /* {XawsmTextSelect, XawsmTextExtend} */
02527 XawTextSelectionAction action; /* {XawactionStart, 
02528                                   XawactionAdjust, XawactionEnd} */
02529 String  *params;
02530 Cardinal        *num_params;
02531 {
02532   XawTextPosition position;
02533   Boolean flag;
02534 
02535 /*
02536  * This flag is used by TextPop.c:DoReplace() to determine if the selection
02537  * is okay to use, or if it has been modified.
02538  */
02539     
02540   if (ctx->text.search != NULL)
02541     ctx->text.search->selection_changed = TRUE;
02542 
02543   position = PositionForXY (ctx, (int) ctx->text.ev_x, (int) ctx->text.ev_y);
02544 
02545   flag = (action != XawactionStart);
02546   if (mode == XawsmTextSelect)
02547     DoSelection (ctx, position, ctx->text.time, flag);
02548   else                  /* mode == XawsmTextExtend */
02549    ExtendSelection (ctx, position, flag);
02550 
02551   if (action == XawactionEnd) 
02552     _XawTextSetSelection(ctx, ctx->text.s.left, ctx->text.s.right,
02553                          params, *num_params);
02554 }
02555 
02556 /*      Function Name: RectanglesOverlap
02557  *      Description: Returns TRUE if two rectangles overlap.
02558  *      Arguments: rect1, rect2 - the two rectangles to check.
02559  *      Returns: TRUE iff these rectangles overlap.
02560  */
02561 
02562 static Boolean
02563 RectanglesOverlap(rect1, rect2)
02564 XRectangle *rect1, *rect2;
02565 {
02566   return ( (rect1->x < rect2->x + (short) rect2->width) &&
02567            (rect2->x < rect1->x + (short) rect1->width) &&
02568            (rect1->y < rect2->y + (short) rect2->height) &&
02569            (rect2->y < rect1->y + (short) rect1->height) );
02570 }
02571 
02572 /*      Function Name: UpdateTextInRectangle.
02573  *      Description: Updates the text in a rectangle.
02574  *      Arguments: ctx - the text widget.
02575  *                 rect - the rectangle to update.
02576  *      Returns: none.
02577  */
02578 
02579 static void
02580 UpdateTextInRectangle(ctx, rect)
02581 TextWidget ctx;
02582 XRectangle * rect;
02583 {
02584   XawTextLineTableEntry *info = ctx->text.lt.info;
02585   int line, x = rect->x, y = rect->y;
02586   int right = rect->width + x, bottom = rect->height + y;
02587 
02588   for (line = 0;( (line < ctx->text.lt.lines) &&
02589                  IsValidLine(ctx, line) && (info->y < bottom)); line++, info++)
02590     if ( (info + 1)->y >= y ) 
02591       UpdateTextInLine(ctx, line, x, right);
02592 }
02593 
02594 /*
02595  * This routine processes all "expose region" XEvents. In general, its job
02596  * is to the best job at minimal re-paint of the text, displayed in the
02597  * window, that it can.
02598  */
02599 
02600 /* ARGSUSED */
02601 static void
02602 ProcessExposeRegion(w, event, region)
02603 Widget w;
02604 XEvent *event;
02605 Region region;                  /* Unused. */
02606 {
02607     TextWidget ctx = (TextWidget) w;
02608     XRectangle expose, cursor;
02609     Boolean need_to_draw;
02610     
02611     if (event->type == Expose) {
02612         expose.x = event->xexpose.x;
02613         expose.y = event->xexpose.y;
02614         expose.width = event->xexpose.width;
02615         expose.height = event->xexpose.height;
02616     }
02617     else if (event->type == GraphicsExpose) {
02618         expose.x = event->xgraphicsexpose.x;
02619         expose.y = event->xgraphicsexpose.y;
02620         expose.width = event->xgraphicsexpose.width;
02621         expose.height = event->xgraphicsexpose.height;
02622     }      
02623     else { /* No Expose */
02624         PopCopyQueue(ctx);              
02625         return;                 /* no more processing necessary. */
02626     }
02627 
02628     need_to_draw = TranslateExposeRegion(ctx, &expose);
02629     if ((event->type == GraphicsExpose) && (event->xgraphicsexpose.count == 0))
02630         PopCopyQueue(ctx);      
02631 
02632     if (!need_to_draw) 
02633         return;                 /* don't draw if we don't need to. */
02634 
02635     _XawTextPrepareToUpdate(ctx);
02636     UpdateTextInRectangle(ctx, &expose);
02637     XawTextSinkGetCursorBounds(ctx->text.sink, &cursor);
02638     if (RectanglesOverlap(&cursor, &expose)) {
02639         SinkClearToBG(ctx->text.sink, (Position) cursor.x, (Position) cursor.y,
02640                       (Dimension) cursor.width, (Dimension) cursor.height);
02641         UpdateTextInRectangle(ctx, &cursor);
02642     }
02643     _XawTextExecuteUpdate(ctx);
02644 }
02645 
02646 /*
02647  * This routine does all setup required to syncronize batched screen updates
02648  */
02649 
02650 void
02651 _XawTextPrepareToUpdate(ctx)
02652 TextWidget ctx;
02653 {
02654   if (ctx->text.old_insert < 0) {
02655     InsertCursor((Widget)ctx, XawisOff);
02656     ctx->text.numranges = 0;
02657     ctx->text.showposition = FALSE;
02658     ctx->text.old_insert = ctx->text.insertPos;
02659   }
02660 }
02661 
02662 /*
02663  * This is a private utility routine used by _XawTextExecuteUpdate. It
02664  * processes all the outstanding update requests and merges update
02665  * ranges where possible.
02666  */
02667 
02668 static 
02669 void FlushUpdate(ctx)
02670 TextWidget ctx;
02671 {
02672   int i, w;
02673   XawTextPosition updateFrom, updateTo;
02674   if (!XtIsRealized((Widget)ctx)) {
02675     ctx->text.numranges = 0;
02676     return;
02677   }
02678   while (ctx->text.numranges > 0) {
02679     updateFrom = ctx->text.updateFrom[0];
02680     w = 0;
02681     for (i = 1 ; i < ctx->text.numranges ; i++) {
02682       if (ctx->text.updateFrom[i] < updateFrom) {
02683         updateFrom = ctx->text.updateFrom[i];
02684         w = i;
02685       }
02686     }
02687     updateTo = ctx->text.updateTo[w];
02688     ctx->text.numranges--;
02689     ctx->text.updateFrom[w] = ctx->text.updateFrom[ctx->text.numranges];
02690     ctx->text.updateTo[w] = ctx->text.updateTo[ctx->text.numranges];
02691     for (i = ctx->text.numranges - 1 ; i >= 0 ; i--) {
02692       while (ctx->text.updateFrom[i] <= updateTo && i < ctx->text.numranges) {
02693         updateTo = ctx->text.updateTo[i];
02694         ctx->text.numranges--;
02695         ctx->text.updateFrom[i] = ctx->text.updateFrom[ctx->text.numranges];
02696         ctx->text.updateTo[i] = ctx->text.updateTo[ctx->text.numranges];
02697       }
02698     }
02699     DisplayText((Widget)ctx, updateFrom, updateTo);
02700   }
02701 }
02702 
02703 /*
02704  * This is a private utility routine used by _XawTextExecuteUpdate. This
02705  * routine worries about edits causing new data or the insertion point becoming
02706  * invisible (off the screen, or under the horiz. scrollbar). Currently 
02707  * it always makes it visible by scrolling. It probably needs 
02708  * generalization to allow more options.
02709  */
02710 
02711 void
02712 _XawTextShowPosition(ctx)
02713 TextWidget ctx;
02714 {
02715   int x, y, lines, number;
02716   Boolean no_scroll;
02717   XawTextPosition max_pos, top, first;
02718 
02719   if ( (!XtIsRealized((Widget)ctx)) || (ctx->text.lt.lines <= 0) )
02720     return;
02721 
02722 /*
02723  * Find out the bottom the visable window, and make sure that the
02724  * cursor does not go past the end of this space.  
02725  *
02726  * This makes sure that the cursor does not go past the end of the 
02727  * visable window. 
02728  */
02729 
02730   x = ctx->core.width;
02731   y = ctx->core.height - ctx->text.margin.bottom;
02732   if (ctx->text.hbar != NULL)
02733     y -= ctx->text.hbar->core.height + 2 * ctx->text.hbar->core.border_width;
02734   
02735   max_pos = PositionForXY (ctx, x, y);
02736   lines = LineForPosition(ctx, max_pos) + 1; /* number of visable lines. */
02737   
02738   if ( (ctx->text.insertPos >= ctx->text.lt.top) &&
02739        (ctx->text.insertPos < max_pos))
02740     return;
02741 
02742   first = ctx->text.lt.top;
02743   no_scroll = FALSE;
02744 
02745   if (ctx->text.insertPos < first) { /* We need to scroll down. */
02746       top = SrcScan(ctx->text.source, ctx->text.insertPos,
02747                     XawstEOL, XawsdLeft, 1, FALSE);
02748 
02749       /* count the number of lines we have to scroll */
02750 
02751       number = 0;
02752       while (first > top) {
02753           first = SrcScan(ctx->text.source, first,
02754                           XawstEOL, XawsdLeft, 1, TRUE);
02755 
02756           if ( - number > lines ) 
02757               break;
02758 
02759           number--;
02760       }
02761 
02762       if (first <= top) {       /* If we found the proper number
02763                                    of lines. */
02764      
02765           /* Back up to just before the last CR. */
02766       
02767           first = SrcScan(ctx->text.source, first,
02768                           XawstPositions, XawsdRight, 1, TRUE);
02769           
02770           /* Check to make sure the cursor is visable. */
02771           
02772           if (first <= top)
02773               number++;
02774           
02775           lines = number;
02776       }
02777       else
02778           no_scroll = TRUE;
02779   }
02780   else {                        /* We need to Scroll up */
02781       top = SrcScan(ctx->text.source, ctx->text.insertPos,
02782                     XawstEOL, XawsdLeft, lines, FALSE);
02783 
02784       if (top < max_pos) 
02785           lines = LineForPosition(ctx, top);
02786       else 
02787           no_scroll = TRUE;
02788   }
02789 
02790   if (no_scroll) {
02791       _XawTextBuildLineTable(ctx, top, FALSE);      
02792       DisplayTextWindow((Widget)ctx);
02793   }
02794   else 
02795       _XawTextVScroll(ctx, lines);
02796 
02797   _XawTextSetScrollBars(ctx);
02798 }
02799 
02800 /*
02801  * This routine causes all batched screen updates to be performed
02802  */
02803 
02804 void
02805 _XawTextExecuteUpdate(ctx)
02806 TextWidget ctx;
02807 {
02808   if ( ctx->text.update_disabled || (ctx->text.old_insert < 0) ) 
02809     return;
02810 
02811   if((ctx->text.old_insert != ctx->text.insertPos) || (ctx->text.showposition))
02812     _XawTextShowPosition(ctx);
02813   FlushUpdate(ctx);
02814   InsertCursor((Widget)ctx, XawisOn);
02815   ctx->text.old_insert = -1;
02816 }
02817 
02818 
02819 static void 
02820 TextDestroy(w)
02821 Widget w;
02822 {
02823   TextWidget ctx = (TextWidget)w;
02824 
02825   DestroyHScrollBar(ctx);
02826   DestroyVScrollBar(ctx);
02827 
02828   XtFree((char *)ctx->text.s.selections);
02829   XtFree((char *)ctx->text.lt.info);
02830   XtFree((char *)ctx->text.search);
02831   XtFree((char *)ctx->text.updateFrom);
02832   XtFree((char *)ctx->text.updateTo);
02833 }
02834 
02835 /*
02836  * by the time we are managed (and get this far) we had better
02837  * have both a source and a sink 
02838  */
02839 
02840 static void
02841 Resize(w)
02842 Widget w;
02843 {
02844   TextWidget ctx = (TextWidget) w;
02845 
02846   PositionVScrollBar(ctx);
02847   PositionHScrollBar(ctx);
02848 
02849   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
02850   _XawTextSetScrollBars(ctx);
02851 }
02852 
02853 /*
02854  * This routine allow the application program to Set attributes.
02855  */
02856 
02857 /*ARGSUSED*/
02858 static Boolean 
02859 SetValues(current, request, new, args, num_args)
02860 Widget current, request, new;
02861 ArgList args;
02862 Cardinal *num_args;
02863 {
02864   TextWidget oldtw = (TextWidget) current;
02865   TextWidget newtw = (TextWidget) new;
02866   Boolean    redisplay = FALSE;
02867   Boolean    display_caret = newtw->text.display_caret;
02868 
02869 
02870   newtw->text.display_caret = oldtw->text.display_caret;
02871   _XawTextPrepareToUpdate(newtw);
02872   newtw->text.display_caret = display_caret;
02873 
02874   if (oldtw->text.r_margin.left != newtw->text.r_margin.left) {
02875     newtw->text.margin.left = newtw->text.r_margin.left;
02876     if (newtw->text.vbar != NULL)
02877       newtw->text.margin.left += newtw->text.vbar->core.width +
02878                                  newtw->text.vbar->core.border_width;
02879     redisplay = TRUE;
02880   }
02881   
02882   if (oldtw->text.scroll_vert != newtw->text.scroll_vert) {
02883     if (newtw->text.scroll_vert == XawtextScrollNever) 
02884       DestroyVScrollBar(newtw);
02885     else if (newtw->text.scroll_vert == XawtextScrollAlways)
02886       CreateVScrollBar(newtw);
02887     redisplay = TRUE;
02888   }
02889 
02890   if (oldtw->text.r_margin.bottom != newtw->text.r_margin.bottom) {
02891     newtw->text.margin.bottom = newtw->text.r_margin.bottom;
02892     if (newtw->text.hbar != NULL)
02893       newtw->text.margin.bottom += newtw->text.hbar->core.height +
02894                                    newtw->text.hbar->core.border_width;
02895     redisplay = TRUE;
02896   }
02897   
02898   if (oldtw->text.scroll_horiz != newtw->text.scroll_horiz) {
02899     if (newtw->text.scroll_horiz == XawtextScrollNever) 
02900       DestroyHScrollBar(newtw);
02901     else if (newtw->text.scroll_horiz == XawtextScrollAlways)
02902       CreateHScrollBar(newtw);
02903     redisplay = TRUE;
02904   }
02905 
02906   if ( oldtw->text.source != newtw->text.source )
02907     XawTextSetSource( (Widget) newtw, newtw->text.source, newtw->text.lt.top);
02908 
02909   newtw->text.redisplay_needed = False;
02910   XtSetValues( (Widget)newtw->text.source, args, *num_args );
02911   XtSetValues( (Widget)newtw->text.sink, args, *num_args );
02912 
02913   if ( oldtw->text.wrap != newtw->text.wrap ||
02914        oldtw->text.lt.top != newtw->text.lt.top ||
02915        oldtw->text.r_margin.right != newtw->text.r_margin.right ||
02916        oldtw->text.r_margin.top != newtw->text.r_margin.top ||
02917        oldtw->text.sink != newtw->text.sink ||
02918        newtw->text.redisplay_needed )
02919   {
02920     _XawTextBuildLineTable(newtw, newtw->text.lt.top, TRUE);
02921     redisplay = TRUE;
02922   }
02923 
02924   if (oldtw->text.insertPos != newtw->text.insertPos) {
02925     newtw->text.showposition = TRUE;
02926     redisplay = TRUE;
02927   }
02928 
02929   _XawTextExecuteUpdate(newtw);
02930   if (redisplay)
02931     _XawTextSetScrollBars(newtw);
02932 
02933   return redisplay;
02934 }
02935 
02936 /* invoked by the Simple widget's SetValues */
02937 static Boolean ChangeSensitive(w)
02938     Widget w;   /* the new widget */
02939 {
02940     Arg args[1];
02941     TextWidget tw = (TextWidget) w;
02942 
02943     (*(&simpleClassRec)->simple_class.change_sensitive)(w);
02944 
02945     XtSetArg(args[0], XtNancestorSensitive, 
02946                (tw->core.ancestor_sensitive && tw->core.sensitive));
02947     if (tw->text.vbar)
02948         XtSetValues(tw->text.vbar, args, ONE);
02949     if (tw->text.hbar)
02950         XtSetValues(tw->text.hbar, args, ONE);
02951     return False;
02952 }
02953 
02954 /*      Function Name: GetValuesHook
02955  *      Description: This is a get values hook routine that gets the
02956  *                   values in the text source and sink.
02957  *      Arguments: w - the Text Widget.
02958  *                 args - the argument list.
02959  *                 num_args - the number of args.
02960  *      Returns: none.
02961  */
02962 
02963 static void
02964 GetValuesHook(w, args, num_args)
02965 Widget w;
02966 ArgList args;
02967 Cardinal * num_args;
02968 {
02969   XtGetValues( ((TextWidget) w)->text.source, args, *num_args );
02970   XtGetValues( ((TextWidget) w)->text.sink, args, *num_args );
02971 }
02972 
02973 /*      Function Name: FindGoodPosition
02974  *      Description: Returns a valid position given any postition
02975  *      Arguments: pos - any position.
02976  *      Returns: a position between (0 and lastPos);
02977  */
02978 
02979 static XawTextPosition
02980 FindGoodPosition(ctx, pos)
02981 TextWidget ctx;
02982 XawTextPosition pos;
02983 {
02984   if (pos < 0) return(0);
02985   return ( ((pos > ctx->text.lastPos) ? ctx->text.lastPos : pos) );
02986 }
02987 
02988 /************************************************************
02989  * 
02990  * Routines for handling the copy area expose queue.
02991  *
02992  ************************************************************/
02993 
02994 /*      Function Name: PushCopyQueue
02995  *      Description: Pushes a value onto the copy queue.
02996  *      Arguments: ctx - the text widget.
02997  *                 h, v - amount of offset in the horiz and vert directions.
02998  *      Returns: none
02999  */
03000 
03001 static void
03002 PushCopyQueue(ctx, h, v)
03003 TextWidget ctx;
03004 int h, v;
03005 {
03006     struct text_move * offsets = XtNew(struct text_move);
03007 
03008     offsets->h = h;
03009     offsets->v = v;
03010     offsets->next = NULL;
03011 
03012     if (ctx->text.copy_area_offsets == NULL)
03013         ctx->text.copy_area_offsets = offsets;
03014     else {
03015         struct text_move * end = ctx->text.copy_area_offsets;
03016         for ( ; end->next != NULL; end = end->next) {}
03017         end->next = offsets;
03018     }
03019 }
03020 
03021 /*      Function Name: PopCopyQueue
03022  *      Description: Pops the top value off of the copy queue.
03023  *      Arguments: ctx - the text widget.
03024  *      Returns: none.
03025  */
03026 
03027 static void
03028 PopCopyQueue(ctx)
03029 TextWidget ctx;
03030 {
03031     struct text_move * offsets = ctx->text.copy_area_offsets;
03032 
03033     if (offsets == NULL)
03034         (void) printf( "Xaw Text widget %s: empty copy queue\n",
03035                        XtName( (Widget) ctx ) );
03036     else {
03037         ctx->text.copy_area_offsets = offsets->next;
03038         XtFree((char *) offsets);       /* free what you allocate. */
03039     }
03040 }
03041 
03042 /*      Function Name:  TranslateExposeRegion
03043  *      Description: Translates the expose that came into
03044  *                   the cordinates that now exist in the Text widget.
03045  *      Arguments: ctx - the text widget.
03046  *                 expose - a Rectangle, who's region currently
03047  *                          contains the expose event location.
03048  *                          this region will be returned containing
03049  *                          the new rectangle.
03050  *      Returns: True if there is drawing that needs to be done.
03051  */
03052 
03053 static Boolean
03054 TranslateExposeRegion(ctx, expose)
03055 TextWidget ctx;
03056 XRectangle * expose;
03057 {
03058     struct text_move * offsets = ctx->text.copy_area_offsets;
03059     int value;
03060     int x, y, width, height;
03061 
03062     /*
03063      * Skip over the first one, this has already been taken into account.
03064      */
03065 
03066     if (!offsets || !(offsets = offsets->next))
03067         return(TRUE);
03068 
03069     x = expose->x;
03070     y = expose->y;
03071     width = expose->width;
03072     height = expose->height;
03073 
03074     while (offsets) {
03075         x += offsets->h;
03076         y += offsets->v;
03077         offsets = offsets->next;
03078     }
03079 
03080     /*
03081      * remove that area of the region that is now outside the window.
03082      */
03083 
03084     if (y < 0) {
03085         height += y;
03086         y = 0;
03087     }
03088 
03089     value = y + height - ctx->core.height;
03090     if (value > 0)
03091         height -= value;
03092 
03093     if (height <= 0)
03094         return(FALSE);          /* no need to draw outside the window. */
03095 
03096     /*
03097      * and now in the horiz direction...
03098      */
03099 
03100     if (x < 0) {
03101         width += x;
03102         x = 0;
03103     }
03104 
03105     value = x + width - ctx->core.width;
03106     if (value > 0)
03107         width -= value;
03108 
03109     if (width <= 0)
03110         return(FALSE);          /* no need to draw outside the window. */
03111     
03112     expose->x = x;
03113     expose->y = y;
03114     expose->width = width;
03115     expose->height = height;
03116     return(TRUE);
03117 }
03118 
03119 /* Li wrote this so the IM can find a given text position's screen position. */
03120 
03121 void
03122 #if NeedFunctionPrototypes
03123 _XawTextPosToXY( 
03124     Widget w, 
03125     XawTextPosition pos, 
03126     Position* x, 
03127     Position* y )
03128 #else
03129 _XawTextPosToXY( w, pos, x, y )
03130     Widget w;
03131     XawTextPosition pos;
03132     Position *x, *y;
03133 #endif
03134 {
03135     int line;
03136     LineAndXYForPosition( (TextWidget)w, pos, &line, x, y );
03137 }
03138 
03139 /*******************************************************************
03140 The following routines provide procedural interfaces to Text window state
03141 setting and getting. They need to be redone so than the args code can use
03142 them. I suggest we create a complete set that takes the context as an
03143 argument and then have the public version lookup the context and call the
03144 internal one. The major value of this set is that they have actual application
03145 clients and therefore the functionality provided is required for any future
03146 version of Text.
03147 ********************************************************************/
03148 
03149 void
03150 #if NeedFunctionPrototypes
03151 XawTextDisplay (Widget w)
03152 #else
03153 XawTextDisplay (w)
03154 Widget w;
03155 #endif
03156 {
03157   if (!XtIsRealized(w)) return;
03158   
03159   _XawTextPrepareToUpdate( (TextWidget) w);
03160   DisplayTextWindow(w);
03161   _XawTextExecuteUpdate( (TextWidget) w);
03162 }
03163 
03164 void
03165 #if NeedFunctionPrototypes
03166 XawTextSetSelectionArray(Widget w, XawTextSelectType *sarray)
03167 #else
03168 XawTextSetSelectionArray(w, sarray)
03169 Widget w;
03170 XawTextSelectType *sarray;
03171 #endif
03172 {
03173   ((TextWidget)w)->text.sarray = sarray;
03174 }
03175 
03176 void
03177 #if NeedFunctionPrototypes
03178 XawTextGetSelectionPos(Widget w, XawTextPosition *left, XawTextPosition *right)
03179 #else
03180 XawTextGetSelectionPos(w, left, right)
03181 Widget w;
03182 XawTextPosition* left,* right;
03183 #endif
03184 {
03185   *left = ((TextWidget) w)->text.s.left;
03186   *right = ((TextWidget) w)->text.s.right;
03187 }
03188 
03189 
03190 void 
03191 #if NeedFunctionPrototypes
03192 XawTextSetSource(Widget w, Widget source, XawTextPosition startPos)
03193 #else
03194 XawTextSetSource(w, source, startPos)
03195 Widget w, source;
03196 XawTextPosition startPos;
03197 #endif
03198 {
03199   TextWidget ctx = (TextWidget) w;
03200 
03201   ctx->text.source = source;
03202   ctx->text.lt.top = startPos;
03203   ctx->text.s.left = ctx->text.s.right = 0;
03204   ctx->text.insertPos = startPos;
03205   ctx->text.lastPos = GETLASTPOS;
03206   
03207   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
03208   XawTextDisplay(w);
03209 }
03210 
03211 /*
03212  * This public routine deletes the text from startPos to endPos in a source and
03213  * then inserts, at startPos, the text that was passed. As a side effect it
03214  * "invalidates" that portion of the displayed text (if any), so that things
03215  * will be repainted properly.
03216  */
03217 
03218 int 
03219 #if NeedFunctionPrototypes
03220 XawTextReplace(Widget w, XawTextPosition startPos, XawTextPosition endPos,
03221                XawTextBlock *text)
03222 #else
03223 XawTextReplace(w, startPos, endPos, text)
03224 Widget w;
03225 XawTextPosition  startPos, endPos;
03226 XawTextBlock *text;
03227 #endif
03228 {
03229   TextWidget ctx = (TextWidget) w;
03230   int result;
03231 
03232   _XawTextPrepareToUpdate(ctx);
03233   endPos = FindGoodPosition(ctx, endPos);
03234   startPos = FindGoodPosition(ctx, startPos);
03235   if ((result = _XawTextReplace(ctx, startPos, endPos, text)) == XawEditDone) {
03236     int delta = text->length - (endPos - startPos);
03237     if (ctx->text.insertPos >= (endPos + delta)) {
03238       XawTextScanDirection sd = (delta < 0) ? XawsdLeft : XawsdRight;
03239       ctx->text.insertPos = SrcScan(ctx->text.source, ctx->text.insertPos,
03240                                     XawstPositions, sd, abs(delta), TRUE);
03241     }
03242   }
03243 
03244   _XawTextCheckResize(ctx);
03245   _XawTextExecuteUpdate(ctx);
03246   _XawTextSetScrollBars(ctx);
03247   
03248   return result;
03249 }
03250 
03251 XawTextPosition 
03252 #if NeedFunctionPrototypes
03253 XawTextTopPosition(Widget w)
03254 #else
03255 XawTextTopPosition(w)
03256 Widget w;
03257 #endif
03258 {
03259   return( ((TextWidget) w)->text.lt.top );
03260 }
03261 
03262 void 
03263 #if NeedFunctionPrototypes
03264 XawTextSetInsertionPoint(Widget w, XawTextPosition position)
03265 #else
03266 XawTextSetInsertionPoint(w, position)
03267 Widget w;
03268 XawTextPosition position;
03269 #endif
03270 {
03271   TextWidget ctx = (TextWidget) w;
03272 
03273   _XawTextPrepareToUpdate(ctx);
03274   ctx->text.insertPos = FindGoodPosition(ctx, position);
03275   ctx->text.showposition = TRUE;
03276 
03277   _XawTextExecuteUpdate(ctx);
03278 }
03279 
03280 XawTextPosition
03281 #if NeedFunctionPrototypes
03282 XawTextGetInsertionPoint(Widget w)
03283 #else
03284 XawTextGetInsertionPoint(w)
03285 Widget w;
03286 #endif
03287 {
03288   return( ((TextWidget) w)->text.insertPos);
03289 }
03290 
03291 /*
03292  * NOTE: Must walk the selection list in opposite order from LoseSelection.
03293  */
03294 
03295 void 
03296 #if NeedFunctionPrototypes
03297 XawTextUnsetSelection(Widget w)
03298 #else
03299 XawTextUnsetSelection(w)
03300 Widget w;
03301 #endif
03302 {
03303   TextWidget ctx = (TextWidget)w;
03304 
03305   while (ctx->text.s.atom_count != 0) {
03306     Atom sel = ctx->text.s.selections[ctx->text.s.atom_count - 1];
03307     if ( sel != (Atom) 0 ) {
03308 /*
03309  * As selections are lost the atom_count will decrement.
03310  */
03311       if (GetCutBufferNumber(sel) == NOT_A_CUT_BUFFER)
03312         XtDisownSelection(w, sel, ctx->text.time);
03313       LoseSelection(w, &sel); /* In case this is a cut buffer, or 
03314                                  XtDisownSelection failed to call us. */
03315     }
03316   }
03317 }
03318 
03319 void
03320 #if NeedFunctionPrototypes
03321 XawTextSetSelection (Widget w, XawTextPosition left, XawTextPosition right)
03322 #else
03323 XawTextSetSelection (w, left, right)
03324 Widget w;
03325 XawTextPosition left, right;
03326 #endif
03327 {
03328   TextWidget ctx = (TextWidget) w;
03329   
03330   _XawTextPrepareToUpdate(ctx);
03331   _XawTextSetSelection(ctx, FindGoodPosition(ctx, left),
03332                        FindGoodPosition(ctx, right), (String*)NULL, ZERO);
03333   _XawTextExecuteUpdate(ctx);
03334 }
03335 
03336 void 
03337 #if NeedFunctionPrototypes
03338 XawTextInvalidate(Widget w, XawTextPosition from, XawTextPosition to)
03339 #else
03340 XawTextInvalidate(w, from, to)
03341 Widget w;
03342 XawTextPosition from,to;
03343 #endif
03344 {
03345   TextWidget ctx = (TextWidget) w;
03346 
03347   from = FindGoodPosition(ctx, from);
03348   to = FindGoodPosition(ctx, to);
03349   ctx->text.lastPos = GETLASTPOS;
03350   _XawTextPrepareToUpdate(ctx);
03351   _XawTextNeedsUpdating(ctx, from, to);
03352   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
03353   _XawTextExecuteUpdate(ctx);
03354 }
03355 
03356 /*ARGSUSED*/
03357 void
03358 #if NeedFunctionPrototypes
03359 XawTextDisableRedisplay(Widget w)
03360 #else
03361 XawTextDisableRedisplay(w)
03362 Widget w;
03363 #endif
03364 {
03365   ((TextWidget) w)->text.update_disabled = True;
03366   _XawTextPrepareToUpdate( (TextWidget) w);
03367 }
03368 
03369 void 
03370 #if NeedFunctionPrototypes
03371 XawTextEnableRedisplay(Widget w)
03372 #else
03373 XawTextEnableRedisplay(w)
03374 Widget w;
03375 #endif
03376 {
03377   TextWidget ctx = (TextWidget)w;
03378   XawTextPosition lastPos;
03379 
03380   if (!ctx->text.update_disabled) return;
03381 
03382   ctx->text.update_disabled = False;
03383   lastPos = ctx->text.lastPos = GETLASTPOS;
03384   ctx->text.lt.top = FindGoodPosition(ctx, ctx->text.lt.top);
03385   ctx->text.insertPos = FindGoodPosition(ctx, ctx->text.insertPos);
03386   if ( (ctx->text.s.left > lastPos) || (ctx->text.s.right > lastPos) ) 
03387     ctx->text.s.left = ctx->text.s.right = 0;
03388   
03389   _XawTextBuildLineTable(ctx, ctx->text.lt.top, TRUE);
03390   if (XtIsRealized(w))
03391     DisplayTextWindow(w);
03392   _XawTextExecuteUpdate(ctx);
03393 }
03394 
03395 Widget
03396 #if NeedFunctionPrototypes
03397 XawTextGetSource(Widget w)
03398 #else
03399 XawTextGetSource(w)
03400 Widget w;
03401 #endif
03402 {
03403   return ((TextWidget)w)->text.source;
03404 }
03405 
03406 void
03407 #if NeedFunctionPrototypes
03408 XawTextDisplayCaret (Widget w,
03409 #if NeedWidePrototypes
03410                     /* Boolean */ int display_caret)
03411 #else
03412                     Boolean display_caret)
03413 #endif
03414 #else
03415 XawTextDisplayCaret (w, display_caret)
03416 Widget w;
03417 Boolean display_caret;
03418 #endif
03419 {
03420   TextWidget ctx = (TextWidget) w;
03421 
03422   if (ctx->text.display_caret == display_caret) return;
03423 
03424   if (XtIsRealized(w)) {
03425     _XawTextPrepareToUpdate(ctx);
03426     ctx->text.display_caret = display_caret;
03427     _XawTextExecuteUpdate(ctx);
03428   }
03429   else
03430     ctx->text.display_caret = display_caret;
03431 }
03432 
03433 /*      Function Name: XawTextSearch(w, dir, text).
03434  *      Description: searches for the given text block.
03435  *      Arguments: w - The text widget.
03436  *                 dir - The direction to search. 
03437  *                 text - The text block containing info about the string
03438  *                        to search for.
03439  *      Returns: The position of the text found, or XawTextSearchError on 
03440  *               an error.
03441  */
03442 
03443 XawTextPosition
03444 #if NeedFunctionPrototypes
03445 XawTextSearch(Widget w,
03446 #if NeedWidePrototypes
03447             /* XawTextScanDirection */ int dir,
03448 #else
03449             XawTextScanDirection dir,
03450 #endif
03451             XawTextBlock *text)
03452 #else
03453 XawTextSearch(w, dir, text) 
03454 Widget w;
03455 XawTextScanDirection dir;
03456 XawTextBlock * text;
03457 #endif
03458 {
03459   TextWidget ctx = (TextWidget) w;
03460 
03461   return(SrcSearch(ctx->text.source, ctx->text.insertPos, dir, text));
03462 }
03463   
03464 TextClassRec textClassRec = {
03465   { /* core fields */
03466     /* superclass       */      (WidgetClass) &simpleClassRec,
03467     /* class_name       */      "Text",
03468     /* widget_size      */      sizeof(TextRec),
03469     /* class_initialize */      ClassInitialize,
03470     /* class_part_init  */      NULL,
03471     /* class_inited     */      FALSE,
03472     /* initialize       */      Initialize,
03473     /* initialize_hook  */      NULL,
03474     /* realize          */      Realize,
03475     /* actions          */      _XawTextActionsTable,
03476     /* num_actions      */      0,                /* Set in ClassInitialize. */
03477     /* resources        */      resources,
03478     /* num_ resource    */      XtNumber(resources),
03479     /* xrm_class        */      NULLQUARK,
03480     /* compress_motion  */      TRUE,
03481     /* compress_exposure*/      XtExposeGraphicsExpose | XtExposeNoExpose,
03482     /* compress_enterleave*/    TRUE,
03483     /* visible_interest */      FALSE,
03484     /* destroy          */      TextDestroy,
03485     /* resize           */      Resize,
03486     /* expose           */      ProcessExposeRegion,
03487     /* set_values       */      SetValues,
03488     /* set_values_hook  */      NULL,
03489     /* set_values_almost*/      XtInheritSetValuesAlmost,
03490     /* get_values_hook  */      GetValuesHook,
03491     /* accept_focus     */      NULL,
03492     /* version          */      XtVersion,
03493     /* callback_private */      NULL,
03494     /* tm_table         */      NULL,    /* set in ClassInitialize */
03495     /* query_geometry   */      XtInheritQueryGeometry,
03496     /* display_accelerator*/    XtInheritDisplayAccelerator,
03497     /* extension        */      NULL
03498   },
03499   { /* Simple fields */
03500     /* change_sensitive */      ChangeSensitive
03501   },
03502   { /* text fields */
03503     /* empty            */      0
03504   }
03505 };
03506 
03507 WidgetClass textWidgetClass = (WidgetClass)&textClassRec;

Generated on Sun Mar 4 15:03:55 2007 for Scilab [trunk] by  doxygen 1.5.1