1 /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/
2 /* NetHack 3.7 cursmain.c */
3 /* Copyright (c) Karl Garrison, 2010. */
4 /* NetHack may be freely redistributed. See license for details. */
14 /* define this if not linking with <foo>tty.o|.obj for some reason */
15 #ifdef CURSES_DEFINE_ERASE_CHAR
16 char erase_char
, kill_char
;
18 /* defined in sys/<foo>/<foo>tty.o|.obj which gets linked into
19 tty-only, tty+curses, and curses-only binaries */
20 extern char erase_char
, kill_char
;
23 extern long curs_mesg_suppress_seq
; /* from cursmesg.c */
24 extern boolean curs_mesg_no_suppress
; /* ditto */
25 extern int mesg_mixed
;
26 extern glyph_info mesg_gi
;
28 #ifndef CURSES_GENL_PUTMIXED
29 #if defined(PDC_WIDE) || defined(NCURSES_WIDECHAR)
30 #define USE_CURSES_PUTMIXED
32 #ifdef NH_PRAGMA_MESSAGE
34 #pragma message ("Curses wide support not defined so NetHack curses message window functionality reduced")
36 #pragma message "Curses wide support not defined so NetHack curses message window functionality reduced"
38 #endif /* NH_PRAGMA_MESSAGE */
40 #endif /* CURSES_GENL_PUTMIXED */
42 /* stubs for curses_procs{} */
44 static void dummy_update_position_bar(char *);
47 static void curses_change_color(int, long, int);
48 static char *curses_get_color_string(void);
51 /* Public functions for curses NetHack interface */
53 /* Interface definition, for windows.c */
54 struct window_procs curses_procs
= {
56 (WC_ALIGN_MESSAGE
| WC_ALIGN_STATUS
| WC_COLOR
| WC_INVERSE
57 | WC_HILITE_PET
| WC_WINDOWCOLORS
58 #ifdef NCURSES_MOUSE_VERSION /* (this macro name works for PDCURSES too) */
61 | WC_PERM_INVENT
| WC_POPUP_DIALOG
| WC_SPLASH_SCREEN
),
62 (WC2_DARKGRAY
| WC2_HITPOINTBAR
70 #if defined(STATUS_HILITES)
73 | WC2_FLUSH_STATUS
| WC2_TERM_SIZE
74 | WC2_STATUSLINES
| WC2_WINDOWBORDERS
| WC2_PETATTR
| WC2_GUICOLOR
75 | WC2_SUPPRESS_HIST
| WC2_URGENT_MESG
| WC2_MENU_SHIFT
),
76 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
77 curses_init_nhwindows
,
78 curses_player_selection
,
81 curses_exit_nhwindows
,
82 curses_suspend_nhwindows
,
83 curses_resume_nhwindows
,
84 curses_create_nhwindow
,
85 curses_clear_nhwindow
,
86 curses_display_nhwindow
,
87 curses_destroy_nhwindow
,
90 #ifdef USE_CURSES_PUTMIXED
107 dummy_update_position_bar
,
111 curses_raw_print_bold
,
115 curses_doprev_message
,
123 #ifdef MAC /* old OS 9, not OSX */
125 (short (*)(winid
, char *)) 0,
127 curses_get_color_string
,
132 curses_preference_update
,
133 curses_getmsghistory
,
134 curses_putmsghistory
,
136 curses_status_finish
,
137 genl_status_enablefield
,
138 curses_status_update
,
139 genl_can_suspend_yes
,
140 curses_update_inventory
,
141 curses_ctrl_nhwindow
,
145 * Global variables for curses interface
148 int term_rows
, term_cols
; /* size of underlying terminal */
149 int orig_cursor
; /* Preserve initial cursor state */
150 WINDOW
*base_term
; /* underlying terminal window */
151 boolean counting
; /* Count window is active */
152 WINDOW
*mapwin
, *statuswin
, *messagewin
; /* Main windows */
153 color_attr curses_menu_promptstyle
= { NO_COLOR
, ATR_NONE
};
155 /* Track if we're performing an update to the permanent window.
156 Needed since we aren't using the normal menu functions to handle
157 the inventory window. */
158 static int inv_update
= 0;
161 init_nhwindows(int *argcp, char **argv)
162 -- Initialize the windows used by NetHack. This can also
163 create the standard windows listed at the top, but does
165 -- Any commandline arguments relevant to the windowport
166 should be interpreted, and *argcp and *argv should
167 be changed to remove those arguments.
168 -- When the message window is created, the variable
169 iflags.window_inited needs to be set to TRUE. Otherwise
170 all plines() will be done via raw_print().
171 ** Why not have init_nhwindows() create all of the "standard"
172 ** windows? Or at least all but WIN_INFO? -dean
175 curses_init_nhwindows(
180 char window_title
[BUFSZ
];
182 #ifdef CURSES_UNICODE
184 static char pdc_font
[BUFSZ
] = "";
188 #ifdef CURSES_UNICODE
189 setlocale(LC_CTYPE
, "");
191 /* Assume the DOSVGA port of PDCursesMod, or the SDL1 or SDL2 port of
192 either PDCurses or PDCursesMod. Honor the font_map option to set
194 On MS-DOS, if no font_map is set, use ter-u16v.psf if it is present.
195 PDC_FONT has no effect on other PDCurses or PDCursesMod ports. */
196 if (iflags
.wc_font_map
&& iflags
.wc_font_map
[0]) {
197 Snprintf(pdc_font
, sizeof(pdc_font
), "PDC_FONT=%s",
200 } else if (access("ter-u16v.psf", R_OK
) >= 0) {
201 Snprintf(pdc_font
, sizeof(pdc_font
), "PDC_FONT=ter-u16v.psf");
204 if (pdc_font
[0] != '\0') {
210 /* if anything has already been output by nethack (for instance, warnings
211 about RC file issues), let the player acknowlege it before initscr()
213 if (iflags
.raw_printed
)
217 base_term
= Xinitscr(*argcp
, argv
);
219 base_term
= initscr();
223 curses_init_nhcolors();
225 iflags
.use_color
= FALSE
;
226 set_option_mod_status("color", set_in_config
);
227 iflags
.wc2_guicolor
= FALSE
;
228 set_wc2_option_mod_status(WC2_GUICOLOR
, set_in_config
);
232 nonl(); /* don't force ^M into newline (^J); input accepts them both
233 * but as a command, accidental <enter> won't run South */
235 orig_cursor
= curs_set(0);
236 keypad(stdscr
, TRUE
);
237 #ifdef NCURSES_VERSION
242 # endif/* __APPLE__ */
243 #endif /* NCURSES_VERSION */
245 # ifdef DEF_GAME_NAME
246 # ifdef VERSION_STRING
247 Snprintf(window_title
, sizeof window_title
, "%s %s",
248 DEF_GAME_NAME
, VERSION_STRING
);
250 if (nomakedefs
.version_string
)
251 Snprintf(window_title
, sizeof window_title
, "%s %s",
252 DEF_GAME_NAME
, nomakedefs
.version_string
);
254 Snprintf(window_title
, sizeof window_title
, "%s", DEF_GAME_NAME
);
258 # ifdef VERSION_STRING
259 Snprintf(window_title
, sizeof window_title
, "%s %s",
260 "NetHack", VERSION_STRING
);
262 if (nomakedefs
.version_string
)
263 Snprintf(window_title
, sizeof window_title
, "%s %s",
264 "NetHack", nomakedefs
.version_string
);
266 Snprintf(window_title
, sizeof window_title
, "%s", "NetHack");
269 # endif/* DEF_GAME_NAME */
270 PDC_set_title(window_title
);
271 PDC_set_blink(TRUE
); /* Only if the user asks for it! */
275 #endif /* PDCURSES */
276 getmaxyx(base_term
, term_rows
, term_cols
);
278 curses_init_options();
279 if (term_rows
< 15 || term_cols
< 40) {
280 panic("Terminal is too small; must have at least %s%s%s.",
281 (term_rows
< 15) ? "15 rows" : "",
282 (term_rows
< 15 && term_cols
< 40) ? " and " : "",
283 (term_cols
< 40) ? "40 columns" : "");
285 /* during line input, deletes the most recently typed character */
286 erase_char
= erasechar(); /* <delete>/<rubout> or possibly <backspace> */
287 /* during line input, deletes all typed characters */
288 kill_char
= killchar(); /* ^U (back in prehistoric times, '@') */
290 curses_create_main_windows();
291 curses_init_mesg_history();
292 curses_display_splash_window();
295 /* Use the general role/race/&c selection originally implemented for tty. */
297 curses_player_selection(void)
300 if (genl_player_setup(0))
301 return; /* success */
304 curses_bail((const char *) NULL
);
307 /* still present cursinit.c but no longer used */
308 curses_choose_character();
313 /* Ask the user for a player name. */
318 if (iflags
.wc2_selectsaved
&& !iflags
.renameinprogress
)
319 switch (restore_menu(MAP_WIN
)) {
322 case 0: /* new game */
324 case 1: /* picked a save file to restore and set plname[] for it */
327 #endif /* SELECTSAVED */
329 curses_line_input_dialog("Who are you?", svp
.plname
, PL_NSIZ
);
330 (void) mungspaces(svp
.plname
);
331 if (!svp
.plname
[0] || svp
.plname
[0] == '\033')
334 iflags
.renameallowed
= TRUE
; /* tty uses this, we don't [yet?] */
338 /* message is delivered via raw_print() */
339 curses_bail("\nUntil next time then...\n");
344 /* Does window event processing (e.g. exposure events).
345 A noop for the tty and X window-ports.
348 curses_get_nh_event(void)
350 boolean do_reset
= FALSE
;
353 if (is_termresized()) {
358 #ifdef NCURSES_VERSION /* Is there a better way to detect ncurses? */
359 if (is_term_resized(term_rows
, term_cols
)) {
369 getmaxyx(base_term
, term_rows
, term_cols
);
370 curses_got_input(); /* reset More>> */
371 /* status_initialize, create_main_windows, last_messages, doredraw */
372 curs_reset_windows(TRUE
, TRUE
);
376 /* restore terminal state; extracted from curses_exit_nhwindows() */
378 curses_uncurse_terminal(void)
380 /* also called by panictrace_handler(), a signal handler, so somewhat
381 iffy in that situation; but without this, newlines behave as raw
382 line feeds so subsequent backtrace gets scrawled all over the screen
383 and is nearly useless */
385 curs_set(orig_cursor
);
389 /* Exits the window system. This should dismiss all windows,
390 except the "window" used for raw_print(). str is printed if possible.
393 curses_exit_nhwindows(const char *str
)
395 curses_destroy_nhwindow(INV_WIN
);
396 curses_destroy_nhwindow(MAP_WIN
);
397 curses_destroy_nhwindow(STATUS_WIN
);
398 curses_destroy_nhwindow(MESSAGE_WIN
);
399 curs_destroy_all_wins();
401 curses_uncurse_terminal();
403 iflags
.window_inited
= 0;
409 /* Prepare the window to be suspended. */
411 curses_suspend_nhwindows(const char *str UNUSED
)
417 /* Restore the windows after being suspended. */
419 curses_resume_nhwindows(void)
421 curses_refresh_nethack_windows();
424 /* Create a window of type "type" which can be
425 NHW_MESSAGE (top line)
426 NHW_STATUS (bottom lines)
427 NHW_MAP (main dungeon)
428 NHW_MENU (inventory or other "corner" windows)
429 NHW_TEXT (help/text, full screen paged window)
432 curses_create_nhwindow(int type
)
434 winid wid
= curses_get_wid(type
);
436 if (curses_is_menu(wid
))
437 curses_parse_wid_colors(MENU_WIN
, iflags
.wcolors
[wcolor_menu
].fg
,
438 iflags
.wcolors
[wcolor_menu
].bg
);
439 else if (curses_is_text(wid
))
440 curses_parse_wid_colors(TEXT_WIN
, iflags
.wcolors
[wcolor_text
].fg
,
441 iflags
.wcolors
[wcolor_text
].bg
);
442 if (curses_is_menu(wid
) || curses_is_text(wid
)) {
443 curses_start_menu(wid
, MENU_BEHAVE_STANDARD
);
451 /* Clear the given window, when asked to. */
453 curses_clear_nhwindow(winid wid
)
455 if (wid
!= NHW_MESSAGE
) {
456 curses_clear_nhwin(wid
);
458 /* scroll the message window one line if it's full */
459 curses_count_window("");
460 /* remove 'countwin', leaving last message line blank */
461 curses_count_window((char *) 0);
465 /* -- Display the window on the screen. If there is data
466 pending for output in that window, it should be sent.
467 If blocking is TRUE, display_nhwindow() will not
468 return until the data has been displayed on the screen,
469 and acknowledged by the user where appropriate.
470 -- All calls are blocking in the tty window-port.
471 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
472 --more--, if necessary, in the tty window-port.
475 curses_display_nhwindow(winid wid
, boolean block
)
477 menu_item
*selected
= NULL
;
478 int border
= curses_window_has_border(wid
) ? 1 : 0;
482 if (curses_is_menu(wid
) || curses_is_text(wid
)) {
483 curses_end_menu(wid
, "");
484 (void) curses_select_menu(wid
, PICK_NONE
, &selected
);
488 /* don't overwrite the splash screen first time through */
489 if (!iflags
.window_inited
&& wid
== MAP_WIN
) {
490 iflags
.window_inited
= TRUE
;
492 WINDOW
*win
= curses_get_nhwin(wid
);
494 /* actually display the window */
498 /* flush pending writes from other windows too */
501 if ((wid
== MAP_WIN
) && block
) {
502 (void) curses_more();
505 if ((wid
== MESSAGE_WIN
) && block
) {
506 (void) curses_block(TRUE
);
511 /* Destroy will dismiss the window if the window has not
512 * already been dismissed.
515 curses_destroy_nhwindow(winid wid
)
519 curses_teardown_messages(); /* discard ^P message history data */
522 if (VIA_WINDOWPORT())
523 curses_status_finish(); /* discard cached status data */
526 curs_purge_perminv_data(TRUE
);
527 iflags
.perm_invent
= 0; /* avoid unexpected update_inventory() */
534 curses_del_nhwin(wid
);
537 /* Next output to window will start at (x,y), also moves
538 displayable cursor to (x,y). For backward compatibility,
539 1 <= x < cols, 0 <= y < rows, where cols and rows are
543 curses_curs(winid wid
, int x
, int y
)
545 curses_move_cursor(wid
, x
, y
);
549 putstr(window, attr, str)
550 -- Print str on the window with the given attribute. Only
551 printable ASCII characters (040-0126) must be supported.
552 Multiple putstr()s are output on separate lines.
553 Attributes can be one of
559 If a window-port does not support all of these, it may map
560 unsupported attributes to a supported one (e.g. map them
561 all to ATR_INVERSE). putstr() may compress spaces out of
562 str, break str, or truncate str, if necessary for the
563 display. Where putstr() breaks a line, it has to clear
565 -- putstr should be implemented such that if two putstr()s
566 are done consecutively the user will see the first and
567 then the second. In the tty port, pline() achieves this
568 by calling more() or displaying both on the same line.
571 curses_putstr(winid wid
, int attr
, const char *text
)
573 int mesgflags
, curses_attr
;
575 mesgflags
= attr
& (ATR_URGENT
| ATR_NOHISTORY
);
578 /* this is comparable to tty's cw->flags &= ~WIN_STOP; if messages are
579 being suppressed after >>ESC, override that and resume showing them */
580 if ((mesgflags
& ATR_URGENT
) != 0) {
581 curs_mesg_suppress_seq
= -1L;
582 curs_mesg_no_suppress
= TRUE
;
585 if (wid
== WIN_MESSAGE
&& (mesgflags
& ATR_NOHISTORY
) != 0) {
586 /* display message without saving it in recall history */
587 curses_count_window(text
);
589 /* We need to convert NetHack attributes to curses attributes */
590 curses_attr
= curses_convert_attr(attr
);
591 curses_puts(wid
, curses_attr
, text
);
594 /* urgent message handling is a one-shot operation; we're done */
595 curs_mesg_no_suppress
= FALSE
;
599 curses_putmixed(winid window
, int attr
, const char *str
)
601 const char *substr
= 0;
603 boolean done_output
= FALSE
;
604 #ifdef ENHANCED_SYMBOLS
608 if (window
== WIN_MESSAGE
) {
609 str
= mixed_to_glyphinfo(str
, &mesg_gi
);
612 if ((substr
= strstri(str
, "\\G")) != 0) {
613 #ifdef ENHANCED_SYMBOLS
614 if ((windowprocs
.wincap2
& WC2_U_UTF8STR
) && SYMHANDLING(H_UTF8
)) {
615 mixed_to_utf8(buf
, sizeof buf
, str
, &utf8flag
);
618 decode_mixed(buf
, str
);
619 #ifdef ENHANCED_SYMBOLS
622 /* now send buf to the normal putstr */
623 curses_putstr(window
, attr
, buf
);
629 /* just send str to the normal putstr */
630 curses_putstr(window
, attr
, str
);
632 if (window
== WIN_MESSAGE
)
636 /* Display the file named str. Complain about missing files
637 iff complain is TRUE.
640 curses_display_file(const char *filename
, boolean must_exist
)
642 curses_view_file(filename
, must_exist
);
645 /* Start using window as a menu. You must call start_menu()
646 before add_menu(). After calling start_menu() you may not
647 putstr() to the window. Only windows of type NHW_MENU may
651 curses_start_menu(winid wid
, unsigned long mbehavior
)
656 curses_create_nhmenu(wid
, mbehavior
);
660 add_menu(winid wid, const glyph_info *glyphinfo,
661 const anything identifier,
662 char accelerator, char groupacc,
664 char *str, unsigned int itemflags)
665 -- Add a text line str to the given menu window. If identifier
666 is 0, then the line cannot be selected (e.g. a title).
667 Otherwise, identifier is the value returned if the line is
668 selected. Accelerator is a keyboard key that can be used
669 to select the line. If the accelerator of a selectable
670 item is 0, the window system is free to select its own
671 accelerator. It is up to the window-port to make the
672 accelerator visible to the user (e.g. put "a - " in front
673 of str). The value attr is the same as in putstr().
674 -- Glyph is an optional glyph to accompany the line and its
675 modifiers (if any) can be found in glyphinfo. If
676 window port cannot or does not want to display it, this
677 is OK. If there is no glyph applicable, then this
678 value will be NO_GLYPH.
679 -- All accelerators should be in the range [A-Za-z].
680 -- It is expected that callers do not mix accelerator
681 choices. Either all selectable items have an accelerator
682 or let the window system pick them. Don't do both.
683 -- Groupacc is a group accelerator. It may be any character
684 outside of the standard accelerator (see above) or a
685 number. If 0, the item is unaffected by any group
686 accelerator. If this accelerator conflicts with
687 the menu command (or their user defined alises), it loses.
688 The menu commands and aliases take care not to interfere
689 with the default object class symbols.
690 -- If you want this choice to be preselected when the
691 menu is displayed, set bit MENU_ITEMFLAGS_SELECTED.
694 curses_add_menu(winid wid
, const glyph_info
*glyphinfo
,
695 const ANY_P
*identifier
,
696 char accelerator
, char group_accel
, int attr
,
697 int clr
, const char *str
, unsigned itemflags
)
701 attr
&= ~(ATR_URGENT
| ATR_NOHISTORY
);
702 curses_attr
= curses_convert_attr(attr
);
704 /* 'inv_update': 0 for normal menus, 1 and up for perminv window */
706 /* persistent inventory window; nothing is selectable;
707 omit glyphinfo because perm_invent is to the side of
708 the map so usually cramped for horizontal space */
709 curs_add_invt(inv_update
, accelerator
, curses_attr
, clr
, str
);
714 curses_add_nhmenu_item(wid
, glyphinfo
, identifier
,
715 accelerator
, group_accel
,
716 curses_attr
, clr
, str
, itemflags
);
720 end_menu(window, prompt)
721 -- Stop adding entries to the menu and flushes the window
722 to the screen (brings to front?). Prompt is a prompt
723 to give the user. If prompt is NULL, no prompt will
725 ** This probably shouldn't flush the window any more (if
726 ** it ever did). That should be select_menu's job. -dean
729 curses_end_menu(winid wid
, const char *prompt
)
734 curses_finalize_nhmenu(wid
, prompt
);
738 int select_menu(winid window, int how, menu_item **selected)
739 -- Return the number of items selected; 0 if none were chosen,
740 -1 when explicitly cancelled. If items were selected, then
741 selected is filled in with an allocated array of menu_item
742 structures, one for each selected line. The caller must
743 free this array when done with it. The "count" field
744 of selected is a user supplied count. If the user did
745 not supply a count, then the count field is filled with
746 -1 (meaning all). A count of zero is equivalent to not
747 being selected and should not be in the list. If no items
748 were selected, then selected is NULL'ed out. How is the
749 mode of the menu. Three valid values are PICK_NONE,
750 PICK_ONE, and PICK_N, meaning: nothing is selectable,
751 only one thing is selectable, and any number valid items
752 may selected. If how is PICK_NONE, this function should
753 never return anything but 0 or -1.
754 -- You may call select_menu() on a window multiple times --
755 the menu is saved until start_menu() or destroy_nhwindow()
756 is called on the window.
757 -- Note that NHW_MENU windows need not have select_menu()
758 called for them. There is no way of knowing whether
759 select_menu() will be called for the window at
760 create_nhwindow() time.
763 curses_select_menu(winid wid
, int how
, MENU_ITEM_P
** selected
)
768 return curses_display_nhmenu(wid
, how
, selected
);
772 curses_update_inventory(int arg
)
774 /* Don't do anything if perm_invent is off unless it was on and
775 player just changed the option. */
776 if (!iflags
.perm_invent
) {
777 if (curses_get_nhwin(INV_WIN
)) {
778 curs_reset_windows(TRUE
, FALSE
);
779 curs_purge_perminv_data(FALSE
);
784 /* skip inventory updating during character initialization */
785 if (!program_state
.in_moveloop
&& !program_state
.gameover
)
789 /* if perm_invent is just being toggled on, we need to run the
790 update twice; the first time creates the window and organizes
791 the screen to fit it in, the second time populates it;
792 needed if we're called from docrt() because the "organizes
793 the screen" part calls docrt() and that skips recursive calls */
794 boolean no_inv_win_yet
= !curses_get_nhwin(INV_WIN
);
796 /* Update inventory sidebar. NetHack uses normal menu functions
797 when gathering the inventory, and we don't want to change the
798 underlying code. So instead, track if an inventory update is
799 being performed with a static variable. */
806 /* perform scrolling operations on persistent inventory window */
807 curs_update_invt(arg
);
812 curses_ctrl_nhwindow(
815 win_request_info
*wri
)
820 return (win_request_info
*) 0;
824 case request_settings
:
826 case set_menu_promptstyle
:
827 curses_menu_promptstyle
.color
= wri
->fromcore
.menu_promptstyle
.color
;
828 if (curses_menu_promptstyle
.color
== NO_COLOR
)
829 curses_menu_promptstyle
.color
= NONE
;
830 attr
= wri
->fromcore
.menu_promptstyle
.attr
;
831 curses_menu_promptstyle
.attr
= curses_convert_attr(attr
);;
840 mark_synch() -- Don't go beyond this point in I/O on any channel until
841 all channels are caught up to here.
844 curses_mark_synch(void)
846 /* full refresh has unintended side-effect of making a menu window
847 that has called core's get_count() to vanish; do a basic screen
849 /*curses_refresh_nethack_windows();*/
854 wait_synch() -- Wait until all pending output is complete (*flush*() for
856 -- May also deal with exposure events etc. so that the
857 display is OK when return from wait_synch().
860 curses_wait_synch(void)
862 if (iflags
.raw_printed
) {
866 * If any message has been issued via raw_print(), make the user
867 * acknowledge it. This might take place before initscr() so
868 * access to curses is limited. [Despite that, there's probably
869 * a more curses-specific way to handle this. FIXME?]
872 (void) fprintf(stdout
, "\nPress <return> to continue: ");
873 (void) fflush(stdout
);
876 } while (chr
> 0 && chr
!= C('j') && chr
!= C('m') && chr
!= '\033');
878 iflags
.raw_printed
= 0;
881 if (iflags
.window_inited
) {
882 if (curses_got_output())
883 (void) curses_more();
886 /* [do we need 'if (counting) curses_count_window((char *)0);' here?] */
890 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
891 screen if the playing area is larger than the screen.
892 -- This function is only defined if CLIPPING is defined.
895 curses_cliparound(int x
, int y
)
898 boolean redraw
= curses_map_borders(&sx
, &sy
, &ex
, &ey
, x
, y
);
901 curses_draw_map(sx
, sy
, ex
, ey
);
906 print_glyph(window, x, y, glyphinfo, bkglyphinfo)
907 -- Print glyph at (x,y) on the given window. Glyphs are
908 integers within the glyph_info struct that is passed
909 at the interface, mapped to whatever the window-
910 port wants (symbol, font, color, attributes, ...there's
911 a 1-1 map between glyphs and distinct things on the map).
912 bkglyphinfo is to render the background behind the glyph.
914 -- bkglyphinfo contains a background glyph for potential use
915 by some graphical or tiled environments to allow the
916 depiction to fall against a background consistent with
917 the grid around x,y. If bkglyphinfo->glyph is NO_GLYPH,
918 then the parameter should be ignored (do nothing with it).
919 -- glyph_info struct fields:
920 int glyph; the display entity
921 int color; color for window ports not using a tile
922 int ttychar; the character mapping for the original tty
923 interface. Most or all window ports wanted
924 and used this for various things so it is
926 short int symidx; offset into syms array
927 unsigned glyphflags; more detail about the entity
934 coordxy x
, coordxy y
,
935 const glyph_info
*glyphinfo
,
936 const glyph_info
*bkglyphinfo
)
942 unsigned int special
;
945 glyph
= glyphinfo
->glyph
;
946 special
= glyphinfo
->gm
.glyphflags
;
947 ch
= glyphinfo
->ttychar
;
948 color
= glyphinfo
->gm
.sym
.color
;
949 /* Extra color handling
950 * FIQ: The curses library does not support truecolor, only the more limited 256
951 * color mode. On top of this, the windowport only supports 16 color mode.
952 * Thus, we only allow users to customize glyph colors to the basic NetHack
954 if (glyphinfo
->gm
.customcolor
!= 0
955 && (curses_procs
.wincap2
& WC2_EXTRACOLORS
) != 0) {
956 if ((glyphinfo
->gm
.customcolor
& NH_BASIC_COLOR
) != 0) {
957 color
= COLORVAL(glyphinfo
->gm
.customcolor
);
960 /* 24-bit color, NH_BASIC_COLOR == 0 */
961 nhcolor
= COLORVAL(glyphinfo
->gm
.customcolor
);
965 if ((special
& MG_PET
) && iflags
.hilite_pet
) {
966 attr
= curses_convert_attr(iflags
.wc2_petattr
);
968 if ((special
& MG_DETECT
) && iflags
.use_inverse
) {
971 if (SYMHANDLING(H_DEC
))
972 ch
= curses_convert_glyph(ch
, glyph
);
974 if (wid
== NHW_MAP
) {
975 /* hilite stairs not in 3.6, yet
976 if ((special & MG_STAIRS) && iflags.hilite_hidden_stairs) {
977 color = 16 + (color * 2);
980 if ((special
& MG_OBJPILE
) && iflags
.hilite_pile
) {
982 color
= get_framecolor(color
, CLR_BLUE
);
983 else /* if (iflags.use_inverse) */
986 /* water and lava look the same except for color; when color is off
987 (checked by core), render lava in inverse video so that it looks
988 different from water; similar for floor vs ice, fountain vs sink,
989 and corridor vs engranving-in-corridor */
990 if ((special
& (MG_BW_LAVA
| MG_BW_ICE
| MG_BW_SINK
| MG_BW_ENGR
))
991 != 0 && iflags
.use_inverse
) {
992 /* reset_glyphmap() only sets MG_BW_foo if color is off */
995 /* highlight female monsters (wizard mode option) */
996 if ((special
& MG_FEMALE
) && wizard
&& iflags
.wizmgender
) {
1001 curses_putch(wid
, x
, y
, ch
,
1002 #ifdef ENHANCED_SYMBOLS
1003 (SYMHANDLING(H_UTF8
)
1004 && glyphinfo
->gm
.u
&& glyphinfo
->gm
.u
->utf8str
)
1005 ? glyphinfo
->gm
.u
: NULL
,
1007 (nhcolor
!= 0) ? nhcolor
: color
,
1008 bkglyphinfo
->framecolor
, attr
);
1013 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1014 the user sees str. raw_print() appends a newline to str.
1015 It need not recognize ASCII control characters. This is
1016 used during startup (before windowing system initialization
1017 -- maybe this means only error startup messages are raw),
1018 for error messages, and maybe other "msg" uses. E.g.
1019 updating status for micros (i.e, "saving").
1022 curses_raw_print(const char *str
)
1025 /* WINDOW *win = curses_get_nhwin(MESSAGE_WIN); */
1027 if (iflags
.window_inited
) {
1028 curses_message_win_puts(str
, FALSE
);
1033 iflags
.raw_printed
++;
1038 -- Like raw_print(), but prints in bold/standout (if possible).
1041 curses_raw_print_bold(const char *str
)
1043 curses_raw_print(str
);
1047 int nhgetch() -- Returns a single character input from the user.
1048 -- In the tty window-port, nhgetch() assumes that tgetch()
1049 will be the routine the OS provides to read a character.
1050 Returned character _must_ be non-zero.
1053 curses_nhgetch(void)
1057 /* curses_prehousekeeping() assumes that the map window is active;
1058 avoid it when a menu is active */
1060 curses_prehousekeeping();
1062 ch
= curses_read_char();
1065 curses_posthousekeeping();
1071 int nh_poskey(coordxy *x, coordxy *y, int *mod)
1072 -- Returns a single character input from the user or a
1073 a positioning event (perhaps from a mouse). If the
1074 return value is non-zero, a character was typed, else,
1075 a position in the MAP window is returned in x, y and mod.
1078 CLICK_1 -- mouse click type 1
1079 CLICK_2 -- mouse click type 2
1081 The different click types can map to whatever the
1082 hardware supports. If no mouse is supported, this
1083 routine always returns a non-zero character.
1086 curses_nh_poskey(coordxy
*x
, coordxy
*y
, int *mod
)
1088 int key
= curses_nhgetch();
1090 #ifdef NCURSES_MOUSE_VERSION
1091 /* Mouse event if mouse_support is true */
1092 if (key
== KEY_MOUSE
) {
1093 key
= curses_get_mouse(x
, y
, mod
);
1105 nhbell() -- Beep at user. [This will exist at least until sounds are
1106 redone, since sounds aren't attributable to windows anyway.]
1117 -- Display previous messages. Used by the ^P command.
1118 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1121 curses_doprev_message(void)
1128 char yn_function(const char *ques, const char *choices, char default)
1129 -- Print a prompt made up of ques, choices and default.
1130 Read a single character response that is contained in
1131 choices or default. If choices is NULL, all possible
1132 inputs are accepted and returned. This overrides
1133 everything else. The choices are expected to be in
1134 lower case. Entering ESC always maps to 'q', or 'n',
1135 in that order, if present in choices, otherwise it maps
1136 to default. Entering any other quit character (SPACE,
1137 RETURN, NEWLINE) maps to default.
1138 -- If the choices string contains ESC, then anything after
1139 it is an acceptable response, but the ESC and whatever
1140 follows is not included in the prompt.
1141 -- If the choices string contains a '#' then accept a count.
1142 Place this value in the global "yn_number" and return '#'.
1143 -- This uses the top line in the tty window-port, other
1144 ports might use a popup.
1147 curses_yn_function(const char *question
, const char *choices
, char def
)
1149 return (char) curses_character_input_dialog(question
, choices
, def
);
1153 getlin(const char *ques, char *input)
1154 -- Prints ques as a prompt and reads a single line of text,
1155 up to a newline. The string entered is returned without the
1156 newline. ESC is used to cancel, in which case the string
1157 "\033\000" is returned.
1158 -- getlin() must call flush_screen(1) before doing anything.
1159 -- This uses the top line in the tty window-port, other
1160 ports might use a popup.
1163 curses_getlin(const char *question
, char *input
)
1165 curses_line_input_dialog(question
, input
, BUFSZ
);
1169 int get_ext_cmd(void)
1170 -- Get an extended command in a window-port specific way.
1171 An index into extcmdlist[] is returned on a successful
1172 selection, -1 otherwise.
1175 curses_get_ext_cmd(void)
1177 return curses_ext_cmd();
1183 -- Initialize the number pad to the given state.
1186 curses_number_pad(int state UNUSED
)
1192 delay_output() -- Causes a visible delay of 50ms in the output.
1193 Conceptually, this is similar to wait_synch() followed
1194 by a nap(50ms), but allows asynchronous operation.
1197 curses_delay_output(void)
1200 if (flags
.nap
&& !iflags
.debug_fuzzer
) {
1201 /* refreshing the whole display is a waste of time,
1202 * but that's why we're here */
1203 curses_update_stdscr_cursor();
1211 start_screen() -- Only used on Unix tty ports, but must be declared for
1212 completeness. Sets up the tty to work in full-screen
1213 graphics mode. Look at win/tty/termcap.c for an
1214 example. If your window-port does not need this function
1215 just declare an empty function.
1218 curses_start_screen(void)
1223 end_screen() -- Only used on Unix tty ports, but must be declared for
1224 completeness. The complement of start_screen().
1227 curses_end_screen(void)
1233 -- The tombstone code. We use genl_outrip() from rip.c
1234 instead of rolling our own.
1237 curses_outrip(winid wid UNUSED
,
1245 preference_update(preference)
1246 -- The player has just changed one of the wincap preference
1247 settings, and the NetHack core is notifying your window
1248 port of that change. If your window-port is capable of
1249 dynamically adjusting to the change then it should do so.
1250 Your window-port will only be notified of a particular
1251 change if it indicated that it wants to be by setting the
1252 corresponding bit in the wincap mask.
1255 curses_preference_update(const char *pref
)
1257 boolean redo_main
= FALSE
, redo_status
= FALSE
;
1259 if (!strcmp(pref
, "align_status")
1260 || !strcmp(pref
, "statuslines")
1261 || !strcmp(pref
, "windowborders"))
1262 redo_main
= redo_status
= TRUE
;
1263 else if (!strcmp(pref
, "hilite_status"))
1265 else if (!strcmp(pref
, "align_message"))
1267 else if (!strcmp(pref
, "mouse_support"))
1268 curses_mouse_support(iflags
.wc_mouse_support
);
1270 if (redo_main
|| redo_status
)
1271 curs_reset_windows(redo_main
, redo_status
);
1275 curs_reset_windows(boolean redo_main
, boolean redo_status
)
1277 boolean need_redraw
= FALSE
;
1280 status_initialize(REASSESS_ONLY
);
1284 curses_create_main_windows();
1288 curses_last_messages();
1293 /* stubs for curses_procs{} */
1297 dummy_update_position_bar(char *arg UNUSED
)
1305 curses_change_color(int color
, long rgb
, int reverse UNUSED
)
1309 if (!can_change_color())
1312 r
= (rgb
>> 16) & 0xFF;
1313 g
= (rgb
>> 8) & 0xFF;
1315 init_color(color
% 16, r
* 4, g
* 4, b
* 4);
1319 curses_get_color_string(void)