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

⟦874d33ed9⟧ TextFile

    Length: 35753 (0x8ba9)
    Types: TextFile
    Names: »X11.c«

Derivation

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

TextFile

/* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
/* Copyright 1988 by Chris D. Peterson, MIT. */
/* Many improvements by Tim Moore, 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: X11.c,v 1.1 88/06/21 12:30:00 shebs Exp $ */

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

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

/* careful of the path of the X header files. */

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

/* various bitmap definitions. */

#define dots_width 16
#define dots_height 16
static char dots_bits[] = {
   0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};

#define mask_width 16
#define mask_height 16
static char mask_bits[] = {
   0xe0, 0x03,  0xd8, 0x0f,  0xb4, 0x19,  0x8a, 0x21, 
   0x86, 0x61,  0x85, 0x41,  0x83, 0xc1,  0xff, 0xff, 
   0xff, 0xff,  0x83, 0xc1,  0x82, 0xa1,  0x86, 0x61, 
   0x84, 0x51,  0x98, 0x2d,  0xf0, 0x1b,  0xc0, 0x07};

#define curs_width 16
#define curs_height 16
static char curs_bits[] = {
   0xe0, 0x03,  0x98, 0x0c,  0x84, 0x10,  0x82, 0x20, 
   0x82, 0x20,  0x81, 0x40,  0x81, 0x40,  0xff, 0x7f, 
   0x81, 0x40,  0x81, 0x40,  0x82, 0x20,  0x82, 0x20, 
   0x84, 0x10,  0x98, 0x0c,  0xe0, 0x03,  0x00, 0x00};

#define bomb1_width 32
#define bomb1_height 32
static char bomb1_bits[] = {
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0xc0,  0x01, 0x00,  0x00, 0xf0,  0x07, 0x00, 
   0x00, 0xf0,  0x07, 0x00,  0x00, 0xf8,  0x0f, 0x00, 
   0x00, 0xf8,  0x0f, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
   0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
   0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};

#define bomb2_width 32
#define bomb2_height 32
static char bomb2_bits[] = {
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0xf8,  0x01, 0x00, 
   0x00, 0xf8,  0x07, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
   0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfe,  0x1f, 0x00, 
   0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
   0x00, 0xfc,  0x0f, 0x00,  0x00, 0xf0,  0x07, 0x00, 
   0x00, 0xf0,  0x03, 0x00,  0x00, 0xe0,  0x03, 0x00, 
   0x00, 0xf0,  0x07, 0x00,  0x00, 0xf0,  0x07, 0x00, 
   0x00, 0xf0,  0x0f, 0x00,  0x00, 0xf0,  0x0f, 0x00, 
   0x00, 0xf8,  0x0f, 0x00,  0x00, 0xf8,  0x1f, 0x00, 
   0x00, 0xf8,  0x1f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
   0x00, 0xff,  0x7f, 0x00,  0xc0, 0xff,  0xff, 0x03, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};

#define bomb3_width 32
#define bomb3_height 32
static char bomb3_bits[] = {
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0xfe, 0xe2,  0xa3, 0x3f, 
   0x00, 0xfc,  0x1f, 0x00,  0x3c, 0xff,  0x7f, 0x7c, 
   0x80, 0xff,  0xff, 0x00,  0xc0, 0xff,  0xff, 0x01, 
   0xc0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x03, 
   0xe0, 0xff,  0xff, 0x03,  0xe0, 0xff,  0xff, 0x03, 
   0xe0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x49, 
   0x82, 0xff,  0xff, 0x34,  0x14, 0xfe,  0x3f, 0x42, 
   0xe2, 0xff,  0x9f, 0x34,  0x40, 0xfe,  0x3f, 0x41, 
   0xbe, 0xfd,  0xdf, 0x1e,  0x00, 0xf8,  0x1f, 0x01, 
   0xfe, 0xfd,  0xdf, 0x7f,  0x00, 0xfc,  0x1f, 0x00, 
   0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfc,  0x3f, 0x00, 
   0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
   0x00, 0xff,  0x3f, 0x00,  0xc0, 0xff,  0xff, 0x00, 
   0xfc, 0xff,  0xff, 0x3f,  0xfe, 0xff,  0xff, 0x7f, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};

#define bomb4_width 32
#define bomb4_height 32
static char bomb4_bits[] = {
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0xc0,  0x07, 0x00, 
   0x00, 0x78,  0x10, 0x00,  0x00, 0x0f,  0x46, 0x00, 
   0x80, 0x61,  0x81, 0x00,  0xc0, 0x1c,  0x00, 0x01, 
   0x40, 0x02,  0x00, 0x00,  0x20, 0x01,  0x00, 0x00, 
   0x20, 0x01,  0x00, 0x00,  0x20, 0x00,  0x00, 0x00, 
   0x20, 0x00,  0x00, 0x00,  0x40, 0x00,  0x00, 0x00, 
   0x80, 0x00,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
   0x00, 0x02,  0x00, 0x00,  0x00, 0x04,  0x00, 0x00, 
   0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x04,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
   0x00, 0x01,  0x00, 0x00,  0xc0, 0x00,  0x00, 0x00, 
   0x2c, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
   0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};

/* This is the name of a family of programs, so argv[0] inadequate. */

#define PROGRAMNAME "xconq"

/* Name of default font - why is this wired in? */

#define STANDARD "standard"

/* Magic number meaning that this pixmap intentionally left blank. */

#define NOPIXMAP 17

#define INFOLINES 4
#define DELAY 100000

#define BH 32

/* Use with caution - variable name "side" embedded! */

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

#define sdd() (((Screeno *) side->display)->disp)

typedef unsigned int unint;

/* GC rules are for different fonts etc, but not colors or bitmaps. */

typedef struct a_screen {
    Display *disp;
    GC gc;			/* a tmp graphics context for this display */
    GC flashgc;			/* The gc for drawing the flash lines. */
    GC textgc;			/* foreground on background text */
    GC icongc;			/* icon graphics context */
    GC invicongc;		/* icon gc inverted colors. */
    GC varicongc;		/* This is an icon gc with variable fgcolor. */
    GC unitgc;			/* unit bitmap printing gc. */
    GC unittextgc;		/* unit text printing gc. */
    GC cleargc;			/* The gc to use for clearing areas. */
    GC clearbitgc;              /* gc for clearing bitmaps */
    XFontStruct *textfont;	/* font for text display */
    XFontStruct *iconfont;	/* utility font with assorted icons */
    XFontStruct *unitfont;	/* font for unit characters */
    Pixmap bombpics[4];		/* mushroom clouds */
    Pixmap unitpics[MAXUTYPES];	/* used instead of font sometimes */
    Pixmap wbdots, bwdots;	/* blue border and dotted backgrounds */
    Cursor curs;		/* the cursor object itself */
} Screeno;

extern int giventime;

/* Random function declarations. */

XFontStruct * open_font();
Pixmap load_bitmap();
void get_font_size();
Cursor make_cursor();

/* The array of screen objects. */

Screeno screens[MAXSIDES];      /* All the "screen objects" */

/* Values of parameters generally tied to fonts and the like. */

int hw = 20;
int hh = 22;
int hch = 17;
int margin = 2;
int bd = 1;

int helpwinlines = 1;           /* size of help window */

bool rootcursor;                /* true if using parent window's cursor */

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

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 be bad news. */

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

/* Note that the open_display function syncronizes the X server when the */
/* Debug flag is set. */

open_display(side)
Side *side;
{
    side->display = (long) &(screens[side_number(side)]);
    sdd() = XOpenDisplay(side->host);
    if (Debug) {
      XSynchronize(sdd(), TRUE);
      printf("Synching the X server.\n");
    }
    side->main = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
				     50, 3, 100, 100,
				     3, white_color(side), black_color(side));
    return (sdd() != NULL);
}

/* A predicate that tests whether our display can safely be written to. */

active_display(side)
Side *side;
{
    return (side && side->host && !side->lost && side->display);
}

display_width(side)
Side *side;
{
    return ((19 * XDisplayWidth(sdd(), 0)) / 20);
}

display_height(side)
Side *side;
{
    return ((19 * XDisplayHeight(sdd(), 0)) / 20);
}

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

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

/* Could use handlers for X failures... */

/* Do misc setup thingies. */

/* 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 */
/* X11 also needs gazillions of GCs, since we've got so many fonts and */
/* colors and bitmaps. */

init_misc(side)
Side *side;
{
    int u, w, h;
    unsigned long mask;
    XGCValues values;
    Pixmap mmask, mcurs, dots;
    GC gc;

    side->margin = margin;
    side->bd = bd;
    side->hw = hw;
    side->hh = hh;
    side->hch = hch;
    mask = GCForeground | GCBackground;
    values.foreground = side->fgcolor;
    values.background = side->bgcolor;
    gc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->gc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->flashgc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->textgc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->icongc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->varicongc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->unitgc = XCreateGC(sdd(), side->main, mask, &values);
    sd()->unittextgc = XCreateGC(sdd(), side->main, mask, &values);
    values.foreground = side->bgcolor;
    values.background = side->fgcolor;
    sd()->invicongc = XCreateGC(sdd(), side->main, mask, &values);
    values.function = GXclear;
    mask = GCFunction;
    sd()->cleargc = XCreateGC(sdd(), side->main, mask, &values);

    sd()->textfont = open_font(side, TEXTFONT, "TextFont", NULL);
    get_font_size(sd()->textfont, &(side->fw), &(side->fh) );
    sd()->iconfont = open_font(side, ICONFONT, "IconFont", sd()->textfont);
    get_font_size(sd()->iconfont, &(side->hw), &(side->hh) );
    if (period.fontname != NULL && strlen(period.fontname) > 0) {
	sd()->unitfont = 
	    open_font(side, period.fontname, "UnitFont", sd()->textfont);
	get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
    } else {
      	sd()->unitfont = 
	    open_font(side, STANDARD, "UnitFont", sd()->textfont);
	get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
    }
    XSetFont(sdd(), sd()->textgc, sd()->textfont->fid);
    XSetFont(sdd(), sd()->icongc, sd()->iconfont->fid);
    mask = GCFillStyle | GCGraphicsExposures;
    values.fill_style = FillSolid;
    values.graphics_exposures = FALSE;
    XChangeGC(sdd(), sd()->unitgc, mask, &values);
    XSetFont(sdd(), sd()->unittextgc, sd()->unitfont->fid);
    XSetFont(sdd(), sd()->invicongc, sd()->iconfont->fid);
    XSetFont(sdd(), sd()->varicongc, sd()->iconfont->fid);
    XSetFunction(sdd(), sd()->flashgc, GXinvert);

    mmask = XCreateBitmapFromData(sdd(), side->main,
					mask_bits, mask_width, mask_height);
    mcurs = XCreateBitmapFromData(sdd(), side->main,
					curs_bits, curs_width, curs_height);

    dots  = XCreateBitmapFromData(sdd(), side->main, 
				  dots_bits, dots_width, dots_height);

    sd()->bombpics[0] = XCreateBitmapFromData(sdd(), side->main,
	bomb1_bits, bomb1_width, bomb1_height);
    sd()->bombpics[1] = XCreateBitmapFromData(sdd(), side->main,
        bomb2_bits, bomb2_width, bomb2_height);
    sd()->bombpics[2] = XCreateBitmapFromData(sdd(), side->main,
	bomb3_bits, bomb3_width, bomb3_height);
    sd()->bombpics[3] = XCreateBitmapFromData(sdd(), side->main,
	bomb4_bits, bomb4_width, bomb4_height);
    for_all_unit_types(u) {
	if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) {
	    sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname);
	} else {
	    utypes[u].bitmapname = NULL;
	}
    }
    if (Debug) printf("Bitmaps stored ...\n");

    sd()->wbdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
				 DefaultDepth(sdd(), 0) );
    sd()->bwdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
				 DefaultDepth(sdd(), 0) );

    /* Since clearbitgc has to have a depth of 1 we'll */
    /* hang it off bombpics[0] */
    mask = GCFunction;
    values.function = GXclear;
    sd()->clearbitgc = XCreateGC(sdd(), sd()->bombpics[0], mask, &values);

    XSetForeground(sdd(), gc, side->fgcolor);
    XSetBackground(sdd(), gc, side->bgcolor);
    XSetStipple(sdd(), gc, dots);
    XSetFillStyle(sdd(), gc, FillOpaqueStippled);
    XFillRectangle(sdd(), sd()->wbdots, gc, 0, 0, dots_width, dots_height);

    XSetForeground(sdd(), gc, side->bgcolor);
    XSetBackground(sdd(), gc, side->fgcolor);
    XFillRectangle(sdd(), sd()->bwdots, gc, 0, 0, dots_width, dots_height);
    if (Debug) printf("Tiles stored ...\n");

    rootcursor = FALSE;
    XQueryBestCursor(sdd(), side->main, 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) {
        sd()->curs =
	  make_cursor(sdd(), mcurs, mmask, white_color(side),
		      black_color(side), 7, 7);
	   
    } 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");
    XFreeGC(sdd(), gc);
    XFreePixmap(sdd(), dots);
    XFreePixmap(sdd(), mmask);
    XFreePixmap(sdd(), mcurs);
}

/* Since XCreatePixmapCursor() takes XColors and not pixel values we */
/* have to look the colors associated with the foreground and */
/* background pixel values up in the color table and pass them to */
/* XCreatePixmapCursor(). */
   
Cursor make_cursor(dpy, curs, mask, foreground, background, x, y)
Display *dpy;
Pixmap curs, mask;
unsigned long foreground, background;
unsigned int x, y;
{
    XColor defs[2];

    defs[0].pixel = foreground;
    defs[1].pixel = background;
    XQueryColors(dpy, DefaultColormap(dpy, 0), defs, 2);
    return  XCreatePixmapCursor(dpy, curs, mask, &defs[0], &defs[1], x, y);
}

/* 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 */
/* necessary. */

XFontStruct *
open_font(side, name, xdefault, altfont)
Side *side;
char *name, *xdefault;
XFontStruct * altfont;
{
    char *firstname, *altname;
    XFontStruct * font;

    if ((altname = XGetDefault(sdd(), PROGRAMNAME, xdefault)) != NULL)
	name = altname;
    firstname = name;
    if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
	make_pathname(XCONQLIB, name, "snf", spbuf);
	name = spbuf;
	if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
	    fprintf(stderr, "Can't open fonts \"%s\" or \"%s\" on \"%s\"\n",
		    firstname, name, side->host);
	    if (altfont != NULL) {
		fprintf(stderr, "Substituting another font...\n");
		return altfont;
	    } else {
		fprintf(stderr, "No font to substitute!!\n");
		exit(1);
	    }
	}
    }
    if (Debug) printf("Opened font \"%s\" ...\n", name);
    return font;
}

/* Force X11 font fanciness into semblance of X10 font plainness. */

void
get_font_size(font, width, height)
XFontStruct * font;
short *width, *height;
{
    *width = font->max_bounds.rbearing - font->min_bounds.lbearing;
    *height = font->max_bounds.ascent + font->min_bounds.descent;
    if (Debug) {
	printf("rbearing = %d lbearing = %d\n",
	       (int)font->max_bounds.rbearing, (int)font->min_bounds.lbearing);
	printf("returning font size %d %d\n", (int)*width, (int)*height);
    }
}

/* Try to load a bitmap of the given name - can be either X11-only (.b11) */
/* or X10 (.b) bitmaps, but prefer X11 flavor. */

Pixmap
load_bitmap(side, name)
Side *side;
char *name;
{
    int w, h, junk, a;
    Pixmap rslt;

    make_pathname(NULL, name, "b11", spbuf);
    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
    if (a == BitmapSuccess) return rslt;
    make_pathname(XCONQLIB, name, "b11", spbuf);
    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
    if (a == BitmapSuccess) return rslt;
    make_pathname(XCONQLIB, name, "b", spbuf);
    a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
    if (a == BitmapSuccess) return rslt;
    fprintf(stderr, "Bitmap name \"%s\" not found anywhere!\n", name);
    return (-1);
}

/* This routine has to be able to cope with window managers constraining */
/* size.  Actually, the main window was already opened when the display */
/* was opened, so the name is not quite accurate! */

create_main_window(side)
Side *side;
{
    Pixmap dots;
    XSizeHints hints;
		  
    XStoreName(sdd(), side->main, PROGRAMNAME);
    dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
    XSetWindowBackgroundPixmap(sdd(), side->main, dots);

    hints.width = side->mw;
    hints.height = side->mh;
    hints.min_width = side->mw;
    hints.min_height = side->mh;
    hints.flags = PSize|PMinSize;
    XSetNormalHints(sdd(), side->main, &hints);
}

/* Help window is not necessarily a subwindow, though it might be sometimes. */

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

    side->help = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
				     0, 0, 80*side->fw+1,
				     helpwinlines*side->fh+1,
				     1, side->fgcolor, side->bgcolor);
    XStoreName(sdd(), side->help, "xconq-help");
}

/* Subwindow creator. */

create_window(side, x, y, w, h)
Side *side;
int x, y, w, h;
{
    return XCreateSimpleWindow(sdd(), side->main, x, y, w, h,
			       1, side->fgcolor, side->bgcolor);
}

/* Do little things necesary to make it all go, in this case mapping all */
/* the windows (except help win). */

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

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

enable_input(side)
Side *side;
{
    XSelectInput(sdd(), side->main, KeyPressMask|ExposureMask);
    XSelectInput(sdd(), side->map,  ButtonPressMask|ExposureMask);
    XSelectInput(sdd(), side->help, KeyPressMask|ExposureMask);
}

/* Move windows and change their sizes to correspond with the new sizes of */
/* viewports, etc */

reset_misc(side)
Side *side;
{
    Pixmap dots;
    XSizeHints hints;
    XGCValues values;
    unsigned int gcmask;

    dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 

    XResizeWindow(sdd(), side->main, side->mw, side->mh);
    hints.width = side->mw;  hints.height = side->mh;
    hints.min_width = side->mw;  hints.min_height = side->mh;
    hints.flags = PSize|PMinSize;
    XSetNormalHints(sdd(), side->main, &hints);

    XSetWindowBackgroundPixmap(sdd(), side->main, dots);
    XSetWindowBackground(sdd(), side->msg, side->bgcolor);
    XSetWindowBackground(sdd(), side->info, side->bgcolor); 
    XSetWindowBackground(sdd(), side->prompt, side->bgcolor); 
    XSetWindowBackground(sdd(), side->map, side->bgcolor);
    XSetWindowBackground(sdd(), side->timemode, side->bgcolor);
    XSetWindowBackground(sdd(), side->clock, side->bgcolor);
    XSetWindowBackground(sdd(), side->state, side->bgcolor);
    XSetWindowBackground(sdd(), side->help, side->bgcolor);
    XSetWindowBackground(sdd(), side->sides, side->bgcolor);
    XSetWindowBackground(sdd(), side->world, side->bgcolor);
    XSetWindowBorder(sdd(), side->msg, side->fgcolor);
    XSetWindowBorder(sdd(), side->info, side->fgcolor); 
    XSetWindowBorder(sdd(), side->prompt, side->fgcolor); 
    XSetWindowBorder(sdd(), side->map, side->fgcolor);
    XSetWindowBorder(sdd(), side->timemode, side->fgcolor);
    XSetWindowBorder(sdd(), side->clock, side->fgcolor);
    XSetWindowBorder(sdd(), side->state, side->fgcolor);
    XSetWindowBorder(sdd(), side->help, side->fgcolor);
    XSetWindowBorder(sdd(), side->sides, side->fgcolor);
    XSetWindowBorder(sdd(), side->world, side->fgcolor);

    gcmask = GCForeground | GCBackground;
    values.foreground = side->fgcolor;
    values.background = side->bgcolor;
    XChangeGC(sdd(), sd()->gc, gcmask, &values);
    XChangeGC(sdd(), sd()->flashgc, gcmask, &values);
    XChangeGC(sdd(), sd()->textgc, gcmask, &values);
    XChangeGC(sdd(), sd()->icongc, gcmask, &values);
    XChangeGC(sdd(), sd()->unitgc, gcmask, &values);
    values.foreground = side->bgcolor;
    values.background = side->fgcolor;
    XChangeGC(sdd(), sd()->invicongc, gcmask, &values);
}

/* Alter the size and position of a window. */

change_window(side, win, x, y, w, h)
Side *side;
Window win;
int x, y, w, h;
{
    unsigned int mask;
    XWindowChanges changes;

    if (active_display(side)) {
	if (x >= 0) {
	    if (w >= 0) {
		mask = CWX | CWY | CWWidth | CWHeight;
		changes.x = x;  changes.y = y;
		changes.width = w;  changes.height = h;
	    } else {
		mask = CWX | CWY;
		changes.x = x;  changes.y = y;
	    }
	} else {
	    mask = CWWidth | CWHeight;
	    changes.width = w;  changes.height = h;
	}
    }
    XConfigureWindow(sdd(), win, mask, &changes);
}

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

display_colors(side) Side *side; {  return XDisplayCells(sdd(), 0);  }

white_color(side) Side *side; {  return WhitePixel(sdd(), 0);  }

black_color(side) Side *side; {  return BlackPixel(sdd(), 0);  }

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

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

    if (Debug) printf("Allocating %s\n", name);
    XAllocNamedColor(sdd(), DefaultColormap(sdd(), 0), name, &avail, &c);
    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 << ConnectionNumber(sdd()));
	    asides[ConnectionNumber(sdd())] = side;
	    while (XPending(sdd()) > 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, "error in select!\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); 
		update_clock(asides[i]);
	    }
	}
    }
#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[BUFSIZE];
    int nchar, rawx, rawy;
    unsigned int junk;

    while (TRUE) {
	XNextEvent(sdd(), &evt);
	switch (evt.type) {
	case KeyPress:
	    if (evt.xkey.window != side->main &&
		evt.xkey.window != side->help) 
		return FALSE;
	    nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
	    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 ButtonPress:
	    if (evt.xbutton.window == side->map) {
		rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
		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 if (evt.xbutton.window == side->state) {
		rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
		side->reqtype = UNITTYPE;
		side->requtype = rawy / max(side->hh, side->fh);
		if (Debug) printf("Host %s returns unit type %d\n",
				  side->host, side->requtype);
	    }
	    return;
	case Expose:
	    if (evt.xexpose.window == side->main || 
		evt.xexpose.window == side->map) {
		flush_input(side);
		redraw(side);
	    }
	    if (Debug) printf("Host %s exposes itself\n", side->host);
	    return FALSE;
	    break;
	default:
	    case_panic("event type", evt.type);
	    break;
	}
    }
}

/* Freese everything until given side supplies input, use sparingly. */

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

    if (Debug) printf("Waiting for a %s event\n", side->host);
    flush_input(side);
    while(TRUE) {
	XNextEvent(sdd(), &evt);
	if (evt.type == KeyPress) {
	    nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
	    if (nchar > 0) 
		return *buf;
	    else
		return '\0';
	}
    }  
}

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

flush_input(side)
Side *side;
{
    if (humanside(side)) XSync(sdd(), TRUE);
}

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

flush_output(side) 
Side *side; 
{  
    if (humanside(side)) XFlush(sdd());  
}

/* General window clearing. */

clear_window(side, win)
Side *side;
Window win;
{
    XClearWindow(sdd(), 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;
    XSetFillStyle(sdd(), sd()->gc, FillSolid);
    XSetForeground(sdd(), sd()->gc, color);
    if (sx1 < sww && sx2 >= sww) {
	XFillRectangle(sdd(), side->world, sd()->gc,
		       sx1, sy, (unint) sww - sx1, (unint) side->mm);
	XFillRectangle(sdd(), side->world, sd()->gc,
		       0, sy, (unint) sx2 - sww, (unint) side->mm);
    } else {
	sx1 %= sww;
	sx2 %= sww;
	XFillRectangle(sdd(), side->world, sd()->gc,
		       sx1, sy, (unint) sx2 - sx1, (unint) side->mm);
    }
}

/* 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;
    XSetFunction(sdd(), sd()->gc, GXinvert);
    /* is this next call really necessary? */
    XSetLineAttributes(sdd(), sd()->gc, 1, LineSolid, CapButt, JoinMiter);
    XDrawLine(sdd(), side->world, sd()->gc, sx1, sy1, sx2, sy1);
    XDrawLine(sdd(), side->world, sd()->gc, sx2, sy1-1, sx2, sy2+1);
    XDrawLine(sdd(), side->world, sd()->gc, sx2, sy2, sx1, sy2);
    XDrawLine(sdd(), side->world, sd()->gc, sx1, sy2+1, sx1, sy1-1);
    XSetFunction(sdd(), sd()->gc, GXcopy);
}

/* 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;
{
    sy += sd()->iconfont->max_bounds.ascent;
    XSetForeground(sdd(), sd()->icongc, color);
    XDrawString(sdd(), side->map, sd()->icongc, sx, sy, buf, len);
}

/* 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;
    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
    flush_output(side);
    for (i = 0; i < DELAY; ++i);
    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
    XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
}

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

draw_cursor_icon(side, sx, sy)
Side *side;
int sx, sy;
{
    sy += sd()->iconfont->max_bounds.ascent;
    XDrawString(sdd(), side->map, sd()->invicongc, sx, sy, "[", 1);
    XSetForeground(sdd(), sd()->icongc, side->fgcolor);
    XDrawString(sdd(), side->map, sd()->icongc, sx, sy, "]", 1);
}

/* Draw the icon for a hex (given as a char). */

draw_hex_icon(side, win, sx, sy, color, ch)
Side *side;
Window win;
int sx, sy, color;
char ch;
{
    XSetForeground(sdd(), sd()->varicongc, color);
    sy += sd()->iconfont->max_bounds.ascent;
    XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
}

/* Draw the number of an unfriendly side (never called for own units). */

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

    if (n >= 0) {
	XSetForeground(sdd(), sd()->varicongc, color);
	sy += sd()->iconfont->max_bounds.ascent;
	XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
    }
}

draw_blast_icon(side, win, sx, sy, type, color)
Side *side;
Window win;
int sx, sy, color;
char type;
{
    char buf[1];

    XSetForeground(sdd(), sd()->varicongc, color);
    buf[0] = type;
    sy += sd()->iconfont->max_bounds.ascent;
    XDrawString(sdd(), win, sd()->varicongc, sx, sy, buf, 1);
}

/* 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;

    /* GC needs to be set for inverted drawing */
    XDrawRectangle(sdd(), side->map, sd()->gc, 0, 0, sw, sh);
    flush_output(side);
}

/* Draw just one of the mushroom cloud shapes. */

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

    color = ((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor);
    xform(side, unwrap(side, x), y, &sx, &sy);
    XSetForeground(sdd(), sd()->unitgc, color);
    XSetClipMask(sdd(), sd()->unitgc, sd()->bombpics[i]);
    XSetClipOrigin(sdd(), sd()->unitgc, sx-BH/4, sy-BH/2);
    XFillRectangle(sdd(), side->map, sd()->unitgc, sx-BH/4, sy-BH/2, BH, BH);
    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;
	XSetForeground(sdd(), sd()->gc, side->fgcolor);
	XFillRectangle(sdd(), side->info, sd()->gc,
		       boxleft + boxwidth/3 - 1, boxoffset - 1,
		       barwidth + 2, boxheight + 2);
	XSetForeground(sdd(), sd()->gc, side->bgcolor);
	XFillRectangle(sdd(), side->info, sd()->gc,
		       boxleft + boxwidth/3, boxoffset,
		       barwidth, boxheight);
	if ( amount > critical)
	  XSetForeground(sdd(), sd()->gc, side->goodcolor);
	else
	  XSetForeground(sdd(), sd()->gc, side->badcolor);
	XFillRectangle(sdd(), side->info, sd()->gc,
		       boxleft + boxwidth/3, boxoffset + boxheight - barheight,
		       barwidth, barheight);
	draw_text(side, side->info,
		  boxleft+(boxwidth-strlen(title)*side->fw)/2,
		  (INFOLINES-1)*side->fh, title, side->fgcolor);
    }
}

/* 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 buf[1];

    y += 3;			/* fudge factor to make x11 look */
    x += 2;			/*  like X10 (ugh). */
    if (utypes[u].bitmapname != NULL ) {
      XSetForeground(sdd(), sd()->unitgc, color);
      XSetClipMask(sdd(), sd()->unitgc, sd()->unitpics[u]);
      XSetClipOrigin(sdd(), sd()->unitgc, x, y);
      XFillRectangle(sdd(), win, sd()->unitgc, x, y, side->uw, side->uh);
    } else {
        XSetForeground(sdd(), sd()->unittextgc, color);
	buf[0] = utypes[u].uchar;
	y += sd()->unitfont->max_bounds.ascent;
	XDrawString(sdd(), win, sd()->unittextgc, x, y, buf, 1);
    }
}

/* General text drawer. */

draw_text(side, win, x, y, str, color)
Side *side;
Window win;
int x, y, color;
char *str;
{
    y += sd()->textfont->max_bounds.ascent;
    if (color != side->bgcolor) {
	XSetForeground(sdd(), sd()->textgc, color);
	XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
    } else {
	XSetForeground(sdd(), sd()->textgc, side->bgcolor);
	XSetBackground(sdd(), sd()->textgc, side->fgcolor);
	XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
	XSetBackground(sdd(), sd()->textgc, side->bgcolor);
    }
}

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

draw_scratchout(side, pos)
Side *side;
int pos;
{
    XSetForeground(sdd(), sd()->textgc, side->fgcolor);
    XDrawLine(sdd(), side->sides, sd()->textgc, 0, pos, 30*side->fw, pos);
}

/* Beep the beeper! */

beep(side)
Side *side;
{
    XBell(sdd(), 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;
{
    XEvent evt;

    XMapWindow(sdd(), side->help);
    /* wait until this window is exposed to return. */
    XWindowEvent(sdd(), side->help, ExposureMask, &evt);
    return TRUE;
}

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

/* 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(sdd());
    side->display = (long) NULL;
}