/*
 * disp.c
 */

#ifdef  X11_DISP

#include <stdio.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "corewar.h"
#include "cwdisp.h"

/*
 * Values that describe the X environment that I keep around as globals.
 * Shame on me!
 */
aval_t di_next_move = AVAL_NOGOOD;
int  di_next_player;
unsigned long  di_stdfg, di_stdbg;
unsigned  di_depth, di_picsize;
Window  di_win;
XFontStruct  *di_bfontstr, *di_sfontstr, *di_ffontstr;
Font  di_bfont, di_sfont, di_ffont;
Display  *di_dpy;
unsigned  di_winw = -1, di_winh = -1, di_width, di_height;
int  di_ti_x, di_ti_y, di_color;
Colormap  di_cmap;

/* Local stuff, used for the overall init only. */
#define kothicon_width 51
#define kothicon_height 51
static char kothicon_bits[] = {
   0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x07, 0x00, 0x07, 0x20, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x18, 0x10,
   0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x18, 0x00, 0x00,
   0xc0, 0x04, 0x00, 0x00, 0x04, 0x00, 0x07, 0x00, 0x03, 0x00, 0x00, 0x02,
   0xf0, 0x7a, 0x00, 0x02, 0x00, 0x00, 0x01, 0x0c, 0x82, 0x01, 0x04, 0x00,
   0x00, 0x01, 0x03, 0x02, 0x06, 0x04, 0x00, 0x80, 0x80, 0x00, 0x02, 0x08,
   0x08, 0x00, 0x40, 0x40, 0x00, 0x02, 0x10, 0x10, 0x00, 0x40, 0x20, 0x00,
   0x02, 0x28, 0x10, 0x00, 0x20, 0x10, 0x00, 0x02, 0x44, 0x20, 0x00, 0x20,
   0x10, 0x00, 0x02, 0x42, 0x20, 0x00, 0x20, 0x08, 0x80, 0x0a, 0x81, 0x20,
   0x00, 0x10, 0x08, 0x40, 0x92, 0x80, 0x40, 0x00, 0x10, 0x04, 0xa0, 0x4a,
   0x00, 0x41, 0x00, 0x10, 0x04, 0x50, 0x22, 0x00, 0x41, 0x00, 0x10, 0x04,
   0xa8, 0x92, 0x00, 0x41, 0x00, 0x08, 0x04, 0x54, 0x4a, 0x01, 0x81, 0x00,
   0x08, 0x02, 0x00, 0x06, 0x00, 0x82, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
   0x83, 0x07, 0x08, 0x02, 0x00, 0x03, 0x00, 0x82, 0x00, 0x08, 0x44, 0x95,
   0x52, 0x15, 0x81, 0x00, 0x10, 0xa4, 0x4a, 0xaa, 0x2a, 0x41, 0x00, 0x10,
   0x54, 0x25, 0x52, 0x55, 0x41, 0x00, 0x10, 0xa4, 0x92, 0xaa, 0x2a, 0x41,
   0x00, 0x10, 0x48, 0x49, 0x52, 0x95, 0x40, 0x00, 0x20, 0xa8, 0xa4, 0xaa,
   0xaa, 0x20, 0x00, 0x20, 0x50, 0x52, 0x52, 0x55, 0x20, 0x00, 0x20, 0x10,
   0xa9, 0xaa, 0x4a, 0x20, 0x00, 0x40, 0xa0, 0x54, 0x52, 0x25, 0x10, 0x00,
   0x40, 0x40, 0xaa, 0xaa, 0x12, 0x10, 0x00, 0x80, 0xa0, 0x54, 0x52, 0x09,
   0x08, 0x00, 0x00, 0x11, 0xa3, 0x2a, 0x06, 0x04, 0x00, 0x00, 0x09, 0x0c,
   0x82, 0x01, 0x04, 0x00, 0x00, 0x06, 0xf0, 0x7a, 0x00, 0x02, 0x00, 0x00,
   0x06, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x19, 0x00, 0x02, 0xc0, 0x00,
   0x00, 0x80, 0x20, 0x00, 0x02, 0x20, 0x00, 0x00, 0x40, 0xc0, 0x00, 0x02,
   0x18, 0x00, 0x00, 0x20, 0x00, 0x07, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00,
   0x78, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};
#define kothmask_width 51
#define kothmask_height 51
static char kothmask_bits[] = {
   0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
   0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xff, 0xff, 0x07, 0x30, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x1f, 0x18,
   0x00, 0x00, 0xe0, 0xff, 0xff, 0x3f, 0x0c, 0x00, 0x00, 0xf8, 0xff, 0xff,
   0xff, 0x06, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0xfe,
   0xff, 0xfb, 0xff, 0x03, 0x00, 0x00, 0xff, 0x0f, 0x83, 0xff, 0x07, 0x00,
   0x00, 0xff, 0x03, 0x03, 0xfe, 0x07, 0x00, 0x80, 0xff, 0x00, 0x03, 0xf8,
   0x0f, 0x00, 0xc0, 0x7f, 0x00, 0x03, 0xf8, 0x1f, 0x00, 0xc0, 0x3f, 0x00,
   0x03, 0xec, 0x1f, 0x00, 0xe0, 0x1f, 0x00, 0x03, 0xc6, 0x3f, 0x00, 0xe0,
   0x1f, 0x00, 0x07, 0xc3, 0x3f, 0x00, 0xe0, 0x0f, 0x80, 0x8f, 0x81, 0x3f,
   0x00, 0xf0, 0x0f, 0xc0, 0xdf, 0x80, 0x7f, 0x00, 0xf0, 0x07, 0xe0, 0x7f,
   0x00, 0x7f, 0x00, 0xf0, 0x07, 0xf0, 0x7f, 0x00, 0x7f, 0x00, 0xf0, 0x07,
   0xf8, 0xff, 0x00, 0x7f, 0x00, 0xf8, 0x07, 0xfc, 0xff, 0x01, 0xff, 0x00,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0x07, 0xf8, 0x83, 0xff, 0xff, 0x0f, 0xfe, 0x00, 0xf8, 0xc7, 0xff,
   0xff, 0x1f, 0xff, 0x00, 0xf0, 0xe7, 0xff, 0xff, 0x3f, 0x7f, 0x00, 0xf0,
   0xf7, 0xff, 0xff, 0x7f, 0x7f, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x7f,
   0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xe0, 0xff, 0xff, 0xff,
   0xff, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xe0, 0xff,
   0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00,
   0xc0, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
   0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff,
   0xff, 0xff, 0x07, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00,
   0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x80, 0xf9, 0xff, 0xff, 0xff, 0x00,
   0x00, 0xc0, 0xe0, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x60, 0xc0, 0xff, 0xff,
   0x1f, 0x00, 0x00, 0x30, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
   0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00};
static int  last_cyc = 0;

/* Values describing the core display of the screen. */
unsigned  di_co_xoff, di_co_yoff;
char  *di_co_pics = NULL;
Pixmap  di_pixmaps[MAXPICS];
Pixmap  di_bigpixmaps[MAXPICS];
GC  di_picgc[MAXPICS];
int  *di_picmap;
int  di_nprocs[DI_MAXPLAYERS], di_nalive;
int  di_state = DS_STOPPED, di_slopos;
float  di_speed;

/* Values describing the player status windows. */
di_plstatinfo  di_plstat[DI_MAXPLAYERS];

/* Values describing the cycles display. */
int  *di_cyx = NULL, di_cyty, di_cyby, *di_cyw = NULL, di_cyh;
GC  di_cytgc, di_cybgc;

/* Buttons! */
unsigned  di_butbw;
GC  di_butgc, di_butlgc, di_butdgc;

/* Global info. */
program_t  di_progs[DI_MAXPLAYERS];
unsigned  di_cycles = 0;

static void  ehandle(Display *dpy), stealth();
static void  di_mainloop(Display *dpy, Window win, int fightlen);


void  di_init(char *progname, char *geometry, char *dpyname, int iconic,
              unsigned fightlen)  {
	Window  win;
	int  win_x, win_y;  /* Window position on screen. */
	unsigned  win_w, win_h;
	Display  *dpy;
	char  *display_name;
	XSizeHints  xsh;
	XWMHints  wm_hints;
	XClassHint  class_hints;
	XTextProperty  windowName, iconName;
	XWindowAttributes  xwa;
	unsigned  i, hintmask;
	int  defscr;
	XVisualInfo  xvi;
	Pixmap  koth_pixmap, mask_pixmap;
	XSizeHints  size_hints;
	char  *cw_name = "Corewar";

	if ((dpy = di_dpy = XOpenDisplay(dpyname)) == NULL)  {
		fprintf(stderr, "%s: Can't open display \"%s\".\n", progname,
		        XDisplayName(dpyname));
		exit(1);
	}
	defscr = DefaultScreen(dpy);
	di_depth = DefaultDepth(dpy, defscr);
	di_cmap = DefaultColormap(dpy, defscr);
	di_color = (XMatchVisualInfo(dpy, defscr, di_depth, StaticColor, &xvi) ||
	            XMatchVisualInfo(dpy, defscr, di_depth, TrueColor, &xvi) ||
	            XMatchVisualInfo(dpy, defscr, di_depth, PseudoColor, &xvi) ||
	            XMatchVisualInfo(dpy, defscr, di_depth, DirectColor, &xvi));
	di_stdfg = BlackPixel(dpy, defscr);
	if (di_color)  {
		XColor  grey75;

		grey75.red = grey75.green = grey75.blue = 0.75 * MAX_CVAL;
		grey75.flags = DoRed | DoGreen | DoBlue;
		XAllocColor(dpy, di_cmap, &grey75);
		di_stdbg = grey75.pixel;
	} else
		di_stdbg = WhitePixel(dpy, defscr);
	hintmask = 0;
	win_x = 0;
	win_y = 0;
	win_w = 700;
	win_h = (int)((double)win_w / WHRATIO);
	if (geometry != NULL)  {
		char  xdir = '+', ydir = '+';
		int  pcount;

		if (geometry[0] == '=')
			++geometry;
		if ((geometry[0] == '+') || (geometry[0] == '-'))  {
			hintmask |= USPosition;
			pcount = sscanf(geometry, "%c%d%c%d", &xdir, &win_x, &ydir, &win_y);
			if ((pcount != 4) ||
					((xdir != '-') && (xdir != '+')) ||
					((ydir != '-') && (ydir != '+')))  {
				fprintf(stderr, "%s: Cannot understand geometry \"%s\".\n",
				        progname, geometry);
				exit(-1);
			}
		} else  {
			hintmask |= USSize;
			pcount = sscanf(geometry, "%dx%d%c%d%c%d", &win_w, &win_h,
			                &xdir, &win_x, &ydir, &win_y);
			if (pcount != 2)
				hintmask |= USPosition;
			if ((pcount != 2) && (pcount != 6) ||
					((xdir != '-') && (xdir != '+')) ||
					((ydir != '-') && (ydir != '+')))  {
				fprintf(stderr, "%s: Cannot understand geometry \"%s\".\n",
				        progname, geometry);
				exit(-1);
			}
		}
		if (xdir == '-')
			win_x = DisplayWidth(dpy, defscr) - win_x - win_w;
		if (ydir == '-')
			win_y = DisplayHeight(dpy, defscr) - win_y - win_h;
	}

	win = XCreateSimpleWindow(dpy, RootWindow(dpy, defscr), win_x, win_y,
	                          win_w, win_h, 0, di_stdbg, di_stdfg);
	koth_pixmap = XCreateBitmapFromData(dpy, win, kothicon_bits,
	                                    kothicon_width, kothicon_height);
	mask_pixmap = XCreateBitmapFromData(dpy, win, kothmask_bits,
	                                    kothmask_width, kothmask_height);
	size_hints.flags = PPosition | PSize | PMinSize | hintmask;
	size_hints.min_width = 200;
	size_hints.min_height = 150;
#ifdef  X11R3
	size_hints.x = win_x;
	size_hints.y = win_y;
	size_hints.width = win_w;
	size_hints.height = win_h;
	XSetStandardProperties(dpy, win, "Corewar", "Corewar", koth_pixmap,
												 NULL, 0, &size_hints);
#else  /* X11R4 or later. */
	{
		XWMHints  wm_hints;
		XClassHint  class_hints;
		XTextProperty windowName, iconName;
		char  *dumb_argv[] = {NULL};

		if (XStringListToTextProperty(&cw_name, 1, &windowName) == 0)  {
			fprintf(stderr, "Cannot allocate windowName.\n");
			exit(-1);
		}
		if (XStringListToTextProperty(&cw_name, 1, &iconName) == 0)  {
			fprintf(stderr, "Cannot allocate windowName.\n");
			exit(-1);
		}
		if (iconic)
			wm_hints.initial_state = IconicState;
		else
			wm_hints.initial_state = NormalState;
		wm_hints.input = TRUE;
		wm_hints.icon_pixmap = koth_pixmap;
		wm_hints.icon_mask = mask_pixmap;
		wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint;
		class_hints.res_name = "koth";
		class_hints.res_class = "Basicwin";
		XSetWMProperties(dpy, win, &windowName, &iconName, dumb_argv, 0,
										 &size_hints, &wm_hints, &class_hints);
	}
#endif  X11R3
	di_win = win;
	XSelectInput(dpy, win, ExposureMask | StructureNotifyMask |
							 PointerMotionMask | ButtonPressMask | KeyPressMask |
							 ButtonReleaseMask | KeyReleaseMask);
	XMapWindow(dpy, win);
	gbut_init(dpy, win);
	di_in_init();
	di_dis_init();
	XGetWindowAttributes(dpy, win, &xwa);
	di_nalive = 0;
	for (i = 0;  i < DI_MAXPLAYERS;  ++i)
		di_nprocs[i] = NOTLOADED;
	di_reset_cy();
	interactive = TRUE;
	di_redraw(dpy, win, &xwa, 0, 0, xwa.width, xwa.height);
	signal(SIGQUIT, di_exit);
	/* OK, window is opened.  Time to go stealth, as xantfarm did. */
	stealth();
	for (;;)  {
		if ((di_nalive == 0) || (di_cycles == -1))  {
			last_cyc = 0;
			di_cycles = 0;
		}
		do  {
			di_mainloop(dpy, win, fightlen);
		} while ((di_state != DS_STOPPED) && !XPending(dpy));
		if (di_state == DS_STOPPED)  {
			XEvent  dummy;

			XPeekEvent(dpy, &dummy);  /* Wait for an event. */
		}
		ehandle(dpy);
	}
}


static void  di_mainloop(Display *dpy, Window win, int fightlen)  {
	int  cycle, n;
	aval_t  old_nextmove;

	if (di_state == DS_RUNSLOW)
		if (!di_timer_wait(dpy))
			return;
	if (!di_nalive)  {
		di_changestate(dpy, win, DS_STOPPED);
		gbut_setflags(DI_BSTOP, GBUT_NOPRESS);
		gbut_setflags(DI_BSLOW, GBUT_NOPRESS);
		gbut_setflags(DI_BGO, GBUT_NOPRESS);
		return;
	}
	for (cycle = last_cyc;  cycle < DI_MAXPLAYERS;  ++cycle)  {
		if ((di_nprocs[cycle] == 0) || (di_nprocs[cycle] == NOTLOADED))
			continue;
		if ((di_state == DS_STOPPED) || XPending(dpy))  {
			last_cyc = cycle;
			return;
		}
		old_nextmove = di_next_move;
		n = sim_cyc();
		di_next_move = sim_nextaddr();
		di_next_player = sim_nextplayer();
		if (di_indis[old_nextmove])
			di_fixline(old_nextmove);
		if (di_indis[di_next_move])
			di_fixline(di_next_move);
		if (n != di_nprocs[cycle])  {
			if (n == 0)  {
				--di_nalive;
				if (di_nalive <= 1)  {
					di_changestate(dpy, win, DS_STOPPED);
					if (di_nalive < 1)  {
						gbut_setflags(DI_BSTOP, GBUT_NOPRESS);
						gbut_setflags(DI_BSLOW, GBUT_NOPRESS);
						gbut_setflags(DI_BGO, GBUT_NOPRESS);
					}
					di_draw_nprocs(cycle, di_nprocs[cycle] = n, dpy, win);
					last_cyc = cycle;
					return;
				}
			}
			di_draw_nprocs(cycle, di_nprocs[cycle] = n, dpy, win);
		}
		if (di_state == DS_STEP)
			di_state = DS_STOPPED;
	}
	if (cycle >= DI_MAXPLAYERS)  {
		if (++di_cycles == fightlen)
			di_changestate(dpy, win, DS_STOPPED);
		di_update_cy(dpy, win);
		last_cyc = 0;
	}
}


void  di_changestate(Display *dpy, Window win, int newstate)  {
	int  oldstate = di_state, i;

	if ((newstate == oldstate) && (newstate != DS_RUNSLOW))
		return;
	di_state = newstate;
	switch(oldstate)  {
	case DS_STOPPED:
	case DS_STEP:
		for (i = 0;  i < DI_MAXPLAYERS;  ++i)  {
			gbut_setflags(DI_BPLAY(i), GBUT_NOPRESS);
		}
		if ((newstate != DS_STEP) && (newstate != DS_STOPPED))  {
			di_but[DI_BSTOP].packet = (void *)"Stop";
			gbut_draw(DI_BSTOP);
			if (newstate == DS_RUNSLOW)
				gbut_draw(DI_BSLOW);
		}
		break;
	case DS_RUNSLOW:
		di_unset_timer();
	case DS_RUNFAST:
		if ((newstate == DS_RUNSLOW) || (oldstate == DS_RUNSLOW))
			gbut_draw(DI_BSLOW);
		if ((newstate != DS_RUNFAST) && (newstate != DS_RUNSLOW))  {
			di_but[DI_BSTOP].packet = (void *)"Step";
			gbut_draw(DI_BSTOP);
		}
		break;
	}
}

		
static void  ehandle(Display *dpy)  {
	XEvent  event;
	XWindowAttributes  xwa;
	int  redraw_needed = FALSE, rdrw2 = FALSE, rdrw3 = FALSE, wagot = FALSE;
	unsigned  rx1 = -1, ry1 = -1, rx2 = 0, ry2 = 0;

	while (XPending(dpy))  {
		XNextEvent(dpy, &event);
		switch(event.type)  {
		case Expose:
			if (event.xexpose.window == di_win)  {
				if (event.xexpose.x < rx1)
					rx1 = event.xexpose.x;
				if (event.xexpose.y < ry1)
					ry1 = event.xexpose.y;
				if (event.xexpose.x + event.xexpose.width > rx2)
					rx2 = event.xexpose.x + event.xexpose.width;
				if (event.xexpose.y + event.xexpose.height > ry2)
					ry2 = event.xexpose.y + event.xexpose.height;
				redraw_needed = TRUE;
			} else if ((di_win2w != 0) && (event.xexpose.window == di_win2))
				rdrw2 = TRUE;
			else  { /* Must be a win3. */
				XGetWindowAttributes(dpy, event.xexpose.window, &xwa);
				di_redraw3(dpy, event.xexpose.window, xwa.x,xwa.y,
									 xwa.width,xwa.height);
			}
			break;
		case ConfigureNotify:
			if (event.xexpose.window == di_win)  {
				if (!wagot)  {
					XGetWindowAttributes(dpy, di_win, &xwa);
					wagot = TRUE;
				}
				if ((xwa.width != di_winw) || (xwa.height != di_winh))  {
					redraw_needed = TRUE;
					rx1 = 0;
					ry1 = 0;
					rx2 = xwa.width;
					ry2 = xwa.height;
				}
			} else if ((di_win2w != 0) && (event.xexpose.window == di_win2))
				rdrw2 = TRUE;
			else  { /* Must be a win3. */
				XGetWindowAttributes(dpy, event.xexpose.window, &xwa);
				di_redraw3(dpy, event.xexpose.window, xwa.x,xwa.y,
									 xwa.width,xwa.height);
			}
			break;
		case MapNotify:  /* Who cares about these? */
		case ReparentNotify:
		case UnmapNotify:
			break;
		case DestroyNotify:  /* I should handle this correctly. */
/*
			fprintf(stderr, "koth: Window destroyed unexpectedly.\n");
			exit(1);
*/
			break;
		case ButtonPress:
			di_butpress(dpy, event.xbutton.window, &(event.xbutton));
			break;
		case ButtonRelease:
			di_butrelease(dpy, event.xbutton.window, &(event.xbutton));
			break;
		case KeyPress:
			di_keypress(dpy, event.xkey.window, &(event.xkey));
			break;
		case KeyRelease:
			di_keyrelease(dpy, event.xkey.window, &(event.xkey));
			break;
		case MotionNotify:
			if (XPending(dpy))  {
				XEvent  ev2;

				XPeekEvent(dpy, &ev2);
				if (ev2.type == MotionNotify)
					break;
			}
			di_input_m(dpy, event.xmotion.window, &(event.xmotion));
			break;
		}
	}
	if (redraw_needed)  {
		if (!wagot)
			XGetWindowAttributes(dpy, di_win, &xwa);
		if (rx1 == -1)  {
			rx1 = 0;
			ry1 = 0;
			rx2 = xwa.width;
			ry2 = xwa.height;
		}
		di_redraw(dpy, di_win, &xwa, rx1, ry1, rx2-rx1, ry2-ry1);
	}
	if (rdrw2)  {
		XGetWindowAttributes(dpy, di_win2, &xwa);
		if (xwa.map_state == IsViewable)
			di_redraw2(dpy, di_win2, &xwa);
	}
}


void  di_drawaddr(aval_t addr, int val)  {
	if (((di_picmap[addr]&~CP_M) != val) && (addr < 8000))  {
		XFillRectangle(di_dpy, di_win, di_picgc[val],
									 (addr % 100) * di_picsize + di_co_xoff,
									 (addr / 100) * di_picsize + di_co_yoff,
									 di_picsize, di_picsize);
		if (di_picmap[addr]&CP_M)
			di_drawoutline(addr, di_picmap[addr]);
		di_picmap[addr] = (di_picmap[addr] & CP_M) | val;
	}
	if (di_indis[addr])
		di_fixline(addr);
}


void  di_newoutline(aval_t addr, int val)  {
	int  oldval, pic;

	addr = (addr + coresize) % coresize;
	oldval = di_picmap[addr] & CP_M;
	if ((oldval && val) || (!oldval && !val))
		return;
	pic = di_picmap[addr] & ~CP_M;
	XFillRectangle(di_dpy, di_win, di_picgc[pic],
								 (addr % 100) * di_picsize + di_co_xoff,
								 (addr / 100) * di_picsize + di_co_yoff,
								 di_picsize, di_picsize);
	if (val)
		di_drawoutline(addr, val);
	di_picmap[addr] = pic | val;
}

		
void  di_exit(int  exval)  {
	XFlush(di_dpy);
	XCloseDisplay(di_dpy);
	exit(exval);
}


static void  stealth()  {
	int pid, tty;

#ifndef  DEBUG
	pid = fork();
	if (pid < 0)  {
		perror("koth: fork() failed");
		exit(1);
	} else if (pid > 0)
		/* Parent just exits. */
		exit(0);
	/* Go stealth (ditch our controlling tty). */
	tty = open("/dev/tty", 0);
	if (tty < 0)  {
		perror("koth: open(\"/dev/tty\", 0) failed");
		exit(1);
	} else  {
		if (ioctl(tty, TIOCNOTTY, 0) < 0)  {
	    perror("koth: ioctl(tty, TIOCNOTTY, 0) failed");
	    exit(1);
		}
		close(tty);
	}
#endif  DEBUG
}


#endif  /* X11_DISP */
