diff --git a/CHANGES b/CHANGES index 500fc30d..2c85331c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ 19 May 2009 +* Try to guess if the window is UTF-8 by outputting a three-byte UTF-8 wide + character and seeing how much the cursor moves. Currently tries to figure out + if this works by some stupid checks on the terminal, these need to be + rethought. Also might be better using a width 1 character rather than width 2. * If LANG contains "UTF-8", assume the terminal supports UTF-8, on the grounds that anyone who configures it probably wants UTF-8. Not certain if this is a perfect idea but let's see if it causes any problems. @@ -1278,7 +1282,7 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.294 2009-05-19 16:03:18 nicm Exp $ +$Id: CHANGES,v 1.295 2009-05-19 16:08:35 nicm Exp $ LocalWords: showw utf UTF fulvio ciriaco joshe OSC APC gettime abc DEF OA clr LocalWords: rivo nurges lscm Erdely eol smysession mysession ek dstname RB ms diff --git a/cmd-list-clients.c b/cmd-list-clients.c index 67a0cc5b..a38f90a6 100644 --- a/cmd-list-clients.c +++ b/cmd-list-clients.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-clients.c,v 1.13 2009-02-11 17:50:32 nicm Exp $ */ +/* $Id: cmd-list-clients.c,v 1.14 2009-05-19 16:08:35 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -47,14 +47,20 @@ cmd_list_clients_exec(unused struct cmd *self, struct cmd_ctx *ctx) { struct client *c; u_int i; + const char *s_utf8; for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); if (c == NULL || c->session == NULL) continue; - ctx->print(ctx, "%s: %s [%ux%u %s]", c->tty.path, - c->session->name, c->tty.sx, c->tty.sy, c->tty.termname); + if (c->tty.flags & TTY_UTF8) + s_utf8 = " (utf8)"; + else + s_utf8 = ""; + ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path, + c->session->name, c->tty.sx, c->tty.sy, + c->tty.termname, s_utf8); } return (0); diff --git a/tmux.h b/tmux.h index 6e1f7ef7..e12a9e47 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.324 2009-05-19 13:32:55 tcunha Exp $ */ +/* $Id: tmux.h,v 1.325 2009-05-19 16:08:35 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1117,6 +1117,7 @@ void tty_putc(struct tty *, u_char); void tty_init(struct tty *, char *, char *); void tty_start_tty(struct tty *); void tty_stop_tty(struct tty *); +void tty_detect_utf8(struct tty *); void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int); void tty_draw_line( diff --git a/tty.c b/tty.c index 72224039..9920b4a1 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.98 2009-05-14 16:21:55 nicm Exp $ */ +/* $Id: tty.c,v 1.99 2009-05-19 16:08:35 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -136,6 +136,8 @@ tty_start_tty(struct tty *tty) int what; #endif + tty_detect_utf8(tty); + if (tcgetattr(tty->fd, &tty->tio) != 0) fatal("tcgetattr failed"); memcpy(&tio, &tty->tio, sizeof tio); @@ -197,15 +199,96 @@ tty_stop_tty(struct tty *tty) tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); - tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); - + tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); + tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); if (tty_term_has(tty->term, TTYC_KMOUS)) tty_raw(tty, "\033[?1000l"); } +void +tty_detect_utf8(struct tty *tty) +{ + struct pollfd pfd; + char buf[7]; + size_t len; + ssize_t n; + int nfds; + struct termios tio, old_tio; +#ifdef TIOCFLUSH + int what; +#endif + + if (tty->flags & TTY_UTF8) + return; + + /* + * If the terminal looks reasonably likely to support this, try to + * write a three-byte UTF-8 wide character to the terminal, then read + * the cursor position. + * + * XXX This entire function is a hack. + */ + + /* Check if the terminal looks sort of vt100. */ + if (strstr(tty_term_string(tty->term, TTYC_CLEAR), "[2J") == NULL || + strstr(tty_term_string(tty->term, TTYC_CUP), "H") == NULL) + return; + + if (tcgetattr(tty->fd, &old_tio) != 0) + fatal("tcgetattr failed"); + cfmakeraw(&tio); + if (tcsetattr(tty->fd, TCSANOW, &tio) != 0) + fatal("tcsetattr failed"); + +#ifdef TIOCFLUSH + what = 0; + if (ioctl(tty->fd, TIOCFLUSH, &what) != 0) + fatal("ioctl(TIOCFLUSH)"); +#endif + +#define UTF8_TEST_DATA "\033[H\357\277\246\033[6n" + if (write(tty->fd, UTF8_TEST_DATA, (sizeof UTF8_TEST_DATA) - 1) == -1) + fatal("write failed"); +#undef UTF8_TEST_DATA + + len = 0; + for (;;) { + pfd.fd = tty->fd; + pfd.events = POLLIN; + + nfds = poll(&pfd, 1, 500); + if (nfds == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + fatal("poll failed"); + } + if (nfds == 0) + break; +#ifdef HAVE_POLL + if (pfd.revents & (POLLERR|POLLNVAL|POLLHUP)) + break; +#endif + if (!(pfd.revents & POLLIN)) + continue; + + if ((n = read(tty->fd, buf + len, 1)) != 1) + break; + buf[++len] = '\0'; + + if (len == (sizeof buf) - 1) { + if (strcmp(buf, "\033[1;3R") == 0) + tty->flags |= TTY_UTF8; + break; + } + } + + if (tcsetattr(tty->fd, TCSANOW, &old_tio) != 0) + fatal("tcsetattr failed"); +} + void tty_fill_acs(struct tty *tty) {