-/* NetHack 3.6 winX.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.33 $ */
-/* Copyright (c) Dean Luick, 1992 */
+/* 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 $ */
+/* Copyright (c) Dean Luick, 1992 */
/* NetHack may be freely redistributed. See license for details. */
+/* JNetHack Copyright */
+/* (c) Issei Numata 1994-1999 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2023 */
+/* JNetHack may be freely redistributed. See license for details. */
+
/*
* "Main" file for the X window-port. This contains most of the interface
* routines. Please see doc/window.doc for an description of the window
* interface.
*/
-/*
-** Japanese version Copyright (C) Issei Numata, 1994-1999
-** changing point is marked `JP' (94/6/7) or XI18N (96/7/19)
-** For 3.4.0, Copyright (c) Kentaro Shirakata, 2002
-** JNetHack may be freely redistributed. See license for details.
-*/
-
#ifndef SYSV
#define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
#endif
#include "hack.h"
#include "winX.h"
#include "dlb.h"
+#include "xwindow.h"
#ifndef NO_SIGNAL
#include <signal.h>
struct xwindow window_list[MAX_WINDOWS];
AppResources appResources;
void FDECL((*input_func), (Widget, XEvent *, String *, Cardinal *));
-int click_x, click_y, click_button; /* Click position on a map window */
- /* (filled by set_button_values()). */
+int click_x, click_y, click_button; /* Click position on a map window
+ * (filled by set_button_values()). */
int updated_inventory;
+static void FDECL(X11_error_handler, (String)) NORETURN;
+static int FDECL(X11_io_error_handler, (Display *));
+
+static int FDECL((*old_error_handler), (Display *, XErrorEvent *));
+
#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
#if XtSpecificationRelease >= 6
#define X11_HANGUP_SIGNAL
#endif
#endif
-/* this is only needed until X11_status_* routines are written */
-extern NEARDATA winid WIN_STATUS;
-
/* Interface definition, for windows.c */
struct window_procs X11_procs = {
- "X11", WC_COLOR | WC_HILITE_PET | WC_TILED_MAP, 0L, X11_init_nhwindows,
+ "X11",
+ (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP
+ | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT),
+#if defined(STATUS_HILITES)
+ WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS |
+#endif
+ 0L,
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
+ X11_init_nhwindows,
X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows,
X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow,
X11_clear_nhwindow, X11_display_nhwindow, X11_destroy_nhwindow, X11_curs,
#else
genl_outrip,
#endif
- X11_preference_update, genl_getmsghistory, genl_putmsghistory,
-#ifdef STATUS_VIA_WINDOWPORT
- genl_status_init, genl_status_finish, genl_status_enablefield,
- genl_status_update,
-#ifdef STATUS_HILITES
- genl_status_threshold,
-#endif
-#endif
+ X11_preference_update, X11_getmsghistory, X11_putmsghistory,
+ X11_status_init, X11_status_finish, X11_status_enablefield,
+ X11_status_update,
genl_can_suspend_no, /* XXX may not always be correct */
};
/*
* Local functions.
*/
-static void FDECL(dismiss_file, (Widget, XEvent *, String *, Cardinal *));
-static void FDECL(delete_file, (Widget, XEvent *, String *, Cardinal *));
-static void FDECL(yn_key, (Widget, XEvent *, String *, Cardinal *));
-static void FDECL(yn_delete, (Widget, XEvent *, String *, Cardinal *));
+static winid NDECL(find_free_window);
+#ifdef TEXTCOLOR
+static void FDECL(nhFreePixel, (XtAppContext, XrmValuePtr, XtPointer,
+ XrmValuePtr, Cardinal *));
+#endif
+static boolean FDECL(new_resource_macro, (String, unsigned));
+static void NDECL(load_default_resources);
+static void NDECL(release_default_resources);
+static int FDECL(panic_on_error, (Display *, XErrorEvent *));
+#ifdef X11_HANGUP_SIGNAL
+static void FDECL(X11_sig, (int));
+static void FDECL(X11_sig_cb, (XtPointer, XtSignalId *));
+#endif
+static void FDECL(d_timeout, (XtPointer, XtIntervalId *));
+static void FDECL(X11_hangup, (Widget, XEvent *, String *, Cardinal *));
static void FDECL(askname_delete, (Widget, XEvent *, String *, Cardinal *));
+static void FDECL(askname_done, (Widget, XtPointer, XtPointer));
+static void FDECL(done_button, (Widget, XtPointer, XtPointer));
static void FDECL(getline_delete, (Widget, XEvent *, String *, Cardinal *));
-static void FDECL(X11_hangup, (Widget, XEvent *, String *, Cardinal *));
+static void FDECL(abort_button, (Widget, XtPointer, XtPointer));
+static void NDECL(release_getline_widgets);
+static void FDECL(yn_delete, (Widget, XEvent *, String *, Cardinal *));
+static void FDECL(yn_key, (Widget, XEvent *, String *, Cardinal *));
+static void NDECL(release_yn_widgets);
static int FDECL(input_event, (int));
static void FDECL(win_visible, (Widget, XtPointer, XEvent *, Boolean *));
static void NDECL(init_standard_windows);
-#ifdef X11_HANGUP_SIGNAL
-static void FDECL(X11_sig, (int));
-static void FDECL(X11_sig_cb, (XtPointer, XtSignalId *));
+
+#ifdef INSTALLCOLORMAP
+Colormap cmap;
#endif
/*
* Local variables.
*/
-static boolean x_inited = FALSE; /* TRUE if window system is set up. */
-static winid message_win = WIN_ERR, /* These are the winids of the */
- map_win = WIN_ERR, /* message, map, and status */
- status_win = WIN_ERR; /* windows, when they are created */
- /* in init_windows(). */
-static Pixmap icon_pixmap = None; /* Pixmap for icon. */
+static boolean x_inited = FALSE; /* TRUE if window system is set up. */
+static winid message_win = WIN_ERR, /* These are the winids of the message, */
+ map_win = WIN_ERR, /* map, and status windows, when they */
+ status_win = WIN_ERR; /* are created in init_windows(). */
+static Pixmap icon_pixmap = None; /* Pixmap for icon. */
-#ifdef INSTALLCOLORMAP
-Colormap cmap;
-#endif
+void
+X11_putmsghistory(msg, is_restoring)
+const char *msg;
+boolean is_restoring;
+{
+ if (WIN_MESSAGE != WIN_ERR) {
+ struct xwindow *wp = &window_list[WIN_MESSAGE];
+ debugpline2("X11_putmsghistory('%s',%i)", msg, is_restoring);
+ if (msg)
+ append_message(wp, msg);
+ }
+}
+
+char *
+X11_getmsghistory(init)
+boolean init;
+{
+ if (WIN_MESSAGE != WIN_ERR) {
+ static struct line_element *curr = (struct line_element *) 0;
+ static int numlines = 0;
+ struct xwindow *wp = &window_list[WIN_MESSAGE];
+
+ if (init)
+ curr = (struct line_element *) 0;
+
+ if (!curr) {
+ curr = wp->mesg_information->head;
+ numlines = 0;
+ }
+
+ if (numlines < wp->mesg_information->num_lines) {
+ curr = curr->next;
+ numlines++;
+ debugpline2("X11_getmsghistory(%i)='%s'", init, curr->line);
+ return curr->line;
+ }
+ }
+ return (char *) 0;
+}
/*
* Find the window structure that corresponds to the given widget. Note
int windex;
struct xwindow *wp;
- /* Search to find the corresponding window. Look at the main widget, */
- /* popup, the parent of the main widget, then parent of the widget. */
+ /*
+ * Search to find the corresponding window. Look at the main widget,
+ * popup, the parent of the main widget, then parent of the widget.
+ */
for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++)
if (wp->type != NHW_NONE && (wp->w == w || wp->popup == w
|| (wp->w && (XtParent(wp->w)) == w)
return (winid) windex;
}
+
+XColor
+get_nhcolor(wp, clr)
+struct xwindow *wp;
+int clr;
+{
+ init_menu_nhcolors(wp);
+ /* FIXME: init_menu_nhcolors may fail */
+
+ if (clr >= 0 && clr < CLR_MAX)
+ return wp->nh_colors[clr];
+
+ return wp->nh_colors[0];
+}
+
+void
+init_menu_nhcolors(wp)
+struct xwindow *wp;
+{
+ static const char *mapCLR_to_res[CLR_MAX] = {
+ XtNblack,
+ XtNred,
+ XtNgreen,
+ XtNbrown,
+ XtNblue,
+ XtNmagenta,
+ XtNcyan,
+ XtNgray,
+ XtNforeground,
+ XtNorange,
+ XtNbright_green,
+ XtNyellow,
+ XtNbright_blue,
+ XtNbright_magenta,
+ XtNbright_cyan,
+ XtNwhite,
+ };
+ Display *dpy;
+ Colormap screen_colormap;
+ XrmDatabase rDB;
+ XrmValue value;
+ Status rc;
+ int color;
+ char *ret_type[32];
+ char clr_name[BUFSZ];
+ char clrclass[BUFSZ];
+ const char *wintypenames[NHW_TEXT] = {
+ "message", "status", "map", "menu", "text"
+ };
+ const char *wtn;
+ char wtn_up[BUFSZ];
+
+ if (wp->nh_colors_inited || !wp->type)
+ return;
+
+ wtn = wintypenames[wp->type - 1];
+ Strcpy(wtn_up, wtn);
+ (void) upstart(wtn_up);
+
+ dpy = XtDisplay(wp->w);
+ screen_colormap = DefaultColormap(dpy, DefaultScreen(dpy));
+ rDB = XrmGetDatabase(dpy);
+
+ for (color = 0; color < CLR_MAX; color++) {
+/*JP
+ Sprintf(clr_name, "nethack.%s.%s", wtn, mapCLR_to_res[color]);
+*/
+ Sprintf(clr_name, "jnethack.%s.%s", wtn, mapCLR_to_res[color]);
+/*JP
+ Sprintf(clrclass, "NetHack.%s.%s", wtn_up, mapCLR_to_res[color]);
+*/
+ Sprintf(clrclass, "JNetHack.%s.%s", wtn_up, mapCLR_to_res[color]);
+
+ if (!XrmGetResource(rDB, clr_name, clrclass, ret_type, &value)) {
+/*JP
+ Sprintf(clr_name, "nethack.map.%s", mapCLR_to_res[color]);
+*/
+ Sprintf(clr_name, "jnethack.map.%s", mapCLR_to_res[color]);
+/*JP
+ Sprintf(clrclass, "NetHack.Map.%s", mapCLR_to_res[color]);
+*/
+ Sprintf(clrclass, "JNetHack.Map.%s", mapCLR_to_res[color]);
+ }
+
+ if (!XrmGetResource(rDB, clr_name, clrclass, ret_type, &value)) {
+ impossible("XrmGetResource error (%s)", clr_name);
+ } else if (!strcmp(ret_type[0], "String")) {
+ char tmpbuf[256];
+
+ if (value.size >= sizeof tmpbuf)
+ value.size = sizeof tmpbuf - 1;
+ (void) strncpy(tmpbuf, (char *) value.addr, (int) value.size);
+ tmpbuf[value.size] = '\0';
+ /* tmpbuf now contains the color name from the named resource */
+
+ rc = XAllocNamedColor(dpy, screen_colormap, tmpbuf,
+ &wp->nh_colors[color],
+ &wp->nh_colors[color]);
+ if (rc == 0) {
+ impossible("XAllocNamedColor failed for color %i (%s)",
+ color, clr_name);
+ }
+ }
+ }
+
+ wp->nh_colors_inited = TRUE;
+}
+
/*
* Color conversion. The default X11 color converters don't try very
* hard to find matching colors in PseudoColor visuals. If they can't
* This is an attempt to find some close readonly cell and use it.
*/
XtConvertArgRec const nhcolorConvertArgs[] = {
- { XtWidgetBaseOffset, (XtPointer) XtOffset(Widget, core.screen),
- sizeof(Screen *) },
- { XtWidgetBaseOffset, (XtPointer) XtOffset(Widget, core.colormap),
- sizeof(Colormap) }
+ { XtWidgetBaseOffset,
+ (XtPointer) (ptrdiff_t) XtOffset(Widget, core.screen),
+ sizeof (Screen *) },
+ { XtWidgetBaseOffset,
+ (XtPointer) (ptrdiff_t) XtOffset(Widget, core.colormap),
+ sizeof (Colormap) }
};
#define done(type, value) \
}
/*
- * Find a color that approximates the color named in "str". The "str" color
- * may be a color name ("red") or number ("#7f0000"). If str == NULL, then
- * "color" is assumed to contain the RGB color wanted.
+ * Find a color that approximates the color named in "str".
+ * The "str" color may be a color name ("red") or number ("#7f0000").
+ * If str is Null, then "color" is assumed to contain the RGB color wanted.
* The approximate color found is returned in color as well.
* Return True if something close was found.
*/
register int i, j;
register long tdiff;
- /* if the screen doesn't have a big colormap, don't waste our time */
- /* or if it's huge, and _some_ match should have been possible */
+ /* if the screen doesn't have a big colormap, don't waste our time
+ or if it's huge, and _some_ match should have been possible */
if ((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096)
return False;
XQueryColors(DisplayOfScreen(screen), colormap, table, ncells);
}
-/* go thru cells and look for the one with smallest diff */
+/* go thru cells and look for the one with smallest diff */
/* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */
-/* a more knowledgeable color person might improve this -dlc */
+/* a more knowledgeable color person might improve this -dlc */
try_again:
for (i = 0; i < ncells; i++) {
if (table[i].flags == tmp.flags) {
Cardinal num_params = 1;
if (*num_args != 2) {
- XtAppWarningMsg(
- app, "wrongParameters", "cvtStringToPixel", "XtToolkitError",
- "String to pixel conversion needs screen and colormap arguments",
- (String *) 0, (Cardinal *) 0);
+ XtAppWarningMsg(app, "wrongParameters",
+ "cvtStringToPixel", "XtToolkitError",
+ "String to pixel conversion needs screen and colormap arguments",
+ (String *) 0, (Cardinal *) 0);
return False;
}
}
}
+/* Ask the WM for window frame size */
+void
+get_window_frame_extents(w, top, bottom, left, right)
+Widget w;
+long *top, *bottom, *left, *right;
+{
+ XEvent event;
+ Display *dpy = XtDisplay(w);
+ Window win = XtWindow(w);
+ Atom prop, retprop;
+ int retfmt;
+ unsigned long nitems;
+ unsigned long nbytes;
+ unsigned char *data = 0;
+ long *extents;
+
+ prop = XInternAtom(dpy, "_NET_FRAME_EXTENTS", True);
+
+ while (XGetWindowProperty(dpy, win, prop,
+ 0, 4, False, AnyPropertyType,
+ &retprop, &retfmt,
+ &nitems, &nbytes, &data) != Success
+ || nitems != 4 || nbytes != 0)
+ {
+ XNextEvent(dpy, &event);
+ }
+
+ extents = (long *) data;
+
+ *left = extents[0];
+ *right = extents[1];
+ *top = extents[2];
+ *bottom = extents[3];
+}
+
+void
+get_widget_window_geometry(w, x,y, width, height)
+Widget w;
+int *x, *y, *width, *height;
+{
+ long top, bottom, left, right;
+ Arg args[5];
+ XtSetArg(args[0], nhStr(XtNx), x);
+ XtSetArg(args[1], nhStr(XtNy), y);
+ XtSetArg(args[2], nhStr(XtNwidth), width);
+ XtSetArg(args[3], nhStr(XtNheight), height);
+ XtGetValues(w, args, 4);
+ get_window_frame_extents(w, &top, &bottom, &left, &right);
+ *x -= left;
+ *y -= top;
+}
+
+/* Change the full font name string so the weight is "bold" */
+char *
+fontname_boldify(fontname)
+const char *fontname;
+{
+ static char buf[BUFSZ];
+ char *bufp = buf;
+ int idx = 0;
+
+ while (*fontname) {
+ if (*fontname == '-')
+ idx++;
+ *bufp = *fontname;
+ if (idx == 3) {
+ strcat(buf, "bold");
+ bufp += 5;
+ do {
+ fontname++;
+ } while (*fontname && *fontname != '-');
+ } else {
+ bufp++;
+ fontname++;
+ }
+ }
+ *bufp = '\0';
+ return buf;
+}
+
+void
+load_boldfont(wp, w)
+struct xwindow *wp;
+Widget w;
+{
+ Arg args[1];
+ XFontStruct *fs;
+ unsigned long ret;
+ char *fontname;
+ Display *dpy;
+
+ if (wp->boldfs)
+ return;
+
+ XtSetArg(args[0], nhStr(XtNfont), &fs);
+ XtGetValues(w, args, 1);
+
+ if (!XGetFontProperty(fs, XA_FONT, &ret))
+ return;
+
+ wp->boldfs_dpy = dpy = XtDisplay(w);
+ fontname = fontname_boldify(XGetAtomName(dpy, (Atom)ret));
+ wp->boldfs = XLoadQueryFont(dpy, fontname);
+}
+
+#ifdef TEXTCOLOR
/* ARGSUSED */
static void
nhFreePixel(app, toVal, closure, args, num_args)
Colormap colormap;
if (*num_args != 2) {
- XtAppWarningMsg(
- app, "wrongParameters", "freePixel", "XtToolkitError",
- "Freeing a pixel requires screen and colormap arguments",
- (String *) 0, (Cardinal *) 0);
+ XtAppWarningMsg(app, "wrongParameters", "freePixel", "XtToolkitError",
+ "Freeing a pixel requires screen and colormap arguments",
+ (String *) 0, (Cardinal *) 0);
return;
}
(unsigned long *) toVal->addr, 1, (unsigned long) 0);
}
}
+#endif /*TEXTCOLOR*/
/* [ALI] Utility function to ask Xaw for font height, since the previous
* assumption of ascent + descent is not always valid.
*/
-Dimension nhFontHeight(w) Widget w;
-#ifdef _XawTextSink_h
+Dimension
+nhFontHeight(w)
+Widget w;
{
+#ifdef _XawTextSink_h
Widget sink;
XawTextPosition pos = 0;
int resWidth, resHeight;
XawTextSinkFindPosition(sink, pos, 0, 0, 0, &pos, &resWidth, &resHeight);
return resHeight;
-}
#else
-{
XFontStruct *fs;
Arg args[1];
/* Assume font height is ascent + descent. */
return = fs->ascent + fs->descent;
-}
#endif
+}
-/* Global Functions ========================================================
- */
+static String *default_resource_data = 0, /* NULL-terminated arrays */
+ *def_rsrc_macr = 0, /* macro names */
+ *def_rsrc_valu = 0; /* macro values */
+
+/* caller found "#define"; parse into macro name and its expansion value */
+static boolean
+new_resource_macro(inbuf, numdefs)
+String inbuf; /* points past '#define' rather than to start of buffer */
+unsigned numdefs; /* array slot to fill */
+{
+ String p, q;
+
+ /* we expect inbuf to be terminated by newline; get rid of it */
+ q = eos(inbuf);
+ if (q > inbuf && q[-1] == '\n')
+ q[-1] = '\0';
+
+ /* figure out macro's name */
+ for (p = inbuf; *p == ' ' || *p == '\t'; ++p)
+ continue; /* skip whitespace */
+ for (q = p; *q && *q != ' ' && *q != '\t'; ++q)
+ continue; /* token consists of non-whitespace */
+ Strcat(q, " "); /* guarantee something beyond '#define FOO' */
+ *q++ = '\0'; /* p..(q-1) contains macro name */
+ if (!*p) /* invalid definition: '#define' followed by nothing */
+ return FALSE;
+ def_rsrc_macr[numdefs] = dupstr(p);
+
+ /* figure out macro's value; empty value is supported but not expected */
+ while (*q == ' ' || *q == '\t')
+ ++q; /* skip whitespace between name and value */
+ for (p = eos(q); --p > q && (*p == ' ' || *p == '\t'); )
+ continue; /* discard trailing whitespace */
+ *++p = '\0'; /* q..p containes macro value */
+ def_rsrc_valu[numdefs] = dupstr(q);
+ return TRUE;
+}
+
+/* read the template NetHack.ad into default_resource_data[] to supply
+ fallback resources to XtAppInitialize() */
+static void
+load_default_resources()
+{
+ FILE *fp;
+ String inbuf;
+ unsigned insiz, linelen, longlen, numlines, numdefs, midx;
+ boolean comment, isdef;
+
+ /*
+ * Running nethack via the shell script adds $HACKDIR to the path used
+ * by X to find resources, but running it directly doesn't. So, if we
+ * can find the template file for NetHack.ad in the current directory,
+ * load its contents into memory so that the application startup call
+ * in X11_init_nhwindows() can use them as fallback resources.
+ *
+ * No attempt to support the 'include' directive has been made, nor
+ * backslash+newline continuation lines. Macro expansion (at most
+ * one substitution per line) is supported. '#define' to introduce
+ * a macro must be at start of line (no whitespace before or after
+ * the '#' character).
+ */
+ fp = fopen("./NetHack.ad", "r");
+ if (!fp)
+ return;
+
+ /* measure the file without retaining its contents */
+ insiz = BUFSIZ; /* stdio BUFSIZ, not nethack BUFSZ */
+ inbuf = (String) alloc(insiz);
+ linelen = longlen = 0;
+ numlines = numdefs = 0;
+ comment = isdef = FALSE; /* lint suppression */
+ while (fgets(inbuf, insiz, fp)) {
+ if (!linelen) {
+ /* !linelen: inbuf has start of record; treat empty as comment */
+ comment = (*inbuf == '!' || *inbuf == '\n');
+ isdef = !strncmp(inbuf, "#define", 7);
+ ++numdefs;
+ }
+ linelen += strlen(inbuf);
+ if (!index(inbuf, '\n'))
+ continue;
+ if (linelen > longlen)
+ longlen = linelen;
+ linelen = 0;
+ if (!comment && !isdef)
+ ++numlines;
+ }
+ insiz = longlen + 1;
+ if (numdefs) { /* don't alloc if 0; no need for any terminator */
+ def_rsrc_macr = (String *) alloc(numdefs * sizeof (String));
+ def_rsrc_valu = (String *) alloc(numdefs * sizeof (String));
+ insiz += BUFSIZ; /* include room for macro expansion within buffer */
+ }
+ if (insiz > BUFSIZ) {
+ free((genericptr_t) inbuf);
+ inbuf = (String) alloc(insiz);
+ }
+ ++numlines; /* room for terminator */
+ default_resource_data = (String *) alloc(numlines * sizeof (String));
+
+ /* now re-read the file, storing its contents into the allocated array
+ after performing macro substitutions */
+ (void) rewind(fp);
+ numlines = numdefs = 0;
+ while (fgets(inbuf, insiz, fp)) {
+ if (!strncmp(inbuf, "#define", 7)) {
+ if (new_resource_macro(&inbuf[7], numdefs))
+ ++numdefs;
+ } else if (*inbuf != '!' && *inbuf != '\n') {
+ if (numdefs) {
+ /*
+ * Macro expansion: we assume at most one substitution
+ * per line. That's all that our sample NetHack.ad uses.
+ *
+ * If we ever need more, this will have to become a lot
+ * more sophisticated. It will need to find the first
+ * instance within inbuf[] rather than first macro which
+ * appears, and to avoid finding names within substituted
+ * expansion values.
+ *
+ * Any substitution which would exceed the buffer size is
+ * skipped. A sophisticated implementation would need to
+ * be prepared to allocate a bigger buffer when needed.
+ */
+ linelen = strlen(inbuf);
+ for (midx = 0; midx < numdefs; ++midx) {
+ if ((linelen + strlen(def_rsrc_valu[midx])
+ < insiz - strlen(def_rsrc_macr[midx]))
+ && strNsubst(inbuf, def_rsrc_macr[midx],
+ def_rsrc_valu[midx], 1))
+ break;
+ }
+ }
+ default_resource_data[numlines++] = dupstr(inbuf);
+ }
+ }
+ default_resource_data[numlines] = (String) 0;
+ (void) fclose(fp);
+ free((genericptr_t) inbuf);
+ if (def_rsrc_macr) { /* implies def_rsrc_valu is non-Null too */
+ for (midx = 0; midx < numdefs; ++midx) {
+ free((genericptr_t) def_rsrc_macr[midx]);
+ free((genericptr_t) def_rsrc_valu[midx]);
+ }
+ free((genericptr_t) def_rsrc_macr), def_rsrc_macr = 0;
+ free((genericptr_t) def_rsrc_valu), def_rsrc_valu = 0;
+ }
+}
+
+static void
+release_default_resources()
+{
+ if (default_resource_data) {
+ unsigned idx;
+
+ for (idx = 0; default_resource_data[idx]; idx++)
+ free((genericptr_t) default_resource_data[idx]);
+ free((genericptr_t) default_resource_data), default_resource_data = 0;
+ }
+ /* def_rsrc_macr[] and def_rsrc_valu[] have already been released */
+}
+
+/* Global Functions ======================================================= */
void
X11_raw_print(str)
const char *str;
toplines[TBUFSZ - 1] = 0;
append_message(wp, str);
break;
+#ifndef STATUS_HILITES
case NHW_STATUS:
adjust_status(wp, str);
break;
+#endif
case NHW_MAP:
impossible("putstr: called on map window \"%s\"", str);
break;
wp->prevx = wp->prevy = wp->cursx = wp->cursy = wp->pixel_width =
wp->pixel_height = 0;
wp->keep_window = FALSE;
+ wp->nh_colors_inited = FALSE;
+ wp->boldfs = (XFontStruct *) 0;
+ wp->boldfs_dpy = (Display *) 0;
+ wp->title = (char *) 0;
switch (type) {
case NHW_MAP:
if (wp->popup)
nh_XtPopup(wp->popup, (int) XtGrabNone, wp->w);
display_map_window(wp); /* flush map */
- /*
- * We need to flush the message window here due to the way the tty
- * port is set up. To flush a window, you need to call this
- * routine. However, the tty port _pauses_ with a --more-- if we
- * do a display_nhwindow(WIN_MESSAGE, FALSE). Thus, we can't call
- * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we
- * get a --more-- after every line.
- *
- * Perhaps the window document should mention that when the map
- * is flushed, everything on the three main windows should be
- * flushed. Note: we don't need to flush the status window
- * because we don't buffer changes.
- */
+
+ /*
+ * We need to flush the message window here due to the way the tty
+ * port is set up. To flush a window, you need to call this
+ * routine. However, the tty port _pauses_ with a --more-- if we
+ * do a display_nhwindow(WIN_MESSAGE, FALSE). Thus, we can't call
+ * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we
+ * get a --more-- after every line.
+ *
+ * Perhaps the window document should mention that when the map
+ * is flushed, everything on the three main windows should be
+ * flushed. Note: we don't need to flush the status window
+ * because we don't buffer changes.
+ */
if (WIN_MESSAGE != WIN_ERR)
display_message_window(&window_list[WIN_MESSAGE]);
if (blocking)
WIN_INVEN = WIN_ERR;
}
+ if (wp->boldfs) {
+ XFreeFont(wp->boldfs_dpy, wp->boldfs);
+ wp->boldfs = (XFontStruct *) 0;
+ wp->boldfs_dpy = (Display *) 0;
+ }
+
+ if (wp->title) {
+ free(wp->title);
+ wp->title = (char *) 0;
+ }
+
switch (wp->type) {
case NHW_MAP:
destroy_map_window(wp);
/* Under X, we don't need to initialize the number pad. */
/* ARGSUSED */
-void X11_number_pad(state) /* called from options.c */
+void
+X11_number_pad(state) /* called from options.c */
int state;
{
nhUse(state);
return;
}
+/* called from setftty() in unixtty.c */
void
X11_start_screen()
{
return;
-} /* called from setftty() in unixtty.c */
+}
+
+/* called from settty() in unixtty.c */
void
X11_end_screen()
{
return;
-} /* called from settty() in unixtty.c */
+}
#ifdef GRAPHIC_TOMBSTONE
void
time_t when;
{
struct xwindow *wp;
+ FILE *rip_fp = 0;
check_winid(window);
wp = &window_list[window];
+ /* make sure the graphical tombstone is available; it's not easy to
+ revert to the ASCII-art text tombstone once we're past this point */
+ if (appResources.tombstone && *appResources.tombstone)
+ rip_fp = fopen(appResources.tombstone, "r"); /* "rip.xpm" */
+ if (!rip_fp) {
+ genl_outrip(window, how, when);
+ return;
+ }
+ (void) fclose(rip_fp);
+
if (wp->type == NHW_TEXT) {
wp->text_information->is_rip = TRUE;
} else {
}
#endif
-/* init and exit nhwindows -------------------------------------------------
- */
+/* init and exit nhwindows ------------------------------------------------ */
XtAppContext app_context; /* context of application */
Widget toplevel = (Widget) 0; /* toplevel widget */
Atom wm_delete_window; /* pop down windows */
static XtActionsRec actions[] = {
- { nhStr("dismiss_file"), dismiss_file }, /* file viewing widget */
- { nhStr("delete_file"), delete_file }, /* file delete-window */
{ nhStr("dismiss_text"), dismiss_text }, /* text widget button action */
{ nhStr("delete_text"), delete_text }, /* text widget delete action */
- { nhStr("key_dismiss_text"),
- key_dismiss_text }, /* text widget key action */
+ { nhStr("key_dismiss_text"), key_dismiss_text }, /* text key action */
#ifdef GRAPHIC_TOMBSTONE
{ nhStr("rip_dismiss_text"), rip_dismiss_text }, /* rip in text widget */
#endif
{ nhStr("ec_key"), ec_key }, /* extended commands */
{ nhStr("ec_delete"), ec_delete }, /* ext-com menu delete */
{ nhStr("ps_key"), ps_key }, /* player selection */
+ { nhStr("plsel_quit"), plsel_quit }, /* player selection dialog */
+ { nhStr("plsel_play"), plsel_play }, /* player selection dialog */
+ { nhStr("plsel_rnd"), plsel_randomize }, /* player selection dialog */
{ nhStr("race_key"), race_key }, /* race selection */
{ nhStr("gend_key"), gend_key }, /* gender selection */
{ nhStr("algn_key"), algn_key }, /* alignment selection */
static XtResource resources[] = {
{ nhStr("slow"), nhStr("Slow"), XtRBoolean, sizeof(Boolean),
XtOffset(AppResources *, slow), XtRString, nhStr("True") },
+ { nhStr("fancy_status"), nhStr("Fancy_status"), XtRBoolean, sizeof(Boolean),
+ XtOffset(AppResources *, fancy_status), XtRString, nhStr("True") },
{ nhStr("autofocus"), nhStr("AutoFocus"), XtRBoolean, sizeof(Boolean),
XtOffset(AppResources *, autofocus), XtRString, nhStr("False") },
{ nhStr("message_line"), nhStr("Message_line"), XtRBoolean,
sizeof(Boolean), XtOffset(AppResources *, message_line), XtRString,
nhStr("False") },
+ { nhStr("highlight_prompt"), nhStr("Highlight_prompt"), XtRBoolean,
+ sizeof(Boolean), XtOffset(AppResources *, highlight_prompt), XtRString,
+ nhStr("True") },
{ nhStr("double_tile_size"), nhStr("Double_tile_size"), XtRBoolean,
sizeof(Boolean), XtOffset(AppResources *, double_tile_size), XtRString,
nhStr("False") },
{ nhStr("tile_file"), nhStr("Tile_file"), XtRString, sizeof(String),
XtOffset(AppResources *, tile_file), XtRString, nhStr("x11tiles") },
-#ifdef X11LARGETILE
- { nhStr("tile_width"), nhStr("Tile_width"), XtRInt, sizeof(int),
- XtOffset(AppResources *, tile_width), XtRString, nhStr("32") },
- { nhStr("tile_height"), nhStr("Tile_height"), XtRInt, sizeof(int),
- XtOffset(AppResources *, tile_height), XtRString, nhStr("32") },
-#endif
{ nhStr("icon"), nhStr("Icon"), XtRString, sizeof(String),
XtOffset(AppResources *, icon), XtRString, nhStr("nh72") },
{ nhStr("message_lines"), nhStr("Message_lines"), XtRInt, sizeof(int),
XtOffset(AppResources *, message_lines), XtRString, nhStr("12") },
+ { nhStr("extcmd_height_delta"), nhStr("Extcmd_height_delta"),
+ XtRInt, sizeof (int),
+ XtOffset(AppResources *, extcmd_height_delta), XtRString, nhStr("0") },
{ nhStr("pet_mark_bitmap"), nhStr("Pet_mark_bitmap"), XtRString,
sizeof(String), XtOffset(AppResources *, pet_mark_bitmap), XtRString,
nhStr("pet_mark.xbm") },
sizeof(XtRPixel), XtOffset(AppResources *, pilemark_color), XtRString,
nhStr("Green") },
#ifdef GRAPHIC_TOMBSTONE
- { nhStr("tombstone"), "Tombstone", XtRString, sizeof(String),
- XtOffset(AppResources *, tombstone), XtRString, "rip.xpm" },
- { nhStr("tombtext_x"), "Tombtext_x", XtRInt, sizeof(int),
- XtOffset(AppResources *, tombtext_x), XtRString, "155" },
- { nhStr("tombtext_y"), "Tombtext_y", XtRInt, sizeof(int),
- XtOffset(AppResources *, tombtext_y), XtRString, "78" },
- { nhStr("tombtext_dx"), "Tombtext_dx", XtRInt, sizeof(int),
- XtOffset(AppResources *, tombtext_dx), XtRString, "0" },
- { nhStr("tombtext_dy"), "Tombtext_dy", XtRInt, sizeof(int),
- XtOffset(AppResources *, tombtext_dy), XtRString, "13" },
+ { nhStr("tombstone"), nhStr("Tombstone"), XtRString, sizeof(String),
+ XtOffset(AppResources *, tombstone), XtRString, nhStr("rip.xpm") },
+ { nhStr("tombtext_x"), nhStr("Tombtext_x"), XtRInt, sizeof(int),
+ XtOffset(AppResources *, tombtext_x), XtRString, nhStr("155") },
+ { nhStr("tombtext_y"), nhStr("Tombtext_y"), XtRInt, sizeof(int),
+ XtOffset(AppResources *, tombtext_y), XtRString, nhStr("78") },
+ { nhStr("tombtext_dx"), nhStr("Tombtext_dx"), XtRInt, sizeof(int),
+ XtOffset(AppResources *, tombtext_dx), XtRString, nhStr("0") },
+ { nhStr("tombtext_dy"), nhStr("Tombtext_dy"), XtRInt, sizeof(int),
+ XtOffset(AppResources *, tombtext_dy), XtRString, nhStr("13") },
#endif
};
+static int
+panic_on_error(display, error)
+Display *display;
+XErrorEvent *error;
+{
+ char buf[BUFSZ];
+ XGetErrorText(display, error->error_code, buf, BUFSZ);
+ fprintf(stderr, "X Error: code %i (%s), request %i, minor %i, serial %lu\n",
+ error->error_code, buf,
+ error->request_code, error->minor_code,
+ error->serial);
+ panic("X Error");
+ return 0;
+}
+
+static void
+X11_error_handler(str)
+String str;
+{
+ nhUse(str);
+ hangup(1);
+#ifdef SAFERHANGUP /* keeps going after hangup() for '#if SAFERHANGUP' */
+ end_of_input();
+#endif
+ /*NOTREACHED*/
+ nh_terminate(EXIT_FAILURE);
+}
+
+static int
+X11_io_error_handler(display)
+Display *display;
+{
+ nhUse(display);
+ hangup(1);
+#ifdef SAFERHANGUP /* keeps going after hangup() for '#if SAFERHANGUP' */
+ end_of_input();
+#endif
+ /*NOREACHED*/ /* but not declared NORETURN */
+ return 0;
+}
+
+
void
X11_init_nhwindows(argcp, argv)
int *argcp;
for (i = 0; i < MAX_WINDOWS; i++)
window_list[i].type = NHW_NONE;
+ /* force high scores display to be shown in a window, and don't allow
+ that to be toggled off via 'O' (note: 'nethack -s' won't reach here;
+ its output goes to stdout and could be redirected into a file) */
+ iflags.toptenwin = TRUE;
+ set_option_mod_status("toptenwin", SET_IN_FILE);
+
/* add another option that can be set */
set_wc_option_mod_status(WC_TILED_MAP, SET_IN_GAME);
+ set_option_mod_status("mouse_support", SET_IN_GAME);
+
+ load_default_resources(); /* create default_resource_data[] */
/*
* setuid hack: make sure that if nethack is setuid, to use real uid
savuid = geteuid();
(void) seteuid(getuid());
- XSetIOErrorHandler((XIOErrorHandler) hangup);
+ XSetIOErrorHandler(X11_io_error_handler);
#ifdef XI18N
XtSetLanguageProc(NULL, NULL, NULL);
0, 0, XtCacheByDisplay, 0);
#endif
num_args = 0;
- XtSetArg(args[num_args], XtNallowShellResize, True);
- num_args++;
- toplevel =
+ XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
+ XtSetArg(args[num_args], XtNtitle, "NetHack"); num_args++;
+
#if 0 /*JP*/
- XtAppInitialize(&app_context, "NetHack", /* application class */
+ toplevel = XtAppInitialize(&app_context, "NetHack", /* application */
#else
- XtAppInitialize(&app_context, "JNetHack", /* application class */
+ toplevel = XtAppInitialize(&app_context, "JNetHack", /* application */
#endif
- (XrmOptionDescList) 0, 0, /* options list */
- argcp, (String *) argv, /* command line args */
- (String *) 0, /* fallback resources */
- (ArgList) args, num_args);
- XtOverrideTranslations(
- toplevel,
- XtParseTranslationTable("<Message>WM_PROTOCOLS: X11_hangup()"));
+ (XrmOptionDescList) 0, 0, /* options list */
+ argcp, (String *) argv, /* command line */
+ default_resource_data, /* fallback resources */
+ (ArgList) args, num_args);
+ XtOverrideTranslations(toplevel,
+ XtParseTranslationTable("<Message>WM_PROTOCOLS: X11_hangup()"));
+
+ /* We don't need to realize the top level widget. */
-/* We don't need to realize the top level widget. */
+ old_error_handler = XSetErrorHandler(panic_on_error);
#ifdef TEXTCOLOR
/* add new color converter to deal with overused colormaps */
(void) seteuid(savuid);
x_inited = TRUE; /* X is now initialized */
+ plsel_ask_name = FALSE;
+
+ release_default_resources();
/* Display the startup banner in the message window. */
for (i = 1; i <= 4 + 2; ++i) /* (values beyond 4 yield blank lines) */
X11_destroy_nhwindow(WIN_MAP);
if (WIN_MESSAGE != WIN_ERR)
X11_destroy_nhwindow(WIN_MESSAGE);
+
+ release_getline_widgets();
+ release_yn_widgets();
}
#ifdef X11_HANGUP_SIGNAL
-static void X11_sig(sig) /* Unix signal handler */
+static void
+X11_sig(sig) /* Unix signal handler */
int sig;
{
XtNoticeSignal(X11_sig_id);
}
#endif
-/* delay_output ------------------------------------------------------------
- */
+/* delay_output ----------------------------------------------------------- */
/*
* Timeout callback for delay_output(). Send a fake message to the map
(void) x_event(EXIT_ON_SENT_EVENT);
}
-/* X11_hangup --------------------------------------------------------------
- */
+/* X11_hangup ------------------------------------------------------------- */
/* ARGSUSED */
static void
X11_hangup(w, event, params, num_params)
exit_x_event = TRUE;
}
-/* askname -----------------------------------------------------------------
- */
+/* askname ---------------------------------------------------------------- */
/* ARGSUSED */
static void
askname_delete(w, event, params, num_params)
XtPointer client_data;
XtPointer call_data;
{
- int len;
+ unsigned len;
char *s;
Widget dialog = (Widget) client_data;
s = (char *) GetDialogResponse(dialog);
- len = (int) strlen(s);
+ len = strlen(s);
if (len == 0) {
X11_nhbell();
return;
}
/* Truncate name if necessary */
- if (len >= (int) sizeof(plname) - 1)
- len = (int) sizeof(plname) - 1;
+ if (len >= sizeof plname - 1)
+ len = sizeof plname - 1;
(void) strncpy(plname, s, len);
plname[len] = '\0';
exit_x_event = TRUE;
}
+/* ask player for character's name to replace generic name "player" (or other
+ values; see config.h) after 'nethack -u player' or OPTIONS=name:player */
void
X11_askname()
{
Widget popup, dialog;
Arg args[1];
+ if (iflags.wc_player_selection == VIA_DIALOG) {
+ /* X11_player_selection_dialog() handles name query */
+ plsel_ask_name = TRUE;
+ iflags.defer_plname = TRUE;
+ return;
+ } /* else iflags.wc_player_selection == VIA_PROMPTS */
+
XtSetArg(args[0], XtNallowShellResize, True);
popup = XtCreatePopupShell("askname", transientShellWidgetClass, toplevel,
args, ONE);
- XtOverrideTranslations(
- popup,
- XtParseTranslationTable("<Message>WM_PROTOCOLS: askname_delete()"));
+ XtOverrideTranslations(popup,
+ XtParseTranslationTable("<Message>WM_PROTOCOLS: askname_delete()"));
dialog = CreateDialog(popup, nhStr("dialog"), askname_done,
(XtCallbackProc) 0);
SetDialogPrompt(dialog, nhStr("What is your name?")); /* set prompt */
- SetDialogResponse(dialog, nhStr("")); /* set default answer */
+ SetDialogResponse(dialog, plname, PL_NSIZ); /* set default answer */
XtRealizeWidget(popup);
positionpopup(popup, TRUE); /* center,bottom */
/* The callback will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
+
+ XtDestroyWidget(dialog);
+ XtDestroyWidget(popup);
}
-/* getline -----------------------------------------------------------------
- */
+/* getline ---------------------------------------------------------------- */
/* This uses Tim Theisen's dialog widget set (from GhostView). */
static Widget getline_popup, getline_dialog;
exit_x_event = TRUE;
}
+static void
+release_getline_widgets()
+{
+ if (getline_dialog)
+ XtDestroyWidget(getline_dialog), getline_dialog = (Widget) 0;
+ if (getline_popup)
+ XtDestroyWidget(getline_popup), getline_popup = (Widget) 0;
+}
+
void
X11_getlin(question, input)
const char *question;
char *input;
{
- static boolean need_to_init = True;
-
getline_input = input;
flush_screen(1);
- if (need_to_init) {
+ if (!getline_popup) {
Arg args[1];
- need_to_init = False;
-
XtSetArg(args[0], XtNallowShellResize, True);
- getline_popup = XtCreatePopupShell(
- "getline", transientShellWidgetClass, toplevel, args, ONE);
- XtOverrideTranslations(
- getline_popup, XtParseTranslationTable(
- "<Message>WM_PROTOCOLS: getline_delete()"));
+ getline_popup = XtCreatePopupShell("getline",
+ transientShellWidgetClass,
+ toplevel, args, ONE);
+ XtOverrideTranslations(getline_popup,
+ XtParseTranslationTable(
+ "<Message>WM_PROTOCOLS: getline_delete()"));
getline_dialog = CreateDialog(getline_popup, nhStr("dialog"),
done_button, abort_button);
+#if 0 /*JP*//*\95¶\8e\9a\97ñ\90Ý\92è\82Ì\8cã\82ë\82É\89ñ\82·*/
XtRealizeWidget(getline_popup);
XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup),
&wm_delete_window, 1);
+#endif
}
SetDialogPrompt(getline_dialog, (String) question); /* set prompt */
- SetDialogResponse(getline_dialog, nhStr("")); /* set default answer */
+ /* 60: make the answer widget be wide enough to hold 60 characters,
+ or the length of the prompt string, whichever is bigger. User's
+ response can be longer--when limit is reached, value-so-far will
+ slide left hiding some chars at the beginning of the response but
+ making room to type more. [Prior to 3.6.1, width wasn't specifiable
+ and answer box always got sized to match the width of the prompt.] */
+#ifdef EDIT_GETLIN
+ SetDialogResponse(getline_dialog, input, 60); /* set default answer */
+#else
+ SetDialogResponse(getline_dialog, nhStr(""), 60); /* set default answer */
+#endif
+#if 1 /*JP*//*\95¶\8e\9a\97ñ\90Ý\92è\82Ì\8cã\82ë\82É\89ñ\82·*/
+ XtRealizeWidget(getline_popup);
+ XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup),
+ &wm_delete_window, 1);
+#endif
positionpopup(getline_popup, TRUE); /* center,bottom */
nh_XtPopup(getline_popup, (int) XtGrabExclusive, getline_dialog);
/* The callback will enable the event loop exit. */
(void) x_event(EXIT_ON_EXIT);
-}
-/* Display file ------------------------------------------------------------
- */
-static const char display_translations[] = "#override\n\
- <Key>q: dismiss_file()\n\
- <Key>Escape: dismiss_file()\n\
- <BtnDown>: dismiss_file()";
-
-/* WM_DELETE_WINDOW callback for file dismissal. */
-/*ARGSUSED*/
-static void
-delete_file(w, event, params, num_params)
-Widget w;
-XEvent *event;
-String *params;
-Cardinal *num_params;
-{
- nhUse(event);
- nhUse(params);
- nhUse(num_params);
-
- nh_XtPopdown(w);
- XtDestroyWidget(w);
+#if 1 /*JP*//*\96\88\89ñ\94j\8aü\82·\82é*/
+ release_getline_widgets();
+#endif
}
-/* Callback for file dismissal. */
-/*ARGSUSED*/
-static void
-dismiss_file(w, event, params, num_params)
-Widget w;
-XEvent *event;
-String *params;
-Cardinal *num_params;
-{
- Widget popup = XtParent(w);
-
- nhUse(event);
- nhUse(params);
- nhUse(num_params);
-
- nh_XtPopdown(popup);
- XtDestroyWidget(popup);
-}
+/* Display file ----------------------------------------------------------- */
+/* uses a menu (with no selectors specified) rather than a text window
+ to allow previous_page and first_menu actions to move backwards */
void
X11_display_file(str, complain)
const char *str;
boolean complain;
{
dlb *fp;
- Arg args[12];
- Cardinal num_args;
- Widget popup, dispfile;
- Position top_margin, bottom_margin, left_margin, right_margin;
-#if 0 /*JP*/
- XFontStruct *fs;
-#endif
- int new_width, new_height;
+ winid newwin;
+ struct xwindow *wp;
+ anything any;
+ menu_item *menu_list;
#define LLEN 128
char line[LLEN];
- int num_lines;
- char *textlines;
- int charcount;
#ifdef XI18N
XFontSet fontset;
XFontSetExtents *extent;
/* Use the port-independent file opener to see if the file exists. */
fp = dlb_fopen(str, RDTMODE);
-
if (!fp) {
if (complain)
pline("Cannot open %s. Sorry.", str);
-
return; /* it doesn't exist, ignore */
}
- /*
- * Count the number of lines and characters in the file.
- */
- num_lines = 0;
- charcount = 1;
- while (dlb_fgets(line, LLEN, fp)) {
- num_lines++;
- charcount += strlen(line);
- }
-
- (void) dlb_fclose(fp);
-
- /* Ignore empty files */
- if (num_lines == 0)
- return;
-
- /* If over the max window size, truncate the window size to the max */
- if (num_lines >= DISPLAY_FILE_SIZE)
- num_lines = DISPLAY_FILE_SIZE;
-
- /*
- * Re-open the file and read the data into a buffer. Cannot use
- * the XawAsciiFile type of widget, because that is not DLB-aware.
- */
- textlines = (char *) alloc((unsigned int) charcount);
- textlines[0] = '\0';
-
- fp = dlb_fopen(str, RDTMODE);
+ newwin = X11_create_nhwindow(NHW_MENU);
+ wp = &window_list[newwin];
+ X11_start_menu(newwin);
+ any = zeroany;
while (dlb_fgets(line, LLEN, fp)) {
- (void) strcat(textlines, line);
+ X11_add_menu(newwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+ line, MENU_UNSELECTED);
}
-
(void) dlb_fclose(fp);
- num_args = 0;
- XtSetArg(args[num_args], nhStr(XtNtitle), str);
- num_args++;
-
- popup = XtCreatePopupShell("display_file", topLevelShellWidgetClass,
- toplevel, args, num_args);
- XtOverrideTranslations(
- popup,
- XtParseTranslationTable("<Message>WM_PROTOCOLS: delete_file()"));
-
- num_args = 0;
- XtSetArg(args[num_args], nhStr(XtNscrollHorizontal),
- XawtextScrollWhenNeeded);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNscrollVertical), XawtextScrollAlways);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNtype), XawAsciiString);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNstring), textlines);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNdisplayCaret), False);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNtranslations),
- XtParseTranslationTable(display_translations));
- num_args++;
-
-/*JP*/
-#if defined(X11R6) && defined(XI18N)
- XtSetArg(args[num_args], XtNinternational, True);
- num_args++;
-#endif
- dispfile =
- XtCreateManagedWidget("text", /* name */
- asciiTextWidgetClass, popup, /* parent widget */
- args, /* set some values */
- num_args); /* number of values to set */
-
- /* Get font and border information. */
- num_args = 0;
-#ifndef XI18N
- XtSetArg(args[num_args], nhStr(XtNfont), &fs);
-#else
- XtSetArg(args[num_args], XtNfontSet, &fontset);
-#endif
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNtopMargin), &top_margin);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNbottomMargin), &bottom_margin);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNleftMargin), &left_margin);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNrightMargin), &right_margin);
- num_args++;
- XtGetValues(dispfile, args, num_args);
-
- /*
- * The data files are currently set up assuming an 80 char wide window
- * and a fixed width font. Soo..
- */
-#ifndef XI18N
- new_height =
- num_lines * nhFontHeight(dispfile) + top_margin + bottom_margin;
- new_width = 80 * fs->max_bounds.width + left_margin + right_margin;
-#else
- extent = XExtentsOfFontSet(fontset);
- new_height =
- num_lines * extent->max_logical_extent.height + top_margin + bottom_margin;
- new_width = 40 * extent->max_logical_extent.width + left_margin + right_margin;
-#endif
-
- /* Set the new width and height. */
- num_args = 0;
- XtSetArg(args[num_args], XtNwidth, new_width);
- num_args++;
- XtSetArg(args[num_args], XtNheight, new_height);
- num_args++;
- XtSetValues(dispfile, args, num_args);
+ /* show file name as the window title */
+ if (str)
+ wp->title = dupstr(str);
- nh_XtPopup(popup, (int) XtGrabNone, (Widget) 0);
- free(textlines);
+ wp->menu_information->permi = FALSE;
+ wp->menu_information->disable_mcolors = TRUE;
+ (void) X11_select_menu(newwin, PICK_NONE, &menu_list);
+ X11_destroy_nhwindow(newwin);
}
-/* yn_function -------------------------------------------------------------
- */
+/* yn_function ------------------------------------------------------------ */
/* (not threaded) */
static const char *yn_quitchars = " \n\r";
exit_x_event = TRUE; /* exit our event handler */
}
+/* called at exit time */
+static void
+release_yn_widgets()
+{
+ if (yn_label)
+ XtDestroyWidget(yn_label), yn_label = (Widget) 0;
+ if (yn_popup)
+ XtDestroyWidget(yn_popup), yn_popup = (Widget) 0;
+}
+
+/* X11-specific edition of yn_function(), the routine called by the core
+ to show a prompt and get a single keystroke answer, often 'y' vs 'n' */
char
X11_yn_function(ques, choices, def)
const char *ques;
-const char *choices;
-char def;
+const char *choices; /* string of possible response chars; any char if Null */
+char def; /* default response if user hits <space> or <return> */
{
- static Boolean need_to_init = True;
char buf[BUFSZ];
Arg args[4];
Cardinal num_args;
yn_choices = choices; /* set up globals for callback to use */
yn_def = def;
- yn_preserve_case =
- !choices; /* preserve when arbitrary response allowed */
+ yn_preserve_case = !choices; /* preserve case when an arbitrary
+ response is allowed */
/*
* This is sort of a kludge. There are quite a few places in the main
Strcat(buf, " ");
/* escape maps to 'q' or 'n' or default, in that order */
- yn_esc_map =
- (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def));
+ yn_esc_map = (index(choices, 'q') ? 'q'
+ : index(choices, 'n') ? 'n'
+ : def);
} else {
if ((int) (1 + strlen(ques) + 1) >= BUFSZ)
panic("X11_yn_function: question too long");
Strcat(buf, " ");
}
- if (!appResources.slow && need_to_init) {
- need_to_init = False;
+ /*
+ * The 'slow' resource is misleadingly named. When it is True, we
+ * re-use the same one-line widget above the map for all yn prompt
+ * responses instead of re-using a popup widget for each one. It's
+ * crucial for client/server configs where the server is slow putting
+ * up a popup or requires click-to-focus to respond to the popup, but
+ * is also useful for players who just want to be able to look at the
+ * same location to read questions they're being asked to answer.
+ */
+ if (appResources.slow) {
+ /*
+ * 'slow': the yn_label widget was created when the map and
+ * status widgets were, and is positioned between them. It
+ * will persist until end of game. All we need to do for
+ * yn_function is direct keystroke input to the yn response
+ * handler and reset its label to be the prompt text (below).
+ */
+ input_func = yn_key;
+ highlight_yn(FALSE); /* expose yn_label as separate from map */
+ } else if (!yn_label) {
+ /*
+ * Not 'slow'; create a persistent widget that will be popped up
+ * as needed, then down again, and last until end of game. The
+ * associated yn_label widget is used to track whether it exists.
+ */
XtSetArg(args[0], XtNallowShellResize, True);
yn_popup = XtCreatePopupShell("query", transientShellWidgetClass,
toplevel, args, ONE);
- XtOverrideTranslations(
- yn_popup,
- XtParseTranslationTable("<Message>WM_PROTOCOLS: yn_delete()"));
+ XtOverrideTranslations(yn_popup,
+ XtParseTranslationTable("<Message>WM_PROTOCOLS: yn_delete()"));
num_args = 0;
XtSetArg(args[num_args], XtNtranslations,
- XtParseTranslationTable(yn_translations));
- num_args++;
-/*JP*/
+ XtParseTranslationTable(yn_translations)); num_args++;
#if defined(X11R6) && defined(XI18N)
- XtSetArg(args[num_args], XtNinternational, True);
- num_args++;
+ XtSetArg(args[num_args], XtNinternational, True); num_args++;
#endif
yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass,
yn_popup, args, num_args);
&wm_delete_window, 1);
}
- if (appResources.slow)
- input_func = yn_key;
-
+ /* set the label of the yn widget to be the prompt text */
num_args = 0;
- XtSetArg(args[num_args], XtNlabel, buf);
- num_args++;
+ XtSetArg(args[num_args], XtNlabel, buf); num_args++;
XtSetValues(yn_label, args, num_args);
if (!appResources.slow) {
* need to set the label twice to get the size to change.
*/
num_args = 0;
- XtSetArg(args[num_args], XtNlabel, buf);
- num_args++;
+ XtSetArg(args[num_args], XtNlabel, buf); num_args++;
XtSetValues(yn_label, args, num_args);
positionpopup(yn_popup, TRUE);
}
yn_getting_num = FALSE;
- (void) x_event(EXIT_ON_EXIT);
+ (void) x_event(EXIT_ON_EXIT); /* get keystroke(s) */
if (appResources.slow) {
+ /* keystrokes now belong to the map */
input_func = 0;
+ /* erase the prompt */
num_args = 0;
- XtSetArg(args[num_args], XtNlabel, " ");
- num_args++;
+ XtSetArg(args[num_args], XtNlabel, " "); num_args++;
XtSetValues(yn_label, args, num_args);
+ highlight_yn(FALSE); /* disguise yn_label as part of map */
} else {
nh_XtPopdown(yn_popup); /* this removes the event grab */
}
+ pline("%s%c", buf, (yn_return != '\033') ? yn_return : '\0');
+
return yn_return;
}
-/*ARGSUSED*/
+/* used when processing window-capability-specific run-time options;
+ we support toggling tiles on and off via iflags.wc_tiled_map */
void
X11_preference_update(pref)
const char *pref;
}
}
-/* End global functions ====================================================
- */
+/* End global functions =================================================== */
/*
* Before we wait for input via nhgetch() and nh_poskey(), we need to
input_event(exit_condition)
int exit_condition;
{
- if (WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */
+ if (appResources.fancy_status && WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */
check_turn_events();
if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */
check_cursor_visibility(&window_list[WIN_MAP]);
map_input(window_list[WIN_MAP].w, event, (String *) 0, &num);
}
+/* only called for autofocus */
/*ARGSUSED*/
-static void win_visible(w, data, event, flag) /* only called for autofocus */
+static void
+win_visible(w, data, event, flag)
Widget w;
XtPointer data; /* client_data not used */
XEvent *event;
}
}
+/* if 'slow' and 'highlight_prompt', set the yn_label widget to look like
+ part of the map when idle or to invert background and foreground when
+ a prompt is active */
+void
+highlight_yn(init)
+boolean init;
+{
+ struct xwindow *xmap;
+
+ if (!appResources.slow || !appResources.highlight_prompt)
+ return;
+
+ /* first time through, WIN_MAP isn't fully initiialized yet */
+ xmap = ((map_win != WIN_ERR) ? &window_list[map_win]
+ : (WIN_MAP != WIN_ERR) ? &window_list[WIN_MAP] : 0);
+
+ if (init && xmap) {
+ Arg args[2];
+ XGCValues vals;
+ unsigned long fg_bg = (GCForeground | GCBackground);
+ GC gc = (xmap->map_information->is_tile
+ ? xmap->map_information->tile_map.white_gc
+ : xmap->map_information->text_map.copy_gc);
+
+ (void) memset((genericptr_t) &vals, 0, sizeof vals);
+ if (XGetGCValues(XtDisplay(xmap->w), gc, fg_bg, &vals)) {
+ XtSetArg(args[0], XtNforeground, vals.foreground);
+ XtSetArg(args[1], XtNbackground, vals.background);
+ XtSetValues(yn_label, args, TWO);
+ }
+ } else
+ swap_fg_bg(yn_label);
+}
+
/*
* Set up the playing console. This has three major parts: the
* message window, the map, and the status window.
+ *
+ * For configs specifying the 'slow' resource, the yn_label widget
+ * is placed above the map and below the message window. Prompts
+ * requiring a single character response are displayed there rather
+ * than using a popup.
*/
static void
init_standard_windows()
struct xwindow *wp;
num_args = 0;
- XtSetArg(args[num_args], XtNallowShellResize, True);
- num_args++;
+ XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
#if 0 /*JP*/
form = XtCreateManagedWidget("nethack", panedWidgetClass, toplevel, args,
num_args);
/* Tell the form that contains it that resizes are OK. */
num_args = 0;
- XtSetArg(args[num_args], nhStr(XtNresizable), True);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop);
- num_args++;
+ XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++;
XtSetValues(message_viewport, args, num_args);
if (appResources.slow) {
num_args = 0;
XtSetArg(args[num_args], XtNtranslations,
- XtParseTranslationTable(yn_translations));
- num_args++;
-/*JP*/
+ XtParseTranslationTable(yn_translations)); num_args++;
#if defined(X11R6) && defined(XI18N)
XtSetArg(args[num_args], XtNinternational, True);
num_args++;
args, num_args);
num_args = 0;
XtSetArg(args[num_args], nhStr(XtNfromVert), message_viewport);
- num_args++;
+ num_args++;
XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNresizable), True);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNlabel), " ");
- num_args++;
+ num_args++;
+ XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNlabel), " "); num_args++;
XtSetValues(yn_label, args, num_args);
}
/* Chain beneath message_viewport or yn window. */
num_args = 0;
if (appResources.slow) {
- XtSetArg(args[num_args], nhStr(XtNfromVert), yn_label);
- num_args++;
+ XtSetArg(args[num_args], nhStr(XtNfromVert), yn_label); num_args++;
} else {
XtSetArg(args[num_args], nhStr(XtNfromVert), message_viewport);
- num_args++;
+ num_args++;
}
- XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom);
- num_args++;
+ XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
XtSetValues(map_viewport, args, num_args);
/* Create the status window, with the form as it's parent. */
* will never expand or contract.
*/
num_args = 0;
- XtSetArg(args[num_args], nhStr(XtNfromVert), map_viewport);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNtop), XtChainBottom);
- num_args++;
- XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom);
- num_args++;
+ XtSetArg(args[num_args], nhStr(XtNfromVert), map_viewport); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNtop), XtChainBottom); num_args++;
+ XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++;
XtSetValues(status, args, num_args);
/*
*/
/* XtSetMappedWhenManaged(toplevel, False); */
XtRealizeWidget(toplevel);
- wm_delete_window =
- XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False);
+ wm_delete_window = XInternAtom(XtDisplay(toplevel),
+ "WM_DELETE_WINDOW", False);
XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel),
&wm_delete_window, 1);
* after the fancy status widget is realized (above, with the game popup),
* but before it is popped up.
*/
- null_out_status();
+ if (appResources.fancy_status)
+ null_out_status();
/*
* Set the map size to its standard size. As with the message window
* above, the map window needs to be set to its constrained size until
set_message_slider(&window_list[message_win]);
/* attempt to catch fatal X11 errors before the program quits */
- (void) XtAppSetErrorHandler(app_context, (XtErrorHandler) hangup);
+ (void) XtAppSetErrorHandler(app_context, X11_error_handler);
+
+ highlight_yn(TRUE); /* switch foreground and background */
/* We can now print to the message window. */
iflags.window_inited = 1;
nh_XtPopup(w, g, childwid)
Widget w; /* widget */
int g; /* type of grab */
-Widget childwid; /* child to recieve focus (can be None) */
+Widget childwid; /* child to receive focus (can be None) */
{
XtPopup(w, (XtGrabKind) g);
XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
* libXmu.sa.4.0, but not in libXmu.so.4.0. Rather than fiddle with
* static linking, we do this.
*/
- if (rn2(2) > 2) {
- /* i.e., FALSE that an optimizer probably can't find */
+ if (rn2(2) > 2) { /* i.e., FALSE that an optimizer probably can't find */
get_wmShellWidgetClass();
get_applicationShellWidgetClass();
}
return;
}
+void
+find_scrollbars(w, horiz, vert)
+Widget w;
+Widget *horiz, *vert;
+{
+ if (w) {
+ do {
+ *horiz = XtNameToWidget(w, "*horizontal");
+ *vert = XtNameToWidget(w, "*vertical");
+ w = XtParent(w);
+ } while (!*horiz && !*vert && w);
+ }
+}
+
/* Callback
* Scroll a viewport, using standard NH 1,2,3,4,6,7,8,9 directions.
*/
Cardinal *num_params;
{
Arg arg[2];
- Widget horiz_sb, vert_sb;
+ Widget horiz_sb = (Widget) 0, vert_sb = (Widget) 0;
float top, shown;
Boolean do_call;
int direction;
direction = atoi(params[0]);
- horiz_sb = XtNameToWidget(viewport, "*horizontal");
- vert_sb = XtNameToWidget(viewport, "*vertical");
-
- if (!horiz_sb && !vert_sb) {
- /* Perhaps the widget enclosing this has scrollbars (could use while)
- */
- Widget parent = XtParent(viewport);
- if (parent) {
- horiz_sb = XtNameToWidget(parent, "horizontal");
- vert_sb = XtNameToWidget(parent, "vertical");
- }
- }
+ find_scrollbars(viewport, &horiz_sb, &vert_sb);
#define H_DELTA 0.25 /* distance of horiz shift */
/* vert shift is half of curr distance */