]> granicus.if.org Git - xconq/blobdiff - x11/xinit.c
commits for 7.5.0 pre-release tarball
[xconq] / x11 / xinit.c
diff --git a/x11/xinit.c b/x11/xinit.c
new file mode 100644 (file)
index 0000000..d370063
--- /dev/null
@@ -0,0 +1,1887 @@
+/* Initialization for the X11 interface to Xconq.
+   Copyright (C) 1987-1989, 1991-1998 Stanley T. Shebs.
+
+Xconq is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.  See the file COPYING.  */
+
+#include "conq.h"
+#include "xtconq.h"
+extern void init_emblem(Side *side, Side *side2);
+
+extern XrmOptionDescRec xoptions[];
+extern int xoptions_count;
+
+static void set_optional_colors(Side *side);
+static void init_gcs(Side *side);
+static void init_fonts(Side *side);
+static void init_bitmaps(Side *side);
+static void init_cursors(Side *side);
+
+static void init_terrain_images(Side *side);
+static void init_emblem_images(Side *side);
+static void report_missing_images(Side *side);
+static void x11_describe_image(Side *side, Image *img);
+
+typedef struct s_varw {
+  Widget dialog;
+  char *value;
+  char *mess;
+} Varw;
+
+typedef struct s_assignw {
+  Widget sidew, pname, pid;
+  char *vname, *vid, *messname, *messid;
+  int vflag;
+} Assignw;
+
+typedef struct s_gamepop {
+  Widget shell;
+  Widget form;
+  Widget name;
+  Widget basemodule;
+  Widget version;
+  Widget title;
+  Widget blurb;
+  Widget instructions;
+  Widget notes;
+  Widget ok;
+  Widget add;
+  Widget verify;
+  Widget cancel;
+  Varw *variants;
+  int numvariants;
+  Assignw *assign;
+} GamePop;
+
+typedef struct s_gamew {
+  Widget form;
+  Widget name;
+  Widget title;
+  Widget blurb;
+  GamePop *pop;
+} Gamew;
+
+
+static void popup_game(int g, int flag);
+static void quit_dialog(Widget w, XtPointer client_data, XtPointer call_data);
+static void game_callback(Widget w, XtPointer client_data,
+                         XtPointer call_data);
+static void cancel_dialog(Widget w, XtPointer client_data,
+                         XtPointer call_data);
+static void ok_dialog(Widget w, XtPointer client_data, XtPointer call_data);
+static void go_dialog(Widget w, XtPointer client_data, XtPointer call_data);
+static void verify_dialog(Widget w, XtPointer client_data,
+                         XtPointer call_data);
+static void add_player_dialog(Widget w, XtPointer client_data,
+                             XtPointer call_data);
+static int valid_gamepop(void);
+static void splat_obj_in_textw(Widget w, Obj *obj);
+static Widget createTextWidget(char *name, Widget parent, Widget up, Obj *obj);
+static char *variant_default(Variant *var);
+static char *variant_name(Variant *var);
+static void horizontalDialog(Widget w);
+static void reverseVideoDialog(Widget w);
+static void implement_variant(char *value, Variant *var);
+static int valid_variant(char *value, Variant *var);
+static int type_player(char *value);
+static void init_assignw_player(Assignw *assignw, Player *player);
+static int can_open_display(char *dpyname);
+static int boolean_lisp(char *value);
+
+static int loop, chosen_game;
+
+static Widget gameShell;
+
+static Gamew *games;
+
+/* we could share this buffers with other modules */
+char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], errormess[BUFSIZE];
+
+Obj *variants;
+
+/* Display and window globals used in callbacks from generic imf
+   handling code. */
+
+extern int tmp_valid;
+
+extern Display *tmp_display;
+
+extern Window tmp_root_window;
+
+/* various bitmap definitions. */
+
+#include "bitmaps/lookglass.b"
+#include "bitmaps/lookmask.b"
+#include "bitmaps/movecurs.b"
+#include "bitmaps/movemask.b"
+#include "bitmaps/shootcurs.b"
+#include "bitmaps/shootmask.b"
+#include "bitmaps/buildcurs.b"
+#include "bitmaps/buildmask.b"
+
+#include "bitmaps/bomb1.b"
+#include "bitmaps/bomb2.b"
+#include "bitmaps/bomb3.b"
+#include "bitmaps/bomb4.b"
+
+#include "bitmaps/miss.b"
+#include "bitmaps/hit.b"
+#include "bitmaps/kill.b"
+
+#include "bitmaps/hex16.b"
+#include "bitmaps/hex16b.b"
+#include "bitmaps/hex32.b"
+#include "bitmaps/hex32b.b"
+
+#include "bitmaps/closer.b"
+#include "bitmaps/farther.b"
+
+#include "bitmaps/gray.b"
+#include "bitmaps/darkgray.b"
+
+#include "bitmaps/dots.b"
+
+#ifdef DESIGNERS
+#include "bitmaps/hexcurs.b"
+#include "bitmaps/hexcursmask.b"
+#include "bitmaps/bordcurs.b"
+#include "bitmaps/conncurs.b"
+#include "bitmaps/addunits.b"
+#include "bitmaps/people.b"
+#include "bitmaps/feature.b"
+#include "bitmaps/featuremask.b"
+#endif /* DESIGNERS */
+
+/* (add arrays of info about various drawing styles and allowable options) */
+
+enum whattouse terrstyles[] = {
+    useblocks,
+    useblocks,
+    useblocks,
+    usepolygons,
+    usepictures,
+    usepictures,
+    usepolygons,
+    usepolygons
+};
+
+/* The set of X11 resources that Xconq knows about. */
+
+static XtResource resources[] = {
+    { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
+      XtOffsetOf(UI, foreground), XtRString, (XtPointer)XtDefaultForeground },
+    { XtNbackground, XtCBackground, XtRPixel, sizeof (Pixel),
+      XtOffsetOf(UI, background), XtRString, (XtPointer)XtDefaultBackground },
+    { XtNgeometry, XtCGeometry, XtRString, sizeof (String),
+      XtOffsetOf(UI, geospec), XtRString, (XtPointer)NULL },
+};
+
+/* Do a precheck of the intended displays.  This happens just after
+   player spec reading so that any losing displays can be found before
+   game startup gets in too deep. */
+
+void
+check_player_displays()
+{
+    int numfailures = 0;
+    char *dpyname;
+    Player *player;
+    Display *dpy;
+
+    for_all_players(player) {
+       /* Try to open the display. */
+       dpyname = player->displayname;
+       if (dpyname != NULL) {
+           if (strcmp("_", dpyname) == 0)
+             dpyname = getenv("DISPLAY");
+           dpy = XOpenDisplay(dpyname);
+           if (dpy == NULL) {
+               fprintf(stderr, "Cannot open display \"%s\"!\n", dpyname);
+               ++numfailures;
+           } else {
+               XCloseDisplay(dpy);
+           }
+       }
+    }
+    if (numfailures > 0) {
+       init_error("can't open all the required displays");
+       exit(1);
+    }
+}
+
+/* Set up the basic user interface for a side.  This is called from the
+   kernel while doing the final assignment of players to sides, and
+   does not cause any display activity. */
+
+void
+init_ui(Side *side)
+{
+       /* This is a hack. Should figure out why the indepside
+        * is asking for a display! */
+    if (side_wants_display(side) && side != indepside) {
+        side->ui = (UI *) xmalloc(sizeof(UI));
+       Dprintf("One UI is %d bytes.\n", sizeof(UI));
+    } else {
+       side->ui = NULL;
+    }
+}
+
+/* Do a full redraw on each display. */
+
+void
+init_redraws()
+{
+    Side *side;
+
+    for_all_sides(side) {
+       if (side->ui != NULL) {
+           /* The moment of truth - up to now output has been suppressed. */
+           side->ui->active = TRUE;
+           draw_all_maps(side);
+       }
+    }
+}
+
+/* Open display, create all the windows we'll need, do misc setup
+   things, and initialize some globals to out-of-range values for
+   recognition later. */
+
+int toplevel_display_used = FALSE;
+
+void
+init_display(Side *side)
+{
+    int argc, p, u, t, s, depth;
+    char *dpyname, *str;
+    Display *dpy;
+
+    dpyname = side->player->displayname;
+
+    Dprintf("Will try to open %s display `%s'...\n",
+           side_desig(side), dpyname);
+
+    /* Detect the placeholder for the default display. */
+    if (strcmp("_", dpyname) == 0)
+      dpyname = getenv("DISPLAY");
+
+    /* See if we can use the already-opened display for this side;
+       if not, then open one. */
+    dpy = NULL;
+    if (!toplevel_display_used) {
+       str = XDisplayString(XtDisplay(thistoplevel));
+       if (!empty_string(str) && strcmp(str, dpyname) == 0) {
+           dpy = XtDisplay(thistoplevel);
+           side->ui->shell = thistoplevel;
+           toplevel_display_used = TRUE;
+       }
+    }
+    if (dpy == NULL) {
+       argc = 0;
+       dpy = XtOpenDisplay(thisapp, dpyname, PROGRAMNAME, PROGRAMCLASSNAME,
+                           xoptions, xoptions_count, &argc, NULL);
+       side->ui->shell = XtAppCreateShell(PROGRAMNAME, PROGRAMCLASSNAME,
+                                          topLevelShellWidgetClass, dpy,
+                                          tmpargs, 0);
+    }
+    side->ui->dpy = dpy;
+
+    if (DebugG)
+      XSynchronize(side->ui->dpy, True);
+
+    XtGetApplicationResources(side->ui->shell, side->ui,
+                             resources, XtNumber(resources), NULL, 0);
+
+    side->ui->kill_atom = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
+    /* Cache some generally useful values. */
+    side->ui->screen = DefaultScreen(dpy);
+    side->ui->rootwin = DefaultRootWindow(dpy);
+
+    /* Set up things shared by all the windows. */
+    side->ui->dflt_color_terr_images = TRUE;
+    side->ui->dflt_color_unit_images = TRUE;
+    side->ui->dflt_color_embl_images = TRUE;
+    side->ui->default_meridian_interval = 600;
+    side->ui->bonw = BLACKONWHITE;
+    depth = XDisplayCells(dpy, side->ui->screen);
+    DGprintf("%d different colors available ...\n", depth);
+    side->ui->monochrome = (depth <= 2);
+    for (p = 0; p < NUMPOWERS; ++p) {
+       side->ui->usewhat[p] =
+           (enum whattouse *)xmalloc (sizeof (side->ui->usewhat[p][0]) * numttypes);
+       side->ui->terrpics[p] =
+           (Pixmap*)xmalloc (sizeof (side->ui->terrpics[p][0]) * numttypes);
+       side->ui->terrchars[p] =
+           (char *)xmalloc (sizeof (side->ui->terrchars[p][0]) * numttypes);
+       side->ui->terrfonts[p] =
+           (XFontStruct**)xmalloc (sizeof (side->ui->terrfonts[p][0]) * numttypes);
+       for_all_terrain_types(t) {
+           /* Decide what display technique to use at each power. */
+           side->ui->usewhat[p][t] = terrstyles[p];
+           side->ui->terrpics[p][t] = None;
+           side->ui->terrchars[p][t] = '\0';
+           side->ui->terrfonts[p][t] = NULL;
+       }
+       side->ui->unitpics[p] =
+           (Pixmap*)xmalloc (sizeof (side->ui->unitpics[p][0]) * numutypes);
+       side->ui->unitmasks[p] =
+           (Pixmap*)xmalloc (sizeof (side->ui->unitmasks[p][0]) * numutypes);
+       side->ui->unitchars[p] =
+           (char *)xmalloc (sizeof (side->ui->unitchars[p][0]) * numutypes);
+       side->ui->unitfonts[p] =
+           (XFontStruct**)xmalloc (sizeof (side->ui->unitfonts[p][0]) * numutypes);
+       side->ui->ulegendfonts[p] =
+           (XFontStruct**)xmalloc (sizeof (side->ui->ulegendfonts[p][0]) * numutypes);
+       for_all_unit_types(u) {
+           side->ui->unitpics[p][u] = None;
+           side->ui->unitmasks[p][u] = None;
+           side->ui->unitchars[p][u] = '\0';
+           side->ui->unitfonts[p][u] = NULL;
+           side->ui->ulegendfonts[p][u] = NULL;
+       }
+    }
+    for (s = 0; s < MAXSIDES; ++s) {
+       side->ui->emblempics[s] = None;
+       side->ui->emblemmasks[s] = None;
+    }
+    set_colors(side);
+    init_fonts(side);
+    imf_interp_hook = x11_interp_imf;
+    imf_load_hook = x11_load_imf;
+    tmp_display = side->ui->dpy;
+    tmp_root_window = side->ui->rootwin;
+    tmp_valid = TRUE;
+    init_unit_images(side);
+    init_terrain_images(side);
+    init_emblem_images(side);
+    tmp_valid = FALSE;
+    report_missing_images(side);
+    imf_describe_hook = x11_describe_image;
+    set_optional_colors(side);
+    init_bitmaps(side);
+    init_gcs(side);
+    init_cursors(side);
+    /* Create the generic windows. */
+    side->ui->maps = NULL;
+
+    create_map(side, 5, side->ui->geospec);
+
+    /* At this point, the toplevel widget has been realized, so we can */
+    /* start doing things to it...  So, first things first: */
+    XSetWMProtocols(dpy, XtWindow(side->ui->shell),
+                   &side->ui->kill_atom, 1);
+    XtOverrideTranslations(side->ui->shell,
+                          XtParseTranslationTable("<Message>WM_PROTOCOLS: wm-quit()"));
+
+#ifdef DESIGNERS
+    /* If this side is already a designer (perhaps via command-line option)
+       popup the design controls now. */
+    if (side->designer)
+      popup_design(side);
+#endif /* DESIGNERS */
+
+    Dprintf("Successfully initialized `%s'!\n", dpyname);
+}
+
+/* This will set up the correct set of colors at any point in the game.
+   Colors are all specified by name; if any are not available, it is up to
+   the graphics interface to supply a substitute. */
+
+void
+set_colors(Side *side)
+{
+    int        t;
+
+    side->ui->fgcolor = side->ui->foreground;
+    side->ui->bgcolor = side->ui->background;
+    side->ui->whitecolor = request_color(side, "white");
+    side->ui->blackcolor = request_color(side, "black");
+    side->ui->diffcolor = side->ui->blackcolor;
+    side->ui->graycolor = side->ui->whitecolor;
+    side->ui->goodcolor = side->ui->badcolor = side->ui->whitecolor;
+    side->ui->gridcolor = side->ui->fgcolor;
+    side->ui->unseencolor = side->ui->fgcolor;
+    side->ui->contour_color = side->ui->fgcolor;
+    side->ui->country_border_color = side->ui->fgcolor;
+    side->ui->feature_color = side->ui->fgcolor;
+    side->ui->frontline_color = side->ui->fgcolor;
+    side->ui->meridian_color = side->ui->fgcolor;
+    side->ui->shoreline_color = side->ui->fgcolor;
+    side->ui->unit_name_color = side->ui->fgcolor;
+    /* Set colors to distinctive default; will set usefully later. */
+    side->ui->cellcolor =
+       (long int*)xmalloc (sizeof (side->ui->cellcolor[0]) * numttypes);
+    for_all_terrain_types(t) {
+       side->ui->cellcolor[t] = -1;
+    }
+}
+
+/* This will set up colors that are not crucial to the game.  By doing
+   after basic image color allocation, these won't suck up colormap
+   space that should go to images. */
+
+static void
+set_optional_colors(Side *side)
+{
+    if (!side->ui->monochrome) {
+       side->ui->diffcolor = request_color(side, "maroon");
+       side->ui->graycolor = request_color(side, "light gray");
+       side->ui->contour_color = request_color(side, g_contour_color());
+       side->ui->country_border_color =
+         request_color(side, g_country_border_color());
+#if 0 /* need to work with a list here */
+       side->ui->feature_color = request_color(side, g_feature_color());
+#endif
+       side->ui->frontline_color = request_color(side, g_frontline_color());
+       side->ui->meridian_color = request_color(side, g_meridian_color());
+       side->ui->shoreline_color = request_color(side, g_shoreline_color());
+       side->ui->unit_name_color = request_color(side, g_unit_name_color());
+       side->ui->goodcolor = request_color(side, "green");
+       side->ui->badcolor = request_color(side, "red");
+    }
+}
+
+/* Collect all the names of types etc for which no images could be found,
+   report them all at once. */
+
+static void
+report_missing_images(Side *side)
+{
+  int u, t, e;
+  Side *side2;
+
+  for_all_terrain_types(t) {
+    if (side->ui->timages[t] == NULL
+       || side->ui->timages[t]->ersatz)
+      record_missing_image(TTYP, t_type_name(t));
+  }
+  for_all_unit_types(u) {
+    if (uimages[u] == NULL
+       || uimages[u]->ersatz)
+      record_missing_image(UTYP, u_type_name(u));
+  }
+  for_all_sides(side2) {
+    e = side_number(side2);
+    if (side->ui->eimages[e] == NULL
+       || side->ui->eimages[e]->ersatz)
+      record_missing_image(3, side_desig(side));
+  }
+  if (missing_images(tmpbuf)) {
+    init_warning("Could not find %s", tmpbuf);
+  }
+}
+
+/* A predicate that tests whether our display can safely be written to. */
+
+int
+active_display(Side *side)
+{
+    return (side && side->ui && side->ui->active);
+}
+
+/* Set up all the GCs. */
+
+static void
+init_gcs(Side *side)
+{
+    unsigned long mask;
+    XGCValues values;
+    GC gc;
+    Display *dpy = side->ui->dpy;
+    Window rootwin = side->ui->rootwin;
+
+    gc = DefaultGCOfScreen(DefaultScreenOfDisplay(dpy));
+
+    side->ui->gc = XCreateGC(dpy, rootwin, 0L, NULL);
+    side->ui->textgc = XCreateGC(dpy, rootwin, 0L, NULL);
+    side->ui->ltextgc = XCreateGC(dpy, rootwin, 0L, NULL);
+    side->ui->terrgc = XCreateGC(dpy, rootwin, 0L, NULL);
+    side->ui->unitgc = XCreateGC(dpy, rootwin, 0L, NULL);
+    side->ui->emblgc = XCreateGC(dpy, rootwin, 0L, NULL);
+    side->ui->bdrygc = XCreateGC(dpy, rootwin, 0L, NULL);
+
+    /* Set the fonts associated with each GC. */
+    XSetFont(dpy, side->ui->gc, side->ui->textfont->fid);
+    XSetFont(dpy, side->ui->textgc, side->ui->textfont->fid);
+    XSetFont(dpy, side->ui->ltextgc, side->ui->textfont->fid);
+    if (side->ui->unitfont != NULL)
+      XSetFont(dpy, side->ui->unitgc, side->ui->unitfont->fid);
+    /* Set misc properties of each GC. */
+    mask = GCFillStyle | GCGraphicsExposures;
+    values.fill_style = FillSolid;
+    values.graphics_exposures = FALSE;
+    XChangeGC(dpy, side->ui->terrgc, mask, &values);
+    XChangeGC(dpy, side->ui->unitgc, mask, &values);
+    XChangeGC(dpy, side->ui->emblgc, mask, &values);
+    XChangeGC(dpy, side->ui->bdrygc, mask, &values);
+
+    DGprintf("GCs stored ...\n");
+}
+
+/* Set up all the fonts. */
+
+static void
+init_fonts(Side *side)
+{
+    int p, u;
+    XFontStruct *font;
+
+    side->ui->textfont =
+      open_font(side, TEXTFONT, "TextFont", NULL, "", NULL);
+    side->ui->fw = font_width(side->ui->textfont);
+    side->ui->fh = font_height(side->ui->textfont);
+    font =
+      open_font(side, "*-bold-r-*-10-*", "LegendFont",
+               side->ui->textfont, "text", NULL);
+    for (p = 0; p < NUMPOWERS; ++p) {
+       for_all_unit_types(u) {
+           side->ui->ulegendfonts[p][u] = font;
+       }
+    }
+    side->ui->flegendfonts[0] =
+      open_font(side, "-*-helvetica-medium-r-*-*-8-*-*-*-*-*-*-*",
+               "LegendFont0", side->ui->textfont, "text",
+               &side->ui->flegendfids[0]);
+    side->ui->flegendfonts[1] =
+      open_font(side, "-*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*",
+               "LegendFont1", side->ui->textfont, "text",
+               &side->ui->flegendfids[1]);
+    side->ui->flegendfonts[2] =
+      open_font(side, "-*-helvetica-medium-r-*-*-14-*-*-*-*-*-*-*",
+               "LegendFont2", side->ui->textfont, "text",
+               &side->ui->flegendfids[2]);
+    side->ui->flegendfonts[3] =
+      open_font(side, "-*-helvetica-medium-r-*-*-18-*-*-*-*-*-*-*",
+               "LegendFont3", side->ui->textfont, "text",
+               &side->ui->flegendfids[3]);
+    side->ui->flegendfonts[4] =
+      open_font(side, "-*-helvetica-medium-r-*-*-24-*-*-*-*-*-*-*",
+               "LegendFont4", side->ui->textfont, "text",
+               &side->ui->flegendfids[4]);
+    DGprintf("Fonts opened ...\n");
+}
+
+/* Get a color set up and warn if not getting what was asked for.  We can */
+/* tolerate being off somewhat.  (Note X rgb value range is 0-65535.) */
+
+#define CLOSE_ENOUGH(X,Y) (ABS(((int) X) - ((int) Y)) < 4000)
+
+long
+request_color(Side *side, char *name)
+{
+    XColor c, avail;
+
+    DGprintf("Requesting color %s\n", (name ? name : "<null>"));
+    /* This might be called to get user-specified colors, even on a mono
+       display, so deal with it. */
+    if (empty_string(name)) {
+       init_warning(
+          "Requesting anonymous color on display \"%s\", substituting white",
+                    side->player->displayname);
+       return WhitePixel(side->ui->dpy, side->ui->screen);
+    } else if (side->ui->monochrome) {
+       if (strcmp("white", name) == 0) {
+           return WhitePixel(side->ui->dpy, side->ui->screen);
+       } else if (strcmp("black", name) == 0) {
+           return BlackPixel(side->ui->dpy, side->ui->screen);
+       } else {
+           init_warning(
+              "No color \"%s\" on the mono display \"%s\", substituting white",
+                        name, side->player->displayname);
+           return WhitePixel(side->ui->dpy, side->ui->screen);
+       }
+    } else {
+       XAllocNamedColor(side->ui->dpy,
+                        DefaultColormap(side->ui->dpy, side->ui->screen),
+                        name, &avail, &c);
+       if (!(CLOSE_ENOUGH(c.red, avail.red)
+             && CLOSE_ENOUGH(c.green, avail.green)
+             && CLOSE_ENOUGH(c.blue, avail.blue))) {
+           init_warning("%s color is way off on display \"%s\"!",
+                        name, side->player->displayname);
+           init_warning("(%d %d %d instead of %d %d %d), but using it anyway",
+                        avail.red, avail.green, avail.blue,
+                        c.red, c.green, c.blue);
+       }
+       return avail.pixel;
+    }
+}
+
+static void
+init_bitmaps(Side *side)
+{
+    int i;
+    Display *dpy = side->ui->dpy;
+    Window win = side->ui->rootwin;
+
+    /* Get the solid hex outlines. */
+    side->ui->hexpics[4] =
+      XCreateBitmapFromData(dpy, win, hex16_bits, hex16_width, hex16_height);
+    side->ui->bhexpics[4] =
+      XCreateBitmapFromData(dpy, win, hex16b_bits, hex16b_width, hex16b_height);
+    side->ui->hexpics[5] =
+      XCreateBitmapFromData(dpy, win, hex32_bits, hex32_width, hex32_height);
+    side->ui->bhexpics[5] =
+      XCreateBitmapFromData(dpy, win, hex32b_bits, hex32b_width, hex32b_height);
+    /* (should use for larger images? polygons have poor borders) */
+
+    /* Get pictures of mushroom clouds. */
+    side->ui->bombpics[0] =
+      XCreateBitmapFromData(dpy, win, bomb1_bits, bomb1_width, bomb1_height);
+    side->ui->bombpics[1] =
+      XCreateBitmapFromData(dpy, win, bomb2_bits, bomb2_width, bomb2_height);
+    side->ui->bombpics[2] =
+      XCreateBitmapFromData(dpy, win, bomb3_bits, bomb3_width, bomb3_height);
+    side->ui->bombpics[3] =
+      XCreateBitmapFromData(dpy, win, bomb4_bits, bomb4_width, bomb4_height);
+    side->ui->hitpics[0] =
+      XCreateBitmapFromData(dpy, win, miss_bits, miss_width, miss_height);
+    side->ui->hitpics[1] =
+      XCreateBitmapFromData(dpy, win, hit_bits, hit_width, hit_height);
+    side->ui->hitpics[2] =
+      XCreateBitmapFromData(dpy, win, kill_bits, kill_width, kill_height);
+
+    side->ui->grays[gray] =
+      XCreateBitmapFromData(dpy, win, gray_bits, gray_width, gray_height);
+    side->ui->grays[darkgray] =
+      XCreateBitmapFromData(dpy, win, (const char*)darkgray_bits, darkgray_width, darkgray_height);
+    side->ui->dots =
+      XCreateBitmapFromData(dpy, win, dots_bits, dots_width, dots_height);
+
+    /* Collect pictures that will be used with map controls. */
+    for (i = 0; i < numcontrols; ++i)
+      side->ui->controlpics[i] = None;
+    side->ui->controlpics[LOOK] =
+      XCreateBitmapFromData(dpy, win, lookglass_bits, 16, 16);
+    side->ui->controlpics[MOVE] =
+      XCreateBitmapFromData(dpy, win, shootcursor_bits, 16, 16);
+    side->ui->controlpics[UNIT_MOVE] =
+      XCreateBitmapFromData(dpy, win, movecursor_bits, 16, 16);
+    side->ui->controlpics[UNIT_SHOOT] =
+      XCreateBitmapFromData(dpy, win, shootcursor_bits, 16, 16);
+    side->ui->controlpics[UNIT_BUILD] =
+      XCreateBitmapFromData(dpy, win, buildcursor_bits, 16, 16);
+    side->ui->controlpics[ZOOM_OUT] =
+      XCreateBitmapFromData(dpy, win, farther_bits, 16, 16);
+    side->ui->controlpics[ZOOM_IN] =
+      XCreateBitmapFromData(dpy, win, closer_bits, 16, 16);
+    DGprintf("Bitmaps stored ...\n");
+}
+
+/* Make all the different kinds of cursors we intend to use.  Should be
+   one for each kind of mode or tool.  Cursors should always be 16x16. */
+
+static void
+init_cursors(Side *side)
+{
+    int i;
+    Display *dpy = side->ui->dpy;
+    Window win = side->ui->rootwin;
+    int fg = side->ui->fgcolor, bg = side->ui->bgcolor;
+
+    for (i = 0; i < numtools; ++i)
+      side->ui->toolcursors[i] = None;
+    side->ui->toolcursors[looktool] =
+      make_cursor(dpy, win, lookglass_bits, lookmask_bits,
+                 fg, bg, lookglass_x_hot, lookglass_y_hot);
+    side->ui->toolcursors[movetool] =
+      make_cursor(dpy, win, shootcursor_bits, shootmask_bits,
+                 fg, bg, shootcursor_x_hot, shootcursor_y_hot);
+    side->ui->toolcursors[unitmovetool] =
+      make_cursor(dpy, win, movecursor_bits, movemask_bits,
+                 fg, bg, movecursor_x_hot, movecursor_y_hot);
+    side->ui->toolcursors[unitshoottool] =
+      make_cursor(dpy, win, shootcursor_bits, shootmask_bits,
+                 fg, bg, shootcursor_x_hot, shootcursor_y_hot);
+    side->ui->toolcursors[unitbuildtool] =
+      make_cursor(dpy, win, buildcursor_bits, buildmask_bits,
+                 fg, bg, buildcursor_x_hot, buildcursor_y_hot);
+#ifdef DESIGNERS
+    side->ui->toolcursors[cellpainttool] =
+      make_cursor(dpy, win, hexcursor_bits, (char*)hexcursormask_bits,
+                 fg, bg, hexcursor_x_hot, hexcursor_y_hot);
+    side->ui->toolcursors[bordpainttool] =
+      make_cursor(dpy, win, bordcursor_bits, bordcursor_bits, /* should have separate mask */
+                 fg, bg, bordcursor_x_hot, bordcursor_y_hot);
+    side->ui->toolcursors[connpainttool] =
+      make_cursor(dpy, win, conncursor_bits, conncursor_bits, /* should have separate mask */
+                 fg, bg, conncursor_x_hot, conncursor_y_hot);
+    side->ui->toolcursors[unitaddtool] =
+      make_cursor(dpy, win, addunits_bits, addunits_bits,
+                 fg, bg, addunits_x_hot, addunits_y_hot);
+    side->ui->toolcursors[peoplepainttool] =
+      make_cursor(dpy, win, people_bits, people_bits,
+                 fg, bg, people_x_hot, people_y_hot);
+    side->ui->toolcursors[featurepainttool] =
+      make_cursor(dpy, win, feature_bits, (char *)featuremask_bits,
+                 fg, bg, feature_x_hot, feature_y_hot);
+#endif /* DESIGNERS */
+    DGprintf("Cursors stored ...\n");
+}
+
+/* Since XCreatePixmapCursor() takes XColors and not pixel values we
+   have to look up the colors associated with the foreground and
+   background pixel values in the color table and pass them to
+   XCreatePixmapCursor(). */
+   
+Cursor
+make_cursor(Display *dpy, Window win, char *cursbits, char *maskbits, unsigned long fg, unsigned long bg, unsigned int x, unsigned int y)
+{
+    Pixmap curs, mask;
+    XColor fgcolor, bgcolor;
+    Cursor rslt;
+
+    mask = XCreateBitmapFromData(dpy, win, maskbits, 16, 16);
+    curs = XCreateBitmapFromData(dpy, win, cursbits, 16, 16);
+    fgcolor.pixel = fg;
+    XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &fgcolor);
+    bgcolor.pixel = bg;
+    XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &bgcolor);
+    rslt = XCreatePixmapCursor(dpy, curs, mask, &fgcolor, &bgcolor, x, y);
+    XFreePixmap(dpy, mask);
+    XFreePixmap(dpy, curs);
+    return rslt;
+}
+
+/* Open a font, possibly substituting another font if our desired one is
+   missing for some reason. */
+
+XFontStruct *
+open_font(Side *side, char *name, char *xdefault, XFontStruct *altfont, char *alttype, Font *fid)
+{
+    XFontStruct *font;
+
+    if (fid) {
+       *fid = XLoadFont(side->ui->dpy, name);
+       font = XQueryFont(side->ui->dpy, *fid);
+    } else {
+       font = XLoadQueryFont(side->ui->dpy, name);
+    }
+    if (font == NULL) {
+       init_warning("Can't open font \"%s\" on \"%s\"",
+                    name, side->player->displayname);
+       if (altfont != NULL) {
+           init_warning("Substituting the %s font, hope it works!", alttype);
+           return altfont;
+       } else {
+           return NULL;
+       }
+    }
+    DGprintf("Opened font \"%s\" ...\n", name);
+    return font;
+}
+
+/* Get a total bounding box on the font. */
+
+int
+font_width(XFontStruct *font)
+{
+    return font->max_bounds.width;
+}
+
+int
+font_height(XFontStruct *font)
+{
+    return font->max_bounds.ascent + font->max_bounds.descent;
+}
+
+/* Collect images for all the terrain types. */
+
+static void
+init_terrain_images(Side *side)
+{
+    int t, p;
+    ImageFamily *imf;
+    Image *img, *timg;
+    X11Image *ximg;
+
+    side->ui->timages =
+      (ImageFamily **) xmalloc(numttypes * sizeof(ImageFamily *));
+    for_all_terrain_types(t) {
+       imf = get_terrain_type_images(side, t);
+       if (DebugG)
+         describe_imf(side, "terrain type", t_type_name(t), imf);
+       side->ui->timages[t] = imf;
+       /* Precalculate which images to use at which magnifications. */
+       for (p = 0; p < NUMPOWERS; ++p) {
+           timg = best_image(side->ui->timages[t], hws[p], hhs[p]);
+           if (timg != NULL) {
+               ximg = (X11Image *) timg->hook;
+               if (ximg != NULL) {
+                   if (!side->ui->monochrome
+                       /* if somebody changes their mind about using
+                           the color images, this will lose */
+                       && side->ui->dflt_color_terr_images
+                       && ximg->colr != None)
+                     side->ui->terrpics[p][t] = ximg->colr;
+                   else
+                     side->ui->terrpics[p][t] = ximg->mono;
+               }
+           }
+       }
+       /* Look for a solid color. */
+       timg = NULL;
+       for_all_images(side->ui->timages[t], img) {
+           if (img->w == 1 && img->h == 1) {
+               timg = img;
+               break;
+           }
+       }
+       if (timg != NULL && timg->w == 1 && timg->h == 1) {
+           if (timg->hook) {
+               ximg = (X11Image *) timg->hook;
+               /* Save the color if found. */
+               if (ximg->colpix) 
+                 side->ui->cellcolor[t] = ximg->colpix[0];
+           }
+       }
+    }
+}
+
+/* Set up a side's view of everybody else's colors and emblems. */
+
+static void
+init_emblem_images(Side *side)
+{
+    Side *side2;
+    
+    side->ui->eimages =
+      (ImageFamily **) xmalloc((g_sides_max() + 1) * sizeof(ImageFamily *));
+    side->ui->eimages_loaded =
+      (short *) xmalloc((g_sides_max() + 1) * sizeof(short));
+    /* Independent units may have a distinguishing emblem, so the
+       indepside is included here. */
+    for_all_sides(side2) {
+       init_emblem(side, side2);
+    }
+}
+
+/* Compute the distinctive emblem by which one side will recognize units
+   of another side.  This does both our view of ourselves and others
+   orthogonally.  Note that sides without displays can still have emblems
+   and colors that the sides with displays will see, but that sides
+   without displays don't need to do any emblem init. */
+
+void
+init_emblem(Side *side, Side *side2)
+{
+    char cbuf[BUFSIZ], *s, *c;
+    int s2 = side_number(side2), i;
+    ImageFamily *imf;
+
+    /* Collect the color names of the other side and try to request
+       them for our own display. */
+    if (!side->ui->monochrome && !empty_string(side2->colorscheme)) {
+       /* take spec apart and iterate for multiple colors */
+        /* (should be generic code) */
+       for (s = side2->colorscheme, c = cbuf, i = 0; i < 3; ++s) {
+           if (*s == ',' || *s == '\0') {
+               *c = '\0';
+               c = cbuf;
+               side->ui->colors[s2][i++] = request_color(side, cbuf);
+           } else {
+               *c++ = *s;
+           }
+           if (*s == '\0')
+             break;
+       }
+       side->ui->numcolors[s2] = i;
+    } else {
+       side->ui->numcolors[s2] = 0;
+    }
+    tmp_display = side->ui->dpy;
+    tmp_root_window = side->ui->rootwin;
+    tmp_valid = TRUE;
+    imf = get_emblem_images(side, side2);
+    tmp_valid = FALSE;
+    if (DebugG)
+      describe_imf(side, "emblem", side_desig(side2), imf);
+    side->ui->eimages[s2] = imf;
+    side->ui->eimages_loaded[s2] = TRUE;
+}
+
+/* Describe (for debugging) X11-specific parts of an image. */
+
+static void
+x11_describe_image(Side *side, Image *img)
+{
+    X11Image *ximg;
+
+    ximg = (X11Image *) img->hook;
+    if (ximg)
+      DGprintf(" (x11 mono %d color %d mask %d)",
+              ximg->mono, ximg->colr, ximg->mask);
+}
+
+/* Pop up a dialog listing all the standard games in the library, plus
+   a bit of description of each one. */
+
+void 
+popup_game_dialog ()
+{
+    int i;
+    Widget outform, label, quit, viewp, inform;
+    Module *module;
+    
+    collect_possible_games();
+    games = (Gamew *) xmalloc(numgames * sizeof(Gamew));
+    
+    gameShell =
+      XtVaCreatePopupShell("gameDialog", topLevelShellWidgetClass, thistoplevel,
+                          NULL);
+    outform =
+      XtVaCreateManagedWidget("outForm", formWidgetClass, gameShell,
+                             NULL);
+    label =
+      XtVaCreateManagedWidget("label", labelWidgetClass, outform,
+                             XtNtop,    XawChainTop, 
+                             XtNbottom, XawChainTop, 
+                             XtNleft,   XawChainLeft, 
+                             XtNright,  XawChainLeft,
+                             NULL);
+    quit =
+      XtVaCreateManagedWidget("quit", commandWidgetClass, outform,
+                             XtNfromHoriz, label,
+                             XtNtop,    XawChainTop, 
+                             XtNbottom, XawChainTop, 
+                             XtNleft,   XawChainLeft, 
+                             XtNright,  XawChainLeft,
+                             NULL);
+    XtAddCallback (quit, XtNcallback, quit_dialog, NULL);
+
+    viewp =
+      XtVaCreateManagedWidget("viewport", viewportWidgetClass,  outform,
+                             XtNfromVert,  label,
+                             XtNallowVert, True,
+                             XtNtop,    XawChainTop, 
+                             XtNbottom, XawChainBottom, 
+                             XtNleft,   XawChainLeft, 
+                             XtNright,  XawChainRight,
+                             NULL);
+    inform =
+      XtVaCreateManagedWidget("inForm", formWidgetClass, viewp,
+                             NULL);
+    
+    for (i = 0; i < numgames; ++i) {
+       module = possible_games[i];
+       games[i].form =
+         XtVaCreateManagedWidget(module->name, formWidgetClass, inform, 
+                                 XtNfromVert, i ? games[i-1].form : NULL,
+                                 XtNtop,    XawChainTop, 
+                                 XtNbottom, XawChainTop, 
+                                 XtNleft,   XawChainLeft, 
+                                 XtNright,  XawChainLeft,
+                                 NULL);
+       games[i].name =
+         XtVaCreateManagedWidget("name", commandWidgetClass, games[i].form,
+                                 XtNlabel, module->name,
+                                 XtNtop,    XawChainTop, 
+                                 XtNbottom, XawChainTop, 
+                                 XtNleft,   XawChainLeft, 
+                                 XtNright,  XawChainLeft,
+                                 NULL);
+       XtAddCallback (games[i].name, XtNcallback, game_callback, NULL);
+       if (!empty_string(module->title)) {
+           games[i].title =
+             XtVaCreateManagedWidget("title", labelWidgetClass, games[i].form,
+                                     XtNlabel, module->title,
+                                     XtNfromHoriz, games[i].name,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainTop, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+       } else {
+           games[i].title = NULL;
+       }
+       if (module->blurb != lispnil) {
+           char blurb[BLURBSIZE];
+       
+           append_blurb_strings(blurb, module->blurb);
+           games[i].blurb =
+             XtVaCreateManagedWidget("blurb", labelWidgetClass, games[i].form,
+                                     XtNlabel, blurb,
+                                     XtNfromHoriz,
+                                     games[i].title ? games[i].title : games[i].name,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainTop, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+       } else {
+           games[i].blurb = NULL;
+       }
+       games[i].pop = NULL;
+    }
+    
+    XtPopup(gameShell, XtGrabNone);
+    
+    /* replacement for XtAppMainLoop(thisapp): */
+    loop = 1;
+    while (loop) {
+       XEvent event;
+
+       XtAppNextEvent(thisapp, &event);
+       XtDispatchEvent(&event);
+    }
+}
+
+static void
+popup_game(int g, int flag)
+{
+    char *vartypename = NULL;
+    GamePop *pop = games[g].pop;
+    Module *module = possible_games[g];
+    Widget up, left, save;
+    Variant *var;
+    Varw *varw;
+    int i;
+    Side *side;
+    Player *player;
+    static char *player_type[] = { "none", "human", "machine" };
+    Widget pane;
+
+    if (!pop || flag) {
+       if (!pop) {
+           games[g].pop = pop = (GamePop *) xmalloc(sizeof(GamePop));
+           pop->variants = NULL;
+       }
+       sprintf(buf1, "xconq game: %s", module->name);
+       pop->shell =
+         XtVaCreatePopupShell(module->name, topLevelShellWidgetClass,
+                              thistoplevel, 
+                              XtNtitle, buf1,
+                              NULL);
+       pop->form =
+         XtVaCreateManagedWidget("gameForm", formWidgetClass, pop->shell,
+                                 NULL);
+       up = left = pop->name =
+         XtVaCreateManagedWidget("name", labelWidgetClass, pop->form,
+                                 XtNlabel, module->name,
+                                 XtNtop,    XawChainTop, 
+                                 XtNbottom, XawChainTop, 
+                                 XtNleft,   XawChainLeft, 
+                                 XtNright,  XawChainLeft,
+                                 NULL);
+       if (module->basemodulename && module->basemodulename[0]) {
+           sprintf(buf1, "base module: %s", module->basemodulename);
+       } else {
+           strcpy(buf1, "no base module");
+       }
+       left = pop->basemodule =
+         XtVaCreateManagedWidget("basemodule", labelWidgetClass, pop->form,
+                                 XtNlabel, buf1,
+                                 XtNfromHoriz, left,
+                                 XtNtop,    XawChainTop, 
+                                 XtNbottom, XawChainTop, 
+                                 XtNleft,   XawChainLeft, 
+                                 XtNright,  XawChainLeft,
+                                 NULL);
+       if (module->version && module->version[0]) {
+           sprintf(buf1, "version: %s", module->version);
+           left = pop->version =
+             XtVaCreateManagedWidget("version", labelWidgetClass, pop->form,
+                                     XtNlabel, module->version,
+                                     XtNfromHoriz, left,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainTop, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+       }
+       if (module->title && module->title[0]) {
+           up = pop->title =
+             XtVaCreateManagedWidget("title", labelWidgetClass, pop->form,
+                                     XtNlabel, module->title,
+                                     XtNfromVert, pop->name,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainTop, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+       }
+       if (module->blurb != lispnil) {
+           char blurb[BLURBSIZE];
+           
+           append_blurb_strings(blurb, module->blurb);
+           up = pop->blurb =
+             XtVaCreateManagedWidget("blurb", labelWidgetClass, pop->form,
+                                     XtNlabel, blurb,
+                                     XtNfromHoriz, pop->title,
+                                     XtNfromVert, pop->name,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainTop, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+       }
+
+       if (module->variants) {
+           for (i = 0; module->variants[i].id != lispnil; ++i) { }
+           pop->numvariants = i;
+       } else {
+           pop->numvariants = 0;
+       }
+       if (flag && pop->numvariants) {
+           if (flag == 1) {
+               pop->variants =
+                 (Varw *) xmalloc(pop->numvariants*sizeof(Varw));
+           }
+           up =
+             XtVaCreateManagedWidget("variant", labelWidgetClass, pop->form,
+                                     XtNlabel, "Variants:",
+                                     XtNfromVert, up,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainTop, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+
+           for (i = 0; i < pop->numvariants; ++i) {
+               var = &(module->variants[i]);
+               varw = &(pop->variants[i]);
+               vartypename = c_string(var->id);
+
+               if (flag == 1)
+                 varw->value = variant_default(var); 
+               sprintf(buf1, "variant%d", i);
+               up = varw->dialog =
+                 XtVaCreateManagedWidget(buf1, dialogWidgetClass, pop->form,
+                                         XtNlabel, variant_name(var),
+                                         XtNvalue, varw->value,
+                                         XtNfromVert, up,
+                                         XtNtop,    XawChainTop, 
+                                         XtNbottom, XawChainTop, 
+                                         XtNleft,   XawChainLeft, 
+                                         XtNright,  XawChainLeft,
+                                         NULL);
+               horizontalDialog(varw->dialog);
+               if (varw->mess && varw->mess[0]) {
+                   reverseVideoDialog(varw->dialog);
+                   up =
+                     XtVaCreateManagedWidget("varMessage", labelWidgetClass,
+                                             pop->form,
+                                             XtNlabel, varw->mess,
+                                             XtNfromVert, up,
+                                             XtNtop,    XawChainTop, 
+                                             XtNbottom, XawChainTop, 
+                                             XtNleft,   XawChainLeft, 
+                                             XtNright,  XawChainLeft,
+                                             NULL);
+               }
+           }
+       }
+
+       if (module->instructions != lispnil ||
+           module->notes != lispnil) {
+           up = pane =
+             XtVaCreateManagedWidget("pane", panedWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNorientation, XtorientVertical,
+                                     XtNtop,    XawChainTop, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainRight,
+                                     NULL);
+           pop->instructions =
+             createTextWidget("instructions", pane,
+                              NULL, module->instructions);
+           pop->notes =
+             createTextWidget("notes", pane,
+                              pop->instructions, module->notes);
+           
+       }
+       if (flag) {
+           up = XtVaCreateManagedWidget("assign", labelWidgetClass, pop->form,
+                                        XtNlabel, "Assignments:",
+                                        XtNfromVert, up,
+                                        XtNtop,    XawChainBottom, 
+                                        XtNbottom, XawChainBottom, 
+                                        XtNleft,   XawChainLeft, 
+                                        XtNright,  XawChainLeft,
+                                        NULL);
+           if (flag == 1) {
+               pop->assign = (Assignw *) xmalloc((MAXSIDES + 1) * sizeof(Assignw));
+           }
+           for (i = 1; i <= numsides; ++i) {
+               side   = assignments[i].side;
+               player = assignments[i].player;
+               if (flag == 1) { 
+                   init_assignw_player(&(pop->assign[i]), player);
+               }
+               if (side->sideclass && side->sideclass[0]) {
+                   sprintf(buf1, "%s (%s)", short_side_title(side),
+                           side->sideclass);
+               } else {
+                   strcpy(buf1, short_side_title(side));
+               }
+               save = left = pop->assign[i].sidew =
+                 XtVaCreateManagedWidget("side", labelWidgetClass, pop->form,
+                                         XtNlabel, buf1,
+                                         XtNfromVert, up,
+                                         XtNtop,    XawChainBottom, 
+                                         XtNbottom, XawChainBottom, 
+                                         XtNleft,   XawChainLeft, 
+                                         XtNright,  XawChainLeft,
+                                         NULL);
+               left = pop->assign[i].pname =
+                 XtVaCreateManagedWidget("pname", dialogWidgetClass,
+                                         pop->form,
+                                         XtNlabel, "name",
+                                         XtNvalue, pop->assign[i].vname,
+                                         XtNfromHoriz, left,
+                                         XtNfromVert, up,
+                                         XtNtop,    XawChainBottom, 
+                                         XtNbottom, XawChainBottom, 
+                                         XtNleft,   XawChainLeft, 
+                                         XtNright,  XawChainLeft,
+                                         NULL);
+               horizontalDialog(pop->assign[i].pname);
+               up = pop->assign[i].pid =
+                 XtVaCreateManagedWidget("pid", dialogWidgetClass, pop->form,
+                                         XtNlabel, player_type[pop->assign[i].vflag],
+                                         XtNvalue, pop->assign[i].vid,
+                                         XtNfromHoriz, left,
+                                         XtNfromVert, up,
+                                         XtNtop,    XawChainBottom, 
+                                         XtNbottom, XawChainBottom, 
+                                         XtNleft,   XawChainLeft, 
+                                         XtNright,  XawChainLeft,
+                                         NULL);
+               horizontalDialog(pop->assign[i].pid);
+               if (pop->assign[i].messname && pop->assign[i].messname[0]) {
+                   reverseVideoDialog(pop->assign[i].pname);
+                   up = XtVaCreateManagedWidget("nameMessage",
+                                                labelWidgetClass, pop->form,
+                                                XtNlabel, pop->assign[i].messname,
+                                                XtNfromHoriz, save,
+                                                XtNfromVert, up,
+                                                XtNtop,    XawChainBottom, 
+                                                XtNbottom, XawChainBottom, 
+                                                XtNleft,   XawChainLeft, 
+                                                XtNright,  XawChainLeft,
+                                                NULL);
+               }
+               if (pop->assign[i].messid && pop->assign[i].messid[0]) {
+                   reverseVideoDialog(pop->assign[i].pid);
+                   up = XtVaCreateManagedWidget("idMessage",
+                                                labelWidgetClass, pop->form,
+                                                XtNlabel, pop->assign[i].messid,
+                                                XtNfromHoriz, save,
+                                                XtNfromVert, up,
+                                                XtNtop,    XawChainBottom, 
+                                                XtNbottom, XawChainBottom, 
+                                                XtNleft,   XawChainLeft, 
+                                                XtNright,  XawChainLeft,
+                                                NULL);
+               }
+           }
+           left = pop->add =
+             XtVaCreateManagedWidget("add", commandWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNtop,    XawChainBottom, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+           XtAddCallback (pop->add, XtNcallback, add_player_dialog, NULL);
+           left = pop->verify =
+             XtVaCreateManagedWidget("verify", commandWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNfromHoriz, left,
+                                     XtNtop,    XawChainBottom, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+           XtAddCallback (pop->verify, XtNcallback, verify_dialog, NULL);
+           left = pop->ok =
+             XtVaCreateManagedWidget("go", commandWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNfromHoriz, left,
+                                     XtNtop,    XawChainBottom, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+           XtAddCallback (pop->ok, XtNcallback, go_dialog, NULL);
+           pop->cancel =
+             XtVaCreateManagedWidget("quit", commandWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNfromHoriz, left,
+                                     XtNtop,    XawChainBottom, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+           XtAddCallback (pop->cancel, XtNcallback, quit_dialog, NULL);
+       } else {
+           left = pop->ok =
+             XtVaCreateManagedWidget("ok", commandWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNtop,    XawChainBottom, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+           XtAddCallback (pop->ok, XtNcallback, ok_dialog, NULL);
+           pop->cancel =
+             XtVaCreateManagedWidget("cancel", commandWidgetClass, pop->form,
+                                     XtNfromVert, up,
+                                     XtNfromHoriz, left,
+                                     XtNtop,    XawChainBottom, 
+                                     XtNbottom, XawChainBottom, 
+                                     XtNleft,   XawChainLeft, 
+                                     XtNright,  XawChainLeft,
+                                     NULL);
+           XtAddCallback (pop->cancel, XtNcallback, cancel_dialog, NULL);
+       }
+    }
+    XtPopup (pop->shell, XtGrabNone);
+    raise_widget(pop->shell);
+}
+
+static Widget
+createTextWidget(char *name, Widget parent, Widget up, Obj *obj)
+{
+    Widget w, form;
+
+    if (obj == lispnil)
+      return NULL;
+
+    form =
+      XtVaCreateManagedWidget("form", formWidgetClass, parent,
+                             NULL);
+
+    sprintf(buf1, "%s_label", name);
+    w =
+      XtVaCreateManagedWidget(buf1, labelWidgetClass, form,
+                             XtNlabel, name,
+                             XtNtop,    XawChainTop, 
+                             XtNbottom, XawChainTop, 
+                             XtNleft,   XawChainLeft, 
+                             XtNright,  XawChainLeft,
+                             NULL);
+    w =
+      XtVaCreateManagedWidget(name, asciiTextWidgetClass, form,
+                             XtNfromVert, w,
+                             XtNvertDistance, -1,
+                             XtNdisplayCaret, False,
+                             XtNtop,    XawChainTop, 
+                             XtNbottom, XawChainBottom, 
+                             XtNleft,   XawChainLeft, 
+                             XtNright,  XawChainRight,
+                             NULL);
+    splat_obj_in_textw(w, obj);
+    return w;
+}
+
+static void
+splat_obj_in_textw(Widget w, Obj *obj)
+{
+    Obj *rest;
+
+    if (!obj || obj == lispnil)
+      return;
+
+    if (stringp(obj)) {
+       textw_printf(w, "%s\n", c_string(obj));
+       return;
+    }
+
+    if (!consp(obj))
+      return;
+
+    for (rest = obj; rest != lispnil; rest = cdr(rest)) {
+       if (stringp(car(rest))) {
+           textw_printf(w, "%s\n", c_string(car(rest)));
+       }
+    }
+}
+
+static void
+quit_dialog (Widget w, XtPointer client_data, XtPointer call_data)
+{
+    exit(0);
+}
+
+
+static void
+game_callback (Widget w, XtPointer client_data, XtPointer call_data)
+{
+    int i;
+
+    for (i = 0; i < numgames; ++i) {
+       if (w == games[i].name) {
+           popup_game(i, 0);
+           return;
+       }
+    }
+}
+
+static void
+cancel_dialog (Widget w, XtPointer client_data, XtPointer call_data)
+{
+    int i;
+    Widget form = XtParent(w);
+
+    for (i = 0; i < numgames; ++i) {
+       if (games[i].pop && form == games[i].pop->form) {
+           XtPopdown(games[i].pop->shell);
+       }
+    }
+}
+
+static void
+ok_dialog (Widget w, XtPointer client_data, XtPointer call_data)
+{
+    int i;
+    Widget form = XtParent(w);
+
+    for (i = 0; i < numgames; ++i) {
+       if (games[i].pop && form == games[i].pop->form) {
+           break;
+       }
+    }
+    chosen_game = i;
+  
+    /* clean up */
+    for (i = 0; i < numgames; ++i) {
+       if (games[i].pop) {
+           XtPopdown(games[i].pop->shell);
+           XtDestroyWidget(games[i].pop->shell);
+           if (i != chosen_game) {
+               if (games[i].pop->variants)
+                 free(games[i].pop->variants);
+               free(games[i].pop);
+               games[i].pop = NULL;
+           }
+       }
+    }
+    XtPopdown(gameShell);
+    XtDestroyWidget(gameShell);
+
+    /* initialize game and sides */
+    mainmodule = possible_games[chosen_game];
+    load_game_module(mainmodule, TRUE);
+    check_game_validity();
+    make_trial_assignments();
+
+    popup_game(chosen_game, 1);
+}
+
+static void
+go_dialog (Widget w, XtPointer client_data, XtPointer call_data)
+{
+    GamePop *pop = games[chosen_game].pop;
+    char *value, *name;
+    int i, flag;
+
+    if (!valid_gamepop()) {
+       verify_dialog(w, NULL, NULL);
+       XBell(XtDisplay(pop->shell),50);
+       return;
+    }
+
+    variants = lispnil;
+    /* setup variants */
+    for (i = 0; i < pop->numvariants; ++i) {
+       value = XawDialogGetValueString(pop->variants[i].dialog);
+       implement_variant(value, &(mainmodule->variants[i]));
+       if (pop->variants[i].mess)
+         free(pop->variants[i].mess);
+    }
+    /* get side values */
+    for (i = 1; i <= numsides; ++i) {
+       if (pop->assign[i].pname) {
+           name = NULL;
+           value = XawDialogGetValueString(pop->assign[i].pname);
+           if (!empty_string(value))
+             name = copy_string(value);
+           if (assignments[i].player)
+             assignments[i].player->name = name;
+           if (pop->assign[i].messname)
+             free(pop->assign[i].messname);
+       }
+       if (pop->assign[i].pid) {
+           name = NULL;
+           value = XawDialogGetValueString(pop->assign[i].pid);
+           flag = type_player(value);
+           if (!empty_string(value))
+             name = copy_string(value);
+           if (assignments[i].player) {
+               assignments[i].player->displayname =
+                 (ABS(flag) == 1 ? name : NULL);
+               assignments[i].player->aitypename =
+                 (ABS(flag) != 1 ? name : NULL);
+           }
+           if (pop->assign[i].messid)
+             free(pop->assign[i].messid);
+       }
+    }
+
+    XtPopdown(pop->shell);
+    XtDestroyWidget(pop->shell);
+    if (pop->variants)
+      free(pop->variants);
+    if (pop->assign)
+      free(pop->assign);
+    free(pop);
+    free(games);
+    games = NULL;
+
+    do_module_variants(mainmodule, variants);
+    check_game_validity();
+
+    loop = 0;
+}
+
+static int
+valid_gamepop()
+{
+    GamePop *pop = games[chosen_game].pop;
+    char *value;
+    int i, res = 1;
+
+    /* check variants */
+    for (i = 0; i < pop->numvariants; ++i) {
+       value = XawDialogGetValueString(pop->variants[i].dialog);
+       res = res && valid_variant(value, &(mainmodule->variants[i]));
+    }
+    /* check sides */
+    for (i = 1; i <= numsides; ++i) {
+       if (pop->assign[i].pid) {
+           value = XawDialogGetValueString(pop->assign[i].pid);
+           res = res && type_player(value)>0;
+       }
+    }
+
+    return res;
+}
+
+static void
+verify_dialog(Widget w, XtPointer client_data, XtPointer call_data)
+{
+    GamePop *pop = games[chosen_game].pop;
+    char *value;
+    int i, flag = 0; /* init to keep GCC quiet */
+
+    /* save variant values */
+    for (i = 0; i < pop->numvariants; ++i) {
+       value = XawDialogGetValueString(pop->variants[i].dialog);
+       pop->variants[i].value = copy_string(value);
+       if (valid_variant(value, &(mainmodule->variants[i]))) {
+           if (pop->variants[i].mess)  free(pop->variants[i].mess);
+           pop->variants[i].mess = NULL;
+       } else {
+           pop->variants[i].mess = copy_string(errormess);
+       }
+    }
+    /* save side values */
+    for (i = 1; i <= numsides; ++i) {
+       if (pop->assign[i].pname) {
+           value = XawDialogGetValueString(pop->assign[i].pname);
+           pop->assign[i].vname = copy_string(value);
+           pop->assign[i].messname = 0;  /* names always OK? */
+       }
+       if (pop->assign[i].pid) {
+           value = XawDialogGetValueString(pop->assign[i].pid);
+           pop->assign[i].vid = copy_string(value);
+           flag = type_player(value);
+           if (flag > 0) {
+               if (pop->assign[i].messid)
+                 free(pop->assign[i].messid);
+               pop->assign[i].messid = NULL;
+           } else {
+               pop->assign[i].messid = copy_string(errormess);
+           }
+       }
+       pop->assign[i].vflag = ABS(flag);
+    }
+
+    XtPopdown(pop->shell);
+    XtDestroyWidget(pop->shell);
+
+    popup_game(chosen_game, 2);
+}
+
+static char *
+variant_default(Variant *var)
+{
+    int i1, i2, i3, i4, i5, n;
+    char *p;
+
+    switch (keyword_code(c_string(var->id))) {
+      case K_WORLD_SEEN:
+      case K_SEE_ALL:
+      case K_SEQUENTIAL:
+       if (var->dflt == lispnil)  return "true";
+       return (char*)(c_number(eval(var->dflt)) ? " true" : "false");
+      case K_WORLD_SIZE:
+       sprintlisp(buf3, var->dflt, BUFSIZE);
+       for (p = buf3; *p; ++p) {
+           if (!isdigit(*p))
+             *p = ' ';
+       }
+       n = sscanf(buf3, "%d%d%d%d%d", &i1, &i2, &i3, &i4, &i5);
+       sprintf(buf3, "(%d %d %d)",
+               (n>0) ? i1 : DEFAULTWIDTH,
+               (n>1) ? i2 : DEFAULTHEIGHT,
+               (n>2) ? i3 : DEFAULTCIRCUMFERENCE);
+       if (n == 4) {
+           sprintf(buf3, "(%d %d %d %d)", i1, i2, i3, i4);
+       }
+       if (n == 5) {
+           sprintf(buf3, "(%d %d %d %d %d)", i1, i2, i3, i4, i5);
+       }
+       return buf3;
+      default:
+       sprintlisp(buf3, var->dflt, BUFSIZE);
+       return buf3;
+    }
+}
+
+static char *
+variant_name(Variant *var)
+{
+    switch (keyword_code(c_string(var->id))) {
+      case K_WORLD_SEEN:
+       sprintf(buf2, "%s: make the world be seen already", var->name);
+       return buf2;
+      case K_SEE_ALL:
+       sprintf(buf2, "%s: make everything be always seen", var->name);
+       return buf2;
+      case K_SEQUENTIAL:
+       sprintf(buf2, "%s: move sequentially", var->name);
+       return buf2;
+      case K_WORLD_SIZE:
+       sprintf(buf2, 
+       "%s: set world size (width height circumference [longitude [latitude]])",
+           var->name);
+       return buf2;
+      default:
+       return var->name;
+    }
+}
+
+static void
+horizontalDialog(Widget w)
+{
+    Widget label, value;
+
+    label = XtNameToWidget(w, "label");
+    value = XtNameToWidget(w, "value");
+    if (label && value) {
+       XtVaSetValues(value,
+                     XtNfromVert,  NULL,
+                     XtNfromHoriz, label,
+                     NULL);
+    }
+}
+
+static void
+reverseVideoDialog(Widget w)
+{
+    Pixel fg, bg;
+    Widget label = XtNameToWidget(w, "label");
+
+    if (!label)
+      return;
+    XtVaGetValues(label, XtNbackground, &bg, XtNforeground, &fg, NULL);
+    XtVaSetValues(w, XtNbackground, fg, NULL);
+    XtVaSetValues(label, XtNbackground, fg, XtNforeground, bg, NULL);
+}
+
+static int
+boolean_lisp(char *value)
+{
+    char c, *p;
+
+    if (!value || !value[0])
+      return 0;
+
+    for (p = value; *p; ++p) {
+       if (isalnum(*p)){
+           c = tolower(value[0]);
+           return (c != '0' && c != 'n' && c != 'f');
+       }
+    }
+    return FALSE;
+}
+
+static void
+implement_variant(char *value, Variant *var)
+{
+    int key = keyword_code(c_string(var->id)), i1, i2, i3, i4, i5, n;
+    char *p;
+
+    switch (key) {
+      case K_WORLD_SEEN:
+      case K_SEE_ALL:
+      case K_SEQUENTIAL:
+       push_key_int_binding(&variants, key, boolean_lisp(value));
+       break;
+      case K_WORLD_SIZE:
+       for (p=value; *p; p++) {
+           if (!isdigit(*p))  *p = ' ';
+       }
+       n = sscanf(value, "%d%d%d%d%d", &i1, &i2, &i3, &i4, &i5);
+       if (n < 4)
+         i4 = 0;
+       if (n < 5)
+         i5 = 0;
+       push_key_cdr_binding(&variants, key,
+                            cons(new_number(i1),
+                                 cons(new_number(i2),
+                                      cons(new_number(i3),
+                                           cons(new_number(i4),
+                                                cons(new_number(i5),
+                                                     lispnil))))));
+       break;
+
+      default:
+       /* what to do here? */
+       break;
+    }
+}
+
+static int
+valid_variant(char *value, Variant *var)
+{
+    int key = keyword_code(c_string(var->id)), i1, i2, i3, i4, i5, n;
+    char *p;
+
+    errormess[0] = '\0';
+
+    switch (key) {
+      case K_WORLD_SEEN:
+      case K_SEE_ALL:
+      case K_SEQUENTIAL:
+       return (value && value[0]);
+
+      case K_WORLD_SIZE:
+       for (p = value; *p; p++) {
+           if (!isdigit(*p))
+             *p = ' ';
+       }
+       n = sscanf(value, "%d%d%d%d%d", &i1, &i2, &i3, &i4, &i5);
+       return (n > 2 && n < 6);
+
+      default:
+       /* what to do here? */
+       return (value && value[0]);
+    }
+}
+
+/* return codes:
+   0 = none
+   1 =   valid display
+   2 =   valid machine player
+  -1 = invalid display 
+  -2 = invalid machine player */
+
+static int
+type_player(char *value)
+{
+    errormess[0] = '\0';
+    if (!value[0]) {
+       strcpy(errormess, "no player specification");
+       return 0;
+    } else if (strchr(value,':') || !strcmp(value,"here")) {
+       if (can_open_display(value)) {
+           return 1;
+       } else {
+           sprintf(errormess, "cannot open display \"%s\"", value);
+           return -1;
+       }
+    } else {
+       if (strcmp(value,"mplayer")) {
+           sprintf(errormess,
+                   "invalid or unkonwn AI \"%s\", try \"mplayer\"", value);
+           return -2;
+       } else {
+           return 2;
+       }
+    }
+}
+
+static void 
+add_player_dialog(Widget w,XtPointer  client_data, XtPointer call_data)
+{
+    int i, oldnumsides = numsides;
+    GamePop *pop = games[chosen_game].pop;
+
+    if (numsides > g_sides_max()) {
+       XBell(XtDisplay(pop->shell),50);
+       return;
+    }
+
+    add_side_and_player();
+
+    for (i = 1 + oldnumsides; i <= numsides; ++i) {
+       init_assignw_player(&(pop->assign[i]), assignments[i].player);
+       pop->assign[i].messid =
+         copy_string("enter display name or \"mplayer\"");
+    }
+
+    verify_dialog(w, NULL, NULL);
+}
+
+static void
+init_assignw_player(Assignw *assignw, Player *player)
+{
+    assignw->vname = (char *)(player && player->name ? player->name : "");
+    if (player && player->displayname) {
+       assignw->vid = player->displayname;
+       assignw->vflag = 1;
+    } else if (player && player->aitypename) {
+       assignw->vid = player->aitypename;
+       assignw->vflag = 2;
+    } else {
+       assignw->vid = "";
+       assignw->vflag = 0;
+    }
+}
+
+static int
+can_open_display(char *dpyname)
+{
+    Display *dpy;
+
+    if (dpyname == NULL)
+      return FALSE;
+
+    if (strcmp("here", dpyname) == 0)
+      dpyname = getenv("DISPLAY");
+
+    dpy = XOpenDisplay(dpyname);
+    if (dpy) {
+       XCloseDisplay(dpy);
+       return TRUE;
+    } else {
+       return FALSE;
+    }
+}
+
+/* Shut the side's display down. */
+
+void
+close_display(Side *side)
+{
+    Display *dpy = side->ui->dpy;
+
+    flush_output(side);
+    XSync(dpy, True);
+    /* Mark it as inactive. */
+    side->ui->active = FALSE;
+    /* Clean up after ourselves. */
+    XFreeGC(dpy, side->ui->gc);
+    XFreeGC(dpy, side->ui->textgc);
+    XFreeGC(dpy, side->ui->ltextgc);
+    XFreeGC(dpy, side->ui->terrgc);
+    XFreeGC(dpy, side->ui->unitgc);
+    XFreeGC(dpy, side->ui->emblgc);
+    XtCloseDisplay(dpy);
+}