win32gui: set correct checkmark on "Lock Windows" menu item on startup
win32gui: redraw message window on resizing (it does not update properly otherwise)
win32gui: fixed copy/paste error in read registry settings function
+platforms that support hangup: SAFERHANGUP to avoid losing objects in transit
+ between lists when hangup occurs, and also avoid cheats due to
+ well-timed hangups to stop a long melee
General New Features
will be the routine the OS provides to read a character.
Returned character _must_ be non-zero and it must be
non meta-zero too (zero with the meta-bit set).
+ -- If platform uses it, should check program_state.done_hup
+ and immediately return ASCII 033 (escape) if it is.
+ This is required if the window-port supports SAFERHANGUP.
+ -- ASCII 033 must also be returned rather than EOF (applies
+ mainly to the tty window-port).
+ -- The program_state.done_hup flag can be set asynchronously
+ when SAFERHANGUP is defined and in that case, nhgetch()
+ needs to detect that the value of program_state.done_hup
+ changed and also return ASCII 033 in this case.
int nh_poskey(int *x, int *y, int *mod)
-- Returns a single character input from the user or a
a positioning event (perhaps from a mouse). If the
The different click types can map to whatever the
hardware supports. If no mouse is supported, this
routine always returns a non-zero character.
+ -- Otherwise follows the same behavior as nhgetch().
B. High-level routines:
#define SUSPEND /* let ^Z suspend the game */
#endif
+/*
+ * Define SAFERHANGUP to delay hangup processing until the main command
+ * loop. 'safer' because it avoids certain cheats and also avoids losing
+ * objects being thrown when the hangup occurs. All unix windowports
+ * support SAFERHANGUP (couldn't define it here otherwise).
+ */
+#define SAFERHANGUP
+
#if defined(BSD) || defined(ULTRIX)
#include <sys/time.h>
STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *));
-#ifdef UNIX
+#if defined(UNIX) || defined(SAFERHANGUP)
static void NDECL(end_of_input);
#endif
firsttime = (cmd == 0);
iflags.menu_requested = FALSE;
+#ifdef SAFERHANGUP
+ if (program_state.done_hup) end_of_input();
+#endif
if (firsttime) {
flags.nopick = 0;
cmd = parse();
return(in_line);
}
-#ifdef UNIX
+#if defined(UNIX) || defined(SAFERHANGUP)
static
void
end_of_input()
{
exit_nhwindows("End of input?");
#ifndef NOSAVEONHANGUP
- if (!program_state.done_hup++ && program_state.something_worth_saving)
- (void) dosave0();
+# ifndef SAFERHANGUP
+ if (!program_state.done_hup++)
+#endif
+ if (program_state.something_worth_saving) (void) dosave0();
#endif
clearlocks();
terminate(EXIT_SUCCESS);
} while (--cnt && sym == EOF);
}
# endif /* NR_OF_EOFS */
- if (sym == EOF)
+ if (sym == EOF) {
+# ifndef SAFERHANGUP
end_of_input();
+# else
+ program_state.done_hup++;
+ sym = '\033';
+# endif
+ }
#endif /* UNIX */
if(sym == 0) {
# endif
# else /* SAVEONHANGUP */
if (!program_state.done_hup++) {
+# ifndef SAFERHANGUP
+ /* When using SAFERHANGUP, the done_hup flag it tested in rhack
+ * and actual hangup behavior occurs then. This is 'safer'
+ * because it disallows certain cheats and also protects
+ * against losing objects in the process of being thrown. */
if (program_state.something_worth_saving)
(void) dosave0();
# ifdef VMS
clearlocks();
terminate(EXIT_FAILURE);
}
+# endif /* !SAFERHANGUP */
}
# endif
- return;
}
#endif
* It seems you really want to play.
*/
u.uhp = 1; /* prevent RIP on early quits */
+#ifdef SA_RESTART
+ /* don't want reads to restart. If SA_RESTART is defined, we know
+ * sigaction exists and can be used to ensure reads won't restart.
+ * If it's not defined, assume reads do not restart. If reads restart
+ * and a signal occurs, the game won't do anything until the read
+ * succeeds (or the stream returns EOF, which might not happen if
+ * reading from, say, a window manager). */
+ {
+ struct sigaction sact;
+
+ (void) memset((char*) &sact, 0, sizeof(struct sigaction));
+ sact.sa_handler = (SIG_RET_TYPE)hangup;
+ (void) sigaction(SIGHUP, &sact, (struct sigaction*)0);
+#ifdef SIGXCPU
+ (void) sigaction(SIGXCPU, &sact, (struct sigaction*)0);
+#endif
+ }
+#else
(void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
#ifdef SIGXCPU
(void) signal(SIGXCPU, (SIG_RET_TYPE) hangup);
+#endif
#endif
process_options(argc, argv); /* command line options */
(void) printf("\nThere is already a game in progress under your name.");
(void) printf(" Destroy old game? [yn] ");
(void) fflush(stdout);
- c = getchar();
- (void) putchar(c);
- (void) fflush(stdout);
- while (getchar() != '\n') ; /* eat rest of line and newline */
+ if ((c = getchar()) != EOF) {
+ int tmp;
+
+ (void) putchar(c);
+ (void) fflush(stdout);
+ while ((tmp = getchar()) != '\n' && tmp != EOF)
+ ; /* eat rest of line and newline */
+ }
}
- if(c == 'y' || c == 'Y')
+ if(c == 'y' || c == 'Y') {
if(eraseoldlocks())
goto gotlock;
else {
unlock_file(HLOCK);
error("Couldn't destroy old game.");
}
- else {
+ } else {
unlock_file(HLOCK);
error("%s", "");
}
#include "patchlevel.h"
#endif
+#ifndef NO_SIGNAL
+#include <signal.h>
+#endif
+
/* Should be defined in <X11/Intrinsic.h> but you never know */
#ifndef XtSpecificationRelease
#define XtSpecificationRelease 0
/* (filled by set_button_values()). */
int updated_inventory;
+#ifndef NO_SIGNAL
+static XtSignalId X11_sig_id;
+#endif
/* Interface definition, for windows.c */
struct window_procs X11_procs = {
static int FDECL(input_event, (int));
static void FDECL(win_visible, (Widget,XtPointer,XEvent *,Boolean *));
static void NDECL(init_standard_windows);
-
+#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
+static void FDECL(X11_sig, (int));
+static void FDECL(X11_sig_cb, (XtPointer, XtSignalId*));
+#endif
/*
* Local variables.
if (!x_inited)
panic("create_nhwindow: windows not initialized");
+#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
+ /* set up our own signal handlers on the first call. Can't do this in
+ * X11_init_nhwindows because unixmain sets its handler after calling
+ * all the init routines. */
+ if (X11_sig_id == 0) {
+ X11_sig_id = XtAppAddSignal(app_context, X11_sig_cb, (XtPointer)0);
+#ifdef SA_RESTART
+ {
+ struct sigaction sact;
+
+ (void) memset((char*) &sact, 0, sizeof(struct sigaction));
+ sact.sa_handler = (SIG_RET_TYPE)X11_sig;
+ (void) sigaction(SIGHUP, &sact, (struct sigaction*)0);
+#ifdef SIGXCPU
+ (void) sigaction(SIGXCPU, &sact, (struct sigaction*)0);
+#endif
+ }
+#else
+ (void) signal(SIGHUP, (SIG_RET_TYPE) X11_sig);
+#ifdef SIGXCPU
+ (void) signal(SIGXCPU, (SIG_RET_TYPE) X11_sig);
+#endif
+#endif
+ }
+#endif
+
/*
* We have already created the standard message, map, and status
* windows in the window init routine. The first window of that
X11_destroy_nhwindow(WIN_MESSAGE);
}
+#if !defined(NO_SIGNAL) && defined(SAFERHANGUP)
+void
+X11_sig(sig) /* Unix signal handler */
+int sig;
+{
+ XtNoticeSignal(X11_sig_id);
+ hangup(sig);
+}
+
+void
+X11_sig_cb(not_used, id)
+ XtPointer not_used;
+ XtSignalId* id;
+{
+ XEvent event;
+ XClientMessageEvent *mesg;
+
+ /* Set up a fake message to the event handler. */
+ mesg = (XClientMessageEvent *) &event;
+ mesg->type = ClientMessage;
+ mesg->message_type = XA_STRING;
+ mesg->format = 8;
+
+ XSendEvent(XtDisplay(window_list[WIN_MAP].w),
+ XtWindow(window_list[WIN_MAP].w),
+ False,
+ NoEventMask,
+ (XEvent*) mesg);
+}
+#endif
/* delay_output ------------------------------------------------------------ */
inptr = (inptr+1) % INBUF_SIZE;
/* pkey(retval); */
keep_going = FALSE;
+ } else if (program_state.done_hup) {
+ retval = '\033';
+ inptr = (inptr+1) % INBUF_SIZE;
+ keep_going = FALSE;
}
break;
case EXIT_ON_KEY_OR_BUTTON_PRESS:
/* pkey(retval); */
}
keep_going = FALSE;
+ } else if (program_state.done_hup) {
+ retval = '\033';
+ inptr = (inptr+1) % INBUF_SIZE;
+ keep_going = FALSE;
}
break;
default:
if (sel >= 0) sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
- gnome_exit_nhwindows(0);
+ gtk_exit(0);
}
free(choices);
free(pickmap);
if (sel >= 0) sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
- gnome_exit_nhwindows(0);
+ gtk_exit(0);
}
flags.initrace = sel;
free(choices);
if (sel >= 0) sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
- gnome_exit_nhwindows(0);
+ gtk_exit(0);
}
flags.initgend = sel;
free(choices);
if (sel >= 0) sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
- gnome_exit_nhwindows(0);
+ gtk_exit(0);
}
flags.initalign = sel;
free(choices);
/* Quit if they want to quit... */
if (ret==-1)
{
- gnome_exit_nhwindows(0);
+ gtk_exit(0);
}
}
*/
void gnome_exit_nhwindows(const char *str)
{
- gtk_exit (0);
- terminate(EXIT_SUCCESS);
+ /* gtk cannot do this without exiting the program, do nothing */
}
/* Prepare the window to be suspended. */
winid
gnome_create_nhwindow(int type)
{
+ winid i = 0;
- winid i = 0;
+ /* Return the next available winid */
-/* Return the next available winid
- */
-
- for (i=0; i<MAXWINDOWS; i++)
- if (gnome_windowlist[i].win == NULL)
- break;
- if (i == MAXWINDOWS)
- g_error ("ERROR: No windows available...\n");
- gnome_create_nhwindow_by_id( type, i);
- return i;
+ for (i=0; i<MAXWINDOWS; i++)
+ if (gnome_windowlist[i].win == NULL)
+ break;
+ if (i == MAXWINDOWS)
+ g_error ("ERROR: No windows available...\n");
+ gnome_create_nhwindow_by_id( type, i);
+ return i;
}
void
g_askingQuestion = 1;
/* Process events until a key press event arrives. */
- while ( g_numKeys == 0 )
+ while ( g_numKeys == 0 ) {
+ if (program_state.done_hup) return '\033';
gtk_main_iteration();
+ }
theFirst = g_list_first( g_keyBuffer);
g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst);
g_askingQuestion = 0;
/* Process events until a key or map-click arrives. */
- while ( g_numKeys == 0 && g_numClicks == 0 )
+ while ( g_numKeys == 0 && g_numClicks == 0 ) {
+ if (program_state.done_hup) return '\033';
gtk_main_iteration();
+ }
if (g_numKeys > 0) {
int key;
(void) fflush(stdout);
Sprintf(toplines, "%s ", query);
Strcat(toplines, obufp);
- if((c = Getchar()) == EOF) {
-#ifndef NEWAUTOCOMP
- *bufp = 0;
-#endif /* not NEWAUTOCOMP */
- break;
- }
+ if((c = Getchar()) == EOF) c = '\033';
if(c == '\033') {
*obufp = c;
obufp[1] = 0;
while((c = tty_nhgetch()) != '\n') {
if(iflags.cbreak) {
+ if (c == EOF || c == '\033') {
+ ttyDisplay->dismiss_more = 1;
+ morc = '\033';
+ break;
+ }
if ((s && index(s,c)) || c == x) {
morc = (char) c;
break;
wins[BASE_WINDOW]->cury - 1);
ct = 0;
while((c = tty_nhgetch()) != '\n') {
- if(c == EOF) error("End of input\n");
+ if(c == EOF) c = '\033';
if (c == '\033') { ct = 0; break; } /* continue outer loop */
#if defined(WIN32CON)
if (c == '\003') bail("^C abort.\n");
i = tgetch();
#endif
if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+ else if (i == EOF) i = '\033'; /* same for EOF */
if (ttyDisplay && ttyDisplay->toplin == 1)
ttyDisplay->toplin = 2;
return i;
if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE])
wins[WIN_MESSAGE]->flags &= ~WIN_STOP;
i = ntposkey(x, y, mod);
- if (!i && mod && *mod == 0)
- i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
+ if (!i && mod && (*mod == 0 || *mod == EOF))
+ i = '\033'; /* map NUL or EOF to ESC, nethack doesn't expect either */
if (ttyDisplay && ttyDisplay->toplin == 1)
ttyDisplay->toplin = 2;
return i;