diff --git a/include/extern.h b/include/extern.h index 1edaf34f1..6076f585d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3119,6 +3119,7 @@ extern int hide_privileges(boolean); #ifdef ENHANCED_SYMBOLS extern int glyphrep(const char *); extern char *mixed_to_utf8(char *buf, size_t bufsz, const char *str, int *); +extern const char *mixed_to_glyphinfo(const char *str, glyph_info *gip); extern int match_glyph(char *); extern void dump_all_glyphids(FILE *fp); extern void fill_glyphid_cache(void); diff --git a/include/wincurs.h b/include/wincurs.h index 07e6083d2..e18863b36 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -79,6 +79,7 @@ extern void curses_display_nhwindow(winid wid, boolean block); extern void curses_destroy_nhwindow(winid wid); extern void curses_curs(winid wid, int x, int y); extern void curses_putstr(winid wid, int attr, const char *text); +extern void curses_putmixed(winid window, int attr, const char *str); extern void curses_display_file(const char *filename, boolean must_exist); extern void curses_start_menu(winid wid, unsigned long); extern void curses_add_menu(winid wid, const glyph_info *, diff --git a/src/utf8map.c b/src/utf8map.c index 136ba4c78..a3424d812 100644 --- a/src/utf8map.c +++ b/src/utf8map.c @@ -542,6 +542,33 @@ mixed_to_utf8(char *buf, size_t bufsz, const char *str, int *retflags) return buf; } +/* + * helper routine if a window port wants to extract the unicode + * representation from a glyph representation in the string; + * the returned string is the remainder of the string after + * extracting the \GNNNNNNNN information. + */ +const char * +mixed_to_glyphinfo(const char *str, glyph_info *gip) +{ + int dcount, ggv; + + if (!str || !gip) + return " "; + + *gip = nul_glyphinfo; + if (*str == '\\' && *(str + 1) == 'G') { + if ((dcount = decode_glyph(str + 2, &ggv))) { + map_glyphinfo(0, 0, ggv, 0, gip); + /* 'str' is ready for the next loop iteration and + '*str' should not be copied at the end of this + iteration */ + str += (dcount + 2); + } + } + return str; +} + void dump_all_glyphids(FILE *fp) { diff --git a/sys/unix/hints/include/multiw-2.370 b/sys/unix/hints/include/multiw-2.370 index 2218207f5..a032300eb 100644 --- a/sys/unix/hints/include/multiw-2.370 +++ b/sys/unix/hints/include/multiw-2.370 @@ -90,7 +90,7 @@ WINCFLAGS += -DNOTTYGRAPHICS endif ifdef WANT_WIN_CURSES -WINCFLAGS += -DCURSES_GRAPHICS +WINCFLAGS += -DCURSES_GRAPHICS -D_XOPEN_SOURCE_EXTENDED=1 WINSRC += $(WINCURSESSRC) WINOBJ0 += $(WINCURSESOBJ) endif diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index ba76ecf4e..d82f464f3 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -22,6 +22,8 @@ extern char erase_char, kill_char; extern long curs_mesg_suppress_seq; /* from cursmesg.c */ extern boolean curs_mesg_no_suppress; /* ditto */ +extern int mesg_mixed; +extern glyph_info mesg_gi; /* stubs for curses_procs{} */ #ifdef POSITIONBAR @@ -70,7 +72,7 @@ struct window_procs curses_procs = { curses_destroy_nhwindow, curses_curs, curses_putstr, - genl_putmixed, + curses_putmixed, curses_display_file, curses_start_menu, curses_add_menu, @@ -561,6 +563,19 @@ curses_putstr(winid wid, int attr, const char *text) curs_mesg_no_suppress = FALSE; } +void +curses_putmixed(winid window, int attr, const char *str) +{ + if (window == WIN_MESSAGE) { + str = mixed_to_glyphinfo(str, &mesg_gi); + mesg_mixed = 1; + } + /* now send it to the normal putstr */ + curses_putstr(window, attr, str); + if (window == WIN_MESSAGE) + mesg_mixed = 0; +} + /* Display the file named str. Complain about missing files iff complain is TRUE. */ diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index ebcf9e6b1..ff755d3a7 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -26,10 +26,13 @@ long curs_mesg_suppress_seq = -1L; message triggers More>> for the previous message and the player responds with ESC; we need to avoid initiating suppression in that situation */ boolean curs_mesg_no_suppress = FALSE; +/* curses_putmixed() will place information in these next two */ +int mesg_mixed = 0; +glyph_info mesg_gi; /* Message window routines for curses interface */ -/* Private declatations */ +/* Private declarations */ typedef struct nhpm { char *str; /* Message text */ @@ -43,6 +46,7 @@ static void unscroll_window(winid wid); static void directional_scroll(winid wid, int nlines); static void mesg_add_line(const char *mline); static nhprev_mesg *get_msg_line(boolean reverse, int mindex); +static int curscolor(int nhcolor, boolean *boldon); static int turn_lines = 0; static int mx = 0; @@ -61,8 +65,10 @@ curses_message_win_puts(const char *message, boolean recursed) int height, width, border_space, linespace; char *tmpstr; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); - boolean bold, border = curses_window_has_border(MESSAGE_WIN); + boolean bold, border = curses_window_has_border(MESSAGE_WIN), + have_mixed_leadin = FALSE, adjustbold = FALSE; int message_length = (int) strlen(message); + cchar_t mixed_leadin_cchar[2]; #if 0 /* @@ -110,6 +116,36 @@ curses_message_win_puts(const char *message, boolean recursed) /* -2: for leading " " (if combining this message with preceding one) */ if (mx > border_space) linespace -= 2; + bold = (height > 1 && !last_messages); + + if (mesg_mixed) { + wchar_t w[2]; + int leadin_color; + + leadin_color = curscolor(mesg_gi.gm.sym.color, &adjustbold); + /* + * curses_putmixed() skipped past the \GNNNNNNNN encoding + * in the string, and filled in the mesg_gi glyphinfo. It + * flagged that to us by setting mesg_mixed. + */ + + w[0] = (wchar_t) mesg_gi.ttychar; +#ifdef ENHANCED_SYMBOLS + if ((windowprocs.wincap2 & WC2_U_UTF8STR) && SYMHANDLING(H_UTF8) + && mesg_gi.gm.u) { + /* FIXME: this won't work with all unicode values (32 bits -> 16 + * bits on Windows) */ + w[0] = (wchar_t) mesg_gi.gm.u->utf32ch; + } +#endif + w[1] = L'\0'; + if (setcchar(mixed_leadin_cchar, w, + (bold || adjustbold) ? A_BOLD : A_NORMAL, + leadin_color, 0) == OK) { + have_mixed_leadin = TRUE; + message_length++; /* account for that additional column */ + } + } if (linespace < message_length) { if (my - border_space >= height - 1) { @@ -143,35 +179,76 @@ curses_message_win_puts(const char *message, boolean recursed) } } - bold = (height > 1 && !last_messages); - if (bold) + if (bold || adjustbold) curses_toggle_color_attr(win, NONE, A_BOLD, ON); /* will this message fit as-is or do we need to split it? */ if (mx == border_space && message_length > width - 3) { /* split needed */ tmpstr = curses_break_str(message, (width - 3), 1); + if (have_mixed_leadin) { + mvwadd_wch(win, my, mx, mixed_leadin_cchar); + ++mx; + message_length--; + have_mixed_leadin = FALSE; + mesg_mixed = 0; + } mvwprintw(win, my, mx, "%s", tmpstr), mx += (int) strlen(tmpstr); /* one space to separate first part of message from rest [is this actually useful?] */ if (mx < width) ++mx; free(tmpstr); - if (bold) + if (bold || adjustbold) curses_toggle_color_attr(win, NONE, A_BOLD, OFF); tmpstr = curses_str_remainder(message, (width - 3), 1); curses_message_win_puts(tmpstr, TRUE); free(tmpstr); } else { + if (have_mixed_leadin) { + mvwadd_wch(win, my, mx, mixed_leadin_cchar); + ++mx; + message_length--; + have_mixed_leadin = FALSE; + mesg_mixed = 0; + } mvwprintw(win, my, mx, "%s", message), mx += message_length; - if (bold) + if (bold || adjustbold) curses_toggle_color_attr(win, NONE, A_BOLD, OFF); } wrefresh(win); } -void -curses_got_input(void) + +static int +curscolor(int nhcolor, boolean *boldon) +{ + int curses_color; + + *boldon = FALSE; + if (nhcolor == 0) { /* make black fg visible */ +#ifdef USE_DARKGRAY + if (iflags.wc2_darkgray) { + if (COLORS > 16) { + /* colorpair for black is already darkgray */ + } else { /* Use bold for a bright black */ + *boldon = TRUE; + } + } else +#endif /* USE_DARKGRAY */ + nhcolor = CLR_BLUE; + } + curses_color = nhcolor + 1; + if (COLORS < 16) { + if (curses_color > 8 && curses_color < 17) + curses_color -= 8; + else if (curses_color > (17 + 16)) + curses_color -= 16; + } + return curses_color; +} + +void curses_got_input(void) { /* if messages are being suppressed, reenable them */ curs_mesg_suppress_seq = -1L;