1 /* aNetHack 0.0.1 winmap.c $ANH-Date: 1455389908 2016/02/13 18:58:28 $ $ANH-Branch: aNetHack-3.6.0 $:$ANH-Revision: 1.29 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* aNetHack 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 anethack 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/Xatom.h>
30 #ifdef PRESERVE_NO_SYSV
34 #undef PRESERVE_NO_SYSV
37 #include "xwindow.h" /* map widget declarations */
48 extern short glyph2tile
[];
49 extern int total_tiles_used
;
51 /* Define these if you really want a lot of junk on your screen. */
52 /* #define VERBOSE */ /* print various info & events as they happen */
53 /* #define VERBOSE_UPDATE */ /* print screen update bounds */
54 /* #define VERBOSE_INPUT */ /* print input events */
56 #define USE_WHITE /* almost always use white as a tile cursor border */
58 static boolean
FDECL(init_tiles
, (struct xwindow
*));
59 static void FDECL(set_button_values
, (Widget
, int, int, unsigned));
60 static void FDECL(map_check_size_change
, (struct xwindow
*));
61 static void FDECL(map_update
, (struct xwindow
*, int, int, int, int,
63 static void FDECL(init_text
, (struct xwindow
*));
64 static void FDECL(map_exposed
, (Widget
, XtPointer
, XtPointer
));
65 static void FDECL(set_gc
, (Widget
, Font
, const char *, Pixel
, GC
*, GC
*));
66 static void FDECL(get_text_gc
, (struct xwindow
*, Font
));
67 static void FDECL(get_char_info
, (struct xwindow
*));
68 static void FDECL(display_cursor
, (struct xwindow
*));
70 /* Global functions ======================================================= */
73 X11_print_glyph(window
, x
, y
, glyph
, bkglyph
)
79 struct map_info_t
*map_info
;
80 boolean update_bbox
= FALSE
;
83 if (window_list
[window
].type
!= NHW_MAP
) {
84 impossible("print_glyph: can (currently) only print to map windows");
87 map_info
= window_list
[window
].map_information
;
89 /* update both the tile and text backing stores */
91 unsigned short *t_ptr
= &map_info
->tile_map
.glyphs
[y
][x
].glyph
;
93 if (*t_ptr
!= glyph
) {
95 if (map_info
->is_tile
)
101 register unsigned char *ch_ptr
;
106 register unsigned char *co_ptr
;
109 /* map glyph to character and color */
110 (void) mapglyph(glyph
, &och
, &color
, &special
, x
, y
);
113 if (special
!= map_info
->tile_map
.glyphs
[y
][x
].special
) {
114 map_info
->tile_map
.glyphs
[y
][x
].special
= special
;
118 /* Only update if we need to. */
119 ch_ptr
= &map_info
->text_map
.text
[y
][x
];
122 if (!map_info
->is_tile
)
126 co_ptr
= &map_info
->text_map
.colors
[y
][x
];
127 colordif
= (((special
& MG_PET
) != 0 && iflags
.hilite_pet
)
128 || ((special
& MG_OBJPILE
) != 0 && iflags
.hilite_pile
)
129 || ((special
& (MG_DETECT
| MG_BW_LAVA
)) != 0))
131 if (*co_ptr
!= (uchar
) (color
+ colordif
)) {
132 *co_ptr
= (uchar
) (color
+ colordif
);
133 if (!map_info
->is_tile
)
139 if (update_bbox
) { /* update row bbox */
140 if ((uchar
) x
< map_info
->t_start
[y
])
141 map_info
->t_start
[y
] = x
;
142 if ((uchar
) x
> map_info
->t_stop
[y
])
143 map_info
->t_stop
[y
] = x
;
149 * The is the tty clip call. Since X can resize at any time, we can't depend
150 * on this being defined.
160 #endif /* CLIPPING */
162 /* End global functions =================================================== */
164 #include "tile2x11.h"
167 * We're expecting to never read more than one tile file per session.
168 * If this is false, then we can make an array of this information,
169 * or just keep it on a per-window basis.
171 Pixmap tile_pixmap
= None
;
172 static int tile_width
;
173 static int tile_height
;
174 static int tile_count
;
175 static XImage
*tile_image
= 0;
178 * This structure is used for small bitmaps that are used for annotating
179 * tiles. For example, a "heart" annotates pets.
181 struct tile_annotation
{
184 unsigned int width
, height
;
185 int hotx
, hoty
; /* not currently used */
188 static struct tile_annotation pet_annotation
;
189 static struct tile_annotation pile_annotation
;
192 init_annotation(annotation
, filename
, colorpixel
)
193 struct tile_annotation
*annotation
;
197 Display
*dpy
= XtDisplay(toplevel
);
199 if (0 != XReadBitmapFile(dpy
, XtWindow(toplevel
), filename
,
200 &annotation
->width
, &annotation
->height
,
201 &annotation
->bitmap
, &annotation
->hotx
,
202 &annotation
->hoty
)) {
205 Sprintf(buf
, "Failed to load %s", filename
);
209 annotation
->foreground
= colorpixel
;
213 * Put the tile image on the server.
215 * We can't send the image to the server until the top level
216 * is realized. When the tile file is first processed, the top
217 * level is not realized. This routine is called after we
218 * realize the top level, but before we start resizing the
224 Display
*dpy
= XtDisplay(toplevel
);
225 unsigned int width
, height
;
228 return; /* no tiles */
230 height
= tile_image
->height
;
231 width
= tile_image
->width
;
233 tile_pixmap
= XCreatePixmap(dpy
, XtWindow(toplevel
), width
, height
,
234 DefaultDepth(dpy
, DefaultScreen(dpy
)));
236 XPutImage(dpy
, tile_pixmap
, DefaultGC(dpy
, DefaultScreen(dpy
)),
237 tile_image
, 0, 0, 0, 0, /* src, dest top left */
241 /* if we let XDestroyImage() handle it, our tracking will be off */
242 if (tile_image
->data
)
243 free((genericptr_t
) tile_image
->data
), tile_image
->data
= 0;
245 XDestroyImage(tile_image
); /* data bytes free'd also */
248 init_annotation(&pet_annotation
, appResources
.pet_mark_bitmap
,
249 appResources
.pet_mark_color
);
250 init_annotation(&pile_annotation
, appResources
.pilemark_bitmap
,
251 appResources
.pilemark_color
);
255 * Open and read the tile file. Return TRUE if there were no problems.
256 * Return FALSE otherwise.
263 XpmAttributes attributes
;
266 FILE *fp
= (FILE *) 0;
268 unsigned char *cp
, *colormap
= (unsigned char *) 0;
269 unsigned char *tb
, *tile_bytes
= (unsigned char *) 0;
271 XColor
*colors
= (XColor
*) 0;
278 Display
*dpy
= XtDisplay(toplevel
);
279 Screen
*screen
= DefaultScreenOfDisplay(dpy
);
280 struct map_info_t
*map_info
= (struct map_info_t
*) 0;
281 struct tile_map_info_t
*tile_info
= (struct tile_map_info_t
*) 0;
282 unsigned int image_height
= 0, image_width
= 0;
283 boolean result
= TRUE
;
287 /* already have tile information */
288 if (tile_pixmap
!= None
)
291 map_info
= wp
->map_information
;
292 tile_info
= &map_info
->tile_map
;
293 (void) memset((genericptr_t
) tile_info
, 0,
294 sizeof(struct tile_map_info_t
));
296 /* no tile file name, no tile information */
297 if (!appResources
.tile_file
[0]) {
303 attributes
.valuemask
= XpmCloseness
;
304 attributes
.closeness
= 25000;
306 errorcode
= XpmReadFileToImage(dpy
, appResources
.tile_file
, &tile_image
,
309 if (errorcode
== XpmColorFailed
) {
310 Sprintf(buf
, "Insufficient colors available to load %s.",
311 appResources
.tile_file
);
313 X11_raw_print("Try closing other colorful applications and restart.");
314 X11_raw_print("Attempting to load with inferior colors.");
315 attributes
.closeness
= 50000;
316 errorcode
= XpmReadFileToImage(dpy
, appResources
.tile_file
,
317 &tile_image
, 0, &attributes
);
320 if (errorcode
!= XpmSuccess
) {
321 if (errorcode
== XpmColorFailed
) {
322 Sprintf(buf
, "Insufficient colors available to load %s.",
323 appResources
.tile_file
);
326 Sprintf(buf
, "Failed to load %s: %s", appResources
.tile_file
,
327 XpmGetErrorString(errorcode
));
331 X11_raw_print("Switching to text-based mode.");
335 /* assume a fixed number of tiles per row */
336 if (tile_image
->width
% TILES_PER_ROW
!= 0
337 || tile_image
->width
<= TILES_PER_ROW
) {
339 "%s is not a multiple of %d (number of tiles/row) pixels wide",
340 appResources
.tile_file
, TILES_PER_ROW
);
342 XDestroyImage(tile_image
);
348 /* infer tile dimensions from image size and TILES_PER_ROW */
349 image_width
= tile_image
->width
;
350 image_height
= tile_image
->height
;
352 tile_count
= total_tiles_used
;
353 if ((tile_count
% TILES_PER_ROW
) != 0) {
354 tile_count
+= TILES_PER_ROW
- (tile_count
% TILES_PER_ROW
);
356 tile_width
= image_width
/ TILES_PER_ROW
;
357 tile_height
= image_height
/ (tile_count
/ TILES_PER_ROW
);
359 /* any less than 16 colours makes tiles useless */
360 ddepth
= DefaultDepthOfScreen(screen
);
362 X11_raw_print("need a screen depth of at least 4");
367 fp
= fopen_datafile(appResources
.tile_file
, RDBMODE
, FALSE
);
369 X11_raw_print("can't open tile file");
374 if ((int) fread((char *) &header
, sizeof(header
), 1, fp
) != 1) {
375 X11_raw_print("read of header failed");
380 if (header
.version
!= 2) {
381 Sprintf(buf
, "Wrong tile file version, expected 2, got %lu",
389 X11 tile file:\n version %ld\n ncolors %ld\n \
390 tile width %ld\n tile height %ld\n per row %ld\n \
392 header
.version
, header
.ncolors
, header
.tile_width
,
393 header
.tile_height
, header
.per_row
, header
.ntiles
);
396 size
= 3 * header
.ncolors
;
397 colormap
= (unsigned char *) alloc((unsigned) size
);
398 if ((int) fread((char *) colormap
, 1, size
, fp
) != size
) {
399 X11_raw_print("read of colormap failed");
404 colors
= (XColor
*) alloc(sizeof(XColor
) * (unsigned) header
.ncolors
);
405 for (i
= 0; i
< header
.ncolors
; i
++) {
406 cp
= colormap
+ (3 * i
);
407 colors
[i
].red
= cp
[0] * 256;
408 colors
[i
].green
= cp
[1] * 256;
409 colors
[i
].blue
= cp
[2] * 256;
413 if (!XAllocColor(dpy
, DefaultColormapOfScreen(screen
), &colors
[i
])
414 && !nhApproxColor(screen
, DefaultColormapOfScreen(screen
),
415 (char *) 0, &colors
[i
])) {
416 Sprintf(buf
, "%dth out of %ld color allocation failed", i
,
424 size
= header
.tile_height
* header
.tile_width
;
426 * This alloc() and the one below require 32-bit ints, since tile_bytes
427 * is currently ~200k and alloc() takes an int
429 tile_count
= header
.ntiles
;
430 if ((tile_count
% header
.per_row
) != 0) {
431 tile_count
+= header
.per_row
- (tile_count
% header
.per_row
);
433 tile_bytes
= (unsigned char *) alloc((unsigned) tile_count
* size
);
434 if ((int) fread((char *) tile_bytes
, size
, tile_count
, fp
)
436 X11_raw_print("read of tile bytes failed");
441 if (header
.ntiles
< (unsigned) total_tiles_used
) {
442 Sprintf(buf
, "tile file incomplete, expecting %d tiles, found %lu",
443 total_tiles_used
, header
.ntiles
);
449 if (appResources
.double_tile_size
) {
450 tile_width
= 2 * header
.tile_width
;
451 tile_height
= 2 * header
.tile_height
;
453 tile_width
= header
.tile_width
;
454 tile_height
= header
.tile_height
;
457 image_height
= tile_height
* tile_count
/ header
.per_row
;
458 image_width
= tile_width
* header
.per_row
;
460 /* calculate bitmap_pad */
468 tile_image
= XCreateImage(dpy
, DefaultVisualOfScreen(screen
),
470 ZPixmap
, /* format */
472 (char *) 0, /* data */
473 image_width
, /* width */
474 image_height
, /* height */
475 bitmap_pad
, /* bit pad */
476 0); /* bytes_per_line */
479 impossible("init_tiles: insufficient memory to create image");
481 /* now we know the physical memory requirements, we can allocate space */
483 (char *) alloc((unsigned) tile_image
->bytes_per_line
* image_height
);
485 if (appResources
.double_tile_size
) {
486 unsigned long *expanded_row
=
487 (unsigned long *) alloc(sizeof(unsigned long) * image_width
);
490 for (y
= 0; y
< (int) image_height
; y
++) {
491 for (x
= 0; x
< (int) image_width
/ 2; x
++)
492 expanded_row
[2 * x
] = expanded_row
[(2 * x
) + 1] =
495 for (x
= 0; x
< (int) image_width
; x
++)
496 XPutPixel(tile_image
, x
, y
, expanded_row
[x
]);
498 y
++; /* duplicate row */
499 for (x
= 0; x
< (int) image_width
; x
++)
500 XPutPixel(tile_image
, x
, y
, expanded_row
[x
]);
502 free((genericptr_t
) expanded_row
);
505 for (tb
= tile_bytes
, y
= 0; y
< (int) image_height
; y
++)
506 for (x
= 0; x
< (int) image_width
; x
++, tb
++)
507 XPutPixel(tile_image
, x
, y
, colors
[*tb
].pixel
);
509 #endif /* ?USE_XPM */
511 /* fake an inverted tile by drawing a border around the edges */
513 /* use white or black as the border */
514 mask
= GCFunction
| GCForeground
| GCGraphicsExposures
;
515 values
.graphics_exposures
= False
;
516 values
.foreground
= WhitePixelOfScreen(screen
);
517 values
.function
= GXcopy
;
518 tile_info
->white_gc
= XtGetGC(wp
->w
, mask
, &values
);
519 values
.graphics_exposures
= False
;
520 values
.foreground
= BlackPixelOfScreen(screen
);
521 values
.function
= GXcopy
;
522 tile_info
->black_gc
= XtGetGC(wp
->w
, mask
, &values
);
525 * Use xor so we don't have to check for special colors. Xor white
526 * against the upper left pixel of the corridor so that we have a
527 * white rectangle when in a corridor.
529 mask
= GCFunction
| GCForeground
| GCGraphicsExposures
;
530 values
.graphics_exposures
= False
;
532 WhitePixelOfScreen(screen
)
533 ^ XGetPixel(tile_image
, 0,
534 tile_height
* glyph2tile
[cmap_to_glyph(S_corr
)]);
535 values
.function
= GXxor
;
536 tile_info
->white_gc
= XtGetGC(wp
->w
, mask
, &values
);
538 mask
= GCFunction
| GCGraphicsExposures
;
539 values
.function
= GXCopy
;
540 values
.graphics_exposures
= False
;
541 tile_info
->black_gc
= XtGetGC(wp
->w
, mask
, &values
);
542 #endif /* USE_WHITE */
549 free((genericptr_t
) colormap
);
551 free((genericptr_t
) tile_bytes
);
553 free((genericptr_t
) colors
);
556 if (result
) { /* succeeded */
557 tile_info
->square_height
= tile_height
;
558 tile_info
->square_width
= tile_width
;
559 tile_info
->square_ascent
= 0;
560 tile_info
->square_lbearing
= 0;
561 tile_info
->image_width
= image_width
;
562 tile_info
->image_height
= image_height
;
569 * Make sure the map's cursor is always visible.
572 check_cursor_visibility(wp
)
576 Widget viewport
, horiz_sb
, vert_sb
;
577 float top
, shown
, cursor_middle
;
578 Boolean do_call
, adjusted
= False
;
583 viewport
= XtParent(wp
->w
);
584 horiz_sb
= XtNameToWidget(viewport
, "horizontal");
585 vert_sb
= XtNameToWidget(viewport
, "vertical");
587 /* All values are relative to currently visible area */
589 #define V_BORDER 0.25 /* if this far from vert edge, shift */
590 #define H_BORDER 0.25 /* if this from from horiz edge, shift */
592 #define H_DELTA 0.25 /* distance of horiz shift */
593 #define V_DELTA 0.25 /* distance of vert shift */
596 XtSetArg(arg
[0], XtNshown
, &shown
);
597 XtSetArg(arg
[1], nhStr(XtNtopOfThumb
), &top
);
598 XtGetValues(horiz_sb
, arg
, TWO
);
600 /* [ALI] Don't assume map widget is the same size as actual map */
601 if (wp
->map_information
->is_tile
)
602 cursor_middle
= wp
->map_information
->tile_map
.square_width
;
604 cursor_middle
= wp
->map_information
->text_map
.square_width
;
605 cursor_middle
= (wp
->cursx
+ 0.5) * cursor_middle
/ wp
->pixel_width
;
609 if (cursor_middle
< top
) {
611 } else if (cursor_middle
< top
+ shown
* H_BORDER
) {
612 s
= " close to left";
613 } else if (cursor_middle
> (top
+ shown
)) {
614 s
= " outside right";
615 } else if (cursor_middle
> (top
+ shown
- shown
* H_BORDER
)) {
616 s
= " close to right";
620 printf("Horiz: shown = %3.2f, top = %3.2f%s", shown
, top
, s
);
623 if (cursor_middle
< top
) {
624 top
= cursor_middle
- shown
* H_DELTA
;
627 } else if (cursor_middle
< top
+ shown
* H_BORDER
) {
628 top
-= shown
* H_DELTA
;
631 } else if (cursor_middle
> (top
+ shown
)) {
632 top
= cursor_middle
- shown
* H_DELTA
;
635 if (top
+ shown
> 1.0)
637 } else if (cursor_middle
> (top
+ shown
- shown
* H_BORDER
)) {
638 top
+= shown
* H_DELTA
;
639 if (top
+ shown
> 1.0)
646 XtCallCallbacks(horiz_sb
, XtNjumpProc
, &top
);
652 XtSetArg(arg
[0], XtNshown
, &shown
);
653 XtSetArg(arg
[1], nhStr(XtNtopOfThumb
), &top
);
654 XtGetValues(vert_sb
, arg
, TWO
);
656 if (wp
->map_information
->is_tile
)
657 cursor_middle
= wp
->map_information
->tile_map
.square_height
;
659 cursor_middle
= wp
->map_information
->text_map
.square_height
;
660 cursor_middle
= (wp
->cursy
+ 0.5) * cursor_middle
/ wp
->pixel_height
;
664 if (cursor_middle
< top
) {
666 } else if (cursor_middle
< top
+ shown
* V_BORDER
) {
668 } else if (cursor_middle
> (top
+ shown
)) {
670 } else if (cursor_middle
> (top
+ shown
- shown
* V_BORDER
)) {
671 s
= " close to bottom";
675 printf("%sVert: shown = %3.2f, top = %3.2f%s", horiz_sb
? "; " : "",
679 if (cursor_middle
< top
) {
680 top
= cursor_middle
- shown
* V_DELTA
;
683 } else if (cursor_middle
< top
+ shown
* V_BORDER
) {
684 top
-= shown
* V_DELTA
;
687 } else if (cursor_middle
> (top
+ shown
)) {
688 top
= cursor_middle
- shown
* V_DELTA
;
691 if (top
+ shown
> 1.0)
693 } else if (cursor_middle
> (top
+ shown
- shown
* V_BORDER
)) {
694 top
+= shown
* V_DELTA
;
695 if (top
+ shown
> 1.0)
702 XtCallCallbacks(vert_sb
, XtNjumpProc
, &top
);
707 /* make sure cursor is displayed during dowhatis.. */
712 if (horiz_sb
|| vert_sb
)
718 * Check to see if the viewport has grown smaller. If so, then we want to
720 * sure that the cursor is still on the screen. We do this to keep the cursor
721 * on the screen when the user resizes the anethack window.
724 map_check_size_change(wp
)
727 struct map_info_t
*map_info
= wp
->map_information
;
729 Dimension new_width
, new_height
;
732 viewport
= XtParent(wp
->w
);
734 XtSetArg(arg
[0], XtNwidth
, &new_width
);
735 XtSetArg(arg
[1], XtNheight
, &new_height
);
736 XtGetValues(viewport
, arg
, TWO
);
738 /* Only do cursor check if new size is smaller. */
739 if (new_width
< map_info
->viewport_width
740 || new_height
< map_info
->viewport_height
) {
741 /* [ALI] If the viewport was larger than the map (and so the map
742 * widget was contrained to be larger than the actual map) then we
743 * may be able to shrink the map widget as the viewport shrinks.
745 if (map_info
->is_tile
) {
746 wp
->pixel_width
= map_info
->tile_map
.square_width
* COLNO
;
747 wp
->pixel_height
= map_info
->tile_map
.square_height
* ROWNO
;
749 wp
->pixel_width
= map_info
->text_map
.square_width
* COLNO
;
750 wp
->pixel_height
= map_info
->text_map
.square_height
* ROWNO
;
753 if (wp
->pixel_width
< new_width
)
754 wp
->pixel_width
= new_width
;
755 if (wp
->pixel_height
< new_height
)
756 wp
->pixel_height
= new_height
;
757 XtSetArg(arg
[0], XtNwidth
, wp
->pixel_width
);
758 XtSetArg(arg
[1], XtNheight
, wp
->pixel_height
);
759 XtSetValues(wp
->w
, arg
, TWO
);
761 check_cursor_visibility(wp
);
764 map_info
->viewport_width
= new_width
;
765 map_info
->viewport_height
= new_height
;
767 /* [ALI] These may have changed if the user has re-sized the viewport */
768 XtSetArg(arg
[0], XtNwidth
, &wp
->pixel_width
);
769 XtSetArg(arg
[1], XtNheight
, &wp
->pixel_height
);
770 XtGetValues(wp
->w
, arg
, TWO
);
774 * Fill in parameters "regular" and "inverse" with newly created GCs.
775 * Using the given background pixel and the foreground pixel optained
776 * by querying the widget with the resource name.
779 set_gc(w
, font
, resource_name
, bgpixel
, regular
, inverse
)
782 const char *resource_name
;
784 GC
*regular
, *inverse
;
787 XtGCMask mask
= GCFunction
| GCForeground
| GCBackground
| GCFont
;
791 XtSetArg(arg
[0], (char *) resource_name
, &curpixel
);
792 XtGetValues(w
, arg
, ONE
);
794 values
.foreground
= curpixel
;
795 values
.background
= bgpixel
;
796 values
.function
= GXcopy
;
798 *regular
= XtGetGC(w
, mask
, &values
);
799 values
.foreground
= bgpixel
;
800 values
.background
= curpixel
;
801 values
.function
= GXcopy
;
803 *inverse
= XtGetGC(w
, mask
, &values
);
807 * Create the GC's for each color.
809 * I'm not sure if it is a good idea to have a GC for each color (and
810 * inverse). It might be faster to just modify the foreground and
811 * background colors on the current GC as needed.
814 get_text_gc(wp
, font
)
818 struct map_info_t
*map_info
= wp
->map_information
;
822 /* Get background pixel. */
823 XtSetArg(arg
[0], XtNbackground
, &bgpixel
);
824 XtGetValues(wp
->w
, arg
, ONE
);
827 #define set_color_gc(nh_color, resource_name) \
828 set_gc(wp->w, font, resource_name, bgpixel, \
829 &map_info->text_map.color_gcs[nh_color], \
830 &map_info->text_map.inv_color_gcs[nh_color]);
832 set_color_gc(CLR_BLACK
, XtNblack
);
833 set_color_gc(CLR_RED
, XtNred
);
834 set_color_gc(CLR_GREEN
, XtNgreen
);
835 set_color_gc(CLR_BROWN
, XtNbrown
);
836 set_color_gc(CLR_BLUE
, XtNblue
);
837 set_color_gc(CLR_MAGENTA
, XtNmagenta
);
838 set_color_gc(CLR_CYAN
, XtNcyan
);
839 set_color_gc(CLR_GRAY
, XtNgray
);
840 set_color_gc(NO_COLOR
, XtNforeground
);
841 set_color_gc(CLR_ORANGE
, XtNorange
);
842 set_color_gc(CLR_BRIGHT_GREEN
, XtNbright_green
);
843 set_color_gc(CLR_YELLOW
, XtNyellow
);
844 set_color_gc(CLR_BRIGHT_BLUE
, XtNbright_blue
);
845 set_color_gc(CLR_BRIGHT_MAGENTA
, XtNbright_magenta
);
846 set_color_gc(CLR_BRIGHT_CYAN
, XtNbright_cyan
);
847 set_color_gc(CLR_WHITE
, XtNwhite
);
849 set_gc(wp
->w
, font
, XtNforeground
, bgpixel
,
850 &map_info
->text_map
.copy_gc
,
851 &map_info
->text_map
.inv_copy_gc
);
856 * Display the cursor on the map window.
862 /* Redisplay the cursor location inverted. */
863 map_update(wp
, wp
->cursy
, wp
->cursy
, wp
->cursx
, wp
->cursx
, TRUE
);
867 * Check if there are any changed characters. If so, then plaster them on
871 display_map_window(wp
)
875 struct map_info_t
*map_info
= wp
->map_information
;
877 if ((Is_rogue_level(&u
.uz
) ? map_info
->is_tile
878 : (map_info
->is_tile
!= iflags
.wc_tiled_map
))
879 && map_info
->tile_map
.image_width
) {
880 /* changed map display mode, re-display the full map */
881 (void) memset((genericptr_t
) map_info
->t_start
, (char) 0,
882 sizeof(map_info
->t_start
));
883 (void) memset((genericptr_t
) map_info
->t_stop
, (char) (COLNO
- 1),
884 sizeof(map_info
->t_stop
));
885 map_info
->is_tile
= iflags
.wc_tiled_map
&& !Is_rogue_level(&u
.uz
);
886 XClearWindow(XtDisplay(wp
->w
), XtWindow(wp
->w
));
887 set_map_size(wp
, COLNO
, ROWNO
);
888 check_cursor_visibility(wp
);
889 highlight_yn(TRUE
); /* change fg/bg to match map */
890 } else if (wp
->prevx
!= wp
->cursx
|| wp
->prevy
!= wp
->cursy
) {
891 register unsigned int x
= wp
->prevx
, y
= wp
->prevy
;
894 * Previous cursor position is not the same as the current
895 * cursor position, update the old cursor position.
897 if (x
< map_info
->t_start
[y
])
898 map_info
->t_start
[y
] = x
;
899 if (x
> map_info
->t_stop
[y
])
900 map_info
->t_stop
[y
] = x
;
903 for (row
= 0; row
< ROWNO
; row
++) {
904 if (map_info
->t_start
[row
] <= map_info
->t_stop
[row
]) {
905 map_update(wp
, row
, row
, (int) map_info
->t_start
[row
],
906 (int) map_info
->t_stop
[row
], FALSE
);
907 map_info
->t_start
[row
] = COLNO
- 1;
908 map_info
->t_stop
[row
] = 0;
912 wp
->prevx
= wp
->cursx
; /* adjust old cursor position */
913 wp
->prevy
= wp
->cursy
;
917 * Set all map tiles to S_stone
920 map_all_stone(map_info
)
921 struct map_info_t
*map_info
;
924 unsigned short stone
= cmap_to_glyph(S_stone
);
926 for (x
= 0; x
< COLNO
; x
++)
927 for (y
= 0; y
< ROWNO
; y
++) {
928 map_info
->tile_map
.glyphs
[y
][x
].glyph
= stone
;
929 map_info
->tile_map
.glyphs
[y
][x
].special
= 0;
934 * Fill the saved screen characters with the "clear" tile or character.
936 * Flush out everything by resetting the "new" bounds and calling
937 * display_map_window().
943 struct map_info_t
*map_info
= wp
->map_information
;
945 /* update both tile and text backing store, then update */
947 map_all_stone(map_info
);
948 (void) memset((genericptr_t
) map_info
->text_map
.text
, ' ',
949 sizeof map_info
->text_map
.text
);
951 (void) memset((genericptr_t
) map_info
->text_map
.colors
, NO_COLOR
,
952 sizeof map_info
->text_map
.colors
);
955 /* force a full update */
956 (void) memset((genericptr_t
) map_info
->t_start
, (char) 0,
957 sizeof map_info
->t_start
);
958 (void) memset((genericptr_t
) map_info
->t_stop
, (char) COLNO
- 1,
959 sizeof map_info
->t_stop
);
960 display_map_window(wp
);
964 * Retreive the font associated with the map window and save attributes
965 * that are used when updating it.
972 struct map_info_t
*map_info
= wp
->map_information
;
973 struct text_map_info_t
*text_map
= &map_info
->text_map
;
975 fs
= WindowFontStruct(wp
->w
);
976 text_map
->square_width
= fs
->max_bounds
.width
;
977 text_map
->square_height
= fs
->max_bounds
.ascent
+ fs
->max_bounds
.descent
;
978 text_map
->square_ascent
= fs
->max_bounds
.ascent
;
979 text_map
->square_lbearing
= -fs
->min_bounds
.lbearing
;
982 printf("Font information:\n");
983 printf("fid = %ld, direction = %d\n", fs
->fid
, fs
->direction
);
984 printf("first = %d, last = %d\n",
985 fs
->min_char_or_byte2
, fs
->max_char_or_byte2
);
986 printf("all chars exist? %s\n", fs
->all_chars_exist
? "yes" : "no");
987 printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
988 fs
->min_bounds
.lbearing
, fs
->min_bounds
.rbearing
,
989 fs
->min_bounds
.width
, fs
->min_bounds
.ascent
,
990 fs
->min_bounds
.descent
, fs
->min_bounds
.attributes
);
991 printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
992 fs
->max_bounds
.lbearing
, fs
->max_bounds
.rbearing
,
993 fs
->max_bounds
.width
, fs
->max_bounds
.ascent
,
994 fs
->max_bounds
.descent
, fs
->max_bounds
.attributes
);
995 printf("per_char = 0x%lx\n", (unsigned long) fs
->per_char
);
996 printf("Text: (max) width = %d, height = %d\n",
997 text_map
->square_width
, text_map
->square_height
);
1000 if (fs
->min_bounds
.width
!= fs
->max_bounds
.width
)
1001 X11_raw_print("Warning: map font is not monospaced!");
1007 #define INBUF_SIZE 64
1008 static int inbuf
[INBUF_SIZE
];
1009 static int incount
= 0;
1010 static int inptr
= 0; /* points to valid data */
1013 * Keyboard and button event handler for map window.
1016 map_input(w
, event
, params
, num_params
)
1020 Cardinal
*num_params
;
1023 XButtonEvent
*button
;
1024 boolean meta
= FALSE
;
1026 Cardinal in_nparams
= (num_params
? *num_params
: 0);
1028 char keystring
[MAX_KEY_STRING
];
1030 switch (event
->type
) {
1032 button
= (XButtonEvent
*) event
;
1033 #ifdef VERBOSE_INPUT
1034 printf("button press\n");
1036 if (in_nparams
> 0 && (nbytes
= strlen(params
[0])) < MAX_KEY_STRING
) {
1037 Strcpy(keystring
, params
[0]);
1038 key
= (XKeyEvent
*) event
; /* just in case */
1041 if (w
!= window_list
[WIN_MAP
].w
) {
1042 #ifdef VERBOSE_INPUT
1043 printf("map_input called from wrong window\n");
1048 set_button_values(w
, button
->x
, button
->y
, button
->button
);
1051 #ifdef VERBOSE_INPUT
1054 if (appResources
.slow
&& input_func
) {
1055 (*input_func
)(w
, event
, params
, num_params
);
1060 * Don't use key_event_to_char() because we want to be able
1061 * to allow keys mapped to multiple characters.
1063 key
= (XKeyEvent
*) event
;
1064 if (in_nparams
> 0 && (nbytes
= strlen(params
[0])) < MAX_KEY_STRING
) {
1065 Strcpy(keystring
, params
[0]);
1068 * Assume that mod1 is really the meta key.
1070 meta
= !!(key
->state
& Mod1Mask
);
1071 nbytes
= XLookupString(key
, keystring
, MAX_KEY_STRING
,
1072 (KeySym
*) 0, (XComposeStatus
*) 0);
1075 /* Modifier keys return a zero length string when pressed. */
1077 #ifdef VERBOSE_INPUT
1080 for (i
= 0; i
< nbytes
; i
++) {
1083 if (incount
< INBUF_SIZE
) {
1084 inbuf
[(inptr
+ incount
) % INBUF_SIZE
] =
1085 ((int) c
) + (meta
? 0x80 : 0);
1090 #ifdef VERBOSE_INPUT
1091 if (meta
) /* meta will print as M<c> */
1092 (void) putchar('M');
1093 if (c
< ' ') { /* ctrl will print as ^<c> */
1094 (void) putchar('^');
1100 #ifdef VERBOSE_INPUT
1101 printf("\" [%d bytes]\n", nbytes
);
1107 impossible("unexpected X event, type = %d\n", (int) event
->type
);
1113 set_button_values(w
, x
, y
, button
)
1117 unsigned int button
;
1120 struct map_info_t
*map_info
;
1122 wp
= find_widget(w
);
1123 map_info
= wp
->map_information
;
1125 if (map_info
->is_tile
) {
1126 click_x
= x
/ map_info
->tile_map
.square_width
;
1127 click_y
= y
/ map_info
->tile_map
.square_height
;
1129 click_x
= x
/ map_info
->text_map
.square_width
;
1130 click_y
= y
/ map_info
->text_map
.square_height
;
1133 /* The values can be out of range if the map window has been resized
1134 to be larger than the max size. */
1135 if (click_x
>= COLNO
)
1136 click_x
= COLNO
- 1;
1137 if (click_y
>= ROWNO
)
1138 click_y
= ROWNO
- 1;
1140 /* Map all buttons but the first to the second click */
1141 click_button
= (button
== Button1
) ? CLICK_1
: CLICK_2
;
1145 * Map window expose callback.
1149 map_exposed(w
, client_data
, widget_data
)
1151 XtPointer client_data
; /* unused */
1152 XtPointer widget_data
; /* expose event from Window widget */
1156 struct map_info_t
*map_info
;
1157 unsigned width
, height
;
1158 int start_row
, stop_row
, start_col
, stop_col
;
1159 XExposeEvent
*event
= (XExposeEvent
*) widget_data
;
1160 int t_height
, t_width
; /* tile/text height & width */
1164 if (!XtIsRealized(w
) || event
->count
> 0)
1167 wp
= find_widget(w
);
1168 map_info
= wp
->map_information
;
1169 if (wp
->keep_window
&& !map_info
)
1172 * The map is sent an expose event when the viewport resizes. Make sure
1173 * that the cursor is still in the viewport after the resize.
1175 map_check_size_change(wp
);
1177 if (event
) { /* called from button-event */
1180 width
= event
->width
;
1181 height
= event
->height
;
1185 width
= wp
->pixel_width
;
1186 height
= wp
->pixel_height
;
1189 * Convert pixels into INCLUSIVE text rows and columns.
1191 if (map_info
->is_tile
) {
1192 t_height
= map_info
->tile_map
.square_height
;
1193 t_width
= map_info
->tile_map
.square_width
;
1195 t_height
= map_info
->text_map
.square_height
;
1196 t_width
= map_info
->text_map
.square_width
;
1198 start_row
= y
/ t_height
;
1199 stop_row
= ((y
+ height
) / t_height
)
1200 + ((((y
+ height
) % t_height
) == 0) ? 0 : 1) - 1;
1202 start_col
= x
/ t_width
;
1203 stop_col
= ((x
+ width
) / t_width
)
1204 + ((((x
+ width
) % t_width
) == 0) ? 0 : 1) - 1;
1207 printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n", x
, y
,
1209 printf("chars %d x %d, rows %d to %d, columns %d to %d\n", t_height
,
1210 t_width
, start_row
, stop_row
, start_col
, stop_col
);
1213 /* Out of range values are possible if the map window is resized to be
1214 bigger than the largest expected value. */
1215 if (stop_row
>= ROWNO
)
1216 stop_row
= ROWNO
- 1;
1217 if (stop_col
>= COLNO
)
1218 stop_col
= COLNO
- 1;
1220 map_update(wp
, start_row
, stop_row
, start_col
, stop_col
, FALSE
);
1221 display_cursor(wp
); /* make sure cursor shows up */
1225 * Do the actual work of the putting characters onto our X window. This
1226 * is called from the expose event routine, the display window (flush)
1227 * routine, and the display cursor routine. The last involves inverting
1228 * the foreground and background colors, which are also inverted when the
1229 * position's color is above CLR_MAX.
1231 * This works for rectangular regions (this includes one line rectangles).
1232 * The start and stop columns are *inclusive*.
1235 map_update(wp
, start_row
, stop_row
, start_col
, stop_col
, inverted
)
1237 int start_row
, stop_row
, start_col
, stop_col
;
1240 int win_start_row
, win_start_col
;
1241 struct map_info_t
*map_info
= wp
->map_information
;
1245 if (start_row
< 0 || stop_row
>= ROWNO
) {
1246 impossible("map_update: bad row range %d-%d\n", start_row
, stop_row
);
1249 if (start_col
< 0 || stop_col
>= COLNO
) {
1250 impossible("map_update: bad col range %d-%d\n", start_col
, stop_col
);
1254 #ifdef VERBOSE_UPDATE
1255 printf("update: [0x%x] %d %d %d %d\n",
1256 (int) wp
->w
, start_row
, stop_row
, start_col
, stop_col
);
1258 win_start_row
= start_row
;
1259 win_start_col
= start_col
;
1261 if (map_info
->is_tile
) {
1262 struct tile_map_info_t
*tile_map
= &map_info
->tile_map
;
1264 Display
*dpy
= XtDisplay(wp
->w
);
1265 Screen
*screen
= DefaultScreenOfDisplay(dpy
);
1267 for (row
= start_row
; row
<= stop_row
; row
++) {
1268 for (cur_col
= start_col
; cur_col
<= stop_col
; cur_col
++) {
1269 int glyph
= tile_map
->glyphs
[row
][cur_col
].glyph
;
1270 int tile
= glyph2tile
[glyph
];
1272 int dest_x
= cur_col
* tile_map
->square_width
;
1273 int dest_y
= row
* tile_map
->square_height
;
1275 src_x
= (tile
% TILES_PER_ROW
) * tile_width
;
1276 src_y
= (tile
/ TILES_PER_ROW
) * tile_height
;
1277 XCopyArea(dpy
, tile_pixmap
, XtWindow(wp
->w
),
1278 tile_map
->black_gc
, /* no grapics_expose */
1279 src_x
, src_y
, tile_width
, tile_height
,
1282 if (glyph_is_pet(glyph
) && iflags
.hilite_pet
) {
1283 /* draw pet annotation (a heart) */
1284 XSetForeground(dpy
, tile_map
->black_gc
,
1285 pet_annotation
.foreground
);
1286 XSetClipOrigin(dpy
, tile_map
->black_gc
, dest_x
, dest_y
);
1287 XSetClipMask(dpy
, tile_map
->black_gc
,
1288 pet_annotation
.bitmap
);
1289 XCopyPlane(dpy
, pet_annotation
.bitmap
, XtWindow(wp
->w
),
1290 tile_map
->black_gc
, 0, 0, pet_annotation
.width
,
1291 pet_annotation
.height
, dest_x
, dest_y
, 1);
1292 XSetClipOrigin(dpy
, tile_map
->black_gc
, 0, 0);
1293 XSetClipMask(dpy
, tile_map
->black_gc
, None
);
1294 XSetForeground(dpy
, tile_map
->black_gc
,
1295 BlackPixelOfScreen(screen
));
1297 if ((tile_map
->glyphs
[row
][cur_col
].special
& MG_OBJPILE
)) {
1298 /* draw object pile annotation (a plus sign) */
1299 XSetForeground(dpy
, tile_map
->black_gc
,
1300 pile_annotation
.foreground
);
1301 XSetClipOrigin(dpy
, tile_map
->black_gc
, dest_x
, dest_y
);
1302 XSetClipMask(dpy
, tile_map
->black_gc
,
1303 pile_annotation
.bitmap
);
1304 XCopyPlane(dpy
, pile_annotation
.bitmap
, XtWindow(wp
->w
),
1305 tile_map
->black_gc
, 0, 0,
1306 pile_annotation
.width
, pile_annotation
.height
,
1308 XSetClipOrigin(dpy
, tile_map
->black_gc
, 0, 0);
1309 XSetClipMask(dpy
, tile_map
->black_gc
, None
);
1310 XSetForeground(dpy
, tile_map
->black_gc
,
1311 BlackPixelOfScreen(screen
));
1317 XDrawRectangle(XtDisplay(wp
->w
), XtWindow(wp
->w
),
1319 /* kludge for white square... */
1320 (tile_map
->glyphs
[start_row
][start_col
].glyph
1321 == cmap_to_glyph(S_ice
))
1322 ? tile_map
->black_gc
1323 : tile_map
->white_gc
,
1327 start_col
* tile_map
->square_width
,
1328 start_row
* tile_map
->square_height
,
1329 tile_map
->square_width
- 1,
1330 tile_map
->square_height
- 1);
1333 struct text_map_info_t
*text_map
= &map_info
->text_map
;
1337 register char *c_ptr
;
1339 int cur_col
, color
, win_ystart
;
1342 for (row
= start_row
; row
<= stop_row
; row
++) {
1344 text_map
->square_ascent
+ (row
* text_map
->square_height
);
1346 t_ptr
= (char *) &(text_map
->text
[row
][start_col
]);
1347 c_ptr
= (char *) &(text_map
->colors
[row
][start_col
]);
1348 cur_col
= start_col
;
1349 while (cur_col
<= stop_col
) {
1353 while ((cur_col
+ count
) <= stop_col
&& *c_ptr
== color
) {
1357 if (color
>= CLR_MAX
) {
1362 XDrawImageString(XtDisplay(wp
->w
), XtWindow(wp
->w
),
1365 ? text_map
->inv_color_gcs
[color
]
1366 : text_map
->color_gcs
[color
])
1368 ? text_map
->inv_copy_gc
1369 : text_map
->copy_gc
),
1370 text_map
->square_lbearing
1371 + (text_map
->square_width
* cur_col
),
1372 win_ystart
, t_ptr
, count
);
1374 /* move text pointer and column count */
1380 #else /* !TEXTCOLOR */
1382 int win_row
, win_xstart
;
1384 /* We always start at the same x window position and have
1385 the same character count. */
1386 win_xstart
= text_map
->square_lbearing
1387 + (win_start_col
* text_map
->square_width
);
1388 count
= stop_col
- start_col
+ 1;
1390 for (row
= start_row
, win_row
= win_start_row
; row
<= stop_row
;
1392 XDrawImageString(XtDisplay(wp
->w
), XtWindow(wp
->w
),
1393 inverted
? text_map
->inv_copy_gc
1394 : text_map
->copy_gc
,
1396 text_map
->square_ascent
1397 + (win_row
* text_map
->square_height
),
1398 (char *) &(text_map
->text
[row
][start_col
]),
1402 #endif /* ?TEXTCOLOR */
1406 /* Adjust the number of rows and columns on the given map window */
1408 set_map_size(wp
, cols
, rows
)
1410 Dimension cols
, rows
;
1415 if (wp
->map_information
->is_tile
) {
1416 wp
->pixel_width
= wp
->map_information
->tile_map
.square_width
* cols
;
1417 wp
->pixel_height
= wp
->map_information
->tile_map
.square_height
* rows
;
1419 wp
->pixel_width
= wp
->map_information
->text_map
.square_width
* cols
;
1420 wp
->pixel_height
= wp
->map_information
->text_map
.square_height
* rows
;
1424 XtSetArg(args
[num_args
], XtNwidth
, wp
->pixel_width
); num_args
++;
1425 XtSetArg(args
[num_args
], XtNheight
, wp
->pixel_height
); num_args
++;
1426 XtSetValues(wp
->w
, args
, num_args
);
1433 struct map_info_t
*map_info
= wp
->map_information
;
1434 struct text_map_info_t
*text_map
= &map_info
->text_map
;
1436 (void) memset((genericptr_t
) text_map
->text
, ' ', sizeof text_map
->text
);
1438 (void) memset((genericptr_t
) text_map
->colors
, NO_COLOR
,
1439 sizeof text_map
->colors
);
1443 get_text_gc(wp
, WindowFont(wp
->w
));
1446 static char map_translations
[] = "#override\n\
1447 <Key>Left: scroll(4)\n\
1448 <Key>Right: scroll(6)\n\
1449 <Key>Up: scroll(8)\n\
1450 <Key>Down: scroll(2)\n\
1455 * The map window creation routine.
1458 create_map_window(wp
, create_popup
, parent
)
1460 boolean create_popup
; /* parent is a popup shell that we create */
1463 struct map_info_t
*map_info
; /* map info pointer */
1464 Widget map
, viewport
;
1467 Dimension rows
, columns
;
1469 int screen_width
, screen_height
;
1476 * Create a popup that accepts key and button events.
1479 XtSetArg(args
[num_args
], XtNinput
, False
);
1482 wp
->popup
= parent
= XtCreatePopupShell("anethack",
1483 topLevelShellWidgetClass
,
1484 toplevel
, args
, num_args
);
1486 * If we're here, then this is an auxiliary map window. If we're
1487 * cancelled via a delete window message, we should just pop down.
1492 XtSetArg(args
[num_args
], XtNallowHoriz
, True
);
1494 XtSetArg(args
[num_args
], XtNallowVert
, True
);
1497 XtSetArg(args
[num_args
], XtNforceBars
, True
);
1500 XtSetArg(args
[num_args
], XtNuseBottom
, True
);
1502 XtSetArg(args
[num_args
], XtNtranslations
,
1503 XtParseTranslationTable(map_translations
));
1505 viewport
= XtCreateManagedWidget("map_viewport", /* name */
1506 viewportWidgetClass
, /* from Window.h */
1507 parent
, /* parent widget */
1508 args
, /* set some values */
1509 num_args
); /* number of values to set */
1512 * Create a map window. We need to set the width and height to some
1513 * value when we create it. We will change it to the value we want
1517 XtSetArg(args
[num_args
], XtNwidth
, 100);
1519 XtSetArg(args
[num_args
], XtNheight
, 100);
1521 XtSetArg(args
[num_args
], XtNtranslations
,
1522 XtParseTranslationTable(map_translations
));
1525 wp
->w
= map
= XtCreateManagedWidget(
1527 windowWidgetClass
, /* widget class from Window.h */
1528 viewport
, /* parent widget */
1529 args
, /* set some values */
1530 num_args
); /* number of values to set */
1532 XtAddCallback(map
, XtNexposeCallback
, map_exposed
, (XtPointer
) 0);
1534 map_info
= wp
->map_information
=
1535 (struct map_info_t
*) alloc(sizeof(struct map_info_t
));
1537 map_info
->viewport_width
= map_info
->viewport_height
= 0;
1539 /* reset the "new entry" indicators */
1540 (void) memset((genericptr_t
) map_info
->t_start
, (char) COLNO
,
1541 sizeof(map_info
->t_start
));
1542 (void) memset((genericptr_t
) map_info
->t_stop
, (char) 0,
1543 sizeof(map_info
->t_stop
));
1545 /* we probably want to restrict this to the 1st map window only */
1546 map_info
->is_tile
= (init_tiles(wp
) && iflags
.wc_tiled_map
);
1550 * Initially, set the map widget to be the size specified by the
1551 * widget rows and columns resources. We need to do this to
1552 * correctly set the viewport window size. After the viewport is
1553 * realized, then the map can resize to its normal size.
1556 XtSetArg(args
[num_args
], nhStr(XtNrows
), &rows
);
1558 XtSetArg(args
[num_args
], nhStr(XtNcolumns
), &columns
);
1560 XtGetValues(wp
->w
, args
, num_args
);
1562 /* Don't bother with windows larger than ROWNOxCOLNO. */
1563 if (columns
> COLNO
)
1568 set_map_size(wp
, columns
, rows
);
1571 * If we have created our own popup, then realize it so that the
1572 * viewport is also realized. Then resize the map window.
1575 XtRealizeWidget(wp
->popup
);
1576 XSetWMProtocols(XtDisplay(wp
->popup
), XtWindow(wp
->popup
),
1577 &wm_delete_window
, 1);
1578 set_map_size(wp
, COLNO
, ROWNO
);
1581 map_all_stone(map_info
);
1585 * Destroy this map window.
1588 destroy_map_window(wp
)
1591 struct map_info_t
*map_info
= wp
->map_information
;
1594 nh_XtPopdown(wp
->popup
);
1597 struct text_map_info_t
*text_map
= &map_info
->text_map
;
1599 /* Free allocated GCs. */
1603 for (i
= 0; i
< CLR_MAX
; i
++) {
1604 XtReleaseGC(wp
->w
, text_map
->color_gcs
[i
]);
1605 XtReleaseGC(wp
->w
, text_map
->inv_color_gcs
[i
]);
1608 XtReleaseGC(wp
->w
, text_map
->copy_gc
);
1609 XtReleaseGC(wp
->w
, text_map
->inv_copy_gc
);
1612 /* Free malloc'ed space. */
1613 free((genericptr_t
) map_info
);
1614 wp
->map_information
= 0;
1617 /* Destroy map widget. */
1618 if (wp
->popup
&& !wp
->keep_window
)
1619 XtDestroyWidget(wp
->popup
), wp
->popup
= (Widget
) 0;
1621 if (wp
->keep_window
)
1622 XtRemoveCallback(wp
->w
, XtNexposeCallback
, map_exposed
,
1625 wp
->type
= NHW_NONE
; /* allow re-use */
1627 /* when map goes away, presumably we're exiting, so get rid of the
1628 cached extended commands menu (if we aren't actually exiting, it
1629 will get recreated if needed again) */
1630 release_extended_cmds();
1633 boolean exit_x_event
; /* exit condition for the event loop */
1640 printf("key = '%s%c'\n", (k
< 32) ? "^" : "", (k
< 32) ? '@' + k
: k
);
1645 * Main X event loop. Here we accept and dispatch X events. We only exit
1646 * under certain circumstances.
1649 x_event(exit_condition
)
1654 boolean keep_going
= TRUE
;
1656 /* Hold globals so function is re-entrant */
1657 boolean hold_exit_x_event
= exit_x_event
;
1659 click_button
= NO_CLICK
; /* reset click exit condition */
1660 exit_x_event
= FALSE
; /* reset callback exit condition */
1663 * Loop until we get a sent event, callback exit, or are accepting key
1664 * press and button press events and we receive one.
1666 if ((exit_condition
== EXIT_ON_KEY_PRESS
1667 || exit_condition
== EXIT_ON_KEY_OR_BUTTON_PRESS
) && incount
)
1671 XtAppNextEvent(app_context
, &event
);
1672 XtDispatchEvent(&event
);
1674 /* See if we can exit. */
1676 switch (exit_condition
) {
1677 case EXIT_ON_SENT_EVENT
: {
1678 XAnyEvent
*any
= (XAnyEvent
*) &event
;
1680 if (any
->send_event
) {
1693 case EXIT_ON_KEY_PRESS
:
1695 /* get first pressed key */
1697 retval
= inbuf
[inptr
];
1698 inptr
= (inptr
+ 1) % INBUF_SIZE
;
1701 } else if (program_state
.done_hup
) {
1703 inptr
= (inptr
+ 1) % INBUF_SIZE
;
1707 case EXIT_ON_KEY_OR_BUTTON_PRESS
:
1708 if (incount
!= 0 || click_button
!= NO_CLICK
) {
1709 if (click_button
!= NO_CLICK
) { /* button press */
1710 /* click values are already set */
1712 } else { /* key press */
1713 /* get first pressed key */
1715 retval
= inbuf
[inptr
];
1716 inptr
= (inptr
+ 1) % INBUF_SIZE
;
1720 } else if (program_state
.done_hup
) {
1722 inptr
= (inptr
+ 1) % INBUF_SIZE
;
1727 panic("x_event: unknown exit condition %d", exit_condition
);
1730 } while (keep_going
);
1732 /* Restore globals */
1733 exit_x_event
= hold_exit_x_event
;