DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T X

⟦0e3259af6⟧ TextFile

    Length: 28618 (0x6fca)
    Types: TextFile
    Names: »X10.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xconq/X10.c« 

TextFile

/* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
/* This program may be used, copied, modified, and redistributed freely */
/* for noncommercial purposes, so long as this notice remains intact. */

/* RCS $Header: X10.c,v 1.1 88/06/21 12:29:56 shebs Exp $ */

/* Interface implementations for the X10 version of xconq. */

/* Warning: all of these routines are "bare", in that active_display */
/* is assumed to have already switched to the correct display.  Do not */
/* call these in any other context! */

#include "config.h"
#include "misc.h"
#include "period.h"
#include "side.h"
#include "unit.h"
#include "map.h"
#include "global.h"

/* Some perverse X installations may need to change the Xlib include. */

#ifdef UNIX
#include <signal.h>   /* needed for ^C disabling */
#include <X/Xlib.h>
#endif UNIX

/* Bitmap that will become a tile for a dotted background. */

#define dots_width 16
#define dots_height 16
static short dots_bits[] = {
   0x0101, 0x0000, 0x0000, 0x0000,
   0x1010, 0x0000, 0x0000, 0x0000,
   0x0101, 0x0000, 0x0000, 0x0000,
   0x1010, 0x0000, 0x0000, 0x0000};

/* Bitmaps to make the "unit cursor" (white box with black surround). */

#define mask_width 16
#define mask_height 16
static short mask_bits[] = {
   0x03e0, 0x0fd8, 0x19b4, 0x218a,
   0x6186, 0x4185, 0xc183, 0xffff,
   0xffff, 0xc183, 0xa182, 0x6186,
   0x5184, 0x2d98, 0x1bf0, 0x07c0};

#define curs_width 16
#define curs_height 16
static short curs_bits[] = {
   0x03e0, 0x0c98, 0x1084, 0x2082,
   0x2082, 0x4081, 0x4081, 0x7fff,
   0x4081, 0x4081, 0x2082, 0x2082,
   0x1084, 0x0c98, 0x03e0, 0x0000};

/* Large bitmaps to make flashy picture of mushroom cloud. */

#define bomb1_width 32
#define bomb1_height 32
static short bomb1_bits[] = {
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0xc000, 0x0001, 0xf000, 0x0007,
   0xf000, 0x0007, 0xf800, 0x000f,
   0xf800, 0x000f, 0xfc00, 0x000f,
   0xfe00, 0x001f, 0xfe00, 0x003f,
   0xfe00, 0x003f, 0xfc00, 0x001f,
   0x0000, 0x0000, 0x0000, 0x0000};

#define bomb2_width 32
#define bomb2_height 32
static short bomb2_bits[] = {
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0xf800, 0x0001,
   0xf800, 0x0007, 0xfc00, 0x000f,
   0xfc00, 0x001f, 0xfe00, 0x001f,
   0xfe00, 0x003f, 0xfc00, 0x001f,
   0xfc00, 0x000f, 0xf000, 0x0007,
   0xf000, 0x0003, 0xe000, 0x0003,
   0xf000, 0x0007, 0xf000, 0x0007,
   0xf000, 0x000f, 0xf000, 0x000f,
   0xf800, 0x000f, 0xf800, 0x001f,
   0xf800, 0x001f, 0xfc00, 0x001f,
   0xff00, 0x007f, 0xffc0, 0x03ff,
   0x0000, 0x0000, 0x0000, 0x0000};

#define bomb3_width 32
#define bomb3_height 32
static short bomb3_bits[] = {
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0xe2fe, 0x3fa3,
   0xfc00, 0x001f, 0xff3c, 0x7c7f,
   0xff80, 0x00ff, 0xffc0, 0x01ff,
   0xffc0, 0x01ff, 0xffe0, 0x03ff,
   0xffe0, 0x03ff, 0xffe0, 0x03ff,
   0xffe0, 0x01ff, 0xffe0, 0x49ff,
   0xff82, 0x34ff, 0xfe14, 0x423f,
   0xffe2, 0x349f, 0xfe40, 0x413f,
   0xfdbe, 0x1edf, 0xf800, 0x011f,
   0xfdfe, 0x7fdf, 0xfc00, 0x001f,
   0xfc00, 0x001f, 0xfc00, 0x003f,
   0xfe00, 0x001f, 0xfe00, 0x003f,
   0xff00, 0x003f, 0xffc0, 0x00ff,
   0xfffc, 0x3fff, 0xfffe, 0x7fff,
   0x0000, 0x0000, 0x0000, 0x0000};

#define bomb4_width 32
#define bomb4_height 32
static short bomb4_bits[] = {
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0xc000, 0x0007,
   0x7800, 0x0010, 0x0f00, 0x0046,
   0x6180, 0x0081, 0x1cc0, 0x0100,
   0x0240, 0x0000, 0x0120, 0x0000,
   0x0120, 0x0000, 0x0020, 0x0000,
   0x0020, 0x0000, 0x0040, 0x0000,
   0x0080, 0x0000, 0x0200, 0x0000,
   0x0200, 0x0000, 0x0400, 0x0000,
   0x0400, 0x0000, 0x0000, 0x0000,
   0x0400, 0x0000, 0x0000, 0x0000,
   0x0400, 0x0000, 0x0000, 0x0000,
   0x0400, 0x0000, 0x0200, 0x0000,
   0x0100, 0x0000, 0x00c0, 0x0000,
   0x002c, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000};

#define INFOLINES 4

/* Beware - this macro mentions a normal variable "side"! */

#define sd() ((Screen *) side->display)

/* The next set of definitions has been carefully designed to work with */
/* 16x16 unit icons.  They do not, however, require any particular font */
/* size, and will even work with text fonts properly. */

int hw = 20;                 /* width of box enclosing hex */
int hh = 22;                 /* height of box enclosing hex */
int hch = 17;                /* center-to-center height is less */
int margin = 2;              /* pixels between window edge and text */
int bd = 1;                  /* width of internal window borders */

int helpwinlines = 1;        /* will eventually be size of help window */

/* This structure contains all things that we need to feed to X. */

typedef struct a_screen {
    Display *disp;            /* the X display structure proper */
    Font textfont;            /* font for text display */
    Font iconfont;            /* utility font with assorted icons */
    Font unitfont;            /* font for unit characters */
    Bitmap ccurs, cmask;      /* Bitmaps for unit "cursor" */
    Bitmap mcurs, mmask;      /* bitmaps for cursor that tracks mouse */
    Bitmap dots;              /* basic dotted background pattern */
    Bitmap bombpics[4];       /* mushroom clouds */
    Bitmap unitpics[MAXUTYPES];  /* used instead of font sometimes */
    Pixmap bdtile, wbdots, bwdots;  /* blue border and dotted backgrounds */
    Cursor curs;              /* the cursor object itself */
} Screen;

extern int giventime;

Screen screens[MAXSIDES];     /* one of those screen objects per side */

bool rootcursor;              /* true if cursor creation fails */

/* Put in a default player, probably the invoker of the program. */
/* An empty host name will confuse the program. */

add_default_player()
{
#ifdef UNIX
    add_player(TRUE, getenv("DISPLAY"));
#endif UNIX
}

/* Ignore ^C if humans in the game, do it otherwise, including when the */
/* last human player turns into a machine (this is called by option cmd). */
/* Attempts to be more clever seem to cause trouble. */

init_sighandlers()
{
#ifdef UNIX
    if (numhumans > 0 && !Debug) {
	signal(SIGINT, SIG_IGN);
    } else {
	signal(SIGINT, SIG_DFL);
    }
#endif UNIX
}

/* Since X needs all various objects to do its work, we have to make space */
/* in a per-side structure. */

open_display(side)
Side *side;
{
    side->display = (long) &(screens[side_number(side)]);
    sd()->disp = XOpenDisplay(side->host);
    return (sd()->disp != NULL);
}

/* A predicate that tests whether our display can safely be written to. */
/* If so, it activates the display (so random routines don't need to). */
/* X version 10 has the notion of a "current display".  Bad things happen */
/* if you attempt to do anything to any non-current display... */

active_display(side)
Side *side;
{
    if (side && side->host && !side->lost && side->display) {
	XSetDisplay(sd()->disp);
	return TRUE;
    } else {
	return FALSE;
    }
}

/* A little trickery here so that the main window doesn't cover everything. */

display_width(side) Side *side; {  return ((19 * DisplayWidth()) / 20);  }

display_height(side) Side *side; {  return ((19 * DisplayHeight()) / 20); }

/* Most X displays have enough screen to do a world map. */

world_display(side) Side *side; {  return TRUE;  }

/* Handlers for X catastrophes attempt to do a save first. */
/* Could be more friendly and check success of save, but can't do anything */
/* about it anyway... */

handle_x_error(disp, evt)
Display *disp;
XErrorEvent *evt;
{
    printf("\nX error: trying emergency save!\n");
    write_savefile(SAVEFILE);
    abort();
}

handle_xio_error(disp)
Display *disp;
{
    printf("\nX IO error: trying emergency save!\n");
    write_savefile(SAVEFILE);
    exit(1);
}

/* Xconq needs 2 or 3 fonts - one for normal messages, one for standard */
/* pictures (cursor, terrain pics, etc), and an optional font for a period's */
/* units.  The last is optional because bitmaps might be used instead. */
/* The character font is nothing unusual, but the other fonts are not a */
/* standard part of X, so we look for them either in the usual place or in */
/* the library directory, and will even subsitute text if necessary. */
/* Note that xconq will fail utterly if even the text font can't be opened. */

/* Also do the rigmarole to convert all those short arrays into X-approved */
/* Bitmaps.  Note that this has to be for *each* display separately (!) */
/* Also get the cursor shape.  If the hardware can't hack the desired */
/* cursor size, warn about it and just use the root window's cursor. */
/* 0x0 cursor specs seem to be don't cares - machine can handle any size */

init_misc(side)
Side *side;
{
    int u, w, h;
    FontInfo fontinfo;

    side->margin = margin;
    side->bd = bd;
    sd()->textfont = open_font(TEXTFONT, "TextFont", NULL);
    XQueryFont(sd()->textfont, &fontinfo);
    side->fw = fontinfo.width;
    side->fh = fontinfo.height;
    sd()->iconfont = open_font(ICONFONT, "IconFont", sd()->textfont);
    XQueryFont(sd()->iconfont, &fontinfo);
    side->hw = max(hw, fontinfo.width);
    side->hh = max(hh, fontinfo.height);
    side->hch = hch;
    if (period.fontname != NULL && strlen(period.fontname) > 0) {
	sd()->unitfont = 
	    open_font(period.fontname, "UnitFont", sd()->textfont);
	XQueryFont(sd()->unitfont, &fontinfo);
	side->uw = fontinfo.width;
	side->uh = fontinfo.height;
    } else {
	sd()->unitfont = sd()->textfont;
	side->uw = side->fw;  side->uh = side->fh;
    }
    rootcursor = FALSE;
    sd()->dots  = XStoreBitmap(dots_width, dots_height, dots_bits);
    sd()->mmask = XStoreBitmap(mask_width, mask_height, mask_bits);
    sd()->mcurs = XStoreBitmap(curs_width, curs_height, curs_bits);
    sd()->cmask = XCharBitmap(sd()->iconfont, '[');
    sd()->ccurs = XCharBitmap(sd()->iconfont, ']');
    sd()->bombpics[0] = XStoreBitmap(bomb1_width, bomb1_height, bomb1_bits);
    sd()->bombpics[1] = XStoreBitmap(bomb2_width, bomb2_height, bomb2_bits);
    sd()->bombpics[2] = XStoreBitmap(bomb3_width, bomb3_height, bomb3_bits);
    sd()->bombpics[3] = XStoreBitmap(bomb4_width, bomb4_height, bomb4_bits);
    for_all_unit_types(u) {
	sd()->unitpics[u] = (-1);
	if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) {
	    sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname);
	}
	if (sd()->unitpics[u] < 0) {
	    utypes[u].bitmapname = NULL;
	}
    }
    if (Debug) printf("Bitmaps stored ...\n");
    sd()->bdtile = XMakeTile(side->bdcolor);
    XQueryTileShape(dots_width, dots_height, &w, &h);
    if (Debug) printf("Allowed tile shape is %dx%d\n", w, h);
    if (dots_width != w || dots_height != h) {
	fprintf(stderr, "Display %s cannot support %dx%d tiles!\n",
		side->host, dots_width, dots_height);
	fprintf(stderr, "Substituting a solid background...\n");
        sd()->wbdots = BlackPixmap;
        sd()->bwdots = WhitePixmap;
    } else {
	sd()->wbdots =
	    XMakePixmap(sd()->dots, side->graycolor, side->bgcolor);
	sd()->bwdots =
	    XMakePixmap(sd()->dots, side->bgcolor, side->graycolor);
    }
    if (Debug) printf("Tiles stored ...\n");
    XQueryCursorShape(curs_width, curs_height, &w, &h);
    if (Debug) printf("Allowed cursor shape is %dx%d\n", w, h);
    if ((w == curs_width && h == curs_height) || (w == 0 && h == 0)) {
	sd()->curs = XStoreCursor(sd()->mcurs, sd()->mmask, 7, 7,
				  side->fgcolor, side->bgcolor, GXcopy);
    } else {
	fprintf(stderr, "Warning: Can't have %dx%d cursors on \"%s\"!\n",
		curs_width, curs_height, side->host);
        fprintf(stderr, "Using default cursor...\n");
        rootcursor = TRUE;
    }
    if (Debug) printf("Cursor stored ...\n");
    XIOErrorHandler(handle_xio_error);
    XErrorHandler(handle_x_error);
}

/* Since font lookup is still not smart among Xs, this is a general routine */
/* that can deal with unopenable, missing, etc, fonts, as well as the use of */
/* .Xdefaults.  One of the inputs is another font that can be substituted if */
/* absolutely necessary. */

Font
open_font(name, xdefault, altfont)
char *name, *xdefault;
Font altfont;
{
    char *firstname, *altname;
    FontInfo *fontinfo;

    if ((altname = XGetDefault("xconq", xdefault)) != NULL) name = altname;
    firstname = name;
    if ((fontinfo = XOpenFont(name)) == NULL) {
	make_pathname(XCONQLIB, name, "onx", spbuf);
	name = spbuf;
	if ((fontinfo = XOpenFont(name)) == NULL) {
	    fprintf(stderr, "Can't open fonts \"%s\" or \"%s\" on \"%s\"\n",
		    firstname, name, DisplayName());
	    if (altfont != 0) {
		fprintf(stderr, "Substituting another font...\n");
		return altfont;
	    } else {
		fprintf(stderr, "No font to substitute for \"%s\"!!\n", name);
		exit(1);
	    }
	}
    }
    if (Debug) printf("Opened font \"%s\" ...\n", name);
    return fontinfo->id;
}

/* Try to load a bitmap of the given name. */

load_bitmap(side, name)
Side *side;
char *name;
{
    short **data;
    int w, h;

    make_pathname(NULL, name, "b", spbuf);
    if (XReadBitmapFile(spbuf, &w, &h, &data, NULL, NULL) > 0) {
	side->uw = w;  side->uh = h;
	return XStoreBitmap(w, h, data);
    } else {
	make_pathname(XCONQLIB, name, "b", spbuf);
	if (XReadBitmapFile(spbuf, &w, &h, &data, NULL, NULL) > 0) {
	    side->uw = w;  side->uh = h;
	    return XStoreBitmap(w, h, data);
	} else {
	    fprintf(stderr, "Bitmap \"%s\" not found!\n", name);
	    return (-1);
	}
    }
}

/* The main window can be positioned by the player, but the size is */
/* predetermined. */

create_main_window(side)
Side *side;
{
    OpaqueFrame mainframe;

    sprintf(spbuf, "=%dx%d", side->mw, side->mh);
    mainframe.bdrwidth = 3;
    mainframe.border = sd()->bdtile;
    mainframe.background = (side->bonw ? sd()->bwdots : sd()->wbdots);
    side->main = XCreate("xconq", "xconq", spbuf, "", &mainframe, 
			 side->mw, side->mh);
    XStoreName(side->main, "xconq");   /* for iconification */
    XMapWindow(side->main);
}

/* Help window is not a subwindow, but sits at a fixed location (not good). */
/* 45 is approximation to number of commands - exactness more complicated. */

create_help_window(side)
Side *side;
{
    helpwinlines =
	max(45, (24 + period.numrtypes + period.numttypes + period.numutypes));

    side->help = XCreateWindow(RootWindow, 0, 0,
			       80*side->fw, helpwinlines*side->fh,
			       1, sd()->bdtile, BlackPixmap);
}

/* Subwindow creator. */

Window
create_window(side, x, y, w, h)
Side *side;
int x, y, w, h;
{
    return XCreateWindow(side->main, x, y, w, h, 1, sd()->bdtile, BlackPixmap);
}

/* Do little things necesary to make it all go - map all the subwindows */
/* (with possible exception of chess clock), and attach a special cursor */
/* if we had succeeded in defining one previously. */

fixup_windows(side)
Side *side;
{
    XMapSubwindows(side->main);
    if (!giventime) XUnmapWindow(side->clock);
    if (!rootcursor) XDefineCursor(side->map, sd()->curs);
}

/* Specify the sorts of input that will be allowed. */

enable_input(side)
Side *side;
{
    XSelectInput(side->main,
		 KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow);
    XSelectInput(side->help,
		 KeyPressed|ButtonPressed|ExposeRegion|ExposeWindow);
}

/* Rehack anything that might need to be changed as a result of the user */
/* fiddling with options. */

reset_misc(side)
Side *side;
{
    Pixmap bg, fg, bd, dots;

    bg = (side->bonw ? WhitePixmap : BlackPixmap);
    fg = (side->bonw ? BlackPixmap : WhitePixmap);
    bd = (side->bonw ? BlackPixmap :
	  (side->monochrome ? WhitePixmap : sd()->bdtile));
    dots = (side->bonw ? sd()->bwdots : sd()->wbdots);
    XChangeBackground(side->main, dots);
    XChangeBackground(side->map, bg);
    XChangeBackground(side->world, bg);
    XChangeBackground(side->msg, bg);
    XChangeBackground(side->prompt, bg);
    XChangeBackground(side->info, bg);
    XChangeBackground(side->timemode, bg);
    XChangeBackground(side->clock, bg);
    XChangeBackground(side->state, bg);
    XChangeBackground(side->sides, bg);
    XChangeBackground(side->help, bg);
    XChangeBorder(side->main, bd);
    XChangeBorder(side->map, bd);
    XChangeBorder(side->msg, bd);
    XChangeBorder(side->prompt, bd);
    XChangeBorder(side->info, bd);
    XChangeBorder(side->sides, bd);
    XChangeBorder(side->timemode, bd);
    XChangeBorder(side->clock, bd);
    XChangeBorder(side->state, bd);
    XChangeBorder(side->world, bd);
    XChangeBorder(side->help, bd);
}

/* Alter a window's position and/or size.  Negative args indicate things */
/* not to bother changing. */

change_window(side, win, x, y, w, h)
Side *side;
Window win;
int x, y, w, h;
{
    if (active_display(side)) {
	if (x >= 0) {
	    if (w >= 0) {
		XConfigureWindow(win, x, y, w, h);
	    } else {
		XMoveWindow(win, x, y);
	    }
	} else {
	    XChangeWindow(win, w, h);
	}
    }
}

/* Return the number of colors - this is used to guess about monochromeness. */

display_colors(side) Side *side; {  return (DisplayCells());  }

white_color(side) Side *side; {  return WhitePixel;  }

black_color(side) Side *side; {  return BlackPixel;  }

/* Get a color set up and warn if not getting what was asked for. */

request_color(side, name)
Side *side;
char *name;
{
    Color c, avail;

    XGetColor(name, &avail, &c);
    XGetHardwareColor(&avail);
    if (c.red != avail.red || c.green != avail.green || c.blue != avail.blue) {
	fprintf(stderr, "Warning: %s color not exact on \"%s\"!\n",
		name, side->host);
	fprintf(stderr, "Is %d %d %d instead of %d %d %d\n",
		avail.red, avail.green, avail.blue, c.red, c.green, c.blue);
    }
    return avail.pixel;
}

/* Main funnel for input returns both mouse and keyboard events, and maybe */
/* other kinds eventually.  Some events like window exposure are handled */
/* strictly locally. */

get_input()
{
#ifdef SELECT2
    int i, mask;
    Side *side, *asides[32];

    mask = 0;
    for_all_sides(side) {
	if (active_display(side)) {
	    mask |= (1 << sd()->disp->fd);
	    asides[sd()->disp->fd] = side;
	    while (XPending() > 0) {
		process_events(side);
	    }
	    side->lasttime = time(0);
	}
    }
    if (Debug) {
	printf("Waiting for input from ");
	for_all_sides(side)
	    if (active_display(side)) printf("%s ", side->host);
	printf("\n");
    }
    if (select(32, &mask, 0, 0, 0) < 0) {
	fprintf(stderr, "get_input: error in select(2)!\n");
	abort();
    } else {
	for (i = 0; i < 32; ++i) {
	    if (mask & (1 << i)) {
		process_events(asides[i]);
		asides[i]->timeleft -= (time(0) - asides[i]->lasttime);
	    }
	}
    }
#else
    extern Side *curside;

    /* No simultaneity, but there's no portable way to do it, sigh */
    if (active_display(curside) && humanside(curside)) {
	if (Debug) printf("Waiting for input from %s\n", curside->host);
	process_events(curside);
    }
#endif SELECT2
}

/* Look at a single event and fill the request structure appropriately. */

process_events(side)
Side *side;
{
    XEvent evt;
    char *buf;
    int nchar, rawx, rawy, rux, ruy;
    Window dummy;

    XSetDisplay(sd()->disp);
    while (TRUE) {
	XNextEvent(&evt);
	switch (evt.type) {
	case KeyPressed:
	    buf = XLookupMapping(&evt, &nchar);
	    if (nchar > 0) {
		side->reqtype = KEYBOARD;
		side->reqch = *buf;
		if (Debug) printf("Host %s returns key '%c'\n",
				  side->host, side->reqch);
		return;
	    }
	    break;
	case ButtonPressed:
	    XQueryMouse(side->map, &rawx, &rawy, &dummy);
	    XQueryMouse(side->state, &rux, &ruy, &dummy);
	    if (rux < 0) {
		side->reqtype = MAPPOS;
		deform(side, rawx, rawy, &(side->reqx), &(side->reqy));
		if (Debug) printf("Host %s returns map %d %d\n",
				  side->host, side->reqx, side->reqy);
	    } else {
		side->reqtype = UNITTYPE;
		side->requtype = ruy / max(side->hh, side->fh);
		if (Debug) printf("Host %s returns unit type %d\n",
				  side->host, side->requtype);
	    }
	    return;
	case ExposeRegion:
	    /* Too much work to be clever about redrawing part of screen */
	case ExposeWindow:
	    if (evt.window == side->main) {
		flush_input(side);
		redraw(side);
	    }
	    if (Debug) printf("Host %s exposes itself\n", side->host);
	    /* Test so machines with screens don't wedge everybody else... */
	    if (!humanside(side)) return;
	    break;
	default:
            case_panic("event type", evt.type);
	    break;
	}
    }
}

/* Freeze everything until the given side supplies any event.  Use this */
/* sparingly... */

freeze_wait(side)
Side *side;
{
    char *buf;
    int nchar;
    XEvent evt;

    if (Debug) printf("Waiting for a %s event\n", side->host);
    XSetDisplay(sd()->disp);
    sleep(1);
    XSync(TRUE);
    XNextEvent(&evt);
    return '\0';
}

/* Get rid of extra key/mouse clicks. */

flush_input(side)
Side *side;
{
    if (active_display(side)) XSync(TRUE);
}

/* Trivial abstraction - sometimes other routines like to ensure all output */
/* actually on the screen. */

flush_output(side)
Side *side;
{
    if (active_display(side)) XFlush();
}

/* General window clearing. */

clear_window(side, win)
Side *side;
Window win;
{
    XClear(win);
}

/* Draw a single horizontal constant-color bar on the world map.  If part */
/* would not be drawn because of the map's obliqueness, cut it in two and */
/* wrap one of the pieces around. */

draw_bar(side, x, y, len, color)
Side *side;
int x, y, len, color;
{
    int sx1, sx2, sy, sww;

    w_xform(side, x, y, &sx1, &sy);
    w_xform(side, x + len, y, &sx2, &sy);
    sww = side->mm * world.width;
    if (sx1 < sww && sx2 >= sww) {
	XPixSet(side->world, sx1, sy, sww - sx1, side->mm, color);
	XPixSet(side->world, 0, sy, sx2 - sww, side->mm, color);
    } else {
	sx1 %= sww;
	sx2 %= sww;
	XPixSet(side->world, sx1, sy, sx2 - sx1, side->mm, color);
    }
}

/* Invert the outline box on the world map.  This is a little tricky, */
/* because we want the lines to run through the middle of the world's */
/* hexes, and because the line drawn should not overlap (or the overlaps */
/* will be doubly inverted and look strange). */

invert_box(side, vcx, vcy)
Side *side;
int vcx, vcy;
{
    int x1, y1, x2, y2, sx1, sy1, sx2, sy2, mm2 = side->mm/2;

    x1 = vcx - side->vw2 + side->vh2/2;  y1 = vcy - side->vh2;
    x2 = vcx + side->vw2 - side->vh2/2;  y2 = vcy + side->vh2;
    w_xform(side, x1, y1, &sx1, &sy1);
    w_xform(side, x2, y2, &sx2, &sy2);
    sx1 += mm2;  sy1 -= mm2;  sx2 += mm2;  sy2 += mm2;
    XLine(side->world, sx1, sy1, sx2, sy1,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
    XLine(side->world, sx2, sy1-1, sx2, sy2+1,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
    XLine(side->world, sx2, sy2, sx1, sy2,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
    XLine(side->world, sx1, sy2+1, sx1, sy1-1,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
}

/* This interfaces higher-level drawing decisions to the rendition of */
/* individual pieces of display. */

draw_terrain_row(side, sx, sy, buf, len, color)
Side *side;
int sx, sy, len, color;
char *buf;
{
    XTextMaskPad(side->map, sx, sy, buf, len, sd()->iconfont,
		 0, side->hw, color, GXcopy, AllPlanes);
}

/* Flash a pair of lines up, slow enough to draw the eye, but not so slow */
/* as to get in the way. */

flash_position(side, sx, sy)
Side *side;
int sx, sy;
{
    int i, sx1, sy1, sx2, sy2;

    sx1 = sx - 50 + side->hw/2;  sy1 = sy + 50 + side->hch/2;
    sx2 = sx + 50 + side->hw/2;  sy2 = sy - 50 + side->hch/2;
    XLine(side->map, sx1, sy1, sx2, sy2,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
    XLine(side->map, sx1, sy2, sx2, sy1,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
    flush_output(side);
    for (i = 0; i < DELAY; ++i);
    XLine(side->map, sx1, sy1, sx2, sy2,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
    XLine(side->map, sx1, sy2, sx2, sy1,
	  1, 1, side->owncolor, GXinvert, AllPlanes);
}

/* The "cursor icon" is just a pair of bitmaps - has nothing to do with */
/* X's notion of cursors. */

draw_cursor_icon(side, sx, sy)
Side *side;
int sx, sy;
{
    XPixFill(side->map, sx, sy, side->hw, side->hh,
	     side->bgcolor, sd()->cmask, GXcopy, AllPlanes);
    XPixFill(side->map, sx, sy, side->hw, side->hh,
	     side->fgcolor, sd()->ccurs, GXcopy, AllPlanes);
}

/* Generic hex drawer. */

draw_hex_icon(side, win, x, y, color, ch)
Side *side;
Window win;
int x, y, color;
char ch;
{
    XTextMask(win, x, y, &ch, 1, sd()->iconfont, color);
}

/* For little numbers in the corner of the hex. */

draw_side_number(side, win, x, y, n, color)
Side *side;
Window win;
int x, y, n, color;
{
    char ch = n + '0';

    if (n >= 0) XTextMask(win, x, y, &ch, 1, sd()->iconfont, color);
}

/* For flashes due to combat. */

draw_blast_icon(side, win, x, y, type, color)
Side *side;
Window win;
int x, y, color;
char type;
{
    XTextMask(win, x, y, &type, 1, sd()->iconfont, color);
}

/* Flash the player's screen in an unmistakable way. */

invert_whole_map(side)
Side *side;
{
    int sw = side->vw * side->hw, sh = side->vh * side->hh;

    XTileFill(side->map, 0, 0, sw, sh, WhitePixmap, 0, GXinvert, AllPlanes);
    flush_output(side);
}

/* Draw just one of the mushroom cloud shapes.  For color displays, all but */
/* the last one are black, for mono, all are white (foreground color). */

draw_mushroom(side, x, y, i)
Side *side;
int x, y, i;
{
    int sx, sy;

    xform(side, unwrap(side, x), y, &sx, &sy);
    XPixFill(side->map, sx-bomb1_width/4, sy-bomb1_height/2,
	     bomb1_width, bomb1_height,
	     ((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor),
	     sd()->bombpics[i], GXcopy, AllPlanes);
    flush_output(side);
}

/* Confirm that we can indeed do bar graph displays. */

bar_graphs(side) Side *side;  {  return TRUE;  }

/* Do yet another X-toolkit-type function.  This draws a bar graph. */

draw_graph(side, number, amount, total, critical, title)
Side *side;
int number, amount, total, critical;
{
    int boxwidth, boxheight, boxoffset, boxleft, barwidth, barheight;

    if (total > 0) {
	boxwidth = 5*side->fw;
	boxheight = (INFOLINES-1)*side->fh - 2*side->margin;
	boxoffset = side->margin;
	boxleft = 30*side->fw + number * boxwidth;
	barwidth = boxwidth / 3;
	barheight = (boxheight * amount) / total;
	XPixSet(side->info, boxleft + boxwidth/3 - 1, boxoffset - 1,
		barwidth + 2, boxheight + 2, side->fgcolor);
	XPixSet(side->info, boxleft + boxwidth/3, boxoffset,
		barwidth, boxheight, side->bgcolor);
	XPixSet(side->info,
		boxleft + boxwidth/3, boxoffset + boxheight - barheight,
		barwidth, barheight,
		(amount > critical ? side->goodcolor : side->badcolor));
	XText(side->info,
	      boxleft+(boxwidth-strlen(title)*side->fw)/2,
	      (INFOLINES-1)*side->fh,
	      title, strlen(title),
	      sd()->textfont, side->fgcolor, side->bgcolor);
    }
}

/* Splash a unit image (either bitmap or font char) onto some window. */

draw_unit_icon(side, win, x, y, u, color)
Side *side;
Window win;
int x, y, u, color;
{
    char ch;
    int px, py;

    px = x + (side->hw - side->uw) / 2;  py = y + (side->hh - side->uh) / 2;
    if (utypes[u].bitmapname != NULL) {
	XPixFill(win, px, py, side->uw, side->uh, color,
		 sd()->unitpics[u], GXcopy, AllPlanes);
    } else {
	ch = utypes[u].uchar;
	XTextMask(win, px, py, &ch, 1, sd()->unitfont, color);
    }
}

/* General text drawer. */

draw_text(side, win, x, y, str, color)
Side *side;
Window win;
int x, y, color;
char *str;
{
    if (color != side->bgcolor) {
	XText(win, x, y, str, strlen(str),
	      sd()->textfont, color, side->bgcolor);
    } else {
	XText(win, x, y, str, strlen(str),
	      sd()->textfont, side->bgcolor, side->fgcolor);
    }
}

/* Draw a line through some side's title. */

draw_scratchout(side, pos)
Side *side;
int pos;
{
    XLine(side->sides, 0, pos, side->fw * side->sw, pos,
	  1, 1, side->graycolor, GXcopy, AllPlanes);
}

/* Beep the beeper! */

beep(side)
Side *side;
{
    XFeep(0);
}

/* Little routines to pop up the help window and make it go away again */
/* They only get called when display is in use. */

reveal_help(side)
Side *side;
{
    XMapWindow(side->help);
    return TRUE;
}

conceal_help(side)
Side *side;
{
    XUnmapWindow(side->help);
}

/* Shut a single display down, but only if there's one to operate on. */
/* Hit the display slot, for safety. */

close_display(side)
Side *side;
{
    XCloseDisplay(sd()->disp);
    side->display = (long) NULL;
}