Logo Search packages:      
Sourcecode: lesstif1-1 version File versions  Download package

TextOut.c

/**
 *
 * $Header: /cvsroot/lesstif/lesstif/lib/Xm/TextOut.c,v 1.130 2003/10/23 08:33:00 amai Exp $
 *
 * Copyright (C) 1995 Free Software Foundation, Inc.
 * Copyright  1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 LessTif Development Team
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm/TextOut.c,v 1.130 2003/10/23 08:33:00 amai Exp $";

/* Do NOT use this (USE_XT_GC) :
 * it requires setting all the dynamic GC fields before every use of
 * the GC. As we have too many GC fields that can change, this is
 * really a bad idea.
 * Setting this macro leads to use of XtAllocateGC and XtGetGC,
 * and similar for the free operations.
 * This path has been explored more than once, by different
 * developers. Please keep the comments here so it gets
 * remembered.
 */
#undef      USE_XT_GC
/*
 * End of the USE_XT_GC blurb.
 */

#include <LTconfig.h>

#include <stdio.h>
#include <limits.h>           /* for INT_MAX */
#include <string.h>
#include <stdlib.h>

#include <Xm/XmP.h>
#include <Xm/TextP.h>
#include <Xm/TextOutP.h>
#include <Xm/ScrolledWP.h>
#include <Xm/ScrollBarP.h>
#include <Xm/AtomMgr.h>
#include <XmI/XmI.h>
#include <XmI/AtomMgrI.h>

#include <XmI/DebugUtil.h>


#undef VERBOSE

static void Draw(XmTextWidget w, LineNum num, XmTextPosition start, XmTextPosition end, XmHighlightMode highlight);

#define Offset(field) XtOffsetOf(XmTextInnerRec, inner.out.field)


#if XmVERSION > 1
#define     USE_AVERAGE_WIDTH 1
#else
/* same behavior as XmTextField.*/
#undef      USE_AVERAGE_WIDTH
#endif

#undef      Out_FontTextWidth
#define     Out_FontTextWidth(o,s,l)      (int)_XmOut_FontTextWidth(o, s, l)
#define     Out_FontMaxWidth(o)     (int)_XmOut_FontMaxWidth(o)

static void _XmTextOutSetRenderTable(Widget w, int o, XrmValue *v);
      
/* Resources for the TextInner class */
static XtResource output_resources[] =
{
    {
      XmNblinkRate, XmCBlinkRate, XmRInt,
      sizeof(int), Offset(blinkrate),
      XmRImmediate, (XtPointer)500
    },
    {
      XmNcolumns, XmCColumns, XmRShort,
      sizeof(short), Offset(columns),
      XmRImmediate, (XtPointer)20
    },
    {
      XmNcursorPositionVisible, XmCCursorPositionVisible, XmRBoolean,
      sizeof(Boolean), Offset(cursor_position_visible),
      XmRImmediate, (XtPointer)True
    },
#if (XmVERSION > 1) && defined(USE_XFT)
    /* Note that the right order is important here ! */
    {
      "keep.off", "Keep.off", XmRBoolean,
      sizeof(Boolean), Offset(check_set_render_table),
      XmRImmediate, (XtPointer)NULL
    },
    {
      XmNfontList, XmCFontList, XmRFontList,
      sizeof(XmFontList), Offset(fontlist),
      XmRCallProc, (XtPointer)_XmTextOutSetRenderTable
    },
    {
      XmNrenderTable, XmCRenderTable, XmRRenderTable,
      sizeof(XmFontList), Offset(fontlist),
      XmRCallProc, (XtPointer)_XmTextOutSetRenderTable
    },
#else
    {
      XmNfontList, XmCFontList, XmRFontList,
      sizeof(XmFontList), Offset(fontlist),
      XmRImmediate, (XtPointer)XmUNSPECIFIED
    },
#endif
    {
      XmNresizeHeight, XmCResizeHeight, XmRBoolean,
      sizeof(Boolean), Offset(resizeheight),
      XmRImmediate, (XtPointer)False
    },
    {
      XmNresizeWidth, XmCResizeWidth, XmRBoolean,
      sizeof(Boolean), Offset(resizewidth),
      XmRImmediate, (XtPointer)False
    },
    {
      XmNrows, XmCRows, XmRShort,
      sizeof(short), Offset(rows),
      XmRImmediate, (XtPointer)1
    },
    {
      XmNwordWrap, XmCWordWrap, XmRBoolean,
      sizeof(Boolean), Offset(wordwrap),
      XmRImmediate, (XtPointer)False
    },

    /* ScrolledText resources */
    {
      XmNscrollHorizontal, XmCScroll, XmRBoolean,
      sizeof(Boolean), Offset(scrollhorizontal),
      XmRImmediate, (XtPointer)True
    },
    {
      XmNscrollLeftSide, XmCScrollSide, XmRBoolean,
      sizeof(Boolean), Offset(scrollleftside),
      XmRImmediate, (XtPointer)False
    },
    {
      XmNscrollTopSide, XmCScrollSide, XmRBoolean,
      sizeof(Boolean), Offset(scrolltopside),
      XmRImmediate, (XtPointer)False
    },
    {
      XmNscrollVertical, XmCScroll, XmRBoolean,
      sizeof(Boolean), Offset(scrollvertical),
      XmRImmediate, (XtPointer)True
    },
};

/*
 * Common initialization procedures -------------------------------------------
 */
extern int
_XmFontCalculateAverageCharacterWidth(Widget w, XFontStruct *fs)
{
      /*CP: The following is more or less what the XFree86 people have suggested. */
      unsigned long width;
      Atom atom;

      if (fs == NULL) {
            /* Especially important in Xft case */
            return 0;
      }

      /* this is copied from a similar function in Screen.c */
      if ((atom = XmInternAtom(XtDisplay(w), _XA_AVERAGE_WIDTH, True))
                  && XGetFontProperty(fs, atom, &width) && width) {
            width = (width + 5) / 10; /*CP: just to round it up slightly */
      } else if ((! XGetFontProperty(fs, XA_QUAD_WIDTH, &width)) || width == 0) {
            /*CP: Yes, even if the property is available it could be 0 - as per XF86 people */
            /*So we will will use the character "x" */
            if ( fs->per_char &&  fs->min_char_or_byte2 <= 'x' &&
                        fs->max_char_or_byte2 >= 'x')
                        /* i.e. we have data for x */
                  width = fs->per_char['a' - fs->min_char_or_byte2].width;
            else
                  width = fs->max_bounds.width / 2 ;                                          
      }
      return width;
}


/* FIX ME - this thing is clearly overly simplistic. */
/* I think it should :
 *    - grab a fontset whenever it can (bypassing fonts)
 *      - make sure you pick any fontset (preferably) or font (if all else
 *        fails) from the list if nothing matches the tag we want
 */
/*
 * Note : never *ever* use XmFONTLIST_DEFAULT_TAG without checking
 * XmSTRING_DEFAULT_CHARSET as well. Pre-1.2 docs use the latter everywhere.
 */
static void
FontInit(XmTextWidget w)
{
      OutputData o = Text_OutputData(w);
      XmFontListEntry entry = NULL;
      XmFontList oldlist = Out_FontList(o);
      XFontStruct *fs;
      int i;

      DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "FontInit(fontlist %p)\n", oldlist));

      /* This part is probably all wrong ... FIX ME */
      for (i = 0; Out_FontList(o)->renditions[i]->tag != NULL; i++) {
            if (strcmp(XmFONTLIST_DEFAULT_TAG,
                        Out_FontList(o)->renditions[i]->tag) == 0 ||
                        strcmp(XmSTRING_DEFAULT_CHARSET,
                        Out_FontList(o)->renditions[i]->tag) == 0) {
                  entry = Out_FontList(o)->renditions[i];

                  if (entry->font == NULL) {
                        entry = NULL;
                        continue;
                  }

                  break;
            }
      }

      if (!entry) {
            for (i = 0; Out_FontList(o)->renditions[i]->tag != NULL; i++) {
                  if (Out_FontList(o)->renditions[i]->type == XmFONT_IS_FONTSET) {
                        entry = Out_FontList(o)->renditions[i];

                        if (entry->font == NULL) {
                              entry = NULL;
                              continue;
                        }

                        break;
                  }
            }
      }

      if (!entry) {
            for (i = 0; Out_FontList(o)->renditions[i]->tag != NULL; i++) {
                  if (Out_FontList(o)->renditions[i]->type == XmFONT_IS_FONT) {
                        entry = Out_FontList(o)->renditions[i];

                        if (entry->font == NULL) {
                              entry = NULL;
                              continue;
                        }

                        break;
                  }
            }
      }
      /* (Hopefully) end of the all wrong part */

#if   USE_XFT
      Out_FontType(o) = XmFONT_IS_FONT;
      o->xft_font = NULL;
      
      /*
       * We need a hack to get Xft fonts accepted.
       * The current (initial hack) is to use Xft for fonts if
       * the first item in the fontList is an Xft font.
       */
      if (Out_FontList(o) && Out_FontList(o)->renditions[0]
                  && Out_FontList(o)->renditions[0]->type == XmFONT_IS_XFT) {
            Out_FontType(o) = XmFONT_IS_XFT;
            entry = Out_FontList(o)->renditions[0];
            o->xft_font = entry->xft_font;
            Out_Font(o) = NULL;
      }
#endif

      /* This should only be the very very last resort. */
#ifdef      USE_XFT
      if (entry == NULL || (entry->font == NULL && entry->type != XmFONT_IS_XFT))
#else
      if (entry == NULL || entry->font == NULL)
#endif
      {
            Out_FontList(o) = _XmFontListCreateDefault(XtDisplay((Widget)w));
            entry = Out_FontList(o)->renditions[0];
      } else {    /* Make copy. Original will be free */
            /*  amai, 20010313:
             *  I do not understand why this is necessary, but
             *  it seems to be ...
             *  Why does copying the list affect behaviour?!
             *  Try to omit the copying step and run test/Xm/text/test17!
             *  The original will _not_ be freed, or at least it won't be
             *  always freed, see test/Xm/text/test11, the leak check!
             */
            Out_FontList(o) = XmFontListAppendEntry(NULL, entry);
            if (Out_FontListCreated(o))
                  XmFontListFree(oldlist);
            entry = Out_FontList(o)->renditions[0];
            Out_FontListCreated(o) = True;
      }

      /* We may get a font or a fontset here */
      if (entry->type == XmFONT_IS_FONT)
      {
            fs = (XFontStruct *)entry->font;

            Out_FontAverageWidth(o) =
                  (fs->max_bounds.width + fs->min_bounds.width) / 2;
            Out_UseFontSet(o) = False;
            Out_Font(o) = fs;
#ifdef      USE_XFT
      } else if (entry->type == XmFONT_IS_XFT) {
            Out_FontAverageWidth(o) = Out_XftFont(o)->max_advance_width;
            Out_FontAverageWidth(o) = entry->font_average_width;  /* FIX ME HACK */
            Out_UseFontSet(o) = False;
#endif
      } else {                /* XmFONT_IS_FONTSET */
            XFontStruct **fsl;
            char **nl;
            int r, i, max, min;

            r = XFontsOfFontSet((XFontSet)entry->font, &fsl, &nl);
            DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XFontsOfFontSet : %d\n", r));
            for (i = 0; i < r; i++) {
                  DEBUGOUT(_LtDebug0(__FILE__, NULL, "\t%s\n", nl[i]));
            }

            /* FIX ME - just pick the first one */
            if (r == 0) {
                  DEBUGOUT(_LtDebug(__FILE__, NULL, "No font in fontset\n"));
                  abort();
            }

            fs = fsl[0];
            /* correct calculation */
            max = 0; min = INT_MAX;
            for(i=0; i<r; i++) {
                  if (fsl[i]->max_bounds.width  > max)
                        max = fsl[i]->max_bounds.width;
                  if (fsl[i]->min_bounds.width  < min)
                        min = fsl[i]->min_bounds.width;
            }
            Out_FontAverageWidth(o) = (max + min) / 2;
            Out_Font(o) = fs;

      /*    Out_UseFontSet(o) = True;     */
      }

      if ( Out_FontAverageWidth(o) <= 0 ) {
            Out_FontAverageWidth(o) = _XmFontCalculateAverageCharacterWidth((Widget)w, fs);
      }
      Out_TabWidth(o) = 8 * Out_FontAverageWidth(o);
#if 0
      /*
       * These fields are never used.
       */
      Out_Font_Ascent(o) = Out_FontAscent(o);
      Out_Font_Descent(o) = Out_FontDescent(o);
#endif
      Out_FontHeight(o) = Out_FontAscent(o) + Out_FontDescent(o);
      Out_CursorHeight(o) = Out_FontHeight(o);

      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "FontInit - fl %p font %p : ascent=%d descent=%d height=%d avewidth=%d\n",
            Out_FontList(o), Out_Font(o),
            Out_FontAscent(o), Out_FontDescent(o),
            Out_FontHeight(o), Out_FontAverageWidth(o)));
}


/*
 * This thing still creates GC's the anti-social way - with XCreateGC.
 *
 * By using XtGetGC or XtAllocateGC, Xt will allow us to share GC's
 * with other widgets. We'd just have to be sure about what we want to be
 * the properties of the thing.
 *
 * Note: the explanation for this is in comments at the top of this file.
 */
static void
GCInitialize(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);
    XGCValues values;
    XtGCMask mask, dynamic, dontcare;

    /*
     * DrawGC
     *      Need to change :  ClipRectangles
     *                        GCFillStyle | GCStipple
     */
      values.line_style = LineSolid;
      values.line_width = 0;
      values.fill_style = FillSolid;

      mask = GCLineStyle | GCLineWidth | GCForeground | GCBackground
            | GCClipXOrigin | GCClipYOrigin;
      if (Out_FontType(o) == XmFONT_IS_FONT) {
            values.font = Out_Font(o)->fid;
            mask |= GCFont;
      } else
#ifdef      USE_XFT
      if (Out_FontType(o) == XmFONT_IS_XFT) {
            /* FIX ME XmFONT_IS_XFT */
      }
#endif
#ifdef      USE_BIDI
      else if (Out_FontType(o) == XmFONT_IS_XOC) {
            /* FIX ME XmFONT_IS_BIDI */
      }
#endif
    values.foreground = Prim_Foreground(w);
    values.background = XtBackground(w);
    values.clip_x_origin = 0;
    values.clip_y_origin = 0;
    dynamic = 0;
    dontcare = 0;

    if (! w->core.sensitive) {
      Screen      *s = XtScreen((Widget)w);

      mask |= GCStipple;
      values.fill_style = FillStippled;
      values.stipple = XmGetPixmapByDepth(s, "50_foreground", 1, 0, 1);
    }

#ifdef      USE_XT_GC
    Out_DrawGC(o) = XtAllocateGC((Widget)w, w->core.depth,
      mask, &values, dynamic, dontcare);
#else
    Out_DrawGC(o) = XCreateGC(XtDisplay((Widget)w), XtWindow(w), mask, &values);
#endif
    Out_DrawGCInverted(o) = False;

    /*
     * Cursor GC
     *      Need to change :        Tile/Stipple Origin, Stipple
     */
    values.line_style = LineSolid;
    values.line_width = 0;
    values.fill_style = FillStippled;
    values.foreground = Prim_Foreground(w);
    values.background = XtBackground(w);
    mask = GCLineStyle | GCLineWidth | GCFillStyle |
      GCForeground | GCBackground;
    dynamic = GCTileStipXOrigin | GCTileStipYOrigin | GCStipple;

    dontcare = 0;

#ifdef USE_XT_GC
    Out_CursorGC(o) = XtAllocateGC((Widget)w, w->core.depth,
      mask, &values, dynamic, dontcare);
#else
    Out_CursorGC(o) = XCreateGC(XtDisplay((Widget)w), XtWindow(w), mask, &values);
#endif

    /*
     * CopyGC
     *      At least this one is not changed anywhere :-)
     */
    values.line_style = LineSolid;
    values.line_width = 0;
    values.fill_style = FillSolid;
    values.foreground = XtBackground(w);
    values.background = Prim_Foreground(w);
    mask = GCLineStyle | GCLineWidth | GCFillStyle |
      GCForeground | GCBackground;

    Out_CopyGC(o) = XtGetGC((Widget)w, mask, &values);
}


static void
GCPixmap(XmTextWidget tw)
{
      OutputData o = Text_OutputData(tw);
      Widget w = (Widget)tw;
      static char dots[] = {2, 1, 1};
      GC gc;
      int width=0, width_erase=0, height=0;
      Display *display;
      XGCValues values;
      XtGCMask mask;

      values.line_style = LineSolid;
      values.line_width = 0;
      values.fill_style = FillSolid;
      values.foreground = 0;
      values.background = 0;

      display = XtDisplay(w);
      width = Out_CursorWidth(o) ;

      if (Out_FontType(o) == XmFONT_IS_FONT) {
            width_erase = 2 * Out_Font(o)->max_bounds.width;
            height = Out_CursorHeight(o) = Out_FontHeight(o);
      } else
#ifdef      USE_XFT
      if (Out_FontType(o) == XmFONT_IS_XFT) {
            width_erase = 2 * ((XftFont *)o->xft_font)->max_advance_width;
            width_erase = 2 * Out_FontAverageWidth(o);      /* FIX ME HACK */
            height = Out_CursorHeight(o) = Out_XftFont(o)->height;
      }
#endif

      if (Out_CursorIBeam(o)) {
            XFreePixmap(XtDisplay(w), Out_CursorIBeam(o));
      }
      Out_CursorIBeam(o) = (Pixmap)NULL;

      if (Out_CursorStipple(o)) {
            XFreePixmap(XtDisplay(w), Out_CursorStipple(o));
      }
      Out_CursorStipple(o) = (Pixmap)NULL;

      if (Out_CursorSave(o)) {
            XFreePixmap(XtDisplay(w), Out_CursorSave(o));
      }
      Out_CursorSave(o) = (Pixmap)NULL;

      Out_CursorSaveValid(o) = False;

      if (height > 0) {
            Out_CursorIBeam(o) = XCreatePixmap(display,
                  RootWindowOfScreen(XtScreen(w)),
                  width, height, 1);
            Out_CursorStipple(o) = XCreatePixmap(display,
                  RootWindowOfScreen(XtScreen(w)),
                  width, height, 1);
            Out_CursorSave(o) = XCreatePixmap(display,
                  RootWindowOfScreen(XtScreen(w)),
                  width_erase, height, w->core.depth);
            values.line_style = LineSolid;
            values.line_width = 0;
            values.fill_style = FillSolid;
            values.foreground = 0;
            values.background = 0;
            mask = GCLineStyle | GCLineWidth | GCFillStyle |
                  GCForeground | GCBackground;
            gc = XCreateGC(display, Out_CursorIBeam(o), mask, &values);

            XFillRectangle(display, Out_CursorIBeam(o), gc, 0, 0, width, height);
            XFillRectangle(display, Out_CursorStipple(o), gc, 0, 0, width, height);

            XSetForeground(display, gc, 1);

            if (Text_InputData(w)->overstrike) {
                  /* Overwrite cursor */
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        0, 0,
                        0, height - 1);
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        0, height - 1,
                        width - 1, height - 1);
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        width - 1, height - 1,
                        width - 1, 0);
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        width - 1, 0,
                        0, 0);
            } else {
                  /* I-beam */
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        2, 1, 2, height - 2);
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        0, 0, 4, 0);
                  XDrawLine(display, Out_CursorIBeam(o), gc,
                        0, height - 1,
                        4, height - 1);
            }

            XSetLineAttributes(display, gc, 0, LineOnOffDash, CapRound, JoinRound);
            XSetDashes(display, gc, 0, &dots[1], (int)dots[0]);

            XDrawLine(display, Out_CursorStipple(o), gc, 2, 1, 2, height - 2);
            XDrawLine(display, Out_CursorStipple(o), gc, 1, 0, 3, 0);
            XDrawLine(display, Out_CursorStipple(o), gc, 1, height - 1,
                  3, height - 1);

            XFreeGC(display, gc);
      }
}


static void
GCClip(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);
    XRectangle clip;

    clip.x = 0;
    clip.y = 0;
    clip.width = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) );
    clip.height = XtHeight(w) - ( Out_TopMargin(o) + Out_BottomMargin(o) );

#ifdef      DANNY
    fprintf(stderr, "XmText GCClip wid %d ht %d\n", clip.width, clip.height);
#endif

    /* These calls change the GCs */
    XSetClipRectangles(XtDisplay((Widget)w), Out_DrawGC(o),
         Out_LeftMargin(o), Out_TopMargin(o), &clip, 1, Unsorted);

    GCPixmap(w);
}


/* Take current dimensions, calculate #rows, #columns from it */
static void
SizeRecalc(XmTextWidget w)
{
      OutputData o = Text_OutputData(w);
      int previousColumns = Out_Columns(o);

      Out_XDraw(o) = Out_LeftMargin(o);

#ifdef      USE_XFT
      /* HACK */
      if (Out_XftFont(o) && Out_XftFont(o)->height < 0)
            Out_XftFont(o)->height = Out_XftFont(o)->ascent + Out_XftFont(o)->descent;
      if (Out_XftFont(o)) {
                  Out_Columns(o) = (XtWidth(w) - (Out_LeftMargin(o) + Out_RightMargin(o)))
                        / Out_XftFont(o)->max_advance_width;
                  Out_Columns(o) = (XtWidth(w) - (Out_LeftMargin(o) + Out_RightMargin(o)))
                        / Out_FontAverageWidth(o);    /* FIX ME HACK */
                  DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                        "SizeRecalc: xft cols %d = (wid %d - lm %d - rm %d) / fw %d, "
                        "ht %d = %d + %d\n",
                        Out_Columns(o), XtWidth(w), Out_LeftMargin(o), Out_RightMargin(o),
                        Out_XftFont(o)->max_advance_width,
                        Out_XftFont(o)->height,
                        Out_XftFont(o)->ascent, Out_XftFont(o)->descent));
      } else 
#endif
      {
#ifdef USE_AVERAGE_WIDTH
            Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) ) )
                  / Out_FontAverageWidth(o);
            DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "SizeRecalc: cols %d = (wid %d - lm %d - rm %d) / fw %d\n",
                  Out_Columns(o), XtWidth(w), Out_LeftMargin(o), Out_RightMargin(o),
                  Out_FontAverageWidth(o)));
#else
            Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) ) )
                  / Out_FontMaxWidth(o);
            DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "SizeRecalc: cols %d = (wid %d - lm %d - rm %d) / fw %d\n",
                  Out_Columns(o), XtWidth(w), Out_LeftMargin(o), Out_RightMargin(o),
                  Out_FontMaxWidth(o)));
#endif
      }

      /* Y offset for a row R is calculated as Out_YDraw(o) - R*fontHeight,
       * and I add FontAscent here because y positions for fonts are
       * measured from the baseline of the font. */
      Out_YDraw(o) = Out_TopMargin(o) + Out_FontAscent(o);

      if (Text_EditMode(w) == XmSINGLE_LINE_EDIT) {
            Out_Rows(o) = 1;
      } else {
            Out_Rows(o) = (XtHeight(w)
                  - ( Out_TopMargin(o) + Out_BottomMargin(o) ) )
                  / Out_FontHeight(o);
            if ( Out_Rows(o) < 1 ) {
                  Out_Rows(o) = 1;
            }
      }
      if (XtHeight(w) < (Out_TopMargin(o) + Out_BottomMargin(o)
                        + Out_FontHeight(o) * Out_Rows(o))) {
            XtHeight(w) = Out_TopMargin(o) + Out_BottomMargin(o)
                  + Out_FontHeight(o) * Out_Rows(o);
      }

      Out_NumberLines(o) = Out_Rows(o);
      if (Out_Columns(o) != previousColumns && Out_WordWrap(o)) {
            _XmTextUpdateLineTable((Widget)w, 0, 0, NULL, False);
      }

      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "SizeRecalc wid %d ht %d -> rows %d cols %d\n",
            XtWidth(w), XtHeight(w), Out_Rows(o), Out_Columns(o)));
}




/* Text Drawing functions ------------------------------------------------ */

/*
 * This thing calls "Draw" which in turn calls "DrawText".
 * Both expect their last argument to be a flag indicating which type
 * of highlighting is to be used :
 *      - XmHIGHLIGHT_NORMAL (no highlighting)
 *      - XmHIGHLIGHT_SELECTED (reversed colours)
 *      - XmHIGHLIGHT_SECONDARY_SELECTED (underlined)
 *
 * This means that this function should break up those parts of text that
 * are indicated as selected and/or highlighted.
 *
 * Highlighted stuff is recorded in an array. The array size is
 *      Text_Highlight(w).number
 * Each element in the array has a mode and a position, e.g.
 *      Text_Highlight(w).list[n].position
 */
static void
DrawAll(XmTextWidget w)
{
    Cardinal i;
    int resty, mh, hi;
    int                 highlight = XmHIGHLIGHT_NORMAL;           /* initial value */
    XmTextPosition      np, first;

    OutputData o = Text_OutputData(w);

#ifdef      DANNY
    fprintf(stderr, "XmText DrawAll(%s dpy %p)\n", XtName(w), XtDisplay(w));
#endif

    /*
     * Without this, the area under the cursor is saved before it
     * is actually drawn; I can't figure out how that can happen but
     * it does. Registering when you redraw that the saved image is
     * invalid helps because we no longer restore invalid images...
     */
    Out_CursorSaveValid(o) = False;

    mh = Text_Highlight(w).number;
    hi = 0;
    np = -1;
    if (mh)
    {
      if (Text_Highlight(w).list[0].position == 0)
      {
          highlight = Text_Highlight(w).list[0].mode;
          hi++;
      }

      if (hi < mh)
      {
          np = Text_Highlight(w).list[hi].position;
      }
      else
      {
          np = -1;
      }
    }
    while ( np != -1 && Text_Line(w)[0].start > np )
      {
      highlight = Text_Highlight(w).list[hi].mode;
      hi++;
      if (hi < mh)
          {
          np = Text_Highlight(w).list[hi].position;
          }
      else
          {
          np = -1;
          }
      }
    if ( np < Text_Line(w)[0].start )
      {
      np = -1;
      }
 
    for (i = 0; i < (Text_LineCount(w) < Out_Rows(o) ?
                 Text_LineCount(w) : Out_Rows(o)); i++)
    {
      Line line = &Text_Line(w)[i];
      Line next = &Text_Line(w)[i + 1];

#ifdef VERBOSE
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
               "DrawAll: line[%d]: start=%d end=%d, highlight change %d\n",
                    i, line->start, next->start - 1, np));
#endif

       /* Cleaning part of widget */
    XClearArea(XtDisplay(w), XtWindow(w),
              Prim_HighlightThickness(w) + Prim_ShadowThickness(w),
               Out_TopMargin(o) + i * Out_FontHeight(o),
              XtWidth(w) -
              2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)),               
               Out_FontHeight(o),
              False);

      /* Does highlighting change in this range of text ?? */
      if (np >= line->start && np <= next->start - 1)
      {                 /* Yes */
          /* Often highlight changes more than once per line */

          /* Draw the first part */
          first = line->start;

          /* Check whether a change is due right now */
          if (first == np)
          {
            if (hi < mh)
            {
                if (Text_Highlight(w).list[hi].position == first)
                {
                  highlight = Text_Highlight(w).list[hi].mode;
                  hi++;

                  if (hi < mh)
                  {
                      np = Text_Highlight(w).list[hi].position;
                  }
                  else
                  {
                      np = -1;
                  }
                }
            }
          }

          while (np != -1 && np <= next->start - 1)
          {
            XmTextPosition drawTo = np;
#if 0
            if ( np < next->start - 1 )
                {
                  /*CP:16 May 1999: basically do not include the return char 
                  ** if the next highlight position is not past the end of the line. */
                drawTo ++;
                }
#endif
            (*Text_Output(w)->Draw)(w, i, first, drawTo, highlight);
            first = np;

            /* Find the next change */
            highlight = Text_Highlight(w).list[hi].mode;
            hi++;
            if (hi == mh - 1) {
                np = -1;
            } else if (hi < mh) {
                np = Text_Highlight(w).list[hi].position;
            }
          }

          /* Draw the last part */
          if (np != next->start - 1)
          {
            XmTextPosition endPos = next->start - 1;
            if ( np > endPos )
                 {
                  /*CP:16 May 1999: basically include the return char 
                  ** if the next highlight position is past the end of the line. */
                 endPos ++;
                 }
            (*Text_Output(w)->Draw)(w, i, first, endPos,
                  highlight);
          }
      }
      else
      {
          /* Sanity checks */
          if (next->start > 0 && line->start < next->start - 1)
          {
                  /*CP:16 May 1999: this point is reached only for lines which
                  ** are inside a selection area, so also include the newline. */
            (*Text_Output(w)->Draw)(w, i, line->start, next->start,
                  highlight);
          }
          else if ( (  line->start == next->start - 1 ) &&
                  highlight != XmHIGHLIGHT_NORMAL )
          {
            (*Text_Output(w)->Draw)(w, i, line->start, next->start,
                  highlight);
          }
      }
    }

       /* Cleaning rest of widget */
    resty = Out_TopMargin(o) + i * Out_FontHeight(o) ;
    XClearArea(XtDisplay(w), XtWindow(w),
              Prim_HighlightThickness(w) + Prim_ShadowThickness(w),
               resty,
              XtWidth(w) -
              2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)),               
              XtHeight(w) - resty - 
              (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)),           
              False);
}




/* Utilities ------------------------------------------------------------- */


#define Out_NextTabStop(o,x) \
    (Out_TabWidth(o)*((x+Out_TabWidth(o))/Out_TabWidth(o)))

/* XTextWidth clone, but taking TABS into account.
 * FIX ME: Must start from col 0 (or a tab boundary) for tab position to be
 *        accurate.
 */
static int
_XmTextNextX(XmTextWidget w, int x, char *ptr, int len)
{
    OutputData o = Text_OutputData(w);
    XFontStruct *fs = Out_Font(o);
    XRectangle ink, log;

    while (len > 0)
    {
      unsigned int c;

      c = (unsigned char)*ptr;
      if (c == '\t') {
          x = Out_NextTabStop(o, x);
      } else if (c == '\0') {
          x = 0;
      } else {
          if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) {
                x += XTextWidth(fs, ptr, 1);
            } else if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONTSET) {
                XmbTextExtents((XFontSet)Out_FontList(o)->renditions[0]->font, ptr, 1, &ink, &log);
                x += log.width;
#ifdef      USE_XFT
            } else if (Out_XftFont(o)) {
            XGlyphInfo  ext;
            XftTextExtents8(XtDisplay((Widget)w), Out_XftFont(o),
                  ptr, 1, &ext);
            x += ext.width;
#endif
          } else {
            /* ??? */
          }

#if 0
            break;

          if (c < fs->min_char_or_byte2 || c > fs->max_char_or_byte2)
          {
            c = fs->default_char;

            /*
             * Hack by vogt@kvi.nl
             * Updated 8 nov 2000 by Tom Pollard pollard@schrodinger.com
             */
            if (c < fs->min_char_or_byte2 || c > fs->max_char_or_byte2) {
                  DEBUGOUT(_LtDebug(__FILE__, (Widget)w, 
                        "_XmTextNextX: fs->default_char %d -> 32\n",
                        c));
                  c = 32;
            }
            /* end hack */
          }

          if (fs->per_char)
          {
            c -= fs->min_char_or_byte2;
            x += fs->per_char[c].width;
          }
          else
            x += fs->max_bounds.width;
#endif
      }

      ptr++;
      len--;
    }

    return x;
}


static Dimension
FontTextWidth(XmTextWidget w, XmTextPosition pos, XmTextPosition end)
{
    XmTextBlockRec block;
    Dimension width;

    if (Text_Source(w) == NULL)
    {
      _XmWarning((Widget)w, "FontTextWidth: no source\n");

      return 1;
    }

    (*Text_Source(w)->ReadSource) (Text_Source(w), pos, end, &block);

    width = _XmTextNextX(w, 0, block.ptr, block.length);

#ifdef VERBOSE
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "FontTextWidth(%s) => %d\n", block.ptr, width));
#endif

    XtFree(block.ptr);

    return width;
}


static XmTextPosition
XToPos(XmTextWidget w, LineNum row, int x)
{
    OutputData o = Text_OutputData(w);
    Line line = &Text_Line(w)[row];
    Line next = &Text_Line(w)[row + 1];
    XmTextPosition start, end, pos;
    XmTextBlockRec block;

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "XToPos(row %d, x %d) TotalLines %d\n",
                  row, x, Text_TotalLines(w)));

    /* Just guessing - Is this right ?? Danny */
    if (row >= Text_TotalLines(w) - 0)
    {
      next = &Text_Line(w)[Text_TotalLines(w) - 1];
      end = next->start - 1;

      if (end < 0)
      {
          end = 0;
      }

      return end;
    }

    start = line->start;
    if (next->start == (XmTextPosition)PASTENDPOS)
    {
      end = Text_LastPos(w);  /* Avoid PASTENDPOS */
    }
#if 0
    else if (next->past_end)        /* There's nothing there ... */
    {
      end = start;                  /* FIXME - this is probably wrong */
    }
#endif
    else
    {
      end = next->start - 1;
    }

    /* x is now the width from the start of the line to the pixel pos */
    x -= Out_LeftMargin(o) - Out_XOffset(o);

    (*Text_Source(w)->ReadSource) (Text_Source(w), start, end, &block);

    /* check if the cursor is before the 1st character */
    if (x <= 0)
    {
      pos = start;
    }
    /* OK, how 'bout after the last character */
    else if (x > _XmTextNextX(w, 0, block.ptr, block.length))
    {
      pos = end;
    }
    /* must be in between somewhere... */
    else
    {
      int count, prevTot, tot, i, diff, mb;
      
      prevTot = tot = 0;
      count = end - start;
      pos = -1;
      diff = x;
      mb = 0;
      for (i = 0; i < count; i++)
      {
          tot = Out_FontTextWidth(o, block.ptr, i);
          if (x < tot)
          {
            pos = start + i;
            if (tot - x > diff)
                pos = pos - 1 - mb;

            break;
          }
          if (i && prevTot == tot) /* Fix at 1k2.2 */
            mb++;
          else
            mb = 0;
          prevTot = tot;
          diff = x - tot;
      }

      if (pos < 0)
      {
          pos = end;
      }
    }

    XtFree(block.ptr);

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
             "XToPos: x=%d start=%d end=%d pos=%d\n", x, start, end, pos));

    return pos;
}


static LineNum
YToLineNum(XmTextWidget w, Position y)
{
    OutputData o = Text_OutputData(w);
    LineNum line, l;

    l = line = (LineNum)((y - Out_TopMargin(o))
            / Out_FontHeight(o));

    if (line >= Text_LineCount(w))
    {
      line = Text_LineCount(w);
    }

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "YToLineNum: y=%d line=%d (l %d Text_LineCount %d)\n",
            y, line, l, Text_LineCount(w)));

    return line;
}


static void
DrawText(XmTextWidget w, int x, int y, char *ptr, int len, XmHighlightMode highlight)
{
      OutputData o = Text_OutputData(w);
      int   xoff, xstart = x, xend;
      Pixel fg, bg;

#ifdef VERBOSE
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "DrawText: x %d y %d '%s' len %d hl %d\n",
            x, y, (ptr == 0) ? "(NULL)" : ptr, len, highlight));
#endif

      xoff = Out_LeftMargin(o) - Out_XOffset(o);

#if 1
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "XmText DrawText x %d y %d '%s' len %d hl %d, fh %d\n",
            x + xoff, y, (ptr == 0) ? "(NULL)" : ptr, len, highlight,
            Out_FontHeight(o)));
#endif

      fg = Prim_Foreground(w);
      bg = XtBackground(w);

      /* Only change the GC if we need to */
      if (highlight == XmHIGHLIGHT_SELECTED) {
            fg = XtBackground(w);
            bg = Prim_Foreground(w);
      } else {
            fg = Prim_Foreground(w);
            bg = XtBackground(w);
      }

      while (len > 0 && *ptr) {
            char *start;
            Dimension piecewidth, pieceheight;
            int count;

            start = ptr;
            count = 0;
            while (len > 0 && *ptr && *ptr != '\t' && *ptr != '\n' ) {
                  ptr++, count++, len--;
            }

            if (count > 0) {
                  piecewidth = _XmTextNextX(w, 0, start, count);
                  pieceheight = 10; /* FIX ME */

                  if (count > 0) {
#if 1
                        /* This is for bug #558840.
                         * Can be tested in test/Xm/text/test1 by double-clicking.
                         */
                        unsigned long     mask = GCForeground | GCBackground;
                        XGCValues   v;

                        v.foreground = bg;
                        v.background = fg;
                        XChangeGC(XtDisplay(w), Out_DrawGC(o), mask, &v);
                        XFillRectangle(XtDisplay(w), XtWindow(w), Out_DrawGC(o),
                              x + xoff, y - Out_FontAscent(o),
                              piecewidth, y + Out_FontDescent(o));

                        v.background = bg;
                        v.foreground = fg;
                        XChangeGC(XtDisplay(w), Out_DrawGC(o), mask, &v);
#endif
                        if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) {
                              XDrawString(XtDisplay(w), XtWindow(w), Out_DrawGC(o),
                                     x + xoff, y, start, count);
                        } else if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONTSET) {
                              XmbDrawString(XtDisplay(w), XtWindow(w),
                                    (XFontSet)Out_FontList(o)->renditions[0]->font,
                                    Out_DrawGC(o),
                                    x + xoff, y,
                                    start, count);
#ifdef      USE_XFT
                        } else if (Out_XftFont(o)) {
                              _XmXftDrawString(XtDisplay(w), XtWindow(w),
                                    Out_FontList(o)->renditions[0],
                                    1,
                                    x + xoff, y,
                                    start, count);
#endif
                        } else {
                              /* ??? */
                        }

                  }

#ifdef VERBOSE
          if (_LtDebugInDebug(__FILE__, (Widget)w))
          {
            char temp[256];

            strncpy(temp, start, count);
            temp[count] = '\0';
            DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                          "Draw: x=%d y=%d -->%s<--\n", x, y, temp));
          }
#endif

                  x += piecewidth;
            }

      if (len > 0 && *ptr == '\t')
      {
          int left = x;
          x = Out_NextTabStop(o, x);
          if ( highlight == XmHIGHLIGHT_SELECTED )
            {
            XSetForeground(XtDisplay(w), Out_DrawGC(o), Prim_Foreground(w));
            XFillRectangle(XtDisplay(w), XtWindow(w), Out_DrawGC(o),
                  left + xoff, y - Out_FontAscent(o),
                  x - left, Out_FontHeight(o));
            XSetForeground(XtDisplay(w), Out_DrawGC(o), XtBackground(w));
            }

          ptr++, len--;
      }
      if (len > 0 && *ptr == '\n')
      {
          int left = x;

          x = Out_NextTabStop(o, x);

          if (highlight == XmHIGHLIGHT_SELECTED)
          {
            XSetForeground(XtDisplay(w), Out_DrawGC(o), Prim_Foreground(w));
            XFillRectangle(XtDisplay(w), XtWindow(w), Out_DrawGC(o),
                  left + xoff, y - Out_FontAscent(o),
                  Out_ScrollWidth(o) - ( left + xoff ),
                  Out_FontHeight(o));
            XSetForeground(XtDisplay(w), Out_DrawGC(o), XtBackground(w));
          }

          ptr++, len--;
      }
    }

    xend = x;

    if (highlight == XmHIGHLIGHT_SECONDARY_SELECTED)
    {
      XDrawLine(XtDisplay(w), XtWindow(w), Out_DrawGC(o),
              xoff + xstart, y + 1, xoff + xend, y + 1);
    }
}


static void
ChangeHOffset(XmTextWidget w, int offset)
{
    OutputData o = Text_OutputData(w);

      DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "ChangeHOffset(%d)\n", offset));

    if (Out_XOffset(o) == offset)
    {
      return;
    }

    Out_XOffset(o) = offset;
    Out_CursorSaveValid(o) = False;

    (*Text_Output(w)->expose) ((Widget)w, NULL, (Region)NULL);

}


extern void
_XmRedisplayHBar(XmTextWidget w, int offset)
{
    OutputData o = Text_OutputData(w);
    Dimension displayWidth, maxWidth;
    int oldMin, oldMax, oldSize, oldValue;
    int newValue;
    int i;

    Out_ScrollWidth(o) = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) );
    if (Out_Hbar(o) == NULL)
    {
      return;
    }

    ChangeHOffset(w, offset);
    if (!Out_ScrollHorizontal(o))
    {
      return;
    }

    maxWidth = 0;
    for (i = 0; i < (Text_LineCount(w) < Out_Rows(o) ?
                 Text_LineCount(w) : Out_Rows(o)); i++)
    {
      if (maxWidth < Text_Line(w)[i].extra->width)
      {
          maxWidth = Text_Line(w)[i].extra->width;
      }
    }

    displayWidth = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) );

    if (maxWidth < displayWidth)
    {
      maxWidth = displayWidth;
    }

    Out_ScrollWidth(o) = maxWidth;

    XtVaGetValues(Out_Hbar(o),
              XmNmaximum, &oldMax,
              XmNminimum, &oldMin,
              XmNsliderSize, &oldSize,
              XmNvalue, &oldValue,
              NULL);

    newValue = _XmMin(Out_XOffset(o), maxWidth - displayWidth);

    if (oldMax != maxWidth || oldMin != 0 ||
      oldSize != displayWidth || oldValue != newValue)
    {
      XtVaSetValues(Out_Hbar(o),
                  XmNmaximum, maxWidth,
                  XmNminimum, 0,
                  XmNsliderSize, displayWidth,
                  XmNvalue, newValue,
                  NULL);
    }

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
             "_XmRedisplayHBar: oldmax=%d newmax=%d oldsize=%d newsize=%d\n",
                  oldMax, maxWidth, oldSize, displayWidth));
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "_XmRedisplayHBar: oldvalue=%d newvalue=%d\n",
                  oldValue, newValue));

}


extern void
_XmChangeVSB(XmTextWidget w, XmTextPosition pos)
{
    OutputData o = Text_OutputData(w);
    int top_index, pos_index, newValue;
    int oldMin = 0, oldMax = 0, oldSize = 0, oldValue = 0, newMax;

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "_XmChangeVSB: pos=%d\n", pos));

    top_index = _XmTextGetTableIndex(w, Text_TopPos(w));
    pos_index = _XmTextGetTableIndex(w, pos);

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "_XmChangeVSB: top_index=%d pos_index=%d\n",
                  top_index, pos_index));

    if (Out_Vbar(o))
    {
      XtVaGetValues(Out_Vbar(o),
                  XmNmaximum, &oldMax,
                  XmNminimum, &oldMin,
                  XmNsliderSize, &oldSize,
                  XmNvalue, &oldValue,
                  NULL);
    }

/* SG (15/08/1998)    newMax = _XmMax(Text_TotalLines(w) - 1, Out_Rows(o));
   with the original code it was not possible to use the scrollbar to scroll
   down to the last line. Most obviously if out_rows is 1 (hence the slider
   size is 1) and there are 2 lines of text, setting scrollbar max to 1
   with a slider size of 1 means you cannot move the scroll bar at all ! */
    newMax = _XmMax(Text_TotalLines(w) , Out_Rows(o));

    if (newMax == 0)
    {
      newMax = 1;       /* Avoid another warning message ?? */
    }

    /* Setting XmNminimum == XmNmaximum is not a good idea */

#if 0
    /* rws 16 Jan 1999
       What does this do????  The scrollbar value should be the index of the
       first visible line, right??
     */
    newValue = pos_index > (newMax - Out_Rows(o))
      ? (newMax - Out_Rows(o)) : pos_index;
#else
    newValue = top_index;
#endif

    if (Out_Vbar(o) && (oldMax != newMax || oldMin != 0 ||
                  oldSize != Out_Rows(o) || oldValue != newValue))
    {
      XmScrollBarCallbackStruct cbs;

      XtVaSetValues(Out_Vbar(o),
                  XmNmaximum, newMax,
                  XmNminimum, 0,
                  XmNvalue, newValue,
                  XmNsliderSize, Out_Rows(o),
                  XmNpageIncrement, Out_Rows(o),
                  NULL);

      cbs.event = NULL;
      cbs.value = newValue;
      cbs.reason = XmCR_VALUE_CHANGED;
      cbs.pixel = 0;

      XtCallCallbacks(Out_Vbar(o), XmNvalueChangedCallback, &cbs);
    }

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
               "_XmChangeVSB: oldmax=%d newmax=%d oldsize=%d newsize=%d\n",
                  oldMax, newMax, oldSize, Out_Rows(o)));

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "_XmChangeVSB: oldvalue=%d newvalue=%d\n",
                  oldValue, newValue));

}

/* Cursor functions -------------------------------------------------------- */

static void
CursorInit(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);

    Out_CursorIBeam(o) = (Pixmap)NULL;
    Out_CursorStipple(o) = (Pixmap)NULL;
    Out_CursorSave(o) = (Pixmap)NULL;

    /* Out_CursorPositionVisible(o) = True; */
    Out_CursorSaveValid(o) = False;
}


void
_XmCursorOverstrike(Widget w)
{
    OutputData o = Text_OutputData(w);
    /* These change the GC !! (Danny) */
    if (Out_HasFocus(o)) {
      GCPixmap((XmTextWidget)w);
      if (Text_InputData(w)->overstrike) {
            XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o),
                  Out_CursorIBeam(o));
      } else {
            XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o),
                  Out_CursorIBeam(o));
      }
    } else {
      XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o),
                Out_CursorStipple(o));
    }
}

static void
CursorSet(XmTextWidget w, Boolean focus)
{
    OutputData o = Text_OutputData(w);

    Out_HasFocus(o) = focus;

    /* These change the GC !! (Danny) */
    if (focus) {
      XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o),
            Out_CursorIBeam(o));
    } else {
      XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o),
                Out_CursorStipple(o));
    }
}


static void
CursorSaveUnderIBeam(XmTextWidget w, Position x, Position y)
{
    OutputData o = Text_OutputData(w);

    if (!XtIsRealized((Widget)w))
    {
      return;
    }

#ifdef VERBOSE
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "CursorSaveUnderIBeam\n"));
#endif

    /* Make sure that the text is drawn before saving the cursor */
    XFlush(XtDisplay((Widget)w));

    /* save the area under the cursor */
    XFillRectangle(XtDisplay((Widget)w), Out_CursorSave(o), Out_CopyGC(o),
               0, 0, Out_CursorWidth(o), Out_CursorHeight(o) );

    XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), Out_CursorSave(o),
            Out_CursorGC(o),
            x - 2, y,
            Out_CursorWidth(o), Out_CursorHeight(o), 0, 0);

    Out_CursorSaveValid(o) = True;
}


static void
CursorRestoreUnderIBeam(XmTextWidget w, Position x, Position y)
{
    OutputData o = Text_OutputData(w);

    if (!XtIsRealized((Widget)w))
    {
      return;
    }

#ifdef VERBOSE
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "CursorRestoreUnderIBeam\n"));
#endif

    /* Make sure that the text is drawn before erasing the cursor */
    XFlush(XtDisplay((Widget)w));

    XCopyArea(XtDisplay((Widget)w), Out_CursorSave(o), XtWindow((Widget)w),
            Out_CursorGC(o), 0, 0, 5, Out_FontHeight(o),
            x - 2, y);

    Out_CursorSaveValid(o) = False; /* Huh ?? FIX ME */
}


static void
CursorDrawIBeam(XmTextWidget w, int x, int y)
{
    OutputData o = Text_OutputData(w);

    /* save the area under the cursor */
    CursorSaveUnderIBeam(w, x, y);

    /* Bail if the GC's don't exist yet. */
    if (!XtIsRealized((Widget)w))
    {
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "CursorDrawIBeam: no GC\n"));
      return;
    }

    /* These change the GC !! (Danny) */
    XSetTSOrigin(XtDisplay((Widget)w), Out_CursorGC(o),
             x - 2, y);

    if (Text_InputData(w)->overstrike) {
    } else {
    }

      XFillRectangle(XtDisplay((Widget)w), XtWindow((Widget)w),
            Out_CursorGC(o),
            x - 2, y,
            Out_CursorWidth(o), Out_CursorHeight(o));
}


static void
CursorDraw(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);

    if (Out_CursorPositionVisible(o))
    {
      CursorDrawIBeam(w, Out_CursorX(o), 
            ( Out_CursorY(o) - Out_CursorHeight(o) ) + Out_FontDescent(o) );
      Out_BlinkOn(o) = True;
    }
}


static void
CursorErase(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);

    if (Out_CursorSaveValid(o))
    {
      CursorRestoreUnderIBeam(w, Out_CursorX(o), 
            ( Out_CursorY(o) - Out_CursorHeight(o) ) + Out_FontDescent(o) );
    }

    Out_BlinkOn(o) = False;
}

/* Callbacks --------------------------------------------------------------- */

static void
HandleTimer(XtPointer client_data, XtIntervalId *timer)
{
    XmTextWidget w = (XmTextWidget)client_data;
    OutputData o = Text_OutputData(w);

    OnOrOff nextBlinkState = Out_BlinkState(o) == on ? off : on;
    (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w),
                                 nextBlinkState );
    Out_BlinkState(o) = nextBlinkState;
    Out_TimerId(o) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
                             Out_BlinkRate(o), HandleTimer,
                             (XtPointer)w);
}


static void
HandleHBar(Widget sw, XtPointer client_data, XtPointer call_data)
{
    XmTextWidget w = (XmTextWidget)client_data;
    OutputData o = Text_OutputData(w);
    XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)call_data;
    Dimension displayWidth, newOffset = 0;

    switch (cbs->reason)
    {
    case XmCR_DECREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
              "HandleHbar reason=XmCR_DECREMENT value= %d\n", cbs->value));

      newOffset = Out_XOffset(o) > Out_FontAverageWidth(o) ?
          Out_XOffset(o) - Out_FontAverageWidth(o) : 0;
      break;

    case XmCR_DRAG:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "HandleHbar reason=XmCR_DRAG value=%d\n", cbs->value));

      newOffset = cbs->value / Out_FontAverageWidth(o) *
          Out_FontAverageWidth(o);
      break;

    case XmCR_INCREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
               "HandleHbar reason=XmCR_INCREMENT value=%d\n", cbs->value));

      displayWidth = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) );

      if (Out_XOffset(o) < Out_ScrollWidth(o) - displayWidth - Out_FontAverageWidth(o))
      {
          newOffset = Out_XOffset(o) + Out_FontAverageWidth(o);
      }
      else
      {
          newOffset = Out_ScrollWidth(o) - displayWidth;
      }
      break;

    case XmCR_PAGE_DECREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleHbar reason=XmCR_PAGE_DECREMENT value=%d\n",
                    cbs->value));

#ifdef USE_AVERAGE_WIDTH
      newOffset = Out_XOffset(o) > Out_Columns(o) * Out_FontAverageWidth(o) ?
          Out_XOffset(o) - Out_Columns(o) * Out_FontAverageWidth(o) : 0;
#else
      newOffset = Out_XOffset(o) > Out_Columns(o) * Out_FontMaxWidth(o) ?
          Out_XOffset(o) - Out_Columns(o) * Out_FontMaxWidth(o) : 0;
#endif
      break;

    case XmCR_PAGE_INCREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleHbar reason=XmCR_PAGE_INCREMENT value=%d\n",
                    cbs->value));

      displayWidth = XtWidth(w) - 2 * (Prim_HighlightThickness(w) +
                        Prim_ShadowThickness(w) + Text_MarginWidth(w));

#ifdef USE_AVERAGE_WIDTH
      if (Out_XOffset(o) < Out_ScrollWidth(o) - displayWidth -
          Out_Columns(o) * Out_FontAverageWidth(o))
      {
          newOffset = Out_XOffset(o) + Out_Columns(o) * Out_FontAverageWidth(o);
#else
      if (Out_XOffset(o) < Out_ScrollWidth(o) - displayWidth -
          Out_Columns(o) * Out_FontMaxWidth(o))
      {
          newOffset = Out_XOffset(o) + Out_Columns(o) * Out_FontMaxWidth(o);
#endif
      }
      else
      {
          newOffset = Out_ScrollWidth(o) - displayWidth;
      }

      break;

    case XmCR_TO_BOTTOM:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "HandleHbar reason=XmCR_TO_BOTTOM value=%d pixel=%d\n",
                    cbs->value, cbs->pixel));

      newOffset = 0;
      break;

    case XmCR_TO_TOP:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleHbar reason=XmCR_TO_TOP value=%d pixel=%d\n",
                    cbs->value, cbs->pixel));

      displayWidth = XtWidth(w) - 2 * (Prim_HighlightThickness(w) +
                        Prim_ShadowThickness(w) + Text_MarginWidth(w));
      newOffset = Out_ScrollWidth(o) - displayWidth;
      break;

    case XmCR_VALUE_CHANGED:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleHbar reason=XmCR_VALUE_CHANGED value=%d\n",
                    cbs->value));
      newOffset = cbs->value / Out_FontAverageWidth(o) *
          Out_FontAverageWidth(o);
      break;

    default:
      newOffset = Out_XOffset(o);
      break;
    }

    ChangeHOffset(w, newOffset);

    XtVaSetValues(Out_Hbar(o), XmNvalue, Out_XOffset(o), NULL);
}


static void
HandleVBar(Widget sw, XtPointer client_data, XtPointer call_data)
{
    XmTextWidget w = (XmTextWidget)client_data;
    OutputData o = Text_OutputData(w);
    XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)call_data;
    Dimension index;

    switch (cbs->reason)
    {
    case XmCR_DECREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_DECREMENT\n"));

      XmTextScroll((Widget)w, -1);
      break;

    case XmCR_DRAG:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_DRAG value=%d\n",
                    cbs->value));

      index = cbs->value;
      Text_TopPos(w) = Text_LineTable(w)[index].start_pos;
      Text_NeedsRefigureLines(w) = True;
      break;

    case XmCR_INCREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_INCREMENT\n"));
      XmTextScroll((Widget)w, 1);
      break;

    case XmCR_PAGE_DECREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_PAGE_DECREMENT\n"));

      XmTextScroll((Widget)w, -Out_Rows(o));
      break;

    case XmCR_PAGE_INCREMENT:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_PAGE_INCREMENT\n"));

      XmTextScroll((Widget)w, Out_Rows(o));
      break;

    case XmCR_TO_BOTTOM:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_TO_BOTTOM\n"));

      index = Text_TotalLines(w) - 1 - Out_Rows(o);
      Text_TopPos(w) = Text_LineTable(w)[index].start_pos;
      Text_NeedsRefigureLines(w) = True;
      break;

    case XmCR_TO_TOP:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmCR_TO_TOP\n"));

      Text_TopPos(w) = Text_FirstPos(w);
      Text_NeedsRefigureLines(w) = True;
      break;

    case XmCR_VALUE_CHANGED:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=XmVALUE_CHANGED\n"));

      index = cbs->value;
      Text_TopPos(w) = Text_LineTable(w)[index].start_pos;
      Text_NeedsRefigureLines(w) = True;
      break;

    default:
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "HandleVbar reason=UNKNOWN\n %d", cbs->reason));
      break;
    }

    _XmRedisplayHBar(w, Out_XOffset(o));

/*CP : I do not think this is needed here
    Text_NeedsRefigureLines(w) = True;
*/
    (*w->core.widget_class->core_class.expose) ((Widget)w, NULL, (Region)NULL);

}


static void
HandleFocusEvents(Widget aw, XtPointer client_data, XEvent* event, Boolean* continueToDispatch )
{
    XmTextWidget w = (XmTextWidget)aw;
    OutputData o = Text_OutputData(w);

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleFocusEvent event=%s\n",
                  event->type == FocusIn ? "FocusIn" : "FocusOut"));

    if ( event->type == FocusIn && event->xany.send_event && !Out_HasFocus(o) )
    {
      if (Text_FocusCallback(w) )
      {
          XmAnyCallbackStruct cbs;
          cbs.reason = XmCR_FOCUS;
          cbs.event = event;

          XtCallCallbackList((Widget)w, Text_FocusCallback(w), &cbs);
      }

      Out_HasFocus(o) = True;

      XSetStipple(XtDisplay(aw), Out_CursorGC(o), Out_CursorIBeam(o));

      if (Out_BlinkRate(o) > 0)
      {
/*CP:Handle timer will do all this
          Out_TimerId(o) = XtAppAddTimeOut(XtWidgetToApplicationContext(aw),
                                   Out_BlinkRate(o), HandleTimer,
                                   (XtPointer)w);
*/
          HandleTimer((XtPointer)w, 0);
      }
      (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on);
    }
    else if ( event->type == FocusOut && Out_HasFocus(o) )
    {
      if (Text_LosingFocusCallback(w))
      {
          XmTextVerifyCallbackStruct cbs;
          cbs.reason = XmCR_LOSING_FOCUS;
          cbs.event = event;
          cbs.currInsert = cbs.newInsert = Text_CursorPos(w);
          cbs.startPos = cbs.endPos = 0;
          cbs.text = NULL;

          XtCallCallbackList((Widget)w, Text_LosingFocusCallback(w), &cbs);
      }
      Out_HasFocus(o) = False;

      XSetStipple(XtDisplay(aw), Out_CursorGC(o), Out_CursorStipple(o));
      (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on);

      if (Out_TimerId(o))
      {
          XtRemoveTimeOut(Out_TimerId(o));
          Out_TimerId(o) = 0;
      }
    }

}



/* Output Methods --------------------------------------------------------- */

static XmTextPosition
XYToPos(XmTextWidget w, Position x, Position y)
{
    LineNum row = YToLineNum(w, y);
    if ( row == Text_LineCount(w))
      return Text_LastPos(w);
    return XToPos(w, row, x);
}


/*
 * Returns whether the cursor is in an area that's currently visible.
 */
static Boolean
PosToXY(XmTextWidget w, XmTextPosition pos, Position *x, Position *y)
{
    OutputData o = Text_OutputData(w);
    Cardinal i;

    *x = *y = -1;       /* On purpose ! */

    if (pos < Text_TopPos(w))
    {
      return False;
    }

    for (i = 0; i < Text_LineCount(w); i++)
    {
      Line line = &Text_Line(w)[i];
      Line next = &Text_Line(w)[i + 1];

      if (pos >= line->start && pos < next->start)
      {
          *y = Out_YDraw(o) + i * Out_FontHeight(o);
          *x = Out_XDraw(o) - Out_XOffset(o) +
            FontTextWidth(w, line->start, pos);
          return True;
      }
    }

    return False;
}


static void
MakePositionVisible(XmTextWidget w, XmTextPosition pos)
{
    OutputData o = Text_OutputData(w);
    unsigned int line, newTopLine;
    int start, offset;
    Dimension xpos, last_xpos;
    Boolean UpdateVSB = False;

    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "MakePositionVisible pos=%d\n", pos));

    line = _XmTextGetTableIndex(w, pos);
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                  "\tline=%d, top_line=%d, line_count=%d, rows=%d redisplay=%s refigure=%s\n", 
                  line,
                  Text_TopLine(w),
                  Text_LineCount(w),
                  Out_Rows(o),
                  Text_NeedsRedisplay(w) ? "True" : "False",
                  Text_NeedsRefigureLines(w) ? "True" : "False" ));

    if (line < Text_TopLine(w))
    {
      newTopLine = line;
    }
    else if (line > Text_TopLine(w) + Out_Rows(o) - 1)
    {
      newTopLine = line - Out_Rows(o) + 1;
    }
    else
    {
      newTopLine = Text_TopLine(w);
    }

    if (newTopLine != Text_TopLine(w))
    {
      Text_TopPos(w) = Text_LineTable(w)[newTopLine].start_pos;
      Text_NeedsRedisplay(w) = True;
      Text_NeedsRefigureLines(w) = True;
      UpdateVSB = True;
    }

    start = Text_LineTable(w)[line].start_pos;
    xpos = FontTextWidth(w, start, pos);
    last_xpos = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) );

    if (xpos - Out_XOffset(o) > last_xpos)
    {
      offset = xpos - last_xpos;
    }
    else if (xpos < Out_XOffset(o))
    {
      offset = xpos;
    }
    else
    {
      offset = Out_XOffset(o);
    }

    /* FIX ME should Out_ScrollHorizontal and Out_ScrollVertical be False if
     * Text is not child of scrolledwindow
     */
    if (offset != Out_XOffset(o))
    {
      if (Out_ScrollHorizontal(o) && Out_Hbar(o))
      {
          _XmRedisplayHBar(w, offset);
      }
      else
      {
          ChangeHOffset(w, offset);
      }
    }

    if (Out_ScrollVertical(o) && Out_Vbar(o) && UpdateVSB)
    {
      _XmChangeVSB(w, pos);
    }
}


static Boolean
MoveLines(XmTextWidget w, LineNum from, LineNum to, LineNum dest)
{
    return False;
}


static Boolean
MeasureLine(XmTextWidget w, LineNum num, XmTextPosition pos,
          XmTextPosition *next, LineTableExtraRec **extra)
{
    OutputData o = Text_OutputData(w);
    Dimension width = 0;
    XmTextPosition start, end;
    LineTableExtra e;

#ifdef VERBOSE
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
        "MeasureLine: line=%d pos=%d %s %s\n",
        num, pos, 
        next ? "wants next" : "",
        extra ? "wants width": ""));
#endif
    start = pos < Text_LastPos(w) ? pos : Text_LastPos(w);
    if (start < Text_LastPos(w))
    {
      end = (*Text_Source(w)->Scan) (Text_Source(w), pos,
                               XmSELECT_LINE, XmsdRight, 1, False);
    }
    else
    {
      end = Text_LastPos(w);
    }
#ifdef VERBOSE
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
      "\tmeasure from %d to %d\n", start, end));
#endif

    if (next)
    {
      if (end >= Text_LastPos(w))
      {
          *next = (XmTextPosition)PASTENDPOS;
#ifdef VERBOSE
          DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "\tnext PASTENDPOS\n"));
#endif
      }
      else
      {
          *next = end + 1;
#ifdef VERBOSE
          DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "\tnext %d\n", *next));
#endif
      }

      width = FontTextWidth(w, start, end);

      if (extra)
      {
          e = (LineTableExtra)XtMalloc(sizeof(LineTableExtraRec));
          e->width = width;
          e->wrappedbychar = False;

          *extra = e;
      }
    }

#if VERBOSE
    /* This is incredibly verbose; besides it seems to work. */
    if (_LtDebugInDebug(__FILE__, (Widget)w))
    {
      if (next)
          DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                        "MeasureLine: line=%d pos=%d next=%d width=%d\n",
                        num, pos, *next, width));
      else
          DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                      "MeasureLine: line=%d pos=%d next=NULL width=%d\n",
                        num, pos, width));
    }
#endif

    if (num <= Out_Rows(o) - 1)
    {
      return True;
    }
    else
    {
      _XmRedisplayHBar(w, Out_XOffset(o));

      return False;
    }
}


/*
 * DrawInsertionPoint() gets called all the time from TextIn.c, which doesn't
 *      keep track of whether the insertion point should be visible at all.
 * We should therefore implement XmNcursorPositionVisible here.
 *
 * Between calls of DrawInsertionPoint() we should keep track of whether and
 *      where the cursor is with Out_CursorX(o) and Out_CursorY(o); set them
 *      to -1 for no cursor.
 */
static void
DrawInsertionPoint(XmTextWidget w, XmTextPosition pos, OnOrOff state)
{
    OutputData o = Text_OutputData(w);
    Position x, y;

#if 1
/* rws 1 Apr 2000
WRT the disappearing cursor....

HandleTimer seems to be getting called when it should. This takes care of
setting Out_BlinkState, then calls DrawInsertionPoint, which is also
messing with Out_BlinkState. I'm not sure what Out_BlinkOn is keeping track
of, but I would expect the two if clauses near the start of
DrawInsertionPoint to be a little more symetrical wrt Out_BlinkOn and
Out_BlinkState. Commenting out the two lines messing with the BlinkState
seems to keep my cursor from disappearing. I've bracketted the section in
question with #if 1, it needs a little more investigation.....
*/
    if ( state == off )
    {
      if ( Out_BlinkOn(o) == 0 )
      {
          Out_BlinkState(o) = off;
      }
      Out_BlinkOn(o) -- ;
    }
    if ( state == on )
    {
      if ( Out_BlinkOn(o) < 0 )
      {
          Out_BlinkOn(o)++ ;
      }
      Out_BlinkState(o) = on;
    }
#endif

    if ( Out_BlinkOn(o) != 0 )
    {
      return;
    }

    if (pos == PASTENDPOS)    /* No No No : don't want this */
    {
      pos = Text_LastPos(w);  /* ??? Danny 6/7/97 */
    }

#ifdef VERBOSE
    DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
            "DrawInsertionPoint Cursor : Pos %d, Save %sValid, %s Visible\n",
                  pos, Out_CursorSaveValid(o) ? "" : "not ",
                  Out_CursorPositionVisible(o) ? "" : "not"));
#endif

#if 0
    /* Experimental */
    /* Figure out what to do with the cursor here, before actually showing it. */
    if (!Out_CursorPositionVisible(o))
    {
      if (state == off)
          CursorErase(w);
      return;
    }
#endif

    if (!XtIsRealized((Widget)w))
    {
      return;
    }
    /* Force to get forcus to display strings quickly. */
    XmImSetFocusValues((Widget)w, NULL, 0);

    /* erase previously visible cursor */
    if (Out_CursorX(o) >= 0 && Out_CursorY(o) >= 0)
    {
      CursorErase(w);
    }

    if (state == on)
    {
      /* draw new cursor
       * PosToXY returns whether the position is in the area currently
       * shown
       */
      if ((*Text_Output(w)->PosToXY) (w, pos, &x, &y))
      {
          Out_CursorX(o) = x;
          Out_CursorY(o) = y;

#if 0
      /*
       * This shouldn't be necessary 'cause CursorDraw calls CursorDrawIBeam
       * which already takes care of this.
       */
          if (!Out_CursorSaveValid(o))
          {
            CursorSaveUnderIBeam(w, Out_CursorX(o), Out_CursorY(o));
          }
#endif

#ifdef VERBOSE
          DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "Draw cursor at %d %d\n",
                        Out_CursorX(o), Out_CursorY(o)));
#endif

          CursorDraw(w);
      }
    }

#if VERBOSE
    if (_LtDebugInDebug(__FILE__, (Widget)w))
    {
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "DrawInsertionPoint: x=%d pos=%d state=%s\n",
                    Out_CursorX(o), pos, (state == on ? "on" : "off")));
    }
#endif
}


static void
Draw(XmTextWidget w, LineNum num, XmTextPosition start, XmTextPosition end,
     XmHighlightMode highlight)
{
    OutputData o = Text_OutputData(w);
    XmTextBlockRec block;
    Line line = &Text_Line(w)[num];

#ifdef      DANNY
    fprintf(stderr, "XmText Draw(%s dpy %p)\n", XtName(w), XtDisplay(w));
#endif

    if (start > Text_LastPos(w)) {
      return;
    }

    if (end > Text_LastPos(w))
    {
      end = Text_LastPos(w);
      if (line->start > end)
      {
          return;
      }
    }

    (*Text_Source(w)->ReadSource) (Text_Source(w), line->start, end, &block);

    if (block.length > 0)
    {
      int x, y;
      char *ptr;
      int len;

      ptr = block.ptr + start - line->start;
      len = end - start;
      if (start > line->start)
      {
          x = _XmTextNextX(w, 0, block.ptr, start - line->start);
      }
      else
      {
          x = 0;
      }

      y = Out_YDraw(o) + num * Out_FontHeight(o);

      DrawText(w, x, y, ptr, len, highlight);
    }

    XtFree(block.ptr);
}


static void
OutputInvalidate(XmTextWidget w, XmTextPosition start, XmTextPosition end,
             long delta)
{
    OutputData o = Text_OutputData(w);
    Out_CursorSaveValid(o) = False;
}


static void
GetPreferredSize(Widget aw, Dimension *width, Dimension *height)
{
      XmTextWidget      w = (XmTextWidget)aw;
      OutputData  o = Text_OutputData(w);

      *height = Out_TopMargin(o) + Out_BottomMargin(o) +
            Out_Rows(o) * Out_FontHeight(o);

#ifdef      USE_XFT
      if (Out_XftFont(o)) {
            *width = Out_LeftMargin(o) + Out_RightMargin(o) +
                  Out_Columns(o) * Out_FontAverageWidth(o);
            DEBUGOUT(_LtDebug(__FILE__, aw, "GetPreferredSize (fw %d )-> wid %d ht %d\n",
                  Out_FontAverageWidth(o), *width, *height));
      } else
#endif
      {
#ifdef USE_AVERAGE_WIDTH
            *width = Out_LeftMargin(o) + Out_RightMargin(o) +
                  Out_Columns(o) * Out_FontAverageWidth(o) ;
            DEBUGOUT(_LtDebug(__FILE__, aw, "GetPreferredSize (fw %d )-> wid %d ht %d\n",
                        Out_FontAverageWidth(o), *width, *height));
#else
            *width = Out_LeftMargin(o) + Out_RightMargin(o) +
                  Out_Columns(o) * Out_FontMaxWidth(o) ;
            DEBUGOUT(_LtDebug(__FILE__, aw, "GetPreferredSize (fw %d )-> wid %d ht %d\n",
                        Out_FontMaxWidth(o), *width, *height));
#endif
      }
}


static void
OutputGetValues(Widget w, ArgList args, Cardinal num_args)
{
    XmTextInnerWidget iw = Text_InnerWidget(w);

#if VERBOSE
    /* Just print a list of resources requested */
    DEBUGOUT(_LtDebug(__FILE__, w, "OutputGetValues"));

    if (_LtDebugInDebug(__FILE__, w) && num_args != 0)
    {
      int i;

      DEBUGOUT(_LtDebug0(__FILE__, w, "("));
      for (i = 0; i < num_args - 1; i++)
      {
          DEBUGOUT(_LtDebug0(__FILE__, w, "%s, ", args[i].name));
      }

      DEBUGOUT(_LtDebug0(__FILE__, w, "%s)", args[num_args - 1].name));
    }
    DEBUGOUT(_LtDebug0(__FILE__, w, "\n"));
#endif

    XtGetSubvalues(iw, output_resources, XtNumber(output_resources),
               args, num_args);
    if (_LtDebugInDebug(__FILE__, w))
    {
      DEBUGOUT(_LtDebug(__FILE__, w, "OutputGetValues :\n"));
      _LtDebugPrintArgList(__FILE__, w, args, num_args, True);
    }
}


/*
 * Oh boy. We're getting called directly, not through Xt. Therefore, we
 * have different old, new widgets (XmText), but they all point to the
 * same OutputData.
 *
 * So, enter the hack of the month : we'll have to take care of this. :-(
 * The trouble is all the stuff that's underneath... we'll see how far this
 * leads us. We may have to find another way to solve this.
 *
 * Note we're replacing the *old* variables by temp variables; so the functions
 * we call from here all get the real stuff and change things in the right
 * places.
 *
 * 19/5/97 : already on two levels (OutputRec and OutputDataRec).
 */
static Boolean
OutputSetValues(Widget old, Widget request, Widget new_w,
            ArgList args, Cardinal *num_args)
{
    OutputRec oldOutput;
    OutputDataRec oldData;
    OutputData nd = Text_OutputData(new_w), od = &oldData;
    XmTextInnerWidget iw = Text_InnerWidget(new_w);
    Boolean redraw = False;


    DEBUGOUT(_LtDebug(__FILE__, new_w,
                  "OutputSetValues: %i args\n"
                  "\t    old X %5i Y %5i W %5i H %5i\n"
                  "\trequest X %5i Y %5i W %5i H %5i\n"
                  "\t    new X %5i Y %5i W %5i H %5i\n",
                  *num_args,
                  XtX(old), XtY(old),
                  XtWidth(old), XtHeight(old),
                  XtX(request), XtY(request),
                  XtWidth(request), XtHeight(request),
                  XtX(new_w), XtY(new_w),
                  XtWidth(new_w), XtHeight(new_w)));
    DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));

    /* Insert new variables */
    oldOutput = *Text_Output(old);  /* Copy old values */
    Text_Output(old) = &oldOutput;
    *od = *nd;                /* Copy old values */
    Text_OutputData(old) = od;

    /* Ready */

    /* Copy whatever we get passed into our data structures */
    XtSetSubvalues(iw, output_resources, XtNumber(output_resources),
               args, *num_args);

    Out_RightMargin(nd) = Out_LeftMargin(nd) = Prim_ShadowThickness(new_w) + 
            Prim_HighlightThickness(new_w) + Text_MarginWidth(new_w) ;
    Out_TopMargin(nd) = Out_BottomMargin(nd) = Prim_ShadowThickness(new_w) + 
            Prim_HighlightThickness(new_w) + Text_MarginHeight(new_w) ;

    if (Out_RightMargin(od) != Out_RightMargin(nd) ||  Out_LeftMargin(nd) !=  Out_LeftMargin(od) 
      || Out_TopMargin(nd) != Out_TopMargin(od) || Out_BottomMargin(nd) != Out_BottomMargin(od))
    {
      (*Text_Output(old)->resize) (new_w, True);          
      redraw = True;
    }
    /* Check if we need to act */

    if (Out_FontList(od) != Out_FontList(nd))
    {
      DEBUGOUT(_LtDebug(__FILE__, new_w,
                    "OutputSetValues: FontList change.\n"));

      /* T. Straumann: make a copy of the font list and free the old one */
      Out_FontList(nd) = XmFontListCopy(Out_FontList(nd));
      /* rws 17 Jul 1999
         But only free it if we created it....
         xmgrace Data->Results
      */
      if (Out_FontListCreated(od) && Out_FontList(od)) {
            XmFontListFree(Out_FontList(od));
      }

      FontInit((XmTextWidget)new_w);
      /* From OutputCreate : */
      XtHeight(new_w) = Out_FontHeight(nd)
          + 2 * (Prim_ShadowThickness(new_w) + Text_MarginHeight(new_w));
#ifdef USE_AVERAGE_WIDTH
      XtWidth(new_w) = Out_Columns(nd) * Out_FontAverageWidth(nd)
            + Out_LeftMargin(nd) + Out_RightMargin(nd) ;
#else
      XtWidth(new_w) = Out_Columns(nd) * Out_FontMaxWidth(nd)
            + Out_LeftMargin(nd) + Out_RightMargin(nd) ;
#endif

      if (Out_DrawGC(nd)) {
          /*
           * We need to change the font id in the DrawGC,
           * not the other GC's.
           *
           * Note we can only do this because the mask used when
           * we got this GC specifies that we can change the font.
           */
          XGCValues     values;

          if (Out_FontType(nd) == XmFONT_IS_FONT) {
            values.font = Out_Font(nd)->fid;
            XChangeGC(XtDisplay(new_w), Out_DrawGC(nd), GCFont, &values);
          } else
#ifdef      USE_XFT
          if (Out_FontType(nd) == XmFONT_IS_XFT) {
            /* Probably nothing to do here */
          }
#endif

          {
            /*
             * Need braces here to provide an 'else' statement
             * in case that USE_XFT is not defined.
             */

            /* We may still need to do things here.
             * CP Hennessy suggest calling
                  GCClip((XmTextWidget)new_w);
             */
          }
      }

      redraw = True;
    }

    if (Out_WordWrap(od) != Out_WordWrap(nd))
    {
      DEBUGOUT(_LtDebug(__FILE__, new_w,
                    "OutputSetValues: WordWrap change.\n"));
            /*CP:15 May 1999:rebuild the line table */
      _XmTextUpdateLineTable(new_w, 0, 0, NULL, False); 
      redraw = True;
    }

    if (Out_CursorPositionVisible(od) != Out_CursorPositionVisible(nd))
    {
      DEBUGOUT(_LtDebug(__FILE__, new_w,
                    "OutputSetValues: CursorPosVis change.\n"));

      /* FIX ME ?? */
      DrawInsertionPoint((XmTextWidget)new_w, Text_CursorPos(new_w), off);

      redraw = True;
    }

    if (Out_Rows(od) != Out_Rows(nd))
    {
      DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: Rows change.\n"));

      /* FIX ME ? */
      XtHeight(new_w) = Out_Rows(nd) * Out_FontHeight(nd)
          + Out_TopMargin(nd) + Out_BottomMargin(nd) ;

      redraw = True;
    }

    if (Out_Columns(od) != Out_Columns(nd))
    {
      DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: Columns change.\n"));

      /* FIX ME ? */
#ifdef      USE_XFT
      if (Out_XftFont(nd)) {
            XtWidth(new_w) = Out_Columns(nd) * Out_XftFont(nd)->max_advance_width
                  + Out_LeftMargin(nd) + Out_RightMargin(nd);
            XtWidth(new_w) = Out_Columns(nd) * Out_FontAverageWidth(nd)
                  + Out_LeftMargin(nd) + Out_RightMargin(nd);     /* FIX ME HACK */
      } else
#endif
      {
#ifdef USE_AVERAGE_WIDTH
            XtWidth(new_w) = Out_Columns(nd) * Out_FontAverageWidth(nd)
                  + Out_LeftMargin(nd) + Out_RightMargin(nd);
#else
            XtWidth(new_w) = Out_Columns(nd) * Out_FontMaxWidth(nd)
                  + Out_LeftMargin(nd) + Out_RightMargin(nd);
#endif
      }

      redraw = True;
    }

    if ( XtBackground(old) != XtBackground(new_w) )
    {
      if (Out_DrawGC(nd)) {
          XGCValues     values;

          values.background =  XtBackground(new_w);
          XChangeGC(XtDisplay(new_w), Out_DrawGC(nd), GCBackground, &values );
      }
    }

    if ( Prim_Foreground(old) != Prim_Foreground(new_w) )
    {
      if (Out_DrawGC(nd)) {
          XGCValues     values;

          values.foreground =  Prim_Foreground(new_w);
          XChangeGC(XtDisplay(new_w), Out_DrawGC(nd), GCForeground, &values );
      }
    }

    if (Out_BlinkRate(od) != Out_BlinkRate(nd))
    {
      /* FIX ME */
    }

    if (Out_ResizeHeight(od) != Out_ResizeHeight(nd))
    {
      /* FIX ME */
    }

    if (Out_ResizeWidth(od) != Out_ResizeWidth(nd))
    {
      /* FIX ME */
    }

    if (Out_ScrollHorizontal(od) != Out_ScrollHorizontal(nd))
    {
      /* FIX ME */
    }

    if (Out_ScrollVertical(od) != Out_ScrollVertical(nd))
    {
      /* FIX ME */
    }

    if (Out_ScrollLeftSide(od) != Out_ScrollLeftSide(nd))
    {
      /* FIX ME */
    }

    if (Out_ScrollTopSide(od) != Out_ScrollTopSide(nd))
    {
      /* FIX ME */
    }

    /* Done, restore old stuff */
    Text_Output(old) = Text_Output(new_w);
    Text_OutputData(old) = nd;

    return redraw;
}


static void
destroy(Widget aw)
{
    XmTextWidget w = (XmTextWidget)aw;
    OutputData o = Text_OutputData(w);

    DEBUGOUT(_LtDebug(__FILE__, aw, "destroy\n"));

    if (o && Out_TimerId(o))
    {
      XtRemoveTimeOut(Out_TimerId(o));
      Out_TimerId(o) = 0;
    }

    if (o && Out_DrawGC(o))
    {
#ifdef      USE_XT_GC
      XtReleaseGC(aw, Out_DrawGC(o));
#else
      XFreeGC(XtDisplay(w), Out_DrawGC(o));
#endif
    }
    if (o && Out_CursorGC(o))
    {
#ifdef      USE_XT_GC
      XtReleaseGC(aw, Out_CursorGC(o));
#else
      XFreeGC(XtDisplay(w), Out_CursorGC(o));
#endif
    }
    if (o && Out_CopyGC(o))
    {
      XtReleaseGC((Widget)w, Out_CopyGC(o));
    }

    if (Out_CursorIBeam(o))
    {
      XFreePixmap(XtDisplay((Widget)w), Out_CursorIBeam(o));
    }
    if (Out_CursorStipple(o))
    {
      XFreePixmap(XtDisplay((Widget)w), Out_CursorStipple(o));
    }
    if (Out_CursorSave(o))
    {
      XFreePixmap(XtDisplay((Widget)w), Out_CursorSave(o));
    }

    if (Out_FontListCreated(o) && Out_FontList(o))
    {
      XmFontListFree(Out_FontList(o));
    }
#ifdef      USE_XFT
      /* FIX ME */
#endif

    XtFree((char *)Text_Output(w));
}


static void
OutputExpose(Widget aw, XEvent *event, Region region)
{
      XmTextWidget w = (XmTextWidget)aw;

      DEBUGOUT(_LtDebug(__FILE__, aw, "OutputExpose: cursor pos: %d\n",
            Text_CursorPos(w)));

      if (!XtIsRealized(aw)) {
            return;
      }

/*
    XClearArea(XtDisplay(w), XtWindow(w),
             Prim_HighlightThickness(w) + Prim_ShadowThickness(w),
             Prim_HighlightThickness(w) + Prim_ShadowThickness(w),
             XtWidth(w) -
             2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)),
             XtHeight(w) -
             2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)),
             False);
*/

    DrawAll(w);

    if (Prim_Highlighted(aw))
    {
      (*PrimC_BorderHighlight(XtClass(aw))) (aw);
    }
    else
    {
      (*PrimC_BorderUnhighlight(XtClass(aw))) (aw);
    }

    _XmDrawShadows(XtDisplay(w),
               XtWindow(w),
               Prim_TopShadowGC(w),
               Prim_BottomShadowGC(w),
               Prim_HighlightThickness(w), Prim_HighlightThickness(w),
               XtWidth(w) - 2 * Prim_HighlightThickness(w),
               XtHeight(w) - 2 * Prim_HighlightThickness(w),
               Prim_ShadowThickness(w),
               XmSHADOW_IN);

    (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on);
}


static void
OutputRealize(Widget aw, XtValueMask *value_mask, XSetWindowAttributes *attributes)
{
      XmTextWidget w = (XmTextWidget)aw;

      DEBUGOUT(_LtDebug(__FILE__, aw, "OutputRealize (fl %p)\n",
            Out_FontList(Text_OutputData(aw))));

      GCInitialize(w);
      GCClip(w);

      CursorSet(w, False);

#if 0
      CursorSaveUnderIBeam(w, 0, 0);
#endif
}


static void
resize(Widget aw, Boolean state)
{
      XmTextWidget w = (XmTextWidget)aw;
      OutputData o = Text_OutputData(w);

      SizeRecalc(w);

      /* SG (15/08/1998) Update scrollbars immediately on resize
       * to give the correct visual feedback to the user and keep
       * scroll bars in sync with any keyboard actions after this resize */

      _XmChangeVSB(w, Text_TopPos(w));
        _XmRedisplayHBar(w, Out_XOffset(o));

      /* Only adjust the GCs if they have already been created! */
      if (Out_DrawGC(o)) {
            GCClip(w);
      }
}


static OutputRec outputRec =
{
    /* _OutputDataRec            */ NULL,
    /* XYToPosProc               */ XYToPos,
    /* PosToXYProc               */ PosToXY,
    /* MeasureLineProc           */ MeasureLine,
    /* DrawProc                  */ Draw,
    /* DrawInsertionPointProc    */ DrawInsertionPoint,
    /* MakePositionVisibleProc   */ MakePositionVisible,
    /* MoveLinesProc             */ MoveLines,
    /* InvalidateProc            */ OutputInvalidate,
    /* GetPreferredSizeProc      */ GetPreferredSize,
    /* GetValuesProc             */ OutputGetValues,
    /* SetValuesProc             */ OutputSetValues,
    /* XmRealizeOutProc          */ OutputRealize,
    /* XtWidgetProc              */ destroy,
    /* XmResizeFlagProc          */ resize,
    /* XtExposeProc              */ OutputExpose
};


extern void
_XmTextOutputCreate(Widget aw, ArgList args, Cardinal num_args)
{
    XmTextWidget w = (XmTextWidget)aw;
    OutputData o;
    XmTextInnerWidget iw = (XmTextInnerWidget)w->text.inner_widget;
    Dimension width, height;

    DEBUGOUT(_LtDebug(__FILE__, aw, "_XmTextOutputCreate("));
    DEBUGOUT(_LtDebugPrintArgList(__FILE__, aw, args, num_args, False));
    DEBUGOUT(_LtDebug0(__FILE__, aw, ")\n"));

    Text_Output(w) = (Output)XtMalloc(sizeof(OutputRec));
    memcpy(Text_Output(w), &outputRec, sizeof(OutputRec));

    Text_OutputData(w) = o = &iw->inner.out;
    XtGetSubresources(aw, iw,
                  aw->core.name,
                  aw->core.widget_class->core_class.class_name,
                  output_resources,
                  XtNumber(output_resources),
                  args, num_args);

    Out_XOffset(o) = 0;

    /*CP: debugging */
    XtAddEventHandler(aw, FocusChangeMask, False, HandleFocusEvents, NULL);

    CursorInit(w);

    /* Use DrawGC as a flag to see if the GCs have been created */
    Out_DrawGC(o) = NULL;
    Out_RightMargin(o) = Out_LeftMargin(o) = Prim_ShadowThickness(w) + Prim_HighlightThickness(w)
            + Text_MarginWidth(w) ;
    Out_TopMargin(o) = Out_BottomMargin(o) = Prim_ShadowThickness(w) + Prim_HighlightThickness(w)
            + Text_MarginHeight(w) ;


    Out_CursorWidth(o) = 5; /*CP: M*tif seems to use 5, but why ?? */

    /* Get the font information */
    if ( !Out_FontList(o) || (Out_FontList(o) == (XmFontList)XmUNSPECIFIED) )
    {
      Out_FontList(o) = _XmGetDefaultFontList((Widget)w, XmTEXT_FONTLIST);
      /* T. Straumann: changed this to 'true'; XmGetDefaultFontList() seems
       *                       to make a copy.
       */
      Out_FontListCreated(o) = True;
    }
    else
    {
      /* Out_FontListCreated(o) = True; */
      Out_FontListCreated(o) = False;
      /* we created this, so free it when the time comes */
      /* rws 12 Apr 1999
         If we created this, where???? A True value here is causing ml to
         segfault in FontListFree whenever the message window is destroyed.
       */
    }

    FontInit(w);

    DEBUGOUT(_LtDebug(__FILE__, aw,
                  "OutputCreate (initially) : rows %d cols %d\n",
                  Out_Rows(o), Out_Columns(o)));

    /* Check window dimensions */
    if (XtWidth(w) == (Dimension)0)
    {
      if (Out_Columns(o) <= 0)
      {
          Out_Columns(o) = 20;
      }
    }
    else
    {
      /* Reverse of this thing also copied into OutputSetValues */
#ifdef      USE_XFT
      if (Out_XftFont(o)) {
            Out_Columns(o) = (XtWidth(w) -
                  (Out_LeftMargin(o) + Out_RightMargin(o)))
                  / Out_XftFont(o)->max_advance_width;
            Out_Columns(o) = (XtWidth(w) -
                  (Out_LeftMargin(o) + Out_RightMargin(o)))
                  / Out_FontAverageWidth(o);    /* FIX ME HACK */
      } else
#endif
      {
#ifdef USE_AVERAGE_WIDTH
      Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) )
            ) / Out_FontAverageWidth(o);
#else
      Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) )
            ) / Out_FontMaxWidth(o);
#endif
      }
    }

    if (XtHeight(w) == (Dimension)0)
    {
      if (Out_Rows(o) <= 0)
      {
          Out_Rows(o) = 10;
      }
    }
    else
    {
      Out_Rows(o) = (XtHeight(w) - ( Out_TopMargin(o) + Out_BottomMargin(o) )
            ) / Out_FontHeight(o);
    }

    if (Text_EditMode(w) == XmSINGLE_LINE_EDIT)
    {
      Out_Rows(o) = 1;
      if (XtHeight(w) != 0 &&
          (XtHeight(w) < Out_FontHeight(o)
            + Out_TopMargin(o) + Out_BottomMargin(o) ) )
      {
          /* Statement below also copied into OutputSetValues */
          XtHeight(w) = Out_FontHeight(o)
            + Out_TopMargin(o) + Out_BottomMargin(o);
      }
    }

    DEBUGOUT(_LtDebug(__FILE__, aw,
                  "OutputCreate: rows %d cols %d\n",
                  Out_Rows(o), Out_Columns(o)));
    Out_ColumnsSet(o) = Out_Columns(o);
    Out_RowsSet(o) = Out_Rows(o);

    if (XtWidth(w) == 0 || XtHeight(w) == 0) {
      (*Text_Output(w)->GetPreferredSize) (aw, &width, &height);
      XtWidth(w) = width;
      XtHeight(w) = height;
    }

    SizeRecalc(w);

    /* Create scrollbars if child of scrolledwindow */

    if (XmIsScrolledWindow(XtParent(w)))
    {
      Widget sw = XtParent(w);
      Boolean scrollingPolicy;

      XtVaGetValues(sw, XmNscrollingPolicy, &scrollingPolicy, NULL);

      if (scrollingPolicy == XmAUTOMATIC)
      {
          Out_ScrollVertical(o) = False;
          Out_ScrollHorizontal(o) = False;
      }

      if (Out_ScrollHorizontal(o))
      {

          if (SW_HSB(sw) != NULL)
          {
            Out_Hbar(o) = (Widget)SW_HSB(sw);
          }
          else
          {
            Out_Hbar(o) = XtVaCreateWidget("HorScrollBar",
                                     xmScrollBarWidgetClass,
                                     sw,
                                     XmNorientation, XmHORIZONTAL,
                                     NULL);
          }


          XtAddCallback((Widget)Out_Hbar(o), XmNdecrementCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNdragCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNincrementCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNpageDecrementCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNpageIncrementCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNtoBottomCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNtoTopCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Hbar(o), XmNvalueChangedCallback,
                    HandleHBar,
                    (XtPointer)w);
          XtManageChild(Out_Hbar(o));

          /*CP:Friday 14 May 1999: Set HBar resources to initially sane values */
          XtVaSetValues(Out_Hbar(o),
                    XmNincrement, 1,
                    XmNpageIncrement, 1,
                    XmNsliderSize, 1,
                    XmNmaximum, 1, 
                    XmNminimum, 0,
                    NULL);
      }
      else
      {
          Out_Hbar(o) = NULL;
      }

      if (Out_ScrollVertical(o) && Text_EditMode(w) != XmSINGLE_LINE_EDIT)
      {
          if (SW_VSB(sw) != NULL)
          {
            Out_Vbar(o) = (Widget)SW_VSB(sw);
          }
          else
          {
            Out_Vbar(o) = XtVaCreateWidget("VertScrollBar",
                                     xmScrollBarWidgetClass,
                                     sw,
                                     NULL);
          }

          XtAddCallback((Widget)Out_Vbar(o), XmNdecrementCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNdragCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNincrementCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNpageDecrementCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNpageIncrementCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNtoBottomCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNtoTopCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtAddCallback((Widget)Out_Vbar(o), XmNvalueChangedCallback,
                    HandleVBar,
                    (XtPointer)w);
          XtManageChild(Out_Vbar(o));

          /* Set VSB resources to initially sane values */
          XtVaSetValues(Out_Vbar(o),
                    XmNincrement, 1,
                    XmNpageIncrement, Out_Rows(o),
                    XmNsliderSize, Out_Rows(o),
                    XmNmaximum, Out_Rows(o), /*CP:Friday 14 May 1999 a reasonable initial value */
                    NULL);
      }
      else
      {
          Out_Vbar(o) = NULL;
      }

      XmScrolledWindowSetAreas(sw, Out_Hbar(o), Out_Vbar(o), aw);

      if (Out_ScrollLeftSide(o) && Out_ScrollTopSide(o))
      {
          XtVaSetValues(sw,
                    XmNscrollBarPlacement, XmTOP_LEFT,
                    NULL);
      }
      else if (!Out_ScrollLeftSide(o) && Out_ScrollTopSide(o))
      {
          XtVaSetValues(sw,
                    XmNscrollBarPlacement, XmTOP_RIGHT,
                    NULL);
      }
      else if (Out_ScrollLeftSide(o) && !Out_ScrollTopSide(o))
      {
          XtVaSetValues(sw,
                    XmNscrollBarPlacement, XmBOTTOM_LEFT,
                    NULL);
      }
      else if (!Out_ScrollLeftSide(o) && !Out_ScrollTopSide(o))
      {
          XtVaSetValues(sw,
                    XmNscrollBarPlacement, XmBOTTOM_RIGHT,
                    NULL);
      }
    }

}



/*
 * Quasi-Public functions -----------------------------------------------------
 */


extern void
_XmTextDrawDestination(XmTextWidget widget)
{
}


extern void
_XmTextClearDestination(XmTextWidget widget, Boolean ignore_sens)
{
}


extern void
_XmTextDestinationVisible(Widget w, Boolean turn_on)
{
}


extern void
_XmTextChangeBlinkBehavior(XmTextWidget widget, Boolean newvalue)
{
}


extern void
_XmTextAdjustGC(XmTextWidget w)
{
}


extern Boolean
_XmTextShouldWordWrap(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);

    if (! Out_WordWrap(o) )
    {
      return False;
    }
    if (Text_EditMode(w) == XmSINGLE_LINE_EDIT)
    {
      return False;
    }
    if ( Out_ScrollHorizontal(o) &&
      XtClass(XtParent(w)) == xmScrolledWindowWidgetClass)
    {
      return False;
    }
    if ( Out_ResizeWidth(o) )
    {
      return False;
    }

    return True;
}


extern Boolean
_XmTextScrollable(XmTextWidget w)
{
    OutputData o = Text_OutputData(w);

    return o->scrollvertical;
}


extern void
_XmTextOutputGetSecResData(XmSecondaryResourceData *secResDataRtn)
{
}


extern int
_XmTextGetNumberLines(XmTextWidget w)
{
    return w->text.total_lines - 1;
}


extern Boolean
_XmTextGetDisplayRect(Widget w, XRectangle *display_rect)
{
    return False;
}


extern void
_XmTextMarginsProc(Widget w, XmBaselineMargins *margins_rec)
{
}


extern void
_XmTextChangeHOffset(XmTextWidget widget, int length)
{
}


extern void
_XmTextToggleCursorGC(Widget widget)
{
}


extern void
_XmTextFreeContextData(Widget w, XtPointer clientData, XtPointer callData)
{
}


extern void
_XmTextResetClipOrigin(XmTextWidget tw, XmTextPosition position,
                   Boolean clip_mask_reset)
{
}


/*
 * Return the position of the end of this line, to implement wrapping.
 * FIX ME (currently quite simplistic)
 * FIX ME (should "extra" be filled up ?)
 */
XmTextPosition
_XmTextFindLineEnd(XmTextWidget w, XmTextPosition pos, LineTableExtra *extra)
{
    Dimension avail, width, oldwidth;
    XmTextPosition wordend, last, end;
    OutputData o = Text_OutputData(w);

    avail = XtWidth(w) - (Out_RightMargin(o) + Out_LeftMargin(o));

    /* What's our line ? */
    end = (*Text_Source(w)->Scan) (Text_Source(w), pos,
                           XmSELECT_LINE, XmsdRight, 1, False);

    /* Do we need to spend time on this; the line may be short enough */
    width = FontTextWidth(w, pos, end);
    if (width < avail)
    {
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "_XmTextFindLineEnd(%d) => %d [avail %d width %d]\n",
                    pos, end, avail, width));

      return end;
    }

    /* Unfortunately, we need to investigate */
    wordend = pos;
    do
    {
      last = wordend;
      wordend = (*Text_Source(w)->Scan) (Text_Source(w), last + 1,
                                 XmSELECT_WORD,
                                 XmsdRight, 1, False);
      oldwidth = width;
      width = FontTextWidth(w, pos, wordend);
    }
    while (width <= avail && wordend < end);

    if (last == pos){
      int i;
      /* In this case, we need to clip at non_word_boundary. */
      width = 0;
      for(i=pos+1; i<end; i++){
          oldwidth = width;
          width = FontTextWidth(w, pos, i);
          if (width >= avail){
            last = i - 1;
            break;
          }
          last = i;
      }
    }

    width = oldwidth;

    if (extra)
    {
      LineTableExtra e = (LineTableExtra)XtMalloc(sizeof(LineTableExtraRec));
      e->width = width;
      e->wrappedbychar = False;

      *extra = e;
    }

    /* Take the previous position */
    if (last < end)
    {
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "_XmTextFindLineEnd(%d) => %d [avail %d width %d]\n",
                    pos, last, avail, width));

      return last;
    }
    else
    {
      DEBUGOUT(_LtDebug(__FILE__, (Widget)w,
                    "_XmTextFindLineEnd(%d) => %d [avail %d width %d]\n",
                    pos, PASTENDPOS, avail, width));

      return PASTENDPOS;
    }
}


extern void
_XmTextMovingCursorPosition(XmTextWidget tw, XmTextPosition position)
{
      XmTextShowPosition((Widget)tw, position);
}


extern Boolean
_XmTextGetBaselines(Widget widget, Dimension **baselines, int *line_count)
{
    return False;
}


/* XTextWidth clone for TextFieldWidget. */
extern int
_XmOut_FontTextWidth(OutputData o, char *s, int l)
{
      if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) {
            return XTextWidth(Out_Font(o), s, l);
#ifdef      USE_XFT
      } else if (Out_XftFont(o)) {
            XGlyphInfo  ext;
            XftTextExtents8(Out_FontList(o)->renditions[0]->dpy,
                  Out_XftFont(o), s, l, &ext);

            return ext.width;
#endif
      } else {
            return XmbTextEscapement((XFontSet)Out_FontList(o)->renditions[0]->font, s, l);
      }

}


/* Calculate FontMaxWidth from fontList */
extern int
_XmOut_FontMaxWidth(OutputData o)
{
      if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) {
            return Out_Font(o)->max_bounds.width;
      } else
#ifdef      USE_XFT
      if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_XFT) {
            return Out_FontAverageWidth(o);     /* FIX ME HACK */
            return Out_XftFont(o)->max_advance_width;
      } else
#endif
      {
            XFontStruct **fsl;
            char **nl;
            int i, num, max;

            num = XFontsOfFontSet((XFontSet)Out_FontList(o)->renditions[0]->font, &fsl, &nl);
            max = 0;
            for(i=0; i<num; i++){
                  if (fsl[i]->max_bounds.width  > max)
                        max = fsl[i]->max_bounds.width;
            }
            return max;
      }
}

static void
_XmTextOutSetRenderTable(Widget w, int ofs, XrmValue *v)
{
      OutputData o = Text_OutputData(w);

      DEBUGOUT(_LtDebug(__FILE__, w, "_XmTextOutSetRenderTable (%d)\n",
            o->check_set_render_table));

      if (o->check_set_render_table) {
            /*
             * This is the second time we're getting called.
             * Therefore the result is undefined.
             */
            v->addr = NULL;   /* FIX ME or should we pass nothing ? */
      } else {
            v->addr = (char *)&(o->fontlist);
            o->check_set_render_table = True;
            DEBUGOUT(_LtDebug(__FILE__, w, "_XmTextOutSetRenderTable rt %p\n",
                  o->fontlist));
      }
}

Generated by  Doxygen 1.6.0   Back to index