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> --- hw/display/vga.c | 4 +- include/ui/console.h | 19 +++- ui/curses.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 278 insertions(+), 15 deletions(-) diff --git a/hw/display/vga.c b/hw/display/vga.c index 9ebc54f..53d3c9a 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -1968,7 +1968,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; @@ -1977,7 +1977,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 52a5f65..2939176 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -336,8 +336,12 @@ static inline pixman_format_code_t surface_format(DisplaySurface *s) #ifdef CONFIG_CURSES #include <curses.h> +#ifdef CONFIG_CURSESW +typedef cchar_t console_ch_t; +#else typedef chtype console_ch_t; -extern chtype vga_to_curses[]; +#endif +extern console_ch_t vga_to_curses[]; #else typedef unsigned long console_ch_t; #endif @@ -345,16 +349,27 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) { uint8_t c = ch; #ifdef CONFIG_CURSES +#ifdef CONFIG_CURSESW + if (vga_to_curses[c].chars[0]) { + *dest = vga_to_curses[c]; + } else { + dest->chars[0] = c; + dest->attr = 0; + } + dest->attr |= ch & ~0xff; +#else if (vga_to_curses[c]) { ch &= ~(console_ch_t)0xff; ch |= vga_to_curses[c]; } + *dest = ch; +#endif #else if (c == '\0') { ch |= ' '; } -#endif *dest = ch; +#endif } typedef struct GraphicHwOps { diff --git a/ui/curses.c b/ui/curses.c index 438b8be..9ef54b5 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -28,6 +28,11 @@ #include <sys/ioctl.h> #include <termios.h> #endif +#ifdef CONFIG_CURSESW +#include <locale.h> +#include <wchar.h> +#include <langinfo.h> +#endif #include "qemu-common.h" #include "ui/console.h" @@ -43,16 +48,25 @@ static WINDOW *screenpad = NULL; static int width, height, gwidth, gheight, invalidate; static int px, py, sminx, sminy, smaxx, smaxy; +#ifdef CONFIG_CURSESW +console_ch_t vga_to_curses[256]; +#else chtype vga_to_curses[256]; +#endif 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) + line = ((console_ch_t *) screen) + y * width; + for (h += y; y < h; y ++, line += width) { +#ifdef CONFIG_CURSESW + mvwadd_wchnstr(screenpad, y, 0, line, width); +#else mvwaddchnstr(screenpad, y, 0, line, width); +#endif + } pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1); refresh(); @@ -362,15 +376,245 @@ 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 + +#ifdef CONFIG_CURSESW + 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++) + { + if (vga_to_curses[i].chars[0] == L'\u00a3') + vga_to_curses[i] = *WACS_STERLING; + if (vga_to_curses[i].chars[0] == L'\u2591') + vga_to_curses[i] = *WACS_BOARD; + if (vga_to_curses[i].chars[0] == L'\u2592') + vga_to_curses[i] = *WACS_CKBOARD; + if (vga_to_curses[i].chars[0] == L'\u2502') + vga_to_curses[i] = *WACS_VLINE; + if (vga_to_curses[i].chars[0] == L'\u2524') + vga_to_curses[i] = *WACS_RTEE; + if (vga_to_curses[i].chars[0] == L'\u2510') + vga_to_curses[i] = *WACS_URCORNER; + if (vga_to_curses[i].chars[0] == L'\u2514') + vga_to_curses[i] = *WACS_LLCORNER; + if (vga_to_curses[i].chars[0] == L'\u2534') + vga_to_curses[i] = *WACS_BTEE; + if (vga_to_curses[i].chars[0] == L'\u252c') + vga_to_curses[i] = *WACS_TTEE; + if (vga_to_curses[i].chars[0] == L'\u251c') + vga_to_curses[i] = *WACS_LTEE; + if (vga_to_curses[i].chars[0] == L'\u2500') + vga_to_curses[i] = *WACS_HLINE; + if (vga_to_curses[i].chars[0] == L'\u253c') + vga_to_curses[i] = *WACS_PLUS; + if (vga_to_curses[i].chars[0] == L'\u256c') + vga_to_curses[i] = *WACS_LANTERN; + if (vga_to_curses[i].chars[0] == L'\u256a') + vga_to_curses[i] = *WACS_NEQUAL; + if (vga_to_curses[i].chars[0] == L'\u2518') + vga_to_curses[i] = *WACS_LRCORNER; + if (vga_to_curses[i].chars[0] == L'\u250c') + vga_to_curses[i] = *WACS_ULCORNER; + if (vga_to_curses[i].chars[0] == L'\u2588') + vga_to_curses[i] = *WACS_BLOCK; + if (vga_to_curses[i].chars[0] == L'\u03c0') + vga_to_curses[i] = *WACS_PI; + if (vga_to_curses[i].chars[0] == L'\u00b1') + vga_to_curses[i] = *WACS_PLMINUS; + if (vga_to_curses[i].chars[0] == L'\u2265') + vga_to_curses[i] = *WACS_GEQUAL; + if (vga_to_curses[i].chars[0] == L'\u2264') + vga_to_curses[i] = *WACS_LEQUAL; + if (vga_to_curses[i].chars[0] == L'\u00b0') + vga_to_curses[i] = *WACS_DEGREE; + if (vga_to_curses[i].chars[0] == L'\u25a0') + vga_to_curses[i] = *WACS_BULLET; + if (vga_to_curses[i].chars[0] == L'\u2666') + vga_to_curses[i] = *WACS_DIAMOND; + if (vga_to_curses[i].chars[0] == L'\u2192') + vga_to_curses[i] = *WACS_RARROW; + if (vga_to_curses[i].chars[0] == L'\u2190') + vga_to_curses[i] = *WACS_LARROW; + if (vga_to_curses[i].chars[0] == L'\u2191') + vga_to_curses[i] = *WACS_UARROW; + if (vga_to_curses[i].chars[0] == L'\u2193') + vga_to_curses[i] = *WACS_DARROW; + if (vga_to_curses[i].chars[0] == L'\u23ba') + vga_to_curses[i] = *WACS_S1; + if (vga_to_curses[i].chars[0] == L'\u23bb') + vga_to_curses[i] = *WACS_S3; + if (vga_to_curses[i].chars[0] == L'\u23bc') + vga_to_curses[i] = *WACS_S7; + if (vga_to_curses[i].chars[0] == L'\u23bd') + vga_to_curses[i] = *WACS_S9; + } + } +#else + /* No wide char support, hardcode ASCII + termcap-portable CP437 */ /* ACS_* is not constant. So, we can't initialize statically. */ vga_to_curses['\0'] = ' '; vga_to_curses[0x04] = ACS_DIAMOND; @@ -401,6 +645,7 @@ static void curses_setup(void) vga_to_curses[0xf3] = ACS_LEQUAL; vga_to_curses[0xf8] = ACS_DEGREE; vga_to_curses[0xfe] = ACS_BULLET; +#endif } static void curses_keyboard_setup(void) @@ -434,6 +679,9 @@ void curses_display_init(DisplayState *ds, int full_screen) } #endif +#ifdef CONFIG_CURSESW + setlocale(LC_CTYPE, ""); +#endif curses_setup(); curses_keyboard_setup(); atexit(curses_atexit); -- 2.8.1