1 /* NetHack 3.6 winmap.c $NHDT-Date: 1455389908 2016/02/13 18:58:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.29 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
7 * + global functions print_glyph() and cliparound()
8 * + the map window routines
9 * + the char and pointer input routines
12 * + We don't really have a good way to get the compiled ROWNO and
13 * COLNO as defaults. They are hardwired to the current "correct"
14 * values in the Window widget. I am _not_ in favor of including
15 * some nethack include file for Window.c.
19 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
22 #include <X11/Intrinsic.h>
23 #include <X11/StringDefs.h>
24 #include <X11/Shell.h>
25 #include <X11/Xaw/Cardinals.h>
26 #include <X11/Xaw/Scrollbar.h>
27 #include <X11/Xaw/Viewport.h>
28 #include <X11/Xaw/Label.h>
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
32 #ifdef PRESERVE_NO_SYSV
36 #undef PRESERVE_NO_SYSV
39 #include "xwindow.h" /* map widget declarations */
50 extern short glyph2tile[];
51 extern int total_tiles_used;
53 /* Define these if you really want a lot of junk on your screen. */
54 /* #define VERBOSE */ /* print various info & events as they happen */
55 /* #define VERBOSE_UPDATE */ /* print screen update bounds */
56 /* #define VERBOSE_INPUT */ /* print input events */
58 #define USE_WHITE /* almost always use white as a tile cursor border */
60 static boolean FDECL(init_tiles, (struct xwindow *));
61 static void FDECL(set_button_values, (Widget, int, int, unsigned));
62 static void FDECL(map_check_size_change, (struct xwindow *));
63 static void FDECL(map_update, (struct xwindow *, int, int, int, int,
65 static void FDECL(init_text, (struct xwindow *));
66 static void FDECL(map_exposed, (Widget, XtPointer, XtPointer));
67 static void FDECL(set_gc, (Widget, Font, const char *, Pixel, GC *, GC *));
68 static void FDECL(get_text_gc, (struct xwindow *, Font));
69 static void FDECL(get_char_info, (struct xwindow *));
70 static void FDECL(display_cursor, (struct xwindow *));
79 #define MAX_PXM_SLOTS 100
80 struct pxm_slot_t pxm_slot[MAX_PXM_SLOTS];
83 /* Global functions ======================================================= */
86 X11_print_glyph(window, x, y, glyph, bkglyph)
92 struct map_info_t *map_info;
93 boolean update_bbox = FALSE;
96 if (window_list[window].type != NHW_MAP) {
97 impossible("print_glyph: can (currently) only print to map windows");
100 map_info = window_list[window].map_information;
102 /* update both the tile and text backing stores */
104 unsigned short *t_ptr = &map_info->tile_map.glyphs[y][x].glyph;
106 if (*t_ptr != glyph) {
108 if (map_info->is_tile)
114 register unsigned char *ch_ptr;
119 register unsigned char *co_ptr;
122 /* map glyph to character and color */
123 (void) mapglyph(glyph, &och, &color, &special, x, y, 0);
126 if (special != map_info->tile_map.glyphs[y][x].special) {
127 map_info->tile_map.glyphs[y][x].special = special;
131 /* Only update if we need to. */
132 ch_ptr = &map_info->text_map.text[y][x];
135 if (!map_info->is_tile)
139 co_ptr = &map_info->text_map.colors[y][x];
140 colordif = (((special & MG_PET) != 0 && iflags.hilite_pet)
141 || ((special & MG_OBJPILE) != 0 && iflags.hilite_pile)
142 || ((special & (MG_DETECT | MG_BW_LAVA)) != 0))
144 if (*co_ptr != (uchar) (color + colordif)) {
145 *co_ptr = (uchar) (color + colordif);
146 if (!map_info->is_tile)
152 if (update_bbox) { /* update row bbox */
153 if ((uchar) x < map_info->t_start[y])
154 map_info->t_start[y] = x;
155 if ((uchar) x > map_info->t_stop[y])
156 map_info->t_stop[y] = x;
162 * The is the tty clip call. Since X can resize at any time, we can't depend
163 * on this being defined.
173 #endif /* CLIPPING */
175 /* End global functions =================================================== */
177 #include "tile2x11.h"
180 * We're expecting to never read more than one tile file per session.
181 * If this is false, then we can make an array of this information,
182 * or just keep it on a per-window basis.
184 Pixmap tile_pixmap = None;
186 Pixmap tile_clipmask = None;
188 /*JP #ifdef USE_XPM*/
192 #define TILE_WIDTH appResources.tile_width
193 #define TILE_HEIGHT appResources.tile_height
196 static int tile_width;
197 static int tile_height;
198 static int tile_count;
199 static XImage *tile_image = 0;
203 * This structure is used for small bitmaps that are used for annotating
204 * tiles. For example, a "heart" annotates pets.
206 struct tile_annotation {
209 unsigned int width, height;
210 int hotx, hoty; /* not currently used */
213 static struct tile_annotation pet_annotation;
214 static struct tile_annotation pile_annotation;
217 init_annotation(annotation, filename, colorpixel)
218 struct tile_annotation *annotation;
222 Display *dpy = XtDisplay(toplevel);
224 if (0 != XReadBitmapFile(dpy, XtWindow(toplevel), filename,
225 &annotation->width, &annotation->height,
226 &annotation->bitmap, &annotation->hotx,
227 &annotation->hoty)) {
230 Sprintf(buf, "Failed to load %s", filename);
234 annotation->foreground = colorpixel;
238 * Put the tile image on the server.
240 * We can't send the image to the server until the top level
241 * is realized. When the tile file is first processed, the top
242 * level is not realized. This routine is called after we
243 * realize the top level, but before we start resizing the
249 Display *dpy = XtDisplay(toplevel);
251 unsigned int width, height;
254 return; /* no tiles */
256 height = tile_image->height;
257 width = tile_image->width;
259 tile_pixmap = XCreatePixmap(dpy, XtWindow(toplevel), width, height,
260 DefaultDepth(dpy, DefaultScreen(dpy)));
262 XPutImage(dpy, tile_pixmap, DefaultGC(dpy, DefaultScreen(dpy)),
263 tile_image, 0, 0, 0, 0, /* src, dest top left */
267 /* if we let XDestroyImage() handle it, our tracking will be off */
268 if (tile_image->data)
269 free((genericptr_t) tile_image->data), tile_image->data = 0;
271 XDestroyImage(tile_image); /* data bytes free'd also */
276 XpmAttributes attributes;
283 XtSetArg(args[0], XtNcolormap, &cmap);
284 XtGetValues(toplevel, args, ONE);
286 attributes.valuemask = XpmCloseness | XpmColormap;
287 attributes.colormap = cmap;
288 attributes.closeness = 25000;
290 XpmCreatePixmapFromXpmImage(
299 val.function = GXcopy;
300 val.clip_mask = tile_clipmask;
305 GCFunction | GCClipMask,
309 XpmFreeXpmImage(&tile_image);
314 init_annotation(&pet_annotation, appResources.pet_mark_bitmap,
315 appResources.pet_mark_color);
316 init_annotation(&pile_annotation, appResources.pilemark_bitmap,
317 appResources.pilemark_color);
321 * Open and read the tile file. Return TRUE if there were no problems.
322 * Return FALSE otherwise.
329 XpmAttributes attributes;
332 FILE *fp = (FILE *) 0;
334 unsigned char *cp, *colormap = (unsigned char *) 0;
335 unsigned char *tb, *tile_bytes = (unsigned char *) 0;
337 XColor *colors = (XColor *) 0;
344 Display *dpy = XtDisplay(toplevel);
345 Screen *screen = DefaultScreenOfDisplay(dpy);
346 struct map_info_t *map_info = (struct map_info_t *) 0;
347 struct tile_map_info_t *tile_info = (struct tile_map_info_t *) 0;
348 unsigned int image_height = 0, image_width = 0;
349 boolean result = TRUE;
353 /* already have tile information */
354 if (tile_pixmap != None)
357 map_info = wp->map_information;
358 tile_info = &map_info->tile_map;
359 (void) memset((genericptr_t) tile_info, 0,
360 sizeof(struct tile_map_info_t));
362 /* no tile file name, no tile information */
363 if (!appResources.tile_file[0]) {
369 attributes.valuemask = XpmCloseness;
370 attributes.closeness = 25000;
372 # ifndef X11LARGETILE
373 errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image,
376 errorcode = XpmReadFileToXpmImage(appResources.tile_file, &tile_image,
380 # ifndef X11LARGETILE
381 if (errorcode == XpmColorFailed) {
382 Sprintf(buf, "Insufficient colors available to load %s.",
383 appResources.tile_file);
385 X11_raw_print("Try closing other colorful applications and restart.");
386 X11_raw_print("Attempting to load with inferior colors.");
387 attributes.closeness = 50000;
388 errorcode = XpmReadFileToImage(dpy, appResources.tile_file,
389 &tile_image, 0, &attributes);
393 if (errorcode != XpmSuccess) {
394 if (errorcode == XpmColorFailed) {
395 Sprintf(buf, "Insufficient colors available to load %s.",
396 appResources.tile_file);
399 Sprintf(buf, "Failed to load %s: %s", appResources.tile_file,
400 XpmGetErrorString(errorcode));
404 X11_raw_print("Switching to text-based mode.");
409 TILE_PER_COL = tile_image.width / TILE_WIDTH;
411 /* assume a fixed number of tiles per row */
412 if (tile_image->width % TILES_PER_ROW != 0
413 || tile_image->width <= TILES_PER_ROW) {
415 "%s is not a multiple of %d (number of tiles/row) pixels wide",
416 appResources.tile_file, TILES_PER_ROW);
418 XDestroyImage(tile_image);
424 /* infer tile dimensions from image size and TILES_PER_ROW */
425 image_width = tile_image->width;
426 image_height = tile_image->height;
428 tile_count = total_tiles_used;
429 if ((tile_count % TILES_PER_ROW) != 0) {
430 tile_count += TILES_PER_ROW - (tile_count % TILES_PER_ROW);
432 tile_width = image_width / TILES_PER_ROW;
433 tile_height = image_height / (tile_count / TILES_PER_ROW);
436 /* any less than 16 colours makes tiles useless */
437 ddepth = DefaultDepthOfScreen(screen);
439 X11_raw_print("need a screen depth of at least 4");
444 fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE);
446 X11_raw_print("can't open tile file");
451 if ((int) fread((char *) &header, sizeof(header), 1, fp) != 1) {
452 X11_raw_print("read of header failed");
457 if (header.version != 2) {
458 Sprintf(buf, "Wrong tile file version, expected 2, got %lu",
466 X11 tile file:\n version %ld\n ncolors %ld\n \
467 tile width %ld\n tile height %ld\n per row %ld\n \
469 header.version, header.ncolors, header.tile_width,
470 header.tile_height, header.per_row, header.ntiles);
473 size = 3 * header.ncolors;
474 colormap = (unsigned char *) alloc((unsigned) size);
475 if ((int) fread((char *) colormap, 1, size, fp) != size) {
476 X11_raw_print("read of colormap failed");
481 colors = (XColor *) alloc(sizeof(XColor) * (unsigned) header.ncolors);
482 for (i = 0; i < header.ncolors; i++) {
483 cp = colormap + (3 * i);
484 colors[i].red = cp[0] * 256;
485 colors[i].green = cp[1] * 256;
486 colors[i].blue = cp[2] * 256;
490 if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i])
491 && !nhApproxColor(screen, DefaultColormapOfScreen(screen),
492 (char *) 0, &colors[i])) {
493 Sprintf(buf, "%dth out of %ld color allocation failed", i,
501 size = header.tile_height * header.tile_width;
503 * This alloc() and the one below require 32-bit ints, since tile_bytes
504 * is currently ~200k and alloc() takes an int
506 tile_count = header.ntiles;
507 if ((tile_count % header.per_row) != 0) {
508 tile_count += header.per_row - (tile_count % header.per_row);
510 tile_bytes = (unsigned char *) alloc((unsigned) tile_count * size);
511 if ((int) fread((char *) tile_bytes, size, tile_count, fp)
513 X11_raw_print("read of tile bytes failed");
518 if (header.ntiles < (unsigned) total_tiles_used) {
519 Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu",
520 total_tiles_used, header.ntiles);
526 if (appResources.double_tile_size) {
527 tile_width = 2 * header.tile_width;
528 tile_height = 2 * header.tile_height;
530 tile_width = header.tile_width;
531 tile_height = header.tile_height;
534 image_height = tile_height * tile_count / header.per_row;
535 image_width = tile_width * header.per_row;
537 /* calculate bitmap_pad */
545 tile_image = XCreateImage(dpy, DefaultVisualOfScreen(screen),
547 ZPixmap, /* format */
549 (char *) 0, /* data */
550 image_width, /* width */
551 image_height, /* height */
552 bitmap_pad, /* bit pad */
553 0); /* bytes_per_line */
556 impossible("init_tiles: insufficient memory to create image");
558 /* now we know the physical memory requirements, we can allocate space */
560 (char *) alloc((unsigned) tile_image->bytes_per_line * image_height);
562 if (appResources.double_tile_size) {
563 unsigned long *expanded_row =
564 (unsigned long *) alloc(sizeof(unsigned long) * image_width);
567 for (y = 0; y < (int) image_height; y++) {
568 for (x = 0; x < (int) image_width / 2; x++)
569 expanded_row[2 * x] = expanded_row[(2 * x) + 1] =
572 for (x = 0; x < (int) image_width; x++)
573 XPutPixel(tile_image, x, y, expanded_row[x]);
575 y++; /* duplicate row */
576 for (x = 0; x < (int) image_width; x++)
577 XPutPixel(tile_image, x, y, expanded_row[x]);
579 free((genericptr_t) expanded_row);
582 for (tb = tile_bytes, y = 0; y < (int) image_height; y++)
583 for (x = 0; x < (int) image_width; x++, tb++)
584 XPutPixel(tile_image, x, y, colors[*tb].pixel);
586 #endif /* ?USE_XPM */
588 /* fake an inverted tile by drawing a border around the edges */
590 /* use white or black as the border */
591 mask = GCFunction | GCForeground | GCGraphicsExposures;
592 values.graphics_exposures = False;
593 values.foreground = WhitePixelOfScreen(screen);
594 values.function = GXcopy;
595 tile_info->white_gc = XtGetGC(wp->w, mask, &values);
596 values.graphics_exposures = False;
597 values.foreground = BlackPixelOfScreen(screen);
598 values.function = GXcopy;
599 tile_info->black_gc = XtGetGC(wp->w, mask, &values);
602 * Use xor so we don't have to check for special colors. Xor white
603 * against the upper left pixel of the corridor so that we have a
604 * white rectangle when in a corridor.
606 mask = GCFunction | GCForeground | GCGraphicsExposures;
607 values.graphics_exposures = False;
609 WhitePixelOfScreen(screen)
610 # ifndef X11LARGETILE
611 ^ XGetPixel(tile_image, 0,
612 tile_height * glyph2tile[cmap_to_glyph(S_corr)]);
614 ^ XGetPixel(tile_image,
615 tile_width*(glyph2tile[cmap_to_glyph(S_corr)]%TILE_PER_COL),
616 tile_height*(glyph2tile[cmap_to_glyph(S_corr)]/TILE_PER_COL));
618 values.function = GXxor;
619 tile_info->white_gc = XtGetGC(wp->w, mask, &values);
621 mask = GCFunction | GCGraphicsExposures;
622 values.function = GXCopy;
623 values.graphics_exposures = False;
624 tile_info->black_gc = XtGetGC(wp->w, mask, &values);
625 #endif /* USE_WHITE */
632 free((genericptr_t) colormap);
634 free((genericptr_t) tile_bytes);
636 free((genericptr_t) colors);
640 for(i = 0; i < MAX_PXM_SLOTS; i++){
642 pxm_slot[i].bg = pxm_slot[i].fg = -99;
643 pxm_slot[i].pixmap=0;
649 if (result) { /* succeeded */
651 tile_info->square_height = tile_height;
652 tile_info->square_width = tile_width;
654 tile_info->square_height = TILE_HEIGHT;
655 tile_info->square_width = TILE_WIDTH;
657 tile_info->square_ascent = 0;
658 tile_info->square_lbearing = 0;
659 tile_info->image_width = image_width;
660 tile_info->image_height = image_height;
667 * Make sure the map's cursor is always visible.
670 check_cursor_visibility(wp)
674 Widget viewport, horiz_sb, vert_sb;
675 float top, shown, cursor_middle;
676 Boolean do_call, adjusted = False;
681 viewport = XtParent(wp->w);
682 horiz_sb = XtNameToWidget(viewport, "horizontal");
683 vert_sb = XtNameToWidget(viewport, "vertical");
685 /* All values are relative to currently visible area */
687 #define V_BORDER 0.25 /* if this far from vert edge, shift */
688 #define H_BORDER 0.25 /* if this from from horiz edge, shift */
690 #define H_DELTA 0.25 /* distance of horiz shift */
691 #define V_DELTA 0.25 /* distance of vert shift */
694 XtSetArg(arg[0], XtNshown, &shown);
695 XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top);
696 XtGetValues(horiz_sb, arg, TWO);
698 /* [ALI] Don't assume map widget is the same size as actual map */
699 if (wp->map_information->is_tile)
700 cursor_middle = wp->map_information->tile_map.square_width;
702 cursor_middle = wp->map_information->text_map.square_width;
703 cursor_middle = (wp->cursx + 0.5) * cursor_middle / wp->pixel_width;
707 if (cursor_middle < top) {
709 } else if (cursor_middle < top + shown * H_BORDER) {
710 s = " close to left";
711 } else if (cursor_middle > (top + shown)) {
712 s = " outside right";
713 } else if (cursor_middle > (top + shown - shown * H_BORDER)) {
714 s = " close to right";
718 printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s);
721 if (cursor_middle < top) {
722 top = cursor_middle - shown * H_DELTA;
725 } else if (cursor_middle < top + shown * H_BORDER) {
726 top -= shown * H_DELTA;
729 } else if (cursor_middle > (top + shown)) {
730 top = cursor_middle - shown * H_DELTA;
733 if (top + shown > 1.0)
735 } else if (cursor_middle > (top + shown - shown * H_BORDER)) {
736 top += shown * H_DELTA;
737 if (top + shown > 1.0)
744 XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
750 XtSetArg(arg[0], XtNshown, &shown);
751 XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top);
752 XtGetValues(vert_sb, arg, TWO);
754 if (wp->map_information->is_tile)
755 cursor_middle = wp->map_information->tile_map.square_height;
757 cursor_middle = wp->map_information->text_map.square_height;
758 cursor_middle = (wp->cursy + 0.5) * cursor_middle / wp->pixel_height;
762 if (cursor_middle < top) {
764 } else if (cursor_middle < top + shown * V_BORDER) {
766 } else if (cursor_middle > (top + shown)) {
768 } else if (cursor_middle > (top + shown - shown * V_BORDER)) {
769 s = " close to bottom";
773 printf("%sVert: shown = %3.2f, top = %3.2f%s", horiz_sb ? "; " : "",
777 if (cursor_middle < top) {
778 top = cursor_middle - shown * V_DELTA;
781 } else if (cursor_middle < top + shown * V_BORDER) {
782 top -= shown * V_DELTA;
785 } else if (cursor_middle > (top + shown)) {
786 top = cursor_middle - shown * V_DELTA;
789 if (top + shown > 1.0)
791 } else if (cursor_middle > (top + shown - shown * V_BORDER)) {
792 top += shown * V_DELTA;
793 if (top + shown > 1.0)
800 XtCallCallbacks(vert_sb, XtNjumpProc, &top);
805 /* make sure cursor is displayed during dowhatis.. */
810 if (horiz_sb || vert_sb)
816 * Check to see if the viewport has grown smaller. If so, then we want to
818 * sure that the cursor is still on the screen. We do this to keep the cursor
819 * on the screen when the user resizes the nethack window.
822 map_check_size_change(wp)
825 struct map_info_t *map_info = wp->map_information;
827 Dimension new_width, new_height;
830 viewport = XtParent(wp->w);
832 XtSetArg(arg[0], XtNwidth, &new_width);
833 XtSetArg(arg[1], XtNheight, &new_height);
834 XtGetValues(viewport, arg, TWO);
836 /* Only do cursor check if new size is smaller. */
837 if (new_width < map_info->viewport_width
838 || new_height < map_info->viewport_height) {
839 /* [ALI] If the viewport was larger than the map (and so the map
840 * widget was contrained to be larger than the actual map) then we
841 * may be able to shrink the map widget as the viewport shrinks.
843 if (map_info->is_tile) {
844 wp->pixel_width = map_info->tile_map.square_width * COLNO;
845 wp->pixel_height = map_info->tile_map.square_height * ROWNO;
847 wp->pixel_width = map_info->text_map.square_width * COLNO;
848 wp->pixel_height = map_info->text_map.square_height * ROWNO;
851 if (wp->pixel_width < new_width)
852 wp->pixel_width = new_width;
853 if (wp->pixel_height < new_height)
854 wp->pixel_height = new_height;
855 XtSetArg(arg[0], XtNwidth, wp->pixel_width);
856 XtSetArg(arg[1], XtNheight, wp->pixel_height);
857 XtSetValues(wp->w, arg, TWO);
859 check_cursor_visibility(wp);
862 map_info->viewport_width = new_width;
863 map_info->viewport_height = new_height;
865 /* [ALI] These may have changed if the user has re-sized the viewport */
866 XtSetArg(arg[0], XtNwidth, &wp->pixel_width);
867 XtSetArg(arg[1], XtNheight, &wp->pixel_height);
868 XtGetValues(wp->w, arg, TWO);
872 * Fill in parameters "regular" and "inverse" with newly created GCs.
873 * Using the given background pixel and the foreground pixel optained
874 * by querying the widget with the resource name.
877 set_gc(w, font, resource_name, bgpixel, regular, inverse)
880 const char *resource_name;
882 GC *regular, *inverse;
885 XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
889 XtSetArg(arg[0], (char *) resource_name, &curpixel);
890 XtGetValues(w, arg, ONE);
892 values.foreground = curpixel;
893 values.background = bgpixel;
894 values.function = GXcopy;
896 *regular = XtGetGC(w, mask, &values);
897 values.foreground = bgpixel;
898 values.background = curpixel;
899 values.function = GXcopy;
901 *inverse = XtGetGC(w, mask, &values);
905 * Create the GC's for each color.
907 * I'm not sure if it is a good idea to have a GC for each color (and
908 * inverse). It might be faster to just modify the foreground and
909 * background colors on the current GC as needed.
912 get_text_gc(wp, font)
916 struct map_info_t *map_info = wp->map_information;
920 /* Get background pixel. */
921 XtSetArg(arg[0], XtNbackground, &bgpixel);
922 XtGetValues(wp->w, arg, ONE);
925 #define set_color_gc(nh_color, resource_name) \
926 set_gc(wp->w, font, resource_name, bgpixel, \
927 &map_info->text_map.color_gcs[nh_color], \
928 &map_info->text_map.inv_color_gcs[nh_color]);
930 set_color_gc(CLR_BLACK, XtNblack);
931 set_color_gc(CLR_RED, XtNred);
932 set_color_gc(CLR_GREEN, XtNgreen);
933 set_color_gc(CLR_BROWN, XtNbrown);
934 set_color_gc(CLR_BLUE, XtNblue);
935 set_color_gc(CLR_MAGENTA, XtNmagenta);
936 set_color_gc(CLR_CYAN, XtNcyan);
937 set_color_gc(CLR_GRAY, XtNgray);
938 set_color_gc(NO_COLOR, XtNforeground);
939 set_color_gc(CLR_ORANGE, XtNorange);
940 set_color_gc(CLR_BRIGHT_GREEN, XtNbright_green);
941 set_color_gc(CLR_YELLOW, XtNyellow);
942 set_color_gc(CLR_BRIGHT_BLUE, XtNbright_blue);
943 set_color_gc(CLR_BRIGHT_MAGENTA, XtNbright_magenta);
944 set_color_gc(CLR_BRIGHT_CYAN, XtNbright_cyan);
945 set_color_gc(CLR_WHITE, XtNwhite);
947 set_gc(wp->w, font, XtNforeground, bgpixel,
948 &map_info->text_map.copy_gc,
949 &map_info->text_map.inv_copy_gc);
954 * Display the cursor on the map window.
960 /* Redisplay the cursor location inverted. */
961 map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE);
965 * Check if there are any changed characters. If so, then plaster them on
969 display_map_window(wp)
973 struct map_info_t *map_info = wp->map_information;
975 if ((Is_rogue_level(&u.uz) ? map_info->is_tile
976 : (map_info->is_tile != iflags.wc_tiled_map))
977 && map_info->tile_map.image_width) {
978 /* changed map display mode, re-display the full map */
979 (void) memset((genericptr_t) map_info->t_start, (char) 0,
980 sizeof(map_info->t_start));
981 (void) memset((genericptr_t) map_info->t_stop, (char) (COLNO - 1),
982 sizeof(map_info->t_stop));
983 map_info->is_tile = iflags.wc_tiled_map && !Is_rogue_level(&u.uz);
984 XClearWindow(XtDisplay(wp->w), XtWindow(wp->w));
985 set_map_size(wp, COLNO, ROWNO);
986 check_cursor_visibility(wp);
987 highlight_yn(TRUE); /* change fg/bg to match map */
988 } else if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) {
989 register unsigned int x = wp->prevx, y = wp->prevy;
992 * Previous cursor position is not the same as the current
993 * cursor position, update the old cursor position.
995 if (x < map_info->t_start[y])
996 map_info->t_start[y] = x;
997 if (x > map_info->t_stop[y])
998 map_info->t_stop[y] = x;
1001 for (row = 0; row < ROWNO; row++) {
1002 if (map_info->t_start[row] <= map_info->t_stop[row]) {
1003 map_update(wp, row, row, (int) map_info->t_start[row],
1004 (int) map_info->t_stop[row], FALSE);
1005 map_info->t_start[row] = COLNO - 1;
1006 map_info->t_stop[row] = 0;
1010 wp->prevx = wp->cursx; /* adjust old cursor position */
1011 wp->prevy = wp->cursy;
1015 * Set all map tiles to S_stone
1018 map_all_stone(map_info)
1019 struct map_info_t *map_info;
1022 unsigned short stone = cmap_to_glyph(S_stone);
1024 for (x = 0; x < COLNO; x++)
1025 for (y = 0; y < ROWNO; y++) {
1026 map_info->tile_map.glyphs[y][x].glyph = stone;
1027 map_info->tile_map.glyphs[y][x].special = 0;
1032 * Fill the saved screen characters with the "clear" tile or character.
1034 * Flush out everything by resetting the "new" bounds and calling
1035 * display_map_window().
1038 clear_map_window(wp)
1041 struct map_info_t *map_info = wp->map_information;
1043 /* update both tile and text backing store, then update */
1045 map_all_stone(map_info);
1046 (void) memset((genericptr_t) map_info->text_map.text, ' ',
1047 sizeof map_info->text_map.text);
1049 (void) memset((genericptr_t) map_info->text_map.colors, NO_COLOR,
1050 sizeof map_info->text_map.colors);
1053 /* force a full update */
1054 (void) memset((genericptr_t) map_info->t_start, (char) 0,
1055 sizeof map_info->t_start);
1056 (void) memset((genericptr_t) map_info->t_stop, (char) COLNO - 1,
1057 sizeof map_info->t_stop);
1058 display_map_window(wp);
1062 * Retreive the font associated with the map window and save attributes
1063 * that are used when updating it.
1070 struct map_info_t *map_info = wp->map_information;
1071 struct text_map_info_t *text_map = &map_info->text_map;
1073 fs = WindowFontStruct(wp->w);
1074 text_map->square_width = fs->max_bounds.width;
1075 text_map->square_height = fs->max_bounds.ascent + fs->max_bounds.descent;
1076 text_map->square_ascent = fs->max_bounds.ascent;
1077 text_map->square_lbearing = -fs->min_bounds.lbearing;
1080 printf("Font information:\n");
1081 printf("fid = %ld, direction = %d\n", fs->fid, fs->direction);
1082 printf("first = %d, last = %d\n",
1083 fs->min_char_or_byte2, fs->max_char_or_byte2);
1084 printf("all chars exist? %s\n", fs->all_chars_exist ? "yes" : "no");
1085 printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
1086 fs->min_bounds.lbearing, fs->min_bounds.rbearing,
1087 fs->min_bounds.width, fs->min_bounds.ascent,
1088 fs->min_bounds.descent, fs->min_bounds.attributes);
1089 printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
1090 fs->max_bounds.lbearing, fs->max_bounds.rbearing,
1091 fs->max_bounds.width, fs->max_bounds.ascent,
1092 fs->max_bounds.descent, fs->max_bounds.attributes);
1093 printf("per_char = 0x%lx\n", (unsigned long) fs->per_char);
1094 printf("Text: (max) width = %d, height = %d\n",
1095 text_map->square_width, text_map->square_height);
1098 if (fs->min_bounds.width != fs->max_bounds.width)
1099 X11_raw_print("Warning: map font is not monospaced!");
1105 #define INBUF_SIZE 64
1106 static int inbuf[INBUF_SIZE];
1107 static int incount = 0;
1108 static int inptr = 0; /* points to valid data */
1111 * Keyboard and button event handler for map window.
1114 map_input(w, event, params, num_params)
1118 Cardinal *num_params;
1121 XButtonEvent *button;
1122 boolean meta = FALSE;
1124 Cardinal in_nparams = (num_params ? *num_params : 0);
1126 char keystring[MAX_KEY_STRING];
1131 switch (event->type) {
1133 if (!iflags.wc_mouse_support)
1136 button = (XButtonEvent *) event;
1137 #ifdef VERBOSE_INPUT
1138 printf("button press\n");
1140 if (in_nparams > 0 && (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
1141 Strcpy(keystring, params[0]);
1142 key = (XKeyEvent *) event; /* just in case */
1145 if (w != window_list[WIN_MAP].w) {
1146 #ifdef VERBOSE_INPUT
1147 printf("map_input called from wrong window\n");
1152 set_button_values(w, button->x, button->y, button->button);
1155 #ifdef VERBOSE_INPUT
1158 if (appResources.slow && input_func) {
1159 (*input_func)(w, event, params, num_params);
1164 * Don't use key_event_to_char() because we want to be able
1165 * to allow keys mapped to multiple characters.
1167 key = (XKeyEvent *) event;
1168 if (in_nparams > 0 && (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
1169 Strcpy(keystring, params[0]);
1172 * Assume that mod1 is really the meta key.
1174 meta = !!(key->state & Mod1Mask);
1176 nbytes = XLookupString(key, keystring, MAX_KEY_STRING,
1177 (KeySym *) 0, (XComposeStatus *) 0);
1179 nbytes = XLookupString(key, keystring, MAX_KEY_STRING,
1180 &keysym, (XComposeStatus *) 0);
1187 if(!iflags.num_pad){
1188 if(keysym == XK_KP_1 || keysym == XK_KP_End){
1192 else if(keysym == XK_KP_2 || keysym == XK_KP_Down){
1196 else if(keysym == XK_KP_3 || keysym == XK_KP_Page_Down){
1200 else if(keysym == XK_KP_4 || keysym == XK_KP_Left){
1204 else if(keysym == XK_KP_5 || keysym == XK_KP_Begin){
1208 else if(keysym == XK_KP_6 || keysym == XK_KP_Right){
1212 else if(keysym == XK_KP_7 || keysym == XK_KP_Home){
1216 else if(keysym == XK_KP_8 || keysym == XK_KP_Up){
1220 else if(keysym == XK_KP_9 || keysym == XK_KP_Page_Up){
1227 /* Modifier keys return a zero length string when pressed. */
1229 #ifdef VERBOSE_INPUT
1232 for (i = 0; i < nbytes; i++) {
1235 if (incount < INBUF_SIZE) {
1236 inbuf[(inptr + incount) % INBUF_SIZE] =
1237 ((int) c) + (meta ? 0x80 : 0);
1242 #ifdef VERBOSE_INPUT
1243 if (meta) /* meta will print as M<c> */
1244 (void) putchar('M');
1245 if (c < ' ') { /* ctrl will print as ^<c> */
1246 (void) putchar('^');
1252 #ifdef VERBOSE_INPUT
1253 printf("\" [%d bytes]\n", nbytes);
1259 impossible("unexpected X event, type = %d\n", (int) event->type);
1265 set_button_values(w, x, y, button)
1269 unsigned int button;
1272 struct map_info_t *map_info;
1274 wp = find_widget(w);
1275 map_info = wp->map_information;
1277 if (map_info->is_tile) {
1278 click_x = x / map_info->tile_map.square_width;
1279 click_y = y / map_info->tile_map.square_height;
1281 click_x = x / map_info->text_map.square_width;
1282 click_y = y / map_info->text_map.square_height;
1285 /* The values can be out of range if the map window has been resized
1286 to be larger than the max size. */
1287 if (click_x >= COLNO)
1288 click_x = COLNO - 1;
1289 if (click_y >= ROWNO)
1290 click_y = ROWNO - 1;
1292 /* Map all buttons but the first to the second click */
1293 click_button = (button == Button1) ? CLICK_1 : CLICK_2;
1297 * Map window expose callback.
1301 map_exposed(w, client_data, widget_data)
1303 XtPointer client_data; /* unused */
1304 XtPointer widget_data; /* expose event from Window widget */
1308 struct map_info_t *map_info;
1309 unsigned width, height;
1310 int start_row, stop_row, start_col, stop_col;
1311 XExposeEvent *event = (XExposeEvent *) widget_data;
1312 int t_height, t_width; /* tile/text height & width */
1316 if (!XtIsRealized(w) || event->count > 0)
1319 wp = find_widget(w);
1320 map_info = wp->map_information;
1321 if (wp->keep_window && !map_info)
1324 * The map is sent an expose event when the viewport resizes. Make sure
1325 * that the cursor is still in the viewport after the resize.
1327 map_check_size_change(wp);
1329 if (event) { /* called from button-event */
1332 width = event->width;
1333 height = event->height;
1337 width = wp->pixel_width;
1338 height = wp->pixel_height;
1341 * Convert pixels into INCLUSIVE text rows and columns.
1343 if (map_info->is_tile) {
1344 t_height = map_info->tile_map.square_height;
1345 t_width = map_info->tile_map.square_width;
1347 t_height = map_info->text_map.square_height;
1348 t_width = map_info->text_map.square_width;
1350 start_row = y / t_height;
1351 stop_row = ((y + height) / t_height)
1352 + ((((y + height) % t_height) == 0) ? 0 : 1) - 1;
1354 start_col = x / t_width;
1355 stop_col = ((x + width) / t_width)
1356 + ((((x + width) % t_width) == 0) ? 0 : 1) - 1;
1359 printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n", x, y,
1361 printf("chars %d x %d, rows %d to %d, columns %d to %d\n", t_height,
1362 t_width, start_row, stop_row, start_col, stop_col);
1365 /* Out of range values are possible if the map window is resized to be
1366 bigger than the largest expected value. */
1367 if (stop_row >= ROWNO)
1368 stop_row = ROWNO - 1;
1369 if (stop_col >= COLNO)
1370 stop_col = COLNO - 1;
1372 map_update(wp, start_row, stop_row, start_col, stop_col, FALSE);
1373 display_cursor(wp); /* make sure cursor shows up */
1377 * Do the actual work of the putting characters onto our X window. This
1378 * is called from the expose event routine, the display window (flush)
1379 * routine, and the display cursor routine. The last involves inverting
1380 * the foreground and background colors, which are also inverted when the
1381 * position's color is above CLR_MAX.
1383 * This works for rectangular regions (this includes one line rectangles).
1384 * The start and stop columns are *inclusive*.
1387 map_update(wp, start_row, stop_row, start_col, stop_col, inverted)
1389 int start_row, stop_row, start_col, stop_col;
1392 int win_start_row, win_start_col;
1393 struct map_info_t *map_info = wp->map_information;
1397 if (start_row < 0 || stop_row >= ROWNO) {
1398 impossible("map_update: bad row range %d-%d\n", start_row, stop_row);
1401 if (start_col < 0 || stop_col >= COLNO) {
1402 impossible("map_update: bad col range %d-%d\n", start_col, stop_col);
1406 #ifdef VERBOSE_UPDATE
1407 printf("update: [0x%x] %d %d %d %d\n",
1408 (int) wp->w, start_row, stop_row, start_col, stop_col);
1410 win_start_row = start_row;
1411 win_start_col = start_col;
1413 if (map_info->is_tile) {
1414 struct tile_map_info_t *tile_map = &map_info->tile_map;
1416 Display *dpy = XtDisplay(wp->w);
1417 Screen *screen = DefaultScreenOfDisplay(dpy);
1420 /* each slots ages */
1424 for(i = 0; i < MAX_PXM_SLOTS; i++)
1428 for (row = start_row; row <= stop_row; row++) {
1429 for (cur_col = start_col; cur_col <= stop_col; cur_col++) {
1430 #ifndef X11LARGETILE
1431 int glyph = tile_map->glyphs[row][cur_col].glyph;
1432 int tile = glyph2tile[glyph];
1434 int dest_x = cur_col * tile_map->square_width;
1435 int dest_y = row * tile_map->square_height;
1437 src_x = (tile % TILES_PER_ROW) * tile_width;
1438 src_y = (tile / TILES_PER_ROW) * tile_height;
1439 XCopyArea(dpy, tile_pixmap, XtWindow(wp->w),
1440 tile_map->black_gc, /* no grapics_expose */
1441 src_x, src_y, tile_width, tile_height,
1444 struct rm *lev = &levl[cur_col][row];
1445 int glyph = tile_map->glyphs[row][cur_col].glyph;
1446 int bg = back_to_glyph(cur_col, row);
1457 if(youmonst.data && (Blind || (viz_array && !cansee(cur_col, row))))
1460 bgtile = glyph2tile[bg];
1461 tile = glyph2tile[glyph];
1462 dest_x = cur_col * tile_map->square_width;
1463 dest_y = row * tile_map->square_height;
1464 bgsrc_x = (bgtile % TILE_PER_COL) * TILE_WIDTH;
1465 bgsrc_y = (bgtile / TILE_PER_COL) * TILE_HEIGHT;
1466 src_x = (tile % TILE_PER_COL) * TILE_WIDTH;
1467 src_y = (tile / TILE_PER_COL) * TILE_HEIGHT;
1474 for(i = 0; i < MAX_PXM_SLOTS; i++){
1475 if(tile == pxm_slot[i].fg && bgtile == pxm_slot[i].bg){
1481 /* no match found:dispose the oldest slot and compose pixmap */
1482 for(i = 0; i < MAX_PXM_SLOTS; i++)
1483 if(maxage < pxm_slot[i].age){
1485 maxage = pxm_slot[i].age;
1487 if(!pxm_slot[match].pixmap)
1488 pxm_slot[match].pixmap = XCreatePixmap(
1489 dpy, XtWindow(toplevel),
1490 TILE_WIDTH, TILE_HEIGHT, DefaultDepth(dpy, DefaultScreen(dpy)));
1491 XCopyArea(dpy, tile_pixmap, pxm_slot[match].pixmap,
1494 TILE_WIDTH, TILE_HEIGHT,
1497 XSetClipOrigin(dpy, tile_gc, 0 - src_x, 0 - src_y);
1499 XCopyArea(dpy, tile_pixmap, pxm_slot[match].pixmap,
1502 TILE_WIDTH, TILE_HEIGHT,
1504 pxm_slot[match].fg = tile;
1505 pxm_slot[match].bg = bgtile;
1508 pxm_slot[match].age = 0;
1509 XCopyArea(dpy, pxm_slot[match].pixmap, XtWindow(wp->w),
1512 TILE_WIDTH, TILE_HEIGHT,
1517 XCopyArea(dpy, tile_pixmap, XtWindow(wp->w),
1520 TILE_WIDTH, TILE_HEIGHT,
1525 #endif /* X11LARGETILE */
1527 if (glyph_is_pet(glyph) && iflags.hilite_pet) {
1528 /* draw pet annotation (a heart) */
1529 XSetForeground(dpy, tile_map->black_gc,
1530 pet_annotation.foreground);
1531 XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y);
1532 XSetClipMask(dpy, tile_map->black_gc,
1533 pet_annotation.bitmap);
1534 XCopyPlane(dpy, pet_annotation.bitmap, XtWindow(wp->w),
1535 tile_map->black_gc, 0, 0, pet_annotation.width,
1536 pet_annotation.height, dest_x, dest_y, 1);
1537 XSetClipOrigin(dpy, tile_map->black_gc, 0, 0);
1538 XSetClipMask(dpy, tile_map->black_gc, None);
1539 XSetForeground(dpy, tile_map->black_gc,
1540 BlackPixelOfScreen(screen));
1542 if ((tile_map->glyphs[row][cur_col].special & MG_OBJPILE)) {
1543 /* draw object pile annotation (a plus sign) */
1544 XSetForeground(dpy, tile_map->black_gc,
1545 pile_annotation.foreground);
1546 XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y);
1547 XSetClipMask(dpy, tile_map->black_gc,
1548 pile_annotation.bitmap);
1549 XCopyPlane(dpy, pile_annotation.bitmap, XtWindow(wp->w),
1550 tile_map->black_gc, 0, 0,
1551 pile_annotation.width, pile_annotation.height,
1553 XSetClipOrigin(dpy, tile_map->black_gc, 0, 0);
1554 XSetClipMask(dpy, tile_map->black_gc, None);
1555 XSetForeground(dpy, tile_map->black_gc,
1556 BlackPixelOfScreen(screen));
1562 XDrawRectangle(XtDisplay(wp->w), XtWindow(wp->w),
1564 /* kludge for white square... */
1565 (tile_map->glyphs[start_row][start_col].glyph
1566 == cmap_to_glyph(S_ice))
1567 ? tile_map->black_gc
1568 : tile_map->white_gc,
1572 start_col * tile_map->square_width,
1573 start_row * tile_map->square_height,
1574 tile_map->square_width - 1,
1575 tile_map->square_height - 1);
1578 struct text_map_info_t *text_map = &map_info->text_map;
1582 register char *c_ptr;
1584 int cur_col, color, win_ystart;
1587 for (row = start_row; row <= stop_row; row++) {
1589 text_map->square_ascent + (row * text_map->square_height);
1591 t_ptr = (char *) &(text_map->text[row][start_col]);
1592 c_ptr = (char *) &(text_map->colors[row][start_col]);
1593 cur_col = start_col;
1594 while (cur_col <= stop_col) {
1598 while ((cur_col + count) <= stop_col && *c_ptr == color) {
1602 if (color >= CLR_MAX) {
1607 XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
1610 ? text_map->inv_color_gcs[color]
1611 : text_map->color_gcs[color])
1613 ? text_map->inv_copy_gc
1614 : text_map->copy_gc),
1615 text_map->square_lbearing
1616 + (text_map->square_width * cur_col),
1617 win_ystart, t_ptr, count);
1619 /* move text pointer and column count */
1625 #else /* !TEXTCOLOR */
1627 int win_row, win_xstart;
1629 /* We always start at the same x window position and have
1630 the same character count. */
1631 win_xstart = text_map->square_lbearing
1632 + (win_start_col * text_map->square_width);
1633 count = stop_col - start_col + 1;
1635 for (row = start_row, win_row = win_start_row; row <= stop_row;
1637 XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
1638 inverted ? text_map->inv_copy_gc
1639 : text_map->copy_gc,
1641 text_map->square_ascent
1642 + (win_row * text_map->square_height),
1643 (char *) &(text_map->text[row][start_col]),
1647 #endif /* ?TEXTCOLOR */
1651 /* Adjust the number of rows and columns on the given map window */
1653 set_map_size(wp, cols, rows)
1655 Dimension cols, rows;
1660 if (wp->map_information->is_tile) {
1661 wp->pixel_width = wp->map_information->tile_map.square_width * cols;
1662 wp->pixel_height = wp->map_information->tile_map.square_height * rows;
1664 wp->pixel_width = wp->map_information->text_map.square_width * cols;
1665 wp->pixel_height = wp->map_information->text_map.square_height * rows;
1669 XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++;
1670 XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
1671 XtSetValues(wp->w, args, num_args);
1678 struct map_info_t *map_info = wp->map_information;
1679 struct text_map_info_t *text_map = &map_info->text_map;
1681 (void) memset((genericptr_t) text_map->text, ' ', sizeof text_map->text);
1683 (void) memset((genericptr_t) text_map->colors, NO_COLOR,
1684 sizeof text_map->colors);
1688 get_text_gc(wp, WindowFont(wp->w));
1691 static char map_translations[] = "#override\n\
1692 <Key>Left: scroll(4)\n\
1693 <Key>Right: scroll(6)\n\
1694 <Key>Up: scroll(8)\n\
1695 <Key>Down: scroll(2)\n\
1700 * The map window creation routine.
1703 create_map_window(wp, create_popup, parent)
1705 boolean create_popup; /* parent is a popup shell that we create */
1708 struct map_info_t *map_info; /* map info pointer */
1709 Widget map, viewport;
1712 Dimension rows, columns;
1714 int screen_width, screen_height;
1721 * Create a popup that accepts key and button events.
1724 XtSetArg(args[num_args], XtNinput, False);
1728 wp->popup = parent = XtCreatePopupShell("nethack",
1730 wp->popup = parent = XtCreatePopupShell("jnethack",
1732 topLevelShellWidgetClass,
1733 toplevel, args, num_args);
1735 * If we're here, then this is an auxiliary map window. If we're
1736 * cancelled via a delete window message, we should just pop down.
1741 XtSetArg(args[num_args], XtNallowHoriz, True);
1743 XtSetArg(args[num_args], XtNallowVert, True);
1746 XtSetArg(args[num_args], XtNforceBars, True);
1749 XtSetArg(args[num_args], XtNuseBottom, True);
1751 XtSetArg(args[num_args], XtNtranslations,
1752 XtParseTranslationTable(map_translations));
1754 viewport = XtCreateManagedWidget("map_viewport", /* name */
1755 viewportWidgetClass, /* from Window.h */
1756 parent, /* parent widget */
1757 args, /* set some values */
1758 num_args); /* number of values to set */
1761 * Create a map window. We need to set the width and height to some
1762 * value when we create it. We will change it to the value we want
1766 XtSetArg(args[num_args], XtNwidth, 100);
1768 XtSetArg(args[num_args], XtNheight, 100);
1770 XtSetArg(args[num_args], XtNtranslations,
1771 XtParseTranslationTable(map_translations));
1774 wp->w = map = XtCreateManagedWidget(
1776 windowWidgetClass, /* widget class from Window.h */
1777 viewport, /* parent widget */
1778 args, /* set some values */
1779 num_args); /* number of values to set */
1781 XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
1783 map_info = wp->map_information =
1784 (struct map_info_t *) alloc(sizeof(struct map_info_t));
1786 map_info->viewport_width = map_info->viewport_height = 0;
1788 /* reset the "new entry" indicators */
1789 (void) memset((genericptr_t) map_info->t_start, (char) COLNO,
1790 sizeof(map_info->t_start));
1791 (void) memset((genericptr_t) map_info->t_stop, (char) 0,
1792 sizeof(map_info->t_stop));
1794 /* we probably want to restrict this to the 1st map window only */
1795 map_info->is_tile = (init_tiles(wp) && iflags.wc_tiled_map);
1799 * Initially, set the map widget to be the size specified by the
1800 * widget rows and columns resources. We need to do this to
1801 * correctly set the viewport window size. After the viewport is
1802 * realized, then the map can resize to its normal size.
1805 XtSetArg(args[num_args], nhStr(XtNrows), &rows);
1807 XtSetArg(args[num_args], nhStr(XtNcolumns), &columns);
1809 XtGetValues(wp->w, args, num_args);
1811 /* Don't bother with windows larger than ROWNOxCOLNO. */
1812 if (columns > COLNO)
1817 set_map_size(wp, columns, rows);
1820 * If we have created our own popup, then realize it so that the
1821 * viewport is also realized. Then resize the map window.
1824 XtRealizeWidget(wp->popup);
1825 XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
1826 &wm_delete_window, 1);
1827 set_map_size(wp, COLNO, ROWNO);
1830 map_all_stone(map_info);
1834 * Destroy this map window.
1837 destroy_map_window(wp)
1840 struct map_info_t *map_info = wp->map_information;
1843 nh_XtPopdown(wp->popup);
1846 struct text_map_info_t *text_map = &map_info->text_map;
1848 /* Free allocated GCs. */
1852 for (i = 0; i < CLR_MAX; i++) {
1853 XtReleaseGC(wp->w, text_map->color_gcs[i]);
1854 XtReleaseGC(wp->w, text_map->inv_color_gcs[i]);
1857 XtReleaseGC(wp->w, text_map->copy_gc);
1858 XtReleaseGC(wp->w, text_map->inv_copy_gc);
1861 /* Free malloc'ed space. */
1862 free((genericptr_t) map_info);
1863 wp->map_information = 0;
1866 /* Destroy map widget. */
1867 if (wp->popup && !wp->keep_window)
1868 XtDestroyWidget(wp->popup), wp->popup = (Widget) 0;
1870 if (wp->keep_window)
1871 XtRemoveCallback(wp->w, XtNexposeCallback, map_exposed,
1874 wp->type = NHW_NONE; /* allow re-use */
1876 /* when map goes away, presumably we're exiting, so get rid of the
1877 cached extended commands menu (if we aren't actually exiting, it
1878 will get recreated if needed again) */
1879 release_extended_cmds();
1882 boolean exit_x_event; /* exit condition for the event loop */
1889 printf("key = '%s%c'\n", (k < 32) ? "^" : "", (k < 32) ? '@' + k : k);
1894 * Main X event loop. Here we accept and dispatch X events. We only exit
1895 * under certain circumstances.
1898 x_event(exit_condition)
1903 boolean keep_going = TRUE;
1905 /* Hold globals so function is re-entrant */
1906 boolean hold_exit_x_event = exit_x_event;
1908 click_button = NO_CLICK; /* reset click exit condition */
1909 exit_x_event = FALSE; /* reset callback exit condition */
1912 * Loop until we get a sent event, callback exit, or are accepting key
1913 * press and button press events and we receive one.
1915 if ((exit_condition == EXIT_ON_KEY_PRESS
1916 || exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount)
1920 XtAppNextEvent(app_context, &event);
1921 XtDispatchEvent(&event);
1923 /* See if we can exit. */
1925 switch (exit_condition) {
1926 case EXIT_ON_SENT_EVENT: {
1927 XAnyEvent *any = (XAnyEvent *) &event;
1929 if (any->send_event) {
1942 case EXIT_ON_KEY_PRESS:
1944 /* get first pressed key */
1946 retval = inbuf[inptr];
1947 inptr = (inptr + 1) % INBUF_SIZE;
1950 } else if (program_state.done_hup) {
1952 inptr = (inptr + 1) % INBUF_SIZE;
1956 case EXIT_ON_KEY_OR_BUTTON_PRESS:
1957 if (incount != 0 || click_button != NO_CLICK) {
1958 if (click_button != NO_CLICK) { /* button press */
1959 /* click values are already set */
1961 } else { /* key press */
1962 /* get first pressed key */
1964 retval = inbuf[inptr];
1965 inptr = (inptr + 1) % INBUF_SIZE;
1969 } else if (program_state.done_hup) {
1971 inptr = (inptr + 1) % INBUF_SIZE;
1976 panic("x_event: unknown exit condition %d", exit_condition);
1979 } while (keep_going);
1981 /* Restore globals */
1982 exit_x_event = hold_exit_x_event;