
#include "x11-graph.h"

#include "gx11-message-c.h"
#include "x11-window.h"
#include "gsys/sic_util.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>

#define VERSION "$Revision$ $Date$"

#define NPLANES 0
#define NFIRST 96 /* instead of 104 (256-128-16-8) because the Motif Widget Bar
		     Needs some colors also */
#define NPEN 16
#define CONTIG 0
#define DIRECT 0
#define REVERSE 1
#define TRUE  1
#define FALSE 0

/* event_mask1 are windowing events */
/* StructureNotifyMask enables DestroyNotify event */
#define event_mask0 (ExposureMask|StructureNotifyMask)
#define event_mask1 (event_mask0|ColormapChangeMask)

#define BORDURE 0
#define DoRGB (DoRed|DoGreen|DoBlue)

typedef unsigned char Byte;  /* byte type */

static Visual  *vis;
static GC      GCsp,GCx=NULL;
static Cursor	curseur;

static int wait_display;
static Colormap cmap;
static Colormap default_cmap;
static XColor first_defs[NFIRST];
static unsigned long firstcolors[NFIRST];

/* flag_cross = TRUE for a large crosshair
                FALSE for a small crosshair*/
static int flag_cross;
static int flag_color_display;
static int flag_static_display;
/* flag_pixmap = TRUE for PseudoColor displays
                 FALSE for StaticColor/Grey displays */
static int flag_pixmap;
static int widthofscreen,heightofscreen;
/* ncol est le nombre de points maximum de la colormap
 * Ca va mieux en le disant, ca evite de confondre avec les couleurs de Greg */
static unsigned ncol;

static int Height_default,Width_default;

static XColor tabcolor[NTAB];
/* Nombre de couleurs modifiables des plumes */
static unsigned pen_ncol;
static unsigned pen_col_size;  /* size of RGB map */

/* pour le type de lignes a tracer, pointillees, grasses etc. */
static int      line_style=LineSolid;
static int      width_style=0;
static int      cap_style=CapRound;
static int      join_style=JoinRound;

static char dash_pat[4]={1,1,1,1};

static int save_pen;
static unsigned long pixels_pen[NPEN];

static int ncells=0, ncells_pen=0;
static int named_colors[NFIXED];
static int pix_colors[NCOL];
static int pencil_colors[NPEN];
static int launch_other_XAPP=0;
static unsigned long pixels_ret[NCOL];

static unsigned long black_pix,white_pix;

static int pointer_step=1;

/*
 win_backg permet de commuter pour chaque fenetre la plume 0.
 Vrai pour white background. cf la note philosophique de X_PEN.
 He non, j'ai trouve le truc! on n'a pas besoin de tout ca!!. regarder le
 commentaire dans allocnamedcolors! (GD)

 offset_colormap:  Indique le deplacement dans la colormap
	 (C'est l'index dans la colormap de la premiere place libre.
      (Rendu par XAllocColorsCells))

 flag_backg = TRUE for a white background
              FALSE for a black background
 flag_backingstore = TRUE for backingstore
*/
static int flag_backingstore=FALSE;
static int flag_backg=FALSE;
static int flag_install=FALSE;
static int isAtDefaultDepth=1; /* =0 if we are fortunate enough to use a 8 bit, PseudoColor
				  visual on displays with more than 8 planes */

XVisualInfo OurVisualInfo; /*Will keep the values of the visual we use*/
/* the following are values deduced from the XVisualInfo above but more suited to */
/* our particular needs */
unsigned long red_max, blue_max, green_max, red_mult, blue_mult, green_mult;

/* info on the original window from whence we issued the open_x command
 * (this allows us to create the imaging window and return keyboard focus
 * to the command window so the user doesn't have to do it) */
static Window from_window=0;
static int revert_to;

static int X_ancrage,Y_ancrage;
static int err_alloc_color;

static void Allocnamedcolor(void);
int my_error_handler(Display*, XErrorEvent*);

Display *display = NULL;
Window root_win;
static Screen  *screen;
static int screen_number;
static unsigned depth;

int x11_open_display( char *display_name)
{
    char *env_display;
    char rname[] = "X";

    if (display_name == NULL || !display_name[0])
        display_name = getenv( "DISPLAY");
    if (display_name == NULL)
        display_name = ":0.0";
    display = XOpenDisplay( display_name);

    if (!display) {
        gx11_c_message(seve_e, rname, "Connection error");
        gx11_c_message(seve_d, rname, "Environment variable DISPLAY %s",
         env_display);
        return 1;
    }
    gx11_c_message(seve_d,rname,"DISPLAY %s",display_name);

    /* Now connection is opened */
    screen_number = DefaultScreen( display);
    root_win = RootWindow( display, screen_number);
    depth = DefaultDepth( display, screen_number);
    screen = XDefaultScreenOfDisplay( display);

    return 0;
}

long x11_get_integer_property(Window win, char *name)
{
    Atom atom;
    Atom actual_type;
    int actual_format;
    unsigned long nitems;
    unsigned long bytes_after;
    long ret = 0;
    char *tmp;
    char prop_name[256];

    sprintf( prop_name, "%s_%ld", name, (long)win);
    atom = XInternAtom(display, prop_name, True);
    if (XGetWindowProperty(display, root_win, atom, 0, sizeof(long),
        False, XA_STRING, &actual_type, &actual_format, &nitems,
        &bytes_after, (unsigned char **)&tmp) != Success) {
        fprintf(stderr, "XGetWindowProperty: error\n");
        return 0;
    }
    if (tmp != NULL)
        ret = *(long*)tmp;
    XFree( tmp);

    return ret;
}

void x11_set_integer_property( Window win, char *name, long value)
{
    Atom myatom;
    char prop_name[256];

    sprintf( prop_name, "%s_%ld", name, (long)win);
    myatom = XInternAtom( display, prop_name, False);
    XChangeProperty( display, root_win, myatom,
        XA_STRING, 8, PropModeReplace, (unsigned char *)&value, sizeof(value));
}

void x11_delete_integer_property( Window win, char *name)
{
    Atom myatom;
    char prop_name[256];

    sprintf( prop_name, "%s_%ld", name, (long)win);
    myatom = XInternAtom( display, prop_name, True);
    XDeleteProperty( display, root_win, myatom);
}

/*
 * ---------------------------------------------------------
 * SUBROUTINE NEW_GRAPH
 */
static void x11_new_graph(
               int backg,
               G_env *genv,
               char *dirname,
               int *x1, int *x2, int *y1, int *y2,
               fortran_type dir_cour,
               int reuse)
{
    char window_name[257];
    Window win_graph;
    static unsigned long main_win_graph;
    XSetWindowAttributes watt;
    XGCValues	gcvalues;
    unsigned int background,foreground;
    unsigned long valuemask;
    gx11_env_t *x11_genv = (gx11_env_t *)genv;
    int Width_graphique=genv->Width_graphique;
    int Height_graphique=genv->Height_graphique;
    int i, OK;
    Atom myatom;
    char atom_name[30];
    task_id_t pid;
    XWMHints gestw;
    char rname[] = "X";

    if (!Width_graphique) {
        Width_graphique = Width_default;
        genv->Width_graphique = Width_graphique;
    }
    if (Height_graphique <= 0) {
        Height_graphique = Height_default;
        genv->Height_graphique = Height_graphique;
    }
    pid = sic_get_master_task_id();

    genv->adr_dir = dir_cour;
    /* Definition du background et du foreground */
    if(backg) { background=white_pix; foreground=black_pix; }
    else { background=black_pix; foreground=white_pix; }

    if(reuse) {
        win_graph=x11_genv->win_graph;
        XFreeGC(display,x11_genv->myGC);
    }
    else
    {
#ifndef GAG_USE_GTK
        /* Creation d'une fenetre */
        if (isAtDefaultDepth) {
            /* old, is ok as long as the visual we use IS the default visual */
            x11_genv->win_graph=
                win_graph=XCreateSimpleWindow(display,root_win,X_ancrage,Y_ancrage,
                Width_graphique,Height_graphique,
                BORDURE,foreground,background);
            watt.backing_store=WhenMapped;
            XChangeWindowAttributes(display,win_graph,CWBackingStore,&watt);
            /* Small cursor */
            XDefineCursor(display,win_graph,curseur);
        }
        else
        {
            /*new: create a window vith the chosen Visual (and NOT the
            default one, which could mismatch the visual 'vis'
            obtained elsewhere */
            watt.colormap=cmap;
            watt.background_pixel=background;
            watt.border_pixel=foreground;
            watt.cursor=curseur;
            watt.backing_store=WhenMapped;
            valuemask = CWBackingStore|CWBackPixel|CWBorderPixel|
                CWColormap|CWCursor;
            /* create it */
            x11_genv->win_graph=
                win_graph=XCreateWindow(display,root_win,X_ancrage,Y_ancrage,
                Width_graphique,Height_graphique,
                BORDURE,depth,InputOutput,vis,
                valuemask,&watt);
        }
        /* Big cursor */
        if(flag_pixmap) {
            if(flag_cross) {
                x11_genv->vertical=XCreatePixmap(display,win_graph,1,Height_graphique,depth);
                x11_genv->horizontal=XCreatePixmap(display,win_graph,Width_graphique,1,depth);
            }
            x11_genv->box1=XCreatePixmap(display,win_graph,1,Height_graphique,depth);
            x11_genv->box2=XCreatePixmap(display,win_graph,Width_graphique,1,depth);
            x11_genv->box3=XCreatePixmap(display,win_graph,1,Height_graphique,depth);
            x11_genv->box4=XCreatePixmap(display,win_graph,Width_graphique,1,depth);
        }
#endif
    }

#ifndef GAG_USE_GTK
    /* colormap inheritance */
    if (ncells != 0 && isAtDefaultDepth) {
        XSetWindowColormap(display, win_graph, cmap);
        XSetWindowColormap(display, from_window, cmap);
    }
    /* rappellons nous du fond de cette fenetre */
    genv->win_backg=backg;
    /* Creation d'un GC bien a nous
    * Sert a gerer la couleur background et foreground des fenetres
    * et la plume courante... */
    gcvalues.foreground=foreground; gcvalues.background=background;
    gcvalues.graphics_exposures=FALSE;
    x11_genv->myGC=XCreateGC(display,win_graph,
        GCGraphicsExposures|GCBackground|GCForeground,&gcvalues);
    /* Donnons un nom a la fenetre */
    strcpy( window_name, dirname);

    XStoreName(display,win_graph,window_name);
    /* Prevent focus in STATIC graphic window (focus is only needed when
    * using the cursor, however focus is needed in dynamic displays to reload
    * their colormap) */
    gestw.input = (flag_static_display==1)?FALSE:TRUE;
    gestw.flags = InputHint;
    XSetWMHints(display, win_graph, &gestw);

    XMapWindow(display,win_graph);
    XSelectInput(display,win_graph,event_mask1);
#endif

    if(!reuse) {
#ifndef GAG_USE_GTK
        XEvent 	event;
        /* Attente que la fenetre soit affichee
        * Je pense qu'il y en a besoin pour qu'une demande d'affichage survenant
        * immediatement apres l'open se fasse, sinon X etant asynchrone, l'affichage
        * pourrait etre demande avant que la fenetre ne soit reellement apparue sur
        * l'ecran, et ne pas se faire .. */
        OK=(wait_display==0);
        while(OK) {
            XWindowEvent(display,win_graph,event_mask1,&event);
            if(event.type==Expose && !event.xexpose.count) OK=0;
        }
#endif

        if (launch_other_XAPP) {
            static int firstpass= 1;
            static gx11_toolbar_args_t args;
            int launch_dialog = 0;

            if (firstpass) {
                XSetErrorHandler(my_error_handler);

                gx11_c_message(seve_t,rname,"gtvirt: launching GTV_MOTIF:");
                firstpass = 0;
                launch_dialog = 1;
            }
#ifdef GAG_USE_GTK
            else {
                launch_dialog = 1;
            }
#else
            else {
                int my_ret = -1;
                XWindowAttributes attrib;

                my_ret = XGetWindowAttributes(display, main_win_graph, &attrib);

                if ((main_win_graph == win_graph) || (my_ret == 0)) {
                    launch_dialog = 1;
                }
            }
#endif
            if (launch_dialog) {
                for (i=0; i<ncells; i++)
                    pix_colors[i] = pixels_ret[i];
                for (i=0; i<NFIXED; i++)
                    named_colors[i] = tabcolor[i].pixel;
                for (i=0; i<ncells_pen; i++)
                    pencil_colors[i] = pixels_pen[i];
                args._herit.cmap = cmap;
                strcpy( args._herit.lut_path, sic_s_get_logical_path( "GAG_LUT:"));
                strcpy( args._herit.tmp_path, sic_s_get_logical_path( "GAG_TMP:"));
                args._herit.pix_colors = pix_colors;
                args._herit.named_colors = named_colors;
                args._herit.pencil_colors = pencil_colors;
                if (!flag_static_display) {
                    args._herit.ncells = ncells;
                    args._herit.ncells_pen = ncells_pen;
                } else {
                    args._herit.ncells = 0;
                    args._herit.ncells_pen = 0;
                }

                gx11_c_message(seve_t,rname,"new win id %d",    (int)win_graph);
                gx11_c_message(seve_t,rname,"cmap %d",          (int)cmap);
                gx11_c_message(seve_t,rname,"pix_colors %d",    pix_colors[0]);
                gx11_c_message(seve_t,rname,"ncells %d",        ncells);
                gx11_c_message(seve_t,rname,"named_colors %d",  named_colors[0]);
                gx11_c_message(seve_t,rname,"pencil_colors %d", pencil_colors[0]);
                gx11_c_message(seve_t,rname,"ncells_pen %d",    ncells_pen);

#ifdef GAG_USE_GTK
                args._herit.win_graph = 0;
                args._herit.win_width = Width_graphique;
                args._herit.win_height = Height_graphique;
                args._herit.win_main = 0;
#else /* GAG_USE_GTK */
                args._herit.win_graph = win_graph;
                main_win_graph = x11_genv->win_graph;
#endif /* GAG_USE_GTK */
                args.env = x11_genv;
                args.window_name = dirname;
                launch_gtv_toolbar( (gtv_toolbar_args_t *)&args);
#ifdef GAG_USE_GTK
                sic_wait_widget_created( );
                XFlush( display);
                win_graph =
                    x11_genv->win_graph =
                    args._herit.win_graph;
                x11_genv->win_main = args._herit.win_main;
#endif /* GAG_USE_GTK */
            }

#ifndef GAG_USE_GTK
            x11_genv->win_main = x11_genv->win_graph;
            sprintf(atom_name, "NEWWIN_%d_%d", pid, (int)win_graph);
            myatom = XInternAtom(display, atom_name, 0);

            XChangeProperty(display, root_win, myatom, XA_STRING,
                8, PropModeReplace, (unsigned char *) "NONE",
                strlen("NONE"));
#endif /* GAG_USE_GTK */
        }
    }
    else { XClearWindow(display,win_graph); XFlush(display); }

    x11_set_integer_property( win_graph, "GENV", (long)genv);

#ifdef GAG_USE_GTK
    /* Big cursor */
    if(flag_pixmap) {
        if(flag_cross) {
            x11_genv->vertical=XCreatePixmap(display,win_graph,1,Height_graphique,depth);
            x11_genv->horizontal=XCreatePixmap(display,win_graph,Width_graphique,1,depth);
        }
        x11_genv->box1=XCreatePixmap(display,win_graph,1,Height_graphique,depth);
        x11_genv->box2=XCreatePixmap(display,win_graph,Width_graphique,1,depth);
        x11_genv->box3=XCreatePixmap(display,win_graph,1,Height_graphique,depth);
        x11_genv->box4=XCreatePixmap(display,win_graph,Width_graphique,1,depth);
    }

    /* colormap inheritance */
    if (ncells != 0 && isAtDefaultDepth) {
        XSetWindowColormap(display, win_graph, cmap);
        XSetWindowColormap(display, from_window, cmap);
    }
    /* rappellons nous du fond de cette fenetre */
    genv->win_backg=backg;
    /* Creation d'un GC bien a nous
    * Sert a gerer la couleur background et foreground des fenetres
    * et la plume courante... */
    gcvalues.foreground=foreground; gcvalues.background=background;
    gcvalues.graphics_exposures=FALSE;
    x11_genv->myGC=XCreateGC(display,win_graph,
        GCGraphicsExposures|GCBackground|GCForeground,&gcvalues);
    /* Donnons un nom a la fenetre */
    strcpy( window_name, dirname);

    XStoreName(display,win_graph,window_name);
    /* Prevent focus in STATIC graphic window (focus is only needed when
    * using the cursor, however focus is needed in dynamic displays to reload
    * their colormap) */
    gestw.input = (flag_static_display==1)?FALSE:TRUE;
    gestw.flags = InputHint;
    XSetWMHints(display, win_graph, &gestw);

    XMapWindow(display,win_graph);
    XSelectInput(display,win_graph,event_mask1);
    /* Sauvegarde du contexte et retour de l'adresse de la structure */

    if (flag_backingstore) {
        watt.backing_store=Always;
        XChangeWindowAttributes(display,win_graph,CWBackingStore,&watt);
    }
#endif
    *x1= *y2=1;
    *x2=Width_graphique-1; *y1=Height_graphique-1;
}

/*----------------------------------------------------------------------
 * Module 2
 * C-Function Allocnamedcolor()
 *
 * Allocation de 8 ou 4 couleurs nommees.
 */
static void Allocnamedcolor(void)
{
  int    i,j=(depth==4) ? 4 : 7,err=err_alloc_color,flag=flag_backg;
  int    k=(flag_color_display)?0:1;
  float  delta;
  XColor exact;
  static char str_col[2][8][8] = {
    {"black","white","red","green","blue","cyan","yellow","magenta"},
    {"black","white","grey42","grey70","grey14","grey28","grey56","grey84"},
  };
  char rname[] = "X";

  /*Please note that we in fact allocate white in tabcolor at index 0 and
    black at index 7. A trick in X_PEN insures that the color '0'  is ALWAYS
    the 'good' foreground value, and that the color number 7 is always the
    same as the background, [depending on the background value], by
    referring to index 7 or 0 of tabcolor accordingly.  Other colors (i.e.,
    1 to 6) will draw the subsequent graphics in that very color, regardless
    of the background. So, colors 0 and 7 ARE special. The trick used here goes
    in parallel with the trick in X_PEN, so modifying one implies modify
    the other. flag is used only as a reminder of the previous trick. GD.*/

  flag=0;
  if (!XAllocNamedColor(display,cmap,str_col[k][flag],tabcolor,&exact)) err++;
  gx11_c_message(seve_t,rname,"Allocating color %s pen %d",str_col[k][flag],0);
  for (i=1;i<j;i++) {
    gx11_c_message(seve_t,rname,"Allocating color %s pen %d",str_col[k][i+1],i);
    if (!XAllocNamedColor(display,cmap,str_col[k][i+1],tabcolor+i,&exact)) err++;
  }
  if (depth==4) {
    if (err) gx11_c_message(seve_w,rname,"Allocation Named colors failed %d time(s)",
        err);
    for (i=0;i<4;i++) tabcolor[i+4]=tabcolor[i+8]=tabcolor[i+12]=tabcolor[i];
    err_alloc_color=err; return;
  }
  flag=1;
  if (!XAllocNamedColor(display,cmap,str_col[k][flag],tabcolor+7,&exact)) err++;
  gx11_c_message(seve_t,rname,"Allocating color %s pen %d",str_col[k][flag],7);
  if (err) {
    gx11_c_message(seve_w,rname,"Allocation Named colors failed %d time(s)",err);
  } else {
    gx11_c_message(seve_t,rname,"Allocation Named colors OK");
  }

  pen_col_size=pen_ncol=ncells_pen=NPEN;
  delta=((float)MAX_INTENSITY)/NPEN;

  if(flag_static_display) {
    for(i=0;i<NPEN;i++) {
      tabcolor[i+8].red=tabcolor[i+8].green=tabcolor[i+8].blue=(NPEN-i)*delta;
      tabcolor[i+8].flags=DoRGB;
      if(!XAllocColor(display,cmap,tabcolor+i+8)) {err++;ncells_pen--;}
      gx11_c_message(seve_t,rname,
		"pixel %d (index %d) of fill colormap is %d %d %d",
		i,(int)tabcolor[i+8].pixel,
		tabcolor[i+8].red,tabcolor[i+8].green,tabcolor[i+8].blue);
    }
  }
  else {
    if (!XAllocColorCells(display,cmap,CONTIG,NULL,NPLANES,pixels_pen,NPEN)) {
      gx11_c_message(seve_w,rname,"Allocation of PEN colors failed");
      pen_ncol=ncells_pen=0; }
    else {
      for(i=0;i<NPEN;i++) {
	tabcolor[i+8].red=tabcolor[i+8].green=tabcolor[i+8].blue=(NPEN-i)*delta;
	tabcolor[i+8].flags=DoRGB; tabcolor[i+8].pixel=pixels_pen[i];
      }
      XStoreColors(display,cmap,tabcolor+8,NPEN);
      gx11_c_message(seve_t,rname,"Allocation of PEN colors OK");
    }
  }
  XFlush(display); err_alloc_color=err;
}


void x11_create_edit_lut_window()
{
  if (ncells == 0) {
    gx11_c_message(seve_u,"X","You must use a non-static color display to edit colors...");
    return;
  }
}

int my_error_handler(Display *display, XErrorEvent *myerr)
{
  char msg[80];
  XGetErrorText(display, myerr->error_code, msg, 80);
  gx11_c_message(seve_e,"ERROR_HANDLER","Error code %s\n", msg);
  return 0;  /* return statement needed (DB) */
}

/*
 *----------------------------------------------------------------------
 * Module 20
 *  SUBROUTINE X_PEN
 *  Changer de plume
 *----------------------------------------------------------------------
 */
void x11_x_pen_invert(G_env *genv)
{
    gx11_c_message(seve_f,"X11_X_PEN_INVERT","Not implemented");
}

/*
 * ---------------------------------------------------------------------
 * SUBROUTINE X_FILL_POLY
 *
 * Remplissage de polygone
 *
 * Note philosophique:
 * J'ai constate que si le polygone a tracer n'est pas ferme
 * il n'est pas trace ..
 * ---------------------------------------------------------------------
 */

void x11_x_fill_poly(G_env *genv, int npts_poly, int *tabx, int *taby)
{
  XPoint tab_fill[1024];
  int i;
  for(i=0;i<npts_poly;i++)
    { tab_fill[i].x=tabx[i]; tab_fill[i].y=taby[i]; }
  XFillPolygon(display,((gx11_env_t *)genv)->win_graph,((gx11_env_t *)genv)->myGC,tab_fill,npts_poly,
	       Complex,CoordModeOrigin);
}

/*
 *----------------------------------------------------------------------
 * Module 15
 * Restaure les pixmaps vertical et horizontal
 *----------------------------------------------------------------------
 */
void x11_rest_pix_cross(G_env *genv, int x, int y, int width, int height, int flg_zoom)
{
  gx11_env_t *cur=(gx11_env_t *)genv;
  int gwidth=cur->_herit.Width_graphique,gheight=cur->_herit.Height_graphique;
  Window win_graph=cur->win_graph;
  if(flag_pixmap) {
    GC myGC=cur->myGC;
    if(flag_cross) {
      XCopyArea(display,cur->vertical,win_graph,myGC,0,0,1,gheight,x,0);
      XCopyArea(display,cur->horizontal,win_graph,myGC,0,0,gwidth,1,0,y);
    }
    if(flg_zoom) {
      XCopyArea(display,cur->box1,win_graph,myGC,0,0,1,gheight,x-width,0);
      XCopyArea(display,cur->box3,win_graph,myGC,0,0,1,gheight,x+width,0);
      XCopyArea(display,cur->box2,win_graph,myGC,0,0,gwidth,1,0,y-height);
      XCopyArea(display,cur->box4,win_graph,myGC,0,0,gwidth,1,0,y+height);
    }
  }
  else {
    if(flag_cross) {
      XDrawLine(display,win_graph,GCsp,x,0,x,gheight);
      XDrawLine(display,win_graph,GCsp,0,y,gwidth,y);
    }
    if(flg_zoom)
      XDrawRectangle(display,win_graph,GCsp,x-width,y-height,width*2,height*2);
  }
}

#define min(a,b) (((a)<(b))? (a):(b))
#define max(a,b) (((a)>(b))? (a):(b))

static int prev_rx, prev_ry, prev_width, prev_height, edit=0;


void x11_ask_for_corners( int *ax, int *bx, int *ay, int *by)
{
  *ax = prev_rx;
  *bx = prev_rx + prev_width + 1;

  *ay = prev_ry;
  *by = prev_ry + prev_height + 1;
}

/*
 *----------------------------------------------------------------------
 * Module 19
 *  SUBROUTINE        X_MOVE_CURSOR(dx,dy)
 *      Deplace le curseur de Dx,Dy pixels
 *
 *----------------------------------------------------------------------
 */
void x_move_cursor(G_env *genv, int *dx, int *dy)
{ XWarpPointer(display,((gx11_env_t *)genv)->win_graph,None,0,0,0,0,*dx,*dy); }

/*----------------------------------------------------------------------
 * SUBROUTINE x11_x_weigh(width)
 *
 * appelle par le fortran, cette routine place la largeur de ligne.
 */
void x11_x_weigh(G_env *genv, int width)
{
  width_style= width;
  /* pen of width 1 is forced to width 0 (fast mode) */
  if(width_style<2) width_style=0;
  XSetLineAttributes(display,((gx11_env_t *)genv)->myGC,width_style,line_style,
                     cap_style,join_style);
  XFlush(display);
}
/*----------------------------------------------------------------------
 * SUBROUTINE X_DASH(dashed,pattern)
 *
 * appelle par le fortran, cette routine place le style de pointille.
 */
void x11_x_dash(G_env *genv, int flag_dash, int ds[4])
{

  if(flag_dash) {
    int i;
    for(i=0;i<4;i++) dash_pat[i]=ds[i];
    line_style=LineOnOffDash; cap_style=CapButt;
    XSetDashes(display,((gx11_env_t *)genv)->myGC,0,dash_pat,4);

  }
  else { line_style=LineSolid; cap_style=CapProjecting; }

  XSetLineAttributes(display,((gx11_env_t *)genv)->myGC,width_style,line_style,
                     cap_style,join_style);
  XFlush(display);
}

/*
 *----------------------------------------------------------------------
 * Module ??
 *   SUBROUTINE X_SIZE
 *      Return the window size
 */
void x11_x_size(G_env *genv, int *larg, int *haut)
{
  unsigned int largeur,hauteur,Bordure_graphique;
  Window root_ret;

  XGetGeometry(display,((gx11_env_t *)genv)->win_graph,&root_ret,&X_ancrage,&Y_ancrage,
	       &largeur,&hauteur,&Bordure_graphique,&depth);
  *larg=largeur; *haut=hauteur;
}

/*
 *----------------------------------------------------------------------
 * Module 21
 *   SUBROUTINE X_TEST_EVENT
 *        X_TEST_EVENT
 *        Evenement special
 *
 * Note philosophique 1:
 * --------------------
 * En fortran x_test_event est un logique, qui est teste, en particulier,
 * dans gtview. S'il est vrai l'appel est transforme en gtview('Rewind'),
 * ce qui sert alors a "repeindre" la fenetre qui vient d'etre demasquee.
 * Or cela devient inutile si le terminal gere le Backing Store.
 *
 * Le fonctionnement a ete modifie de la maniere suivante.
 *	1) Pour expose et visibility on tient compte du Backing Store
 *	2) Pour ConfigureNotify on ne le prend en compte (pour faire
 *	   GTVIEW('REWIND')) que si la fenetre a ete effectivement
 *	   redimensionnee.
 *
 * Note philosophique 2:
 * --------------------
 * ATTENTION,bien remarquer que l'on augmente val_ret de !flag_backingstore
 * (C.a.d l'inverse de sa valeur). Si flag_backingstore=1, alors
 * val_ret est inchange, a l'inverse, si flag_backingstore est nul,
 * alors val_ret est incremente.
 *
 *----------------------------------------------------------------------
 */
int x11_x_test_event(G_env *genv, int *ix1, int *ix2, int *iy1, int *iy2)
{
  fprintf( stderr, "call to x11_x_test_event forbidden\n");
  return 0;
}

/*
 *----------------------------------------------------------------------
 * Module 14
 *      SUBROUTINE X_CURS
 *      curseur
 * Note philosophique 1:
 * --------------------
 * Le reticule que l'on dessine se fait avec la plume courante.
 * Je prefere un reticule blanc sur fond noir ou un reticule noir
 * sur fond blanc.
 * De plus, il faut eviter un reticule blanc sur fond blanc ...
 *
 *----------------------------------------------------------------------
 */
void x11_x_curs( gtv_zoom_data_t *data)
{
    G_env *env = data->env;
    int flg_zoom = data->flg_zoom;
    int zwidth = data->width;
    int zheight = data->height;
    KeySym  mykey;
    int first=0;
    int x_oldcurs = 0,y_oldcurs = 0,x_newcurs,y_newcurs;
    int pen_cour=save_pen,dash_cour=line_style,weigh_cour=width_style;
    int zero=0;
    gx11_env_t *genv=(gx11_env_t *)env;
    Window dummyroot,dummychild,win_graph=genv->win_graph;
    unsigned int dummy3;
    int dummy1,dummy2;
    GC cGC=(flag_pixmap) ? genv->myGC : GCsp;
    XEvent event;
    unsigned long event_mask2;
    int width=env->Width_graphique,height=env->Height_graphique;
    XWMHints gestw;
    XSizeHints sizehints,initialstate;
    long hints_supplied;

    /* Passons en plume 0 */
    // x11_x_pen(env, zero);
    x11_x_dash(env, zero,dash_pat);
    x11_x_weigh(env, zero);

    event_mask2=KeyPressMask|ButtonPressMask|EnterWindowMask|LeaveWindowMask;
    event_mask2 |=(flag_cross) ? PointerMotionMask:  PointerMotionHintMask;
    /* get normal state of the window */
    XGetWMNormalHints(display,win_graph,&initialstate,&hints_supplied);
    /* force fixed size to prevent a change of window size with the cursor*/
    sizehints.min_width=sizehints.max_width=width;
    sizehints.min_height=sizehints.max_height=height;
    sizehints.flags=(PMinSize|PMaxSize);
    XSetWMNormalHints(display,win_graph,&sizehints);
    /* add focus to the window on (all) displays */
    gestw.input = TRUE;
    gestw.flags = InputHint;
    XSetWMHints(display, win_graph, &gestw);
    XSelectInput(display,win_graph,event_mask2);
    XRaiseWindow(display,win_graph);
    /* move to the window if not there already */
    XQueryPointer(display,win_graph,&dummyroot,&dummychild,&dummy1,&dummy2,
        data->xpos,data->ypos,&dummy3);
    if (*data->xpos < 0 || *data->xpos > width || *data->ypos < 0 ||
     *data->ypos>height)
        XWarpPointer(display,None,win_graph,0,0,0,0,width>>1,height>>1);
    /* generate a motion event */
    else  {
        XGrabKeyboard(display,win_graph,False,
            GrabModeAsync,GrabModeAsync,CurrentTime);
        XWarpPointer(display,win_graph,None,0,0,0,0,0,0);
    }
    while(1) {
        XWindowEvent(display,win_graph,event_mask2,&event);
        switch(event.type) {
        case EnterNotify:
            XGrabKeyboard(display,win_graph,False,
                GrabModeAsync,GrabModeAsync,CurrentTime);
            XFlush(display);
            break;
        case LeaveNotify:
            XUngrabKeyboard(display,CurrentTime);
            XFlush(display);
            break;
        case KeyPress:
            XLookupString(&event.xkey,data->command,1,&mykey,NULL);
            if(mykey<=255*256) goto fin;
            else switch(mykey) {
        case XK_Left:
            XWarpPointer(display,win_graph,None,0,0,0,0,-pointer_step,0);
            break;
        case XK_Up:
            XWarpPointer(display,win_graph,None,0,0,0,0,0,-pointer_step);
            break;
        case XK_Right:
            XWarpPointer(display,win_graph,None,0,0,0,0,pointer_step,0);
            break;
        case XK_Down:
            XWarpPointer(display,win_graph,None,0,0,0,0,0,pointer_step);
            break;
        case XK_KP_F1: pointer_step=1;
            break;
        case XK_KP_F2: pointer_step=4;
            break;
        case XK_KP_F3: pointer_step=16;
            break;
        case XK_KP_F4: pointer_step=64;
            break;
            }
            break;
        case MotionNotify:
            if (event.type==MotionNotify){
                x_newcurs=event.xmotion.x; y_newcurs=event.xmotion.y;
            }
            else {
                x_newcurs=event.xcrossing.x; y_newcurs=event.xcrossing.y;
            }
            if (!first)
                first=1;
            else
                x11_rest_pix_cross(env, x_oldcurs,y_oldcurs,zwidth,zheight,flg_zoom);
            x_oldcurs=x_newcurs; y_oldcurs=y_newcurs;
            if (flag_pixmap)	{ /* save_pix_cross */
                if (flg_zoom) {
                    XCopyArea(display,win_graph,genv->box1,cGC,
                        x_oldcurs-zwidth,0,1,height,0,0);
                    XCopyArea(display,win_graph,genv->box3,cGC,
                        x_oldcurs+zwidth,0,1,height,0,0);
                    XCopyArea(display,win_graph,genv->box2,cGC,
                        0,y_oldcurs-zheight,width,1,0,0);
                    XCopyArea(display,win_graph,genv->box4,cGC,
                        0,y_oldcurs+zheight,width,1,0,0);
                }
                if (flag_cross) {
                    XCopyArea(display,win_graph,genv->vertical,cGC,
                        x_oldcurs,0,1,height,0,0);
                    XCopyArea(display,win_graph,genv->horizontal,cGC,
                        0,y_oldcurs,width,1,0,0);
                }
            }
            if (flg_zoom) {
                XDrawRectangle(display,win_graph,cGC,
                    x_oldcurs-zwidth,y_oldcurs-zheight,zwidth*2,zheight*2);
            }
            if (flag_cross) {
                XDrawLine(display,win_graph,cGC,x_oldcurs,0,x_oldcurs,height);
                XDrawLine(display,win_graph,cGC,0,y_oldcurs,width,y_oldcurs);
            }
            break;
        case ButtonPress:
            switch(event.xbutton.button) {
            case Button1: *data->command = '^'; break;
            case Button2: *data->command = '&'; break;
            case Button3: *data->command = '*'; break;
            default: printf("Undefined mouse button number: %d\n", event.xbutton.button); break;
            }
            goto fin;
        } /* fin du switch */
    } /* fin du while */

    /* Clears last cross written inside before exiting */
fin: if(first) x11_rest_pix_cross(env, x_oldcurs,y_oldcurs,zwidth,zheight,flg_zoom);
    XQueryPointer(display,win_graph,&dummyroot,&dummychild,
        &dummy1,&dummy2,data->xpos,data->ypos,&dummy3);
    XUngrabKeyboard(display,CurrentTime);
    XSelectInput(display,win_graph,event_mask1);
    /* remove focus to the window on static display */
    gestw.input = (flag_static_display==1)?FALSE:TRUE;
    gestw.flags = InputHint;
    XSetWMHints(display, win_graph, &gestw);
    /* give back the right to change the window size*/
    sizehints.min_width=32;
    sizehints.max_width=widthofscreen;
    sizehints.min_height=32;
    sizehints.max_height=heightofscreen;
    sizehints.flags=(PMinSize|PMaxSize);
    XSetWMNormalHints(display,win_graph,&sizehints);
    XFlush(display);
    /* Restauration de la plume */
    // x11_x_pen(env, pen_cour);
    x11_x_dash(env, dash_cour,dash_pat);
    x11_x_weigh(env, weigh_cour);
}

void x11_other_x_curs( G_env *genv, char *cde)
{
  int pen_cour=save_pen,dash_cour=line_style,weigh_cour=width_style;
  int zero=0;
  gx11_env_t *cur=(gx11_env_t *)genv;
  Window dummyroot,dummychild,win_graph=cur->win_graph;
  unsigned int dummy3;
  int dummy1,dummy2;
  XEvent event;
  unsigned long event_mask2;
  int width=cur->_herit.Width_graphique,height=cur->_herit.Height_graphique;

  static int xpos_curs, ypos_curs;

  int x, y;
  long d, D;
  int n, N=0;
  static int xr, yr;         /* reference coordinates (BUTTON PRESS event) */
  static int prev_x, prev_y; /* previous pointer relative position */
  static int xs[4], ys[4];   /* box corners */

  int rx, ry, bwidth, bheight;
  static int firstpass = 1;
  static XGCValues xor_gcvalues;
  static int move;

  if (firstpass) {
    if (GCx != NULL) XFreeGC(display, GCx);

    if (flag_backg) {
      xor_gcvalues.foreground=~black_pix;
    } else {
      xor_gcvalues.foreground=~white_pix;
    }
    xor_gcvalues.function=GXxor;
    xor_gcvalues.line_width = 2;
    xor_gcvalues.plane_mask = 0x11111111;
    GCx=XCreateGC(display,win_graph,
		  GCPlaneMask|GCFunction|GCLineWidth|GCForeground,
		  &xor_gcvalues);
    firstpass = 0;
  }


  /* Passons en plume 0 */
  // x11_x_pen(genv, zero);
  x11_x_dash(genv, zero,dash_pat);
  x11_x_weigh(genv, zero);


  event_mask2=ButtonPressMask|Button2MotionMask|ButtonReleaseMask;

  XSelectInput(display,win_graph,event_mask2);

  XGrabKeyboard(display,win_graph,False,
		GrabModeAsync,GrabModeAsync,CurrentTime);


  XRaiseWindow(display,win_graph);
  /* move to the window if not there already */
  XQueryPointer(display,win_graph,&dummyroot,&dummychild,&dummy1,&dummy2,
		&xpos_curs,&ypos_curs,&dummy3);
  if(xpos_curs<0 || xpos_curs>width || ypos_curs<0 || ypos_curs>height)
    XWarpPointer(display,None,win_graph,0,0,0,0,width>>1,height>>1);
  /* generate a motion event */
  else   XWarpPointer(display,win_graph,None,0,0,0,0,0,0);

  while(1) {
    XWindowEvent(display,win_graph,event_mask2,&event);
    switch(event.type) {
    case ButtonPress:
      switch (event.xbutton.button) {
      case Button1:
	if (edit) {
	  firstpass = 1;
	  *cde = '^';
	  goto fin;
	}
	break;
      case Button3:
	if (edit) {
	  edit = 0;
	  XDrawRectangle(display, win_graph, GCx,
			 prev_rx, prev_ry, prev_width, prev_height);
	}
	firstpass = 1;
	*cde = '*';
	goto fin;
	break;
      case Button2:
	xr = event.xbutton.x;
	yr = event.xbutton.y;
	move = 0;

	if (!edit) {
	  /* initialize previous position */
	  prev_x = xr;
	  prev_y = yr;
	  prev_rx = xr;
	  prev_ry = yr;
	  prev_width = 0;
	  prev_height = 0;
	}

	else {
	  if ((xr >= prev_rx) && (xr <= prev_rx + prev_width) &&
	      (yr >= prev_ry) && (yr <= prev_ry + prev_height)) {
	    move = 1;
	    break;
	  }

	  /* find new corner */
	  D = 1E+8;
	  for (n=0; n<4; n++) {
	    d = ((ys[n] - yr)*(ys[n] - yr) + (xs[n] - xr)*(xs[n] - xr));
	    if (d < D) {
	      D = d;
	      N = n;
	    }
	  }

	  switch(N) {
	  case 0:
	    xr = xs[2];
	    yr = ys[2];
	    break;
	  case 1:
	    xr = xs[3];
	    yr = ys[3];
	    break;
	  case 2:
	    xr = xs[0];
	    yr = ys[0];
	    break;
	  case 3:
	    xr = xs[1];
	    yr = ys[1];
	    break;
	  }
	  /* re-initialize previous position */
	  prev_x = xs[N];
	  prev_y = ys[N];
	}
	break;
      }
      break;
    case MotionNotify:
      x = event.xmotion.x;
      y = event.xmotion.y;

      if (move) {
	if ((x - prev_width/2 < 0) ||
	    (x > width - prev_width/2) ||
	    (y - prev_height/2 < 0) ||
	    (y > height - prev_height/2)) break;
	bwidth = prev_width;
	bheight = prev_height;
	rx = x - bwidth/2;
	ry = y - bheight/2;
      }
      else {
	if ((x < 0) || (x > width) || (y < 0) || (y > height)) break;
	rx = min(xr, x);
	ry = min(yr, y);
	bwidth  = abs(x - xr);
	bheight = abs(y - yr);
      }

      XDrawRectangle(display, win_graph, GCx,
		     prev_rx, prev_ry, prev_width, prev_height);

      XDrawRectangle(display, win_graph, GCx,
		     rx, ry, bwidth, bheight);

      prev_x = x;
      prev_y = y;
      prev_rx = rx;
      prev_ry = ry;
      prev_width = bwidth;
      prev_height = bheight;

      break;

    case ButtonRelease:

      x = event.xbutton.x;
      y = event.xbutton.y;

      switch (event.xbutton.button) {
      case Button2:

	x = event.xbutton.x;
	y = event.xbutton.y;
	/*
	  xs[0] = xr;
	  ys[0] = yr;
	  xs[1] = prev_x;
	  ys[1] = yr;
	  xs[2] = prev_x;
	  ys[2] = prev_y;
	  xs[3] = xr;
	  ys[3] = prev_y;
	*/
	xs[0] = prev_rx;
	ys[0] = prev_ry;
	xs[1] = prev_rx + prev_width;
	ys[1] = prev_ry;
	xs[2] = prev_rx + prev_width;
	ys[2] = prev_ry + prev_height;
	xs[3] = prev_rx;
	ys[3] = prev_ry + prev_height;
	edit=1;

	break;
      }
      break;
    }
  } /* fin du while */

  /* Clears last cross written inside before exiting */
 fin:
  XUngrabKeyboard(display,CurrentTime);
  XSelectInput(display,win_graph,event_mask1); XFlush(display);
  /* Restauration de la plume */
  // x11_x_pen(genv, pen_cour);
  x11_x_dash(genv, dash_cour,dash_pat);
  x11_x_weigh(genv, weigh_cour);
}

/*--------------------------------------------------------
 * C-Function CREER_GENV
 */
static G_env *x11_creer_genv(void)
{
  gx11_env_t *env;

  if((env=(gx11_env_t *)calloc(1,sizeof(gx11_env_t)))!=0)
    {
      init_genv((G_env *)env);
    }
    return (G_env *)env;
}

/*----------------------------------------------------------------------
 * Module 22
 *      SUBROUTINE XIMAGE_LOADRGB(R,G,B,N,DIRECT)
 *      INTEGER N,DIRECT
 *      INTEGER RED(N),GREEN(N),BLUE(N)
 *
 * Note 1: C'est a la charge de l'appelant de faire correctement de
 *         decalage <<8
 * Note 2: Loin de moi l'idee de faire des remarques desobligeantes a mes
 *         petits camarades, mais, je doute quand meme un peu que l'option
 *         reverse ait marche telle quelle ........
 *
 * --reecrit le 09.06.92-------------------------------------
 * la nouvelle colormap sera chargee comme pseudo-colormap associee
 * a l'environnement courant. Ce ne sera peut-etre pas celle-ci
 * qui apparaitra a l'affichage, car cela depends du display (gestion
 * par la fonction set_colors), mais elle sera au moins defini pour
 * l'gx11_env_cour.
 */
void x11_ximage_loadrgb(int red[], int green[], int blue[], int n, int dir)
{
}

size_t x11_xcolormap_create( float red[], float green[], float blue[], int n, int is_default)
{
    XColor *colormap;
    XColor *color;
    int i;

    if ((colormap = (XColor *)calloc(n, sizeof(XColor))) == NULL) {
        gx11_c_message(seve_e, "X", "Fail to allocate  colormap");
        return 0;
    }

    for (i = 0, color = colormap; i < n; i++, color++) {
        color->red   = (int)  (red[i] * 65535 + 0.5);
        color->green = (int)(green[i] * 65535 + 0.5);
        color->blue  = (int) (blue[i] * 65535 + 0.5);
    }
    return (size_t)colormap;
}

void x11_xcolormap_delete( size_t colormap)
{
    free( (void *)colormap);
}

/*-----------------------------------------------------------------------
 * Module 24
 * SUBROUTINE XIMAGE_INQUIRE(Lcol,Ocol,Nx,Ny,IS_COLOR,IS_STATIC)
 *
 * Note philosophique:
 * -------------------
 * La modif faite est juste pour que ca passe a la compilation
 * Je pense qu'il faudrait compliquer un peu plus, en passant le numero
 * de la fenetre ...
 *-----------------------------------------------------------------------
 */
int x11_ximage_inquire( int *lcol, int *ocol, int *nx, int *ny, int *is_color,
 int *is_static)
{
  *lcol = 128;
  if(flag_static_display)
    *ocol=0;
  else
    *ocol=pixels_ret[0];
  *is_color=flag_color_display;
  *is_static=flag_static_display;
  *nx=Width_default;
  *ny=Height_default;
  return(1);
}

static void dither_line(int *curr, int *next, int width, int step)
{
  int i,error,tmp;

  if(step==RightToLeft) { next += width-1; curr += width-1; }
  for(i=0;i<width;i++) {
    tmp= *curr; *curr=(tmp > Threshold) ? MaxGrey : MinGrey;
    error=tmp - *curr;
    next[step] += error*3/16; *next += error*5/16;
    next -= step; curr -= step;
    *next += error*1/16; *curr += error*7/16;
  }
}

/*
 *-----------------------------------------------------------------------
 * SUBROUTINE X_AFFICHE_IMAGE
 *
 * On nous fournit une adresse d'une struct Image.
 * A nous de l'afficher en fonction du display que l'on possede.
 * Quelque soit le display, nous aurons une structure XImage et donc
 * un pixmap ou un bitmap, on les retournera pour qu'ils soient ecrits
 * dans le fichier.
 * modifie le 19.06.92
 *-----------------------------------------------------------------------
 */
void x11_x_affiche_image(
		     G_env *genv, size_t *adr_data,
		     int n_x0, int n_y0, int n_larg, int n_haut, int val_trou,
                     size_t colormap)
{
  XImage	*ximage;
  gx11_env_t		*cur=(gx11_env_t *)genv;
  int		largeur= n_larg,hauteur= n_haut,bpl=0;
  int		format=ZPixmap,ldepth=depth;
  Byte		*sdata=(Byte *)adr_data;	/* source data */
  int		dithering=NO_DITHERING;
  short         *adr;
  int           *adrl; /* not "long", which woulb 64 on 64bit machines... */
  char          mess[GAG_MAX_MESSAGE_LENGTH];
  /*
   * NOTE1:
   *    he oui,le gray_dithering est presque la (deja au niveau des colorcells)
   *       mais la fonction n'existe pas encore. Peu de travail reste a faire,
   *       l'algo de dithering deux niveaux doit pouvoir facilement etre adapte a
   *       ncol niveaux. Enfin en attendant ce sera un dithering deux niveau dans
   *       tous les cas.
   * NOTE2:
   *       Quand au COLOR_DITHERING il se rencontrera sur une static color.
   *       bien du plaisir pour un dithering en couleurs (la, j'ai pas)
   *       Il est pour le moment, lui aussi, simule par un dithering deux niveau.
   *       (MAIS PAS VERIFIE , je n'ai pas de telle console sous la main).
   */
  if(dithering!=NO_DITHERING) {
    unsigned	i,j,k;		/* loop counters */
    unsigned	size;
    XColor	*col=(XColor *)colormap;

    if(dithering==BW_DITHERING) {
      Byte		*dst;	/* destination data */
      Byte		*src;		/* source data */
      int			*curr,*buff;	/* current line buffer */
      int			*next;		/* next line buffer */
      int			*swap;		/* for swapping line buffers */
      unsigned	dll;		/* destination line length in bytes */
      int			trou;
      unsigned	val,pixel;
      double		tmp;
      /* Passe de dithering deux niveaux, puis recuperation. */
      /* simple floyd-steinberg dither with serpentine raster processing */
      format=XYBitmap; ldepth=1;
      sprintf(mess, "Dithering image ... ");
      /* compute the grey level for each entry and store it in col[]. */
      for(i=0;i<128;i++,col++)
	{
	  tmp=col->red*RED_PERCENT+col->green*GREEN_PERCENT+col->blue*BLUE_PERCENT;
	  val=(tmp/MAX_INTENSITY)*MaxGrey;
	  /* a _very_ simple tone scale adjustment routine. provides a piecewise
	   * linear mapping according to the following:
	   *      input:          output:
	   *     0 (MinGrey)    0 (MinGrey)
	   *     Threshold      Threshold/2
	   *     MaxGrey        MaxGrey
	   * this should help things look a bit better on most displays. */
	  col->pixel=(val<Threshold) ? val/2 :
	    (((val-Threshold)*(MaxGrey-(Threshold/2)))
	     /(MaxGrey-Threshold))+(Threshold/2);
	}
      dll=(largeur/8)+(largeur % 8 !=0); /* thanx johnh@amcc.com */
      trou= val_trou; size=largeur+2;
      buff=(int *)calloc(sizeof(int),size*2); curr=buff+1; next=curr+size;
      /* primary dither loop */
      col=(XColor *)colormap;
      for(src=dst=sdata,i=0;i<hauteur;i++,src+=largeur,dst+=dll) {
	for(j=0;j<largeur;j++) { /* copy the row into the current line */
	  /* -- le 16.06.92 ---------------------------------------------
	   * Ajout pour tenir compte des "trous" de donnees dans greg
	   * Ces trous sont symbolise par une valeur superieur a l'indice
	   * de la plus haute couleur. */
	  curr[j] += col[(src[j]>=128) ? 0 : src[j]].pixel;
	}
	/* dither the current line */
	dither_line(curr,next,largeur,(i & 1) ? RightToLeft : LeftToRight);
	/* copy the dithered line to the destination image */
	/* ET ATTENTION AUX TROUS !! */
	for(j=0;j<largeur;j++) {
	  pixel=src[j]; src[j]=0; k=j>>3; val=7-(j & 7);
	  if(pixel>=128) dst[k] |= trou<<val;
	  else if(curr[j]<Threshold) dst[k] |= 1<<val;
	  curr[j]=0;
	}
	swap=curr; curr=next; next=swap; /* circulate the line buffers */
      }
      free(buff);
      sprintf(mess+strlen(mess), "done"); /* clean up */
      gx11_c_message(seve_t,"X",mess);
    }
    else { /* COLOR_DITHERING et GRAY_DITHERING */
      /* on utilise une indirection pour simuler un changement de couleur */
      size=largeur*hauteur;
      if(ldepth<=8) { for(i=0;i<size;i++) sdata[i]=col[sdata[i]].pixel;}
      if(ldepth==4) {
	/* On comprime 2 bytes d'entree dans un de sortie...mais
	 * si le nombre de pixels en x est impair, il faut finir
	 * sur une frontiere de byte... On utilise le fait que l'argument
	 * bytes-per-lines peut etre passe a XCreateImage, on compresse
	 * scan line par scan line et non la totalite de l'image a la fois */
	if(largeur % 2==0)
	  { /* cas pair , facile */
	    for(i=j=0;j<size;i++) {
	      sdata[i]=sdata[j++]<<4 ;
	      sdata[i] |= sdata[j++];
	    }
	    bpl=largeur/2;
	  }
	else
	  { /* cas impair=cas pair + traitement special dernier byte */
	    for(i=k=0;k<hauteur;k++) {
	      for(j=0;j<largeur-1;i++) {
		sdata[i] = sdata[k*largeur+j++]<<4 ;
		sdata[i] |= sdata[k*largeur+j++];
	      }
	      sdata[i++]=sdata[(k+1)*largeur]<<4;
	    }
	    bpl=(largeur+1)/2;
	  }
      }
    }
  }

  if((ximage=XCreateImage(display,vis,ldepth,format,0,NULL,largeur,hauteur,8,bpl))!=0)
    {
      /* The following is a trick to convert 1byte p/pixel internal images (128  */
      /* different colors) to 16 or 24 bit 'images' to be passed to the X hardware. The */
      /* trick consists in replacing the pixels computed by the GTVIRT by the  */
      /* good index in fixed (usually TrueColor) hardware maps to get a good  */
      /* representation of the desired colors. Normally you would retrieve the red_max, */
      /* red_mult, etc... of the default colormap with a call to */
      /* XGetRGBColormaps(), and scale the pixels accordingly. But under linux, or other vendors, */
      /* this call usually does not work. Fortunately it seems that I am able to deduce the */
      /* correct values from the R,G and B masks returned by a call to XGetVisualInfo  */

      if(dithering==BW_DITHERING) {
	ximage->bitmap_bit_order=MSBFirst; ximage->byte_order=MSBFirst;
      }else{
	/* I MUST figure out the byte order of the machine on which the image is created ! */
#include <sys/types.h>
#ifndef BYTE_ORDER
	/*
	 * Definitions for byte order,
	 * according to byte significance from low address to high.
	 * I do not know how to determine if BYTE_ORDER ise defined under <sys/types.h> (that
	 * seem to exist on most machines) or in another file like <sys/machine.h>, that may
	 * not exist at all and crash the precompiler!. So in the absence of the definition of
	 * BYTE_ORDER, I provide it myself... Obviously at YOUR own risks!
	 */
#define LITTLE_ENDIAN   1234    /* least-significant byte first (vax) */
#define BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
#define PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp) */

#ifdef vax
#define BYTE_ORDER      LITTLE_ENDIAN
#else
#define BYTE_ORDER      BIG_ENDIAN
#endif /* vax */
#ifdef cygwin
#define BYTE_ORDER  LITTLE_ENDIAN
#endif
#endif /* BYTE_ORDER */



	if (BYTE_ORDER==BIG_ENDIAN) ximage->byte_order=MSBFirst;
	if (BYTE_ORDER==LITTLE_ENDIAN) ximage->byte_order=LSBFirst;
      }
      if (depth > 8 && depth < 24) {
	int i;
	unsigned	val;
	double	tmp;
	XColor	*col=(XColor *)colormap;
	adr=malloc(largeur*hauteur*sizeof(short));
	for (i=0;i<largeur*hauteur;i++) {
	  tmp=(col+sdata[i])->red;
	  val=(tmp/MAX_INTENSITY)*(red_max); adr[i]=val*red_mult;
	  tmp=(col+sdata[i])->green;
	  val=(tmp/MAX_INTENSITY)*(green_max);adr[i]|=val*green_mult;
	  tmp=(col+sdata[i])->blue;
	  val=(tmp/MAX_INTENSITY)*(blue_max);adr[i]|=val*blue_mult;
	}
	ximage->data=(char *)adr;
      } else if (depth >= 24) {
	int i;
	unsigned	val;
	double	tmp;
	XColor	*col=(XColor *)colormap;
	adrl=malloc(largeur*hauteur*sizeof(int));
	for (i=0;i<largeur*hauteur;i++) {
	  tmp=(col+sdata[i])->red;
	  val=(tmp/MAX_INTENSITY)*(red_max); adrl[i]=val*red_mult;
	  tmp=(col+sdata[i])->green;
	  val=(tmp/MAX_INTENSITY)*(green_max);adrl[i]|=val*green_mult;
	  tmp=(col+sdata[i])->blue;
	  val=(tmp/MAX_INTENSITY)*(blue_max);adrl[i]|=val*blue_mult;
	}
	ximage->data=(char *)adrl;
      } else  {
	ximage->data=(char *)sdata;
      }
      /* Ca y est, la voila sur l'ecran: */
      XPutImage(display,cur->win_graph,cur->myGC,ximage,
		0,0,n_x0,n_y0,largeur,hauteur);
      /* Prevent XDestroyImage to destroy adr_pixel contents...*/
      if (depth <= 8){ximage->data=0;}
      XDestroyImage(ximage);
    }
  else gx11_c_message(seve_e,"X","Memory allocation failure in X_affiche_image");
}
/*----------------------------------------------------------------------
 *   SUBROUTINE X_CLAL
 *    Clear Alpha
 */
void x11_x_clal(G_env *genv)
{
  XRaiseWindow(display,((gx11_env_t *)genv)->win_graph);
  XFlush(display);
}
/*----------------------------------------------------------------------
 *   SUBROUTINE X_CLPL
 *    Clear Plot(Lower Window)
 */
void x11_x_clpl(G_env *genv)
{
  XLowerWindow(display,((gx11_env_t *)genv)->win_graph);
  XFlush(display);
}
/*----------------------------------------------------------------------
 *  SUBROUTINE X_CMDWIN
 *  set focus back to the command window
 */
void x11_x_cmdwin(void)
{
  XWindowAttributes from_attr;
  /*   if(from_window && isAtDefaultDepth) { */
  if(from_window) {
    XGetWindowAttributes(display,from_window,&from_attr);
    if(from_attr.map_state==IsViewable) {
      XSetInputFocus(display,from_window,RevertToParent,CurrentTime);
    }
  }
}

/*
 *----------------------------------------------------------------------
 * Module 11
 *
 *  SUBROUTINE X_FLUSH
 *      X_FLUSH
 *      Tracer
 *----------------------------------------------------------------------
 */
static void x11_x_flush( G_env *env, struct _point tabpts[], int npts)
{
  if (npts) {
    int i;
    XPoint points[sizeof(env->tabpts) / sizeof(env->tabpts[0])];

    for (i = 0; i < npts; i++) {
        points[i].x = tabpts[i].x;
        points[i].y = tabpts[i].y;
    }
    XDrawLines( display, ((gx11_env_t *)env)->win_graph,
     ((gx11_env_t *)env)->myGC, points, npts, CoordModeOrigin);
  }
  XFlush(display);
}
/*
 *----------------------------------------------------------------------
 * Module 13
 *
 *  SUBROUTINE X_CLOSE
 *      fermer la connexion avec X
 *----------------------------------------------------------------------
 */
void x11_x_close(void)
{
  int status;
  if (!display) { gx11_c_message(seve_e,"X","No connection"); return; }
  if (flag_install) { XFreeColormap (display,cmap); flag_install = FALSE; }
  else if (!flag_static_display) {
    status =XFreeColors(display,cmap,pixels_pen,NPEN,NPLANES);
    status =XFreeColors(display,cmap,pixels_ret,ncol,NPLANES);
  }
  XFreeCursor(display,curseur);
  //XCloseDisplay(display); display=NULL;
  /* Note: Les autres variables seront reinitialisees lors de l'open */
}

void x11_on_destroy( G_env *_env)
{
    gx11_env_t *env = (gx11_env_t *)_env;

    x11_delete_integer_property( env->win_graph, "GENV");
    env->win_main = 0;
    env->win_graph = 0;
    XFreeGC(display,env->myGC);
    if(flag_pixmap) {
        if(flag_cross) {
            XFreePixmap(display,env->horizontal);
            XFreePixmap(display,env->vertical);
        }
        XFreePixmap(display,env->box1); XFreePixmap(display,env->box3);
        XFreePixmap(display,env->box2); XFreePixmap(display,env->box4);
    }
    free(env);
}

/* Does a XDestroyWindow, but send a KILLWIND message to gtv_xinput */

static void (*x11_destroy_window_handler)(void *) = NULL;
static void *x11_destroy_window_data = NULL;

void x11_set_destroy_window_handler( void (*destroy_handler)(void *), void *destroy_data)
{
    x11_destroy_window_handler = destroy_handler;
    x11_destroy_window_data = destroy_data;
}

void x11_destroy_window( G_env *_env)
{
    gx11_env_t *env = (gx11_env_t *)_env;
    if (!x11_get_integer_property( env->win_graph, "GENV"))
        return;
    x11_set_integer_property( env->win_graph, "GENV", 0);

    if (x11_destroy_window_handler != NULL)
        x11_destroy_window_handler( x11_destroy_window_data);
    else
        XDestroyWindow(display, env->win_graph);

    x11_on_destroy( _env);
}

void x11_get_corners( G_env *env, int x[3], int y[3])
{
    int largeur, hauteur;

    largeur=widthofscreen-env->Width_graphique;
    hauteur=heightofscreen-env->Height_graphique;
    x[0]=10; x[1]=largeur>>1; x[2]=largeur-10;
    y[2]=25; y[1]=hauteur>>1; y[0]=hauteur-10;
}

void x11_move_window( G_env *env, int x, int y)
{
    XMoveWindow( display, ((gx11_env_t *)env)->win_graph, x, y);
    XFlush( display);
}

void x11_clear_window( G_env *env)
{
    XClearArea(display, ((gx11_env_t *)env)->win_graph, 0, 0, 0, 0, True);
}

int x11_open_x(
    char *device,
    int backg,           /* !=0 if the user wants reverse video */
    int cross,           /* !=0 if the user wants crosshair cursor  */
    G_env **graph_env,    /* pointer to graphics environment struct */
    char *dirname,
    int *x1, int *x2, int *y1, int *y2,
    fortran_type dir_cour,
    int HT, int LT,     /* requested window size  */
    int col)           /* !=0 if the user want to use color, affected to ncol */
{
  G_env *genv;
  char *getenv();
  int class;
  int X,Y,Width,Height,swidth,sheight;
  /* Largeur et hauteur en millimetre et en pixels
   *  Caracteristiques physiques de la bete */
  int does_back;
  char *vendor;
  XGCValues sp_gcvalues;
  int status;
  int i;
  int pcol;
  char *widgets;
  XVisualInfo    vTemplate;
  XVisualInfo    *visualList;
  int visualsMatched;
  /* Message variables */
  char rname[] = "X";
  char mess[GAG_MAX_MESSAGE_LENGTH];
  enum severities seve;

  /*
   * Start Code ------------------------------------------------------
   */

  /* Connection */
  gx11_c_message(seve_d,rname,"X-Window default version %s",VERSION);
  /* Nom de l'ecran associe a la variable d'environnement DISPLAY */
  x11_open_display( device);
  if (launch_other_XAPP) {
    set_gtv_window_handler( run_gtv_window);
    launch_gtv_x11_window();
  }
  /* Physical characteristics of screen */
  /* Look for default Depth, and ask for less if depth > 8 */
  isAtDefaultDepth=1;
  if (depth > 8) {
    /* We can hope for the best: matching a Pseudocolor 8 planes. */
    vTemplate.screen=screen_number;
    vTemplate.depth=8;
    visualList= XGetVisualInfo(display,VisualScreenMask|VisualDepthMask,
			       &vTemplate,&visualsMatched);
    if (visualsMatched !=0) {
      vis=visualList[0].visual;
      class=visualList[0].class;
      depth=visualList[0].depth;
      isAtDefaultDepth=0;
      sprintf(mess, "Screen (%d planes) agreed to be a %d planes, ",
          DefaultDepth(display,screen_number),depth);
      seve = seve_i;
      XFree(visualList);
    }
    else { /* go forward but pray, since this is not well supported */
      vis=DefaultVisual(display,screen_number);
      depth=DefaultDepth(display,screen_number);
      class=vis->class;
      vTemplate.screen=screen_number;
      vTemplate.depth=depth;
      visualList= XGetVisualInfo(display,VisualScreenMask|VisualDepthMask,
				 &vTemplate,&visualsMatched);
      if (visualsMatched !=0) {
	vis=visualList[0].visual;
	class=visualList[0].class;
	depth=visualList[0].depth;

	/* save the XVisualInfo struture */
        OurVisualInfo.visualid=visualList[0].visualid;
        OurVisualInfo.screen=visualList[0].screen;
        OurVisualInfo.depth=visualList[0].depth;
        OurVisualInfo.class=visualList[0].class;
        OurVisualInfo.red_mask=visualList[0].red_mask;
        OurVisualInfo.green_mask=visualList[0].green_mask;
        OurVisualInfo.blue_mask=visualList[0].blue_mask;
        OurVisualInfo.colormap_size=visualList[0].colormap_size;
        OurVisualInfo.bits_per_rgb=visualList[0].bits_per_rgb;
        sprintf(mess, "Screen characteristics %d planes, ", depth);
        seve = seve_d;

	/*Compute red_max, blue_max, green_max, red_mult, blue_mult, green_mult */
	/*By right-shifting the bit fields of red_mask, etc */
	{
	  red_max=OurVisualInfo.red_mask;
	  red_mult=1;
	  for (; red_max!=0; red_max >>=1)
	    {
	      if (red_max & 01) break;
	      red_mult*=2;
	    }
	}
	{
	  green_max=OurVisualInfo.green_mask;
	  green_mult=1;
	  for (; green_max!=0; green_max >>=1)
	    {
	      if (green_max & 01) break;
	      green_mult*=2;
	    }
	}
	{
	  blue_max=OurVisualInfo.blue_mask;
	  blue_mult=1;
	  for (; blue_max!=0; blue_max >>=1)
	    {
	      if (blue_max & 01) break;
	      blue_mult*=2;
	    }
	}
      } else {
        sprintf(mess,"Unsupported Screen characteristics: %d planes, ",depth);
        seve = seve_f;
      }
      XFree(visualList);
    }
  }
  /* at 8 or less depth, we will support all possibilities with a
     rather complicated code... */
  else
    {
      vis=DefaultVisual(display,screen_number);
      depth=DefaultDepth(display,screen_number);
      class=vis->class;
      sprintf(mess,"Screen characteristics: %d %s, ",depth,(depth>1)?"planes":"plane");
      seve = seve_d;
    }
  /* Classe du terminal, calcul de la place libre dans la colormap
   * et initialisation.
   * if fcolo=0, the user doesn't want color, so treat the display
   * like the corresponding greyscale one (ie static or otherwise) */
  err_alloc_color=0;
  pen_ncol=0; if (depth==1) col = 0;
  /*
   * Check Static vs Dynamic displays
   */
  switch(class) {
  case PseudoColor:
    flag_color_display=TRUE;
    flag_static_display=FALSE;
    sprintf(mess+strlen(mess), "PseudoColor");
    break;
  case DirectColor:
    flag_color_display=TRUE;
    flag_static_display=TRUE;
    sprintf(mess+strlen(mess), "DirectColor");
    break;
  case GrayScale:
    flag_color_display=FALSE;
    flag_static_display=FALSE;
    sprintf(mess+strlen(mess), "GrayScale");
    break;
  case StaticColor:
    flag_color_display=TRUE;
    flag_static_display=TRUE;
    sprintf(mess+strlen(mess), "StaticColor");
    break;
  case TrueColor:
    flag_color_display=TRUE;
    flag_static_display=TRUE;
    sprintf(mess+strlen(mess), "TrueColor");
    break;
  case StaticGray:
    flag_color_display=FALSE;
    flag_static_display=TRUE;
    sprintf(mess+strlen(mess), "StaticGray");
    /* Fin du switch */
  }
  gx11_c_message(seve, rname, mess);
  /* Gestion du backing store */
  flag_backingstore=0;
  does_back=XDoesBackingStore(screen);
  if(does_back==NotUseful) gx11_c_message(seve_d,rname,"Backing Store NOT supported");
  else {
    if(does_back==WhenMapped) gx11_c_message(seve_d,rname,"Backing Store supported WhenMapped");
    else gx11_c_message(seve_d,rname,"Backing Store ALWAYS supported");
    flag_backingstore=1;
  }
  /* Vendor: relatively useless */
  vendor=XServerVendor(display);
  gx11_c_message(seve_d,rname,"Vendor %s; release %d",
      vendor,XVendorRelease(display));
  gx11_c_message(seve_d,rname,"Protocol X%d ;revision: %d",
      XProtocolVersion(display),XProtocolRevision(display));
  /* Physical size */
  sheight=heightofscreen=XHeightOfScreen(screen);
  swidth=widthofscreen=XWidthOfScreen(screen);
  gx11_c_message(seve_d,rname,"Screen size (mm) : height: %d, width: %d",
      XHeightMMOfScreen(screen),XWidthMMOfScreen(screen));
  gx11_c_message(seve_d,rname,"Screen pixels : height: %d, width: %d",
      sheight,swidth);

  /*
   * Install private colormap if required..
   */
  flag_install = FALSE;
  if (isAtDefaultDepth)
    {
      if ( depth == 8 && col != 0 && !flag_static_display )
	{
	  pcol = 128+16;  /* 128 Colors + 16 user defined pen colors */
	  cmap = XDefaultColormap(display,screen_number);
	  sprintf(mess, "Allocating %d cells in default colormap... ",pcol);
	  status = XAllocColorCells(display,cmap,CONTIG,NULL,NPLANES,
				    pixels_ret,pcol);
	  if (status)
	    { /* check they are contiguous, CONTIG means that
		 PLANES are contiguous */
	      int plast, pnew;

	      sprintf(mess+strlen(mess), "ok. Checking they ARE contiguous... ");
	      plast = pixels_ret[0] ;
	      for (i=1;i<128+16;i++)
		{
		  pnew = pixels_ret[i];
		  if (pnew != plast+1)
		    {
		      flag_install = TRUE;
		      sprintf(mess+strlen(mess), "failed");
		      gx11_c_message(seve_t,rname,mess);
		      break;
		    }
		  plast = pnew ;
		}
	      sprintf(mess+strlen(mess), "ok");
	      gx11_c_message(seve_t,rname,mess);
	      XFreeColors(display, cmap, pixels_ret, pcol, 0);
	    }
	  else
	    {
	      flag_install = TRUE;
	      /*install it...*/
	      sprintf(mess+strlen(mess), "failed. Trying to install a private Cmap... ");
	      default_cmap = XDefaultColormap(display,screen_number);
	      cmap = XCopyColormapAndFree(display, default_cmap);
	      status = XAllocColorCells(display,cmap,CONTIG,NULL,NPLANES,
					firstcolors,NFIRST);

	      if (status) sprintf(mess+strlen(mess), "ok");
	      else        sprintf(mess+strlen(mess), "failed");
	      gx11_c_message(seve_t,rname,mess);

	      for (i = 0; i < NFIRST; i++)
		first_defs[i].pixel = firstcolors[i];
	      XQueryColors (display, default_cmap, first_defs, NFIRST);
	      XStoreColors (display, cmap, first_defs, NFIRST);
	    }
	}  /* following case is: No color needed by an XstoreColor */
      else {
	gx11_c_message(seve_t,rname,"Using default colormap...");
	cmap = XDefaultColormap(display,screen_number);
	/* here you would normally get the current colormap  with a call to
	   XGetRGBColormaps, retrieve the values of how much pixels are for
	   the red, and theit offset, etc..., and use them later in
	   x_affiche_image. Problem: does not work under linux...*/
      }
    }
  else  /* following case is: Not AT default Depth: use a visual */
    {
      /* We are obliged to create a new colormap */
      sprintf(mess,"Allocating private colormap... ");
      flag_install = TRUE;
      cmap = XCreateColormap(display,root_win,vis,AllocNone);
      default_cmap = XDefaultColormap(display,screen_number);
      status = XAllocColorCells(display,cmap,CONTIG,NULL,NPLANES,
				firstcolors,NFIRST);

      if (status) sprintf(mess+strlen(mess), "ok");
      else sprintf(mess+strlen(mess), "failed");
      gx11_c_message(seve_t,rname,mess);

      for (i = 0; i < NFIRST; i++)
	first_defs[i].pixel = firstcolors[i];
      XQueryColors (display, default_cmap, first_defs, NFIRST);
      XStoreColors (display, cmap, first_defs, NFIRST);
    }
  /*
   *  Now work in defined colormap.
   */
  flag_pixmap=TRUE;
  Allocnamedcolor();

  /* get window information from the originating window (ie the one from whence
   * the program is being run */
  /*  if(isAtDefaultDepth) XGetInputFocus(display, &from_window, &revert_to); */
  XGetInputFocus(display, &from_window, &revert_to);

  wait_display=!strncmp(vendor,"MacX",4);
  if (wait_display==0) {
    wait_display=!strncmp(vendor,"The Cygwin/X Project",19);
  }

  /* Graphic context */
  if (isAtDefaultDepth) {
    black_pix=BlackPixel(display,screen_number);
    white_pix=WhitePixel(display,screen_number);
  }else{
    black_pix=tabcolor[0].pixel;
    white_pix=tabcolor[7].pixel;
  }
  /* Small cursor */
  curseur=XCreateFontCursor(display,XC_crosshair);
  flag_cross= cross;
  flag_backg= backg;

  /* Creons le premier contexte graphique.
   * Allocation de la premiere structure, et mise a jour de PREM et LAST */
  genv = x11_creer_genv();

  /* Now open a (graphic) window */
  X_ancrage=50; Y_ancrage=50;
  Width= LT; Height= HT;
  if(!Height && !Width) {
    X=(*x2==1) ? (80*swidth)/100 : *x2-*x1+1;
    Y=(*y2==1) ? (66*sheight)/100 : *y2-*y1+1;
    if(X<=swidth && Y<=sheight) { Height=Y; Width=X; }
    else {
      Height=(85*sheight)/100; Width=(X*Height)/Y;
      if(Width>=swidth) { Width=(85*swidth)/100; Height=(Y*Width)/X; }
    }
  }
  /* Gardons ces dimensions pour les autres */
  Width_default=Width; Height_default=Height;
  genv->Width_graphique=Width;
  genv->Height_graphique=Height;

  x11_new_graph(backg,genv,dirname,x1,x2,y1,y2,dir_cour,0);

  /* Creation du GC 'invert' pour les displays static grey. Ce GC sert pour
   * gerer le big curseur, sans effacer le dessin (en mode GCInvert)
   * pour des display "static grey" ainsi que pour tout trace non permanent
   * (boite de zoom..) */
  if(!flag_pixmap) {
    if(backg) {
      sp_gcvalues.foreground=white_pix;
      sp_gcvalues.background=black_pix;
    }
    else {
      sp_gcvalues.foreground=black_pix;
      sp_gcvalues.background=white_pix;
    }
    sp_gcvalues.function=GXinvert;
    sp_gcvalues.line_width=0;
    sp_gcvalues.line_style=LineSolid;
    sp_gcvalues.cap_style=CapProjecting;
    sp_gcvalues.join_style=JoinMiter;
    GCsp=XCreateGC(display,((gx11_env_t *)genv)->win_graph,
                   GCFunction|GCForeground|GCBackground,&sp_gcvalues);
  }
  /* Deplacons la fenetre dans le coin en haut a droite.
   * Arbitraire, mais bien pratique avec ces c... de Window Manager
   * qui les mettent n'importe ou */
  {
      int x[3],y[3];
      x11_get_corners( genv, x, y);
      x11_move_window( genv, x[2], y[2]);
  }
  *graph_env = genv;
  return(1);
}

int x11_get_image_width( int x)
{
    return x;
}


static void x11_refresh_window( fortran_type adr_dir, int mode, G_env *env)
{
    if (env != NULL)
        gtv_refresh_win( adr_dir, env->fen_num, mode);
    else
        gtv_refresh_dir( adr_dir, mode);
}

static graph_api_t s_x11_graph_api = {
    x11_creer_genv,
    x11_destroy_window,
    x11_refresh_window,
    NULL, /* x11_open_window */
    NULL, /* x11_close_window */
    NULL,
    x11_move_window,
    NULL, /* x11_resize_window */
    NULL, /* x11_invalidate_window */
    x11_clear_window,
    x11_get_corners,
    x11_get_image_width,
    x11_new_graph,
    x11_create_edit_lut_window,
    x11_open_x,
    x11_x_pen_invert,
    x11_x_fill_poly,
    x11_x_curs,
    x11_ask_for_corners,
    x11_other_x_curs,
    x11_x_weigh,
    x11_x_dash,
    x11_x_test_event,
    x11_ximage_loadrgb,
    x11_xcolormap_create,
    x11_xcolormap_delete,
    x11_ximage_inquire,
    x11_x_affiche_image,
    x11_x_clal,
    x11_x_clpl,
    x11_x_cmdwin,
    x11_x_size,
    x11_x_flush,
    x11_x_close,
    NULL,
    NULL,
};

#define init_graph_api CFC_EXPORT_NAME( init_graph_api)

void CFC_API init_graph_api()
{
    set_graph_api( &s_x11_graph_api);
}
