1 /* NetHack 3.6 winX.c $NHDT-Date: 1552441031 2019/03/13 01:37:11 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.73 $ */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata 1994-1999 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2022 */
8 /* JNetHack may be freely redistributed. See license for details. */
11 * "Main" file for the X window-port. This contains most of the interface
12 * routines. Please see doc/window.doc for an description of the window
17 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
20 #ifdef MSDOS /* from compiler */
21 #define SHORT_FILENAMES
24 #include <X11/Intrinsic.h>
25 #include <X11/StringDefs.h>
26 #include <X11/Shell.h>
27 #include <X11/Xaw/AsciiText.h>
28 #include <X11/Xaw/Label.h>
29 #include <X11/Xaw/Form.h>
30 #include <X11/Xaw/Scrollbar.h>
31 #include <X11/Xaw/Paned.h>
32 #include <X11/Xaw/Cardinals.h>
33 #include <X11/Xatom.h>
36 /* for color support */
37 #ifdef SHORT_FILENAMES
38 #include <X11/IntrinsP.h>
40 #include <X11/IntrinsicP.h>
43 #ifdef PRESERVE_NO_SYSV
47 #undef PRESERVE_NO_SYSV
50 #ifdef SHORT_FILENAMES
51 #undef SHORT_FILENAMES /* hack.h will reset via global.h if necessary */
63 /* Should be defined in <X11/Intrinsic.h> but you never know */
64 #ifndef XtSpecificationRelease
65 #define XtSpecificationRelease 0
71 #include "../win/X11/nh72icon"
72 #include "../win/X11/nh56icon"
73 #include "../win/X11/nh32icon"
75 static struct icon_info {
78 unsigned width, height;
79 } icon_data[] = { { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height },
80 { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height },
81 { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height },
82 { (const char *) 0, (unsigned char *) 0, 0, 0 } };
85 * Private global variables (shared among the window port files).
87 struct xwindow window_list[MAX_WINDOWS];
88 AppResources appResources;
89 void FDECL((*input_func), (Widget, XEvent *, String *, Cardinal *));
90 int click_x, click_y, click_button; /* Click position on a map window
91 * (filled by set_button_values()). */
92 int updated_inventory;
94 static void FDECL(X11_error_handler, (String)) NORETURN;
95 static int FDECL(X11_io_error_handler, (Display *));
97 static int FDECL((*old_error_handler), (Display *, XErrorEvent *));
99 #if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
100 #if XtSpecificationRelease >= 6
101 #define X11_HANGUP_SIGNAL
102 static XtSignalId X11_sig_id;
106 /* Interface definition, for windows.c */
107 struct window_procs X11_procs = {
109 (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP
110 | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT),
111 #if defined(STATUS_HILITES)
112 WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS |
115 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
117 X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows,
118 X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow,
119 X11_clear_nhwindow, X11_display_nhwindow, X11_destroy_nhwindow, X11_curs,
120 X11_putstr, genl_putmixed, X11_display_file, X11_start_menu, X11_add_menu,
121 X11_end_menu, X11_select_menu,
122 genl_message_menu, /* no need for X-specific handling */
123 X11_update_inventory, X11_mark_synch, X11_wait_synch,
130 X11_print_glyph, X11_raw_print, X11_raw_print_bold, X11_nhgetch,
131 X11_nh_poskey, X11_nhbell, X11_doprev_message, X11_yn_function,
132 X11_getlin, X11_get_ext_cmd, X11_number_pad, X11_delay_output,
133 #ifdef CHANGE_COLOR /* only a Mac option currently */
136 /* other defs that really should go away (they're tty specific) */
137 X11_start_screen, X11_end_screen,
138 #ifdef GRAPHIC_TOMBSTONE
143 X11_preference_update, X11_getmsghistory, X11_putmsghistory,
144 X11_status_init, X11_status_finish, X11_status_enablefield,
146 genl_can_suspend_no, /* XXX may not always be correct */
152 static winid NDECL(find_free_window);
154 static void FDECL(nhFreePixel, (XtAppContext, XrmValuePtr, XtPointer,
155 XrmValuePtr, Cardinal *));
157 static boolean FDECL(new_resource_macro, (String, unsigned));
158 static void NDECL(load_default_resources);
159 static void NDECL(release_default_resources);
160 static int FDECL(panic_on_error, (Display *, XErrorEvent *));
161 #ifdef X11_HANGUP_SIGNAL
162 static void FDECL(X11_sig, (int));
163 static void FDECL(X11_sig_cb, (XtPointer, XtSignalId *));
165 static void FDECL(d_timeout, (XtPointer, XtIntervalId *));
166 static void FDECL(X11_hangup, (Widget, XEvent *, String *, Cardinal *));
167 static void FDECL(askname_delete, (Widget, XEvent *, String *, Cardinal *));
168 static void FDECL(askname_done, (Widget, XtPointer, XtPointer));
169 static void FDECL(done_button, (Widget, XtPointer, XtPointer));
170 static void FDECL(getline_delete, (Widget, XEvent *, String *, Cardinal *));
171 static void FDECL(abort_button, (Widget, XtPointer, XtPointer));
172 static void NDECL(release_getline_widgets);
173 static void FDECL(yn_delete, (Widget, XEvent *, String *, Cardinal *));
174 static void FDECL(yn_key, (Widget, XEvent *, String *, Cardinal *));
175 static void NDECL(release_yn_widgets);
176 static int FDECL(input_event, (int));
177 static void FDECL(win_visible, (Widget, XtPointer, XEvent *, Boolean *));
178 static void NDECL(init_standard_windows);
180 #ifdef INSTALLCOLORMAP
187 static boolean x_inited = FALSE; /* TRUE if window system is set up. */
188 static winid message_win = WIN_ERR, /* These are the winids of the message, */
189 map_win = WIN_ERR, /* map, and status windows, when they */
190 status_win = WIN_ERR; /* are created in init_windows(). */
191 static Pixmap icon_pixmap = None; /* Pixmap for icon. */
194 X11_putmsghistory(msg, is_restoring)
196 boolean is_restoring;
198 if (WIN_MESSAGE != WIN_ERR) {
199 struct xwindow *wp = &window_list[WIN_MESSAGE];
200 debugpline2("X11_putmsghistory('%s',%i)", msg, is_restoring);
202 append_message(wp, msg);
207 X11_getmsghistory(init)
210 if (WIN_MESSAGE != WIN_ERR) {
211 static struct line_element *curr = (struct line_element *) 0;
212 static int numlines = 0;
213 struct xwindow *wp = &window_list[WIN_MESSAGE];
216 curr = (struct line_element *) 0;
219 curr = wp->mesg_information->head;
223 if (numlines < wp->mesg_information->num_lines) {
226 debugpline2("X11_getmsghistory(%i)='%s'", init, curr->line);
234 * Find the window structure that corresponds to the given widget. Note
235 * that this is not the popup widget, nor the viewport, but the child.
245 * Search to find the corresponding window. Look at the main widget,
246 * popup, the parent of the main widget, then parent of the widget.
248 for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++)
249 if (wp->type != NHW_NONE && (wp->w == w || wp->popup == w
250 || (wp->w && (XtParent(wp->w)) == w)
251 || (wp->popup == XtParent(w))))
254 if (windex == MAX_WINDOWS)
255 panic("find_widget: can't match widget");
260 * Find a free window slot for use.
268 for (windex = 0, wp = &window_list[0]; windex < MAX_WINDOWS;
270 if (wp->type == NHW_NONE)
273 if (windex == MAX_WINDOWS)
274 panic("find_free_window: no free windows!");
275 return (winid) windex;
284 init_menu_nhcolors(wp);
285 /* FIXME: init_menu_nhcolors may fail */
287 if (clr >= 0 && clr < CLR_MAX)
288 return wp->nh_colors[clr];
290 return wp->nh_colors[0];
294 init_menu_nhcolors(wp)
297 static const char *mapCLR_to_res[CLR_MAX] = {
316 Colormap screen_colormap;
322 char clr_name[BUFSZ];
323 char clrclass[BUFSZ];
324 const char *wintypenames[NHW_TEXT] = {
325 "message", "status", "map", "menu", "text"
330 if (wp->nh_colors_inited || !wp->type)
333 wtn = wintypenames[wp->type - 1];
335 (void) upstart(wtn_up);
337 dpy = XtDisplay(wp->w);
338 screen_colormap = DefaultColormap(dpy, DefaultScreen(dpy));
339 rDB = XrmGetDatabase(dpy);
341 for (color = 0; color < CLR_MAX; color++) {
343 Sprintf(clr_name, "nethack.%s.%s", wtn, mapCLR_to_res[color]);
345 Sprintf(clr_name, "jnethack.%s.%s", wtn, mapCLR_to_res[color]);
347 Sprintf(clrclass, "NetHack.%s.%s", wtn_up, mapCLR_to_res[color]);
349 Sprintf(clrclass, "JNetHack.%s.%s", wtn_up, mapCLR_to_res[color]);
351 if (!XrmGetResource(rDB, clr_name, clrclass, ret_type, &value)) {
353 Sprintf(clr_name, "nethack.map.%s", mapCLR_to_res[color]);
355 Sprintf(clr_name, "jnethack.map.%s", mapCLR_to_res[color]);
357 Sprintf(clrclass, "NetHack.Map.%s", mapCLR_to_res[color]);
359 Sprintf(clrclass, "JNetHack.Map.%s", mapCLR_to_res[color]);
362 if (!XrmGetResource(rDB, clr_name, clrclass, ret_type, &value)) {
363 impossible("XrmGetResource error (%s)", clr_name);
364 } else if (!strcmp(ret_type[0], "String")) {
367 if (value.size >= sizeof tmpbuf)
368 value.size = sizeof tmpbuf - 1;
369 (void) strncpy(tmpbuf, (char *) value.addr, (int) value.size);
370 tmpbuf[value.size] = '\0';
371 /* tmpbuf now contains the color name from the named resource */
373 rc = XAllocNamedColor(dpy, screen_colormap, tmpbuf,
374 &wp->nh_colors[color],
375 &wp->nh_colors[color]);
377 impossible("XAllocNamedColor failed for color %i (%s)",
383 wp->nh_colors_inited = TRUE;
387 * Color conversion. The default X11 color converters don't try very
388 * hard to find matching colors in PseudoColor visuals. If they can't
389 * allocate the exact color, they puke and give you something stupid.
390 * This is an attempt to find some close readonly cell and use it.
392 XtConvertArgRec const nhcolorConvertArgs[] = {
393 { XtWidgetBaseOffset,
394 (XtPointer) (ptrdiff_t) XtOffset(Widget, core.screen),
396 { XtWidgetBaseOffset,
397 (XtPointer) (ptrdiff_t) XtOffset(Widget, core.colormap),
401 #define done(type, value) \
403 if (toVal->addr != 0) { \
404 if (toVal->size < sizeof(type)) { \
405 toVal->size = sizeof(type); \
408 *(type *)(toVal->addr) = (value); \
410 static type static_val; \
411 static_val = (value); \
412 toVal->addr = (genericptr_t) &static_val; \
414 toVal->size = sizeof(type); \
419 * Find a color that approximates the color named in "str".
420 * The "str" color may be a color name ("red") or number ("#7f0000").
421 * If str is Null, then "color" is assumed to contain the RGB color wanted.
422 * The approximate color found is returned in color as well.
423 * Return True if something close was found.
426 nhApproxColor(screen, colormap, str, color)
427 Screen *screen; /* screen to use */
428 Colormap colormap; /* the colormap to use */
429 char *str; /* color name */
430 XColor *color; /* the X color structure; changed only if successful */
433 long cdiff = 16777216; /* 2^24; hopefully our map is smaller */
435 static XColor *table = 0;
439 /* if the screen doesn't have a big colormap, don't waste our time
440 or if it's huge, and _some_ match should have been possible */
441 if ((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096)
444 if (str != (char *) 0) {
445 if (!XParseColor(DisplayOfScreen(screen), colormap, str, &tmp))
449 tmp.flags = 7; /* force to use all 3 of RGB */
453 table = (XColor *) XtCalloc(ncells, sizeof(XColor));
454 for (i = 0; i < ncells; i++)
456 XQueryColors(DisplayOfScreen(screen), colormap, table, ncells);
459 /* go thru cells and look for the one with smallest diff */
460 /* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */
461 /* a more knowledgeable color person might improve this -dlc */
463 for (i = 0; i < ncells; i++) {
464 if (table[i].flags == tmp.flags) {
465 j = (int) table[i].red - (int) tmp.red;
469 j = (int) table[i].green - (int) tmp.green;
473 j = (int) table[i].blue - (int) tmp.blue;
479 tmp.pixel = i; /* table[i].pixel == i */
484 if (cdiff == 16777216)
485 return False; /* nothing found?! */
488 * Found something. Return it and mark this color as used to avoid
489 * reuse. Reuse causes major contrast problems :-)
491 *color = table[tmp.pixel];
492 table[tmp.pixel].flags = 0;
493 /* try to alloc the color, so no one else can change it */
494 if (!XAllocColor(DisplayOfScreen(screen), colormap, color)) {
501 #ifdef INSTALLCOLORMAP
503 nhCvtStringToColormap(dpy, args, num_args, fromVal, toVal, data)
512 int screen = DefaultScreen(dpy);
513 Colormap dcmap = DefaultColormap(dpy, screen);
515 if(strncmp(fromVal->addr, "install", 7)){
519 cmap = XCreateColormap(dpy,
520 RootWindow(dpy, screen),
521 DefaultVisual(dpy, screen),
531 white.green = 0xffff;
534 XAllocColor(dpy, dcmap, &black);
535 XAllocColor(dpy, dcmap, &white);
537 XAllocColor(dpy, cmap, &black);
538 XAllocColor(dpy, cmap, &white);
541 done(Colormap, cmap);
543 #endif /*INSTALLCOLORMAP*/
546 nhCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret)
552 XtPointer *closure_ret;
554 String str = (String) fromVal->addr;
558 XtAppContext app = XtDisplayToApplicationContext(dpy);
562 Cardinal num_params = 1;
564 if (*num_args != 2) {
565 XtAppWarningMsg(app, "wrongParameters",
566 "cvtStringToPixel", "XtToolkitError",
567 "String to pixel conversion needs screen and colormap arguments",
568 (String *) 0, (Cardinal *) 0);
572 screen = *((Screen **) args[0].addr);
573 colormap = *((Colormap *) args[1].addr);
575 /* If Xt colors, use the Xt routine and hope for the best */
576 #if (XtSpecificationRelease >= 5)
577 if ((strcmpi(str, XtDefaultBackground) == 0)
578 || (strcmpi(str, XtDefaultForeground) == 0)) {
579 return XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal,
583 if (strcmpi(str, XtDefaultBackground) == 0) {
584 *closure_ret = (char *) False;
585 done(Pixel, WhitePixelOfScreen(screen));
587 if (strcmpi(str, XtDefaultForeground) == 0) {
588 *closure_ret = (char *) False;
589 done(Pixel, BlackPixelOfScreen(screen));
593 status = XAllocNamedColor(DisplayOfScreen(screen), colormap, (char *) str,
594 &screenColor, &exactColor);
598 /* some versions of XAllocNamedColor don't allow #xxyyzz names */
599 if (str[0] == '#' && XParseColor(DisplayOfScreen(screen), colormap,
601 && XAllocColor(DisplayOfScreen(screen), colormap, &exactColor)) {
602 *closure_ret = (char *) True;
603 done(Pixel, exactColor.pixel);
607 /* Server returns a specific error code but Xlib discards it. Ugh */
608 if (XLookupColor(DisplayOfScreen(screen), colormap, (char *) str,
609 &exactColor, &screenColor)) {
610 /* try to find another color that will do */
611 if (nhApproxColor(screen, colormap, (char *) str, &screenColor)) {
612 *closure_ret = (char *) True;
613 done(Pixel, screenColor.pixel);
615 type = nhStr("noColormap");
616 msg = nhStr("Cannot allocate colormap entry for \"%s\"");
618 /* some versions of XLookupColor also don't allow #xxyyzz names */
620 && (nhApproxColor(screen, colormap, (char *) str,
622 *closure_ret = (char *) True;
623 done(Pixel, screenColor.pixel);
625 type = nhStr("badValue");
626 msg = nhStr("Color name \"%s\" is not defined");
629 XtAppWarningMsg(app, type, "cvtStringToPixel", "XtToolkitError", msg,
630 params, &num_params);
631 *closure_ret = False;
634 *closure_ret = (char *) True;
635 done(Pixel, screenColor.pixel);
639 /* Ask the WM for window frame size */
641 get_window_frame_extents(w, top, bottom, left, right)
643 long *top, *bottom, *left, *right;
646 Display *dpy = XtDisplay(w);
647 Window win = XtWindow(w);
650 unsigned long nitems;
651 unsigned long nbytes;
652 unsigned char *data = 0;
655 prop = XInternAtom(dpy, "_NET_FRAME_EXTENTS", True);
657 while (XGetWindowProperty(dpy, win, prop,
658 0, 4, False, AnyPropertyType,
660 &nitems, &nbytes, &data) != Success
661 || nitems != 4 || nbytes != 0)
663 XNextEvent(dpy, &event);
666 extents = (long *) data;
671 *bottom = extents[3];
675 get_widget_window_geometry(w, x,y, width, height)
677 int *x, *y, *width, *height;
679 long top, bottom, left, right;
681 XtSetArg(args[0], nhStr(XtNx), x);
682 XtSetArg(args[1], nhStr(XtNy), y);
683 XtSetArg(args[2], nhStr(XtNwidth), width);
684 XtSetArg(args[3], nhStr(XtNheight), height);
685 XtGetValues(w, args, 4);
686 get_window_frame_extents(w, &top, &bottom, &left, &right);
691 /* Change the full font name string so the weight is "bold" */
693 fontname_boldify(fontname)
694 const char *fontname;
696 static char buf[BUFSZ];
701 if (*fontname == '-')
709 } while (*fontname && *fontname != '-');
733 XtSetArg(args[0], nhStr(XtNfont), &fs);
734 XtGetValues(w, args, 1);
736 if (!XGetFontProperty(fs, XA_FONT, &ret))
739 wp->boldfs_dpy = dpy = XtDisplay(w);
740 fontname = fontname_boldify(XGetAtomName(dpy, (Atom)ret));
741 wp->boldfs = XLoadQueryFont(dpy, fontname);
747 nhFreePixel(app, toVal, closure, args, num_args)
757 if (*num_args != 2) {
758 XtAppWarningMsg(app, "wrongParameters", "freePixel", "XtToolkitError",
759 "Freeing a pixel requires screen and colormap arguments",
760 (String *) 0, (Cardinal *) 0);
764 screen = *((Screen **) args[0].addr);
765 colormap = *((Colormap *) args[1].addr);
768 XFreeColors(DisplayOfScreen(screen), colormap,
769 (unsigned long *) toVal->addr, 1, (unsigned long) 0);
774 /* [ALI] Utility function to ask Xaw for font height, since the previous
775 * assumption of ascent + descent is not always valid.
781 #ifdef _XawTextSink_h
783 XawTextPosition pos = 0;
784 int resWidth, resHeight;
787 XtSetArg(args[0], XtNtextSink, &sink);
788 XtGetValues(w, args, 1);
790 XawTextSinkFindPosition(sink, pos, 0, 0, 0, &pos, &resWidth, &resHeight);
796 XtSetArg(args[0], XtNfont, &fs);
797 XtGetValues(w, args, 1);
799 /* Assume font height is ascent + descent. */
800 return = fs->ascent + fs->descent;
804 static String *default_resource_data = 0, /* NULL-terminated arrays */
805 *def_rsrc_macr = 0, /* macro names */
806 *def_rsrc_valu = 0; /* macro values */
808 /* caller found "#define"; parse into macro name and its expansion value */
810 new_resource_macro(inbuf, numdefs)
811 String inbuf; /* points past '#define' rather than to start of buffer */
812 unsigned numdefs; /* array slot to fill */
816 /* we expect inbuf to be terminated by newline; get rid of it */
818 if (q > inbuf && q[-1] == '\n')
821 /* figure out macro's name */
822 for (p = inbuf; *p == ' ' || *p == '\t'; ++p)
823 continue; /* skip whitespace */
824 for (q = p; *q && *q != ' ' && *q != '\t'; ++q)
825 continue; /* token consists of non-whitespace */
826 Strcat(q, " "); /* guarantee something beyond '#define FOO' */
827 *q++ = '\0'; /* p..(q-1) contains macro name */
828 if (!*p) /* invalid definition: '#define' followed by nothing */
830 def_rsrc_macr[numdefs] = dupstr(p);
832 /* figure out macro's value; empty value is supported but not expected */
833 while (*q == ' ' || *q == '\t')
834 ++q; /* skip whitespace between name and value */
835 for (p = eos(q); --p > q && (*p == ' ' || *p == '\t'); )
836 continue; /* discard trailing whitespace */
837 *++p = '\0'; /* q..p containes macro value */
838 def_rsrc_valu[numdefs] = dupstr(q);
842 /* read the template NetHack.ad into default_resource_data[] to supply
843 fallback resources to XtAppInitialize() */
845 load_default_resources()
849 unsigned insiz, linelen, longlen, numlines, numdefs, midx;
850 boolean comment, isdef;
853 * Running nethack via the shell script adds $HACKDIR to the path used
854 * by X to find resources, but running it directly doesn't. So, if we
855 * can find the template file for NetHack.ad in the current directory,
856 * load its contents into memory so that the application startup call
857 * in X11_init_nhwindows() can use them as fallback resources.
859 * No attempt to support the 'include' directive has been made, nor
860 * backslash+newline continuation lines. Macro expansion (at most
861 * one substitution per line) is supported. '#define' to introduce
862 * a macro must be at start of line (no whitespace before or after
863 * the '#' character).
865 fp = fopen("./NetHack.ad", "r");
869 /* measure the file without retaining its contents */
870 insiz = BUFSIZ; /* stdio BUFSIZ, not nethack BUFSZ */
871 inbuf = (String) alloc(insiz);
872 linelen = longlen = 0;
873 numlines = numdefs = 0;
874 comment = isdef = FALSE; /* lint suppression */
875 while (fgets(inbuf, insiz, fp)) {
877 /* !linelen: inbuf has start of record; treat empty as comment */
878 comment = (*inbuf == '!' || *inbuf == '\n');
879 isdef = !strncmp(inbuf, "#define", 7);
882 linelen += strlen(inbuf);
883 if (!index(inbuf, '\n'))
885 if (linelen > longlen)
888 if (!comment && !isdef)
892 if (numdefs) { /* don't alloc if 0; no need for any terminator */
893 def_rsrc_macr = (String *) alloc(numdefs * sizeof (String));
894 def_rsrc_valu = (String *) alloc(numdefs * sizeof (String));
895 insiz += BUFSIZ; /* include room for macro expansion within buffer */
897 if (insiz > BUFSIZ) {
898 free((genericptr_t) inbuf);
899 inbuf = (String) alloc(insiz);
901 ++numlines; /* room for terminator */
902 default_resource_data = (String *) alloc(numlines * sizeof (String));
904 /* now re-read the file, storing its contents into the allocated array
905 after performing macro substitutions */
907 numlines = numdefs = 0;
908 while (fgets(inbuf, insiz, fp)) {
909 if (!strncmp(inbuf, "#define", 7)) {
910 if (new_resource_macro(&inbuf[7], numdefs))
912 } else if (*inbuf != '!' && *inbuf != '\n') {
915 * Macro expansion: we assume at most one substitution
916 * per line. That's all that our sample NetHack.ad uses.
918 * If we ever need more, this will have to become a lot
919 * more sophisticated. It will need to find the first
920 * instance within inbuf[] rather than first macro which
921 * appears, and to avoid finding names within substituted
924 * Any substitution which would exceed the buffer size is
925 * skipped. A sophisticated implementation would need to
926 * be prepared to allocate a bigger buffer when needed.
928 linelen = strlen(inbuf);
929 for (midx = 0; midx < numdefs; ++midx) {
930 if ((linelen + strlen(def_rsrc_valu[midx])
931 < insiz - strlen(def_rsrc_macr[midx]))
932 && strNsubst(inbuf, def_rsrc_macr[midx],
933 def_rsrc_valu[midx], 1))
937 default_resource_data[numlines++] = dupstr(inbuf);
940 default_resource_data[numlines] = (String) 0;
942 free((genericptr_t) inbuf);
943 if (def_rsrc_macr) { /* implies def_rsrc_valu is non-Null too */
944 for (midx = 0; midx < numdefs; ++midx) {
945 free((genericptr_t) def_rsrc_macr[midx]);
946 free((genericptr_t) def_rsrc_valu[midx]);
948 free((genericptr_t) def_rsrc_macr), def_rsrc_macr = 0;
949 free((genericptr_t) def_rsrc_valu), def_rsrc_valu = 0;
954 release_default_resources()
956 if (default_resource_data) {
959 for (idx = 0; default_resource_data[idx]; idx++)
960 free((genericptr_t) default_resource_data[idx]);
961 free((genericptr_t) default_resource_data), default_resource_data = 0;
963 /* def_rsrc_macr[] and def_rsrc_valu[] have already been released */
966 /* Global Functions ======================================================= */
978 X11_raw_print_bold(str)
988 X11_curs(window, x, y)
994 if (x < 0 || x >= COLNO) {
995 impossible("curs: bad x value [%d]", x);
998 if (y < 0 || y >= ROWNO) {
999 impossible("curs: bad y value [%d]", y);
1003 window_list[window].cursx = x;
1004 window_list[window].cursy = y;
1008 X11_putstr(window, attr, str)
1016 check_winid(window);
1017 wp = &window_list[window];
1021 (void) strncpy(toplines, str, TBUFSZ); /* for Norep(). */
1022 toplines[TBUFSZ - 1] = 0;
1023 append_message(wp, str);
1025 #ifndef STATUS_HILITES
1027 adjust_status(wp, str);
1031 impossible("putstr: called on map window \"%s\"", str);
1034 if (wp->menu_information->is_menu) {
1035 impossible("putstr: called on a menu window, \"%s\" discarded",
1040 * Change this menu window into a text window by creating a
1041 * new text window, then copying it to this winid.
1043 new_win = X11_create_nhwindow(NHW_TEXT);
1044 X11_destroy_nhwindow(window);
1045 *wp = window_list[new_win];
1046 window_list[new_win].type = NHW_NONE; /* allow re-use */
1047 /* fall though to add text */
1049 add_to_text_window(wp, attr, str);
1052 impossible("putstr: unknown window type [%d] \"%s\"", wp->type, str);
1056 /* We do event processing as a callback, so this is a null routine. */
1066 return input_event(EXIT_ON_KEY_PRESS);
1070 X11_nh_poskey(x, y, mod)
1073 int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
1075 if (val == 0) { /* user clicked on a map window */
1078 *mod = click_button;
1084 X11_create_nhwindow(type)
1091 panic("create_nhwindow: windows not initialized");
1093 #ifdef X11_HANGUP_SIGNAL
1094 /* set up our own signal handlers on the first call. Can't do this in
1095 * X11_init_nhwindows because unixmain sets its handler after calling
1096 * all the init routines. */
1097 if (X11_sig_id == 0) {
1098 X11_sig_id = XtAppAddSignal(app_context, X11_sig_cb, (XtPointer) 0);
1101 struct sigaction sact;
1103 (void) memset((char *) &sact, 0, sizeof(struct sigaction));
1104 sact.sa_handler = (SIG_RET_TYPE) X11_sig;
1105 (void) sigaction(SIGHUP, &sact, (struct sigaction *) 0);
1107 (void) sigaction(SIGXCPU, &sact, (struct sigaction *) 0);
1111 (void) signal(SIGHUP, (SIG_RET_TYPE) X11_sig);
1113 (void) signal(SIGXCPU, (SIG_RET_TYPE) X11_sig);
1120 * We have already created the standard message, map, and status
1121 * windows in the window init routine. The first window of that
1122 * type to be created becomes the standard.
1124 * A better way to do this would be to say that init_nhwindows()
1125 * has already defined these three windows.
1127 if (type == NHW_MAP && map_win != WIN_ERR) {
1132 if (type == NHW_MESSAGE && message_win != WIN_ERR) {
1133 window = message_win;
1134 message_win = WIN_ERR;
1137 if (type == NHW_STATUS && status_win != WIN_ERR) {
1138 window = status_win;
1139 status_win = WIN_ERR;
1143 window = find_free_window();
1144 wp = &window_list[window];
1146 /* The create routines will set type, popup, w, and Win_info. */
1147 wp->prevx = wp->prevy = wp->cursx = wp->cursy = wp->pixel_width =
1148 wp->pixel_height = 0;
1149 wp->keep_window = FALSE;
1150 wp->nh_colors_inited = FALSE;
1151 wp->boldfs = (XFontStruct *) 0;
1152 wp->boldfs_dpy = (Display *) 0;
1153 wp->title = (char *) 0;
1157 create_map_window(wp, TRUE, (Widget) 0);
1160 create_message_window(wp, TRUE, (Widget) 0);
1163 create_status_window(wp, TRUE, (Widget) 0);
1166 create_menu_window(wp);
1169 create_text_window(wp);
1172 panic("create_nhwindow: unknown type [%d]", type);
1179 X11_clear_nhwindow(window)
1184 check_winid(window);
1185 wp = &window_list[window];
1189 clear_map_window(wp);
1192 clear_text_window(wp);
1197 /* do nothing for these window types */
1200 panic("clear_nhwindow: unknown window type [%d]", wp->type);
1206 X11_display_nhwindow(window, blocking)
1212 check_winid(window);
1213 wp = &window_list[window];
1218 nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w);
1219 display_map_window(wp); /* flush map */
1222 * We need to flush the message window here due to the way the tty
1223 * port is set up. To flush a window, you need to call this
1224 * routine. However, the tty port _pauses_ with a --more-- if we
1225 * do a display_nhwindow(WIN_MESSAGE, FALSE). Thus, we can't call
1226 * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we
1227 * get a --more-- after every line.
1229 * Perhaps the window document should mention that when the map
1230 * is flushed, everything on the three main windows should be
1231 * flushed. Note: we don't need to flush the status window
1232 * because we don't buffer changes.
1234 if (WIN_MESSAGE != WIN_ERR)
1235 display_message_window(&window_list[WIN_MESSAGE]);
1237 (void) x_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
1241 nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w);
1242 display_message_window(wp); /* flush messages */
1246 nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w);
1247 break; /* no flushing necessary */
1250 menu_item *selected;
1253 n = X11_select_menu(window, PICK_NONE, &selected);
1255 impossible("perminvent: %d selected??", n);
1256 free((genericptr_t) selected);
1261 display_text_window(wp, blocking); /* pop up text window */
1264 panic("display_nhwindow: unknown window type [%d]", wp->type);
1270 X11_destroy_nhwindow(window)
1275 check_winid(window);
1276 wp = &window_list[window];
1278 * "Zap" known windows, but don't destroy them. We need to keep the
1279 * toplevel widget popped up so that later windows (e.g. tombstone)
1280 * are visible on DECWindow systems. This is due to the virtual
1281 * roots that the DECWindow wm creates.
1283 if (window == WIN_MESSAGE) {
1284 wp->keep_window = TRUE;
1285 WIN_MESSAGE = WIN_ERR;
1286 iflags.window_inited = 0;
1287 } else if (window == WIN_MAP) {
1288 wp->keep_window = TRUE;
1290 } else if (window == WIN_STATUS) {
1291 wp->keep_window = TRUE;
1292 WIN_STATUS = WIN_ERR;
1293 } else if (window == WIN_INVEN) {
1294 /* don't need to keep this one */
1295 WIN_INVEN = WIN_ERR;
1299 XFreeFont(wp->boldfs_dpy, wp->boldfs);
1300 wp->boldfs = (XFontStruct *) 0;
1301 wp->boldfs_dpy = (Display *) 0;
1306 wp->title = (char *) 0;
1311 destroy_map_window(wp);
1314 destroy_menu_window(wp);
1317 destroy_text_window(wp);
1320 destroy_status_window(wp);
1323 destroy_message_window(wp);
1326 panic("destroy_nhwindow: unknown window type [%d]", wp->type);
1332 X11_update_inventory()
1334 if (x_inited && window_list[WIN_INVEN].menu_information->is_up) {
1335 updated_inventory = 1; /* hack to avoid mapping&raising window */
1336 (void) display_inventory((char *) 0, FALSE);
1337 updated_inventory = 0;
1341 /* The current implementation has all of the saved lines on the screen. */
1343 X11_doprev_message()
1351 /* We can't use XBell until toplevel has been initialized. */
1353 XBell(XtDisplay(toplevel), 0);
1354 /* else print ^G ?? */
1362 * The window document is unclear about the status of text
1363 * that has been pline()d but not displayed w/display_nhwindow().
1364 * Both the main and tty code assume that a pline() followed
1365 * by mark_synch() results in the text being seen, even if
1366 * display_nhwindow() wasn't called. Duplicate this behavior.
1368 if (WIN_MESSAGE != WIN_ERR)
1369 display_message_window(&window_list[WIN_MESSAGE]);
1370 XSync(XtDisplay(toplevel), False);
1378 XFlush(XtDisplay(toplevel));
1381 /* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */
1383 X11_resume_nhwindows()
1389 X11_suspend_nhwindows(str)
1397 /* Under X, we don't need to initialize the number pad. */
1400 X11_number_pad(state) /* called from options.c */
1408 /* called from setftty() in unixtty.c */
1415 /* called from settty() in unixtty.c */
1422 #ifdef GRAPHIC_TOMBSTONE
1424 X11_outrip(window, how, when)
1432 check_winid(window);
1433 wp = &window_list[window];
1435 /* make sure the graphical tombstone is available; it's not easy to
1436 revert to the ASCII-art text tombstone once we're past this point */
1437 if (appResources.tombstone && *appResources.tombstone)
1438 rip_fp = fopen(appResources.tombstone, "r"); /* "rip.xpm" */
1440 genl_outrip(window, how, when);
1443 (void) fclose(rip_fp);
1445 if (wp->type == NHW_TEXT) {
1446 wp->text_information->is_rip = TRUE;
1448 panic("ripout on non-text window (window type [%d])", wp->type);
1451 calculate_rip_text(how, when);
1455 /* init and exit nhwindows ------------------------------------------------ */
1457 XtAppContext app_context; /* context of application */
1458 Widget toplevel = (Widget) 0; /* toplevel widget */
1459 Atom wm_delete_window; /* pop down windows */
1461 static XtActionsRec actions[] = {
1462 { nhStr("dismiss_text"), dismiss_text }, /* text widget button action */
1463 { nhStr("delete_text"), delete_text }, /* text widget delete action */
1464 { nhStr("key_dismiss_text"), key_dismiss_text }, /* text key action */
1465 #ifdef GRAPHIC_TOMBSTONE
1466 { nhStr("rip_dismiss_text"), rip_dismiss_text }, /* rip in text widget */
1468 { nhStr("menu_key"), menu_key }, /* menu accelerators */
1469 { nhStr("yn_key"), yn_key }, /* yn accelerators */
1470 { nhStr("yn_delete"), yn_delete }, /* yn delete-window */
1471 { nhStr("askname_delete"), askname_delete }, /* askname delete-window */
1472 { nhStr("getline_delete"), getline_delete }, /* getline delete-window */
1473 { nhStr("menu_delete"), menu_delete }, /* menu delete-window */
1474 { nhStr("ec_key"), ec_key }, /* extended commands */
1475 { nhStr("ec_delete"), ec_delete }, /* ext-com menu delete */
1476 { nhStr("ps_key"), ps_key }, /* player selection */
1477 { nhStr("plsel_quit"), plsel_quit }, /* player selection dialog */
1478 { nhStr("plsel_play"), plsel_play }, /* player selection dialog */
1479 { nhStr("plsel_rnd"), plsel_randomize }, /* player selection dialog */
1480 { nhStr("race_key"), race_key }, /* race selection */
1481 { nhStr("gend_key"), gend_key }, /* gender selection */
1482 { nhStr("algn_key"), algn_key }, /* alignment selection */
1483 { nhStr("X11_hangup"), X11_hangup }, /* delete of top-level */
1484 { nhStr("input"), map_input }, /* key input */
1485 { nhStr("scroll"), nh_keyscroll }, /* scrolling by keys */
1488 static XtResource resources[] = {
1489 { nhStr("slow"), nhStr("Slow"), XtRBoolean, sizeof(Boolean),
1490 XtOffset(AppResources *, slow), XtRString, nhStr("True") },
1491 { nhStr("fancy_status"), nhStr("Fancy_status"), XtRBoolean, sizeof(Boolean),
1492 XtOffset(AppResources *, fancy_status), XtRString, nhStr("True") },
1493 { nhStr("autofocus"), nhStr("AutoFocus"), XtRBoolean, sizeof(Boolean),
1494 XtOffset(AppResources *, autofocus), XtRString, nhStr("False") },
1495 { nhStr("message_line"), nhStr("Message_line"), XtRBoolean,
1496 sizeof(Boolean), XtOffset(AppResources *, message_line), XtRString,
1498 { nhStr("highlight_prompt"), nhStr("Highlight_prompt"), XtRBoolean,
1499 sizeof(Boolean), XtOffset(AppResources *, highlight_prompt), XtRString,
1501 { nhStr("double_tile_size"), nhStr("Double_tile_size"), XtRBoolean,
1502 sizeof(Boolean), XtOffset(AppResources *, double_tile_size), XtRString,
1504 { nhStr("tile_file"), nhStr("Tile_file"), XtRString, sizeof(String),
1505 XtOffset(AppResources *, tile_file), XtRString, nhStr("x11tiles") },
1506 { nhStr("icon"), nhStr("Icon"), XtRString, sizeof(String),
1507 XtOffset(AppResources *, icon), XtRString, nhStr("nh72") },
1508 { nhStr("message_lines"), nhStr("Message_lines"), XtRInt, sizeof(int),
1509 XtOffset(AppResources *, message_lines), XtRString, nhStr("12") },
1510 { nhStr("extcmd_height_delta"), nhStr("Extcmd_height_delta"),
1511 XtRInt, sizeof (int),
1512 XtOffset(AppResources *, extcmd_height_delta), XtRString, nhStr("0") },
1513 { nhStr("pet_mark_bitmap"), nhStr("Pet_mark_bitmap"), XtRString,
1514 sizeof(String), XtOffset(AppResources *, pet_mark_bitmap), XtRString,
1515 nhStr("pet_mark.xbm") },
1516 { nhStr("pet_mark_color"), nhStr("Pet_mark_color"), XtRPixel,
1517 sizeof(XtRPixel), XtOffset(AppResources *, pet_mark_color), XtRString,
1519 { nhStr("pilemark_bitmap"), nhStr("Pilemark_bitmap"), XtRString,
1520 sizeof(String), XtOffset(AppResources *, pilemark_bitmap), XtRString,
1521 nhStr("pilemark.xbm") },
1522 { nhStr("pilemark_color"), nhStr("Pilemark_color"), XtRPixel,
1523 sizeof(XtRPixel), XtOffset(AppResources *, pilemark_color), XtRString,
1525 #ifdef GRAPHIC_TOMBSTONE
1526 { nhStr("tombstone"), nhStr("Tombstone"), XtRString, sizeof(String),
1527 XtOffset(AppResources *, tombstone), XtRString, nhStr("rip.xpm") },
1528 { nhStr("tombtext_x"), nhStr("Tombtext_x"), XtRInt, sizeof(int),
1529 XtOffset(AppResources *, tombtext_x), XtRString, nhStr("155") },
1530 { nhStr("tombtext_y"), nhStr("Tombtext_y"), XtRInt, sizeof(int),
1531 XtOffset(AppResources *, tombtext_y), XtRString, nhStr("78") },
1532 { nhStr("tombtext_dx"), nhStr("Tombtext_dx"), XtRInt, sizeof(int),
1533 XtOffset(AppResources *, tombtext_dx), XtRString, nhStr("0") },
1534 { nhStr("tombtext_dy"), nhStr("Tombtext_dy"), XtRInt, sizeof(int),
1535 XtOffset(AppResources *, tombtext_dy), XtRString, nhStr("13") },
1540 panic_on_error(display, error)
1545 XGetErrorText(display, error->error_code, buf, BUFSZ);
1546 fprintf(stderr, "X Error: code %i (%s), request %i, minor %i, serial %lu\n",
1547 error->error_code, buf,
1548 error->request_code, error->minor_code,
1555 X11_error_handler(str)
1560 #ifdef SAFERHANGUP /* keeps going after hangup() for '#if SAFERHANGUP' */
1564 nh_terminate(EXIT_FAILURE);
1568 X11_io_error_handler(display)
1573 #ifdef SAFERHANGUP /* keeps going after hangup() for '#if SAFERHANGUP' */
1576 /*NOREACHED*/ /* but not declared NORETURN */
1582 X11_init_nhwindows(argcp, argv)
1591 /* Init windows to nothing. */
1592 for (i = 0; i < MAX_WINDOWS; i++)
1593 window_list[i].type = NHW_NONE;
1595 /* force high scores display to be shown in a window, and don't allow
1596 that to be toggled off via 'O' (note: 'nethack -s' won't reach here;
1597 its output goes to stdout and could be redirected into a file) */
1598 iflags.toptenwin = TRUE;
1599 set_option_mod_status("toptenwin", SET_IN_FILE);
1601 /* add another option that can be set */
1602 set_wc_option_mod_status(WC_TILED_MAP, SET_IN_GAME);
1603 set_option_mod_status("mouse_support", SET_IN_GAME);
1605 load_default_resources(); /* create default_resource_data[] */
1608 * setuid hack: make sure that if nethack is setuid, to use real uid
1609 * when opening X11 connections, in case the user is using xauth, since
1610 * the "games" or whatever user probably doesn't have permission to open
1611 * a window on the user's display. This code is harmless if the binary
1612 * is not installed setuid. See include/system.h on compilation failures.
1615 (void) seteuid(getuid());
1617 XSetIOErrorHandler(X11_io_error_handler);
1620 XtSetLanguageProc(NULL, NULL, NULL);
1623 XSetIOErrorHandler((XIOErrorHandler) hangup);
1625 #ifdef INSTALLCOLORMAP
1626 XtSetTypeConverter(XtRString, XtRColormap, nhCvtStringToColormap,
1627 0, 0, XtCacheByDisplay, 0);
1630 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
1631 XtSetArg(args[num_args], XtNtitle, "NetHack"); num_args++;
1634 toplevel = XtAppInitialize(&app_context, "NetHack", /* application */
1636 toplevel = XtAppInitialize(&app_context, "JNetHack", /* application */
1638 (XrmOptionDescList) 0, 0, /* options list */
1639 argcp, (String *) argv, /* command line */
1640 default_resource_data, /* fallback resources */
1641 (ArgList) args, num_args);
1642 XtOverrideTranslations(toplevel,
1643 XtParseTranslationTable("<Message>WM_PROTOCOLS: X11_hangup()"));
1645 /* We don't need to realize the top level widget. */
1647 old_error_handler = XSetErrorHandler(panic_on_error);
1650 /* add new color converter to deal with overused colormaps */
1651 XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel,
1652 (XtConvertArgList) nhcolorConvertArgs,
1653 XtNumber(nhcolorConvertArgs), XtCacheByDisplay,
1655 #endif /* TEXTCOLOR */
1657 /* Register the actions mentioned in "actions". */
1658 XtAppAddActions(app_context, actions, XtNumber(actions));
1660 /* Get application-wide resources */
1661 XtGetApplicationResources(toplevel, (XtPointer) &appResources, resources,
1662 XtNumber(resources), (ArgList) 0, ZERO);
1664 /* Initialize other things. */
1665 init_standard_windows();
1667 /* Give the window manager an icon to use; toplevel must be realized. */
1668 if (appResources.icon && *appResources.icon) {
1669 struct icon_info *ip;
1671 for (ip = icon_data; ip->name; ip++)
1672 if (!strcmp(appResources.icon, ip->name)) {
1673 icon_pixmap = XCreateBitmapFromData(
1674 XtDisplay(toplevel), XtWindow(toplevel),
1675 (genericptr_t) ip->bits, ip->width, ip->height);
1676 if (icon_pixmap != None) {
1679 (void) memset((genericptr_t) &hints, 0, sizeof(XWMHints));
1680 hints.flags = IconPixmapHint;
1681 hints.icon_pixmap = icon_pixmap;
1682 XSetWMHints(XtDisplay(toplevel), XtWindow(toplevel),
1689 /* end of setuid hack: reset uid back to the "games" uid */
1690 (void) seteuid(savuid);
1692 x_inited = TRUE; /* X is now initialized */
1693 plsel_ask_name = FALSE;
1695 release_default_resources();
1697 /* Display the startup banner in the message window. */
1698 for (i = 1; i <= 4 + 2; ++i) /* (values beyond 4 yield blank lines) */
1699 X11_putstr(WIN_MESSAGE, 0, copyright_banner_line(i));
1707 X11_exit_nhwindows(dummy)
1710 extern Pixmap tile_pixmap; /* from winmap.c */
1714 /* explicitly free the icon and tile pixmaps */
1715 if (icon_pixmap != None) {
1716 XFreePixmap(XtDisplay(toplevel), icon_pixmap);
1719 if (tile_pixmap != None) {
1720 XFreePixmap(XtDisplay(toplevel), tile_pixmap);
1723 if (WIN_INVEN != WIN_ERR)
1724 X11_destroy_nhwindow(WIN_INVEN);
1725 if (WIN_STATUS != WIN_ERR)
1726 X11_destroy_nhwindow(WIN_STATUS);
1727 if (WIN_MAP != WIN_ERR)
1728 X11_destroy_nhwindow(WIN_MAP);
1729 if (WIN_MESSAGE != WIN_ERR)
1730 X11_destroy_nhwindow(WIN_MESSAGE);
1732 release_getline_widgets();
1733 release_yn_widgets();
1736 #ifdef X11_HANGUP_SIGNAL
1738 X11_sig(sig) /* Unix signal handler */
1741 XtNoticeSignal(X11_sig_id);
1746 X11_sig_cb(not_used, id)
1751 XClientMessageEvent *mesg;
1756 /* Set up a fake message to the event handler. */
1757 mesg = (XClientMessageEvent *) &event;
1758 mesg->type = ClientMessage;
1759 mesg->message_type = XA_STRING;
1762 XSendEvent(XtDisplay(window_list[WIN_MAP].w),
1763 XtWindow(window_list[WIN_MAP].w), False, NoEventMask,
1768 /* delay_output ----------------------------------------------------------- */
1771 * Timeout callback for delay_output(). Send a fake message to the map
1776 d_timeout(client_data, id)
1777 XtPointer client_data;
1781 XClientMessageEvent *mesg;
1786 /* Set up a fake message to the event handler. */
1787 mesg = (XClientMessageEvent *) &event;
1788 mesg->type = ClientMessage;
1789 mesg->message_type = XA_STRING;
1791 XSendEvent(XtDisplay(window_list[WIN_MAP].w),
1792 XtWindow(window_list[WIN_MAP].w), False, NoEventMask,
1797 * Delay for 50ms. This is not implemented asynch. Maybe later.
1798 * Start the timeout, then wait in the event loop. The timeout
1799 * function will send an event to the map window which will be waiting
1808 (void) XtAppAddTimeOut(app_context, 30L, d_timeout, (XtPointer) 0);
1810 /* The timeout function will enable the event loop exit. */
1811 (void) x_event(EXIT_ON_SENT_EVENT);
1814 /* X11_hangup ------------------------------------------------------------- */
1817 X11_hangup(w, event, params, num_params)
1821 Cardinal *num_params;
1828 hangup(1); /* 1 is commonly SIGHUP, but ignored anyway */
1829 exit_x_event = TRUE;
1832 /* askname ---------------------------------------------------------------- */
1835 askname_delete(w, event, params, num_params)
1839 Cardinal *num_params;
1846 (void) strcpy(plname, "Mumbles"); /* give them a name... ;-) */
1847 exit_x_event = TRUE;
1850 /* Callback for askname dialog widget. */
1853 askname_done(w, client_data, call_data)
1855 XtPointer client_data;
1856 XtPointer call_data;
1860 Widget dialog = (Widget) client_data;
1865 s = (char *) GetDialogResponse(dialog);
1873 /* Truncate name if necessary */
1874 if (len >= sizeof plname - 1)
1875 len = sizeof plname - 1;
1877 (void) strncpy(plname, s, len);
1881 nh_XtPopdown(XtParent(dialog));
1882 exit_x_event = TRUE;
1885 /* ask player for character's name to replace generic name "player" (or other
1886 values; see config.h) after 'nethack -u player' or OPTIONS=name:player */
1890 Widget popup, dialog;
1893 if (iflags.wc_player_selection == VIA_DIALOG) {
1894 /* X11_player_selection_dialog() handles name query */
1895 plsel_ask_name = TRUE;
1896 iflags.defer_plname = TRUE;
1898 } /* else iflags.wc_player_selection == VIA_PROMPTS */
1900 XtSetArg(args[0], XtNallowShellResize, True);
1902 popup = XtCreatePopupShell("askname", transientShellWidgetClass, toplevel,
1904 XtOverrideTranslations(popup,
1905 XtParseTranslationTable("<Message>WM_PROTOCOLS: askname_delete()"));
1907 dialog = CreateDialog(popup, nhStr("dialog"), askname_done,
1908 (XtCallbackProc) 0);
1910 SetDialogPrompt(dialog, nhStr("What is your name?")); /* set prompt */
1911 SetDialogResponse(dialog, plname, PL_NSIZ); /* set default answer */
1913 XtRealizeWidget(popup);
1914 positionpopup(popup, TRUE); /* center,bottom */
1916 nh_XtPopup(popup, (int) XtGrabExclusive, dialog);
1918 /* The callback will enable the event loop exit. */
1919 (void) x_event(EXIT_ON_EXIT);
1921 XtDestroyWidget(dialog);
1922 XtDestroyWidget(popup);
1925 /* getline ---------------------------------------------------------------- */
1926 /* This uses Tim Theisen's dialog widget set (from GhostView). */
1928 static Widget getline_popup, getline_dialog;
1930 #define CANCEL_STR "\033"
1931 static char *getline_input;
1933 /* Callback for getline dialog widget. */
1936 done_button(w, client_data, call_data)
1938 XtPointer client_data;
1939 XtPointer call_data;
1943 Widget dialog = (Widget) client_data;
1948 s = (char *) GetDialogResponse(dialog);
1951 /* Truncate input if necessary */
1955 (void) strncpy(getline_input, s, len);
1956 getline_input[len] = '\0';
1959 nh_XtPopdown(XtParent(dialog));
1960 exit_x_event = TRUE;
1965 getline_delete(w, event, params, num_params)
1969 Cardinal *num_params;
1975 Strcpy(getline_input, CANCEL_STR);
1977 exit_x_event = TRUE;
1980 /* Callback for getline dialog widget. */
1983 abort_button(w, client_data, call_data)
1985 XtPointer client_data;
1986 XtPointer call_data;
1988 Widget dialog = (Widget) client_data;
1993 Strcpy(getline_input, CANCEL_STR);
1994 nh_XtPopdown(XtParent(dialog));
1995 exit_x_event = TRUE;
1999 release_getline_widgets()
2002 XtDestroyWidget(getline_dialog), getline_dialog = (Widget) 0;
2004 XtDestroyWidget(getline_popup), getline_popup = (Widget) 0;
2008 X11_getlin(question, input)
2009 const char *question;
2012 getline_input = input;
2015 if (!getline_popup) {
2018 XtSetArg(args[0], XtNallowShellResize, True);
2020 getline_popup = XtCreatePopupShell("getline",
2021 transientShellWidgetClass,
2022 toplevel, args, ONE);
2023 XtOverrideTranslations(getline_popup,
2024 XtParseTranslationTable(
2025 "<Message>WM_PROTOCOLS: getline_delete()"));
2027 getline_dialog = CreateDialog(getline_popup, nhStr("dialog"),
2028 done_button, abort_button);
2030 #if 0 /*JP*//*
\95¶
\8e\9a\97ñ
\90Ý
\92è
\82Ì
\8cã
\82ë
\82É
\89ñ
\82·*/
2031 XtRealizeWidget(getline_popup);
2032 XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup),
2033 &wm_delete_window, 1);
2036 SetDialogPrompt(getline_dialog, (String) question); /* set prompt */
2037 /* 60: make the answer widget be wide enough to hold 60 characters,
2038 or the length of the prompt string, whichever is bigger. User's
2039 response can be longer--when limit is reached, value-so-far will
2040 slide left hiding some chars at the beginning of the response but
2041 making room to type more. [Prior to 3.6.1, width wasn't specifiable
2042 and answer box always got sized to match the width of the prompt.] */
2044 SetDialogResponse(getline_dialog, input, 60); /* set default answer */
2046 SetDialogResponse(getline_dialog, nhStr(""), 60); /* set default answer */
2048 #if 1 /*JP*//*
\95¶
\8e\9a\97ñ
\90Ý
\92è
\82Ì
\8cã
\82ë
\82É
\89ñ
\82·*/
2049 XtRealizeWidget(getline_popup);
2050 XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup),
2051 &wm_delete_window, 1);
2053 positionpopup(getline_popup, TRUE); /* center,bottom */
2055 nh_XtPopup(getline_popup, (int) XtGrabExclusive, getline_dialog);
2057 /* The callback will enable the event loop exit. */
2058 (void) x_event(EXIT_ON_EXIT);
2060 #if 1 /*JP*//*
\96\88\89ñ
\94j
\8aü
\82·
\82é*/
2061 release_getline_widgets();
2065 /* Display file ----------------------------------------------------------- */
2067 /* uses a menu (with no selectors specified) rather than a text window
2068 to allow previous_page and first_menu actions to move backwards */
2070 X11_display_file(str, complain)
2078 menu_item *menu_list;
2083 XFontSetExtents *extent;
2086 /* Use the port-independent file opener to see if the file exists. */
2087 fp = dlb_fopen(str, RDTMODE);
2090 pline("Cannot open %s. Sorry.", str);
2091 return; /* it doesn't exist, ignore */
2094 newwin = X11_create_nhwindow(NHW_MENU);
2095 wp = &window_list[newwin];
2096 X11_start_menu(newwin);
2099 while (dlb_fgets(line, LLEN, fp)) {
2100 X11_add_menu(newwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
2101 line, MENU_UNSELECTED);
2103 (void) dlb_fclose(fp);
2105 /* show file name as the window title */
2107 wp->title = dupstr(str);
2109 wp->menu_information->permi = FALSE;
2110 wp->menu_information->disable_mcolors = TRUE;
2111 (void) X11_select_menu(newwin, PICK_NONE, &menu_list);
2112 X11_destroy_nhwindow(newwin);
2115 /* yn_function ------------------------------------------------------------ */
2116 /* (not threaded) */
2118 static const char *yn_quitchars = " \n\r";
2119 static const char *yn_choices; /* string of acceptable input */
2121 static char yn_return; /* return value */
2122 static char yn_esc_map; /* ESC maps to this char. */
2123 static Widget yn_popup; /* popup for the yn fuction (created once) */
2124 static Widget yn_label; /* label for yn function (created once) */
2125 static boolean yn_getting_num; /* TRUE if accepting digits */
2126 static boolean yn_preserve_case; /* default is to force yn to lower case */
2127 static int yn_ndigits; /* digit count */
2128 static long yn_val; /* accumulated value */
2130 static const char yn_translations[] = "#override\n\
2134 * Convert the given key event into a character. If the key maps to
2135 * more than one character only the first is returned. If there is
2136 * no conversion (i.e. just the CTRL key hit) a NUL is returned.
2139 key_event_to_char(key)
2142 char keystring[MAX_KEY_STRING];
2144 boolean meta = !!(key->state & Mod1Mask);
2146 nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *) 0,
2147 (XComposeStatus *) 0);
2149 /* Modifier keys return a zero lengh string when pressed. */
2153 return (char) (((int) keystring[0]) + (meta ? 0x80 : 0));
2157 * Called when we get a WM_DELETE_WINDOW event on a yn window.
2161 yn_delete(w, event, params, num_params)
2165 Cardinal *num_params;
2172 yn_getting_num = FALSE;
2173 /* Only use yn_esc_map if we have choices. Otherwise, return ESC. */
2174 yn_return = yn_choices ? yn_esc_map : '\033';
2175 exit_x_event = TRUE; /* exit our event handler */
2179 * Called when we get a key press event on a yn window.
2183 yn_key(w, event, params, num_params)
2187 Cardinal *num_params;
2191 if (appResources.slow && !input_func)
2192 map_input(w, event, params, num_params);
2194 ch = key_event_to_char((XKeyEvent *) event);
2196 if (ch == '\0') { /* don't accept nul char or modifier event */
2201 if (!yn_choices) { /* accept any input */
2204 if (!yn_preserve_case)
2205 ch = lowc(ch); /* move to lower case */
2208 yn_getting_num = FALSE;
2209 yn_return = yn_esc_map;
2210 } else if (index(yn_quitchars, ch)) {
2212 } else if (index(yn_choices, ch)) {
2214 if (yn_getting_num) { /* don't select again */
2218 yn_getting_num = TRUE;
2221 return; /* wait for more input */
2225 yn_getting_num = FALSE;
2227 if (yn_getting_num) {
2230 yn_val = (yn_val * 10) + (long) (ch - '0');
2231 return; /* wait for more input */
2233 if (yn_ndigits && (ch == '\b' || ch == 127 /*DEL*/)) {
2235 yn_val = yn_val / 10;
2236 return; /* wait for more input */
2239 X11_nhbell(); /* no match */
2243 if (yn_getting_num) {
2247 yn_number = yn_val; /* assign global */
2250 exit_x_event = TRUE; /* exit our event handler */
2253 /* called at exit time */
2255 release_yn_widgets()
2258 XtDestroyWidget(yn_label), yn_label = (Widget) 0;
2260 XtDestroyWidget(yn_popup), yn_popup = (Widget) 0;
2263 /* X11-specific edition of yn_function(), the routine called by the core
2264 to show a prompt and get a single keystroke answer, often 'y' vs 'n' */
2266 X11_yn_function(ques, choices, def)
2268 const char *choices; /* string of possible response chars; any char if Null */
2269 char def; /* default response if user hits <space> or <return> */
2275 yn_choices = choices; /* set up globals for callback to use */
2277 yn_preserve_case = !choices; /* preserve case when an arbitrary
2278 response is allowed */
2281 * This is sort of a kludge. There are quite a few places in the main
2282 * nethack code where a pline containing information is followed by a
2283 * call to yn_function(). There is no flush of the message window
2284 * (it is implicit in the tty window port), so the line never shows
2285 * up for us! Solution: do our own flush.
2287 if (WIN_MESSAGE != WIN_ERR)
2288 display_message_window(&window_list[WIN_MESSAGE]);
2291 char *cb, choicebuf[QBUFSZ];
2293 Strcpy(choicebuf, choices); /* anything beyond <esc> is hidden */
2294 /* default when choices are present is to force yn answer to
2295 lowercase unless one or more choices are explicitly uppercase;
2296 check this before stripping the hidden choices */
2297 for (cb = choicebuf; *cb; ++cb)
2298 if ('A' <= *cb && *cb <= 'Z') {
2299 yn_preserve_case = TRUE;
2302 if ((cb = index(choicebuf, '\033')) != 0)
2304 /* ques [choices] (def) */
2305 if ((int) (1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= BUFSZ)
2306 panic("X11_yn_function: question too long");
2307 (void) strncpy(buf, ques, QBUFSZ - 1);
2308 buf[QBUFSZ - 1] = '\0';
2309 Sprintf(eos(buf), " [%s]", choicebuf);
2311 Sprintf(eos(buf), " (%c)", def);
2314 /* escape maps to 'q' or 'n' or default, in that order */
2315 yn_esc_map = (index(choices, 'q') ? 'q'
2316 : index(choices, 'n') ? 'n'
2319 if ((int) (1 + strlen(ques) + 1) >= BUFSZ)
2320 panic("X11_yn_function: question too long");
2326 * The 'slow' resource is misleadingly named. When it is True, we
2327 * re-use the same one-line widget above the map for all yn prompt
2328 * responses instead of re-using a popup widget for each one. It's
2329 * crucial for client/server configs where the server is slow putting
2330 * up a popup or requires click-to-focus to respond to the popup, but
2331 * is also useful for players who just want to be able to look at the
2332 * same location to read questions they're being asked to answer.
2335 if (appResources.slow) {
2337 * 'slow': the yn_label widget was created when the map and
2338 * status widgets were, and is positioned between them. It
2339 * will persist until end of game. All we need to do for
2340 * yn_function is direct keystroke input to the yn response
2341 * handler and reset its label to be the prompt text (below).
2343 input_func = yn_key;
2344 highlight_yn(FALSE); /* expose yn_label as separate from map */
2345 } else if (!yn_label) {
2347 * Not 'slow'; create a persistent widget that will be popped up
2348 * as needed, then down again, and last until end of game. The
2349 * associated yn_label widget is used to track whether it exists.
2351 XtSetArg(args[0], XtNallowShellResize, True);
2352 yn_popup = XtCreatePopupShell("query", transientShellWidgetClass,
2353 toplevel, args, ONE);
2354 XtOverrideTranslations(yn_popup,
2355 XtParseTranslationTable("<Message>WM_PROTOCOLS: yn_delete()"));
2358 XtSetArg(args[num_args], XtNtranslations,
2359 XtParseTranslationTable(yn_translations)); num_args++;
2360 #if defined(X11R6) && defined(XI18N)
2361 XtSetArg(args[num_args], XtNinternational, True); num_args++;
2363 yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass,
2364 yn_popup, args, num_args);
2366 XtRealizeWidget(yn_popup);
2367 XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup),
2368 &wm_delete_window, 1);
2371 /* set the label of the yn widget to be the prompt text */
2373 XtSetArg(args[num_args], XtNlabel, buf); num_args++;
2374 XtSetValues(yn_label, args, num_args);
2376 if (!appResources.slow) {
2378 * Due to some kind of weird bug in the X11R4 and X11R5 shell, we
2379 * need to set the label twice to get the size to change.
2382 XtSetArg(args[num_args], XtNlabel, buf); num_args++;
2383 XtSetValues(yn_label, args, num_args);
2385 positionpopup(yn_popup, TRUE);
2386 nh_XtPopup(yn_popup, (int) XtGrabExclusive, yn_label);
2389 yn_getting_num = FALSE;
2390 (void) x_event(EXIT_ON_EXIT); /* get keystroke(s) */
2392 if (appResources.slow) {
2393 /* keystrokes now belong to the map */
2395 /* erase the prompt */
2397 XtSetArg(args[num_args], XtNlabel, " "); num_args++;
2398 XtSetValues(yn_label, args, num_args);
2399 highlight_yn(FALSE); /* disguise yn_label as part of map */
2401 nh_XtPopdown(yn_popup); /* this removes the event grab */
2404 pline("%s%c", buf, (yn_return != '\033') ? yn_return : '\0');
2409 /* used when processing window-capability-specific run-time options;
2410 we support toggling tiles on and off via iflags.wc_tiled_map */
2412 X11_preference_update(pref)
2415 if (!strcmp(pref, "tiled_map")) {
2416 if (WIN_MAP != WIN_ERR)
2417 display_map_window(&window_list[WIN_MAP]);
2421 /* End global functions =================================================== */
2424 * Before we wait for input via nhgetch() and nh_poskey(), we need to
2425 * do some pre-processing.
2428 input_event(exit_condition)
2431 if (appResources.fancy_status && WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */
2432 check_turn_events();
2433 if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */
2434 check_cursor_visibility(&window_list[WIN_MAP]);
2435 if (WIN_MESSAGE != WIN_ERR) /* reset pause line */
2436 set_last_pause(&window_list[WIN_MESSAGE]);
2438 return x_event(exit_condition);
2443 msgkey(w, data, event)
2453 map_input(window_list[WIN_MAP].w, event, (String *) 0, &num);
2456 /* only called for autofocus */
2459 win_visible(w, data, event, flag)
2461 XtPointer data; /* client_data not used */
2463 Boolean *flag; /* continue_to_dispatch flag not used */
2465 XVisibilityEvent *vis_event = (XVisibilityEvent *) event;
2470 if (vis_event->state != VisibilityFullyObscured) {
2471 /* one-time operation; cancel ourself */
2472 XtRemoveEventHandler(toplevel, VisibilityChangeMask, False,
2473 win_visible, (XtPointer) 0);
2474 /* grab initial input focus */
2475 XSetInputFocus(XtDisplay(w), XtWindow(w), RevertToNone, CurrentTime);
2479 /* if 'slow' and 'highlight_prompt', set the yn_label widget to look like
2480 part of the map when idle or to invert background and foreground when
2481 a prompt is active */
2486 struct xwindow *xmap;
2488 if (!appResources.slow || !appResources.highlight_prompt)
2491 /* first time through, WIN_MAP isn't fully initiialized yet */
2492 xmap = ((map_win != WIN_ERR) ? &window_list[map_win]
2493 : (WIN_MAP != WIN_ERR) ? &window_list[WIN_MAP] : 0);
2498 unsigned long fg_bg = (GCForeground | GCBackground);
2499 GC gc = (xmap->map_information->is_tile
2500 ? xmap->map_information->tile_map.white_gc
2501 : xmap->map_information->text_map.copy_gc);
2503 (void) memset((genericptr_t) &vals, 0, sizeof vals);
2504 if (XGetGCValues(XtDisplay(xmap->w), gc, fg_bg, &vals)) {
2505 XtSetArg(args[0], XtNforeground, vals.foreground);
2506 XtSetArg(args[1], XtNbackground, vals.background);
2507 XtSetValues(yn_label, args, TWO);
2510 swap_fg_bg(yn_label);
2514 * Set up the playing console. This has three major parts: the
2515 * message window, the map, and the status window.
2517 * For configs specifying the 'slow' resource, the yn_label widget
2518 * is placed above the map and below the message window. Prompts
2519 * requiring a single character response are displayed there rather
2520 * than using a popup.
2523 init_standard_windows()
2525 Widget form, message_viewport, map_viewport, status;
2528 Dimension message_vp_width, map_vp_width, status_width, max_width;
2529 int map_vp_hd, status_hd;
2533 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
2535 form = XtCreateManagedWidget("nethack", panedWidgetClass, toplevel, args,
2538 form = XtCreateManagedWidget("jnethack", panedWidgetClass, toplevel, args,
2542 XtAddEventHandler(form, KeyPressMask, False, (XtEventHandler) msgkey,
2545 if (appResources.autofocus)
2546 XtAddEventHandler(toplevel, VisibilityChangeMask, False, win_visible,
2550 * Create message window.
2552 WIN_MESSAGE = message_win = find_free_window();
2553 wp = &window_list[message_win];
2554 wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
2555 wp->popup = (Widget) 0;
2556 create_message_window(wp, FALSE, form);
2557 message_viewport = XtParent(wp->w);
2559 /* Tell the form that contains it that resizes are OK. */
2561 XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++;
2562 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
2563 XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
2564 XtSetValues(message_viewport, args, num_args);
2566 if (appResources.slow) {
2568 XtSetArg(args[num_args], XtNtranslations,
2569 XtParseTranslationTable(yn_translations)); num_args++;
2570 #if defined(X11R6) && defined(XI18N)
2571 XtSetArg(args[num_args], XtNinternational, True);
2574 yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, form,
2577 XtSetArg(args[num_args], nhStr(XtNfromVert), message_viewport);
2579 XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft);
2581 XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++;
2582 XtSetArg(args[num_args], nhStr(XtNlabel), " "); num_args++;
2583 XtSetValues(yn_label, args, num_args);
2587 * Create the map window & viewport and chain the viewport beneath the
2590 map_win = find_free_window();
2591 wp = &window_list[map_win];
2592 wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
2593 wp->popup = (Widget) 0;
2594 create_map_window(wp, FALSE, form);
2595 map_viewport = XtParent(wp->w);
2597 /* Chain beneath message_viewport or yn window. */
2599 if (appResources.slow) {
2600 XtSetArg(args[num_args], nhStr(XtNfromVert), yn_label); num_args++;
2602 XtSetArg(args[num_args], nhStr(XtNfromVert), message_viewport);
2605 XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
2606 XtSetValues(map_viewport, args, num_args);
2608 /* Create the status window, with the form as it's parent. */
2609 status_win = find_free_window();
2610 wp = &window_list[status_win];
2611 wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
2612 wp->popup = (Widget) 0;
2613 create_status_window(wp, FALSE, form);
2617 * Chain the status window beneath the viewport. Mark the left and right
2618 * edges so that they stay a fixed distance from the left edge of the
2619 * parent, as well as the top and bottom edges so that they stay a fixed
2620 * distance from the bottom of the parent. We do this so that the status
2621 * will never expand or contract.
2624 XtSetArg(args[num_args], nhStr(XtNfromVert), map_viewport); num_args++;
2625 XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
2626 XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
2627 XtSetArg(args[num_args], nhStr(XtNtop), XtChainBottom); num_args++;
2628 XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
2629 XtSetValues(status, args, num_args);
2632 * Realize the popup so that the status widget knows it's size.
2634 * If we unset MappedWhenManaged then the DECwindow driver doesn't
2635 * attach the nethack toplevel to the highest virtual root window.
2638 /* XtSetMappedWhenManaged(toplevel, False); */
2639 XtRealizeWidget(toplevel);
2640 wm_delete_window = XInternAtom(XtDisplay(toplevel),
2641 "WM_DELETE_WINDOW", False);
2642 XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel),
2643 &wm_delete_window, 1);
2646 * Resize to at most full-screen.
2649 #define TITLEBAR_SPACE 18 /* Leave SOME screen for window decorations */
2651 int screen_width = WidthOfScreen(XtScreen(wp->w));
2652 int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE;
2653 Dimension form_width, form_height;
2655 XtSetArg(args[0], XtNwidth, &form_width);
2656 XtSetArg(args[1], XtNheight, &form_height);
2657 XtGetValues(toplevel, args, TWO);
2659 if (form_width > screen_width || form_height > screen_height) {
2660 XtSetArg(args[0], XtNwidth, min(form_width, screen_width));
2661 XtSetArg(args[1], XtNheight, min(form_height, screen_height));
2662 XtSetValues(toplevel, args, TWO);
2663 XMoveWindow(XtDisplay(toplevel), XtWindow(toplevel), 0,
2666 #undef TITLEBAR_SPACE
2669 post_process_tiles(); /* after toplevel is realized */
2672 * Now get the default widths of the windows.
2674 XtSetArg(args[0], nhStr(XtNwidth), &message_vp_width);
2675 XtGetValues(message_viewport, args, ONE);
2676 XtSetArg(args[0], nhStr(XtNwidth), &map_vp_width);
2677 XtSetArg(args[1], nhStr(XtNhorizDistance), &map_vp_hd);
2678 XtGetValues(map_viewport, args, TWO);
2679 XtSetArg(args[0], nhStr(XtNwidth), &status_width);
2680 XtSetArg(args[1], nhStr(XtNhorizDistance), &status_hd);
2681 XtGetValues(status, args, TWO);
2684 * Adjust positions and sizes. The message viewport widens out to the
2685 * widest width. Both the map and status are centered by adjusting
2686 * their horizDistance.
2688 if (map_vp_width < status_width || map_vp_width < message_vp_width) {
2689 if (status_width > message_vp_width) {
2690 XtSetArg(args[0], nhStr(XtNwidth), status_width);
2691 XtSetValues(message_viewport, args, ONE);
2692 max_width = status_width;
2694 max_width = message_vp_width;
2696 XtSetArg(args[0], nhStr(XtNhorizDistance),
2697 map_vp_hd + ((int) (max_width - map_vp_width) / 2));
2698 XtSetValues(map_viewport, args, ONE);
2700 } else { /* map is widest */
2701 XtSetArg(args[0], nhStr(XtNwidth), map_vp_width);
2702 XtSetValues(message_viewport, args, ONE);
2705 * Clear all data values on the fancy status widget so that the values
2706 * used for spacing don't appear. This needs to be called some time
2707 * after the fancy status widget is realized (above, with the game popup),
2708 * but before it is popped up.
2710 if (appResources.fancy_status)
2713 * Set the map size to its standard size. As with the message window
2714 * above, the map window needs to be set to its constrained size until
2715 * its parent (the viewport widget) was realized.
2717 * Move the message window's slider to the bottom.
2719 set_map_size(&window_list[map_win], COLNO, ROWNO);
2720 set_message_slider(&window_list[message_win]);
2722 /* attempt to catch fatal X11 errors before the program quits */
2723 (void) XtAppSetErrorHandler(app_context, X11_error_handler);
2725 highlight_yn(TRUE); /* switch foreground and background */
2727 /* We can now print to the message window. */
2728 iflags.window_inited = 1;
2732 nh_XtPopup(w, g, childwid)
2733 Widget w; /* widget */
2734 int g; /* type of grab */
2735 Widget childwid; /* child to receive focus (can be None) */
2737 XtPopup(w, (XtGrabKind) g);
2738 XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
2739 if (appResources.autofocus)
2740 XtSetKeyboardFocus(toplevel, childwid);
2748 if (appResources.autofocus)
2749 XtSetKeyboardFocus(toplevel, None);
2760 /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these
2761 * two routines will not be found when linking. An apparently correct
2762 * executable is produced, along with nasty messages and a failure code
2763 * returned to make. The routines are in the static libXmu.a and
2764 * libXmu.sa.4.0, but not in libXmu.so.4.0. Rather than fiddle with
2765 * static linking, we do this.
2767 if (rn2(2) > 2) { /* i.e., FALSE that an optimizer probably can't find */
2768 get_wmShellWidgetClass();
2769 get_applicationShellWidgetClass();
2776 find_scrollbars(w, horiz, vert)
2778 Widget *horiz, *vert;
2782 *horiz = XtNameToWidget(w, "*horizontal");
2783 *vert = XtNameToWidget(w, "*vertical");
2785 } while (!*horiz && !*vert && w);
2790 * Scroll a viewport, using standard NH 1,2,3,4,6,7,8,9 directions.
2794 nh_keyscroll(viewport, event, params, num_params)
2798 Cardinal *num_params;
2801 Widget horiz_sb = (Widget) 0, vert_sb = (Widget) 0;
2805 Cardinal in_nparams = (num_params ? *num_params : 0);
2809 if (in_nparams != 1)
2810 return; /* bad translation */
2812 direction = atoi(params[0]);
2814 find_scrollbars(viewport, &horiz_sb, &vert_sb);
2816 #define H_DELTA 0.25 /* distance of horiz shift */
2817 /* vert shift is half of curr distance */
2818 /* The V_DELTA is 1/2 the value of shown. */
2821 XtSetArg(arg[0], nhStr(XtNshown), &shown);
2822 XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top);
2823 XtGetValues(horiz_sb, arg, TWO);
2827 switch (direction) {
2839 if (top + shown > 1.0)
2847 XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
2852 XtSetArg(arg[0], nhStr(XtNshown), &shown);
2853 XtSetArg(arg[1], nhStr(XtNtopOfThumb), &top);
2854 XtGetValues(vert_sb, arg, TWO);
2858 switch (direction) {
2870 if (top + shown > 1.0)
2878 XtCallCallbacks(vert_sb, XtNjumpProc, &top);