]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:06:03 +0000 (21:06 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:06:03 +0000 (21:06 +0000)
win/X11/winmap.c [new file with mode: 0644]

diff --git a/win/X11/winmap.c b/win/X11/winmap.c
new file mode 100644 (file)
index 0000000..b028806
--- /dev/null
@@ -0,0 +1,1644 @@
+/*     SCCS Id: @(#)winmap.c   3.3     96/04/05        */
+/* Copyright (c) Dean Luick, 1992                                */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains:
+ *     + global functions print_glyph() and cliparound()
+ *     + the map window routines
+ *     + the char and pointer input routines
+ *
+ * Notes:
+ *     + We don't really have a good way to get the compiled ROWNO and
+ *       COLNO as defaults.  They are hardwired to the current "correct"
+ *       values in the Window widget.  I am _not_ in favor of including
+ *       some nethack include file for Window.c.
+ */
+
+#ifndef SYSV
+#define PRESERVE_NO_SYSV       /* X11 include files may define SYSV */
+#endif
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Cardinals.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xatom.h>
+
+#ifdef PRESERVE_NO_SYSV
+# ifdef SYSV
+#  undef SYSV
+# endif
+# undef PRESERVE_NO_SYSV
+#endif
+
+#include "xwindow.h"   /* map widget declarations */
+
+#include "hack.h"
+#include "dlb.h"
+#include "winX.h"
+
+#ifdef USE_XPM
+#include <X11/xpm.h>
+#endif
+
+
+/* from tile.c */
+extern short glyph2tile[];
+extern int total_tiles_used;
+
+/* Define these if you really want a lot of junk on your screen. */
+/* #define VERBOSE */          /* print various info & events as they happen */
+/* #define VERBOSE_UPDATE */   /* print screen update bounds */
+/* #define VERBOSE_INPUT */    /* print input events */
+
+
+#define USE_WHITE      /* almost always use white as a tile cursor border */
+
+
+static boolean FDECL(init_tiles, (struct xwindow *));
+static void FDECL(set_button_values, (Widget,int,int,unsigned));
+static void FDECL(map_check_size_change, (struct xwindow *));
+static void FDECL(map_update, (struct xwindow *,int,int,int,int,BOOLEAN_P));
+static void FDECL(init_text, (struct xwindow *));
+static void FDECL(map_exposed, (Widget,XtPointer,XtPointer));
+static void FDECL(set_gc, (Widget,Font,char *,Pixel,GC *,GC *));
+static void FDECL(get_text_gc, (struct xwindow *,Font));
+static void FDECL(get_char_info, (struct xwindow *));
+static void FDECL(display_cursor, (struct xwindow *));
+
+/* Global functions ======================================================== */
+
+void
+X11_print_glyph(window, x, y, glyph)
+    winid window;
+    xchar x, y;
+    int glyph;
+{
+    struct map_info_t *map_info;
+    boolean update_bbox;
+
+    check_winid(window);
+    if (window_list[window].type != NHW_MAP) {
+       impossible("print_glyph: can (currently) only print to map windows");
+       return;
+    }
+    map_info = window_list[window].map_information;
+
+    if (map_info->is_tile) {
+       unsigned short *t_ptr;
+
+       t_ptr = &map_info->mtype.tile_map->glyphs[y][x];
+
+       if (*t_ptr != glyph) {
+           *t_ptr = glyph;
+           update_bbox = TRUE;
+       } else
+           update_bbox = FALSE;
+
+    } else {
+       uchar                   ch;
+       register unsigned char *ch_ptr;
+       int                     color,och;
+       unsigned                special;
+#ifdef TEXTCOLOR
+       register unsigned char *co_ptr;
+#endif
+       /* map glyph to character and color */
+        mapglyph(glyph, &och, &color, &special, x, y);
+       ch = (uchar)och;
+       
+       /* Only update if we need to. */
+       ch_ptr = &map_info->mtype.text_map->text[y][x];
+
+#ifdef TEXTCOLOR
+       co_ptr = &map_info->mtype.text_map->colors[y][x];
+       if (*ch_ptr != ch || *co_ptr != color)
+#else
+       if (*ch_ptr != ch)
+#endif
+       {
+           *ch_ptr = ch;
+#ifdef TEXTCOLOR
+           *co_ptr = color;
+#endif
+           update_bbox = TRUE;
+       } else
+           update_bbox = FALSE;
+
+#undef zap_color
+#undef cmap_color
+#undef obj_color
+#undef mon_color
+#undef pet_color
+    }
+
+    if (update_bbox) {         /* update row bbox */
+       if ((uchar) x < map_info->t_start[y]) map_info->t_start[y] = x;
+       if ((uchar) x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
+    }
+}
+
+#ifdef CLIPPING
+/*
+ * The is the tty clip call.  Since X can resize at any time, we can't depend
+ * on this being defined.
+ */
+/*ARGSUSED*/
+void X11_cliparound(x, y) int x, y; { }
+#endif /* CLIPPING */
+
+/* End global functions ==================================================== */
+
+#include "tile2x11.h"
+
+/*
+ * We're expecting to never read more than one tile file per session.
+ * If this is false, then we can make an array of this information,
+ * or just keep it on a per-window basis.
+ */
+Pixmap tile_pixmap = None;
+static int tile_width;
+static int tile_height;
+static int tile_count;
+static XImage *tile_image = 0;
+
+/*
+ * This structure is used for small bitmaps that are used for annotating
+ * tiles.  For example, a "heart" annotates pets.
+ */
+struct tile_annotation {
+    Pixmap bitmap;
+    Pixel foreground;
+    unsigned int width, height;
+    int hotx, hoty; /* not currently used */
+};
+
+static struct tile_annotation pet_annotation;
+
+static void
+init_annotation(annotation, filename, colorpixel)
+struct tile_annotation *annotation;
+char *filename;
+Pixel colorpixel;
+{
+    Display *dpy = XtDisplay(toplevel);
+
+    if (0!=XReadBitmapFile(dpy, XtWindow(toplevel), filename,
+           &annotation->width, &annotation->height, &annotation->bitmap,
+           &annotation->hotx, &annotation->hoty)) {
+       char buf[BUFSZ];
+       Sprintf(buf, "Failed to load %s", filename);
+       X11_raw_print(buf);
+    }
+
+    annotation->foreground = colorpixel;
+}
+
+/*
+ * Put the tile image on the server.
+ *
+ * We can't send the image to the server until the top level
+ * is realized.  When the tile file is first processed, the top
+ * level is not realized.  This routine is called after we
+ * realize the top level, but before we start resizing the
+ * map viewport.
+ */
+void
+post_process_tiles()
+{
+    Display *dpy = XtDisplay(toplevel);
+    unsigned int width, height;
+
+    height = tile_height * tile_count;
+    width  = tile_width;
+
+    if (tile_image == 0) return;       /* no tiles */
+
+    tile_pixmap = XCreatePixmap(dpy, XtWindow(toplevel),
+                       width,
+                       height,
+                       DefaultDepth(dpy, DefaultScreen(dpy)));
+
+    XPutImage(dpy, tile_pixmap,
+       DefaultGC(dpy, DefaultScreen(dpy)),
+       tile_image,
+       0,0, 0,0,               /* src, dest top left */
+       width,
+       height);
+
+    XDestroyImage(tile_image); /* data bytes free'd also */
+    tile_image = 0;
+
+    init_annotation(&pet_annotation,
+       appResources.pet_mark_bitmap, appResources.pet_mark_color);
+}
+
+
+/*
+ * Open and read the tile file.  Return TRUE if there were no problems.
+ * Return FALSE otherwise.
+ */
+static boolean
+init_tiles(wp)
+    struct xwindow *wp;
+{
+#ifndef USE_XPM
+    FILE *fp = (FILE *)0;
+    x11_header header;
+    unsigned char *cp, *colormap = (unsigned char *)0;
+    unsigned char *tb, *tile_bytes = (unsigned char *)0;
+    int size;
+    XColor *colors = (XColor *)0;
+    int i, x, y;
+    int bitmap_pad;
+    unsigned int image_height, image_width;
+    int ddepth;
+#endif
+    Display *dpy = XtDisplay(toplevel);
+    Screen *screen = DefaultScreenOfDisplay(dpy);
+    struct map_info_t *map_info = (struct map_info_t *)0;
+    struct tile_map_info_t *tile_info = (struct tile_map_info_t *)0;
+    boolean result = TRUE;
+    XGCValues values;
+    XtGCMask mask;
+
+    /* already have tile information */
+    if (tile_pixmap != None) goto tiledone;
+
+    map_info = wp->map_information;
+    tile_info = map_info->mtype.tile_map =
+           (struct tile_map_info_t *) alloc(sizeof(struct tile_map_info_t));
+    (void) memset((genericptr_t) tile_info, 0,
+                               sizeof(struct tile_map_info_t));
+
+#ifdef USE_XPM
+    {
+       char buf[BUFSZ];
+       XpmAttributes attributes;
+       int errorcode;
+
+       attributes.valuemask = XpmCloseness;
+       attributes.closeness = 25000;
+
+       errorcode=XpmReadFileToImage(dpy,appResources.tile_file,&tile_image,0,&attributes);
+
+       if (errorcode == XpmColorFailed) {
+           Sprintf(buf, "Insufficient colors available to load %s.",appResources.tile_file);
+           X11_raw_print(buf);
+           X11_raw_print("Try closing other colorful applications and restart.");
+           X11_raw_print("Attempting to load with inferior colors.");
+           attributes.closeness = 50000;
+           errorcode=XpmReadFileToImage(dpy,appResources.tile_file,&tile_image,0,&attributes);
+       }
+
+       if (errorcode!=XpmSuccess) {
+           if (errorcode == XpmColorFailed) {
+               Sprintf(buf, "Insufficient colors available to load %s.",appResources.tile_file);
+               X11_raw_print(buf);
+           } else {
+               Sprintf(buf, "Failed to load %s: %s",appResources.tile_file,
+                       XpmGetErrorString(errorcode));
+               X11_raw_print(buf);
+           }
+           result = FALSE;
+           X11_raw_print("Switching to text-based mode.");
+           goto tiledone;
+       }
+
+       if (tile_image->height%total_tiles_used != 0) {
+           Sprintf(buf,
+               "%s is not a multiple of %d (the number of tiles) pixels high",
+               appResources.tile_file, total_tiles_used);
+           X11_raw_print(buf);
+           XDestroyImage(tile_image);
+           tile_image = 0;
+           result = FALSE;
+           goto tiledone;
+       }
+
+       /* infer tile dimensions from image size */
+       tile_count=total_tiles_used;
+       tile_width=tile_image->width;
+       tile_height=tile_image->height/tile_count;
+    }
+#else
+    /* any less than 16 colours makes tiles useless */
+    ddepth = DefaultDepthOfScreen(screen);
+    if (ddepth < 4) {
+       X11_raw_print("need a screen depth of at least 4");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE);
+    if (!fp) {
+       X11_raw_print("can't open tile file");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    if (fread((char *) &header, sizeof(header), 1, fp) != 1) {
+       X11_raw_print("read of header failed");
+       result = FALSE;
+       goto tiledone;
+    }
+
+# ifdef VERBOSE
+    fprintf(stderr, "X11 tile file:\n    version %ld\n    ncolors %ld\n    tile width %ld\n    tile height %ld\n    ntiles %ld\n",
+       header.version,
+       header.ncolors,
+       header.tile_width,
+       header.tile_height,
+       header.ntiles);
+# endif
+
+    size = 3*header.ncolors;
+    colormap = (unsigned char *) alloc((unsigned)size);
+    if (fread((char *) colormap, 1, size, fp) != size) {
+       X11_raw_print("read of colormap failed");
+       result = FALSE;
+       goto tiledone;
+    }
+
+/* defined in decl.h - these are _not_ good defines to have */
+#undef red
+#undef green
+#undef blue
+
+    colors = (XColor *) alloc(sizeof(XColor) * (unsigned)header.ncolors);
+    for (i = 0; i < header.ncolors; i++) {
+       cp = colormap + (3 * i);
+       colors[i].red   = cp[0] * 256;
+       colors[i].green = cp[1] * 256;
+       colors[i].blue  = cp[2] * 256;
+       colors[i].flags = 0;
+       colors[i].pixel = 0;
+
+       if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i]) &&
+           !nhApproxColor(screen, DefaultColormapOfScreen(screen),
+                          (char *)0, &colors[i])) {
+           char buf[BUFSZ];
+           Sprintf(buf, "%dth out of %ld color allocation failed",
+               i, header.ncolors);
+           X11_raw_print(buf);
+           result = FALSE;
+           goto tiledone;
+       }
+    }
+
+    size = header.tile_height * header.tile_width;
+    /*
+     * This alloc() and the one below require 32-bit ints, since tile_bytes
+     * is currently ~200k and alloc() takes an int
+     */
+    tile_bytes = (unsigned char *) alloc((unsigned)header.ntiles*size);
+    tile_count = header.ntiles;
+    if (fread((char *) tile_bytes, size, tile_count, fp) != tile_count) {
+       X11_raw_print("read of tile bytes failed");
+       result = FALSE;
+       goto tiledone;
+    }
+
+    if (header.ntiles < total_tiles_used) {
+       char buf[BUFSZ];
+       Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu",
+               total_tiles_used, header.ntiles);
+       X11_raw_print(buf);
+       result = FALSE;
+       goto tiledone;
+    }
+
+
+    if (appResources.double_tile_size) {
+       tile_width  = 2*header.tile_width;
+       tile_height = 2*header.tile_height;
+    } else {
+       tile_width  = header.tile_width;
+       tile_height = header.tile_height;
+    }
+
+    image_height = tile_height * tile_count;
+    image_width  = tile_width;
+
+    /* calculate bitmap_pad */
+    if (ddepth > 16)
+       bitmap_pad = 32;
+    else if (ddepth > 8)
+       bitmap_pad = 16;
+    else
+       bitmap_pad = 8;
+
+    tile_image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
+               ddepth,                 /* depth */
+               ZPixmap,                /* format */
+               0,                      /* offset */
+               0,                      /* data */
+               image_width,            /* width */
+               image_height,           /* height */
+               bitmap_pad,             /* bit pad */
+               0);                     /* bytes_per_line */
+
+    if (!tile_image)
+       impossible("init_tiles: insufficient memory to create image");
+
+    /* now we know the physical memory requirements, we can allocate space */
+    tile_image->data =
+       (char *) alloc((unsigned)tile_image->bytes_per_line * image_height);
+
+    if (appResources.double_tile_size) {
+       unsigned long *expanded_row =
+           (unsigned long *)alloc(sizeof(unsigned long)*(unsigned)tile_width);
+
+       tb = tile_bytes;
+       for (y = 0; y < image_height; y++) {
+           for (x = 0; x < header.tile_width; x++)
+               expanded_row[2*x] =
+                           expanded_row[(2*x)+1] = colors[*tb++].pixel;
+
+           for (x = 0; x < tile_width; x++)
+               XPutPixel(tile_image, x, y, expanded_row[x]);
+
+           y++;        /* duplicate row */
+           for (x = 0; x < tile_width; x++)
+               XPutPixel(tile_image, x, y, expanded_row[x]);
+       }
+       free((genericptr_t)expanded_row);
+
+    } else {
+
+       for (tb = tile_bytes, y = 0; y < image_height; y++)
+           for (x = 0; x < image_width; x++, tb++)
+               XPutPixel(tile_image, x, y, colors[*tb].pixel);
+    }
+#endif /* USE_XPM */
+
+    /* fake an inverted tile by drawing a border around the edges */
+#ifdef USE_WHITE
+    /* use white or black as the border */
+    mask = GCFunction | GCForeground | GCGraphicsExposures;
+    values.graphics_exposures = False;
+    values.foreground = WhitePixelOfScreen(screen);
+    values.function   = GXcopy;
+    tile_info->white_gc = XtGetGC(wp->w, mask, &values);
+    values.graphics_exposures = False;
+    values.foreground = BlackPixelOfScreen(screen);
+    values.function   = GXcopy;
+    tile_info->black_gc = XtGetGC(wp->w, mask, &values);
+#else
+    /*
+     * Use xor so we don't have to check for special colors.  Xor white
+     * against the upper left pixel of the corridor so that we have a
+     * white rectangle when in a corridor.
+     */
+    mask = GCFunction | GCForeground | GCGraphicsExposures;
+    values.graphics_exposures = False;
+#if 1
+    values.foreground = WhitePixelOfScreen(screen) ^
+       XGetPixel(tile_image, 0, tile_height*glyph2tile[cmap_to_glyph(S_corr)]);
+#else
+    values.foreground = ~((unsigned long) 0);
+#endif
+    values.function = GXxor;
+    tile_info->white_gc = XtGetGC(wp->w, mask, &values);
+
+    mask = GCFunction | GCGraphicsExposures;
+    values.function = GXCopy;
+    values.graphics_exposures = False;
+    tile_info->black_gc = XtGetGC(wp->w, mask, &values);
+#endif
+
+tiledone:
+#ifndef USE_XPM
+    if (fp) (void) fclose(fp);
+    if (colormap) free((genericptr_t)colormap);
+    if (tile_bytes) free((genericptr_t)tile_bytes);
+    if (colors) free((genericptr_t)colors);
+#endif
+
+    if (result) {                              /* succeeded */
+       map_info->square_height = tile_height;
+       map_info->square_width = tile_width;
+       map_info->square_ascent = 0;
+       map_info->square_lbearing = 0;
+    } else {
+       if (tile_info) free((genericptr_t)tile_info);
+       tile_info = 0;
+    }
+
+    return result;
+}
+
+
+/*
+ * Make sure the map's cursor is always visible.
+ */
+void
+check_cursor_visibility(wp)
+    struct xwindow *wp;
+{
+    Arg arg[2];
+    Widget viewport, horiz_sb, vert_sb;
+    float top, shown, cursor_middle;
+    Boolean do_call, adjusted = False;
+#ifdef VERBOSE
+    char *s;
+#endif
+
+    viewport = XtParent(wp->w);
+    horiz_sb = XtNameToWidget(viewport, "horizontal");
+    vert_sb  = XtNameToWidget(viewport, "vertical");
+
+/* All values are relative to currently visible area */
+
+#define V_BORDER 0.3   /* if this far from vert edge, shift */
+#define H_BORDER 0.3   /* if this from from horiz edge, shift */
+
+#define H_DELTA 0.4    /* distance of horiz shift */
+#define V_DELTA 0.4    /* distance of vert shift */
+
+    if (horiz_sb) {
+       XtSetArg(arg[0], XtNshown,      &shown);
+       XtSetArg(arg[1], XtNtopOfThumb, &top);
+       XtGetValues(horiz_sb, arg, TWO);
+
+       /* [ALI] Don't assume map widget is the same size as actual map */
+       cursor_middle = (wp->cursx + 0.5) * wp->map_information->square_width /
+         wp->pixel_width;
+       do_call = True;
+
+#ifdef VERBOSE
+       if (cursor_middle < top) {
+           s = " outside left";
+       } else if (cursor_middle < top + shown*H_BORDER) {
+           s = " close to left";
+       } else if (cursor_middle > (top + shown)) {
+           s = " outside right";
+       } else if (cursor_middle > (top + shown - shown*H_BORDER)) {
+           s = " close to right";
+       } else {
+           s = "";
+       }
+       printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s);
+#endif
+
+       if (cursor_middle < top) {
+           top = cursor_middle - shown*H_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle < top + shown*H_BORDER) {
+           top -= shown*H_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle > (top + shown)) {
+           top = cursor_middle - shown*H_DELTA;
+           if (top < 0.0) top = 0.0;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else if (cursor_middle > (top + shown - shown*H_BORDER)) {
+           top += shown*H_DELTA;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else {
+           do_call = False;
+       }
+
+       if (do_call) {
+           XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
+           adjusted = True;
+       }
+    }
+
+    if (vert_sb) {
+       XtSetArg(arg[0], XtNshown,      &shown);
+       XtSetArg(arg[1], XtNtopOfThumb, &top);
+       XtGetValues(vert_sb, arg, TWO);
+
+       cursor_middle = (wp->cursy + 0.5) * wp->map_information->square_height /
+         wp->pixel_height;
+       do_call = True;
+
+#ifdef VERBOSE
+       if (cursor_middle < top) {
+           s = " above top";
+       } else if (cursor_middle < top + shown*V_BORDER) {
+           s = " close to top";
+       } else if (cursor_middle > (top + shown)) {
+           s = " below bottom";
+       } else if (cursor_middle > (top + shown - shown*V_BORDER)) {
+           s = " close to bottom";
+       } else {
+           s = "";
+       }
+       printf("%sVert: shown = %3.2f, top = %3.2f%s",
+                                   horiz_sb ? ";  " : "", shown, top, s);
+#endif
+
+       if (cursor_middle < top) {
+           top = cursor_middle - shown*V_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle < top + shown*V_BORDER) {
+           top -= shown*V_DELTA;
+           if (top < 0.0) top = 0.0;
+       } else if (cursor_middle > (top + shown)) {
+           top = cursor_middle - shown*V_DELTA;
+           if (top < 0.0) top = 0.0;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else if (cursor_middle > (top + shown - shown*V_BORDER)) {
+           top += shown*V_DELTA;
+           if (top + shown > 1.0) top = 1.0 - shown;
+       } else {
+           do_call = False;
+       }
+
+       if (do_call) {
+           XtCallCallbacks(vert_sb, XtNjumpProc, &top);
+           adjusted = True;
+       }
+    }
+
+    /* make sure cursor is displayed during dowhatis.. */
+    if (adjusted) display_cursor(wp);
+
+#ifdef VERBOSE
+    if (horiz_sb || vert_sb) printf("\n");
+#endif
+}
+
+
+/*
+ * Check to see if the viewport has grown smaller.  If so, then we want to make
+ * sure that the cursor is still on the screen.  We do this to keep the cursor
+ * on the screen when the user resizes the nethack window.
+ */
+static void
+map_check_size_change(wp)
+    struct xwindow *wp;
+{
+    struct map_info_t *map_info = wp->map_information;
+    Arg arg[2];
+    Dimension new_width, new_height;
+    Widget viewport;
+
+    viewport = XtParent(wp->w);
+
+    XtSetArg(arg[0], XtNwidth,  &new_width);
+    XtSetArg(arg[1], XtNheight, &new_height);
+    XtGetValues(viewport, arg, TWO);
+
+    /* Only do cursor check if new size is smaller. */
+    if (new_width < map_info->viewport_width
+                   || new_height < map_info->viewport_height) {
+       /* [ALI] If the viewport was larger than the map (and so the map
+        * widget was contrained to be larger than the actual map) then we
+        * may be able to shrink the map widget as the viewport shrinks.
+        */
+       wp->pixel_width = map_info->square_width * COLNO;
+       if (wp->pixel_width < new_width)
+           wp->pixel_width = new_width;
+       wp->pixel_height = map_info->square_height * ROWNO;
+       if (wp->pixel_height < new_height)
+           wp->pixel_height = new_height;
+       XtSetArg(arg[0], XtNwidth, wp->pixel_width);
+       XtSetArg(arg[1], XtNheight, wp->pixel_height);
+       XtSetValues(wp->w, arg, TWO);
+
+       check_cursor_visibility(wp);
+    }
+
+    map_info->viewport_width = new_width;
+    map_info->viewport_height = new_height;
+
+    /* [ALI] These may have changed if the user has re-sized the viewport */
+    XtSetArg(arg[0], XtNwidth, &wp->pixel_width);
+    XtSetArg(arg[1], XtNheight, &wp->pixel_height);
+    XtGetValues(wp->w, arg, TWO);
+}
+
+/*
+ * Fill in parameters "regular" and "inverse" with newly created GCs.
+ * Using the given background pixel and the foreground pixel optained
+ * by querying the widget with the resource name.
+ */
+static void
+set_gc(w, font, resource_name, bgpixel, regular, inverse)
+    Widget w;
+    Font font;
+    char *resource_name;
+    Pixel bgpixel;
+    GC   *regular, *inverse;
+{
+    XGCValues values;
+    XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
+    Pixel curpixel;
+    Arg arg[1];
+
+    XtSetArg(arg[0], resource_name, &curpixel);
+    XtGetValues(w, arg, ONE);
+
+    values.foreground = curpixel;
+    values.background = bgpixel;
+    values.function   = GXcopy;
+    values.font              = font;
+    *regular = XtGetGC(w, mask, &values);
+    values.foreground = bgpixel;
+    values.background = curpixel;
+    values.function   = GXcopy;
+    values.font              = font;
+    *inverse = XtGetGC(w, mask, &values);
+}
+
+/*
+ * Create the GC's for each color.
+ *
+ * I'm not sure if it is a good idea to have a GC for each color (and
+ * inverse). It might be faster to just modify the foreground and
+ * background colors on the current GC as needed.
+ */
+static void
+get_text_gc(wp, font)
+    struct xwindow *wp;
+    Font font;
+{
+    struct map_info_t *map_info = wp->map_information;
+    Pixel bgpixel;
+    Arg arg[1];
+
+    /* Get background pixel. */
+    XtSetArg(arg[0], XtNbackground, &bgpixel);
+    XtGetValues(wp->w, arg, ONE);
+
+#ifdef TEXTCOLOR
+#define set_color_gc(nh_color, resource_name)                  \
+           set_gc(wp->w, font, resource_name, bgpixel,         \
+               &map_info->mtype.text_map->color_gcs[nh_color], \
+                   &map_info->mtype.text_map->inv_color_gcs[nh_color]);
+
+    set_color_gc(CLR_BLACK,    XtNblack);
+    set_color_gc(CLR_RED,      XtNred);
+    set_color_gc(CLR_GREEN,    XtNgreen);
+    set_color_gc(CLR_BROWN,    XtNbrown);
+    set_color_gc(CLR_BLUE,     XtNblue);
+    set_color_gc(CLR_MAGENTA,  XtNmagenta);
+    set_color_gc(CLR_CYAN,     XtNcyan);
+    set_color_gc(CLR_GRAY,     XtNgray);
+    set_color_gc(NO_COLOR,     XtNforeground);
+    set_color_gc(CLR_ORANGE,   XtNorange);
+    set_color_gc(CLR_BRIGHT_GREEN, XtNbright_green);
+    set_color_gc(CLR_YELLOW,   XtNyellow);
+    set_color_gc(CLR_BRIGHT_BLUE, XtNbright_blue);
+    set_color_gc(CLR_BRIGHT_MAGENTA, XtNbright_magenta);
+    set_color_gc(CLR_BRIGHT_CYAN, XtNbright_cyan);
+    set_color_gc(CLR_WHITE,    XtNwhite);
+#else
+    set_gc(wp->w, font, XtNforeground, bgpixel,
+               &map_info->mtype.text_map->copy_gc,
+               &map_info->mtype.text_map->inv_copy_gc);
+#endif
+}
+
+
+/*
+ * Display the cursor on the map window.
+ */
+static void
+display_cursor(wp)
+    struct xwindow *wp;
+{
+    /* Redisplay the cursor location inverted. */
+    map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE);
+}
+
+
+/*
+ * Check if there are any changed characters.  If so, then plaster them on
+ * the screen.
+ */
+void
+display_map_window(wp)
+    struct xwindow *wp;
+{
+    register int row;
+    struct map_info_t *map_info = wp->map_information;
+
+    /*
+     * If the previous cursor position is not the same as the current
+     * cursor position, then update the old cursor position.
+     */
+    if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) {
+       register unsigned int x = wp->prevx, y = wp->prevy;
+       if (x < map_info->t_start[y]) map_info->t_start[y] = x;
+       if (x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
+    }
+
+    for (row = 0; row < ROWNO; row++) {
+       if (map_info->t_start[row] <= map_info->t_stop[row]) {
+           map_update(wp, row, row,
+                       (int) map_info->t_start[row],
+                       (int) map_info->t_stop[row], FALSE);
+           map_info->t_start[row] = COLNO-1;
+           map_info->t_stop[row] = 0;
+       }
+    }
+    display_cursor(wp);
+    wp->prevx = wp->cursx;     /* adjust old cursor position */
+    wp->prevy = wp->cursy;
+}
+
+/*
+ * Set all map tiles to S_stone
+ */
+static void
+map_all_stone(map_info)
+struct map_info_t *map_info;
+{
+    int i;
+    unsigned short *sp, stone;
+    stone = cmap_to_glyph(S_stone);
+
+    for (sp = (unsigned short *) map_info->mtype.tile_map->glyphs, i = 0;
+       i < ROWNO*COLNO; sp++, i++)
+
+    *sp = stone;
+}
+
+/*
+ * Fill the saved screen characters with the "clear" tile or character.
+ *
+ * Flush out everything by resetting the "new" bounds and calling
+ * display_map_window().
+ */
+void
+clear_map_window(wp)
+    struct xwindow *wp;
+{
+    struct map_info_t *map_info = wp->map_information;
+
+    if (map_info->is_tile) {
+       map_all_stone(map_info);
+    } else {
+       /* Fill text with spaces, and update */
+       (void) memset((genericptr_t) map_info->mtype.text_map->text, ' ',
+                       sizeof(map_info->mtype.text_map->text));
+#ifdef TEXTCOLOR
+       (void) memset((genericptr_t) map_info->mtype.text_map->colors, NO_COLOR,
+                       sizeof(map_info->mtype.text_map->colors));
+#endif
+    }
+
+    /* force a full update */
+    (void) memset((genericptr_t) map_info->t_start, (char) 0,
+                       sizeof(map_info->t_start));
+    (void) memset((genericptr_t) map_info->t_stop, (char) COLNO-1,
+                       sizeof(map_info->t_stop));
+    display_map_window(wp);
+}
+
+/*
+ * Retreive the font associated with the map window and save attributes
+ * that are used when updating it.
+ */
+static void
+get_char_info(wp)
+    struct xwindow *wp;
+{
+    XFontStruct *fs;
+    struct map_info_t *map_info = wp->map_information;
+
+    fs = WindowFontStruct(wp->w);
+    map_info->square_width    = fs->max_bounds.width;
+    map_info->square_height   = fs->max_bounds.ascent + fs->max_bounds.descent;
+    map_info->square_ascent   = fs->max_bounds.ascent;
+    map_info->square_lbearing = -fs->min_bounds.lbearing;
+
+#ifdef VERBOSE
+    printf("Font information:\n");
+    printf("fid = %d, direction = %d\n", fs->fid, fs->direction);
+    printf("first = %d, last = %d\n",
+                       fs->min_char_or_byte2, fs->max_char_or_byte2);
+    printf("all chars exist? %s\n", fs->all_chars_exist?"yes":"no");
+    printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
+               fs->min_bounds.lbearing, fs->min_bounds.rbearing,
+               fs->min_bounds.width, fs->min_bounds.ascent,
+               fs->min_bounds.descent, fs->min_bounds.attributes);
+    printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
+               fs->max_bounds.lbearing, fs->max_bounds.rbearing,
+               fs->max_bounds.width, fs->max_bounds.ascent,
+               fs->max_bounds.descent, fs->max_bounds.attributes);
+    printf("per_char = 0x%x\n", fs->per_char);
+    printf("Text: (max) width = %d, height = %d\n",
+           map_info->square_width, map_info->square_height);
+#endif
+
+    if (fs->min_bounds.width != fs->max_bounds.width)
+       X11_raw_print("Warning:  map font is not monospaced!");
+}
+
+/*
+ * keyhit buffer
+ */
+#define INBUF_SIZE 64
+int inbuf[INBUF_SIZE];
+int incount = 0;
+int inptr = 0; /* points to valid data */
+
+
+/*
+ * Keyboard and button event handler for map window.
+ */
+void
+map_input(w, event, params, num_params)
+    Widget   w;
+    XEvent   *event;
+    String   *params;
+    Cardinal *num_params;
+{
+    XKeyEvent *key;
+    XButtonEvent *button;
+    boolean meta = FALSE;
+    int i, nbytes;
+    Cardinal in_nparams = (num_params ? *num_params : 0);
+    char c;
+    char keystring[MAX_KEY_STRING];
+
+    switch (event->type) {
+       case ButtonPress:
+           button = (XButtonEvent *) event;
+#ifdef VERBOSE_INPUT
+           printf("button press\n");
+#endif
+           if (in_nparams > 0 &&
+               (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
+               Strcpy(keystring, params[0]);
+               key = (XKeyEvent *) event; /* just in case */
+               goto key_events;
+           }
+           if (w != window_list[WIN_MAP].w) {
+#ifdef VERBOSE_INPUT
+               printf("map_input called from wrong window\n");
+#endif
+               X11_nhbell();
+               return;
+           }
+           set_button_values(w, button->x, button->y, button->button);
+           break;
+       case KeyPress:
+#ifdef VERBOSE_INPUT
+           printf("key: ");
+#endif
+           if(appResources.slow && input_func) {
+               (*input_func)(w, event, params, num_params);
+               break;
+           }
+
+           /*
+            * Don't use key_event_to_char() because we want to be able
+            * to allow keys mapped to multiple characters.
+            */
+           key = (XKeyEvent *) event;
+           if (in_nparams > 0 &&
+               (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
+               Strcpy(keystring, params[0]);
+           } else {
+               /*
+                * Assume that mod1 is really the meta key.
+                */
+               meta = !!(key->state & Mod1Mask);
+               nbytes =
+                   XLookupString(key, keystring, MAX_KEY_STRING,
+                                 (KeySym *)0, (XComposeStatus *)0);
+           }
+       key_events:
+           /* Modifier keys return a zero length string when pressed. */
+           if (nbytes) {
+#ifdef VERBOSE_INPUT
+               printf("\"");
+#endif
+               for (i = 0; i < nbytes; i++) {
+                   c = keystring[i];
+
+                   if (incount < INBUF_SIZE) {
+                       inbuf[(inptr+incount)%INBUF_SIZE] =
+                           ((int) c) + (meta ? 0x80 : 0);
+                       incount++;
+                   } else {
+                       X11_nhbell();
+                   }
+#ifdef VERBOSE_INPUT
+                   if (meta)                   /* meta will print as M<c> */
+                       (void) putchar('M');
+                   if (c < ' ') {              /* ctrl will print as ^<c> */
+                       (void) putchar('^');
+                       c += '@';
+                   }
+                   (void) putchar(c);
+#endif
+               }
+#ifdef VERBOSE_INPUT
+               printf("\" [%d bytes]\n", nbytes);
+#endif
+           }
+           break;
+
+       default:
+           impossible("unexpected X event, type = %d\n", (int) event->type);
+           break;
+    }
+}
+
+static void
+set_button_values(w, x, y, button)
+    Widget w;
+    int x;
+    int y;
+    unsigned int button;
+{
+    struct xwindow *wp;
+    struct map_info_t *map_info;
+
+    wp = find_widget(w);
+    map_info = wp->map_information;
+
+    click_x = x / map_info->square_width;
+    click_y = y / map_info->square_height;
+
+    /* The values can be out of range if the map window has been resized */
+    /* to be larger than the max size.                                  */
+    if (click_x >= COLNO) click_x = COLNO-1;
+    if (click_y >= ROWNO) click_x = ROWNO-1;
+
+    /* Map all buttons but the first to the second click */
+    click_button = (button == Button1) ? CLICK_1 : CLICK_2;
+}
+
+/*
+ * Map window expose callback.
+ */
+/*ARGSUSED*/
+static void
+map_exposed(w, client_data, widget_data)
+    Widget w;
+    XtPointer client_data;     /* unused */
+    XtPointer widget_data;     /* expose event from Window widget */
+{
+    int x, y;
+    struct xwindow *wp;
+    struct map_info_t *map_info;
+    unsigned width, height;
+    int start_row, stop_row, start_col, stop_col;
+    XExposeEvent *event = (XExposeEvent *) widget_data;
+    int t_height, t_width;     /* tile/text height & width */
+
+    if (!XtIsRealized(w) || event->count > 0) return;
+
+    wp = find_widget(w);
+    map_info = wp->map_information;
+    if (wp->keep_window && !map_info) return;
+    /*
+     * The map is sent an expose event when the viewport resizes.  Make sure
+     * that the cursor is still in the viewport after the resize.
+     */
+    map_check_size_change(wp);
+
+    if (event) {               /* called from button-event */
+       x      = event->x;
+       y      = event->y;
+       width  = event->width;
+       height = event->height;
+    } else {
+       x     = 0;
+       y     = 0;
+       width = wp->pixel_width;
+       height= wp->pixel_height;
+    }
+    /*
+     * Convert pixels into INCLUSIVE text rows and columns.
+     */
+    t_height = map_info->square_height;
+    t_width = map_info->square_width;
+    start_row = y / t_height;
+    stop_row = ((y + height) / t_height) +
+               ((((y + height) % t_height) == 0) ? 0 : 1) - 1;
+
+    start_col = x / t_width;
+    stop_col = ((x + width) / t_width) +
+               ((((x + width) % t_width) == 0) ? 0 : 1) - 1;
+
+#ifdef VERBOSE
+    printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n",
+                                                   x, y, width, height);
+    printf("chars %d x %d, rows %d to %d, columns %d to %d\n",
+                       map_info->square_height, map_info->square_width,
+                       start_row, stop_row, start_col, stop_col);
+#endif
+
+    /* Out of range values are possible if the map window is resized to be */
+    /* bigger than the largest expected value.                            */
+    if (stop_row >= ROWNO) stop_row = ROWNO-1;
+    if (stop_col >= COLNO) stop_col = COLNO-1;
+
+    map_update(wp, start_row, stop_row, start_col, stop_col, FALSE);
+    display_cursor(wp);                /* make sure cursor shows up */
+}
+
+/*
+ * Do the actual work of the putting characters onto our X window.  This
+ * is called from the expose event routine, the display window (flush)
+ * routine, and the display cursor routine.  The later is a kludge that
+ * involves the inverted parameter of this function.  A better solution
+ * would be to double the color count, with any color above CLR_MAX
+ * being inverted.
+ *
+ * This works for rectangular regions (this includes one line rectangles).
+ * The start and stop columns are *inclusive*.
+ */
+static void
+map_update(wp, start_row, stop_row, start_col, stop_col, inverted)
+    struct xwindow *wp;
+    int start_row, stop_row, start_col, stop_col;
+    boolean inverted;
+{
+    int win_start_row, win_start_col;
+    struct map_info_t *map_info = wp->map_information;
+    int row;
+    register int count;
+
+    if (start_row < 0 || stop_row >= ROWNO) {
+       impossible("map_update:  bad row range %d-%d\n", start_row, stop_row);
+       return;
+    }
+    if (start_col < 0 || stop_col >=COLNO) {
+       impossible("map_update:  bad col range %d-%d\n", start_col, stop_col);
+       return;
+    }
+
+#ifdef VERBOSE_UPDATE
+    printf("update: [0x%x] %d %d %d %d\n",
+               (int) wp->w, start_row, stop_row, start_col, stop_col);
+#endif
+    win_start_row = start_row;
+    win_start_col = start_col;
+
+    if (map_info->is_tile) {
+       struct tile_map_info_t *tile_map = map_info->mtype.tile_map;
+       int cur_col;
+       Display* dpy=XtDisplay(wp->w);
+       Screen* screen=DefaultScreenOfDisplay(dpy);
+
+       for (row = start_row; row <= stop_row; row++) {
+           for (cur_col = start_col; cur_col <= stop_col; cur_col++) {
+               int glyph = tile_map->glyphs[row][cur_col];
+               int tile = glyph2tile[glyph];
+               int dest_x = cur_col * map_info->square_width;
+               int dest_y = row * map_info->square_height;
+
+               XCopyArea(dpy, tile_pixmap, XtWindow(wp->w),
+                       tile_map->black_gc,     /* no grapics_expose */
+                       0,
+                       tile * map_info->square_height,
+                       tile_width, tile_height,
+                       dest_x,dest_y);
+
+               if (glyph_is_pet(glyph)
+#ifdef TEXTCOLOR
+                       && iflags.hilite_pet
+#endif
+                       ) {
+                   /* draw pet annotation (a heart) */
+                   XSetForeground(dpy, tile_map->black_gc, pet_annotation.foreground);
+                   XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y);
+                   XSetClipMask(dpy, tile_map->black_gc, pet_annotation.bitmap);
+                   XCopyPlane(
+                       dpy,
+                       pet_annotation.bitmap,
+                       XtWindow(wp->w),
+                       tile_map->black_gc,
+                       0,0,
+                       pet_annotation.width,pet_annotation.height,
+                       dest_x,dest_y,
+                       1
+                   );
+                   XSetClipOrigin(dpy, tile_map->black_gc, 0, 0);
+                   XSetClipMask(dpy, tile_map->black_gc, None);
+                   XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen));
+               }
+           }
+       }
+
+       if (inverted) {
+           XDrawRectangle(XtDisplay(wp->w), XtWindow(wp->w),
+#ifdef USE_WHITE
+               /* kludge for white square... */
+               tile_map->glyphs[start_row][start_col] ==
+                   cmap_to_glyph(S_ice) ?
+                       tile_map->black_gc : tile_map->white_gc,
+#else
+               tile_map->white_gc,
+#endif
+               start_col * map_info->square_width,
+               start_row * map_info->square_height,
+               map_info->square_width-1,
+               map_info->square_height-1);
+       }
+    } else {
+       struct text_map_info_t *text_map = map_info->mtype.text_map;
+
+#ifdef TEXTCOLOR
+       if (iflags.use_color) {
+           register char *c_ptr;
+           char *t_ptr;
+           int cur_col, color, win_ystart;
+
+           for (row = start_row; row <= stop_row; row++) {
+               win_ystart = map_info->square_ascent +
+                                       (row * map_info->square_height);
+
+               t_ptr = (char *) &(text_map->text[row][start_col]);
+               c_ptr = (char *) &(text_map->colors[row][start_col]);
+               cur_col = start_col;
+               while (cur_col <= stop_col) {
+                   color = *c_ptr++;
+                   count = 1;
+                   while ((cur_col + count) <= stop_col && *c_ptr == color) {
+                       count++;
+                       c_ptr++;
+                   }
+
+                   XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
+                       inverted ? text_map->inv_color_gcs[color] :
+                                  text_map->color_gcs[color],
+                       map_info->square_lbearing + (map_info->square_width * cur_col),
+                       win_ystart,
+                       t_ptr, count);
+
+                   /* move text pointer and column count */
+                   t_ptr += count;
+                   cur_col += count;
+               } /* col loop */
+           } /* row loop */
+       } else
+#endif /* TEXTCOLOR */
+       {
+           int win_row, win_xstart;
+
+           /* We always start at the same x window position and have   */
+           /* the same character count.                                */
+           win_xstart = map_info->square_lbearing +
+                                   (win_start_col * map_info->square_width);
+           count = stop_col - start_col + 1;
+
+           for (row = start_row, win_row = win_start_row;
+                                       row <= stop_row; row++, win_row++) {
+
+               XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
+                   inverted ? text_map->inv_copy_gc : text_map->copy_gc,
+                   win_xstart,
+                   map_info->square_ascent + (win_row * map_info->square_height),
+                   (char *) &(text_map->text[row][start_col]), count);
+           }
+       }
+    }
+}
+
+/* Adjust the number of rows and columns on the given map window */
+void
+set_map_size(wp, cols, rows)
+    struct xwindow *wp;
+    Dimension cols, rows;
+{
+    Arg args[4];
+    Cardinal num_args;
+
+    wp->pixel_width  = wp->map_information->square_width  * cols;
+    wp->pixel_height = wp->map_information->square_height * rows;
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth, wp->pixel_width);   num_args++;
+    XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
+    XtSetValues(wp->w, args, num_args);
+}
+
+
+static void
+init_text(wp)
+    struct xwindow *wp;
+{
+
+    struct map_info_t *map_info = wp->map_information;
+    struct text_map_info_t *text_map;
+
+    map_info->is_tile = FALSE;
+    text_map = map_info->mtype.text_map =
+       (struct text_map_info_t *) alloc(sizeof(struct text_map_info_t));
+
+    (void) memset((genericptr_t) text_map->text, ' ', sizeof(text_map->text));
+#ifdef TEXTCOLOR
+    (void) memset((genericptr_t) text_map->colors, NO_COLOR,
+                       sizeof(text_map->colors));
+#endif
+
+    get_char_info(wp);
+    get_text_gc(wp, WindowFont(wp->w));
+}
+
+static char map_translations[] =
+"#override\n\
+ <Key>Left: scroll(4)\n\
+ <Key>Right: scroll(6)\n\
+ <Key>Up: scroll(8)\n\
+ <Key>Down: scroll(2)\n\
+ <Key>:                input() \
+";
+
+/*
+ * The map window creation routine.
+ */
+void
+create_map_window(wp, create_popup, parent)
+    struct xwindow *wp;
+    boolean create_popup;      /* parent is a popup shell that we create */
+    Widget parent;
+{
+    struct map_info_t *map_info;       /* map info pointer */
+    Widget map, viewport;
+    Arg args[16];
+    Cardinal num_args;
+    Dimension rows, columns;
+#if 0
+    int screen_width, screen_height;
+#endif
+
+    wp->type = NHW_MAP;
+
+    if (create_popup) {
+       /*
+        * Create a popup that accepts key and button events.
+        */
+       num_args = 0;
+       XtSetArg(args[num_args], XtNinput, False);            num_args++;
+
+       wp->popup = parent = XtCreatePopupShell("nethack",
+                                       topLevelShellWidgetClass,
+                                      toplevel, args, num_args);
+       /*
+        * If we're here, then this is an auxiliary map window.  If we're
+        * cancelled via a delete window message, we should just pop down.
+        */
+    }
+
+    num_args = 0;
+    XtSetArg(args[num_args], XtNallowHoriz, True);     num_args++;
+    XtSetArg(args[num_args], XtNallowVert,  True);     num_args++;
+    /* XtSetArg(args[num_args], XtNforceBars,  True);  num_args++; */
+    XtSetArg(args[num_args], XtNuseBottom,  True);     num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(map_translations));     num_args++;
+    viewport = XtCreateManagedWidget(
+                       "map_viewport",         /* name */
+                       viewportWidgetClass,    /* widget class from Window.h */
+                       parent,                 /* parent widget */
+                       args,                   /* set some values */
+                       num_args);              /* number of values to set */
+
+    /*
+     * Create a map window.  We need to set the width and height to some
+     * value when we create it.  We will change it to the value we want
+     * later
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNwidth,  100); num_args++;
+    XtSetArg(args[num_args], XtNheight, 100); num_args++;
+    XtSetArg(args[num_args], XtNtranslations,
+               XtParseTranslationTable(map_translations));     num_args++;
+
+    wp->w = map = XtCreateManagedWidget(
+               "map",                  /* name */
+               windowWidgetClass,      /* widget class from Window.h */
+               viewport,               /* parent widget */
+               args,                   /* set some values */
+               num_args);              /* number of values to set */
+
+    XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
+
+    map_info = wp->map_information =
+                       (struct map_info_t *) alloc(sizeof(struct map_info_t));
+
+    map_info->viewport_width = map_info->viewport_height = 0;
+
+    /* reset the "new entry" indicators */
+    (void) memset((genericptr_t) map_info->t_start, (char) COLNO,
+                       sizeof(map_info->t_start));
+    (void) memset((genericptr_t) map_info->t_stop, (char) 0,
+                       sizeof(map_info->t_stop));
+
+    /* we probably want to restrict this to the 1st map window only */
+    if (appResources.tile_file[0] && init_tiles(wp)) {
+       map_info->is_tile = TRUE;
+    } else {
+       init_text(wp);
+       map_info->is_tile = FALSE;
+    }
+
+
+    /*
+     * Initially, set the map widget to be the size specified by the
+     * widget rows and columns resources.  We need to do this to
+     * correctly set the viewport window size.  After the viewport is
+     * realized, then the map can resize to its normal size.
+     */
+    num_args = 0;
+    XtSetArg(args[num_args], XtNrows,    &rows);       num_args++;
+    XtSetArg(args[num_args], XtNcolumns, &columns);    num_args++;
+    XtGetValues(wp->w, args, num_args);
+
+    /* Don't bother with windows larger than ROWNOxCOLNO. */
+    if (columns > COLNO) columns = COLNO;
+    if (rows    > ROWNO) rows = ROWNO;
+
+#if 0 /* This is insufficient.  We now resize final window in winX.c */
+    /*
+     * Check for overrunning the size of the screen.  This does an ad hoc
+     * job.
+     *
+     * Width:  We expect that there is nothing but borders on either side
+     *         of the map window.  Use some arbitrary width to decide
+     *         when to shrink.
+     *
+     * Height: if the map takes up more than 1/2 of the screen height, start
+     *         reducing its size.
+     */
+    screen_height = HeightOfScreen(XtScreen(wp->w));
+    screen_width  = WidthOfScreen(XtScreen(wp->w));
+
+#define WOFF 50
+    if ((int)(columns*map_info->square_width) > screen_width-WOFF) {
+       columns = (screen_width-WOFF) / map_info->square_width;
+       if (columns == 0) columns = 1;
+    }
+
+    if ((int)(rows*map_info->square_height) > screen_height/2) {
+       rows = screen_height / (2*map_info->square_height);
+       if (rows == 0) rows = 1;
+    }
+#endif
+
+    set_map_size(wp, columns, rows);
+
+
+    /*
+     * If we have created our own popup, then realize it so that the
+     * viewport is also realized.  Then resize the map window.
+     */
+    if (create_popup) {
+       XtRealizeWidget(wp->popup);
+       XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
+                       &wm_delete_window, 1);
+       set_map_size(wp, COLNO, ROWNO);
+    }
+
+    if (map_info->is_tile) {
+       map_all_stone(map_info);
+    }
+}
+
+/*
+ * Destroy this map window.
+ */
+void
+destroy_map_window(wp)
+    struct xwindow *wp;
+{
+    struct map_info_t *map_info = wp->map_information;
+
+    if (wp->popup)
+       nh_XtPopdown(wp->popup);
+
+    if (map_info) {
+       struct text_map_info_t *text_map = map_info->mtype.text_map;
+
+       /* Free allocated GCs. */
+       if (!map_info->is_tile) {
+#ifdef TEXTCOLOR
+           int i;
+
+           for (i = 0; i < CLR_MAX; i++) {
+               XtReleaseGC(wp->w, text_map->color_gcs[i]);
+               XtReleaseGC(wp->w, text_map->inv_color_gcs[i]);
+           }
+#else
+           XtReleaseGC(wp->w, text_map->copy_gc);
+           XtReleaseGC(wp->w, text_map->inv_copy_gc);
+#endif
+       }
+       /* free alloc'ed text information */
+       free((genericptr_t)text_map),   map_info->mtype.text_map = 0;
+
+       /* Free malloc'ed space. */
+       free((genericptr_t)map_info),  wp->map_information = 0;
+    }
+
+       /* Destroy map widget. */
+    if (wp->popup && !wp->keep_window)
+       XtDestroyWidget(wp->popup),  wp->popup = (Widget)0;
+
+    if (wp->keep_window)
+       XtRemoveCallback(wp->w, XtNexposeCallback, map_exposed, (XtPointer)0);
+    else
+       wp->type = NHW_NONE;    /* allow re-use */
+}
+
+
+
+boolean exit_x_event;  /* exit condition for the event loop */
+/*******
+pkey(k)
+    int k;
+{
+    printf("key = '%s%c'\n", (k<32) ? "^":"", (k<32) ? '@'+k : k);
+}
+******/
+
+/*
+ * Main X event loop.  Here we accept and dispatch X events.  We only exit
+ * under certain circumstances.
+ */
+int
+x_event(exit_condition)
+    int exit_condition;
+{
+    XEvent  event;
+    int     retval = 0;
+    boolean keep_going = TRUE;
+
+    /* Hold globals so function is re-entrant */
+    boolean hold_exit_x_event = exit_x_event;
+
+    click_button = NO_CLICK;   /* reset click exit condition */
+    exit_x_event = FALSE;      /* reset callback exit condition */
+
+    /*
+     * Loop until we get a sent event, callback exit, or are accepting key
+     * press and button press events and we receive one.
+     */
+    if((exit_condition == EXIT_ON_KEY_PRESS ||
+       exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount)
+       goto try_test;
+
+    do {
+       XtAppNextEvent(app_context, &event);
+       XtDispatchEvent(&event);
+
+       /* See if we can exit. */
+    try_test:
+       switch (exit_condition) {
+           case EXIT_ON_SENT_EVENT: {
+               XAnyEvent *any = (XAnyEvent *) &event;
+               if (any->send_event) {
+                   retval = 0;
+                   keep_going = FALSE;
+               }
+               break;
+           }
+           case EXIT_ON_EXIT:
+               if (exit_x_event) {
+                   incount = 0;
+                   retval = 0;
+                   keep_going = FALSE;
+               }
+               break;
+           case EXIT_ON_KEY_PRESS:
+               if (incount != 0) {
+                   /* get first pressed key */
+                   --incount;
+                   retval = inbuf[inptr];
+                   inptr = (inptr+1) % INBUF_SIZE;
+                   /* pkey(retval); */
+                   keep_going = FALSE;
+               }
+               break;
+           case EXIT_ON_KEY_OR_BUTTON_PRESS:
+               if (incount != 0 || click_button != NO_CLICK) {
+                   if (click_button != NO_CLICK) {     /* button press */
+                       /* click values are already set */
+                       retval = 0;
+                   } else {                            /* key press */
+                       /* get first pressed key */
+                       --incount;
+                       retval = inbuf[inptr];
+                       inptr = (inptr+1) % INBUF_SIZE;
+                       /* pkey(retval); */
+                   }
+                   keep_going = FALSE;
+               }
+               break;
+           default:
+               panic("x_event: unknown exit condition %d\n", exit_condition);
+               break;
+       }
+    } while (keep_going);
+
+    /* Restore globals */
+    exit_x_event = hold_exit_x_event;
+
+    return retval;
+}
+
+/*winmap.c*/