/* 
 * $Id: ogra2x11.c,v 1.7 2003/02/16 12:43:37 isizaka Exp isizaka $
 * 
 * This file is part of "Ngraph for X11".
 * 
 * Copyright (C) 2002, Satoshi ISHIZAKA. isizaka@msa.biglobe.ne.jp
 * 
 * "Ngraph for X11" is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * "Ngraph for X11" 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

/**
 *
 * $Log: ogra2x11.c,v $
 * Revision 1.7  2003/02/16 12:43:37  isizaka
 * for release 6.13.18
 *
 * Revision 1.6  2002/07/06 08:57:25  isizaka
 * change to GPL.
 *
 * Revision 1.5  2001/07/14 17:44:50  isizaka
 * for 6.03.14
 *
 * Revision 1.4  2001/03/23 12:17:43  isizaka
 * for 6.3.13
 *
 * Revision 1.3  1999/04/15 12:14:26  isizaka
 * for release 6.03.01
 *
 * Revision 1.2  1999/04/11 06:08:57  isizaka
 * *** empty log message ***
 *
 * Revision 1.1  1999/03/17 13:27:54  isizaka
 * Initial revision
 *
 *
 **/

#include <Xm/XmAll.h>
#include <Xm/XmP.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

#include "ngraph.h"
#include "object.h"
#include "ioutil.h"
#include "gra.h"
#include "nstring.h"
#include "jstring.h"
#include "mathfn.h"
#include "config.h"

#include "x11gui.h"
#include "ogra2x11.h"

#define NAME "gra2x11"
#define PARENT "gra2"
#define VERSION  "1.00.00"
#define GRA2X11CONF "[gra2x11]"
#define LINETOLIMIT 500

#define TRUE  1
#define FALSE 0

extern XtAppContext Application;
extern int OpenApplication();
extern Display *Disp;
extern char *AppName,*AppClass;
extern int OpenApplication();

#define ERRDISPLAY 100
#define ERRCMAP 101

#define ERRNUM 2

char *x11errorlist[ERRNUM]={
  "cannot open display.",
  "not enough color cell."
};

#define X11FONTCASH 20 /* must be greater than 1 */
#define X11COLORDEPTH 2

enum {NORMAL=0,BOLD,ITALIC,BOLDITALIC};

struct fontmap;

struct fontmap {
  char *fontalias;
  char *fontname;
  int type;
  int twobyte;
  struct fontmap *next;
};

struct fontlocal {
  char *fontalias;
  Font font;
  XFontStruct *fontstruct;
  int fontsize,fonttype,fontdir;
  int iso8859;
};

struct x11local {
  struct objlist *obj;
  char *inst;
  Widget toplevel,mainwin,View,HScroll,VScroll;
  Window win;
  char *title;
  int autoredraw;
  GC gc;
  unsigned int winwidth,winheight,windpi;
  Colormap cmap;
  int cdepth;
  double pixel_dot;
  int offsetx,offsety;
  int scrollx,scrolly;
  int vscroll,hscroll;
  int cpx,cpy;
  struct fontmap *fontmaproot;
  int loadfont;
  int loadfontf;
  char *fontalias;
  double fontsize,fontspace,fontcos,fontsin;
  struct fontlocal font[X11FONTCASH];
  XPoint points[LINETOLIMIT];
  int linetonum;
  int PaperWidth,PaperHeight;
  int backingstore;
  int minus_hyphen;
};

int x11loadconfig(struct objlist *obj,struct x11local *x11local)
{
  FILE *fp;
  char *tok,*str,*s2;
  char *f1,*f2,*f3,*f4;
  struct fontmap *fcur,*fnew;
  int val;
  char *endptr;
  int len;

  if ((fp=openconfig(GRA2X11CONF))==NULL) return 0;
  fcur=NULL;
  while ((tok=getconfig(fp,&str))!=NULL) {
    s2=str;
    if (strcmp(tok,"font_map")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      for (;(s2[0]!='\0') && (strchr(" \x09,",s2[0])!=NULL);s2++);
      f4=getitok2(&s2,&len,"");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL)) {
        if ((fnew=memalloc(sizeof(struct fontmap)))==NULL) {
          memfree(tok);
          memfree(f1);
          memfree(f2);
          memfree(f3);
          memfree(f4);
          closeconfig(fp);
          return 1;
        }
        if (fcur==NULL) x11local->fontmaproot=fnew;
        else fcur->next=fnew;
        fcur=fnew;
        fcur->next=NULL;
        fcur->fontalias=f1;
        if (strcmp(f2,"bold")==0) fcur->type=BOLD;
        else if (strcmp(f2,"italic")==0) fcur->type=ITALIC;
        else if (strcmp(f2,"bold_italic")==0) fcur->type=BOLDITALIC;
        else fcur->type=NORMAL;
        memfree(f2);
        val=strtol(f3,&endptr,10);
        fcur->twobyte=val;
        fcur->fontname=f4;
      } else {
        memfree(f1);
        memfree(f2);
        memfree(f3);
        memfree(f4);
      }
    } else if (strcmp(tok,"backing_store")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') x11local->backingstore=val;
      memfree(f1);
    } else if (strcmp(tok,"win_dpi")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') x11local->windpi=val;
      memfree(f1);
    } else if (strcmp(tok,"win_width")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') x11local->winwidth=val;
      memfree(f1);
    } else if (strcmp(tok,"win_height")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') x11local->winheight=val;
      memfree(f1);
    } else if (strcmp(tok,"color_depth")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') x11local->cdepth=val;
      memfree(f1);
    } else if (strcmp(tok,"auto_redraw")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') {
        if (val==0) x11local->autoredraw=FALSE;
        else x11local->autoredraw=TRUE;
      }
      memfree(f1);
    } else if (strcmp(tok,"minus_hyphen")==0) {
      f1=getitok2(&s2,&len," \x09,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') x11local->minus_hyphen=val;
      memfree(f1);
    }
    memfree(tok);
    memfree(str);
  }
  closeconfig(fp);
  return 0;
}

void x11MakeRuler(struct x11local *x11local);
int x11_evloop(struct objlist *obj,char *inst,char *rval,int argc,char **argv);
void x11_redraw(struct objlist *obj,void *inst,struct x11local *x11local)
{
  GRAredraw(obj,inst,FALSE,FALSE);
  x11flush(obj,inst,NULL,0,NULL);
}

void x11evpaint(Widget w,XtPointer client_data,XtPointer call_data)
{
  struct x11local *x11local;
  XmAnyCallbackStruct *dd;
  XExposeEvent *e;

  x11local=(struct x11local *)client_data;
  dd=(XmAnyCallbackStruct *)call_data;
  e=(XExposeEvent *)(dd->event);
  if (e->count!=0) return;
  if (!(x11local->autoredraw)) return;
  x11local->scrollx=x11local->hscroll;
  x11local->scrolly=x11local->vscroll;
  x11MakeRuler(x11local);
  x11_redraw(x11local->obj,x11local->inst,x11local);
}

void x11close(Widget w,XtPointer client_data,XtPointer call_data)
{
  char *inst;
  struct x11local *local;
  int i,id;
  struct objlist *obj;

  obj=chkobject("gra2x11");
  for (i=0;i<=chkobjlastinst(obj);i++) {
    inst=chkobjinst(obj,i);
    _getobj(obj,"_local",inst,&local);
    if (local->toplevel==w) {
      _getobj(obj,"id",inst,&id);
      delobj(obj,id);
      break;
    }
  }
}

void x11vscroll(Widget w,XtPointer client_data,XtPointer call_data)
{
  XmScrollBarCallbackStruct *dd;
  struct x11local *x11local;
  int dy;
  int x,y;
  unsigned int width,height,border,depth;
  Window root;
  GC gc;
  Window win;
  Display *disp;

  dd=(XmScrollBarCallbackStruct *)call_data;
  x11local=(struct x11local *)client_data;
  dy=dd->value-x11local->vscroll;
  if (dy!=0) {
    disp=Disp;
    win=x11local->win;
    gc=XCreateGC(disp,win,0,0);
    XGetGeometry(disp,win,&root,&x,&y,&width,&height,&border,&depth);
    XCopyArea(disp,win,win,gc,
              0,dy,width,height,0,0);
    XFreeGC(disp,gc);
    if (dy>0) XClearArea(disp,win,0,height-dy,width,dy,TRUE);
    else if (dy<0) XClearArea(disp,win,0,0,width,-dy,TRUE);
  }             
  x11local->vscroll=dd->value;
}

void x11hscroll(Widget w,XtPointer client_data,XtPointer call_data)
{
  XmScrollBarCallbackStruct *dd;
  struct x11local *x11local;
  int dx;
  int x,y;
  unsigned int width,height,border,depth;
  Window root;
  GC gc;
  Window win;
  Display *disp;

  dd=(XmScrollBarCallbackStruct *)call_data;
  x11local=(struct x11local *)client_data;
  dx=dd->value-x11local->hscroll;
  if (dx!=0) {
    disp=Disp;
    win=x11local->win;
    gc=XCreateGC(disp,win,0,0);
    XGetGeometry(disp,win,&root,&x,&y,&width,&height,&border,&depth);
    XCopyArea(disp,win,win,gc,
              dx,0,width,height,0,0);
    XFreeGC(disp,gc);
    if (dx>0) XClearArea(disp,win,width-dx,0,dx,height,TRUE);
    else if (dx<0) XClearArea(disp,win,0,0,-dx,height,TRUE);
  }             
  x11local->hscroll=dd->value;
}

void x11changedpi(struct x11local *x11local);

void x11evsize(Widget w,XtPointer client_data,XtPointer call_data)
{
  struct x11local *x11local;

  x11local=(struct x11local *)client_data;
  x11changedpi(x11local);
}

int x11init(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{  
  struct x11local *x11local;
  struct fontmap *fcur,*fdel;
  Window win;
  GC gc;
  int i,oid;
  struct objlist *robj;
  int idn;
  Arg al[20];
  Cardinal ac;
  Widget toplevel;
  Atom xa_wm_delete;
  XSetWindowAttributes attr;
  XEvent event;

  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  if ((x11local=memalloc(sizeof(struct x11local)))==NULL) return 1;
  x11local->obj=obj;
  x11local->inst=inst;
  x11local->toplevel=NULL;
  x11local->fontmaproot=NULL;
  x11local->title=NULL;
  if (_putobj(obj,"_local",inst,x11local)) goto errexit;
  if (_getobj(obj,"oid",inst,&oid)) goto errexit;
  x11local->PaperWidth=0;
  x11local->PaperHeight=0;
  x11local->winwidth=578;
  x11local->winheight=819;
  x11local->windpi=70;
  x11local->autoredraw=TRUE;
  x11local->cdepth=X11COLORDEPTH;
  x11local->backingstore=FALSE;
  x11local->minus_hyphen=TRUE;
  if (x11loadconfig(obj,x11local)) goto errexit;
  if (x11local->windpi<1) x11local->windpi=1;
  if (x11local->windpi>2540) x11local->windpi=2540;
  if (x11local->winwidth<1) x11local->winwidth=1;
  if (x11local->winwidth>10000) x11local->winwidth=10000;
  if (x11local->winheight<1) x11local->winheight=1;
  if (x11local->winheight>10000) x11local->winheight=10000;
  if (x11local->cdepth<2) x11local->cdepth=2;
  if (x11local->cdepth>8) x11local->cdepth=8;
  if (_putobj(obj,"dpi",inst,&(x11local->windpi))) goto errexit;
  if (_putobj(obj,"auto_redraw",inst,&(x11local->autoredraw))) goto errexit;

  if (!OpenApplication()) goto errexit;
  ac=0;
  XtSetArg(al[ac],XmNborderWidth,1);ac++;
  toplevel=XtAppCreateShell(AppName,AppClass,applicationShellWidgetClass,
                            Disp,al,ac);
  XtVaSetValues(toplevel,XmNdeleteResponse,XmDO_NOTHING,NULL);
  xa_wm_delete=XmInternAtom(Disp,"WM_DELETE_WINDOW",False);
  XmAddWMProtocolCallback(toplevel,xa_wm_delete,x11close,NULL);
  ac=0;
  XtSetArg(al[ac],XmNshowSeparator,False); ac++; 
  XtSetArg(al[ac],XmNscrollBarDisplayPolicy,XmSTATIC); ac++;
  XtSetArg(al[ac],XmNcommandWindowLocation,XmCOMMAND_ABOVE_WORKSPACE); ac++; 
  XtSetArg(al[ac],XmNheight,x11local->winheight); ac++;
  XtSetArg(al[ac],XmNwidth,x11local->winwidth); ac++;
  x11local->mainwin=XmCreateMainWindow(toplevel,"gra2x11",al,ac);
  XtManageChild(x11local->mainwin);
  ac=0;
  x11local->View=XmCreateDrawingArea(x11local->mainwin,"viewer",al,ac);
  XtManageChild(x11local->View); 
  ac=0;
  XtSetArg(al[ac],XmNorientation,XmHORIZONTAL); ac++;
  x11local->HScroll=XmCreateScrollBar(x11local->mainwin,NULL,al,ac);
  XtManageChild(x11local->HScroll);
  ac=0;
  XtSetArg(al[ac],XmNorientation,XmVERTICAL); ac++;
  x11local->VScroll=XmCreateScrollBar(x11local->mainwin,NULL,al,ac);
  XtManageChild(x11local->VScroll);
  XmMainWindowSetAreas(x11local->mainwin,NULL,NULL,
                       x11local->HScroll,x11local->VScroll,x11local->View); 

#ifdef PRIVATECOLOR
  x11local->cmap=XCreateColormap(Disp,RootWindow(Disp,0),
                                 DefaultVisual(Disp,0),AllocNone);
#else
  x11local->cmap=DefaultColormap(Disp,0);
#endif

  XtRealizeWidget(toplevel);
  XSetWindowColormap(Disp,XtWindow(toplevel),x11local->cmap);

  win=XtWindow(x11local->View);
  x11local->title=mkobjlist(obj,NULL,oid,NULL,TRUE);
  XtVaSetValues(toplevel,XmNtitle,x11local->title,NULL);
  if (x11local->backingstore) attr.backing_store=Always;
  else attr.backing_store=NotUseful;
  XChangeWindowAttributes(Disp,win,CWBackingStore,&attr);

  gc=XCreateGC(Disp,win,0,0);
  XSetForeground(Disp,gc,BlackPixel(Disp,0));
  XSetBackground(Disp,gc,WhitePixel(Disp,0));
  XSetFillStyle(Disp,gc,FillSolid);
  x11local->toplevel=toplevel;
  x11local->win=win;
  x11local->gc=gc;
  x11local->offsetx=0;
  x11local->offsety=0;
  x11local->cpx=0;
  x11local->cpy=0;
  x11local->pixel_dot=x11local->windpi/25.4/100;
  x11local->fontalias=NULL;
  for (i=0;i<X11FONTCASH;i++) (x11local->font[i]).fontalias=NULL;
  x11local->loadfont=0;
  x11local->loadfontf=-1;
  x11local->linetonum=0;

  XSync(Disp,FALSE);

  if (chkobjfield(obj,"_evloop")) goto errexit;
  else {
    if ((idn=getobjtblpos(obj,"_evloop",&robj))==-1) goto errexit;
  }
  registerevloop(chkobjectname(obj),"_evloop",robj,idn,inst,x11local);
  XtVaSetValues(x11local->HScroll,XmNincrement,10,XmNminimum,0,NULL);
  XtVaSetValues(x11local->VScroll,XmNincrement,10,XmNminimum,0,NULL);
  XtVaGetValues(x11local->HScroll,XmNvalue,&(x11local->hscroll),NULL);
  XtVaGetValues(x11local->VScroll,XmNvalue,&(x11local->vscroll),NULL);
  XtAddCallback(x11local->View,XmNresizeCallback,x11evsize,x11local);
  XtAddCallback(x11local->View,XmNexposeCallback,x11evpaint,x11local);
  XtAddCallback(x11local->HScroll,XmNvalueChangedCallback,x11hscroll,x11local);
  XtAddCallback(x11local->VScroll,XmNvalueChangedCallback,x11vscroll,x11local);
  x11changedpi(x11local);
  x11_evloop(obj,inst,NULL,argc,argv);
  return 0;

errexit:
  if (x11local->toplevel!=NULL) {
    XFreeGC(Disp,x11local->gc);
    XtUnrealizeWidget(x11local->toplevel); 
    XtDestroyWidget(x11local->toplevel); 
    while (XtAppPending(Application)) {
      XtAppNextEvent(Application,&event);
      XtDispatchEvent(&event);
    }
  }
  fcur=x11local->fontmaproot;
  while (fcur!=NULL) {
    fdel=fcur;
    fcur=fcur->next;
    memfree(fdel->fontalias);
    memfree(fdel->fontname);
    memfree(fdel);
  }
  memfree(x11local->title);
  memfree(x11local);
  return 1;
}

int x11done(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct x11local *x11local;
  struct fontmap *fcur,*fdel;
  struct objlist *robj;
  int i,idn;
  XEvent event;

  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  if (x11local->toplevel!=NULL) {
    XFreeGC(Disp,x11local->gc);
    XtUnrealizeWidget(x11local->toplevel);
    XtDestroyWidget(x11local->toplevel);
    while (XtAppPending(Application)) {
      XtAppNextEvent(Application,&event);
      XtDispatchEvent(&event);
    } 
    XFreeColormap(Disp,x11local->cmap); 
  }
  if ((idn=getobjtblpos(obj,"_evloop",&robj))!=-1)
    unregisterevloop(robj,idn,inst); 
  fcur=x11local->fontmaproot;
  while (fcur!=NULL) {
    fdel=fcur;
    fcur=fcur->next;
    memfree(fdel->fontalias);
    memfree(fdel->fontname);
    memfree(fdel);
  }
  memfree(x11local->title);
  memfree(x11local->fontalias);
  for (i=0;i<X11FONTCASH;i++) memfree((x11local->font[i]).fontalias);
  return 0;
}

int x11flush(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct x11local *x11local;

  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  if (x11local->linetonum!=0) {
    XDrawLines(Disp,x11local->win,x11local->gc,
               x11local->points,x11local->linetonum,CoordModeOrigin);
    x11local->linetonum=0;
  }
  XFlush(Disp);
  return 0;
}

int x11clear(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct x11local *x11local;

  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  if (x11local->linetonum!=0) {
    XDrawLines(Disp,x11local->win,x11local->gc,
               x11local->points,x11local->linetonum,CoordModeOrigin);
    x11local->linetonum=0;
  }
  XClearWindow(Disp,x11local->win);
  XFlush(Disp);
  x11local->PaperWidth=0;
  x11local->PaperHeight=0;
  x11changedpi(x11local);
  return 0;
}

int x11dpi(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct x11local *x11local;
  int dpi;

  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  dpi=abs(*(int *)argv[2]);
  if (dpi<1) dpi=1;
  if (dpi>2540) dpi=2540;
  x11local->windpi=dpi;
  x11local->pixel_dot=x11local->windpi/25.4/100;
  *(int *)argv[2]=dpi;
  XClearArea(Disp,x11local->win,0,0,0,0,TRUE);
  x11changedpi(x11local);
  return 0;
}

int x11autoredraw(struct objlist *obj,char *inst,char *rval,
                  int argc,char **argv)
{
  struct x11local *x11local;
  char *arg;

  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  arg=argv[1];
  x11local->autoredraw=abs(*(int *)argv[2]);
  return 0;
}

int x11storememory(struct objlist *obj,char *inst,char *rval,
                   int argc,char **argv)
{
  struct x11local *x11local;
  int a;
  XSetWindowAttributes attr;

  _getobj(obj,"_local",inst,&x11local);
  a=*(int *)argv[2];
  if (a!=x11local->backingstore) {
    x11local->backingstore=a;
    if (x11local->backingstore) attr.backing_store=Always;
    else attr.backing_store=NotUseful;
    XChangeWindowAttributes(Disp,x11local->win,CWBackingStore,&attr);
  }
  return 0;
}

int x11redraw(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct x11local *x11local;

  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  x11_redraw(obj,inst,x11local);
  return 0;
}

int x11_evloop(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  XEvent event;

  while (XtAppPending(Application)) {
    XtAppNextEvent(Application,&event);
    XtDispatchEvent(&event);
  }
  return 0;
}

int dot2pixel(struct x11local *x11local,int r)
{
  return nround(r*x11local->pixel_dot);
}

int dot2pixelx(struct x11local *x11local,int x)
{
  return nround(x*x11local->pixel_dot+x11local->offsetx-x11local->scrollx);
}

int dot2pixely(struct x11local *x11local,int y)
{
  return nround(y*x11local->pixel_dot+x11local->offsety-x11local->scrolly);
}

int pixel2dot(struct x11local *x11local,int r)
{
  return nround(r/x11local->pixel_dot);
}

int pixel2dotx(struct x11local *x11local,int x)
{
  return nround((x-x11local->offsetx)/x11local->pixel_dot);
}

int pixel2doty(struct x11local *x11local,int y)
{
  return nround((y-x11local->offsety)/x11local->pixel_dot);
}

void x11changedpi(struct x11local *x11local)
{
  int width,height;
  double ratex,ratey;
  int XPos,YPos,XRange,YRange,XSlider,YSlider;

  if ((x11local->PaperWidth==0) || (x11local->PaperHeight==0)) {
    XtVaSetValues(x11local->HScroll,XmNmaximum,100,XmNvalue,0,NULL);
    XtVaSetValues(x11local->VScroll,XmNmaximum,100,XmNvalue,0,NULL);
    return;
  }
  XtVaGetValues(x11local->HScroll,XmNvalue,&XPos,XmNmaximum,&XRange,
                           XmNsliderSize,&XSlider,NULL);
  XtVaGetValues(x11local->VScroll,XmNvalue,&YPos,XmNmaximum,&YRange,
                           XmNsliderSize,&YSlider,NULL);
  if (XPos<0) XPos=0;
  if (YPos<0) YPos=0;
  if (XPos>XRange) XPos=XRange;
  if (YPos>YRange) YPos=YRange;
  if (XRange==0) ratex=0;
  else ratex=XPos/(double )XRange;
  if (YRange==0) ratey=0;
  else ratey=YPos/(double )YRange;
  width=dot2pixel(x11local,x11local->PaperWidth);
  height=dot2pixel(x11local,x11local->PaperHeight);
  XPos=width*ratex;
  YPos=height*ratey;
  if (XPos>(XRange-XSlider)) XPos=XRange-XSlider;
  if (YPos>(YRange-YSlider)) YPos=YRange-YSlider;
  XtVaSetValues(x11local->HScroll,XmNmaximum,width,XmNvalue,XPos,NULL);
  XtVaSetValues(x11local->VScroll,XmNmaximum,height,XmNvalue,YPos,NULL); 
  x11local->hscroll=XPos;
  x11local->vscroll=YPos;
  x11local->scrollx=XPos;
  x11local->scrolly=YPos;
}

unsigned long x11RGB(struct x11local *x11local,int R,int G,int B)
{
  XColor col;

  R=R*x11local->cdepth/256;
  if (R>=x11local->cdepth) R=x11local->cdepth-1;
  else if (R<0) R=0;
  G=G*x11local->cdepth/256;
  if (G>=x11local->cdepth) G=x11local->cdepth-1;
  else if (G<0) G=0;
  B=B*x11local->cdepth/256;
  if (B>=x11local->cdepth) B=x11local->cdepth-1;
  else if (B<0) B=0;
  col.red=R*65535/(x11local->cdepth-1);
  col.green=G*65535/(x11local->cdepth-1);
  col.blue=B*65535/(x11local->cdepth-1);
  XAllocColor(Disp,x11local->cmap,&col);
  return col.pixel;
}

void x11MakeRuler(struct x11local *x11local)
{
  int Width,Height;
  unsigned long col1;
  Display *disp;
  Window win;
  GC gc;

  Width=x11local->PaperWidth;
  Height=x11local->PaperHeight;
  if ((Width==0) || (Height==0)) return;
  disp=Disp;
  win=x11local->win;
  gc=XCreateGC(Disp,x11local->win,0,0);
  XSetFunction(Disp,gc,GXxor);
  XSetLineAttributes(disp,gc,1,LineSolid,CapButt,JoinMiter);
  col1=WhitePixel(Disp,0) ^ x11RGB(x11local,127,127,127);
  XSetForeground(disp,gc,col1);
  XDrawRectangle(disp,win,gc,
                 dot2pixelx(x11local,0)-x11local->offsetx,
                 dot2pixely(x11local,0)-x11local->offsety,
                 dot2pixelx(x11local,Width)-dot2pixelx(x11local,0),
                 dot2pixely(x11local,Height)-dot2pixely(x11local,0));
  XSetFunction(Disp,gc,GXcopy);
  XFreeGC(Disp,gc);
}

int x11loadfont(Display *disp,GC gc,struct x11local *x11local,
               char *fontalias,int size,int dir,
               double fsin,double fcos,int top)
{
  int fontcashfind;
  int i;
  char *fsp;
  char *fontname,*fontname2,*fontname3=NULL;
  char **fname2,**fname3;
  struct fontlocal font;
  struct fontmap *fcur;
  char fontmatrix[256];
  int rcount2,rcount3;
  Font newfont;
  XFontStruct *newfontstruct;
  int store;
  int twobyte=FALSE,type;

  fontcashfind=-1;
  for (i=0;i<x11local->loadfont;i++) {
    if ((strcmp((x11local->font[i]).fontalias,fontalias)==0)
    && ((x11local->font[i]).fontsize==size)
    && ((x11local->font[i]).fontdir==dir)) {
      fontcashfind=i;
      break;
    }
  }
  if (fontcashfind!=-1) {
    if (top) {
      font=x11local->font[fontcashfind];
      for (i=fontcashfind-1;i>=0;i--) x11local->font[i+1]=x11local->font[i];
      x11local->font[0]=font;
      XSetFont(disp,gc,(x11local->font[0]).font);
      return 0;
    } else return fontcashfind;
  }

  fcur=x11local->fontmaproot;
  fontname=NULL;
  while (fcur!=NULL) {
    if (strcmp(fontalias,fcur->fontalias)==0) {
      fontname=fcur->fontname;
      type=fcur->type;
      twobyte=fcur->twobyte;
      break;
    }
    fcur=fcur->next;
  }        
  if ((fontname==NULL) || (fontname[0]!='-')) {
    return -1;
  }
  if (((fontname2=memalloc(strlen(fontname)+128))==NULL) 
  || ((fontname3=memalloc(strlen(fontname)+128))==NULL)) {
    memfree(fontname2);
    memfree(fontname3);
    return -1;
  }
  fsp=fontname;
  for (i=0;i<6;i++) fsp=strchr(fsp+1,'-');
  strncpy(fontname2,fontname,fsp-fontname+1);
  strncpy(fontname3,fontname,fsp-fontname+1);
  fontname2[fsp-fontname+1]='\0';
  fontname3[fsp-fontname+1]='\0';
  if ((type==ITALIC) || (type==BOLDITALIC)) {
    sprintf(fontmatrix,"[%.3e %.3e %.3e %.3e]",
            size*fcos,size*fsin,
           -size*fsin+size*fcos*0.36,size*fcos+size*fsin*0.36);
  } else {
    sprintf(fontmatrix,"[%.3e %.3e %.3e %.3e]",
            size*fcos,size*fsin,-size*fsin,size*fcos);
  }
  for (i=0;fontmatrix[i]!='\0';i++)
    if (fontmatrix[i]=='-') fontmatrix[i]='~';
  strcat(fontname2,fontmatrix);
  sprintf(fontmatrix,"%d",size);
  strcat(fontname3,fontmatrix);
  fsp=strchr(fsp+1,'-');
  strcat(fontname2,fsp);
  strcat(fontname3,fsp);
  fname2=XListFonts(disp,fontname2,1,&rcount2);
  if (!twobyte) fname3=XListFonts(disp,fontname3,1,&rcount3);
  else fname3=NULL;
  memfree(fontname2);
  memfree(fontname3);
  if ((fname2!=NULL) && (twobyte || (fname3!=NULL))) {
    newfont=XLoadFont(disp,fname2[0]);
    if (!twobyte) newfontstruct=XLoadQueryFont(disp,fname3[0]);
    else newfontstruct=NULL;
    if (x11local->loadfont==X11FONTCASH) {
      XUnloadFont(disp,(x11local->font[X11FONTCASH-1]).font);
      if (x11local->font[X11FONTCASH-1].fontstruct!=NULL)
        XFreeFont(disp,(x11local->font[X11FONTCASH-1]).fontstruct); 
      XFreeFont(disp,(x11local->font[X11FONTCASH-1]).fontstruct); 
      memfree((x11local->font[X11FONTCASH-1]).fontalias);
      (x11local->font[X11FONTCASH-1]).fontalias=NULL;
      x11local->loadfont--;
    }
    if (top) {
      for (i=x11local->loadfont-1;i>=0;i--) 
        x11local->font[i+1]=x11local->font[i];
      store=0;
    } else store=x11local->loadfont;
    (x11local->font[store]).fontalias=memalloc(strlen(fontalias)+1);
    if ((x11local->font[store]).fontalias==NULL) {
      if (fname2!=NULL) XFreeFontNames(fname2);
      if (fname3!=NULL) XFreeFontNames(fname3);
      return -1;
    }
    strcpy((x11local->font[store]).fontalias,fontalias);
    (x11local->font[store]).font=newfont;
    (x11local->font[store]).fontstruct=newfontstruct;
    (x11local->font[store]).fontsize=size;
    (x11local->font[store]).fonttype=type;
    (x11local->font[store]).fontdir=dir;
    if (strcmp(fname2[0]+strlen(fname2[0])-9,"iso8859-1")==0)
      (x11local->font[store]).iso8859=TRUE;
    else
      (x11local->font[store]).iso8859=FALSE;
    if (top) XSetFont(disp,gc,(x11local->font[store]).font);
    x11local->loadfont++;
    if (fname2!=NULL) XFreeFontNames(fname2);
    if (fname3!=NULL) XFreeFontNames(fname3);
    return store;
  }
  if (fname2!=NULL) XFreeFontNames(fname2);
  if (fname3!=NULL) XFreeFontNames(fname3);
  return -1;
}

int x11_output(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct x11local *x11local;
  char code;
  int *cpar;
  char *cstr,ch[1];
  int i,x,y,x1,y1,x2,y2;
  double bs;
  XRectangle rect;
  int width,style,cap,join,dashn=0;
  char *dashlist=NULL;
  int arcmode;
  XPoint *xpoint;

  double fontsize,fontspace,fontdir,fontsin,fontcos;
  int fontcashsize,fontcashdir;
  double x0,y0,fontwidth;
  XChar2b kanji[1];
  unsigned int jis;
  Region region;

  x11local=(struct x11local *)argv[2];
  code=*(char *)(argv[3]);
  cpar=(int *)argv[4];
  cstr=argv[5];
  if (x11local->linetonum!=0) {
    if ((code!='T') || (x11local->linetonum>=LINETOLIMIT)) {
      XDrawLines(Disp,x11local->win,x11local->gc,
                 x11local->points,x11local->linetonum,CoordModeOrigin);
      x11local->linetonum=0;
    }
  }
  switch (code) {
  case 'I':
    x11local->PaperWidth=cpar[3];
    x11local->PaperHeight=cpar[4];
    x11changedpi(x11local); 
    break;
  case '%': case 'X':
    break;
  case 'E':
    XFlush(Disp);
    break;
  case 'V':
    x11local->offsetx=dot2pixel(x11local,cpar[1]);
    x11local->offsety=dot2pixel(x11local,cpar[2]);
    x11local->cpx=0;
    x11local->cpy=0;
    if (cpar[5]) {
      rect.x=dot2pixel(x11local,cpar[1])-x11local->scrollx;
      rect.y=dot2pixel(x11local,cpar[2])-x11local->scrolly;
      rect.width=dot2pixel(x11local,cpar[3])-x11local->scrollx-rect.x;
      rect.height=dot2pixel(x11local,cpar[4])-x11local->scrolly-rect.y;
      region=XCreateRegion();
      XUnionRectWithRegion(&rect,region,region);
    } else {
      rect.x=0;
      rect.y=0;
      rect.width=SHRT_MAX;
      rect.height=SHRT_MAX;
      region=XCreateRegion();
      XUnionRectWithRegion(&rect,region,region);
    }
    XSetRegion(Disp,x11local->gc,region);
    XDestroyRegion(region);
    break;
  case 'A':
    if (cpar[1]==0) style=LineSolid;
    else {
      style=LineOnOffDash;
      if ((dashlist=memalloc(sizeof(char)*cpar[1]))==NULL) break;
      for (i=0;i<cpar[1];i++)
        if ((dashlist[i]=dot2pixel(x11local,cpar[6+i]))<=0) dashlist[i]=1;
      dashn=cpar[1];
    }
    width=dot2pixel(x11local,cpar[2]);
    if (cpar[3]==2) cap=CapProjecting;
    else if (cpar[3]==1) cap=CapRound;
    else cap=CapButt;
    if (cpar[4]==2) join=JoinBevel;
    else if (cpar[4]==1) join=JoinRound;
    else join=JoinMiter;
    XSetLineAttributes(Disp,x11local->gc,width,style,cap,join);
    if (style!=LineSolid)
      XSetDashes(Disp,x11local->gc,0,dashlist,dashn);
    if (cpar[1]!=0) memfree(dashlist);
    break;
  case 'G':
    XSetForeground(Disp,x11local->gc,
                   x11RGB(x11local,cpar[1],cpar[2],cpar[3]));
    break;
  case 'M':
    x11local->cpx=cpar[1];
    x11local->cpy=cpar[2];
    break;
  case 'N':
    x11local->cpx+=cpar[1];
    x11local->cpy+=cpar[2];
    break;
  case 'L':
    XDrawLine(Disp,x11local->win,x11local->gc,
              dot2pixelx(x11local,cpar[1]),dot2pixely(x11local,cpar[2]),
              dot2pixelx(x11local,cpar[3]),dot2pixely(x11local,cpar[4]));
    break;
  case 'T':
    x=dot2pixelx(x11local,cpar[1]);
    y=dot2pixely(x11local,cpar[2]);
    if (x11local->linetonum==0) {
      x11local->points[0].x=dot2pixelx(x11local,x11local->cpx);
      x11local->points[0].y=dot2pixely(x11local,x11local->cpy);;
      x11local->linetonum++;
    }
    x11local->points[x11local->linetonum].x=x;
    x11local->points[x11local->linetonum].y=y;
    x11local->linetonum++;
    x11local->cpx=cpar[1];
    x11local->cpy=cpar[2];
    break;
  case 'C':
    if (cpar[7]==0) {
      XDrawArc(Disp,x11local->win,x11local->gc,
               dot2pixelx(x11local,cpar[1]-cpar[3]),
               dot2pixely(x11local,cpar[2]-cpar[4]),
               dot2pixel(x11local,2*cpar[3]),dot2pixel(x11local,2*cpar[4]),
               (int )cpar[5]*64/100,(int )cpar[6]*64/100);
    } else {
      if ((dot2pixel(x11local,cpar[3])<2) && (dot2pixel(x11local,cpar[4])<2)) {
        XDrawPoint(Disp,x11local->win,x11local->gc,
                   dot2pixelx(x11local,cpar[1]),dot2pixely(x11local,cpar[2]));
      } else {
        if (cpar[7]==1) arcmode=ArcPieSlice;
        else arcmode=ArcChord;
        XSetArcMode(Disp,x11local->gc,arcmode);
        XFillArc(Disp,x11local->win,x11local->gc,
               dot2pixelx(x11local,cpar[1]-cpar[3]),
               dot2pixely(x11local,cpar[2]-cpar[4]),
               dot2pixel(x11local,2*cpar[3]),dot2pixel(x11local,2*cpar[4]),
               (int )cpar[5]*64/100,(int )cpar[6]*64/100);
      }
    }
    break;
  case 'B':
    if (cpar[1]<=cpar[3]) {
      x1=dot2pixelx(x11local,cpar[1]);
      x2=dot2pixel(x11local,cpar[3]-cpar[1]);
    } else {
      x1=dot2pixelx(x11local,cpar[3]);
      x2=dot2pixel(x11local,cpar[1]-cpar[3]);
    }
    if (cpar[2]<=cpar[4]) {
      y1=dot2pixely(x11local,cpar[2]);
      y2=dot2pixel(x11local,cpar[4]-cpar[2]);
    } else {
      y1=dot2pixely(x11local,cpar[4]);
      y2=dot2pixel(x11local,cpar[2]-cpar[4]);
    }
    if (cpar[5]==0) {
      XDrawRectangle(Disp,x11local->win,x11local->gc,
              x1,y1,x2+1,y2+1);
    } else {
      XFillRectangle(Disp,x11local->win,x11local->gc,
              x1,y1,x2+1,y2+1);
    }
    break;
  case 'P': 
    XDrawPoint(Disp,x11local->win,x11local->gc,
               dot2pixelx(x11local,cpar[1]),dot2pixely(x11local,cpar[2]));
    break;
  case 'R': 
    if (cpar[1]==0) break;
    if ((xpoint=memalloc(sizeof(XPoint)*cpar[1]))==NULL) break;
    for (i=0;i<cpar[1];i++) {
      xpoint[i].x=dot2pixelx(x11local,cpar[i*2+2]);
      xpoint[i].y=dot2pixely(x11local,cpar[i*2+3]);
    }
    XDrawLines(Disp,x11local->win,x11local->gc,
               xpoint,cpar[1],CoordModeOrigin);
    memfree(xpoint);
    break;
  case 'D': 
    if (cpar[1]==0) break;
    if ((xpoint=memalloc(sizeof(XPoint)*cpar[1]))==NULL) break;
    for (i=0;i<cpar[1];i++) {
      xpoint[i].x=dot2pixelx(x11local,cpar[i*2+3]);
      xpoint[i].y=dot2pixely(x11local,cpar[i*2+4]);
    }
    if (cpar[2]==0) {
      XDrawLines(Disp,x11local->win,x11local->gc,
                 xpoint,cpar[1],CoordModeOrigin);
    } else if (cpar[2]==1) {
      XSetFillRule(Disp,x11local->gc,EvenOddRule);
      XFillPolygon(Disp,x11local->win,x11local->gc,
                   xpoint,cpar[1],Complex,CoordModeOrigin);
    } else {
      XSetFillRule(Disp,x11local->gc,WindingRule);
      XFillPolygon(Disp,x11local->win,x11local->gc,
                   xpoint,cpar[1],Complex,CoordModeOrigin);
    }
    memfree(xpoint);
    break;
  case 'F':
    memfree(x11local->fontalias);
    if ((x11local->fontalias=memalloc(strlen(cstr)+1))==NULL) break;
    strcpy(x11local->fontalias,cstr);
    break;
  case 'H':
    fontspace=cpar[2]/72.0*25.4;
    x11local->fontspace=fontspace;
    fontsize=cpar[1]/72.0*25.4;
    x11local->fontsize=fontsize;
    fontcashsize=dot2pixel(x11local,fontsize);
    fontcashdir=cpar[3];
    fontdir=cpar[3]*MPI/18000.0;
    fontsin=sin(fontdir);
    fontcos=cos(fontdir);
    x11local->fontsin=fontsin;
    x11local->fontcos=fontcos;
    x11local->loadfontf=x11loadfont(Disp,x11local->gc,x11local,
                                 x11local->fontalias,fontcashsize,fontcashdir,
                                  fontsin,fontcos,TRUE);
    break;
  case 'S':
    if (x11local->loadfontf==-1) break;
    x0=x11local->cpx;
    y0=x11local->cpy;
    i=0;
    while (i<strlen(cstr)) {
      if (cstr[i]=='\\') {
        if (cstr[i+1]=='x') {
          if (toupper(cstr[i+2])>='A') ch[0]=toupper(cstr[i+2])-'A'+10;
          else ch[0]=cstr[i+2]-'0';
          if (toupper(cstr[i+3])>='A') ch[0]=ch[0]*16+toupper(cstr[i+3])-'A'+10;
          else ch[0]=ch[0]*16+cstr[i+3]-'0';
          i+=4;
        } else if (cstr[i+1]!='\0') {
          ch[0]=cstr[i];
          i+=2;
        }
      } else {
        ch[0]=cstr[i];
        i++;
      }
      XDrawString(Disp,x11local->win,x11local->gc,
                  dot2pixelx(x11local,nround(x0)),
                  dot2pixely(x11local,nround(y0)),ch,1);
      if ((x11local->font[0].fonttype==BOLD) 
       || (x11local->font[0].fonttype==BOLDITALIC)) {
        bs=x11local->fontsize*0.018;
        XDrawString(Disp,x11local->win,x11local->gc,
          dot2pixelx(x11local,nround(x0+bs)),
          dot2pixely(x11local,nround(y0)),ch,1); 
        XDrawString(Disp,x11local->win,x11local->gc,
          dot2pixelx(x11local,nround(x0)),
          dot2pixely(x11local,nround(y0-bs)),ch,1); 
        XDrawString(Disp,x11local->win,x11local->gc,
          dot2pixelx(x11local,nround(x0+bs)),
          dot2pixely(x11local,nround(y0-bs)),ch,1); 
      }
      if ((x11local->font[0]).fontstruct==NULL) {
        fontwidth=pixel2dot(x11local,(x11local->font[0]).fontsize);
      } else {
        if ((x11local->font[0]).iso8859 && x11local->minus_hyphen
        && (ch[0]=='-')) {
          ch[0]='+';
        }
        fontwidth=pixel2dot(x11local,
                  XTextWidth((x11local->font[0]).fontstruct,ch,1));
      }
      x0+=(fontwidth+x11local->fontspace)*x11local->fontcos;
      y0-=(fontwidth+x11local->fontspace)*x11local->fontsin;
    }
    x11local->cpx=nround(x0);
    x11local->cpy=nround(y0);
    break;
  case 'K':
    if (x11local->loadfontf==-1) break;
    i=0;
    x0=x11local->cpx;
    y0=x11local->cpy;
    while (i<strlen(cstr)) {
      if (niskanji((unsigned char)cstr[i]) && (cstr[i+1]!='\0')) {
        jis=njms2jis(((unsigned char)cstr[i] << 8)+(unsigned char)cstr[i+1]);
        kanji[0].byte1=jis >> 8;
        kanji[0].byte2=jis & 0xff;
        XDrawString16(Disp,x11local->win,x11local->gc,
                  dot2pixelx(x11local,nround(x0)),
                  dot2pixely(x11local,nround(y0)),kanji,1);
        if ((x11local->font[0].fonttype==BOLD) 
         || (x11local->font[0].fonttype==BOLDITALIC)) {
          bs=x11local->fontsize*0.018;
          XDrawString16(Disp,x11local->win,x11local->gc,
                    dot2pixelx(x11local,nround(x0+bs)),
                    dot2pixely(x11local,nround(y0)),kanji,1);
          XDrawString16(Disp,x11local->win,x11local->gc,
                    dot2pixelx(x11local,nround(x0)),
                    dot2pixely(x11local,nround(y0-bs)),kanji,1);
          XDrawString16(Disp,x11local->win,x11local->gc,
                    dot2pixelx(x11local,nround(x0+bs)),
                    dot2pixely(x11local,nround(y0-bs)),kanji,1);
        }
        if ((x11local->font[0]).fontstruct==NULL) {
          fontwidth=pixel2dot(x11local,(x11local->font[0]).fontsize);
        } else {
          fontwidth=pixel2dot(x11local,
                    XTextWidth16((x11local->font[0]).fontstruct,kanji,1));
        }
        x0+=(fontwidth+x11local->fontspace)*x11local->fontcos;
        y0-=(fontwidth+x11local->fontspace)*x11local->fontsin;
        i+=2;
      } else i++;
    }
    x11local->cpx=nround(x0);
    x11local->cpy=nround(y0);
    break;
  default: break;
  }
  return 0;
}

int x11_charwidth(struct objlist *obj,char *inst,char *rval,
                    int argc,char **argv)
{
  struct x11local *x11local;
  char ch[3];
  char *font;
  double size;
  int fontcashsize;
  XChar2b kanji[1];
  unsigned int jis;
  int cashpos;
  XFontStruct *fontstruct;

  ch[0]=(*(unsigned int *)(argv[3]) & 0xff);
  ch[1]=(*(unsigned int *)(argv[3]) & 0xff00) >> 8;
  ch[2]='\0';
  size=(*(int *)(argv[4]))/72.0*25.4;
  font=(char *)(argv[5]);
  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  fontcashsize=dot2pixel(x11local,size);
  if ((cashpos=x11loadfont(Disp,NULL,x11local,
                 font,fontcashsize,0,0.0,1.0,FALSE))!=-1) {
    fontstruct=(x11local->font[cashpos]).fontstruct;
    if (fontstruct==NULL) {
      if (ch[1]!=0) *(int *)rval=size;
      else *(int *)rval=nround(size*0.600);
    } else {
      if (ch[1]!=0) {
        jis=njms2jis(*(unsigned int *)(argv[3]));
        kanji[0].byte1=jis >> 8;
        kanji[0].byte2=jis & 0xff;
        *(int *)rval=pixel2dot(x11local,XTextWidth16(fontstruct,kanji,1));
      } else {
        if ((x11local->font[cashpos]).iso8859 && x11local->minus_hyphen
        && (ch[0]=='-')) {
          ch[0]='+';
        }
        *(int *)rval=pixel2dot(x11local,XTextWidth(fontstruct,ch,1));
      }
    }
  } else {
    *(int *)rval=nround(size*0.600);
  }
  return 0;
}

int x11_charheight(struct objlist *obj,char *inst,char *rval,
                     int argc,char **argv)
{
  struct x11local *x11local;
  char *font;
  double size;
  int fontcashsize;
  char *func;
  int height;
  int cashpos;
  XFontStruct *fontstruct;
  struct fontmap *fcur;
  int twobyte;

  func=(char *)argv[1];
  if (strcmp0(func,"_charascent")==0) height=TRUE;
  else height=FALSE;
  size=(*(int *)(argv[3]))/72.0*25.4;
  font=(char *)(argv[4]);
  if (_getobj(obj,"_local",inst,&x11local)) return 1;
  fcur=x11local->fontmaproot;
  twobyte=FALSE;
  while (fcur!=NULL) {
    if (strcmp(font,fcur->fontalias)==0) {
      twobyte=fcur->twobyte;
      break;
    }
    fcur=fcur->next;
  }        
  fontcashsize=dot2pixel(x11local,size);
  if ((cashpos=x11loadfont(Disp,NULL,x11local,
                 font,fontcashsize,0,0.0,1.0,FALSE))!=-1) {
    fontstruct=(x11local->font[cashpos]).fontstruct;
    if (fontstruct==NULL) {
      if (twobyte) {
        if (height) *(int *)rval=nround(size*0.791);
        else *(int *)rval=nround(size*0.250);
      } else {
        if (height) *(int *)rval=nround(size*0.562);
        else *(int *)rval=nround(size*0.250);
      }
    } else {
      if (height) *(int *)rval=pixel2dot(x11local,fontstruct->ascent);
      else *(int *)rval=pixel2dot(x11local,fontstruct->descent);
    }
  } else {
    if (height) *(int *)rval=nround(size*0.562);
    else *(int *)rval=nround(size*0.250);
  }
  return 0;
}


#define TBLNUM 15

struct objtable gra2x11[TBLNUM] = {
  {"init",NVFUNC,NEXEC,x11init,NULL,0},
  {"done",NVFUNC,NEXEC,x11done,NULL,0},
  {"next",NPOINTER,0,NULL,NULL,0},
  {"dpi",NINT,NREAD|NWRITE,x11dpi,NULL,0},
  {"auto_redraw",NBOOL,NREAD|NWRITE,x11autoredraw,NULL,0},
  {"store_in_memory",NBOOL,NREAD|NWRITE,x11storememory,NULL,0},
  {"redraw",NVFUNC,NREAD|NEXEC,x11redraw,"",0},
  {"flush",NVFUNC,NREAD|NEXEC,x11flush,"",0},
  {"clear",NVFUNC,NREAD|NEXEC,x11clear,"",0},
  {"_local",NPOINTER,0,NULL,NULL,0},
  {"_output",NVFUNC,0,x11_output,NULL,0},
  {"_charwidth",NIFUNC,0,x11_charwidth,NULL,0},
  {"_charascent",NIFUNC,0,x11_charheight,NULL,0},
  {"_chardescent",NIFUNC,0,x11_charheight,NULL,0},
  {"_evloop",NVFUNC,0,x11_evloop,NULL,0}
};

void *addgra2x11()
/* addgra2x11() returns NULL on error */
{
  return addobject(NAME,NULL,PARENT,VERSION,TBLNUM,gra2x11,ERRNUM,x11errorlist,
                   NULL,NULL);
}
