/*
 *	This program is Copyright (C) 1987 by the Board of Trustees of the
 *	University of Illinois, and by the author Dirk Grunwald.
 */
  
#include <X11/Xos.h>  
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include "dvi-simple.h"
#include "mio.h"
#include "conv.h"
#include <assert.h>

#include "DviPageP.h"
  
  static XtResource resources[] = {

#define offset(field) XtOffset(DviPageWidget, field)

    /* {name, class, type, size, offset, default_type, default_addr}, */

    {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel),
       offset(dviPage.background), XtRString, "XtDefaultBackground"},

    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
       offset(dviPage.foreground), XtRString, "XtDefaultForeground"},

    {XtNfont,  XtCFont, XtRFontStruct, sizeof(XFontStruct *),
       offset(dviPage.font), XtRString, "XtDefaultFont"},

    {XtNpage,  XtCPage, XtRPointer, sizeof(char *),
       offset(dviPage.page), XtRPointer, 0},

    {XtNpai,  XtCPai, XtRPointer, sizeof(struct PostAmbleInfo *),
       offset(dviPage.pai), XtRPointer, 0 },

    {XtNdviFonts,  XtCDviFonts, XtRPointer, sizeof(DviFontInfo *),
       offset(dviPage.dviFonts), XtRPointer, 0 },

    {XtNxFonts,  XtCXFonts, XtRPointer, sizeof(XFontStruct **),
       offset(dviPage.xFonts), XtRPointer, 0 },

    {XtNuserMag,  XtCUserMag, XtRInt, sizeof(int),
       offset(dviPage.userMag), XtRString, "500"},

    {XtNdpi,  XtCDpi, XtRInt, sizeof(int),
       offset(dviPage.dpi), XtRString, "300"},

    {XtNreverseVideo,  XtCReverseVideo, XtRBool, sizeof(Bool),
       offset(dviPage.reverseVideo), XtRString, "False"},

    {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
    	offset (dviPage.useBackingStore), XtRString, "default"},

    {XtNpaperWidth, XtCPaperWidth, XtRString, sizeof (char *),
    	offset (dviPage.paperWidthString), XtRString, "8.5"},

    {XtNpaperHeight, XtCPaperHeight, XtRString, sizeof (char *),
    	offset (dviPage.paperHeightString), XtRString, "11"}

#undef offset
  };

#ifdef __STDC__
  static void ClassInitialize();
  static void Initialize(), Destroy(), Redisplay();
  static void Realize();
  static Boolean SetValues( );
  static void SetPageSize( DviPageWidget, Dimension *width, Dimension *heigth);
  static XtGeometryResult QueryGeometry();

  extern double atof(char *);
#else
  static void ClassInitialize();
  static void Initialize(), Destroy(), Redisplay();
  static void Realize();
  static Boolean SetValues();
  static XtGeometryResult QueryGeometry();
  static XtGeometryResult QueryGeometry();

  extern double atof();
#endif

static void DviPageAction(/* Widget, XEvent*, String*, Cardinal* */);

static XtActionsRec actions[] =
{
  /* {name, procedure}, */
  {"dviPage",	DviPageAction},
};

static char translations[] =
  "<Key>:		dviPage()	\n\
";

DviPageClassRec dviPageClassRec = {
  { /* core fields */
    /* superclass		*/
    (WidgetClass) &widgetClassRec,
    /* class_name		*/	"DviPage",
    /* widget_size		*/	sizeof(DviPageRec),
    /* class_initialize		*/	ClassInitialize,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	Realize,
    /* actions			*/	actions,
    /* num_actions		*/	XtNumber(actions),
    /* resources		*/	resources,
    /* num_resources		*/	XtNumber(resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	Destroy,
    /* resize			*/	NULL,
    /* expose			*/	Redisplay,
    /* set_values		*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	translations,
    /* query_geometry		*/	QueryGeometry,
    /* display_accelerator	*/	XtInheritDisplayAccelerator,
    /* extension		*/	NULL
    },
      { /* dviPage fields */
	/* empty			*/	0
	}
};

WidgetClass dviPageWidgetClass = (WidgetClass)&dviPageClassRec;

/****************************************************************
 *
 * Class Procedures
 *
 ****************************************************************/

/* Sun cc complains about the following line, but I'll be damned if
   I know why. It's decld a static void above */

static void ClassInitialize()
{
  XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore,
		 NULL, 0 );
}

/****************************************************************
 *
 * Private Procedures
 *
 ****************************************************************/

static void DviPageAction(/* Widget, XEvent*, String*, Cardinal* */)
{
  fprintf(stderr,"EVENT\n");
}

void
SetPageSize(w, wd, ht)
DviPageWidget w;
Dimension *wd;
Dimension *ht;
{
  DviPagePart *pi = & (w -> dviPage);
  struct PostAmbleInfo *pai = pi -> pai;

  long bdr;

  if ( pai != 0 ) {
    int bdr;

    CSetConversion(&(pi -> Conversion),
		   pi -> dpi,
		   pi -> userMag,
		   pai -> pai_Numerator,
		   pai -> pai_Denominator,
		   pai -> pai_DVIMag);
  }
  else {
    long Numerator = 25400000;
    long Denominator = 473628272;

    CSetConversion(&(pi -> Conversion),
		   pi -> dpi,
		   pi -> userMag,
		   Numerator,
		   Denominator,
		   1000);
  }
    
  w -> dviPage.fastFromSpValue
    = (long) ( w -> dviPage.Conversion.c_tosp );

  w -> dviPage.pixelsPerInch
    = cfromSP(&(pi -> Conversion), SP_PER_INCH( POINTS_PER_INCH ));

  bdr = w -> dviPage.pixelsPerInch;

  w -> dviPage.texPicScale = pi -> userMag * bdr;
  
  w -> dviPage.pixelsWide = bdr * w -> dviPage.paperWidth;
  w -> dviPage.pixelsHigh = bdr * w -> dviPage.paperHeight;

  (*wd) = w -> dviPage.pixelsWide;
  (*ht) = w -> dviPage.pixelsHigh;
}

static void Initialize (request, new)
    Widget request, new;
{
  DviPageWidget want = (DviPageWidget) request;
  DviPageWidget w = (DviPageWidget) new;

  XFontStruct *f;
  int dir, as, ds;
  XCharStruct os;

  Dimension wd, ht;

  w -> dviPage.page = want -> dviPage.page;
  w -> dviPage.pai  = want -> dviPage.pai ;
  w -> dviPage.xFonts  = want -> dviPage.xFonts ;
  w -> dviPage.dviFonts  = want -> dviPage.dviFonts ;

  w -> dviPage.paperWidth = atof(want -> dviPage.paperWidthString);
  w -> dviPage.paperHeight = atof(want -> dviPage.paperHeightString);

  w -> dviPage.globalGC  = 0;

  w -> dviPage.dviStack  = 0;
  w -> dviPage.dviStackSize  = 0;
  w -> dviPage.pathLen  = 0;
  w -> dviPage.penSize = 1;
  w -> dviPage.whiten = False;
  w -> dviPage.shade = False;
  w -> dviPage.blacken = False;

  SetPageSize(w, &wd, &ht);

#define MaX(x,y) ((x) > (y) ) ? (x) : (y)

  w -> core.width = MaX(wd, want->core.width);
  w -> core.height = MaX(ht, want->core.height);

#undef MaX

}

static void Realize (gw, valueMask, attrs)
     Widget gw;
     XtValueMask *valueMask;
     XSetWindowAttributes *attrs;
{

  XWindowAttributes wAttributes;

  DviPageWidget	w = (DviPageWidget) gw;
  
  switch (w->dviPage.useBackingStore) {
  case Always:
  case NotUseful:
  case WhenMapped:
    *valueMask |=CWBackingStore;
    attrs->backing_store = w->dviPage.useBackingStore;
    break;
  }

  XtCreateWindow( w, InputOutput, (Visual *)CopyFromParent,
		 *valueMask, attrs);

  XGetWindowAttributes( XtDisplay(w), XtWindow(w), &wAttributes );

  
  w -> dviPage.haveBackingStore
    = ( wAttributes.save_under == Always)
      || (wAttributes.save_under == WhenMapped);

  w->dviPage.globalGC
    = XCreateGC( XtDisplay(w), XtWindow(w), 0, NULL);
}

static void Destroy (gw)
     Widget gw;
{
  DviPageWidget w = (DviPageWidget) gw;
  XtFree( w -> dviPage.dviStack );
  w -> dviPage.dviStack = 0;

  if ( w -> dviPage.globalGC ) {
    XFreeGC( XtDisplay(w), w -> dviPage.globalGC );
    w -> dviPage.globalGC = 0;
  }
}

static Boolean SetValues(current, request, new)
    DviPageWidget current, request, new;
{

  DviPagePart *pi = & (request -> dviPage);
  struct PostAmbleInfo *p = pi -> pai;

  new -> dviPage.page =
    (request -> dviPage.page)
      ? (request -> dviPage.page) : current -> dviPage.page ;

  new -> dviPage.xFonts = 
    (request -> dviPage.xFonts)
      ? (request -> dviPage.xFonts) : current -> dviPage.xFonts;;

  new -> dviPage.pai =
    (request -> dviPage.pai)
      ? (request -> dviPage.pai) : current -> dviPage.pai;

  if ( new -> dviPage.pai ) {

    int stackSize = new -> dviPage.pai -> pai_DVIStackSize;

    if (stackSize > new -> dviPage.dviStackSize ) {

      stackSize += 2;
      
      XtFree( new -> dviPage.dviStack );
      
      new -> dviPage.dviStack  = 0;
      new -> dviPage.dviStackSize = stackSize;
      
      if (stackSize > 0 ) {
	new -> dviPage.dviStack  = 
	  (LocalDviStack *) (malloc( stackSize * sizeof(LocalDviStack) ));
      }
    }
  }

  new -> dviPage.dviFonts =
    (request -> dviPage.dviFonts)
      ? (request -> dviPage.dviFonts) :  current -> dviPage.dviFonts;

  new -> dviPage.paperWidth = 
    (request -> dviPage.paperWidthString)
      ? atof(request -> dviPage.paperWidthString)
	: current -> dviPage.paperWidth;

  new -> dviPage.paperHeight = 
    (request -> dviPage.paperHeightString)
      ? atof(request -> dviPage.paperHeightString)
	: current -> dviPage.paperHeight;

  SetPageSize(new, &(new -> core.width), &(new -> core.height));

  return( True );	 /* resize */
}

static XtGeometryResult QueryGeometry(w, intended, preferred)
    Widget w;
    XtWidgetGeometry *intended, *preferred;
{
    register DviPageWidget lw = (DviPageWidget) w;
    Dimension wd, ht;

    SetPageSize((DviPageWidget) w, &wd, &ht);

    preferred -> request_mode = CWWidth | CWHeight;

    preferred -> width = wd ;
    preferred -> height =  ht ;

    if (  ((intended->request_mode & (CWWidth | CWHeight))
	   	== (CWWidth | CWHeight)) &&
	  intended->width == preferred->width &&
	  intended->height == preferred->height)
	return XtGeometryYes;
    else if (preferred->width == w->core.width &&
	     preferred->height == w->core.height)
	return XtGeometryNo;
    else
	return XtGeometryAlmost;
}

/*
 *	Some very DVI related things
 */

#define	ABS(X)	( (X) < 0 ? -(X) : (X) )

int
selectFont(w, ptr, index, font)
DviPageWidget w;
DviFontInfo **ptr;
int *index;
int font;
{
  if ( *ptr != 0 && (*ptr) -> paf.paf_DVIFontIndex == font ) {
    return 0;
  }
  else {
    int offset;
    DviFontInfo *fonts = w -> dviPage.dviFonts;

    *ptr = 0;
    for ( offset = 0; offset < RegisteredFonts; offset++ ) {
      if ( fonts[offset].paf.paf_DVIFontIndex == font ) {
	*ptr = &(fonts[offset]);
	*index = offset;
	break;
      }
    }
    
    if ( *ptr == 0 ) {
      error(0,0,"Can't find font %d", font);
      return 1;
    }
    else {
      return(0);
    }
  }
}

void DviDisplay(widget)
     DviPageWidget widget;
{
  int c;
  i32 p;
  int advance;
  int wuz;
  int spDrift;

  DviPagePart *page = &( widget -> dviPage); 

  struct PostAmbleInfo *pai = page -> pai;

  char *thisPage = page -> page;
  Conv *conv = &(page -> Conversion);

  DviFontInfo *dviCurrentFont = 0;
  int dviCurrentFontIndex = 0;

/* following are used to reduce the number of XDrawStrings we do */

#define MAX_DVI_STRING 64
  char dviString[ MAX_DVI_STRING ];
  int dviStringLength;
  int startHH, startVV;
  int endHH, endVV;

  LocalDviStack *dviStack = page -> dviStack;
  LocalDviStack *dviStackP;	/* current stack item */

  if ( pai == 0 || thisPage == 0 || dviStack == 0) {
    return;
  }

  assert( dviStack != 0 );

  dviStackP = dviStack;

  dviStringLength = 0;
  startHH = startVV = -1;
  endHH = endVV = -1;

  /* insure that first byte is a BOP mark */

  c = (*thisPage) & 0xff;
  if ( DVI_DT(c) != DT_BOP ) {
    error(0,0,"No BOP found");
    goto cleanup;
  }

  /* initialize spDrift to be a single pixel width */
  spDrift = ctoSP( conv, POINTS_PER_INCH / DviDpi );

  for(;;) {
    
    c = mGetByte(&thisPage);
    
    if (DVI_IsChar(c)) {

      advance = 1;

    doDviChar:
      if ( !advance
	  || ABS(endHH - (dviStackP -> h)) > spDrift
	  || ABS(endVV - (dviStackP -> v)) > spDrift
	  || dviStringLength >= MAX_DVI_STRING )
	{

	  if ( dviStringLength > 0 ) {
	    i32 atHH = fastFromSP(widget, startHH);
	    i32 atVV = fastFromSP(widget, startVV);
	    Bool doit = True;

	    if ( widget -> dviPage.haveBackingStore ) {
	      i32 width = fastFromSP(widget, endHH);
	      i32 height = fastFromSP(widget, endVV);
	      
	      doit =
		XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
			      width, height) != RectangleOut;
	    }

	    if (doit) {
	      XDrawString( XtDisplay( widget ), XtWindow( widget ),
			  page -> globalGC, atHH, atVV,
			  dviString, dviStringLength );
	    }
	  }
	  dviStringLength = 0;
	  startHH = dviStackP -> h;
	  startVV = dviStackP -> v ;
	}

      dviString[ dviStringLength++ ] = c; 

      if ( advance && dviCurrentFont && dviCurrentFont -> widths) {
	dviStackP -> h += (dviCurrentFont -> widths[ c ]) ;
      }

      endHH = dviStackP -> h;
      endVV = dviStackP -> v;

    } else {
      
      switch (DVI_OpLen(c)) {
	
      case DPL_NONE:
	break;
	
      case DPL_SGN1:
	p = mGetByte(&thisPage);
	p = Sign8(p);
	break;
	
      case DPL_SGN2:
	mGetWord(&thisPage, &p);
	p = Sign16(p);
	break;
	
      case DPL_SGN3:
	mGet3Byte(&thisPage, &p);
	p = Sign24(p);
	break;
	
      case DPL_SGN4:
	mGetLong(&thisPage, &p);
	break;
	
      case DPL_UNS1:
	p = UnSign8(mGetByte(&thisPage));
	break;
	
      case DPL_UNS2:
	mGetWord(&thisPage, &p);
	p = UnSign16(p);
	break;
	
      case DPL_UNS3:
	mGet3Byte(&thisPage, &p);
	p = UnSign24(p);
	break;
	
      default:
	panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
	goto cleanup;
	/* NOTREACHED */
      }
      
      switch (DVI_DT(c)) {
	
      case DT_SET:
	c = p;
	advance = 1;
	goto doDviChar;
	break;
	
      case DT_PUT:
	c = p;
	advance = 0;
	goto doDviChar;
	break;;
	
      case DT_SETRULE:
      case DT_PUTRULE:
	
	{
	  i32 cHH, cVV;
	  i32 rhh, rvv;

	  cHH = fastFromSP(widget, dviStackP -> h);
	  cVV = fastFromSP(widget, dviStackP -> v);
	  
	  mGetLong(&thisPage, &rvv);
	  mGetLong(&thisPage, &rhh);

	  if (DVI_DT(c) == DT_SETRULE) {
	    dviStackP -> h += rhh;
	  }
	  
	  rhh = CConvRule(conv, rhh);
	  rvv = CConvRule(conv, rvv);

	  XFillRectangle(XtDisplay(widget), XtWindow(widget),
			 page -> globalGC, cHH, cVV - rvv, rhh, rvv);

	}
	break;
	
      case DT_NOP:
	break;
	
      case DT_BOP:
	/*
	 *	Each beginning of page has 11 4-byte words telling us things
	 *	about the page. We ignore them.
	 */
	thisPage += (11 * 4);

	dviStackP = dviStack;

	dviStackP -> h = SP_PER_INCH( POINTS_PER_INCH );
	dviStackP -> v = SP_PER_INCH( POINTS_PER_INCH );
	startHH = dviStackP -> h;
	startVV = dviStackP -> v ;
	endHH = startHH;
	endVV = startVV;
	dviStackP -> w = 0;
	dviStackP -> x = 0;
	dviStackP -> y = 0;
	dviStackP -> z = 0;

	break;
	
      case DT_EOP:
	goto cleanup;
	/* NOTREACHED */
	
      case DT_PUSH:
	{
	  /* copy the old stack to the new one */

	  LocalDviStack *old = dviStackP;
	  dviStackP++;
	  *dviStackP = *old;
	}
	break;
	
      case DT_POP:
	/* just use the old stack */
	dviStackP--;
	break;
	
      case DT_W0:	/* there should be a way to make these pretty */
	p = dviStackP -> w;
	goto move_right;
	
      case DT_W:
	dviStackP -> w = p;
	goto move_right;
	
      case DT_X0:
	p = dviStackP -> x;
	goto move_right;
	
      case DT_X:
	dviStackP -> x = p;
	goto move_right;
	
      case DT_RIGHT:
      move_right:
	dviStackP -> h += p;
	break;
	
      case DT_Y0:
	p = dviStackP -> y;
	goto move_down;
	
      case DT_Y:
	dviStackP -> y = p;
	goto move_down;
	
      case DT_Z0:
	p = dviStackP -> z;
	goto move_down;
	
      case DT_Z:
	dviStackP -> z = p;
	goto move_down;
	
      case DT_DOWN:
      move_down:
	dviStackP -> v += p;
	break;
	
      case DT_FNTNUM:
      case DT_FNT:
	{
	  int font;

	  /* flush existing text */

	  if ( dviStringLength > 0 ) {
	    i32 atHH = fastFromSP(widget, startHH);
	    i32 atVV = fastFromSP(widget, startVV);
	    Bool doit = True;

	    if ( widget -> dviPage.haveBackingStore ) {
	      i32 width = fastFromSP(widget, endHH);
	      i32 height = fastFromSP(widget, endVV);
	      
	      doit =
		XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
			      width, height) != RectangleOut;
	    }

	    if (doit) {
	      XDrawString( XtDisplay( widget ), XtWindow( widget ),
			  page -> globalGC, atHH, atVV,
			  dviString, dviStringLength );
	    }
	    dviStringLength = 0;
	    startHH = dviStackP -> h;
	    startVV = dviStackP -> v ;
	  }

	  /* switch to new font */

	  font = ( DVI_DT(c) == DT_FNTNUM )
	    ? font = (c - DVI_FNTNUM0) : p;

	  if ( selectFont(widget,
			  &dviCurrentFont, &dviCurrentFontIndex, font) ) {
	    goto cleanup;
	  }
	  else {
	    /* load the font */
	    XSetFont( XtDisplay(widget), widget -> dviPage.globalGC,
		(widget -> dviPage.xFonts && widget -> dviPage.xFonts[ dviCurrentFontIndex ]) 
		? (widget->dviPage.xFonts[ dviCurrentFontIndex ]) -> fid
		: widget -> dviPage.font->fid ) ;
	  }
	}
	break;
	
      case DT_XXX:
	{
	  char specialBuffer [2048];
	  register char *cp;
	  int sweetp = 0;
	  
	  if (p > 2047) {
	    sweetp = p - 2047;
	    p = 2047;
	  }
	  
	  for (cp = specialBuffer ; p > 0; p--) {
	    *cp = mGetByte(&thisPage);
	    cp++;
	  }
	  *(cp) = 0;
	  
	  while(sweetp > 0) {
	    mGetByte(&thisPage);
	  }

	  widget -> dviPage.dviStackPointer = dviStackP;
	  doSpecial(widget, specialBuffer);
	}
	break;
	
      case DT_FNTDEF:
	{
	  int i;
	  long j;
	  mGetLong(&thisPage, &j);
	  mGetLong(&thisPage, &j);
	  mGetLong(&thisPage, &j);
	  i  = UnSign8(mGetByte(&thisPage));
	  i += UnSign8(mGetByte(&thisPage));
	  while (--i >= 0) {
	    (void) mGetByte(&thisPage);
	  }
	}
	break;
	
      case DT_PRE:
	GripeUnexpectedOp("PRE");
	goto cleanup;
	/* NOTREACHED */
	
      case DT_POST:
	GripeUnexpectedOp("POST");
	goto cleanup;
	/* NOTREACHED */
	
      case DT_POSTPOST:
	GripeUnexpectedOp("POSTPOST");
	goto cleanup;
	/* NOTREACHED */
	
      case DT_UNDEF:
	GripeUndefinedOp(c);
	goto cleanup;
	/* NOTREACHED */
	
      default:
	panic("DVI_DT(%d) = %d", c, DVI_DT(c));
	goto cleanup;
	/* NOTREACHED */
      }
    }
  }

 cleanup:
  /* clean up laststring if there was one */

  if ( dviStringLength > 0 ) {
    i32 atHH = fastFromSP(widget, startHH);
    i32 atVV = fastFromSP(widget, startVV);
    Bool doit = True;
    
    if ( widget -> dviPage.haveBackingStore ) {
      i32 width = fastFromSP(widget, endHH);
      i32 height = fastFromSP(widget, endVV);
      
      doit =
	XRectInRegion( widget -> dviPage.updateRegion, atHH, atVV,
		      width, height) != RectangleOut;
    }
    
    if (doit) {
      XDrawString( XtDisplay( widget ), XtWindow( widget ),
		  page -> globalGC, atHH, atVV,
		  dviString, dviStringLength );
    }
    dviStringLength = 0;
  }

  return;

}


/* ARGSUSED */
static void Redisplay (gw, event, region)
    Widget gw;
    XEvent *event;		/* unused */
    Region region;		/* unused */
{
  DviPageWidget w = (DviPageWidget) gw;

  if (XtIsRealized(w)) {

    XGCValues	values;
    unsigned long fore = w->dviPage.foreground;
    unsigned long aft = w->dviPage.background;
    
    if ( w -> dviPage.reverseVideo ) {
      unsigned long tmp = aft;
      aft = fore;
      fore = tmp;
    }
    
    /* Prepare to clear the main screen */
    
    values.function	= GXcopy;
    values.foreground	= aft;
    values.background	= fore;
    
    XChangeGC( XtDisplay(gw), w -> dviPage.globalGC,
	      (unsigned) GCFunction | GCForeground | GCBackground,
	      &values);

    XSetRegion( XtDisplay(w), w -> dviPage.globalGC, region );

    XFillRectangle(XtDisplay(w), XtWindow(w),
		   w -> dviPage.globalGC,
		   0, 0,
		   w -> core.width, w -> core.height);

    /* Prepare to paint */
    
    values.foreground	= fore;
    values.background	= aft;
    values.plane_mask	= AllPlanes;
    values.font		= w->dviPage.font->fid;
    
    if ( aft ) {
      values.function = GXand;
    }
    else {
      values.function = GXor;
    }
    
    XChangeGC( XtDisplay(gw), w -> dviPage.globalGC,
	      (unsigned) GCFunction | GCPlaneMask |
	      GCForeground | GCBackground | GCFont,
	      &values);

    XSetRegion( XtDisplay(w), w -> dviPage.globalGC, region );

    if (w -> dviPage.pai && w -> dviPage.page && w -> dviPage.dviFonts ) {

      w -> dviPage.updateRegion = region;

      DviDisplay(w);

    }
  }
}
