/* $Header: llx.c,v 4.11 88/11/24 18:07:18 samarcq Exp $ */
#include <X/Xlib.h>
#include <lelisp.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>

extern char *malloc();

XAssocTable *XCreateAssocTable();

#define NULL 0

/* Les plans sur lesquels on travaille */
#define PLANES 1

/* Macro pour mettre un int dans la CVAL d'un symbole Lisp */

#define SETINTCVAL(symb,i) *symb = (i) & 0xffff
#define LLLOCATOR(x,y) ((((x) & 0xffff) << 16) | ((y) & 0xffff))

/* les curseurs e'dite's par bitmap */

#define lelisp←width 16
#define lelisp←height 16
#define lelisp←x←hot 1
#define lelisp←y←hot 1
static short lelisp←bits[] = {
   0x0000, 0x0002, 0x0006, 0x000e,
   0x001e, 0x003e, 0x007e, 0x00fe,
   0x001e, 0x0036, 0x0032, 0x0060,
   0x0060, 0x00c0, 0x00c0, 0x0000};

#define lelisp←mask←width 16
#define lelisp←mask←height 16
#define lelisp←mask←x←hot 1
#define lelisp←mask←y←hot 1
static short lelisp←mask←bits[] = {
   0x0003, 0x0007, 0x000f, 0x001f,
   0x003f, 0x007f, 0x00ff, 0x01ff,
   0x01ff, 0x007f, 0x007f, 0x00f3,
   0x00f0, 0x01e0, 0x01e0, 0x01c0};


#define nocursor←width 16
#define nocursor←height 16
#define nocursor←x←hot 1
#define nocursor←y←hot 1
static short nocursor←bits[] = {
   0x0000, 0x0002, 0x0006, 0x000e,
   0x001e, 0x003e, 0x007e, 0x00fe,
   0x001e, 0x0036, 0x0032, 0x0060,
   0x0060, 0x00c0, 0x00c0, 0x0000};

#define nocursor←mask←width 16
#define nocursor←mask←height 16
#define nocursor←mask←x←hot 1
#define nocursor←mask←y←hot 1
static short nocursor←mask←bits[] = {
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
};

/* Les environnements graphiques */

struct grenv {
        FontInfo *font;
        Pattern linestyle;
        int mode;
        Pixmap pattern;
        int clipx;
        int clipy;
        int clipw;
        int cliph;
	int topwindowp;
};


#define FONTINFO(n) (grenvs[n]->font)
#define FONT(n) (grenvs[n]->font->id)
#define MODE(n) (grenvs[n]->mode)
#define LINE←STYLE(n) (grenvs[n]->linestyle)
#define PATTERN(n) (grenvs[n]->pattern)
#define CLIPX(n) (grenvs[n]->clipx)
#define CLIPY(n) (grenvs[n]->clipy)
#define CLIPW(n) (grenvs[n]->clipw)
#define CLIPH(n) (grenvs[n]->cliph)
#define TOPWINDOWP(n) (grenvs[n]->topwindowp)

#define BORDERWIDTH 2
FontInfo *normalfont, *attributefont;
Cursor cursor, nocursor;

#define MAX←WINDOW 5000  /* nombre maximal de fene↑tres */
int nwindow = 0;       /* nombre de fene↑tres construites */

int event←mode;  /* le mode de la souris */

Display *display;                 /* l'e'cran ouvert */
Window windows[MAX←WINDOW];       /* le vecteur des Fene↑tres */
Window clips[MAX←WINDOW];         /* les fene↑tres transparentes pour le 
                                     clip */
struct grenv *grenvs[MAX←WINDOW]; /*                graphenvs */
Pixmap patterns[5];
Pattern line←style[4] = {0, DashedLine, DottedLine, 
XMakePattern(0xf900, 10, 1)};

XAssocTable *assoctable;

Window keyboardgrabber = 0;
Window downgrabber = 0;

short down←dx, down←dy;

int reversevideo;
int ForePixel, BackPixel;
Pixmap ForePixmap, BackPixmap;

/* Les vertex pour les POLYxxx et le FILLAREA */
#define MAXVERTEX 1024
Vertex vertex[MAXVERTEX];

int * lispnil;
int * lispxerrorsymbol;
int * lisperrorsymbol;

FontInfo *
load←font (s) char *s; {
        return XOpenFont(s);
}

FontInfo *
default←font1 () {
        return normalfont;
}

FontInfo *
default←font2 () {
        return attributefont;
}

struct grenv *ge←default (topp) int topp; {
        struct grenv *ge;
	ge = (struct grenv *) malloc(sizeof(struct grenv));
        ge->font = default←font1();
        ge->linestyle = 0;
        ge->mode = GXcopy;
        ge->pattern = ForePixmap;
        ge->clipx = 0;
        ge->clipy = 0;
        ge->clipw = 0;
        ge->cliph = 0;
	ge->topwindowp = topp;
        return(ge);
}

/*ARGSUSED*/
llxError (dpy, rep)
    Display *dpy;
    XErrorEvent *rep;
{
    pusharg(LLT←T, lispxerrorsymbol);
    pusharg(LLT←STRING, XErrDescrip(rep->error←code));
    pusharg(LLT←T, (int *) XLookUpAssoc(assoctable, rep->window));
    lispcall(LLT←T, 3, lisperrorsymbol);
    return(0);
}


ll←io () {
    printf("IT event\r\n");
/* appeler ensuite ll←mouse() dans llmachine.s */
}

/* Initialisations generales. */

Display *bitprologue(xmax, ymax, planes, lenil, llxerror, llerror)
int *xmax, *ymax, *lenil, *llxerror, *llerror, *planes; {
	char *def;

	display = XOpenDisplay (NULL);

	if (display == NULL) {
		perror ("bitprologue: can't open display");
		return (0);
	}

	XSetDisplay (display);

	XErrorHandler(llxError);

	*xmax = (DisplayWidth () - 1) & 0xffff;
	*ymax = (DisplayHeight () - 1) & 0xffff;
	*planes = DisplayPlanes () & 0xffff;

	lispnil = lenil;
	lispxerrorsymbol = llxerror;
	lisperrorsymbol = llerror;
	
	/* reversevideo:on  blanc sur fond noir. (reversevideo true)
	   reversevideo:off noir sur fond blanc. (reversevideo false)
	   default off, reversevideo false.
	   */
	
	def = XGetDefault("lelisp", "ReverseVideo");
	if (!def) def = XGetDefault("xterm", "ReverseVideo");
	if (!def) def = "off";
	reversevideo = strcmp(def, "off"); /* vrai si def <> "off" */
	
	ForePixel = reversevideo ? WhitePixel : BlackPixel ;
	BackPixel = reversevideo ? BlackPixel : WhitePixel ;
	ForePixmap = reversevideo ? WhitePixmap : BlackPixmap ;
	BackPixmap = reversevideo ? BlackPixmap : WhitePixmap ;
	
	def = XGetDefault("lelisp", "font");
	if (!def) def = "vtsingle";
	normalfont = load←font(def);
	
	def = XGetDefault("lelisp", "attributefont");
	if (!def) def = "vtbold";
	attributefont = load←font(def);
	
	cursor = XCreateCursor(lelisp←width, lelisp←height,
			       lelisp←bits, lelisp←mask←bits, 
			       lelisp←x←hot, lelisp←y←hot,
			       ForePixel, BackPixel, GXcopy);

	nocursor = XCreateCursor(nocursor←width, nocursor←height,
			       nocursor←bits, nocursor←mask←bits, 
			       nocursor←x←hot, nocursor←y←hot,
			       ForePixel, BackPixel, GXcopy);

	init←pattern();

	assoctable = XCreateAssocTable(64);

	set←event←mode(0);

	return (display);
}

void
bitepilogue () {
	XDestroyAssocTable(assoctable);
	XFreePixmap(patterns[4]);
	XFreePixmap(patterns[3]);
	XFreePixmap(patterns[2]);
	XFreePixmap(patterns[1]);
	XFreePixmap(patterns[0]);
	XFreeCursor(nocursor);
	XFreeCursor(cursor);
	XCloseFont(attributefont);
	XCloseFont(normalfont);
	XFlush();
	XCloseDisplay(display);
}
	
/* Cre'ation d'une fene↑tre */
int
create←window(lisp, left, top, width, height, ti, hi, vi)
int * lisp;
int left, top, width, height;
char *ti; {
	Window win, cli;
	struct grenv *ge;

        if (nwindow == MAX←WINDOW) return(-1); /* plus de fene↑tres! */
	
	/* X ne veut pas de fene↑tres de taille 0 */
        if (width == 0) width = 1;
        if (height == 0) height = 1;

        /* allocation du GRAPHENV */
        ge = ge←default(1);

        /* cre'ation et allocation du FRAME */
        win = XCreateWindow(RootWindow,
                                left-BORDERWIDTH,
                                top-BORDERWIDTH,
                                width,
                                height,
                                BORDERWIDTH,
                                hi ? ForePixmap : patterns[2],
                                BackPixmap);

	XTileAbsolute(win);
        XStoreName(win, ti);

        cli = XCreateTransparency(win, 0, 0, width, height);
        XClipDrawThrough(cli);

        XDefineCursor(win, cursor);

        /* choix de l'input */

        XSelectInput (win, 0); /* ne pas avoir le premier redisplay */
	XMapWindow (cli);
        if (vi) XMapWindow (win);
        XSelectInput (win, 0x7fbd);

        /* mise a jour des vecteurs */
        windows[nwindow] = win;
        clips[nwindow] = cli;
        grenvs[nwindow] = ge;
	XMakeAssoc(assoctable, win, lisp);

        /* initialisation du ge */
        set←cur←mode (nwindow, 3);
        set←clip(nwindow, 0, 0, width, height);

        return (nwindow++);
}

create←subwindow(lisp, father, left, top, width, height, vi) int * lisp;
int father, left, top, width, height, vi;{
Window win, cli;
struct grenv *ge;

        if (nwindow == MAX←WINDOW) return(-1); /* plus de fene↑tres! */

        if (width == 0) width = 1;
        if (height == 0) height = 1;

        /* allocation du GRAPHENV */
        ge = ge←default(0);

        /* cre'ation et alloc<ation du FRAME */
        win = XCreateTransparency(windows[father],
                                left,
                                top,
                                width,
                                height);
        cli = XCreateTransparency(win,
                                0,
                                0,
                                width,
                                height);
	XTileAbsolute(win);
        /* choix de l'input */
        XSelectInput (win, 0x7fbd);
        XMapWindow (cli);
        if (vi) XMapWindow (win);

        /* mise a jour des vecteurs */
        windows[nwindow] = win;
        clips[nwindow] = cli;
        grenvs[nwindow] = ge;
	XMakeAssoc(assoctable, win, lisp);

        /* initialisation du ge */
        set←cur←mode (nwindow, 3);
        set←clip (nwindow, 0, 0, width, height);

        return (nwindow++);
}

modify←window (win, xyp, x, y, whp, width, height, ti, hi, vi)
char   *ti; {
	
        if (width == 0) width = 1;
        if (height == 0) height = 1;
	
	if (TOPWINDOWP(win)){
		y -= BORDERWIDTH;
		x -= BORDERWIDTH;
	}

	XSelectInput (windows[win], 0);
	if (xyp && whp)
		XConfigureWindow (windows[win], x, y, width, height);
	else if (xyp)
		XMoveWindow (windows[win], x, y);
	else if (whp)
		XChangeWindow (windows[win], width, height);
	XSelectInput (windows[win], 0x7fbd);

	set←clip (win, CLIPX(win), CLIPY(win), width, height);

	if (TOPWINDOWP(win)){
		XStoreName (windows[win], ti);
		if (hi)
			XChangeBorder (windows[win], ForePixmap);
		else
			XChangeBorder (windows[win], patterns[2]);
	}
	if (vi)
		XMapWindow (windows[win]);
	else
		XUnmapWindow (windows[win]);
}

kill←window (n) int n; {
	if ((n < 0) || (n >= nwindow))
		return (-1);
	
	if (keyboardgrabber = windows[n]) keyboardgrabber = 0;
	if (downgrabber = windows[n]) downgrabber = 0;
	XDeleteAssoc(assoctable, windows[n]);
	XDestroyWindow (windows[n]);
	free (grenvs[n]);
	
	if (n != nwindow - 1)
		while (++n < nwindow) {
			windows[n - 1] = windows[n];
			grenvs[n - 1] = grenvs[n];
			clips[n - 1] = clips[n];
		}
	nwindow--;
	return (0);
}

pop←window (n) int  n; {
    XRaiseWindow (windows[n]);
}

/*ARGSUSED*/
move←behind←window (n1, n2) int n1,
                                n2; {
    XLowerWindow (windows[n1]);
}

int *
find←window (x, y, lispnil) int * lispnil; int x, y;{
    int     lx,
            ly,
            loc = LLLOCATOR(x, y);
    int *lispwin = NULL, *prevlispwin = NULL;
    Window win = RootWindow;
    do {
       prevlispwin = lispwin;
       XInterpretLocator (win, &lx, &ly, &win, loc);
       lispwin = (int *) XLookUpAssoc(assoctable, win);
    } while (lispwin);
    return prevlispwin ? prevlispwin : lispnil;
}

map←window (win, x, y, lx, ly)
int     win,
        x,
        y;
int *lx, *ly; {
    Window pwin; int px, py;
    XInterpretLocator (windows[win], &px, &py, &pwin, LLLOCATOR(x, y));
    *lx = px & 0xffff;
    *ly = py & 0xffff;
}


grab←keyboard (win, flag) int win, flag;{
    if (flag)
       keyboardgrabber = windows[win];
    else
       keyboardgrabber = 0;
}

/* grabbe uniquement le clavier, a` corriger */
grab←mouse (win, flag) int win, flag; {
    if (flag){
       keyboardgrabber = windows[win];
       downgrabber = windows[win];
    } else {
       keyboardgrabber = 0;
       downgrabber = 0;
    }
}


draw←cn (win, x, y, cn) char    cn; {
    char    cnstring[2];
    cnstring[0] = cn;
    XTextPad (clips[win], x-CLIPX(win), y-CLIPY(win),
            cnstring, 1, FONT (win), 0, 0,
	    ForePixel, BackPixel, MODE (win), PLANES);
}

draw←substr (win, x, y, s, start, length) char *s; {
	XTextPad (clips[win], x-CLIPX(win), y-CLIPY(win),
		  s + start, length, FONT (win), 0, 0,
		  ForePixel, BackPixel, MODE (win), PLANES);
}

fast←draw←substr (win, x, y, s, start, length)
struct LL←STRING *s;
short win, x, y, start, length; {
char *cs;
        cs = (&((s->ll←strobj)->ll←strfil))+start;
	XTextPad (clips[win], x-CLIPX(win), y-CLIPY(win),
		  cs, length, FONT (win), 0, 0,
		  ForePixel, BackPixel, MODE (win), PLANES);
}

width←substr (s, start, length, win) char  *s; {
    int     plength;
    char    c = s[start + length];
    s[start + length] = '\0';
    plength = (win >= 0) ? 
            XStringWidth (s+start, FONTINFO (win), 0, 0) :
	    XStringWidth (s+start, default←font1(), 0, 0);
    s[start + length] = c;
    return (plength);
}

/*ARGSUSED*/
height←cn (cn, win) char    cn; {
    return (win >= 0) ? FONTINFO (win) -> height : default←font1() -> height;
}

xinc←substr (s, start, length, win) char   *s; {
    return (width←substr (s, start, length, win));
}

tycleol(win, x, y) {
    x -= CLIPX(win);
    y -= CLIPY(win);
    XPixSet(clips[win], x, y, 2000, FONTINFO(win)->height, BackPixel);
}

draw←cursor (win, x, y, st) {
    x -= CLIPX(win);
    y -= CLIPY(win);
    XLine (clips[win],
	    x, y,
	    x, y+(FONTINFO(win)->height)-1,
	    1, 1,
	    st ? ForePixel : BackPixel, GXcopy,
	    PLANES);
}

clear←ge (win) {
    XClear (clips[win]);
}

/* Les environnements graphiques */

current←font (win, font) FontInfo * font; {
    FONTINFO (win) = font;
}

/* la souris */

#define MAXEVENT 256
XEvent events[MAXEVENT];
int ievent = 0, mevent = 0;

fillevent(event) XEvent *event; {
int i, pending;
    if (ievent == mevent) {
       pending = XPending();
       if (pending > MAXEVENT) pending = MAXEVENT;
       if (pending == 0) pending = 1;
          for (i = 0; i < pending; i++)
              XNextEvent(&events[i]);
       ievent = 0;
       mevent = pending;
    }
    *event = events[ievent];
    ievent++;
}

struct llevent {
    int code;
    int * window;
    int detail;
    int gx;
    int gy;
    int x;
    int y;
    int w;
    int h;
};

i←peek←mouse (event) struct llevent *event; {
    XEvent rep;
    XPeekEvent (&rep);
    parse←event (event, &rep, 0);
}

i←read←mouse (event) struct llevent *event; {
    XEvent rep;
    XNextEvent(&rep);
    if (((rep.type) == EnterWindow) || ((rep.type) == LeaveWindow))
      if (XPending())
	XNextEvent(&rep);
    parse←event (event, &rep, 1);
}

flush←event () {
    XSync (1);
}

read←mouse (event)  struct llevent *event; {
	Window subw;
	short state;
	int x, y;
	XQueryMouseButtons(RootWindow, &x, &y, &subw, &state);
	event->gx = x & 0xffff;
	event->gy = y & 0xffff;
        event->detail = (state & 0x0700) ? (state & 0xffff) : 0;
}

set←event←mode (mode) int mode; {
    if(mode & 0x2)
      XCompressEvents ();
    else
      XExpandEvents();
    event←mode = mode;
}

int *
eventp (lispnil) int * lispnil; {
    return XPending() ? (int *) 1 : lispnil;
}


#define ASCII 256
#define MOVE 257
#define DRAG 258
#define DOWN 259
#define UP 260
#define MODIFY 264
#define KILL 265
#define REPAINT 266
#define RELEASE 267
#define ENTERWINDOW 268
#define LEAVEWINDOW 269
#define UNMAPWINDOW 270
#define FOCUSCHANGE 271
#define CODEBIDON 272


parse←event (event, rep, readp) 
struct llevent *event;
XEvent * rep;
int readp; {
/* readp est vrai si on est dans un READ-EVENT, faux dans un PEEK-EVENT */
    int     nbytes;
    char   *bytes;
    int   detail;
    /* L'e've'nement appartient a trois classes:
          - clavier
          - souris
          - fene↑tre
     */
    switch (rep -> type) {
    case MouseMoved:
    case ButtonPressed:
    case ButtonReleased:
	    parse←mouse←event(event, rep, readp); break;
    case KeyPressed:
    case KeyReleased:
	    parse←keyboard←event(event, rep, readp); break;
    default:
	    parse←window←event(event, rep, readp); break;
    }
}

#define bit(i,mask) ((i & mask)? 1 : 0)

parse←mouse←event(event, rep, readp)
struct llevent *event;
XEvent * rep;
int readp; {
int detail;
	/* recherche de la fene↑tre: downgrabber ou window de l'evt */
	event->window =
		(int *)XLookUpAssoc(assoctable,
				    downgrabber ?
				    downgrabber : rep->window);
        /* calcul du code et du detail */
        detail = ((XMouseMovedEvent *) rep) -> detail;
	switch(rep -> type) {
	case MouseMoved:
		event -> detail = bit(detail, MiddleMask)
			+ 2*bit(detail, RightMask);
		event -> code =
			detail & (LeftMask | MiddleMask | RightMask) ?
				DRAG : MOVE;
		break;
	case ButtonPressed:
		event->code = DOWN;
		if (readp) downgrabber = rep->window;
		event->detail = 2-(detail & 0xff);
		down←dx = (((XMouseMovedEvent *) rep) -> location >> 16)
		  - ((XMouseMovedEvent *) rep) -> x;
		down←dy = (((XMouseMovedEvent *) rep) -> location & 0xffff)
		  - ((XMouseMovedEvent *) rep) -> y;
		break;
	case ButtonReleased: 
		event->code = UP;
		if (readp) downgrabber = 0;
		event->detail = 2-(detail & 0xff);
		break;
	}
        event->detail += 3*bit(detail, ShiftMask) + 6*bit(detail, ControlMask)
				+ 9*bit(detail, MetaMask);
        set←x←y←gx←gy(event, rep);
}

parse←keyboard←event(event, rep, readp)
struct llevent *event;
XEvent * rep;
int readp; {
	int  nbytes;
	char *bytes;

	/* recherche de la fene↑tre: keyboardgrabber ou window de l'evt */
	event->window =
		(int *)XLookUpAssoc(assoctable,
				    keyboardgrabber ?
				    keyboardgrabber : rep->window);
	/* recheche du code et des caracteres */
	switch (rep -> type) {
        case KeyPressed: 
		bytes = XLookupMapping (rep, &nbytes);
		if (nbytes == 1){
			event->detail = *bytes;
			event->code = ASCII;
		}else{
			event->code = CODEBIDON;
			event->detail = '\33';
		}
		break;
        case KeyReleased:
		event->code = RELEASE;
		break;
	}
}

parse←window←event(event, rep, readp)
struct llevent *event;
XEvent * rep;
int readp; {
	/* recherche de la fene↑tre: window de l'evt */
	event->window = (int *)XLookUpAssoc(assoctable, rep -> window);

	switch (rep -> type) {
        case EnterWindow:
            event->code = ENTERWINDOW;
            break;
        case LeaveWindow:
            event->code = LEAVEWINDOW;
            break;
        case ExposeWindow: 
/* d'abord un resize */
            event->code = MODIFY;
	    event->x = (int) lispnil;
	    event->y = (int) lispnil;
            event->w = ((XExposeEvent *) rep) -> width;
            event->h = ((XExposeEvent *) rep) -> height;
/* qui sera suivi d'un repaint */
	    if (readp) {
		    rep -> type = ExposeRegion;
		    XPutBackEvent(rep);
	    }
            break;
        case ExposeRegion: 
            event->code = REPAINT;
            event->x = ((XExposeEvent *) rep) -> x;
            event->y = ((XExposeEvent *) rep) -> y;
            event->w = ((XExposeEvent *) rep) -> width;
            event->h = ((XExposeEvent *) rep) -> height;
            break;
        case UnmapWindow:
            event->code = UNMAPWINDOW;
            break;
        case FocusChange:
            event->code = FOCUSCHANGE;
            if (event->detail == LeaveWindow)
               event->window = lispnil;
            break;
        default: 
            event->code = CODEBIDON;
    }
}

find←window←number (window) Window window; {
int i;
   for (i = 0; (i<nwindow) && (windows[i]!=window); i++);
   return i;
}

set←x←y←gx←gy(event, rep) 
struct llevent *event;
XEvent * rep; {
Window subw;
    event -> gx = ((XMouseMovedEvent *) rep) -> location >> 16;
    event -> gy = ((XMouseMovedEvent *) rep) -> location & 0xffff;
    event -> x = event -> gx - down←dx;
    event -> y = event -> gy - down←dy;
    event->x &= 0xffff;
    event->y &= 0xffff;
}


/* le graphique */

int vecmode[16]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int vecmodei[16]={15, 7, 11, 3, 13, 5, 9, 1, 14, 6, 10, 2, 12, 4, 8, 0};

set←cur←mode (win, n) {
    MODE (win) = reversevideo ? vecmode[n] : vecmodei[n];
}

set←clip (win, x, y, w, h) {
    XConfigureWindow (clips[win], x, y, w, h);
    XLowerWindow(clips[win]);
    CLIPX(win) = x;
    CLIPY(win) = y;
    CLIPW(win) = w;
    CLIPH(win) = h;
}

draw←polymarker (win, n, vx, vy) 
int     vx[],
        vy[]; {
    int     next = 0;
    while (n) {
        vx = &vx[next];
        vy = &vy[next];
        next = fill←point (win, n, vx, vy);
        vertex←draw(win, vertex, 2*next);
        n -= next;
      }
}

fill←point (win, n, vx, vy) int vx[], vy[];{
int i, j, fill;
        fill = n*2 < MAXVERTEX ? n : MAXVERTEX/2;
        for(i = 0; i < fill; i+=1){
	  j = i+i;
	  vertex[j].x = vx[i]-CLIPX(win);
	  vertex[j].y = vy[i]-CLIPY(win);
	  vertex[j].flags = VertexDontDraw;
	  vertex[j+1].x = vx[i]-CLIPX(win);
	  vertex[j+1].y = vy[i]-CLIPY(win);
	  vertex[j+1].flags = 0;
        }
        return fill;
}

draw←point (win, x, y)
int     win,
        x,
        y; {
    draw←line (win, x, y, x+1, y+1);
}

draw←line (win, x0, y0, x1, y1) {
    Vertex line[2];
    line[0].x = x0-CLIPX(win); line[0].y = y0-CLIPY(win); line[0].flags = 0;
    line[1].x = x1-CLIPX(win); line[1].y = y1-CLIPY(win); line[1].flags = 0;
    vertex←draw(win, line, 2);
}

draw←rectangle (win, x, y, w, h) {
    Vertex rect[5];
    x -= CLIPX(win);
    y -= CLIPY(win);
    rect[0].x = x; rect[0].y = y; rect[0].flags = 0;
    rect[1].x = x; rect[1].y = y+h; rect[1].flags = 0;
    rect[2].x = x+w; rect[2].y = y+h; rect[2].flags = 0;
    rect[3].x = x+w; rect[3].y = y; rect[3].flags = 0;
    rect[4].x = x; rect[4].y = y; rect[4].flags = 0;
    vertex←draw(win, rect, 5);
}
    

draw←polyline (win, n, vx, vy) 
int     vx[],
        vy[]; {
    int     next = 0;
    while (n) {
        vx = &vx[next];
        vy = &vy[next];
        next = fill←vertex (win, n, vx, vy, 0);
        vertex←draw(win, vertex, next);
        n -= next;
    }
}

vertex←draw (win, vertex, n) Vertex *vertex; {
    if (LINE←STYLE (win)){
	XDrawDashed (clips[win], vertex, n,
		1, 1, ForePixel, LINE←STYLE(win),
		MODE(win), PLANES);
    }
    else
	XDraw (clips[win], vertex, n,
		1, 1, ForePixel, MODE (win), PLANES);
}

set←line←style (win, n) {
    LINE←STYLE(win) = line←style[n];
}

Pixmap
make←pattern (l1, l2) int l1, l2; {
    Bitmap b; Pixmap p; short vec[16]; int i;
    for (i=0; i < 16; i+=2) {
        vec[i]=l1; vec[i+1]=l2;
    }
    b = XStoreBitmap(16, 16, vec);
    p = XMakePixmap(b, WhitePixel, BlackPixel);
    XFreeBitmap(b);

    return(p);
}

init←pattern () {
   patterns[reversevideo ? 0 : 1] = make←pattern (0, 0);
   patterns[reversevideo ? 1 : 0] = make←pattern(0xffff, 0xffff);
   patterns[2] = reversevideo ?
	   make←pattern(0xaaaa, 0x5555) :
		   make←pattern(0x5555, 0xaaaa);
   patterns[reversevideo ? 3 : 4] = make←pattern(0x8888, 0x2222);
   patterns[reversevideo ? 4 : 3] = make←pattern(0x7777, 0xdddd);
}

set←cur←pattern(win, n) int win, n; {
        PATTERN(win)=patterns[n];
}

fill←area (win, n, vx, vy) int  vx[],
                                vy[]; {
    int     i;

    for(i = 0; i < n; i++){
                vertex[i].x = vx[i]-CLIPX(win);
                vertex[i].y = vy[i]-CLIPY(win);
                vertex[i].flags = 0;
    }
    vertex[i].x = vx[0]-CLIPX(win);
    vertex[i].y = vy[0]-CLIPY(win);
    vertex[i].flags = 0;
    vertex[0].flags = VertexStartClosed | VertexDontDraw;
    vertex[i].flags = VertexEndClosed;

#ifdef sun
    no←cursor (win);
#endif sun

    XDrawTiled (clips[win], vertex, i+1, PATTERN(win), MODE(win), PLANES);

#ifdef sun
    std←cursor (win);
#endif sun
  }

no←cursor (win) {
    XDefineCursor (clips[win], nocursor);
  }

std←cursor (win) {
    XDefineCursor (clips[win], cursor);
  }

fill←rectangle (win, x, y, w, h) {
    XTileFill(clips[win], x-CLIPX(win),
                y-CLIPY(win), w, h,
                PATTERN(win), 0, MODE(win), PLANES);
}

fill←vertex (win, n, vx, vy, flags) int vx[], vy[];{
int i, fill;
        fill = n < MAXVERTEX ? n : MAXVERTEX;
        for(i = 0; i < fill; i++){
                vertex[i].x = vx[i]-CLIPX(win);
                vertex[i].y = vy[i]-CLIPY(win);
                vertex[i].flags = flags;
        }
        return fill;
}

draw←ellipse(win, x, y, rx, ry) {
    fil←ver←ell (win, x, y, rx, ry);
    vertex←draw (win, vertex, 5);
}

fill←ellipse(win, x, y, rx, ry) {
    fil←ver←ell (win, x, y, rx, ry);
    XDrawTiled(clips[win], vertex, 5, PATTERN(win), MODE(win), PLANES);
}

fil←ver←ell (win, x, y, rx, ry) {
    x -= CLIPX(win);
    y -= CLIPY(win);
    vertex[0].x = x+rx;
    vertex[1].x = x;
    vertex[2].x = x-rx;
    vertex[3].x = x;
    vertex[4].x = x+rx;

    vertex[0].y = y;
    vertex[1].y = y-ry;
    vertex[2].y = y;
    vertex[3].y = y+ry;
    vertex[4].y = y;

    vertex[0].flags = VertexCurved | VertexStartClosed;
    vertex[1].flags = VertexCurved;
    vertex[2].flags = VertexCurved;
    vertex[3].flags = VertexCurved;
    vertex[4].flags = VertexCurved | VertexEndClosed;
}

draw←vertex(win, n, vx, vy, vf) int vx[], vy[], vf[];{
int i;
    for(i=0; i<n; i++){
       vertex[i].x=CLIPX(win)+vx[i];
       vertex[i].y=CLIPY(win)+vy[i];
       vertex[i].flags=vf[i];
    }
    XDraw(clips[win], vertex, n, 1, 1, ForePixel, MODE(win), PLANES);
}

tile←vertex(win, n, vx, vy, vf) int vx[], vy[], vf[];{
int i;
    for(i=0; i<n; i++){
       vertex[i].x=CLIPX(win)+vx[i];
       vertex[i].y=CLIPY(win)+vy[i];
       vertex[i].flags=vf[i];
    }
    XDrawTiled(clips[win], vertex, n, PATTERN(win), MODE(win), PLANES);
}

/* Les ico↑nes */

getpixmap (win, x, y, w, h, data) char *data; {
    x -= CLIPX(win);
    y -= CLIPY(win);
    XPixmapGetXY (clips[win], x, y, w, h, data);
}

putpixmap (win, xs, ys, xd, yd, w, h, pixmap) Pixmap *pixmap; {
    xd -= CLIPX(win);
    yd -= CLIPY(win);
    XPixmapPut (clips[win], xs, ys, xd, yd, w, h, pixmap, MODE(win), PLANES);
}

copyarea (win, xd, yd, xs, ys, w, h) {
    xd -= CLIPX(win);
    yd -= CLIPY(win);
    xs -= CLIPX(win);
    ys -= CLIPY(win);
    XCopyArea (clips[win], xd, yd, xs, ys, w, h, MODE(win), PLANES);
}

Window Xwindow (win) { return windows[win];}

int llreversevideo () { return reversevideo; }

bidon () {
XFreePixmap();
XFreeBitmap();
XStoreBitmap();
XLine();
XMakePixmap();
XStorePixmapXY();
XPixmapBitsPutXY();
XPixmapGetXY();
XPixmapSave();
}

Window rootwindow() { return(RootWindow); }

int make←color (r, g, b) int r, g, b; {
  Color color;
  color.red = r;
  color.green = g;
  color.blue = b;
  return XGetHardwareColor(&color) ? color.pixel : 0;
}

set←foreground (pixel) {
  ForePixel = pixel;
}

set←background (pixel) {
  BackPixel = pixel;
}