/* Filename: TtyText.c */
/* Author: Andy Lowry */
static char sccs_info[] = "@(#)TtyText.c	1.1 6/18/90";

#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "TtyTextP.h"
#include "TtySrc.h"

/* from Text.c */

extern void ForceBuildLineTable(); /* in Text.c */

/* from AsciiSink.c */
typedef struct _AsciiSinkData {
    Pixel foreground;
    GC normgc, invgc, xorgc;
    XFontStruct *font;
    int em;
    Pixmap insertCursorOn;
    XtTextInsertState laststate;
    int tab_count;
    Position *tabs;
} AsciiSinkData, *AsciiSinkPtr;

/* XXX foreground default should be XtDefaultFGPixel. How do i do that?? */

static XtResource SinkResources[] = {
    {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
        XtOffset(AsciiSinkPtr, font), XtRString, "Fixed"},
    {XtNforeground, XtCForeground, XtRPixel, sizeof (int),
        XtOffset(AsciiSinkPtr, foreground), XtRString, "Black"},    
};

/* end from AsciiSink.c */

Boolean sink_compiled = False;

/* from TtySrc.c */

typedef struct _TtySourceLine {
    char *text;
    int length, maxLength;
} TtySourceLine, *TtySourceLinePtr;

typedef struct _TtySourceData {
    TextWidget owner;
    TtySourceLinePtr lines;
    int lastLine, lookLine, lineCount, maxLines;
    XtTextPosition length, lastLinePos, lookPos;
    char *initText;
    int initLength;
    char *typein;
    Boolean accumulateTypein;
    XtTextPosition typeinLength, typeinMaxLength;
    XtTextPosition editBarrier;
    XtTextPosition left, right;		/* selection */
} TtySourceData, *TtySourcePtr;

static XtResource ttyResources[] = {
    {XtNstring, XtCString, XtRString, sizeof (char *),
        XtOffset(TtySourcePtr, initText), XtRString, NULL},
    {XtNlength, XtCLength, XtRInt, sizeof (int),
        XtOffset(TtySourcePtr, initLength), XtRInt, 0},
    {XtNmaxLines, XtCMaxLines, XtRInt, sizeof (int),
	XtOffset(TtySourcePtr, maxLines), XtRInt, 0},
};

/* end from TtySrc.c */

Boolean tty_compiled = False;

#define offset(field) XtOffset(TtyTextWidget, field)
static XtResource resources[] = {
    {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t), 
       offset(tty_text.callback), XtRCallback, (caddr_t)NULL},
};
#undef offset

static void TtyTextClassInitialize(), TtyTextInitialize(),
    TtyTextCreateSourceSink(), TtyTextDestroy(), TtyTextGetSubpartValues();
static Boolean TtyTextSetValues(), TtyTextSetSubpartValues();

TtyTextClassRec ttyTextClassRec = {
  { /* core fields */
    /* superclass       */      (WidgetClass) &textClassRec,
    /* class_name       */      "TtyText",
    /* widget_size      */      sizeof(TtyTextRec),
    /* class_initialize */      TtyTextClassInitialize,
    /* class_part_init  */	NULL,
    /* class_inited     */      FALSE,
    /* initialize       */      TtyTextInitialize,
    /* initialize_hook  */	TtyTextCreateSourceSink,
    /* realize          */      XtInheritRealize,
    /* actions          */      textActionsTable,
    /* num_actions      */      0,
    /* resources        */      resources,
    /* num_ resource    */      XtNumber(resources),
    /* xrm_class        */      NULLQUARK,
    /* compress_motion  */      TRUE,
    /* compress_exposure*/      FALSE,
    /* compress_enterleave*/	TRUE,
    /* visible_interest */      FALSE,
    /* destroy          */      TtyTextDestroy,
    /* resize           */      XtInheritResize,
    /* expose           */      XtInheritExpose,
    /* set_values       */      TtyTextSetValues,
    /* set_values_hook  */	TtyTextSetSubpartValues,
    /* set_values_almost*/	XtInheritSetValuesAlmost,
    /* get_values_hook  */	TtyTextGetSubpartValues,
    /* accept_focus     */      XtInheritAcceptFocus,
    /* version          */	XtVersion,
    /* callback_private */      NULL,
    /* tm_table         */      XtInheritTranslations,
    /* query_geometry	*/	XtInheritQueryGeometry
  },
  { /* text fields */
    /* empty            */      0
  },
  { /* tty_text fields */
    /* empty            */      0
  }
};

WidgetClass ttyTextWidgetClass = (WidgetClass)&ttyTextClassRec;


static void TtyTextClassInitialize()
{
    ttyTextClassRec.core_class.num_actions = textActionsTableCount;
}

/* ARGSUSED */
static void TtyTextInitialize(request, new)
    Widget request, new;
{
    /* superclass Initialize can't set the following,
     * as it didn't know the source or sink when it was called */
    if (request->core.height == DEFAULT_TEXT_HEIGHT)
	new->core.height = DEFAULT_TEXT_HEIGHT;
}

static void TtyTextCreateSourceSink(widget, args, num_args)
    Widget widget;
    ArgList args;
    Cardinal *num_args;
{
    TtyTextWidget w = (TtyTextWidget)widget;
    void (*NullProc)() = NULL;	/* some compilers require this */
    XtTextPosition lastPos;

    w->text.source = XtTtySourceCreate( widget, args, *num_args );
    w->text.sink = XtAsciiSinkCreate( widget, args, *num_args );

    if (w->core.height == DEFAULT_TEXT_HEIGHT)
        w->core.height = (2*yMargin) + 2
			  + (*w->text.sink->MaxHeight)(widget, 1);

    w->text.lastPos = /* GETLASTPOS */
      (*w->text.source->Scan) ( w->text.source, 0, XtstAll,
			        XtsdRight, 1, TRUE );


    if (w->text.sink->SetTabs != NullProc) {
#define TAB_COUNT 32
	int i;
	Position tabs[TAB_COUNT], tab;

	for (i=0, tab=0; i<TAB_COUNT;i++) {
	    tabs[i] = (tab += 8);
	}
	(w->text.sink->SetTabs) (widget, w->text.leftmargin, TAB_COUNT, tabs);
#undef TAB_COUNT
    }

    ForceBuildLineTable( (TextWidget)w );
    lastPos = (w->text.source->Scan)
      (w->text.source, 0, XtstAll, XtsdRight, 1, True);
    XtTextSetInsertionPoint(w, lastPos);
}

static void TtyTextGetSubpartValues(widget, args, num_args)
     Widget widget;
     ArgList args;
     Cardinal *num_args;
{
    TtyTextWidget w;
    AsciiSinkPtr sinkdata;
    TtySourcePtr srcdata;

    if (!sink_compiled) {
	XrmCompileResourceList(SinkResources, XtNumber(SinkResources));
	sink_compiled = True;
    }
    if (! tty_compiled) {
	XrmCompileResourceList(ttyResources, XtNumber(ttyResources));
	tty_compiled = True;
    }
    w = (TtyTextWidget) widget;
    sinkdata = (AsciiSinkPtr) w->text.sink->data;
    srcdata = (TtySourcePtr) w->text.source->data;
    XtGetSubvalues(sinkdata, SinkResources, XtNumber(SinkResources),
		   args, *num_args);
    XtGetSubvalues(srcdata, ttyResources, XtNumber(ttyResources),
		   args, *num_args);
}


/* setvalues routine is needed only so the hook will get called */
static Boolean TtyTextSetValues(current, request, new)
     Widget current, request, new;
{
    return(False);
}

/* There's a lot of hair in this routine because AsciiSink was not */
/* implemented very nicely! */
static Boolean TtyTextSetSubpartValues(widget, args, num_args)
     Widget widget;
     ArgList args;
     Cardinal *num_args;
{
    TtyTextWidget w;
    AsciiSinkPtr sinkdata;
    TtySourcePtr srcdata;
    Pixel oldfg;
    XFontStruct *oldfont;
    Boolean redisplay = False;
    Display *dpy;
    GC oldgc;
    XGCValues values;
    unsigned long valuemask = (GCFont | GCGraphicsExposures |
			       GCForeground | GCBackground | GCFunction);

    if (!sink_compiled) {
	XrmCompileResourceList(SinkResources, XtNumber(SinkResources));
	sink_compiled = True;
    }
    if (! tty_compiled) {
	XrmCompileResourceList(ttyResources, XtNumber(ttyResources));
	tty_compiled = True;
    }

    w = (TtyTextWidget) widget;
    sinkdata = (AsciiSinkPtr) w->text.sink->data;
    srcdata = (TtySourcePtr) w->text.source->data;

    oldfg = sinkdata->foreground;
    oldfont = sinkdata->font;
    XtSetSubvalues(sinkdata, SinkResources, XtNumber(SinkResources),
		   args, *num_args);
    if (oldfg != sinkdata->foreground || oldfont != sinkdata->font) {
	redisplay = True;
	w->text.sink->foreground = sinkdata->foreground;
	w->text.sink->font = sinkdata->font;
	/* fix all the graphics contexts */
	dpy = DisplayOfScreen(w->core.screen);
	oldgc = sinkdata->normgc;
	values = oldgc->values;
	XtReleaseGC(w, oldgc);
	values.font = sinkdata->font->fid;
	values.foreground = sinkdata->foreground;
	values.background = w->core.background_pixel;
	sinkdata->normgc = XtGetGC(w, valuemask, &values);
	oldgc = sinkdata->invgc;
	values = oldgc->values;
	XtReleaseGC(w, oldgc);
	values.font = sinkdata->font->fid;
	values.foreground = w->core.background_pixel;
	values.background = sinkdata->foreground;
	sinkdata->invgc = XtGetGC(w, valuemask, &values);
	oldgc = sinkdata->xorgc;
	values = oldgc->values;
	XtReleaseGC(w, oldgc);
	values.font = sinkdata->font->fid;
	values.foreground = sinkdata->foreground ^ w->core.background_pixel;
	sinkdata->xorgc = XtGetGC(w, valuemask, &values);
    }	  

    XtSetSubvalues(srcdata, ttyResources, XtNumber(ttyResources),
		   args, *num_args);

    return(redisplay);
}

static void TtyTextDestroy(w)
    Widget w;
{
    XtTtySourceDestroy( ((TtyTextWidget)w)->text.source );
    XtAsciiSinkDestroy( ((TtyTextWidget)w)->text.sink );
}


/* public functions */

/* Add text to the end of the source with typein accumulation disabled */
void TtyTextAddText(widget, text)
     Widget widget;
     XtTextBlock *text;
{
    Boolean orig, TtyAccumulateTypein();
    XtTextPosition lastPos;
    TtyTextWidget w;

    w = (TtyTextWidget) widget;
    orig = TtyAccumulateTypein(w->text.source, False);
    lastPos = (w->text.source->Scan)
      (w->text.source, 0, XtstAll, XtsdRight, 1, True);
    XtTextReplace(w, lastPos, lastPos, text);
    lastPos = (w->text.source->Scan)
      (w->text.source, 0, XtstAll, XtsdRight, 1, True);
    XtTextSetInsertionPoint(w, lastPos);
    TtyAccumulateTypein(w->text.source, orig);
}

/* These appear to be required because they're mentioned in Text.h!? */
XtTextSource XtStringSourceCreate()
{
}

void XtStringSourceDestroy()
{
}
