|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T X
Length: 35753 (0x8ba9) Types: TextFile Names: »X11.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Xconq/X11.c«
/* 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; }