From cfcc111070f73b2b40b836c6d5526e002cba938d Mon Sep 17 00:00:00 2001 From: Peng Wu Date: Mon, 19 Aug 2013 10:59:21 +0800 Subject: [PATCH] Fixes CJK wide character display By jumping two columns when wide character prints, and draw wide background under wide character. --- clients/terminal.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/clients/terminal.c b/clients/terminal.c index 6701fb62..4df0abbe 100644 --- a/clients/terminal.c +++ b/clients/terminal.c @@ -20,6 +20,8 @@ * OF THIS SOFTWARE. */ +#define _XOPEN_SOURCE 700 /* for strnlen, snprintf and wcwidth */ + #include #include #include @@ -33,6 +35,8 @@ #include #include #include +#include +#include #include @@ -218,6 +222,13 @@ get_unicode(union utf8_char utf8) return machine.unicode; } +static bool +is_wide(union utf8_char utf8) +{ + uint32_t unichar = get_unicode(utf8); + return wcwidth(unichar) > 1; +} + struct char_sub { union utf8_char match; union utf8_char replace; @@ -876,6 +887,8 @@ terminal_send_selection(struct terminal *terminal, int fd) for (row = 0; row < terminal->height; row++) { p_row = terminal_get_row(terminal, row); for (col = 0; col < terminal->width; col++) { + if (p_row[col].ch == 0x200B) /* space glyph */ + continue; /* get the attributes for this character cell */ terminal_decode_attr(terminal, row, col, &attr); if (!attr.attr.s) @@ -972,6 +985,7 @@ redraw_handler(struct widget *widget, void *data) struct glyph_run run; cairo_font_extents_t extents; double average_width; + double unichar_width; surface = window_get_surface(terminal->window); widget_get_allocation(terminal->widget, &allocation); @@ -997,6 +1011,7 @@ redraw_handler(struct widget *widget, void *data) allocation.y + top_margin); /* paint the background */ for (row = 0; row < terminal->height; row++) { + p_row = terminal_get_row(terminal, row); for (col = 0; col < terminal->width; col++) { /* get the attributes for this character cell */ terminal_decode_attr(terminal, row, col, &attr); @@ -1004,12 +1019,17 @@ redraw_handler(struct widget *widget, void *data) if (attr.attr.bg == terminal->color_scheme->border) continue; + if (is_wide(p_row[col])) + unichar_width = 2 * average_width; + else + unichar_width = average_width; + terminal_set_color(terminal, cr, attr.attr.bg); cairo_move_to(cr, col * average_width, row * extents.height); - cairo_rel_line_to(cr, average_width, 0); + cairo_rel_line_to(cr, unichar_width, 0); cairo_rel_line_to(cr, 0, extents.height); - cairo_rel_line_to(cr, -average_width, 0); + cairo_rel_line_to(cr, -unichar_width, 0); cairo_close_path(cr); cairo_fill(cr); } @@ -1901,6 +1921,10 @@ handle_char(struct terminal *terminal, union utf8_char utf8) row[terminal->column] = utf8; attr_row[terminal->column++] = terminal->curr_attr; + /* cursor jump for wide character. */ + if (is_wide(utf8)) + row[terminal->column++].ch = 0x200B; /* space glyph */ + if (utf8.ch != terminal->last_char.ch) terminal->last_char = utf8; } @@ -2737,6 +2761,10 @@ int main(int argc, char *argv[]) struct terminal *terminal; int config_fd; + /* as wcwidth is locale-dependent, + wcwidth needs setlocale call to function properly. */ + setlocale(LC_ALL, ""); + option_shell = getenv("SHELL"); if (!option_shell) option_shell = "/bin/bash";