This makes use of cchar_t instead of chtype when using ncursesw, which allows to store a wide char as well as the WACS values.
This also allows to complete the printable glyphs list beyond ascii and the ACS values. Signed-off-by: Samuel Thibault <samuel.thiba...@ens-lyon.org> --- configure | 5 +- hw/display/vga.c | 4 +- include/ui/console.h | 16 ++- ui/curses.c | 321 ++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 294 insertions(+), 52 deletions(-) diff --git a/configure b/configure index 29649d9..ebe0599 100755 --- a/configure +++ b/configure @@ -2901,14 +2901,17 @@ if test "$curses" != "no" ; then #include <locale.h> #include <curses.h> #include <wchar.h> +#include <langinfo.h> int main(void) { const char *s = curses_version(); + const char *codeset; wchar_t wch = L'w'; setlocale(LC_ALL, ""); resize_term(0, 0); addwstr(L"wide chars\n"); addnwstr(&wch, 1); - return s != 0; + codeset = nl_langinfo(CODESET); + return s != 0 && codeset != 0; } EOF IFS=: diff --git a/hw/display/vga.c b/hw/display/vga.c index 2a88b3c..ce225c9 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1966,7 +1966,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; src ++, dst ++, i ++) { console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); - if (*dst != val) { + if (memcmp(dst, &val, sizeof(val))) { *dst = val; c_max = i; break; @@ -1975,7 +1975,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) c_min = i; for (; i < size; src ++, dst ++, i ++) { console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src))); - if (*dst != val) { + if (memcmp(dst, &val, sizeof(val))) { *dst = val; c_max = i; } diff --git a/include/ui/console.h b/include/ui/console.h index d9c13d2..94e3133 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -338,8 +338,8 @@ static inline pixman_format_code_t surface_format(DisplaySurface *s) #ifdef CONFIG_CURSES #include <curses.h> -typedef chtype console_ch_t; -extern chtype vga_to_curses[]; +typedef cchar_t console_ch_t; +extern console_ch_t vga_to_curses[]; #else typedef unsigned long console_ch_t; #endif @@ -347,16 +347,20 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) { uint8_t c = ch; #ifdef CONFIG_CURSES - if (vga_to_curses[c]) { - ch &= ~(console_ch_t)0xff; - ch |= vga_to_curses[c]; + if (vga_to_curses[c].chars[0]) { + *dest = vga_to_curses[c]; + } else { + dest->chars[0] = c; + dest->chars[1] = 0; + dest->attr = 0; } + dest->attr |= ch & ~0xff; #else if (c == '\0') { ch |= ' '; } -#endif *dest = ch; +#endif } typedef struct GraphicHwOps { diff --git a/ui/curses.c b/ui/curses.c index 3599295..cd8ed5f 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -28,6 +28,9 @@ #include <sys/ioctl.h> #include <termios.h> #endif +#include <locale.h> +#include <wchar.h> +#include <langinfo.h> #include "qemu-common.h" #include "ui/console.h" @@ -43,16 +46,17 @@ static WINDOW *screenpad = NULL; static int width, height, gwidth, gheight, invalidate; static int px, py, sminx, sminy, smaxx, smaxy; -chtype vga_to_curses[256]; +console_ch_t vga_to_curses[256]; static void curses_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { - chtype *line; + console_ch_t *line; - line = ((chtype *) screen) + y * width; - for (h += y; y < h; y ++, line += width) - mvwaddchnstr(screenpad, y, 0, line, width); + line = ((console_ch_t *) screen) + y * width; + for (h += y; y < h; y ++, line += width) { + mvwadd_wchnstr(screenpad, y, 0, line, width); + } pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); refresh(); @@ -358,45 +362,275 @@ static void curses_setup(void) /* * Setup mapping for vga to curses line graphics. - * FIXME: for better font, have to use ncursesw and setlocale() */ -#if 0 - /* FIXME: map from where? */ - ACS_S1; - ACS_S3; - ACS_S7; - ACS_S9; -#endif - /* ACS_* is not constant. So, we can't initialize statically. */ - vga_to_curses['\0'] = ' '; - vga_to_curses[0x04] = ACS_DIAMOND; - vga_to_curses[0x18] = ACS_UARROW; - vga_to_curses[0x19] = ACS_DARROW; - vga_to_curses[0x1a] = ACS_RARROW; - vga_to_curses[0x1b] = ACS_LARROW; - vga_to_curses[0x9c] = ACS_STERLING; - vga_to_curses[0xb0] = ACS_BOARD; - vga_to_curses[0xb1] = ACS_CKBOARD; - vga_to_curses[0xb3] = ACS_VLINE; - vga_to_curses[0xb4] = ACS_RTEE; - vga_to_curses[0xbf] = ACS_URCORNER; - vga_to_curses[0xc0] = ACS_LLCORNER; - vga_to_curses[0xc1] = ACS_BTEE; - vga_to_curses[0xc2] = ACS_TTEE; - vga_to_curses[0xc3] = ACS_LTEE; - vga_to_curses[0xc4] = ACS_HLINE; - vga_to_curses[0xc5] = ACS_PLUS; - vga_to_curses[0xce] = ACS_LANTERN; - vga_to_curses[0xd8] = ACS_NEQUAL; - vga_to_curses[0xd9] = ACS_LRCORNER; - vga_to_curses[0xda] = ACS_ULCORNER; - vga_to_curses[0xdb] = ACS_BLOCK; - vga_to_curses[0xe3] = ACS_PI; - vga_to_curses[0xf1] = ACS_PLMINUS; - vga_to_curses[0xf2] = ACS_GEQUAL; - vga_to_curses[0xf3] = ACS_LEQUAL; - vga_to_curses[0xf8] = ACS_DEGREE; - vga_to_curses[0xfe] = ACS_BULLET; + + vga_to_curses['\0'].chars[0] = L' '; + vga_to_curses[0x01].chars[0] = L'\u263a'; + vga_to_curses[0x02].chars[0] = L'\u263b'; + vga_to_curses[0x03].chars[0] = L'\u2665'; + vga_to_curses[0x04].chars[0] = L'\u2666'; + vga_to_curses[0x05].chars[0] = L'\u2663'; + vga_to_curses[0x06].chars[0] = L'\u2660'; + vga_to_curses[0x07].chars[0] = L'\u2022'; + vga_to_curses[0x08].chars[0] = L'\u25d8'; + vga_to_curses[0x09].chars[0] = L'\u25cb'; + vga_to_curses[0x0a].chars[0] = L'\u25d9'; + vga_to_curses[0x0b].chars[0] = L'\u2642'; + vga_to_curses[0x0c].chars[0] = L'\u2640'; + vga_to_curses[0x0d].chars[0] = L'\u266a'; + vga_to_curses[0x0e].chars[0] = L'\u266b'; + vga_to_curses[0x0f].chars[0] = L'\u263c'; + vga_to_curses[0x10].chars[0] = L'\u25ba'; + vga_to_curses[0x11].chars[0] = L'\u25c4'; + vga_to_curses[0x12].chars[0] = L'\u2195'; + vga_to_curses[0x13].chars[0] = L'\u203c'; + vga_to_curses[0x14].chars[0] = L'\u00b6'; + vga_to_curses[0x15].chars[0] = L'\u00a7'; + vga_to_curses[0x16].chars[0] = L'\u25ac'; + vga_to_curses[0x17].chars[0] = L'\u21a8'; + vga_to_curses[0x18].chars[0] = L'\u2191'; + vga_to_curses[0x19].chars[0] = L'\u2193'; + vga_to_curses[0x1a].chars[0] = L'\u2192'; + vga_to_curses[0x1b].chars[0] = L'\u2190'; + vga_to_curses[0x1c].chars[0] = L'\u221f'; + vga_to_curses[0x1d].chars[0] = L'\u2194'; + vga_to_curses[0x1e].chars[0] = L'\u25b2'; + vga_to_curses[0x1f].chars[0] = L'\u25bc'; + + { + /* Hardcode CP437 to unicode */ + vga_to_curses[0x80].chars[0] = L'\u00C7'; + vga_to_curses[0x81].chars[0] = L'\u00FC'; + vga_to_curses[0x82].chars[0] = L'\u00E9'; + vga_to_curses[0x83].chars[0] = L'\u00E2'; + vga_to_curses[0x84].chars[0] = L'\u00E4'; + vga_to_curses[0x85].chars[0] = L'\u00E0'; + vga_to_curses[0x86].chars[0] = L'\u00E5'; + vga_to_curses[0x87].chars[0] = L'\u00E7'; + vga_to_curses[0x88].chars[0] = L'\u00EA'; + vga_to_curses[0x89].chars[0] = L'\u00EB'; + vga_to_curses[0x8a].chars[0] = L'\u00E8'; + vga_to_curses[0x8b].chars[0] = L'\u00EF'; + vga_to_curses[0x8c].chars[0] = L'\u00EE'; + vga_to_curses[0x8d].chars[0] = L'\u00EC'; + vga_to_curses[0x8e].chars[0] = L'\u00C4'; + vga_to_curses[0x8f].chars[0] = L'\u00C5'; + vga_to_curses[0x90].chars[0] = L'\u00C9'; + vga_to_curses[0x91].chars[0] = L'\u00E6'; + vga_to_curses[0x92].chars[0] = L'\u00C6'; + vga_to_curses[0x93].chars[0] = L'\u00F4'; + vga_to_curses[0x94].chars[0] = L'\u00F6'; + vga_to_curses[0x95].chars[0] = L'\u00F2'; + vga_to_curses[0x96].chars[0] = L'\u00FB'; + vga_to_curses[0x97].chars[0] = L'\u00F9'; + vga_to_curses[0x98].chars[0] = L'\u00FF'; + vga_to_curses[0x99].chars[0] = L'\u00D6'; + vga_to_curses[0x9a].chars[0] = L'\u00DC'; + vga_to_curses[0x9b].chars[0] = L'\u00A2'; + vga_to_curses[0x9c].chars[0] = L'\u00A3'; + vga_to_curses[0x9d].chars[0] = L'\u00A5'; + vga_to_curses[0x9e].chars[0] = L'\u20A7'; + vga_to_curses[0x9f].chars[0] = L'\u0192'; + vga_to_curses[0xa0].chars[0] = L'\u00E1'; + vga_to_curses[0xa1].chars[0] = L'\u00ED'; + vga_to_curses[0xa2].chars[0] = L'\u00F3'; + vga_to_curses[0xa3].chars[0] = L'\u00FA'; + vga_to_curses[0xa4].chars[0] = L'\u00F1'; + vga_to_curses[0xa5].chars[0] = L'\u00D1'; + vga_to_curses[0xa6].chars[0] = L'\u00AA'; + vga_to_curses[0xa7].chars[0] = L'\u00BA'; + vga_to_curses[0xa8].chars[0] = L'\u00BF'; + vga_to_curses[0xa9].chars[0] = L'\u2310'; + vga_to_curses[0xaa].chars[0] = L'\u00AC'; + vga_to_curses[0xab].chars[0] = L'\u00BD'; + vga_to_curses[0xac].chars[0] = L'\u00BC'; + vga_to_curses[0xad].chars[0] = L'\u00A1'; + vga_to_curses[0xae].chars[0] = L'\u00AB'; + vga_to_curses[0xaf].chars[0] = L'\u00BB'; + vga_to_curses[0xb0].chars[0] = L'\u2591'; + vga_to_curses[0xb1].chars[0] = L'\u2592'; + vga_to_curses[0xb2].chars[0] = L'\u2593'; + vga_to_curses[0xb3].chars[0] = L'\u2502'; + vga_to_curses[0xb4].chars[0] = L'\u2524'; + vga_to_curses[0xb5].chars[0] = L'\u2561'; + vga_to_curses[0xb6].chars[0] = L'\u2562'; + vga_to_curses[0xb7].chars[0] = L'\u2556'; + vga_to_curses[0xb8].chars[0] = L'\u2555'; + vga_to_curses[0xb9].chars[0] = L'\u2563'; + vga_to_curses[0xba].chars[0] = L'\u2551'; + vga_to_curses[0xbb].chars[0] = L'\u2557'; + vga_to_curses[0xbc].chars[0] = L'\u255D'; + vga_to_curses[0xbd].chars[0] = L'\u255C'; + vga_to_curses[0xbe].chars[0] = L'\u255B'; + vga_to_curses[0xbf].chars[0] = L'\u2510'; + vga_to_curses[0xc0].chars[0] = L'\u2514'; + vga_to_curses[0xc1].chars[0] = L'\u2534'; + vga_to_curses[0xc2].chars[0] = L'\u252C'; + vga_to_curses[0xc3].chars[0] = L'\u251C'; + vga_to_curses[0xc4].chars[0] = L'\u2500'; + vga_to_curses[0xc5].chars[0] = L'\u253C'; + vga_to_curses[0xc6].chars[0] = L'\u255E'; + vga_to_curses[0xc7].chars[0] = L'\u255F'; + vga_to_curses[0xc8].chars[0] = L'\u255A'; + vga_to_curses[0xc9].chars[0] = L'\u2554'; + vga_to_curses[0xca].chars[0] = L'\u2569'; + vga_to_curses[0xcb].chars[0] = L'\u2566'; + vga_to_curses[0xcc].chars[0] = L'\u2560'; + vga_to_curses[0xcd].chars[0] = L'\u2550'; + vga_to_curses[0xce].chars[0] = L'\u256C'; + vga_to_curses[0xcf].chars[0] = L'\u2567'; + vga_to_curses[0xd0].chars[0] = L'\u2568'; + vga_to_curses[0xd1].chars[0] = L'\u2564'; + vga_to_curses[0xd2].chars[0] = L'\u2565'; + vga_to_curses[0xd3].chars[0] = L'\u2559'; + vga_to_curses[0xd4].chars[0] = L'\u2558'; + vga_to_curses[0xd5].chars[0] = L'\u2552'; + vga_to_curses[0xd6].chars[0] = L'\u2553'; + vga_to_curses[0xd7].chars[0] = L'\u256B'; + vga_to_curses[0xd8].chars[0] = L'\u256A'; + vga_to_curses[0xd9].chars[0] = L'\u2518'; + vga_to_curses[0xda].chars[0] = L'\u250C'; + vga_to_curses[0xdb].chars[0] = L'\u2588'; + vga_to_curses[0xdc].chars[0] = L'\u2584'; + vga_to_curses[0xdd].chars[0] = L'\u258C'; + vga_to_curses[0xde].chars[0] = L'\u2590'; + vga_to_curses[0xdf].chars[0] = L'\u2580'; + vga_to_curses[0xe0].chars[0] = L'\u03B1'; + vga_to_curses[0xe1].chars[0] = L'\u00DF'; + vga_to_curses[0xe2].chars[0] = L'\u0393'; + vga_to_curses[0xe3].chars[0] = L'\u03C0'; + vga_to_curses[0xe4].chars[0] = L'\u03A3'; + vga_to_curses[0xe5].chars[0] = L'\u03C3'; + vga_to_curses[0xe6].chars[0] = L'\u00B5'; + vga_to_curses[0xe7].chars[0] = L'\u03C4'; + vga_to_curses[0xe8].chars[0] = L'\u03A6'; + vga_to_curses[0xe9].chars[0] = L'\u0398'; + vga_to_curses[0xea].chars[0] = L'\u03A9'; + vga_to_curses[0xeb].chars[0] = L'\u03B4'; + vga_to_curses[0xec].chars[0] = L'\u221E'; + vga_to_curses[0xed].chars[0] = L'\u03C6'; + vga_to_curses[0xee].chars[0] = L'\u03B5'; + vga_to_curses[0xef].chars[0] = L'\u2229'; + vga_to_curses[0xf0].chars[0] = L'\u2261'; + vga_to_curses[0xf1].chars[0] = L'\u00B1'; + vga_to_curses[0xf2].chars[0] = L'\u2265'; + vga_to_curses[0xf3].chars[0] = L'\u2264'; + vga_to_curses[0xf4].chars[0] = L'\u2320'; + vga_to_curses[0xf5].chars[0] = L'\u2321'; + vga_to_curses[0xf6].chars[0] = L'\u00F7'; + vga_to_curses[0xf7].chars[0] = L'\u2248'; + vga_to_curses[0xf8].chars[0] = L'\u00B0'; + vga_to_curses[0xf9].chars[0] = L'\u2219'; + vga_to_curses[0xfa].chars[0] = L'\u00B7'; + vga_to_curses[0xfb].chars[0] = L'\u221A'; + vga_to_curses[0xfc].chars[0] = L'\u207F'; + vga_to_curses[0xfd].chars[0] = L'\u00B2'; + vga_to_curses[0xfe].chars[0] = L'\u25A0'; + vga_to_curses[0xff].chars[0] = L'\u00A0'; + } + if (strcmp(nl_langinfo(CODESET), "UTF-8")) { + /* Non-Unicode capable, use termcap equivalents for those available */ + for (i = 0; i <= 0xff; i++) { + switch (vga_to_curses[i].chars[0]) { + case L'\u00a3': + vga_to_curses[i] = *WACS_STERLING; + break; + case L'\u2591': + vga_to_curses[i] = *WACS_BOARD; + break; + case L'\u2592': + vga_to_curses[i] = *WACS_CKBOARD; + break; + case L'\u2502': + vga_to_curses[i] = *WACS_VLINE; + break; + case L'\u2524': + vga_to_curses[i] = *WACS_RTEE; + break; + case L'\u2510': + vga_to_curses[i] = *WACS_URCORNER; + break; + case L'\u2514': + vga_to_curses[i] = *WACS_LLCORNER; + break; + case L'\u2534': + vga_to_curses[i] = *WACS_BTEE; + break; + case L'\u252c': + vga_to_curses[i] = *WACS_TTEE; + break; + case L'\u251c': + vga_to_curses[i] = *WACS_LTEE; + break; + case L'\u2500': + vga_to_curses[i] = *WACS_HLINE; + break; + case L'\u253c': + vga_to_curses[i] = *WACS_PLUS; + break; + case L'\u256c': + vga_to_curses[i] = *WACS_LANTERN; + break; + case L'\u256a': + vga_to_curses[i] = *WACS_NEQUAL; + break; + case L'\u2518': + vga_to_curses[i] = *WACS_LRCORNER; + break; + case L'\u250c': + vga_to_curses[i] = *WACS_ULCORNER; + break; + case L'\u2588': + vga_to_curses[i] = *WACS_BLOCK; + break; + case L'\u03c0': + vga_to_curses[i] = *WACS_PI; + break; + case L'\u00b1': + vga_to_curses[i] = *WACS_PLMINUS; + break; + case L'\u2265': + vga_to_curses[i] = *WACS_GEQUAL; + break; + case L'\u2264': + vga_to_curses[i] = *WACS_LEQUAL; + break; + case L'\u00b0': + vga_to_curses[i] = *WACS_DEGREE; + break; + case L'\u25a0': + vga_to_curses[i] = *WACS_BULLET; + break; + case L'\u2666': + vga_to_curses[i] = *WACS_DIAMOND; + break; + case L'\u2192': + vga_to_curses[i] = *WACS_RARROW; + break; + case L'\u2190': + vga_to_curses[i] = *WACS_LARROW; + break; + case L'\u2191': + vga_to_curses[i] = *WACS_UARROW; + break; + case L'\u2193': + vga_to_curses[i] = *WACS_DARROW; + break; + case L'\u23ba': + vga_to_curses[i] = *WACS_S1; + break; + case L'\u23bb': + vga_to_curses[i] = *WACS_S3; + break; + case L'\u23bc': + vga_to_curses[i] = *WACS_S7; + break; + case L'\u23bd': + vga_to_curses[i] = *WACS_S9; + break; + } + } + } } static void curses_keyboard_setup(void) @@ -430,6 +664,7 @@ void curses_display_init(DisplayState *ds, int full_screen) } #endif + setlocale(LC_CTYPE, ""); curses_setup(); curses_keyboard_setup(); atexit(curses_atexit); -- 2.9.3