home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume4 / xconq5 / part02 / X11.c < prev   
C/C++ Source or Header  |  1988-06-29  |  36KB  |  1,144 lines

  1. /* Copyright (c) 1987, 1988  Stanley T. Shebs, University of Utah. */
  2. /* Copyright 1988 by Chris D. Peterson, MIT. */
  3. /* Many improvements by Tim Moore, University of Utah. */
  4. /* This program may be used, copied, modified, and redistributed freely */
  5. /* for noncommercial purposes, so long as this notice remains intact.  */
  6.  
  7. /* RCS $Header: X11.c,v 1.1 88/06/21 12:30:00 shebs Exp $ */
  8.  
  9. /* Interface implementations for the X11 version of xconq. */
  10.  
  11. #include "config.h"
  12. #include "misc.h"
  13. #include "period.h"
  14. #include "side.h"
  15. #include "unit.h"
  16. #include "map.h"
  17. #include "global.h"
  18.  
  19. /* careful of the path of the X header files. */
  20.  
  21. #ifdef UNIX
  22. #include <signal.h>   /* needed for ^C disabling */
  23. #include <X11/Xlib.h>
  24. #include <X11/Xutil.h>
  25. #endif UNIX
  26.  
  27. /* various bitmap definitions. */
  28.  
  29. #define dots_width 16
  30. #define dots_height 16
  31. static char dots_bits[] = {
  32.    0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  33.    0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  34.    0x01, 0x01,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  35.    0x10, 0x10,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  36.  
  37. #define mask_width 16
  38. #define mask_height 16
  39. static char mask_bits[] = {
  40.    0xe0, 0x03,  0xd8, 0x0f,  0xb4, 0x19,  0x8a, 0x21, 
  41.    0x86, 0x61,  0x85, 0x41,  0x83, 0xc1,  0xff, 0xff, 
  42.    0xff, 0xff,  0x83, 0xc1,  0x82, 0xa1,  0x86, 0x61, 
  43.    0x84, 0x51,  0x98, 0x2d,  0xf0, 0x1b,  0xc0, 0x07};
  44.  
  45. #define curs_width 16
  46. #define curs_height 16
  47. static char curs_bits[] = {
  48.    0xe0, 0x03,  0x98, 0x0c,  0x84, 0x10,  0x82, 0x20, 
  49.    0x82, 0x20,  0x81, 0x40,  0x81, 0x40,  0xff, 0x7f, 
  50.    0x81, 0x40,  0x81, 0x40,  0x82, 0x20,  0x82, 0x20, 
  51.    0x84, 0x10,  0x98, 0x0c,  0xe0, 0x03,  0x00, 0x00};
  52.  
  53. #define bomb1_width 32
  54. #define bomb1_height 32
  55. static char bomb1_bits[] = {
  56.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  57.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  58.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  59.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  60.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  61.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  62.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  63.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  64.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  65.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  66.    0x00, 0xc0,  0x01, 0x00,  0x00, 0xf0,  0x07, 0x00, 
  67.    0x00, 0xf0,  0x07, 0x00,  0x00, 0xf8,  0x0f, 0x00, 
  68.    0x00, 0xf8,  0x0f, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
  69.    0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
  70.    0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
  71.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  72.  
  73. #define bomb2_width 32
  74. #define bomb2_height 32
  75. static char bomb2_bits[] = {
  76.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  77.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  78.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  79.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  80.    0x00, 0x00,  0x00, 0x00,  0x00, 0xf8,  0x01, 0x00, 
  81.    0x00, 0xf8,  0x07, 0x00,  0x00, 0xfc,  0x0f, 0x00, 
  82.    0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfe,  0x1f, 0x00, 
  83.    0x00, 0xfe,  0x3f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
  84.    0x00, 0xfc,  0x0f, 0x00,  0x00, 0xf0,  0x07, 0x00, 
  85.    0x00, 0xf0,  0x03, 0x00,  0x00, 0xe0,  0x03, 0x00, 
  86.    0x00, 0xf0,  0x07, 0x00,  0x00, 0xf0,  0x07, 0x00, 
  87.    0x00, 0xf0,  0x0f, 0x00,  0x00, 0xf0,  0x0f, 0x00, 
  88.    0x00, 0xf8,  0x0f, 0x00,  0x00, 0xf8,  0x1f, 0x00, 
  89.    0x00, 0xf8,  0x1f, 0x00,  0x00, 0xfc,  0x1f, 0x00, 
  90.    0x00, 0xff,  0x7f, 0x00,  0xc0, 0xff,  0xff, 0x03, 
  91.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  92.  
  93. #define bomb3_width 32
  94. #define bomb3_height 32
  95. static char bomb3_bits[] = {
  96.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  97.    0x00, 0x00,  0x00, 0x00,  0xfe, 0xe2,  0xa3, 0x3f, 
  98.    0x00, 0xfc,  0x1f, 0x00,  0x3c, 0xff,  0x7f, 0x7c, 
  99.    0x80, 0xff,  0xff, 0x00,  0xc0, 0xff,  0xff, 0x01, 
  100.    0xc0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x03, 
  101.    0xe0, 0xff,  0xff, 0x03,  0xe0, 0xff,  0xff, 0x03, 
  102.    0xe0, 0xff,  0xff, 0x01,  0xe0, 0xff,  0xff, 0x49, 
  103.    0x82, 0xff,  0xff, 0x34,  0x14, 0xfe,  0x3f, 0x42, 
  104.    0xe2, 0xff,  0x9f, 0x34,  0x40, 0xfe,  0x3f, 0x41, 
  105.    0xbe, 0xfd,  0xdf, 0x1e,  0x00, 0xf8,  0x1f, 0x01, 
  106.    0xfe, 0xfd,  0xdf, 0x7f,  0x00, 0xfc,  0x1f, 0x00, 
  107.    0x00, 0xfc,  0x1f, 0x00,  0x00, 0xfc,  0x3f, 0x00, 
  108.    0x00, 0xfe,  0x1f, 0x00,  0x00, 0xfe,  0x3f, 0x00, 
  109.    0x00, 0xff,  0x3f, 0x00,  0xc0, 0xff,  0xff, 0x00, 
  110.    0xfc, 0xff,  0xff, 0x3f,  0xfe, 0xff,  0xff, 0x7f, 
  111.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  112.  
  113. #define bomb4_width 32
  114. #define bomb4_height 32
  115. static char bomb4_bits[] = {
  116.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  117.    0x00, 0x00,  0x00, 0x00,  0x00, 0xc0,  0x07, 0x00, 
  118.    0x00, 0x78,  0x10, 0x00,  0x00, 0x0f,  0x46, 0x00, 
  119.    0x80, 0x61,  0x81, 0x00,  0xc0, 0x1c,  0x00, 0x01, 
  120.    0x40, 0x02,  0x00, 0x00,  0x20, 0x01,  0x00, 0x00, 
  121.    0x20, 0x01,  0x00, 0x00,  0x20, 0x00,  0x00, 0x00, 
  122.    0x20, 0x00,  0x00, 0x00,  0x40, 0x00,  0x00, 0x00, 
  123.    0x80, 0x00,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
  124.    0x00, 0x02,  0x00, 0x00,  0x00, 0x04,  0x00, 0x00, 
  125.    0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  126.    0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  127.    0x00, 0x04,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  128.    0x00, 0x04,  0x00, 0x00,  0x00, 0x02,  0x00, 0x00, 
  129.    0x00, 0x01,  0x00, 0x00,  0xc0, 0x00,  0x00, 0x00, 
  130.    0x2c, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00, 
  131.    0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00};
  132.  
  133. /* This is the name of a family of programs, so argv[0] inadequate. */
  134.  
  135. #define PROGRAMNAME "xconq"
  136.  
  137. /* Name of default font - why is this wired in? */
  138.  
  139. #define STANDARD "standard"
  140.  
  141. /* Magic number meaning that this pixmap intentionally left blank. */
  142.  
  143. #define NOPIXMAP 17
  144.  
  145. #define INFOLINES 4
  146. #define DELAY 100000
  147.  
  148. #define BH 32
  149.  
  150. /* Use with caution - variable name "side" embedded! */
  151.  
  152. #define sd() ((Screeno *) side->display)
  153.  
  154. #define sdd() (((Screeno *) side->display)->disp)
  155.  
  156. typedef unsigned int unint;
  157.  
  158. /* GC rules are for different fonts etc, but not colors or bitmaps. */
  159.  
  160. typedef struct a_screen {
  161.     Display *disp;
  162.     GC gc;            /* a tmp graphics context for this display */
  163.     GC flashgc;            /* The gc for drawing the flash lines. */
  164.     GC textgc;            /* foreground on background text */
  165.     GC icongc;            /* icon graphics context */
  166.     GC invicongc;        /* icon gc inverted colors. */
  167.     GC varicongc;        /* This is an icon gc with variable fgcolor. */
  168.     GC unitgc;            /* unit bitmap printing gc. */
  169.     GC unittextgc;        /* unit text printing gc. */
  170.     GC cleargc;            /* The gc to use for clearing areas. */
  171.     GC clearbitgc;              /* gc for clearing bitmaps */
  172.     XFontStruct *textfont;    /* font for text display */
  173.     XFontStruct *iconfont;    /* utility font with assorted icons */
  174.     XFontStruct *unitfont;    /* font for unit characters */
  175.     Pixmap bombpics[4];        /* mushroom clouds */
  176.     Pixmap unitpics[MAXUTYPES];    /* used instead of font sometimes */
  177.     Pixmap wbdots, bwdots;    /* blue border and dotted backgrounds */
  178.     Cursor curs;        /* the cursor object itself */
  179. } Screeno;
  180.  
  181. extern int giventime;
  182.  
  183. /* Random function declarations. */
  184.  
  185. XFontStruct * open_font();
  186. Pixmap load_bitmap();
  187. void get_font_size();
  188. Cursor make_cursor();
  189.  
  190. /* The array of screen objects. */
  191.  
  192. Screeno screens[MAXSIDES];      /* All the "screen objects" */
  193.  
  194. /* Values of parameters generally tied to fonts and the like. */
  195.  
  196. int hw = 20;
  197. int hh = 22;
  198. int hch = 17;
  199. int margin = 2;
  200. int bd = 1;
  201.  
  202. int helpwinlines = 1;           /* size of help window */
  203.  
  204. bool rootcursor;                /* true if using parent window's cursor */
  205.  
  206. /* Put in a default player, probably the invoker of the program. */
  207. /* An empty host name will confuse everybody. */
  208.  
  209. add_default_player()
  210. {
  211. #ifdef UNIX
  212.     add_player(TRUE, getenv("DISPLAY"));
  213. #endif UNIX
  214. }
  215.  
  216. /* Ignore ^C if humans in the game, do it otherwise, including when the */
  217. /* last human player turns into a machine (this is called by option cmd). */
  218. /* Attempts to be more clever seem to be bad news. */
  219.  
  220. init_sighandlers()
  221. {
  222. #ifdef UNIX
  223.     if (numhumans > 0 && !Debug) {
  224.     signal(SIGINT, SIG_IGN);
  225.     } else {
  226.     signal(SIGINT, SIG_DFL);
  227.     }
  228. #endif UNIX
  229. }
  230.  
  231. /* Note that the open_display function syncronizes the X server when the */
  232. /* Debug flag is set. */
  233.  
  234. open_display(side)
  235. Side *side;
  236. {
  237.     side->display = (long) &(screens[side_number(side)]);
  238.     sdd() = XOpenDisplay(side->host);
  239.     if (Debug) {
  240.       XSynchronize(sdd(), TRUE);
  241.       printf("Synching the X server.\n");
  242.     }
  243.     side->main = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
  244.                      50, 3, 100, 100,
  245.                      3, white_color(side), black_color(side));
  246.     return (sdd() != NULL);
  247. }
  248.  
  249. /* A predicate that tests whether our display can safely be written to. */
  250.  
  251. active_display(side)
  252. Side *side;
  253. {
  254.     return (side && side->host && !side->lost && side->display);
  255. }
  256.  
  257. display_width(side)
  258. Side *side;
  259. {
  260.     return ((19 * XDisplayWidth(sdd(), 0)) / 20);
  261. }
  262.  
  263. display_height(side)
  264. Side *side;
  265. {
  266.     return ((19 * XDisplayHeight(sdd(), 0)) / 20);
  267. }
  268.  
  269. /* Most X displays have enough screen to do a world map. */
  270.  
  271. world_display(side) Side *side; {  return TRUE;  }
  272.  
  273. /* Could use handlers for X failures... */
  274.  
  275. /* Do misc setup thingies. */
  276.  
  277. /* Do the rigmarole to convert all those short arrays into X-approved */
  278. /* Bitmaps.  Note that this has to be for *each* display separately (!) */
  279. /* Also get the cursor shape.  If the hardware can't hack the desired */
  280. /* cursor size, warn about it and just use the root window's cursor. */
  281. /* 0x0 cursor specs seem to be don't cares - machine can handle any size */
  282. /* X11 also needs gazillions of GCs, since we've got so many fonts and */
  283. /* colors and bitmaps. */
  284.  
  285. init_misc(side)
  286. Side *side;
  287. {
  288.     int u, w, h;
  289.     unsigned long mask;
  290.     XGCValues values;
  291.     Pixmap mmask, mcurs, dots;
  292.     GC gc;
  293.  
  294.     side->margin = margin;
  295.     side->bd = bd;
  296.     side->hw = hw;
  297.     side->hh = hh;
  298.     side->hch = hch;
  299.     mask = GCForeground | GCBackground;
  300.     values.foreground = side->fgcolor;
  301.     values.background = side->bgcolor;
  302.     gc = XCreateGC(sdd(), side->main, mask, &values);
  303.     sd()->gc = XCreateGC(sdd(), side->main, mask, &values);
  304.     sd()->flashgc = XCreateGC(sdd(), side->main, mask, &values);
  305.     sd()->textgc = XCreateGC(sdd(), side->main, mask, &values);
  306.     sd()->icongc = XCreateGC(sdd(), side->main, mask, &values);
  307.     sd()->varicongc = XCreateGC(sdd(), side->main, mask, &values);
  308.     sd()->unitgc = XCreateGC(sdd(), side->main, mask, &values);
  309.     sd()->unittextgc = XCreateGC(sdd(), side->main, mask, &values);
  310.     values.foreground = side->bgcolor;
  311.     values.background = side->fgcolor;
  312.     sd()->invicongc = XCreateGC(sdd(), side->main, mask, &values);
  313.     values.function = GXclear;
  314.     mask = GCFunction;
  315.     sd()->cleargc = XCreateGC(sdd(), side->main, mask, &values);
  316.  
  317.     sd()->textfont = open_font(side, TEXTFONT, "TextFont", NULL);
  318.     get_font_size(sd()->textfont, &(side->fw), &(side->fh) );
  319.     sd()->iconfont = open_font(side, ICONFONT, "IconFont", sd()->textfont);
  320.     get_font_size(sd()->iconfont, &(side->hw), &(side->hh) );
  321.     if (period.fontname != NULL && strlen(period.fontname) > 0) {
  322.     sd()->unitfont = 
  323.         open_font(side, period.fontname, "UnitFont", sd()->textfont);
  324.     get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
  325.     } else {
  326.           sd()->unitfont = 
  327.         open_font(side, STANDARD, "UnitFont", sd()->textfont);
  328.     get_font_size(sd()->unitfont, &(side->uw), &(side->uh) );
  329.     }
  330.     XSetFont(sdd(), sd()->textgc, sd()->textfont->fid);
  331.     XSetFont(sdd(), sd()->icongc, sd()->iconfont->fid);
  332.     mask = GCFillStyle | GCGraphicsExposures;
  333.     values.fill_style = FillSolid;
  334.     values.graphics_exposures = FALSE;
  335.     XChangeGC(sdd(), sd()->unitgc, mask, &values);
  336.     XSetFont(sdd(), sd()->unittextgc, sd()->unitfont->fid);
  337.     XSetFont(sdd(), sd()->invicongc, sd()->iconfont->fid);
  338.     XSetFont(sdd(), sd()->varicongc, sd()->iconfont->fid);
  339.     XSetFunction(sdd(), sd()->flashgc, GXinvert);
  340.  
  341.     mmask = XCreateBitmapFromData(sdd(), side->main,
  342.                     mask_bits, mask_width, mask_height);
  343.     mcurs = XCreateBitmapFromData(sdd(), side->main,
  344.                     curs_bits, curs_width, curs_height);
  345.  
  346.     dots  = XCreateBitmapFromData(sdd(), side->main, 
  347.                   dots_bits, dots_width, dots_height);
  348.  
  349.     sd()->bombpics[0] = XCreateBitmapFromData(sdd(), side->main,
  350.     bomb1_bits, bomb1_width, bomb1_height);
  351.     sd()->bombpics[1] = XCreateBitmapFromData(sdd(), side->main,
  352.         bomb2_bits, bomb2_width, bomb2_height);
  353.     sd()->bombpics[2] = XCreateBitmapFromData(sdd(), side->main,
  354.     bomb3_bits, bomb3_width, bomb3_height);
  355.     sd()->bombpics[3] = XCreateBitmapFromData(sdd(), side->main,
  356.     bomb4_bits, bomb4_width, bomb4_height);
  357.     for_all_unit_types(u) {
  358.     if (utypes[u].bitmapname && (strlen(utypes[u].bitmapname) > 0)) {
  359.         sd()->unitpics[u] = load_bitmap(side, utypes[u].bitmapname);
  360.     } else {
  361.         utypes[u].bitmapname = NULL;
  362.     }
  363.     }
  364.     if (Debug) printf("Bitmaps stored ...\n");
  365.  
  366.     sd()->wbdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
  367.                  DefaultDepth(sdd(), 0) );
  368.     sd()->bwdots = XCreatePixmap(sdd(), side->main, dots_width, dots_height,
  369.                  DefaultDepth(sdd(), 0) );
  370.  
  371.     /* Since clearbitgc has to have a depth of 1 we'll */
  372.     /* hang it off bombpics[0] */
  373.     mask = GCFunction;
  374.     values.function = GXclear;
  375.     sd()->clearbitgc = XCreateGC(sdd(), sd()->bombpics[0], mask, &values);
  376.  
  377.     XSetForeground(sdd(), gc, side->fgcolor);
  378.     XSetBackground(sdd(), gc, side->bgcolor);
  379.     XSetStipple(sdd(), gc, dots);
  380.     XSetFillStyle(sdd(), gc, FillOpaqueStippled);
  381.     XFillRectangle(sdd(), sd()->wbdots, gc, 0, 0, dots_width, dots_height);
  382.  
  383.     XSetForeground(sdd(), gc, side->bgcolor);
  384.     XSetBackground(sdd(), gc, side->fgcolor);
  385.     XFillRectangle(sdd(), sd()->bwdots, gc, 0, 0, dots_width, dots_height);
  386.     if (Debug) printf("Tiles stored ...\n");
  387.  
  388.     rootcursor = FALSE;
  389.     XQueryBestCursor(sdd(), side->main, curs_width, curs_height, &w, &h);
  390.     if (Debug) printf("Allowed cursor shape is %dx%d\n", w, h);
  391.     if (w == curs_width && h == curs_height) {
  392.         sd()->curs =
  393.       make_cursor(sdd(), mcurs, mmask, white_color(side),
  394.               black_color(side), 7, 7);
  395.        
  396.     } else {
  397.     fprintf(stderr, "Warning: Can't have %dx%d cursors on \"%s\"!\n",
  398.         curs_width, curs_height, side->host);
  399.         fprintf(stderr, "Using default cursor...\n");
  400.         rootcursor = TRUE;
  401.     }
  402.     if (Debug) printf("Cursor stored ...\n");
  403.     XFreeGC(sdd(), gc);
  404.     XFreePixmap(sdd(), dots);
  405.     XFreePixmap(sdd(), mmask);
  406.     XFreePixmap(sdd(), mcurs);
  407. }
  408.  
  409. /* Since XCreatePixmapCursor() takes XColors and not pixel values we */
  410. /* have to look the colors associated with the foreground and */
  411. /* background pixel values up in the color table and pass them to */
  412. /* XCreatePixmapCursor(). */
  413.    
  414. Cursor make_cursor(dpy, curs, mask, foreground, background, x, y)
  415. Display *dpy;
  416. Pixmap curs, mask;
  417. unsigned long foreground, background;
  418. unsigned int x, y;
  419. {
  420.     XColor defs[2];
  421.  
  422.     defs[0].pixel = foreground;
  423.     defs[1].pixel = background;
  424.     XQueryColors(dpy, DefaultColormap(dpy, 0), defs, 2);
  425.     return  XCreatePixmapCursor(dpy, curs, mask, &defs[0], &defs[1], x, y);
  426. }
  427.  
  428. /* Since font lookup is still not smart among Xs, this is a general routine */
  429. /* that can deal with unopenable, missing, etc, fonts, as well as the use of */
  430. /* .Xdefaults.  One of the inputs is another font that can be substituted if */
  431. /* necessary. */
  432.  
  433. XFontStruct *
  434. open_font(side, name, xdefault, altfont)
  435. Side *side;
  436. char *name, *xdefault;
  437. XFontStruct * altfont;
  438. {
  439.     char *firstname, *altname;
  440.     XFontStruct * font;
  441.  
  442.     if ((altname = XGetDefault(sdd(), PROGRAMNAME, xdefault)) != NULL)
  443.     name = altname;
  444.     firstname = name;
  445.     if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
  446.     make_pathname(XCONQLIB, name, "snf", spbuf);
  447.     name = spbuf;
  448.     if ((font = XLoadQueryFont(sdd(), name)) == NULL) {
  449.         fprintf(stderr, "Can't open fonts \"%s\" or \"%s\" on \"%s\"\n",
  450.             firstname, name, side->host);
  451.         if (altfont != NULL) {
  452.         fprintf(stderr, "Substituting another font...\n");
  453.         return altfont;
  454.         } else {
  455.         fprintf(stderr, "No font to substitute!!\n");
  456.         exit(1);
  457.         }
  458.     }
  459.     }
  460.     if (Debug) printf("Opened font \"%s\" ...\n", name);
  461.     return font;
  462. }
  463.  
  464. /* Force X11 font fanciness into semblance of X10 font plainness. */
  465.  
  466. void
  467. get_font_size(font, width, height)
  468. XFontStruct * font;
  469. short *width, *height;
  470. {
  471.     *width = font->max_bounds.rbearing - font->min_bounds.lbearing;
  472.     *height = font->max_bounds.ascent + font->min_bounds.descent;
  473.     if (Debug) {
  474.     printf("rbearing = %d lbearing = %d\n",
  475.            (int)font->max_bounds.rbearing, (int)font->min_bounds.lbearing);
  476.     printf("returning font size %d %d\n", (int)*width, (int)*height);
  477.     }
  478. }
  479.  
  480. /* Try to load a bitmap of the given name - can be either X11-only (.b11) */
  481. /* or X10 (.b) bitmaps, but prefer X11 flavor. */
  482.  
  483. Pixmap
  484. load_bitmap(side, name)
  485. Side *side;
  486. char *name;
  487. {
  488.     int w, h, junk, a;
  489.     Pixmap rslt;
  490.  
  491.     make_pathname(NULL, name, "b11", spbuf);
  492.     a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
  493.     if (a == BitmapSuccess) return rslt;
  494.     make_pathname(XCONQLIB, name, "b11", spbuf);
  495.     a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
  496.     if (a == BitmapSuccess) return rslt;
  497.     make_pathname(XCONQLIB, name, "b", spbuf);
  498.     a = XReadBitmapFile(sdd(), side->main, spbuf, &w, &h, &rslt, &junk, &junk);
  499.     if (a == BitmapSuccess) return rslt;
  500.     fprintf(stderr, "Bitmap name \"%s\" not found anywhere!\n", name);
  501.     return (-1);
  502. }
  503.  
  504. /* This routine has to be able to cope with window managers constraining */
  505. /* size.  Actually, the main window was already opened when the display */
  506. /* was opened, so the name is not quite accurate! */
  507.  
  508. create_main_window(side)
  509. Side *side;
  510. {
  511.     Pixmap dots;
  512.     XSizeHints hints;
  513.           
  514.     XStoreName(sdd(), side->main, PROGRAMNAME);
  515.     dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
  516.     XSetWindowBackgroundPixmap(sdd(), side->main, dots);
  517.  
  518.     hints.width = side->mw;
  519.     hints.height = side->mh;
  520.     hints.min_width = side->mw;
  521.     hints.min_height = side->mh;
  522.     hints.flags = PSize|PMinSize;
  523.     XSetNormalHints(sdd(), side->main, &hints);
  524. }
  525.  
  526. /* Help window is not necessarily a subwindow, though it might be sometimes. */
  527.  
  528. create_help_window(side)
  529. Side *side;
  530. {
  531.     helpwinlines =
  532.     max(45, (24 + period.numrtypes + period.numttypes + period.numutypes));
  533.  
  534.     side->help = XCreateSimpleWindow(sdd(), DefaultRootWindow(sdd()),
  535.                      0, 0, 80*side->fw+1,
  536.                      helpwinlines*side->fh+1,
  537.                      1, side->fgcolor, side->bgcolor);
  538.     XStoreName(sdd(), side->help, "xconq-help");
  539. }
  540.  
  541. /* Subwindow creator. */
  542.  
  543. create_window(side, x, y, w, h)
  544. Side *side;
  545. int x, y, w, h;
  546. {
  547.     return XCreateSimpleWindow(sdd(), side->main, x, y, w, h,
  548.                    1, side->fgcolor, side->bgcolor);
  549. }
  550.  
  551. /* Do little things necesary to make it all go, in this case mapping all */
  552. /* the windows (except help win). */
  553.  
  554. fixup_windows(side)
  555. Side *side;
  556. {
  557.     XMapWindow(sdd(), side->main);
  558.     XMapSubwindows(sdd(), side->main);
  559.     if (!giventime) XUnmapWindow(sdd(), side->clock);
  560.     if (!rootcursor) XDefineCursor(sdd(), side->map, sd()->curs);
  561. }
  562.  
  563. /* Specify the sorts of input that will be allowed. */
  564.  
  565. enable_input(side)
  566. Side *side;
  567. {
  568.     XSelectInput(sdd(), side->main, KeyPressMask|ExposureMask);
  569.     XSelectInput(sdd(), side->map,  ButtonPressMask|ExposureMask);
  570.     XSelectInput(sdd(), side->help, KeyPressMask|ExposureMask);
  571. }
  572.  
  573. /* Move windows and change their sizes to correspond with the new sizes of */
  574. /* viewports, etc */
  575.  
  576. reset_misc(side)
  577. Side *side;
  578. {
  579.     Pixmap dots;
  580.     XSizeHints hints;
  581.     XGCValues values;
  582.     unsigned int gcmask;
  583.  
  584.     dots = (side->bonw ? sd()->bwdots : sd()->wbdots); 
  585.  
  586.     XResizeWindow(sdd(), side->main, side->mw, side->mh);
  587.     hints.width = side->mw;  hints.height = side->mh;
  588.     hints.min_width = side->mw;  hints.min_height = side->mh;
  589.     hints.flags = PSize|PMinSize;
  590.     XSetNormalHints(sdd(), side->main, &hints);
  591.  
  592.     XSetWindowBackgroundPixmap(sdd(), side->main, dots);
  593.     XSetWindowBackground(sdd(), side->msg, side->bgcolor);
  594.     XSetWindowBackground(sdd(), side->info, side->bgcolor); 
  595.     XSetWindowBackground(sdd(), side->prompt, side->bgcolor); 
  596.     XSetWindowBackground(sdd(), side->map, side->bgcolor);
  597.     XSetWindowBackground(sdd(), side->timemode, side->bgcolor);
  598.     XSetWindowBackground(sdd(), side->clock, side->bgcolor);
  599.     XSetWindowBackground(sdd(), side->state, side->bgcolor);
  600.     XSetWindowBackground(sdd(), side->help, side->bgcolor);
  601.     XSetWindowBackground(sdd(), side->sides, side->bgcolor);
  602.     XSetWindowBackground(sdd(), side->world, side->bgcolor);
  603.     XSetWindowBorder(sdd(), side->msg, side->fgcolor);
  604.     XSetWindowBorder(sdd(), side->info, side->fgcolor); 
  605.     XSetWindowBorder(sdd(), side->prompt, side->fgcolor); 
  606.     XSetWindowBorder(sdd(), side->map, side->fgcolor);
  607.     XSetWindowBorder(sdd(), side->timemode, side->fgcolor);
  608.     XSetWindowBorder(sdd(), side->clock, side->fgcolor);
  609.     XSetWindowBorder(sdd(), side->state, side->fgcolor);
  610.     XSetWindowBorder(sdd(), side->help, side->fgcolor);
  611.     XSetWindowBorder(sdd(), side->sides, side->fgcolor);
  612.     XSetWindowBorder(sdd(), side->world, side->fgcolor);
  613.  
  614.     gcmask = GCForeground | GCBackground;
  615.     values.foreground = side->fgcolor;
  616.     values.background = side->bgcolor;
  617.     XChangeGC(sdd(), sd()->gc, gcmask, &values);
  618.     XChangeGC(sdd(), sd()->flashgc, gcmask, &values);
  619.     XChangeGC(sdd(), sd()->textgc, gcmask, &values);
  620.     XChangeGC(sdd(), sd()->icongc, gcmask, &values);
  621.     XChangeGC(sdd(), sd()->unitgc, gcmask, &values);
  622.     values.foreground = side->bgcolor;
  623.     values.background = side->fgcolor;
  624.     XChangeGC(sdd(), sd()->invicongc, gcmask, &values);
  625. }
  626.  
  627. /* Alter the size and position of a window. */
  628.  
  629. change_window(side, win, x, y, w, h)
  630. Side *side;
  631. Window win;
  632. int x, y, w, h;
  633. {
  634.     unsigned int mask;
  635.     XWindowChanges changes;
  636.  
  637.     if (active_display(side)) {
  638.     if (x >= 0) {
  639.         if (w >= 0) {
  640.         mask = CWX | CWY | CWWidth | CWHeight;
  641.         changes.x = x;  changes.y = y;
  642.         changes.width = w;  changes.height = h;
  643.         } else {
  644.         mask = CWX | CWY;
  645.         changes.x = x;  changes.y = y;
  646.         }
  647.     } else {
  648.         mask = CWWidth | CWHeight;
  649.         changes.width = w;  changes.height = h;
  650.     }
  651.     }
  652.     XConfigureWindow(sdd(), win, mask, &changes);
  653. }
  654.  
  655. /* Return the number of colors - this is used to guess about monochromeness. */
  656.  
  657. display_colors(side) Side *side; {  return XDisplayCells(sdd(), 0);  }
  658.  
  659. white_color(side) Side *side; {  return WhitePixel(sdd(), 0);  }
  660.  
  661. black_color(side) Side *side; {  return BlackPixel(sdd(), 0);  }
  662.  
  663. /* Get a color set up and warn if not getting what was asked for. */
  664.  
  665. long
  666. request_color(side, name)
  667. Side *side;
  668. char *name;
  669. {
  670.     XColor c, avail;
  671.  
  672.     if (Debug) printf("Allocating %s\n", name);
  673.     XAllocNamedColor(sdd(), DefaultColormap(sdd(), 0), name, &avail, &c);
  674.     if (c.red != avail.red || c.green != avail.green || c.blue != avail.blue) {
  675.     fprintf(stderr, "Warning: %s color not exact on \"%s\"!\n",
  676.         name, side->host);
  677.     fprintf(stderr, "Is %d %d %d instead of %d %d %d\n",
  678.         avail.red, avail.green, avail.blue, c.red, c.green, c.blue);
  679.     }
  680.     return avail.pixel;
  681. }
  682.  
  683. /* Main funnel for input returns both mouse and keyboard events, and maybe */
  684. /* other kinds eventually.  Some events like window exposure are handled */
  685. /* strictly locally. */
  686.  
  687. get_input()
  688. {
  689. #ifdef SELECT2
  690.     int i, mask;
  691.     Side *side, *asides[32];
  692.  
  693.     mask = 0;
  694.     for_all_sides(side) {
  695.     if (active_display(side)) {
  696.         mask |= (1 << ConnectionNumber(sdd()));
  697.         asides[ConnectionNumber(sdd())] = side;
  698.         while (XPending(sdd()) > 0) {
  699.         process_events(side);
  700.         }
  701.         side->lasttime = time(0);
  702.     }
  703.     }
  704.     if (Debug) {
  705.     printf("Waiting for input from ");
  706.     for_all_sides(side)
  707.         if (active_display(side)) printf("%s ", side->host);
  708.     printf("\n");
  709.     }
  710.     if (select(32, &mask, 0, 0, 0) < 0) {
  711.     fprintf(stderr, "error in select!\n");
  712.     abort();
  713.     } else {
  714.     for (i = 0; i < 32; ++i) {
  715.         if (mask & (1 << i)) {
  716.         process_events(asides[i]);
  717.         asides[i]->timeleft -= (time(0) - asides[i]->lasttime); 
  718.         update_clock(asides[i]);
  719.         }
  720.     }
  721.     }
  722. #else
  723.     extern Side *curside;
  724.  
  725.     /* No simultaneity, but there's no portable way to do it, sigh */
  726.     if (active_display(curside) && humanside(curside)) {
  727.     if (Debug) printf("Waiting for input from %s\n", curside->host);
  728.     process_events(curside);
  729.     }
  730. #endif SELECT2
  731. }
  732.  
  733. /* Look at a single event and fill the request structure appropriately. */
  734.  
  735. process_events(side)
  736. Side *side;
  737. {
  738.     XEvent evt;
  739.     char buf[BUFSIZE];
  740.     int nchar, rawx, rawy;
  741.     unsigned int junk;
  742.  
  743.     while (TRUE) {
  744.     XNextEvent(sdd(), &evt);
  745.     switch (evt.type) {
  746.     case KeyPress:
  747.         if (evt.xkey.window != side->main &&
  748.         evt.xkey.window != side->help) 
  749.         return FALSE;
  750.         nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
  751.         if (nchar > 0) {
  752.         side->reqtype = KEYBOARD;
  753.         side->reqch = *buf;
  754.         if (Debug) printf("Host %s returns key '%c'\n",
  755.                   side->host, side->reqch);
  756.         return;
  757.         }
  758.         break;
  759.     case ButtonPress:
  760.         if (evt.xbutton.window == side->map) {
  761.         rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
  762.         side->reqtype = MAPPOS;
  763.         deform(side, rawx, rawy, &(side->reqx), &(side->reqy));
  764.         if (Debug) printf("Host %s returns map %d %d\n",
  765.                   side->host, side->reqx, side->reqy);
  766.         } else if (evt.xbutton.window == side->state) {
  767.         rawx = evt.xbutton.x;  rawy = evt.xbutton.y; 
  768.         side->reqtype = UNITTYPE;
  769.         side->requtype = rawy / max(side->hh, side->fh);
  770.         if (Debug) printf("Host %s returns unit type %d\n",
  771.                   side->host, side->requtype);
  772.         }
  773.         return;
  774.     case Expose:
  775.         if (evt.xexpose.window == side->main || 
  776.         evt.xexpose.window == side->map) {
  777.         flush_input(side);
  778.         redraw(side);
  779.         }
  780.         if (Debug) printf("Host %s exposes itself\n", side->host);
  781.         return FALSE;
  782.         break;
  783.     default:
  784.         case_panic("event type", evt.type);
  785.         break;
  786.     }
  787.     }
  788. }
  789.  
  790. /* Freese everything until given side supplies input, use sparingly. */
  791.  
  792. freeze_wait(side)
  793. Side *side;
  794. {
  795.     XEvent evt;
  796.     char buf[BUFSIZE];
  797.     int nchar;
  798.  
  799.     if (Debug) printf("Waiting for a %s event\n", side->host);
  800.     flush_input(side);
  801.     while(TRUE) {
  802.     XNextEvent(sdd(), &evt);
  803.     if (evt.type == KeyPress) {
  804.         nchar = XLookupString(&evt, buf, BUFSIZE, NULL, NULL);
  805.         if (nchar > 0) 
  806.         return *buf;
  807.         else
  808.         return '\0';
  809.     }
  810.     }  
  811. }
  812.  
  813. /* Get rid of extra key/mouse clicks. */
  814.  
  815. flush_input(side)
  816. Side *side;
  817. {
  818.     if (humanside(side)) XSync(sdd(), TRUE);
  819. }
  820.  
  821. /* Trivial abstraction - sometimes other routines like to ensure all output */
  822. /* actually on the screen. */
  823.  
  824. flush_output(side) 
  825. Side *side; 
  826. {  
  827.     if (humanside(side)) XFlush(sdd());  
  828. }
  829.  
  830. /* General window clearing. */
  831.  
  832. clear_window(side, win)
  833. Side *side;
  834. Window win;
  835. {
  836.     XClearWindow(sdd(), win);
  837. }
  838.  
  839. /* Draw a single horizontal constant-color bar on the world map.  If part */
  840. /* would not be drawn because of the map's obliqueness, cut it in two and */
  841. /* wrap one of the pieces around. */
  842.  
  843. draw_bar(side, x, y, len, color)
  844. Side *side;
  845. int x, y, len, color;
  846. {
  847.     int sx1, sx2, sy, sww;
  848.  
  849.     w_xform(side, x, y, &sx1, &sy);
  850.     w_xform(side, x + len, y, &sx2, &sy);
  851.     sww = side->mm * world.width;
  852.     XSetFillStyle(sdd(), sd()->gc, FillSolid);
  853.     XSetForeground(sdd(), sd()->gc, color);
  854.     if (sx1 < sww && sx2 >= sww) {
  855.     XFillRectangle(sdd(), side->world, sd()->gc,
  856.                sx1, sy, (unint) sww - sx1, (unint) side->mm);
  857.     XFillRectangle(sdd(), side->world, sd()->gc,
  858.                0, sy, (unint) sx2 - sww, (unint) side->mm);
  859.     } else {
  860.     sx1 %= sww;
  861.     sx2 %= sww;
  862.     XFillRectangle(sdd(), side->world, sd()->gc,
  863.                sx1, sy, (unint) sx2 - sx1, (unint) side->mm);
  864.     }
  865. }
  866.  
  867. /* Invert the outline box on the world map.  This is a little tricky, */
  868. /* because we want the lines to run through the middle of the world's */
  869. /* hexes, and because the line drawn should not overlap (or the overlaps */
  870. /* will be doubly inverted and look strange). */
  871.  
  872. invert_box(side, vcx, vcy)
  873. Side *side;
  874. int vcx, vcy;
  875. {
  876.     int x1, y1, x2, y2, sx1, sy1, sx2, sy2, mm2 = side->mm/2;
  877.  
  878.     x1 = vcx - side->vw2 + side->vh2/2;  y1 = vcy - side->vh2;
  879.     x2 = vcx + side->vw2 - side->vh2/2;  y2 = vcy + side->vh2;
  880.     w_xform(side, x1, y1, &sx1, &sy1);
  881.     w_xform(side, x2, y2, &sx2, &sy2);
  882.     sx1 += mm2;  sy1 -= mm2;  sx2 += mm2;  sy2 += mm2;
  883.     XSetFunction(sdd(), sd()->gc, GXinvert);
  884.     /* is this next call really necessary? */
  885.     XSetLineAttributes(sdd(), sd()->gc, 1, LineSolid, CapButt, JoinMiter);
  886.     XDrawLine(sdd(), side->world, sd()->gc, sx1, sy1, sx2, sy1);
  887.     XDrawLine(sdd(), side->world, sd()->gc, sx2, sy1-1, sx2, sy2+1);
  888.     XDrawLine(sdd(), side->world, sd()->gc, sx2, sy2, sx1, sy2);
  889.     XDrawLine(sdd(), side->world, sd()->gc, sx1, sy2+1, sx1, sy1-1);
  890.     XSetFunction(sdd(), sd()->gc, GXcopy);
  891. }
  892.  
  893. /* This interfaces higher-level drawing decisions to the rendition of */
  894. /* individual pieces of display. */
  895.  
  896. draw_terrain_row(side, sx, sy, buf, len, color)
  897. Side *side;
  898. int sx, sy, len, color;
  899. char *buf;
  900. {
  901.     sy += sd()->iconfont->max_bounds.ascent;
  902.     XSetForeground(sdd(), sd()->icongc, color);
  903.     XDrawString(sdd(), side->map, sd()->icongc, sx, sy, buf, len);
  904. }
  905.  
  906. /* Flash a pair of lines up, slow enough to draw the eye, but not so slow */
  907. /* as to get in the way. */
  908.  
  909. flash_position(side, sx, sy)
  910. Side *side;
  911. int sx, sy;
  912. {
  913.     int i, sx1, sy1, sx2, sy2;
  914.  
  915.     sx1 = sx - 50 + side->hw/2;  sy1 = sy + 50 + side->hch/2;
  916.     sx2 = sx + 50 + side->hw/2;  sy2 = sy - 50 + side->hch/2;
  917.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
  918.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
  919.     flush_output(side);
  920.     for (i = 0; i < DELAY; ++i);
  921.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy1, sx2, sy2);
  922.     XDrawLine(sdd(), side->map, sd()->flashgc, sx1, sy2, sx2, sy1);
  923. }
  924.  
  925. /* The "cursor icon" is just a pair of special chars - nothing to do with */
  926. /* X's notion of cursors. */
  927.  
  928. draw_cursor_icon(side, sx, sy)
  929. Side *side;
  930. int sx, sy;
  931. {
  932.     sy += sd()->iconfont->max_bounds.ascent;
  933.     XDrawString(sdd(), side->map, sd()->invicongc, sx, sy, "[", 1);
  934.     XSetForeground(sdd(), sd()->icongc, side->fgcolor);
  935.     XDrawString(sdd(), side->map, sd()->icongc, sx, sy, "]", 1);
  936. }
  937.  
  938. /* Draw the icon for a hex (given as a char). */
  939.  
  940. draw_hex_icon(side, win, sx, sy, color, ch)
  941. Side *side;
  942. Window win;
  943. int sx, sy, color;
  944. char ch;
  945. {
  946.     XSetForeground(sdd(), sd()->varicongc, color);
  947.     sy += sd()->iconfont->max_bounds.ascent;
  948.     XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
  949. }
  950.  
  951. /* Draw the number of an unfriendly side (never called for own units). */
  952.  
  953. draw_side_number(side, win, sx, sy, n, color)
  954. Side *side;
  955. Window win;
  956. int sx, sy, n, color;
  957. {
  958.     char ch = n + '0';
  959.  
  960.     if (n >= 0) {
  961.     XSetForeground(sdd(), sd()->varicongc, color);
  962.     sy += sd()->iconfont->max_bounds.ascent;
  963.     XDrawString(sdd(), win, sd()->varicongc, sx, sy, &ch, 1);
  964.     }
  965. }
  966.  
  967. draw_blast_icon(side, win, sx, sy, type, color)
  968. Side *side;
  969. Window win;
  970. int sx, sy, color;
  971. char type;
  972. {
  973.     char buf[1];
  974.  
  975.     XSetForeground(sdd(), sd()->varicongc, color);
  976.     buf[0] = type;
  977.     sy += sd()->iconfont->max_bounds.ascent;
  978.     XDrawString(sdd(), win, sd()->varicongc, sx, sy, buf, 1);
  979. }
  980.  
  981. /* Flash the player's screen in an unmistakable way. */
  982.  
  983. invert_whole_map(side)
  984. Side *side;
  985. {
  986.     int sw = side->vw * side->hw, sh = side->vh * side->hh;
  987.  
  988.     /* GC needs to be set for inverted drawing */
  989.     XDrawRectangle(sdd(), side->map, sd()->gc, 0, 0, sw, sh);
  990.     flush_output(side);
  991. }
  992.  
  993. /* Draw just one of the mushroom cloud shapes. */
  994.  
  995. draw_mushroom(side, x, y, i)
  996. Side *side;
  997. int x, y, i;
  998. {
  999.     int sx, sy;
  1000.     int color;
  1001.  
  1002.     color = ((side->monochrome || i == 3) ? side->fgcolor : side->bgcolor);
  1003.     xform(side, unwrap(side, x), y, &sx, &sy);
  1004.     XSetForeground(sdd(), sd()->unitgc, color);
  1005.     XSetClipMask(sdd(), sd()->unitgc, sd()->bombpics[i]);
  1006.     XSetClipOrigin(sdd(), sd()->unitgc, sx-BH/4, sy-BH/2);
  1007.     XFillRectangle(sdd(), side->map, sd()->unitgc, sx-BH/4, sy-BH/2, BH, BH);
  1008.     flush_output(side);
  1009. }
  1010.  
  1011. /* Confirm that we can indeed do bar graph displays. */
  1012.  
  1013. bar_graphs(side) Side *side;  {  return TRUE;  }
  1014.  
  1015. /* Do yet another X-toolkit-type function.  This draws a bar graph. */
  1016.  
  1017. draw_graph(side, number, amount, total, critical, title)
  1018. Side *side;
  1019. int number, amount, total, critical;
  1020. {
  1021.     int boxwidth, boxheight, boxoffset, boxleft, barwidth, barheight;
  1022.  
  1023.     if (total > 0) {
  1024.     boxwidth = 5*side->fw;
  1025.     boxheight = (INFOLINES-1)*side->fh - 2*side->margin;
  1026.     boxoffset = side->margin;
  1027.     boxleft = 30*side->fw + number * boxwidth;
  1028.     barwidth = boxwidth / 3;
  1029.     barheight = (boxheight * amount) / total;
  1030.     XSetForeground(sdd(), sd()->gc, side->fgcolor);
  1031.     XFillRectangle(sdd(), side->info, sd()->gc,
  1032.                boxleft + boxwidth/3 - 1, boxoffset - 1,
  1033.                barwidth + 2, boxheight + 2);
  1034.     XSetForeground(sdd(), sd()->gc, side->bgcolor);
  1035.     XFillRectangle(sdd(), side->info, sd()->gc,
  1036.                boxleft + boxwidth/3, boxoffset,
  1037.                barwidth, boxheight);
  1038.     if ( amount > critical)
  1039.       XSetForeground(sdd(), sd()->gc, side->goodcolor);
  1040.     else
  1041.       XSetForeground(sdd(), sd()->gc, side->badcolor);
  1042.     XFillRectangle(sdd(), side->info, sd()->gc,
  1043.                boxleft + boxwidth/3, boxoffset + boxheight - barheight,
  1044.                barwidth, barheight);
  1045.     draw_text(side, side->info,
  1046.           boxleft+(boxwidth-strlen(title)*side->fw)/2,
  1047.           (INFOLINES-1)*side->fh, title, side->fgcolor);
  1048.     }
  1049. }
  1050.  
  1051. /* Splash a unit image (either bitmap or font char) onto some window. */
  1052.  
  1053. draw_unit_icon(side, win, x, y, u, color)
  1054. Side *side;
  1055. Window win;
  1056. int x, y, u, color;
  1057. {
  1058.     char buf[1];
  1059.  
  1060.     y += 3;            /* fudge factor to make x11 look */
  1061.     x += 2;            /*  like X10 (ugh). */
  1062.     if (utypes[u].bitmapname != NULL ) {
  1063.       XSetForeground(sdd(), sd()->unitgc, color);
  1064.       XSetClipMask(sdd(), sd()->unitgc, sd()->unitpics[u]);
  1065.       XSetClipOrigin(sdd(), sd()->unitgc, x, y);
  1066.       XFillRectangle(sdd(), win, sd()->unitgc, x, y, side->uw, side->uh);
  1067.     } else {
  1068.         XSetForeground(sdd(), sd()->unittextgc, color);
  1069.     buf[0] = utypes[u].uchar;
  1070.     y += sd()->unitfont->max_bounds.ascent;
  1071.     XDrawString(sdd(), win, sd()->unittextgc, x, y, buf, 1);
  1072.     }
  1073. }
  1074.  
  1075. /* General text drawer. */
  1076.  
  1077. draw_text(side, win, x, y, str, color)
  1078. Side *side;
  1079. Window win;
  1080. int x, y, color;
  1081. char *str;
  1082. {
  1083.     y += sd()->textfont->max_bounds.ascent;
  1084.     if (color != side->bgcolor) {
  1085.     XSetForeground(sdd(), sd()->textgc, color);
  1086.     XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
  1087.     } else {
  1088.     XSetForeground(sdd(), sd()->textgc, side->bgcolor);
  1089.     XSetBackground(sdd(), sd()->textgc, side->fgcolor);
  1090.     XDrawImageString(sdd(), win, sd()->textgc, x, y, str, strlen(str));
  1091.     XSetBackground(sdd(), sd()->textgc, side->bgcolor);
  1092.     }
  1093. }
  1094.  
  1095. /* Draw a line through some side's title. */
  1096.  
  1097. draw_scratchout(side, pos)
  1098. Side *side;
  1099. int pos;
  1100. {
  1101.     XSetForeground(sdd(), sd()->textgc, side->fgcolor);
  1102.     XDrawLine(sdd(), side->sides, sd()->textgc, 0, pos, 30*side->fw, pos);
  1103. }
  1104.  
  1105. /* Beep the beeper! */
  1106.  
  1107. beep(side)
  1108. Side *side;
  1109. {
  1110.     XBell(sdd(), 0);
  1111. }
  1112.  
  1113. /* Little routines to pop up the help window and make it go away again */
  1114. /* They only get called when display is in use. */
  1115.  
  1116. reveal_help(side)
  1117. Side *side;
  1118. {
  1119.     XEvent evt;
  1120.  
  1121.     XMapWindow(sdd(), side->help);
  1122.     /* wait until this window is exposed to return. */
  1123.     XWindowEvent(sdd(), side->help, ExposureMask, &evt);
  1124.     return TRUE;
  1125. }
  1126.  
  1127. conceal_help(side)
  1128. Side *side;
  1129. {
  1130.     XUnmapWindow(sdd(), side->help);
  1131.     flush_output(side);
  1132. }
  1133.  
  1134. /* Shut a single display down, but only if there's one to operate on. */
  1135. /* Hit the display slot, for safety. */
  1136.  
  1137. close_display(side)
  1138. Side *side;
  1139. {
  1140.     XCloseDisplay(sdd());
  1141.     side->display = (long) NULL;
  1142. }
  1143.  
  1144.