From 284452796cab0cac46ef484b072f9a064445c5f7 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 12 Oct 2023 18:45:14 -0700 Subject: [PATCH] redo tty resizing Rest of 'not PR #1102'. Resizing the terminal while getpos was in operation recalculated the map from scratch instead of redrawing what the core considers to already be shown. And it was always operating while an asynchronous signal was excuting which could potentially clobber whatever was running at the time the signal arrived. This uses same redrawing as the prior '^R during getpos()' fix. It also only performs the resize while tty_nhgetch() is waiting for input. If that is the situation at the time that the signal arrives then it will resize immediately (while in the asynchronous signal handler); if not, it will set a flag and tty_nhgetch() will do the resize the next time it gets called. This builds with TTY_PERM_INVENT enabled and doesn't seem to be any worse than before, but there are bugs with that. The only way I could get perminv to appear was to save and restore, then perm_invent was honored for both RC file and mO command. And once I managed to get it to display, moving an item from a lower case slot to slot 'A', made that item vanish; nothing appeared in the invent's right hand panel. Both of those misbehaviors already happen prior to this commit. I also saw an abort+panictrace if I resized while at the "Dump core?" prompt when running the pre-commit code and didn't see that with the post-commit code (although the prompt wasn't shown so I couldn't tell that it was waiting for an answer). The abort probably sounds scarier than it warrants; I suspect that the pre-commit code just treated the resize as answering 'y' for some reason, possibly a stale value in the variable it uses. --- include/decl.h | 1 + include/extern.h | 3 + include/hack.h | 7 + include/wintty.h | 20 +-- src/decl.c | 1 + src/do_name.c | 7 +- sys/vms/vmstty.c | 19 +++ win/tty/getline.c | 5 +- win/tty/termcap.c | 2 + win/tty/wintty.c | 405 ++++++++++++++++++++++++++++++---------------- 10 files changed, 318 insertions(+), 152 deletions(-) diff --git a/include/decl.h b/include/decl.h index 79d8f381a..128b7d93d 100644 --- a/include/decl.h +++ b/include/decl.h @@ -381,6 +381,7 @@ struct instance_globals_g { coordxy gbuf_stop[ROWNO]; /* do_name.c */ + coordxy getposx, getposy; /* cursor position in case of async resize */ struct selectionvar *gloc_filter_map; int gloc_filter_floodfill_match_glyph; diff --git a/include/extern.h b/include/extern.h index ee9befb6b..29a5a27a4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3278,6 +3278,9 @@ ATTRNORETURN extern void error (const char *, ...) PRINTF_F(1, 2) NORETURN; #ifdef TIMED_DELAY extern void msleep(unsigned); #endif +#ifdef SIGWINCH +extern void getwindowsz(void); +#endif #ifdef ENHANCED_SYMBOLS extern void tty_utf8graphics_fixup(void); #endif diff --git a/include/hack.h b/include/hack.h index edb654a2c..860e7b8c8 100644 --- a/include/hack.h +++ b/include/hack.h @@ -775,6 +775,13 @@ struct sinfo { interface to suppress menu commands in similar conditions; readchar() alrways resets it to 'otherInp' prior to returning */ int input_state; /* whether next key pressed will be entering a command */ +#ifdef TTY_GRAPHICS + /* resize_pending only matters when handling a SIGWINCH signal for tty; + getting_char is used along with that and also separately for UNIX; + we minimize #if conditionals for them to avoid unnecessary clutter */ + volatile int resize_pending; /* set by signal handler */ + volatile int getting_char; /* referenced during signal handling */ +#endif }; /* value of program_state.input_state, significant during readchar(); diff --git a/include/wintty.h b/include/wintty.h index 8d272cf56..87152ff54 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -45,16 +45,17 @@ typedef struct tty_mi { /* descriptor for tty-based windows */ struct WinDesc { - int flags; /* window flags */ - xint16 type; /* type of window */ - boolean active; /* true if window is active */ - short offx, offy; /* offset from topleft of display */ - long rows, cols; /* dimensions */ - long curx, cury; /* current cursor position */ - long maxrow, maxcol; /* the maximum size used -- for MENU wins */ + int flags; /* window flags */ + xint16 type; /* type of window */ + boolean active; /* true if window is active */ + boolean blanked; /* for erase_tty_screen(); not used [yet?] */ + short offx, offy; /* offset from topleft of display */ + long rows, cols; /* dimensions */ + long curx, cury; /* current cursor position */ + long maxrow, maxcol; /* the maximum size used -- for MENU wins; + * maxcol is also used by WIN_MESSAGE for + * tracking the ^P command */ unsigned long mbehavior; /* menu behavior flags (MENU) */ - /* maxcol is also used by WIN_MESSAGE for */ - /* tracking the ^P command */ short *datlen; /* allocation size for *data */ char **data; /* window data [row][column] */ char *morestr; /* string to display instead of default */ @@ -218,6 +219,7 @@ E void g_putch(int); E void g_pututf8(uint8 *); #endif #endif /* ENHANCED_SYMBOLS */ +extern void erase_tty_screen(void); E void win_tty_init(int); /* external declarations */ diff --git a/src/decl.c b/src/decl.c index 42ed0f7d3..3191180d5 100644 --- a/src/decl.c +++ b/src/decl.c @@ -374,6 +374,7 @@ const struct instance_globals_g g_init_g = { UNDEFINED_VALUES, /* gbug_stop */ /* do_name.c */ + 0, 0, /* getposx, getposy */ UNDEFINED_PTR, /* gloc_filter_map */ UNDEFINED_VALUE, /* gloc_filter_floodfill_match_glyph */ /* dog.c */ diff --git a/src/do_name.c b/src/do_name.c index 4a458d448..b520277da 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -826,8 +826,8 @@ getpos(coord *ccp, boolean force, const char *goal) visctrl(gc.Cmd.spkeys[NHKF_GETPOS_HELP])); msg_given = TRUE; } - cx = ccp->x; - cy = ccp->y; + cx = gg.getposx = ccp->x; + cy = gg.getposy = ccp->y; #ifdef CLIPPING cliparound(cx, cy); #endif @@ -1134,7 +1134,7 @@ getpos(coord *ccp, boolean force, const char *goal) break; } nxtc: - ; + gg.getposx = cx, gg.getposy = cy; #ifdef CLIPPING cliparound(cx, cy); #endif @@ -1150,6 +1150,7 @@ getpos(coord *ccp, boolean force, const char *goal) clear_nhwindow(WIN_MESSAGE); ccp->x = cx; ccp->y = cy; + gg.getposx = gg.getposy = 0; for (i = 0; i < NUM_GLOCS; i++) if (garr[i]) free((genericptr_t) garr[i]); diff --git a/sys/vms/vmstty.c b/sys/vms/vmstty.c index 00ded425c..1c7130e11 100644 --- a/sys/vms/vmstty.c +++ b/sys/vms/vmstty.c @@ -582,6 +582,23 @@ VA_DECL(const char *, s) #endif exit(EXIT_FAILURE); } + +#ifdef SIGWINCH +/* called by resize_tty(wintty.c) after receiving a SIGWINCH signal; + terminal size has changed and we should update LI and CO (from termcap) */ +void +getwindowsz(void) +{ + /* + * gettty() has code to do this, but it can't be used directly because + * it fetches terminal state in order to reset that upon termination. + * We need to avoid clobbering other saved state with values used by + * game-in-progress. For now, do nothing. + */ + return; +} +#endif + #ifdef ENHANCED_SYMBOLS /* * set in tty_start_screen() and allows @@ -592,6 +609,8 @@ VA_DECL(const char *, s) void tty_utf8graphics_fixup(void) { + return; } #endif /* ENHANCED_SYMBOLS */ +/*vmstty.c */ diff --git a/win/tty/getline.c b/win/tty/getline.c index eecff8bfb..abefed260 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -39,7 +39,10 @@ tty_getlin(const char *query, register char *bufp) } static void -hooked_tty_getlin(const char *query, register char *bufp, getlin_hook_proc hook) +hooked_tty_getlin( + const char *query, + register char *bufp, + getlin_hook_proc hook) { register char *obufp = bufp; register int c; diff --git a/win/tty/termcap.c b/win/tty/termcap.c index a7f38c957..11be382fe 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -627,6 +627,8 @@ term_clear_screen(void) if (CL) { xputs(CL); home(); + /* set remembered data to all spaces */ + erase_tty_screen(); } } diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 7f3214425..e8ed9d934 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -36,9 +36,10 @@ extern void msmsg(const char *, ...); #include "wintty.h" -#ifdef CLIPPING /* might want SIGWINCH */ -#if defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE) +#if defined(CLIPPING) && !defined(NO_SIGNAL) #include +#ifdef SIGWINCH +#define RESIZABLE #endif #endif @@ -80,7 +81,7 @@ extern void msmsg(const char *, ...); */ #define HUPSKIP() \ do { \ - if (gp.program_state.done_hup) { \ + if (gp.program_state.done_hup) { \ morc = '\033'; \ return; \ } \ @@ -88,7 +89,7 @@ extern void msmsg(const char *, ...); /* morc=ESC - in case we bypass xwaitforspace() which sets that */ #define HUPSKIP_RESULT(RES) \ do { \ - if (gp.program_state.done_hup) \ + if (gp.program_state.done_hup) \ return (RES); \ } while (0) #else /* !HANGUPHANDLING */ @@ -177,6 +178,8 @@ struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ extern void cmov(int, int); /* from termcap.c */ extern void nocmov(int, int); /* from termcap.c */ +static volatile int erasing_tty_screen; /* volatile: SIGWINCH */ + #if defined(UNIX) || defined(VMS) static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ #endif @@ -212,6 +215,7 @@ static const char to_continue[] = "to continue"; static void getret(void); #endif static void bail(const char *); /* __attribute__((noreturn)) */ +static void newclipping(coordxy, coordxy); static void new_status_window(void); static void erase_menu_or_text(winid, struct WinDesc *, boolean); static void free_window_info(struct WinDesc *, boolean); @@ -269,6 +273,7 @@ static long last_glyph_reset_when; #endif static boolean calling_from_update_inventory = FALSE; static int ttyinv_create_window(int, struct WinDesc *); +static void ttyinv_remove_data(boolean); static void ttyinv_add_menu(winid, struct WinDesc *, char ch, int attr, int clr, const char *str); static void ttyinv_render(winid window, struct WinDesc *cw); @@ -349,84 +354,141 @@ bail(const char *mesg) /*NOTREACHED*/ } -#if defined(SIGWINCH) && defined(CLIPPING) && !defined(NO_SIGNAL) +#ifdef RESIZABLE static void winch_handler(int); +static void resize_tty(void); + +static volatile int resize_mesg = 0; - /* - * This really ought to just set a flag like the hangup handler does, - * then check the flag at "safe" times, in case the signal arrives - * while something fragile is executing. Better to have a brief period - * where display updates don't fit the new size than for tty internals - * to become corrupted. - * - * 'winch_seen' has been "notyet" for a long time.... - */ /* signal handler is called with at least 1 arg */ /*ARGUSED*/ static void winch_handler(int sig_unused UNUSED) { - int oldLI = LI, oldCO = CO, i; - register struct WinDesc *cw; - #ifdef WINCHAIN { #define WINCH_MESSAGE "(SIGWINCH)" if (wc_tracelogf) (void) write(fileno(wc_tracelogf), WINCH_MESSAGE, - strlen(WINCH_MESSAGE)); + sizeof WINCH_MESSAGE - sizeof ""); #undef WINCH_MESSAGE } #endif -#ifndef VMS - getwindowsz(); + + gp.program_state.resize_pending++; /* resize_tty() will reset it */ + /* if nethack is waiting for input, which is the most likely scenario, + we will go ahead and respond to the resize immediately; otherwise, + tty_nhgetch() will do so the next time it's called */ + if (gp.program_state.getting_char) { + resize_tty(); +#if 0 /* [this doesn't work as intended and seems to be unnecessary] */ + if (resize_mesg) { + /* resize_tty() put "Press a key to continue: " on top line */ + (void) tty_nhgetch(); /* recursion... */ + } #endif - /* For long running events such as multi-page menus and - * display_file(), we note the signal's occurance and - * hope the code there decides to handle the situation - * and reset the flag. There will be race conditions - * when handling this - code handlers so it doesn't matter. - */ -#ifdef notyet - winch_seen = TRUE; + } + return; +} + +/* query the system for tty size (vis getwindowsz()), and adapt the game's + windows to match */ +static void +resize_tty(void) +{ + int oldLI = LI, oldCO = CO, mapx, mapy, oldtoplin, i; + boolean map_active; + struct WinDesc *cw; + + /* reset to 0 rather than just decrement */ + gp.program_state.resize_pending = 0; + resize_mesg = 0; + + getwindowsz(); /* update LI and CO */ + if (!ttyDisplay || (LI == oldLI && CO == oldCO)) + return; + + ttyDisplay->rows = LI; + ttyDisplay->cols = CO; + + cw = wins[BASE_WINDOW]; + cw->rows = ttyDisplay->rows; + cw->cols = ttyDisplay->cols; + + if (!iflags.window_inited) + return; + + /* try to figure out where we'll want to leave the cursor */ + cw = (WIN_MAP != WIN_ERR) ? wins[WIN_MAP] : NULL; + map_active = (cw && cw->active); + if (!map_active) + mapx = 1, mapy = 0; + else if (gg.getposx < 1) + mapx = u.ux, mapy = u.uy; + else + mapx = gg.getposx, mapy = gg.getposy; + + oldtoplin = ttyDisplay->toplin; + ttyDisplay->toplin = TOPLINE_EMPTY; /* (before term_clear_screen()) */ + /* whatever used to be on the screen has become suspect; + blank it all out, then redo the display */ + term_clear_screen(); + new_status_window(); + + /* if the map window is shown, redisplay it (also status, perminv) */ + if (map_active) { + docrt_flags(docrtRefresh); + bot(); /* context.botlx=1 gets set by docrt() */ + for (i = 0; i < MAXWIN; ++i) { + if (i == BASE_WINDOW + || i == WIN_MAP /* docrt() updates it */ + || i == WIN_STATUS /* docrt()+bot() updates it */ +#ifdef TTY_PERM_INVENT + || i == WIN_INVEN /* docrt() again */ #endif - if ((oldLI != LI || oldCO != CO) && ttyDisplay) { - ttyDisplay->rows = LI; - ttyDisplay->cols = CO; - - cw = wins[BASE_WINDOW]; - cw->rows = ttyDisplay->rows; - cw->cols = ttyDisplay->cols; - - if (iflags.window_inited) { - cw = wins[WIN_MESSAGE]; - cw->curx = cw->cury = 0; - - new_status_window(); - if (u.ux) { - i = ttyDisplay->toplin; - ttyDisplay->toplin = TOPLINE_EMPTY; - docrt(); - bot(); - ttyDisplay->toplin = i; - flush_screen(1); - if (i) { - addtopl(gt.toplines); - } else - for (i = WIN_INVEN; i < MAXWIN; i++) - if (wins[i] && wins[i]->active) { - /* cop-out */ - addtopl("Press Return to continue: "); - break; - } - (void) fflush(stdout); - if (i < 2) - flush_screen(1); + || i == WIN_MESSAGE) /* we fake it here */ + continue; + if (wins[i] && wins[i]->active) { + /* cop-out */ + oldtoplin = TOPLINE_EMPTY; /* don't restore it below */ + ttyDisplay->toplin = TOPLINE_NON_EMPTY; + addtopl("Press a key to continue: "); + resize_mesg++; + break; } } + } /* wins[WIN_MAP].active */ + + if (oldtoplin != TOPLINE_EMPTY) { + ttyDisplay->toplin = oldtoplin; + addtopl(gt.toplines); } + if (map_active) { + newclipping(mapx, mapy); + tty_curs(WIN_MAP, mapx, mapy); + tty_display_nhwindow(WIN_MAP, FALSE); /*fflush(stdout)*/ + } + return; +} +#endif /* RESIZABLE */ + +static void +newclipping(coordxy x, coordxy y) +{ +#ifdef CLIPPING + if (CO < COLNO || LI < 1 + ROWNO + iflags.wc2_statuslines) { + setclipped(); /* sets clipping=TRUE */ + if (x) + tty_cliparound(x, y); + } else { + clipping = FALSE; + clipx = clipy = 0; + } +#else + nhUse(x + y); +#endif + return; } -#endif /* SIGWINCH && CLIPPING && !NO_SIGNAL */ /* destroy and recreate status window; extracted from winch_handler() and augmented for use by tty_preference_update() */ @@ -434,11 +496,9 @@ static void new_status_window(void) { if (WIN_STATUS != WIN_ERR) { - /* if it's shrinking, clear it before destroying so that + /* in case it's shrinking, clear it before destroying so that dropped portion won't show anything that's now becoming stale */ - if (wins[WIN_STATUS]->maxrow > iflags.wc2_statuslines) - tty_clear_nhwindow(WIN_STATUS); - + tty_clear_nhwindow(WIN_STATUS); tty_destroy_nhwindow(WIN_STATUS), WIN_STATUS = WIN_ERR; } /* frees some status tracking data */ @@ -449,18 +509,6 @@ new_status_window(void) #ifdef STATUS_HILITES status_initialize(REASSESS_ONLY); #endif - -#ifdef CLIPPING - if (u.ux) { - if (CO < COLNO || LI < 1 + ROWNO + iflags.wc2_statuslines) { - setclipped(); - tty_cliparound(u.ux, u.uy); - } else { - clipping = FALSE; - clipx = clipy = 0; - } - } -#endif } /*ARGSUSED*/ @@ -511,7 +559,7 @@ tty_init_nhwindows(int *argcp UNUSED, char **argv UNUSED) ttyDisplay->lastwin = WIN_ERR; -#if defined(SIGWINCH) && defined(CLIPPING) && !defined(NO_SIGNAL) +#ifdef RESIZABLE (void) signal(SIGWINCH, (SIG_RET_TYPE) winch_handler); #endif @@ -555,6 +603,7 @@ tty_preference_update(const char *pref) { if (!strcmp(pref, "statuslines") && iflags.window_inited) { new_status_window(); + newclipping(u.ux, u.uy); } #if defined(WIN32CON) @@ -983,10 +1032,13 @@ tty_clear_nhwindow(winid window) switch (cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin != TOPLINE_EMPTY) { - home(); - cl_end(); - if (cw->cury) - docorner(1, cw->cury + 1, 0); + if (!erasing_tty_screen) { + home(); + cl_end(); + if (cw->cury) + docorner(1, cw->cury + 1, 0); + } + cw->curx = cw->cury = 0; ttyDisplay->toplin = TOPLINE_EMPTY; } break; @@ -994,9 +1046,10 @@ tty_clear_nhwindow(winid window) m = cw->maxrow; n = cw->cols; for (i = 0; i < m; ++i) { - tty_curs(window, 1, i); - cl_end(); - + if (!erasing_tty_screen) { + tty_curs(window, 1, i); + cl_end(); + } for (j = 0; j < n - 1; ++j) cw->data[i][j] = ' '; cw->data[i][n - 1] = '\0'; @@ -1009,17 +1062,33 @@ tty_clear_nhwindow(winid window) gc.context.botlx = 1; /*FALLTHRU*/ case NHW_BASE: - term_clear_screen(); - /* [this should reset state for MESSAGE, MAP, and STATUS] */ + /* if erasing_tty_screen is True, calling sequence is + term_clear_screen -> erase_tty_screen -> tty_clear_nhwindow + so we don't call term_clear_screen again */ + if (!erasing_tty_screen) { + term_clear_screen(); + } + /* + * Neither map nor base window tracks what is currently shown so + * there's no stale data that would need to be changed to spaces. + */ break; case NHW_MENU: case NHW_TEXT: if (cw->active) erase_menu_or_text(window, cw, TRUE); - free_window_info(cw, FALSE); + if (!erasing_tty_screen) { + free_window_info(cw, FALSE); + } break; +#ifdef TTY_PERM_INVENT + case NHW_PERMINVENT: + ttyinv_remove_data(FALSE); + break; +#endif } cw->curx = cw->cury = 0; + /* cw->blanked = TRUE; -- this isn't used */ } RESTORE_WARNING_FORMAT_NONLITERAL @@ -1906,40 +1975,39 @@ tty_destroy_nhwindow(winid window) if (cw->type == NHW_MAP) term_clear_screen(); #ifdef TTY_PERM_INVENT - if (cw->type == NHW_PERMINVENT) { - int r, c; - - if (cw->cells) { - for (r = 0; r < cw->maxrow; r++) { - if (cw->cells[r]) { - for (c = 0; c < cw->maxcol; c++) { - /* glyph is a flag indicating whether content union - contains a glyph_info structure or just a char */ - if (cw->cells[r][c].glyph) - free((genericptr_t) cw->cells[r][c].content.gi); - cw->cells[r][c] = zerottycell; - cw->cells[r][c].glyph = 0; - } - free((genericptr_t) cw->cells[r]); - cw->cells[r] = (struct tty_perminvent_cell *) 0; - } - } - free((genericptr_t) cw->cells); - cw->cells = (struct tty_perminvent_cell **) 0; - cw->rows = cw->cols = 0; - } - cw->maxrow = cw->maxcol = 0; - WIN_INVEN = WIN_ERR; - done_tty_perm_invent_init = FALSE; - } + if (cw->type == NHW_PERMINVENT) + ttyinv_remove_data(TRUE); #endif free_window_info(cw, TRUE); free((genericptr_t) cw); wins[window] = 0; /* available for re-use */ } +/* when screen is cleared, reset stored data to spaces */ void -tty_curs(winid window, +erase_tty_screen(void) +{ + struct WinDesc *cw; + int i; + + if (erasing_tty_screen++) + return; +#if 0 /* originally we called term_clear_screen() but now it calls us */ + term_clear_screen(); /* erase the screen */ +#endif + /* update window data to reflect that each active window is all blanks */ + for (i = 0; i < MAXWIN; ++i) { + cw = wins[i]; + if (cw && cw->active) + tty_clear_nhwindow(i); + } + tty_curs(BASE_WINDOW, 1, 0); + erasing_tty_screen = 0; +} + +void +tty_curs( + winid window, register int x, register int y) /* not xchar: perhaps xchar is unsigned * then curx-x would be unsigned too */ { @@ -2330,9 +2398,6 @@ tty_display_file( nh_terminate(EXIT_FAILURE); } (void) close(fd); -#ifdef notyet - winch_seen = 0; -#endif } #else /* DEF_PAGER */ { @@ -2406,11 +2471,12 @@ tty_start_menu(winid window, unsigned long mbehavior) return; } if (mbehavior == MENU_BEHAVE_PERMINV - && (iflags.perm_invent - || gp.perm_invent_toggling_direction == toggling_on)) { + && (iflags.perm_invent + || gp.perm_invent_toggling_direction == toggling_on)) { winid w = ttyinv_create_window(window, wins[window]); + if (w == WIN_ERR) { - /* something went wrong, so add clean up code here */ + ; /* something went wrong, so add clean up code here */ } else { cw->mbehavior = mbehavior; } @@ -2537,7 +2603,8 @@ tty_end_menu(winid window, /* menu to use */ } #ifdef TTY_PERM_INVENT if (cw->mbehavior == MENU_BEHAVE_PERMINV - && (iflags.perm_invent || gp.perm_invent_toggling_direction == toggling_on) + && (iflags.perm_invent + || gp.perm_invent_toggling_direction == toggling_on) && window == WIN_INVEN) { if (gp.program_state.in_moveloop) ttyinv_render(window, cw); @@ -2807,7 +2874,6 @@ ttyinv_create_window(int newid, struct WinDesc *newwin) newwin->datlen = (short *) 0; newwin->cells = (struct tty_perminvent_cell **) 0; - if (!assesstty(ttyinvmode, &newwin->offx, &newwin->offy, &newwin->rows, &newwin->cols, &newwin->maxcol, &minrow, &newwin->maxrow)) { @@ -2861,6 +2927,54 @@ ttyinv_create_window(int newid, struct WinDesc *newwin) return newid; } +/* discard perminvent window or erase it and set remembered data to spaces */ +static void +ttyinv_remove_data(boolean destroy) +{ + struct WinDesc *cw = (WIN_INVEN != WIN_ERR) ? wins[WIN_INVEN] : NULL; + + if (!cw) { + impossible("Removing ttyinv data for nonexistent perm invent window?"); + return; + } + + if (cw->cells) { + int r, c; + + for (r = 0; r < cw->maxrow; r++) { + if (cw->cells[r]) { + for (c = 0; c < cw->maxcol; c++) { + struct tty_perminvent_cell *invcell = &cw->cells[r][c]; + + /* glyph is a flag indicating whether content union + contains a glyph_info structure or just a char */ + if (invcell->glyph) + free((genericptr_t) invcell->content.gi); + *invcell = zerottycell; /* sets glyph flag to 0 */ + if (!destroy) { /* erasing */ + invcell->content.ttychar = ' '; + invcell->text = 1; + invcell->refresh = 1; /* full redraw wanted */ + } + } + if (destroy) + free((genericptr_t) cw->cells[r]), + cw->cells[r] = (struct tty_perminvent_cell *) 0; + } + } + if (destroy) { + free((genericptr_t) cw->cells), + cw->cells = (struct tty_perminvent_cell **) 0; + cw->rows = cw->cols = 0; + } + } + if (destroy) { + cw->maxrow = cw->maxcol = 0; + WIN_INVEN = WIN_ERR; + done_tty_perm_invent_init = FALSE; + } +} + static void ttyinv_add_menu(winid window UNUSED, struct WinDesc *cw, char ch, int attr UNUSED, int clr UNUSED, const char *str) @@ -2908,15 +3022,14 @@ ttyinv_add_menu(winid window UNUSED, struct WinDesc *cw, char ch, } return; } + static int selector_to_slot(char ch, const int invflags, boolean *ignore) { int slot = 0; boolean show_gold = (invflags & InvShowGold) != 0, + /* sparse = (invflags & InvSparse) != 0, */ inuse_only = (invflags & InvInUse) != 0; -#if 0 - sparse = (invflags & InvSparse) != 0, -#endif *ignore = FALSE; switch (ch) { @@ -3216,6 +3329,7 @@ tty_invent_box_glyph_init(struct WinDesc *cw) } done_tty_perm_invent_init = TRUE; } + #endif /* TTY_PERM_INVENT */ /* update persistent inventory window */ @@ -3260,7 +3374,9 @@ tty_wait_synch(void) } void -docorner(register int xmin, register int ymax, int ystart_between_menu_pages) +docorner( + register int xmin, register int ymax, + int ystart_between_menu_pages) { register int y; register struct WinDesc *cw = wins[WIN_MAP]; @@ -3274,7 +3390,7 @@ docorner(register int xmin, register int ymax, int ystart_between_menu_pages) HUPSKIP(); #if 0 /* this optimization is not valuable enough to justify - abusing core internals... */ + * abusing core internals... */ if (u.uswallow) { /* Can be done more efficiently */ swallowed(1); /* without this flush, if we happen to follow --More-- displayed in @@ -3285,7 +3401,7 @@ docorner(register int xmin, register int ymax, int ystart_between_menu_pages) } #endif /*0*/ -#if defined(SIGWINCH) && defined(CLIPPING) +#ifdef RESIZABLE if (ymax > LI) ymax = LI; /* can happen if window gets smaller */ #endif @@ -3633,12 +3749,10 @@ tty_nhgetch(void) { int i; #ifdef UNIX - /* kludge alert: Some Unix variants return funny values if getc() - * is called, interrupted, and then called again. There - * is non-reentrant code in the internal _filbuf() routine, called by - * getc(). + /* kludge alert: Some Unix variants return funny values if getc() is + * called, interrupted, and then called again. There is non-reentrant + * code in the internal _filbuf() routine, called by getc(). */ - static volatile int nesting = 0; char nestbuf; #endif @@ -3655,21 +3769,33 @@ tty_nhgetch(void) if (iflags.debug_fuzzer) { i = randomkey(); } else { +#ifdef RESIZABLE + if (gp.program_state.resize_pending) + resize_tty(); +#endif + gp.program_state.getting_char++; #ifdef UNIX - i = (++nesting == 1) + i = (gp.program_state.getting_char == 1) ? tgetch() - : (read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1) - ? (int) nestbuf : EOF; - --nesting; + : ((read(fileno(stdin), (genericptr_t) &nestbuf, 1) == 1) + ? (int) nestbuf : EOF); #else i = tgetch(); +#endif + gp.program_state.getting_char--; +#ifdef RESIZABLE + if (resize_mesg) { + resize_mesg = 0; + tty_clear_nhwindow(WIN_MESSAGE); + i = '\033'; + } #endif } if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ else if (i == EOF) i = '\033'; /* same for EOF */ - /* topline has been seen - we can clear need for more */ + /* topline has been seen - we can clear the need for --More-- */ if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) ttyDisplay->toplin = TOPLINE_NON_EMPTY; #ifdef TTY_TILES_ESCCODES @@ -4826,6 +4952,7 @@ play_usersound_via_idx(int idx, int volume) #undef print_vt_soundcode_idx #endif +#undef RESIZABLE #ifdef getret #undef getret #endif