/* 
 * $Id: ox11menu.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: ox11menu.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/03/20 12:32:54  isizaka
 * minor change
 *
 * Revision 1.1  1999/03/17 13:28:18  isizaka
 * Initial revision
 *
 *
 **/

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

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

#include "ox11menu.h"
#include "x11menu.h"

#define NAME "menu"
#define ALIAS "winmenu:x11menu"
#define PARENT "gra2"
#define VERSION  "1.00.00"
#define MX11CONF "[x11menu]"
#define G2WINCONF "[gra2x11]"
#define TRUE  1
#define FALSE 0

#define ERRNUM 3

char *menuerrorlist[ERRNUM]={
  "already running.",
  "not enough color cell.",
  "cannot create font. Check `windowfont' resource.",
};

extern int OpenApplication();

struct menulocal menulocal;
struct mxlocal *mxlocal;
struct savedstdio x11iosave;

int mx11loadconfig()
{
  FILE *fp;
  char *tok,*str,*s2;
  char *f1,*f2,*f3,*f4,*f5;
  int val;
  char *endptr;
  int len;
  struct fontmap *fcur,*fnew;
  struct extprinter *pcur,*pnew;
  struct prnprinter *pcur2,*pnew2;
  struct script *scur,*snew;

  if ((fp=openconfig(MX11CONF))==NULL) return 0;
  fcur=mxlocal->fontmaproot;
  pcur=menulocal.extprinterroot;
  pcur2=menulocal.prnprinterroot;
  scur=menulocal.scriptroot;
  while ((tok=getconfig(fp,&str))!=NULL) {
    s2=str;
    if (strcmp(tok,"mouse_click")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.mouseclick=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"script_console")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.scriptconsole=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"addin_console")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.addinconsole=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"change_directory")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.changedirectory=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"save_history")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.savehistory=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"expand_dir")==0) {
      f1=getitok2(&s2,&len,"");
      if (f1!=NULL) {
        memfree(menulocal.expanddir);
        menulocal.expanddir=f1;
      }
    } else if (strcmp(tok,"expand")==0) {
      f1=getitok2(&s2,&len," \x09,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.expand=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"ignore_path")==0) {
      f1=getitok2(&s2,&len," \x09,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.ignorepath=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"save_path")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.savepath=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"save_with_data")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.savewithdata=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"save_with_merge")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.savewithmerge=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"ngp_history")==0) {
      for (;(s2[0]!='\0') && (strchr(" \t,",s2[0])!=NULL);s2++);
      f1=getitok2(&s2,&len,"");
      if (f1!=NULL) arrayadd(menulocal.ngpfilelist,&f1);
    } else if (strcmp(tok,"ngp_dir_history")==0) {
      for (;(s2[0]!='\0') && (strchr(" \t,",s2[0])!=NULL);s2++);
      f1=getitok2(&s2,&len,"");
      if (f1!=NULL) arrayadd(menulocal.ngpdirlist,&f1);
    } else if (strcmp(tok,"data_history")==0) {
      for (;(s2[0]!='\0') && (strchr(" \t,",s2[0])!=NULL);s2++);
      f1=getitok2(&s2,&len,"");
      if (f1!=NULL) arrayadd(menulocal.datafilelist,&f1);
    } else if (strcmp(tok,"framex")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') menulocal.framex=val;
    } else if (strcmp(tok,"framey")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') menulocal.framey=val;
    } else if (strcmp(tok,"menu_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL)) {
        val=strtol(f1,&endptr,10);
        if ((endptr[0]=='\0') && (val!=0)) menulocal.menux=val;
        val=strtol(f2,&endptr,10);
        if ((endptr[0]=='\0') && (val!=0)) menulocal.menuy=val;
        val=strtol(f3,&endptr,10);
        if ((endptr[0]=='\0') && (val!=0)) menulocal.menuwidth=val;
        val=strtol(f4,&endptr,10);
        if ((endptr[0]=='\0') && (val!=0)) menulocal.menuheight=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
    } else if (strcmp(tok,"file_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.filex=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.filey=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.filewidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.fileheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.fileopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"axis_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.axiswidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"legend_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendwidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"merge_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergex=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergey=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergewidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergeheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergeopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"information_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogwidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"coordinate_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordwidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"status_bar")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.statusb=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"show_tip")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.showtip=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"move_child_window")==0) {
      f1=getitok2(&s2,&len," \t,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.movechild=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"editor")==0) {
      memfree(menulocal.editor);
      f1=getitok2(&s2,&len,"");
      menulocal.editor=f1;
    } else if (strcmp(tok,"browser")==0) {
      memfree(menulocal.browser);
      f1=getitok2(&s2,&len,"");
      menulocal.browser=f1;
    } else if (strcmp(tok,"gpl")==0) {
      memfree(menulocal.gpl);
      f1=getitok2(&s2,&len,"");
      menulocal.gpl=f1;
    } else if (strcmp(tok,"ext_driver")==0) {
      f1=getitok2(&s2,&len,",");
      f2=getitok2(&s2,&len,",");
      if (s2[1]==',') f3=NULL;
      else f3=getitok2(&s2,&len,",");
      for (;(s2[0]!='\0') && (strchr(" \t,",s2[0])!=NULL);s2++);
      f4=getitok2(&s2,&len,"");
      if ((f1!=NULL) && (f2!=NULL)) {
        if ((pnew=(struct extprinter *)memalloc(sizeof(struct extprinter)))
        ==NULL) {
          memfree(tok);
          memfree(f1);
          memfree(f2);
          memfree(f3);
          memfree(f4);
          closeconfig(fp);
          return 1;
        }
        if (pcur==NULL) menulocal.extprinterroot=pnew;
        else pcur->next=pnew;
        pcur=pnew;
        pcur->next=NULL;
        pcur->name=f1;
        pcur->driver=f2;
        pcur->ext=f3;
        pcur->option=f4;
      } else {
        memfree(f1);
        memfree(f2);
        memfree(f3);
        memfree(f4);
      }
    } else if (strcmp(tok,"prn_driver")==0) {
      f1=getitok2(&s2,&len,",");
      f2=getitok2(&s2,&len,",");
      f3=getitok2(&s2,&len,",");
      for (;(s2[0]!='\0') && (strchr(" \t,",s2[0])!=NULL);s2++);
      f4=getitok2(&s2,&len,"");
      if ((f1!=NULL) && (f2!=NULL)) {
        if ((pnew2=(struct prnprinter *)memalloc(sizeof(struct prnprinter)))
        ==NULL) {
          memfree(tok);
          memfree(f1);
          memfree(f2);
          memfree(f3);
          memfree(f4);
          closeconfig(fp);
          return 1;
        }
        if (pcur2==NULL) menulocal.prnprinterroot=pnew2;
        else pcur2->next=pnew2;
        pcur2=pnew2;
        pcur2->next=NULL;
        pcur2->name=f1;
        pcur2->driver=f2;
        pcur2->prn=f3;
        pcur2->option=f4;
      } else {
        memfree(f1);
        memfree(f2);
        memfree(f3);
        memfree(f4);
      }
    } else if (strcmp(tok,"script")==0) {
      f1=getitok2(&s2,&len,",");
      f2=getitok2(&s2,&len,",");
      for (;(s2[0]!='\0') && (strchr(" \t,",s2[0])!=NULL);s2++);
      f3=getitok2(&s2,&len,"");
      if ((f1!=NULL) && (f2!=NULL)) {
        if ((snew=(struct script *)memalloc(sizeof(struct script)))==NULL) {
          memfree(tok);
          memfree(f1);
          memfree(f2);
          memfree(f3);
          closeconfig(fp);
          return 1;
        }
        if (scur==NULL) menulocal.scriptroot=snew;
        else scur->next=snew;
        scur=snew;
        scur->next=NULL;
        scur->name=f1;
        scur->script=f2;
        scur->option=f3;
      } else {
        memfree(f1);
        memfree(f2);
        memfree(f3);
      }
    } else 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) mxlocal->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);
        memfree(f3);
        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,");
      if (f1!=NULL) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') mxlocal->backingstore=val;
      }
      memfree(f1);
    } else if (strcmp(tok,"viewer_dpi")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') mxlocal->windpi=val;
      memfree(f1);
    } else if (strcmp(tok,"color_depth")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') mxlocal->cdepth=val;
      memfree(f1);
    } else if (strcmp(tok,"viewer_auto_redraw")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') {
        if (val==0) mxlocal->autoredraw=FALSE;
        else mxlocal->autoredraw=TRUE;
      }
      memfree(f1);
    } else if (strcmp(tok,"viewer_load_file_on_redraw")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') {
        if (val==0) mxlocal->redrawf=FALSE;
        else mxlocal->redrawf=TRUE;
      }
      memfree(f1);
    } else if (strcmp(tok,"viewer_show_ruler")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') {
        if (val==0) mxlocal->ruler=FALSE;
        else mxlocal->ruler=TRUE;
      }
      memfree(f1);
    } else if (strcmp(tok,"viewer_grid")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') mxlocal->grid=val;
      memfree(f1);
    } else if (strcmp(tok,"minus_hyphen")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') mxlocal->minus_hyphen=val;
      memfree(f1);
    }
    memfree(tok);
    memfree(str);
  }
  closeconfig(fp);
  return 0;
}

void initwindowconfig()
{
  menulocal.fileopen=menulocal.axisopen=menulocal.legendopen
   =menulocal.mergeopen=menulocal.dialogopen=menulocal.coordopen=FALSE;
  menulocal.filex=menulocal.filey
   =menulocal.fileheight=menulocal.filewidth=CW_USEDEFAULT;
  menulocal.axisx=menulocal.axisy
   =menulocal.axisheight=menulocal.axiswidth=CW_USEDEFAULT;
  menulocal.legendx=menulocal.legendy
   =menulocal.legendheight=menulocal.legendwidth=CW_USEDEFAULT;
  menulocal.mergex=menulocal.mergey
   =menulocal.mergeheight=menulocal.mergewidth=CW_USEDEFAULT;
  menulocal.dialogx=menulocal.dialogy
   =menulocal.dialogheight=menulocal.dialogwidth=CW_USEDEFAULT;
  menulocal.coordx=menulocal.coordy
   =menulocal.coordheight=menulocal.coordwidth=CW_USEDEFAULT;
}

int mx11windowconfig()
{
  FILE *fp;
  char *tok,*str,*s2;
  char *f1,*f2,*f3,*f4,*f5;
  int val;
  char *endptr;
  int len;

  if ((fp=openconfig(MX11CONF))==NULL) return 0;
  while ((tok=getconfig(fp,&str))!=NULL) {
    s2=str;
    if (strcmp(tok,"file_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.filex=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.filey=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.filewidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.fileheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.fileopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"axis_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.axiswidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.axisopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"legend_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendwidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.legendopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"merge_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergex=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergey=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergewidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergeheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.mergeopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"information_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogwidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.dialogopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    } else if (strcmp(tok,"coordinate_win")==0) {
      f1=getitok2(&s2,&len," \t,");
      f2=getitok2(&s2,&len," \t,");
      f3=getitok2(&s2,&len," \t,");
      f4=getitok2(&s2,&len," \t,");
      f5=getitok2(&s2,&len," \t,");
      if ((f1!=NULL) && (f2!=NULL) && (f3!=NULL) && (f4!=NULL) && (f5!=NULL)) {
        val=strtol(f1,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordx=val;
        val=strtol(f2,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordy=val;
        val=strtol(f3,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordwidth=val;
        val=strtol(f4,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordheight=val;
        val=strtol(f5,&endptr,10);
        if (endptr[0]=='\0') menulocal.coordopen=val;
      }
      memfree(f1);
      memfree(f2);
      memfree(f3);
      memfree(f4);
      memfree(f5);
    }
    memfree(tok);
    memfree(str);
  }
  closeconfig(fp);
  return 0;
}

int exwinloadconfig()
{
  FILE *fp;
  char *tok,*str,*s2;
  char *f1;
  int val;
  char *endptr;
  int len;

  if ((fp=openconfig(G2WINCONF))==NULL) return 0;
  while ((tok=getconfig(fp,&str))!=NULL) {
    s2=str;
    if (strcmp(tok,"win_dpi")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') menulocal.exwindpi=val;
      memfree(f1);
    } else if (strcmp(tok,"win_width")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') menulocal.exwinwidth=val;
      memfree(f1);
    } else if (strcmp(tok,"win_height")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') menulocal.exwinheight=val;
      memfree(f1);
    } else if (strcmp(tok,"backing_store")==0) {
      f1=getitok2(&s2,&len," \t,");
      val=strtol(f1,&endptr,10);
      if (endptr[0]=='\0') menulocal.exwinbackingstore=val;
      memfree(f1);
    }
    memfree(tok);
    memfree(str);
  }
  closeconfig(fp);
  return 0;
}

void menuadddrawrable(struct objlist *parent,struct narray *drawrable)
{
  struct objlist *ocur;
  char *name;

  ocur=chkobjroot();
  while (ocur!=NULL) {
    if (chkobjparent(ocur)==parent) {
      name=chkobjectname(ocur);
      arrayadd2(drawrable,&name);
      menuadddrawrable(ocur,drawrable);
    }
    ocur=ocur->next;
  }
}

int menuinit(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct objlist *robj;
  struct fontmap *fcur,*fdel;
  struct extprinter *pcur,*pdel;
  struct prnprinter *pcur2,*pdel2;
  struct script *scur,*sdel;
  int i,numf,numd;
  char *dum;

  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  if ((mxlocal=(struct mxlocal *)memalloc(sizeof(struct mxlocal)))==NULL)
    return 1;
  menulocal.framex=menulocal.framey=0;
  menulocal.menux=menulocal.menuy
   =menulocal.menuheight=menulocal.menuwidth=CW_USEDEFAULT;
  initwindowconfig();
  menulocal.showtip=TRUE;
  menulocal.statusb=TRUE;
  menulocal.movechild=FALSE;
  menulocal.scriptconsole=FALSE;
  menulocal.addinconsole=TRUE;
  menulocal.mouseclick=500;
  menulocal.changedirectory=1;
  menulocal.editor=NULL;
  menulocal.browser=NULL;
  menulocal.gpl=NULL;
  menulocal.PaperWidth=21000;
  menulocal.PaperHeight=29700;
  menulocal.LeftMargin=0;
  menulocal.TopMargin=0;
  menulocal.PaperZoom=10000;
  menulocal.exwindpi=70;
  menulocal.exwinwidth=0;
  menulocal.exwinheight=0;
  menulocal.exwinbackingstore=FALSE;
  menulocal.fileopendir=NULL;
  menulocal.graphloaddir=NULL;
  menulocal.expand=1;
  menulocal.expanddir=(char *)memalloc(3);
  strcpy(menulocal.expanddir,"./");
  menulocal.ignorepath=0;
  menulocal.savepath=0;
  menulocal.savewithdata=0;
  menulocal.savewithmerge=0;
  menulocal.mathlist=arraynew(sizeof(char *));
  menulocal.ngpfilelist=arraynew(sizeof(char *));
  menulocal.ngpdirlist=arraynew(sizeof(char *));
  menulocal.datafilelist=arraynew(sizeof(char *));
  menulocal.GRAobj=chkobject("gra");
  arrayinit(&(menulocal.drawrable),sizeof(char *));
  menuadddrawrable(chkobject("draw"),&(menulocal.drawrable));
  menulocal.extprinterroot=NULL;
  menulocal.prnprinterroot=NULL;
  menulocal.scriptroot=NULL;
  mxlocal->fontmaproot=NULL;
  mxlocal->windpi=70;
  mxlocal->autoredraw=TRUE;
  mxlocal->redrawf=TRUE;
  mxlocal->ruler=TRUE;
  mxlocal->grid=200;
  mxlocal->cdepth=X11COLORDEPTH;
  mxlocal->backingstore=FALSE;
  mxlocal->minus_hyphen=TRUE;
  if (_putobj(obj,"_local",inst,mxlocal)) goto errexit;
  if (mx11loadconfig()) goto errexit; 
  if (exwinloadconfig()) goto errexit;
  numf=arraynum(menulocal.ngpfilelist);
  numd=arraynum(menulocal.ngpdirlist);
  dum=NULL;
  if (numd>numf)
    for (i=numf;i<numd;i++) arrayndel2(menulocal.ngpdirlist,i);
  else if (numd<numf)
    for (i=numd;i<numf;i++) arrayadd(menulocal.ngpdirlist,&dum);
  if (menulocal.exwindpi<1) menulocal.exwindpi=70;
  if (menulocal.exwindpi>2540) menulocal.exwindpi=2540;
  if (mxlocal->windpi<1) mxlocal->windpi=70;
  if (mxlocal->windpi>2540) mxlocal->windpi=2540;
  if (mxlocal->cdepth<2) mxlocal->cdepth=2;
  if (_putobj(obj,"dpi",inst,&(mxlocal->windpi))) goto errexit;
  if (_putobj(obj,"auto_redraw",inst,&(mxlocal->autoredraw))) goto errexit;
  if (_putobj(obj,"redraw_flag",inst,&(mxlocal->redrawf))) goto errexit;
  if (!chkobjfield(obj,"_output")) {
    if ((menulocal.output=getobjtblpos(obj,"_output",&robj))==-1) goto errexit;
    menulocal.outputobj=robj;
  } else menulocal.output=-1;
  menulocal.obj=obj;
  menulocal.inst=inst;
  mxlocal->win=0;
  mxlocal->gc=0;
  mxlocal->lock=0;

  if (!OpenApplication()) goto errexit;
  return 0;

errexit:
  memfree(menulocal.editor);
  memfree(menulocal.browser);
  memfree(menulocal.gpl);
  pcur=menulocal.extprinterroot;
  while (pcur!=NULL) {
    pdel=pcur;
    pcur=pcur->next;
    memfree(pdel->name);
    memfree(pdel->driver);
    memfree(pdel->ext);
    memfree(pdel->option);
    memfree(pdel);
  }
  pcur2=menulocal.prnprinterroot;
  while (pcur2!=NULL) {
    pdel2=pcur2;
    pcur2=pcur2->next;
    memfree(pdel2->name);
    memfree(pdel2->driver);
    memfree(pdel2->option);
    memfree(pdel2->prn);
    memfree(pdel2);
  }
  scur=menulocal.scriptroot;
  while (scur!=NULL) {
    sdel=scur;
    scur=scur->next;
    memfree(sdel->name);
    memfree(sdel->script);
    memfree(sdel->option);
    memfree(sdel);
  }
  fcur=mxlocal->fontmaproot;
  while (fcur!=NULL) {
    fdel=fcur;
    fcur=fcur->next;
    memfree(fdel->fontalias);
    memfree(fdel->fontname);
    memfree(fdel);
  }
  memfree(mxlocal);
  return 1;
}

int menudone(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  struct fontmap *fcur,*fdel;
  struct extprinter *pcur,*pdel;
  struct prnprinter *pcur2,*pdel2;
  struct script *scur,*sdel;

  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  arraydel2(&(menulocal.drawrable));
  arrayfree2(menulocal.mathlist);
  arrayfree2(menulocal.ngpfilelist);
  arrayfree2(menulocal.ngpdirlist);
  arrayfree2(menulocal.datafilelist);
  memfree(menulocal.editor);
  memfree(menulocal.browser);
  memfree(menulocal.gpl);
  free(menulocal.fileopendir);
  free(menulocal.graphloaddir);
  memfree(menulocal.expanddir);
  pcur=menulocal.extprinterroot;
  while (pcur!=NULL) {
    pdel=pcur;
    pcur=pcur->next;
    memfree(pdel->name);
    memfree(pdel->driver);
    memfree(pdel->ext);
    memfree(pdel->option);
    memfree(pdel);
  }
  pcur2=menulocal.prnprinterroot;
  while (pcur2!=NULL) {
    pdel2=pcur2;
    pcur2=pcur2->next;
    memfree(pdel2->name);
    memfree(pdel2->driver);
    memfree(pdel2->option);
    memfree(pdel2->prn);
    memfree(pdel2);
  }
  scur=menulocal.scriptroot;
  while (scur!=NULL) {
    sdel=scur;
    scur=scur->next;
    memfree(sdel->name);
    memfree(sdel->script);
    memfree(sdel->option);
    memfree(sdel);
  }
  fcur=mxlocal->fontmaproot;
  while (fcur!=NULL) {
    fdel=fcur;
    fcur=fcur->next;
    memfree(fdel->fontname);
    memfree(fdel->fontalias);
    memfree(fdel);
  }
  return 0;
}

void mx11displaydialog(char *str)
{
  DisplayDialog(str);
}

void mx11displaystatus(char *str)
{
  DisplayStatus(str);
}

int mx11putstderr(char *s)
{
  return PutStderr(s);
}

int mx11printfstderr(char *fmt,...)
{
  int len;
  char buf[1024];
  va_list ap;

  va_start(ap,fmt);
  len=vsprintf(buf,fmt,ap);
  va_end(ap);
  PutStderr(buf);
  return len;
}

int mx11interrupt()
{
  return ChkInterrupt();
}

int mx11inputyn(char *mes)
{
  return InputYN(mes);
}

int menumenu(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  char *file;

  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  if (mxlocal->lock) {
    error(obj,ERRRUN);
    return 1;
  }
  mxlocal->lock=1;

  savestdio(&x11iosave);

  file=(char *)argv[2];
  application(file);

  loadstdio(&x11iosave);
  mxlocal->lock=0;
  return 0;
}

int mx_evloop(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  ResetEvent();
  return 0;
}

int mxredrawflag(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  mxlocal->redrawf=*(int *)argv[2];
  return 0;
}

void mx_redraw(struct objlist *obj,char *inst)
{
  GRAredraw(obj,inst,TRUE,mxlocal->redrawf);
  mxflush(obj,inst,NULL,0,NULL);
}

void mx_inslist(struct objlist *obj,char *inst,
                struct objlist *aobj,char *ainst,char *afield,int addn)
{
  int GC;

  _getobj(obj,"_GC",inst,&GC);
  GRAinslist(GC,aobj,ainst,chkobjectname(aobj),afield,addn);
}

void mx_dellist(struct objlist *obj,char *inst,int deln)
{
  int GC;

  _getobj(obj,"_GC",inst,&GC);
  GRAdellist(GC,deln);
}

int mxredraw(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  mx_redraw(obj,inst);
  return 0;
}

int mxautoredraw(struct objlist *obj,char *inst,char *rval,
                 int argc,char **argv)
{
  if (!(mxlocal->autoredraw) && (*(int *)argv[2]))
    mx_redraw(obj,inst);
  mxlocal->autoredraw=*(int *)argv[2];
  return 0;
}

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

  dpi=abs(*(int *)argv[2]);
  if (dpi<1) dpi=1;
  if (dpi>2540) dpi=2540;
  mxlocal->windpi=dpi;
  mxlocal->pixel_dot=dpi/2540.0;
  *(int *)argv[2]=dpi;
  if (Disp!=NULL) 
    XClearArea(Disp,mxlocal->win,0,0,0,0,TRUE);
  return 0;
}

int mxflush(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  if (mxlocal->linetonum!=0) {
    if (Disp!=NULL) {
      XDrawLines(Disp,mxlocal->win,mxlocal->gc,
                 mxlocal->points,mxlocal->linetonum,CoordModeOrigin);
      mxlocal->linetonum=0;
    }
  }
  if (Disp!=NULL) XFlush(Disp);
  return 0;
}


int mxclear(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  if (_exeparent(obj,(char *)argv[1],inst,rval,argc,argv)) return 1;
  if (mxlocal->linetonum!=0) {
    if (Disp!=NULL) {
      XDrawLines(Disp,mxlocal->win,mxlocal->gc,
                 mxlocal->points,mxlocal->linetonum,CoordModeOrigin);
      mxlocal->linetonum=0;
    }
  }
  if (Disp!=NULL) {
    XClearArea(Disp,mxlocal->win,0,0,0,0,TRUE);
  }
  return 0;
}

void mxsaveGC(GC gc,Drawable d,int scrollx,int scrolly,
              struct mxlocal *mxsave,int dpi,
              Region region)
{
  int i;

  memcpy(mxsave,mxlocal,sizeof(struct mxlocal));
  mxlocal->win=d;
  mxlocal->gc=gc;
  mxlocal->scrollx=scrollx;
  mxlocal->scrolly=scrolly;
  mxlocal->offsetx=0;
  mxlocal->offsety=0;
  mxlocal->cpx=0;
  mxlocal->cpy=0;
  mxlocal->fontalias=NULL;
  for (i=0;i<X11FONTCASH;i++) (mxlocal->font[i]).fontalias=NULL;
  mxlocal->loadfont=0;
  mxlocal->loadfontf=-1;
  mxlocal->linetonum=0;
  if (dpi!=-1) {
    mxlocal->windpi=dpi;
    mxlocal->pixel_dot=mxlocal->windpi/2540.0;
  } else {
    mxlocal->windpi=mxsave->windpi;
    mxlocal->pixel_dot=mxsave->pixel_dot;
  }
  mxlocal->region=region;
}

void mxrestoreGC(struct mxlocal *mxsave)
{
  int i;

  if (mxlocal->linetonum!=0) {
    if (Disp!=NULL) {
      XDrawLines(Disp,mxlocal->win,mxlocal->gc,
                 mxlocal->points,mxlocal->linetonum,CoordModeOrigin);
      mxlocal->linetonum=0;
      XFlush(Disp);
    }
  }
  memfree(mxlocal->fontalias);
  for (i=0;i<X11FONTCASH;i++) memfree((mxlocal->font[i]).fontalias);
  memcpy(mxlocal,mxsave,sizeof(struct mxlocal));
}

int mxd2p(int r)
{
  return nround(r*mxlocal->pixel_dot);
}

int mxd2px(int x)
{
  return nround(x*mxlocal->pixel_dot+mxlocal->offsetx-mxlocal->scrollx);
}

int mxd2py(int y)
{
  return nround(y*mxlocal->pixel_dot+mxlocal->offsety-mxlocal->scrolly);
}

int mxp2d(int r)
{
  return nround(r/mxlocal->pixel_dot);
}

unsigned long RGB(int R,int G,int B)
{
  XColor col;

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

int mxloadfont(Display *disp,GC gc,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<mxlocal->loadfont;i++) {
    if ((strcmp((mxlocal->font[i]).fontalias,fontalias)==0)
    && ((mxlocal->font[i]).fontsize==size)
    && ((mxlocal->font[i]).fontdir==dir)) {
      fontcashfind=i;
      break;
    }
  }
  if (fontcashfind!=-1) {
    if (top) {
      font=mxlocal->font[fontcashfind];
      for (i=fontcashfind-1;i>=0;i--) mxlocal->font[i+1]=mxlocal->font[i];
      mxlocal->font[0]=font;
      XSetFont(disp,gc,(mxlocal->font[0]).font);
      return 0;
    } else return fontcashfind;
  }

  fcur=mxlocal->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 (mxlocal->loadfont==X11FONTCASH) {
      XUnloadFont(disp,(mxlocal->font[X11FONTCASH-1]).font);
      if (mxlocal->font[X11FONTCASH-1].fontstruct!=NULL)
        XFreeFont(disp,(mxlocal->font[X11FONTCASH-1]).fontstruct); 
      memfree((mxlocal->font[X11FONTCASH-1]).fontalias);
      (mxlocal->font[X11FONTCASH-1]).fontalias=NULL;
      mxlocal->loadfont--;
    }
    if (top) {
      for (i=mxlocal->loadfont-1;i>=0;i--) 
        mxlocal->font[i+1]=mxlocal->font[i];
      store=0;
    } else store=mxlocal->loadfont;
    (mxlocal->font[store]).fontalias=memalloc(strlen(fontalias)+1);
    if ((mxlocal->font[store]).fontalias==NULL) {
      if (fname2!=NULL) XFreeFontNames(fname2);
      if (fname3!=NULL) XFreeFontNames(fname3);
      return -1;
    }
    strcpy((mxlocal->font[store]).fontalias,fontalias);
    (mxlocal->font[store]).font=newfont;
    (mxlocal->font[store]).fontstruct=newfontstruct;
    (mxlocal->font[store]).fontsize=size;
    (mxlocal->font[store]).fonttype=type;
    (mxlocal->font[store]).fontdir=dir;
    if (strcmp(fname2[0]+strlen(fname2[0])-9,"iso8859-1")==0)
      (mxlocal->font[store]).iso8859=TRUE;
    else
      (mxlocal->font[store]).iso8859=FALSE;
    if (top) XSetFont(disp,gc,(mxlocal->font[store]).font);
    mxlocal->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 mx_output(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  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;
  Region region;

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

  code=*(char *)(argv[3]);
  cpar=(int *)argv[4];
  cstr=(char *)argv[5];
  if (Disp==NULL) return -1;
  if (mxlocal->gc==0) return -1;
  if (mxlocal->linetonum!=0) {
    if ((code!='T') || (mxlocal->linetonum>=LINETOLIMIT)) {
      XDrawLines(Disp,mxlocal->win,mxlocal->gc,
                 mxlocal->points,mxlocal->linetonum,CoordModeOrigin);
      mxlocal->linetonum=0;
    }
  }
  switch (code) {
  case 'I': case '%': case 'X':
    break;
  case 'E':
    XFlush(Disp);
    break;
  case 'V':
    mxlocal->offsetx=mxd2p(cpar[1]);
    mxlocal->offsety=mxd2p(cpar[2]);
    mxlocal->cpx=0;
    mxlocal->cpy=0;
    if (cpar[5]) {
      rect.x=mxd2p(cpar[1])-mxlocal->scrollx;
      rect.y=mxd2p(cpar[2])-mxlocal->scrolly;
      rect.width=mxd2p(cpar[3])-mxlocal->scrollx-rect.x;
      rect.height=mxd2p(cpar[4])-mxlocal->scrolly-rect.y;
      region=XCreateRegion();
      XUnionRectWithRegion(&rect,region,region);
      if (mxlocal->region!=NULL)
        XIntersectRegion(region,mxlocal->region,region);
      XSetRegion(Disp,mxlocal->gc,region);
      XDestroyRegion(region);
    } else {
      if (mxlocal->region!=NULL) 
        XSetRegion(Disp,mxlocal->gc,mxlocal->region);
      else {
        rect.x=0;
        rect.y=0;
        rect.width=SHRT_MAX;
        rect.height=SHRT_MAX;
        region=XCreateRegion();
        XUnionRectWithRegion(&rect,region,region);
        XSetRegion(Disp,mxlocal->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]=mxd2p(cpar[6+i]))<=0) dashlist[i]=1;
      dashn=cpar[1];
    }
    width=mxd2p(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,mxlocal->gc,width,style,cap,join);
    if (style!=LineSolid)
      XSetDashes(Disp,mxlocal->gc,0,dashlist,dashn);
    if (cpar[1]!=0) memfree(dashlist);
    break;
  case 'G':
    XSetForeground(Disp,mxlocal->gc,RGB(cpar[1],cpar[2],cpar[3]));
    break;
  case 'M':
    mxlocal->cpx=cpar[1];
    mxlocal->cpy=cpar[2];
    break;
  case 'N':
    mxlocal->cpx+=cpar[1];
    mxlocal->cpy+=cpar[2];
    break;
  case 'L':
    XDrawLine(Disp,mxlocal->win,mxlocal->gc,
              mxd2px(cpar[1]),mxd2py(cpar[2]),
              mxd2px(cpar[3]),mxd2py(cpar[4]));
    break;
  case 'T':
    x=mxd2px(cpar[1]);
    y=mxd2py(cpar[2]);
    if (mxlocal->linetonum==0) {
      mxlocal->points[0].x=mxd2px(mxlocal->cpx);
      mxlocal->points[0].y=mxd2py(mxlocal->cpy);;
      mxlocal->linetonum++;
    }
    mxlocal->points[mxlocal->linetonum].x=x;
    mxlocal->points[mxlocal->linetonum].y=y;
    mxlocal->linetonum++;
    mxlocal->cpx=cpar[1];
    mxlocal->cpy=cpar[2];
    break;
  case 'C':
    if (cpar[7]==0) {
      XDrawArc(Disp,mxlocal->win,mxlocal->gc,
               mxd2px(cpar[1]-cpar[3]),
               mxd2py(cpar[2]-cpar[4]),
               mxd2p(2*cpar[3]),mxd2p(2*cpar[4]),
               (int )cpar[5]*64/100,(int )cpar[6]*64/100);
    } else {
      if ((mxd2p(cpar[3])<2) && (mxd2p(cpar[4])<2)) {
        XDrawPoint(Disp,mxlocal->win,mxlocal->gc,
                   mxd2px(cpar[1]),mxd2py(cpar[2]));
      } else {
        if (cpar[7]==1) arcmode=ArcPieSlice;
        else arcmode=ArcChord;
        XSetArcMode(Disp,mxlocal->gc,arcmode);
        XFillArc(Disp,mxlocal->win,mxlocal->gc,
               mxd2px(cpar[1]-cpar[3]),
               mxd2py(cpar[2]-cpar[4]),
               mxd2p(2*cpar[3]),mxd2p(2*cpar[4]),
               (int )cpar[5]*64/100,(int )cpar[6]*64/100);
      }
    }
    break;
  case 'B':
    if (cpar[1]<=cpar[3]) {
      x1=mxd2px(cpar[1]);
      x2=mxd2p(cpar[3]-cpar[1]);
    } else {
      x1=mxd2px(cpar[3]);
      x2=mxd2p(cpar[1]-cpar[3]);
    }
    if (cpar[2]<=cpar[4]) {
      y1=mxd2py(cpar[2]);
      y2=mxd2p(cpar[4]-cpar[2]);
    } else {
      y1=mxd2py(cpar[4]);
      y2=mxd2p(cpar[2]-cpar[4]);
    }
    if (cpar[5]==0) {
      XDrawRectangle(Disp,mxlocal->win,mxlocal->gc,
              x1,y1,x2+1,y2+1);
    } else {
      XFillRectangle(Disp,mxlocal->win,mxlocal->gc,
              x1,y1,x2+1,y2+1);
    }
    break;
  case 'P': 
    XDrawPoint(Disp,mxlocal->win,mxlocal->gc,
               mxd2px(cpar[1]),mxd2py(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=mxd2px(cpar[i*2+2]);
      xpoint[i].y=mxd2py(cpar[i*2+3]);
    }
    XDrawLines(Disp,mxlocal->win,mxlocal->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=mxd2px(cpar[i*2+3]);
      xpoint[i].y=mxd2py(cpar[i*2+4]);
    }
    if (cpar[2]==0) {
      XDrawLines(Disp,mxlocal->win,mxlocal->gc,
                 xpoint,cpar[1],CoordModeOrigin);
    } else if (cpar[2]==1) {
      XSetFillRule(Disp,mxlocal->gc,EvenOddRule);
      XFillPolygon(Disp,mxlocal->win,mxlocal->gc,
                   xpoint,cpar[1],Complex,CoordModeOrigin);
    } else {
      XSetFillRule(Disp,mxlocal->gc,WindingRule);
      XFillPolygon(Disp,mxlocal->win,mxlocal->gc,
                   xpoint,cpar[1],Complex,CoordModeOrigin);
    }
    memfree(xpoint);
    break;
  case 'F':
    memfree(mxlocal->fontalias);
    if ((mxlocal->fontalias=memalloc(strlen(cstr)+1))==NULL) break;
    strcpy(mxlocal->fontalias,cstr);
    break;
  case 'H':
    fontspace=cpar[2]/72.0*25.4;
    mxlocal->fontspace=fontspace;
    fontsize=cpar[1]/72.0*25.4;
    mxlocal->fontsize=fontsize;
    fontcashsize=mxd2p(fontsize);
    fontcashdir=cpar[3];
    fontdir=cpar[3]*MPI/18000.0;
    fontsin=sin(fontdir);
    fontcos=cos(fontdir);
    mxlocal->fontsin=fontsin;
    mxlocal->fontcos=fontcos;
    mxlocal->loadfontf=mxloadfont(Disp,mxlocal->gc,
                                  mxlocal->fontalias,fontcashsize,fontcashdir,
                                  fontsin,fontcos,TRUE);
    break;
  case 'S':
    if (mxlocal->loadfontf==-1) break;
    x0=mxlocal->cpx;
    y0=mxlocal->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,mxlocal->win,mxlocal->gc,
                  mxd2px(nround(x0)),
                  mxd2py(nround(y0)),ch,1); 
      if ((mxlocal->font[0].fonttype==BOLD) 
       || (mxlocal->font[0].fonttype==BOLDITALIC)) {
        bs=mxlocal->fontsize*0.018;
        XDrawString(Disp,mxlocal->win,mxlocal->gc,
          mxd2px(nround(x0+bs)),
          mxd2py(nround(y0)),ch,1); 
        XDrawString(Disp,mxlocal->win,mxlocal->gc,
          mxd2px(nround(x0)),
          mxd2py(nround(y0-bs)),ch,1); 
        XDrawString(Disp,mxlocal->win,mxlocal->gc,
          mxd2px(nround(x0+bs)),
          mxd2py(nround(y0-bs)),ch,1); 
      }
      if ((mxlocal->font[0]).fontstruct==NULL) {
        fontwidth=mxp2d((mxlocal->font[0]).fontsize);
      } else {
        if ((mxlocal->font[0]).iso8859
        && mxlocal->minus_hyphen && (ch[0]=='-')) {
          ch[0]='+';
        }
        fontwidth=mxp2d(XTextWidth((mxlocal->font[0]).fontstruct,ch,1));
      }
      x0+=(fontwidth+mxlocal->fontspace)*mxlocal->fontcos;
      y0-=(fontwidth+mxlocal->fontspace)*mxlocal->fontsin; 
    }
    mxlocal->cpx=nround(x0);
    mxlocal->cpy=nround(y0);
    break;
  case 'K':
    if (mxlocal->loadfontf==-1) break;
    i=0;
    x0=mxlocal->cpx;
    y0=mxlocal->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,mxlocal->win,mxlocal->gc,
                  mxd2px(nround(x0)),
                  mxd2py(nround(y0)),kanji,1);
        if ((mxlocal->font[0].fonttype==BOLD) 
         || (mxlocal->font[0].fonttype==BOLDITALIC)) {
          bs=mxlocal->fontsize*0.018;
          XDrawString16(Disp,mxlocal->win,mxlocal->gc,
            mxd2px(nround(x0+bs)),
            mxd2py(nround(y0)),kanji,1); 
          XDrawString16(Disp,mxlocal->win,mxlocal->gc,
            mxd2px(nround(x0)),
            mxd2py(nround(y0-bs)),kanji,1); 
          XDrawString16(Disp,mxlocal->win,mxlocal->gc,
            mxd2px(nround(x0+bs)),
            mxd2py(nround(y0-bs)),kanji,1); 
        }
        if ((mxlocal->font[0]).fontstruct==NULL) {
          fontwidth=mxp2d((mxlocal->font[0]).fontsize);
        } else {
          fontwidth=mxp2d(XTextWidth16((mxlocal->font[0]).fontstruct,kanji,1));
        }
        x0+=(fontwidth+mxlocal->fontspace)*mxlocal->fontcos;
        y0-=(fontwidth+mxlocal->fontspace)*mxlocal->fontsin;
        i+=2;
      } else i++;
    }
    mxlocal->cpx=nround(x0);
    mxlocal->cpy=nround(y0);
    break;
  default: break;
  }
  return 0;
}

int mx_charwidth(struct objlist *obj,char *inst,char *rval,
                    int argc,char **argv)
{
  struct mxlocal *mxlocal;
  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,&mxlocal)) return 1;
  fontcashsize=mxd2p(size);
  if ((cashpos=mxloadfont(Disp,NULL,font,fontcashsize,0,0.0,1.0,FALSE))!=-1) {
    fontstruct=(mxlocal->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=mxp2d(XTextWidth16(fontstruct,kanji,1));
      } else {
        if ((mxlocal->font[cashpos]).iso8859 && mxlocal->minus_hyphen
        && (ch[0]=='-')) {
          ch[0]='+';
        }
        *(int *)rval=mxp2d(XTextWidth(fontstruct,ch,1));
      }
    }
  } else *(int *)rval=nround(size*0.600);
  return 0;
}

int mx_charheight(struct objlist *obj,char *inst,char *rval,
                  int argc,char **argv)
{
  struct mxlocal *mxlocal;
  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,&mxlocal)) return 1;
  fcur=mxlocal->fontmaproot;
  twobyte=FALSE;
  while (fcur!=NULL) {
    if (strcmp(font,fcur->fontalias)==0) {
      twobyte=fcur->twobyte;
      break;
    }
    fcur=fcur->next;
  }        
  fontcashsize=mxd2p(size);
  if ((cashpos=mxloadfont(Disp,NULL,font,fontcashsize,0,0.0,1.0,FALSE))!=-1) {
    fontstruct=(mxlocal->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=mxp2d(fontstruct->ascent);
      else *(int *)rval=mxp2d(fontstruct->descent);
    }
  } else {
    if (height) *(int *)rval=nround(size*0.562);
    else *(int *)rval=nround(size*0.250);
  }
  return 0;
}

int mxfullpathngp(struct objlist *obj,char *inst,char *rval,int argc,char **argv)
{
  char *name,*ngp2;

  name=(char *)argv[2];
  if (name==NULL) ngp2=NULL;
  else ngp2=getbasename(name);
  putobj(menulocal.obj,"ngp",0,ngp2);
  return 0;
}

#define TBLNUM 17

struct objtable x11menu[TBLNUM] = {
  {"init",NVFUNC,NEXEC,menuinit,NULL,0},
  {"done",NVFUNC,NEXEC,menudone,NULL,0},
  {"menu",NVFUNC,NREAD|NEXEC,menumenu,NULL,0},
  {"ngp",NSTR,NREAD|NWRITE,NULL,NULL,0},
  {"fullpath_ngp",NSTR,NREAD|NWRITE,mxfullpathngp,NULL,0},
  {"dpi",NINT,NREAD|NWRITE,mxdpi,NULL,0},
  {"auto_redraw",NBOOL,NREAD|NWRITE,mxautoredraw,NULL,0},
  {"redraw_flag",NBOOL,NREAD|NWRITE,mxredrawflag,NULL,0},
  {"redraw",NVFUNC,NREAD|NEXEC,mxredraw,"",0},
  {"flush",NVFUNC,NREAD|NEXEC,mxflush,"",0},
  {"clear",NVFUNC,NREAD|NEXEC,mxclear,"",0},
  {"_output",NVFUNC,0,mx_output,NULL,0},
  {"_charwidth",NIFUNC,0,mx_charwidth,NULL,0},
  {"_charascent",NIFUNC,0,mx_charheight,NULL,0},
  {"_chardescent",NIFUNC,0,mx_charheight,NULL,0},
  {"_evloop",NVFUNC,0,mx_evloop,NULL,0},
  {"_local",NPOINTER,0,NULL,NULL,0},
};

void *addmenu()
{
  return addobject(NAME,ALIAS,PARENT,VERSION,TBLNUM,x11menu,ERRNUM,
                   menuerrorlist,NULL,NULL);
}
