X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-terminal%2Fsubterm.c;h=7c119ac58aa02eb4e96953bde9c48d5be66af40a;hb=b57b06258e0b1894edb6d1fc52a80b3c33164892;hp=5cf3c2a73a56b51aeeb431e09af8880ef91d5c9f;hpb=eccb01acfb327f1f6819c1f3851765049b156865;p=elogind.git diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c index 5cf3c2a73..7c119ac58 100644 --- a/src/libsystemd-terminal/subterm.c +++ b/src/libsystemd-terminal/subterm.c @@ -41,6 +41,7 @@ #include "sd-event.h" #include "term-internal.h" #include "util.h" +#include "utf8.h" typedef struct Output Output; typedef struct Terminal Terminal; @@ -102,10 +103,8 @@ static int output_winch(Output *o) { assert_return(o, -EINVAL); r = ioctl(o->fd, TIOCGWINSZ, &wsz); - if (r < 0) { - log_error("error: cannot read window-size: %m"); - return -errno; - } + if (r < 0) + return log_error_errno(errno, "error: cannot read window-size: %m"); if (wsz.ws_col != o->width || wsz.ws_row != o->height) { o->width = wsz.ws_col; @@ -119,16 +118,14 @@ static int output_winch(Output *o) { } static int output_flush(Output *o) { - ssize_t len; + int r; if (o->n_obuf < 1) return 0; - len = loop_write(o->fd, o->obuf, o->n_obuf, false); - if (len < 0) { - log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len)); - return len; - } + r = loop_write(o->fd, o->obuf, o->n_obuf, false); + if (r < 0) + return log_error_errno(r, "error: cannot write to TTY: %m"); o->n_obuf = 0; @@ -156,10 +153,8 @@ static int output_write(Output *o, const void *buf, size_t size) { return r; len = loop_write(o->fd, buf, size, false); - if (len < 0) { - log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len)); - return len; - } + if (len < 0) + return log_error_errno(len, "error: cannot write to TTY (%zd): %m", len); return 0; } @@ -286,6 +281,8 @@ static Output *output_free(Output *o) { if (!o) return NULL; + /* re-enable cursor */ + output_printf(o, "\e[?25h"); /* disable alternate screen buffer */ output_printf(o, "\e[?1049l"); output_flush(o); @@ -317,6 +314,11 @@ static int output_new(Output **out, int fd) { if (r < 0) goto error; + /* always hide cursor */ + r = output_printf(o, "\e[?25l"); + if (r < 0) + goto error; + r = output_flush(o); if (r < 0) goto error; @@ -392,86 +394,86 @@ static void output_draw_menu(Output *o) { output_frame_printl(o, " ^C: send ^C to the PTY"); } -static void output_draw_screen(Output *o, term_screen *s) { - unsigned int i, j; - bool first = true; - - assert(o); - assert(s); - - for (j = 0; j < s->page->height && j < o->in_height; ++j) { - if (!first) - output_printf(o, "\e[m\r\n" BORDER_VERT); - first = false; - - for (i = 0; i < s->page->width && i < o->in_width; ++i) { - term_charbuf_t buf; - term_cell *cell = &s->page->lines[j]->cells[i]; - size_t k, len, ulen; - const uint32_t *str; - char utf8[4]; - - switch (cell->attr.fg.ccode) { - case TERM_CCODE_DEFAULT: - output_printf(o, "\e[39m"); - break; - case TERM_CCODE_256: - output_printf(o, "\e[38;5;%um", cell->attr.fg.c256); - break; - case TERM_CCODE_RGB: - output_printf(o, "\e[38;2;%u;%u;%um", cell->attr.fg.red, cell->attr.fg.green, cell->attr.fg.blue); - break; - case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: - if (cell->attr.bold) - output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 90); - else - output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 30); - break; - case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: - output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_LIGHT_BLACK + 90); - break; - } +static int output_draw_cell_fn(term_screen *screen, + void *userdata, + unsigned int x, + unsigned int y, + const term_attr *attr, + const uint32_t *ch, + size_t n_ch, + unsigned int ch_width) { + Output *o = userdata; + size_t k, ulen; + char utf8[4]; + + if (x >= o->in_width || y >= o->in_height) + return 0; - switch (cell->attr.bg.ccode) { - case TERM_CCODE_DEFAULT: - output_printf(o, "\e[49m"); - break; - case TERM_CCODE_256: - output_printf(o, "\e[48;5;%um", cell->attr.bg.c256); - break; - case TERM_CCODE_RGB: - output_printf(o, "\e[48;2;%u;%u;%um", cell->attr.bg.red, cell->attr.bg.green, cell->attr.bg.blue); - break; - case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: - output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_BLACK + 40); - break; - case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: - output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_LIGHT_BLACK + 100); - break; - } + if (x == 0 && y != 0) + output_printf(o, "\e[m\r\n" BORDER_VERT); - output_printf(o, "\e[%u;%u;%u;%u;%u;%um", - cell->attr.bold ? 1 : 22, - cell->attr.italic ? 3 : 23, - cell->attr.underline ? 4 : 24, - cell->attr.inverse ? 7 : 27, - cell->attr.blink ? 5 : 25, - cell->attr.hidden ? 8 : 28); + switch (attr->fg.ccode) { + case TERM_CCODE_DEFAULT: + output_printf(o, "\e[39m"); + break; + case TERM_CCODE_256: + output_printf(o, "\e[38;5;%um", attr->fg.c256); + break; + case TERM_CCODE_RGB: + output_printf(o, "\e[38;2;%u;%u;%um", attr->fg.red, attr->fg.green, attr->fg.blue); + break; + case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: + output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_BLACK + 30); + break; + case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: + output_printf(o, "\e[%um", attr->fg.ccode - TERM_CCODE_LIGHT_BLACK + 90); + break; + } - str = term_char_resolve(cell->ch, &len, &buf); + switch (attr->bg.ccode) { + case TERM_CCODE_DEFAULT: + output_printf(o, "\e[49m"); + break; + case TERM_CCODE_256: + output_printf(o, "\e[48;5;%um", attr->bg.c256); + break; + case TERM_CCODE_RGB: + output_printf(o, "\e[48;2;%u;%u;%um", attr->bg.red, attr->bg.green, attr->bg.blue); + break; + case TERM_CCODE_BLACK ... TERM_CCODE_WHITE: + output_printf(o, "\e[%um", attr->bg.ccode - TERM_CCODE_BLACK + 40); + break; + case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE: + output_printf(o, "\e[%um", attr->bg.ccode - TERM_CCODE_LIGHT_BLACK + 100); + break; + } - if (len < 1) { - output_printf(o, " "); - } else { - for (k = 0; k < len; ++k) { - ulen = term_utf8_encode(utf8, str[k]); - output_write(o, utf8, ulen); - } - } + output_printf(o, "\e[%u;%u;%u;%u;%u;%um", + attr->bold ? 1 : 22, + attr->italic ? 3 : 23, + attr->underline ? 4 : 24, + attr->inverse ? 7 : 27, + attr->blink ? 5 : 25, + attr->hidden ? 8 : 28); + + if (n_ch < 1) { + output_printf(o, " "); + } else { + for (k = 0; k < n_ch; ++k) { + ulen = utf8_encode_unichar(utf8, ch[k]); + output_write(o, utf8, ulen); } } - output_move_to(o, s->cursor_x + 1, s->cursor_y + 3); + return 0; +} + +static void output_draw_screen(Output *o, term_screen *s) { + assert(o); + assert(s); + + term_screen_draw(s, output_draw_cell_fn, o, NULL); + output_printf(o, "\e[m"); } @@ -535,10 +537,6 @@ static void output_draw(Output *o, bool menu, term_screen *screen) { else output_draw_screen(o, screen); - /* show cursor */ - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - output_printf(o, "\e[?25h"); - /* * Hack: sd-term was not written to support TTY as output-objects, thus * expects callers to use term_screen_feed_keyboard(). However, we @@ -564,7 +562,7 @@ static void output_draw(Output *o, bool menu, term_screen *screen) { */ static void terminal_dirty(Terminal *t) { - uint64_t usec; + usec_t usec; int r; assert(t); @@ -609,12 +607,12 @@ static int terminal_winch_fn(sd_event_source *source, const struct signalfd_sigi if (t->pty) { r = pty_resize(t->pty, t->output->in_width, t->output->in_height); if (r < 0) - log_error("error: pty_resize() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: pty_resize() (%d): %m", r); } r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height); if (r < 0) - log_error("error: term_screen_resize() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: term_screen_resize() (%d): %m", r); terminal_dirty(t); @@ -628,7 +626,7 @@ static int terminal_push_tmp(Terminal *t, uint32_t ucs4) { assert(t); - len = term_utf8_encode(buf, ucs4); + len = utf8_encode_unichar(buf, ucs4); if (len < 1) return 0; @@ -653,10 +651,8 @@ static int terminal_write_tmp(Terminal *t) { if (t->pty) { for (i = 0; i < num; ++i) { r = pty_write(t->pty, vec[i].iov_base, vec[i].iov_len); - if (r < 0) { - log_error("error: cannot write to PTY (%d): %s", r, strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "error: cannot write to PTY (%d): %m", r); } } @@ -710,22 +706,20 @@ static int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, voi if (errno == EAGAIN || errno == EINTR) return 0; - log_error("error: cannot read from TTY (%d): %m", -errno); + log_error_errno(errno, "error: cannot read from TTY (%d): %m", -errno); return -errno; } for (i = 0; i < len; ++i) { const term_seq *seq; - const uint32_t *str; + uint32_t *str; size_t n_str, j; - str = term_utf8_decode(&t->utf8, &n_str, buf[i]); + n_str = term_utf8_decode(&t->utf8, &str, buf[i]); for (j = 0; j < n_str; ++j) { type = term_parser_feed(t->parser, &seq, str[j]); - if (type < 0) { - log_error("error: term_parser_feed() (%d): %s", type, strerror(-type)); - return type; - } + if (type < 0) + return log_error_errno(type, "error: term_parser_feed() (%d): %m", type); if (!t->is_menu) { r = terminal_push_tmp(t, str[j]); @@ -774,10 +768,8 @@ static int terminal_pty_fn(Pty *pty, void *userdata, unsigned int event, const v break; case PTY_DATA: r = term_screen_feed_text(t->screen, ptr, size); - if (r < 0) { - log_error("error: term_screen_feed_text() (%d): %s", r, strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "error: term_screen_feed_text() (%d): %m", r); terminal_dirty(t); break; @@ -829,16 +821,12 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) { assert_return(out, -EINVAL); r = tcgetattr(in_fd, &in_attr); - if (r < 0) { - log_error("error: tcgetattr() (%d): %m", -errno); - return -errno; - } + if (r < 0) + return log_error_errno(errno, "error: tcgetattr() (%d): %m", -errno); r = tcgetattr(out_fd, &out_attr); - if (r < 0) { - log_error("error: tcgetattr() (%d): %m", -errno); - return -errno; - } + if (r < 0) + return log_error_errno(errno, "error: tcgetattr() (%d): %m", -errno); t = new0(Terminal, 1); if (!t) @@ -854,49 +842,49 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) { r = tcsetattr(t->in_fd, TCSANOW, &in_attr); if (r < 0) { - log_error("error: tcsetattr() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: tcsetattr() (%d): %m", r); goto error; } r = tcsetattr(t->out_fd, TCSANOW, &out_attr); if (r < 0) { - log_error("error: tcsetattr() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: tcsetattr() (%d): %m", r); goto error; } r = sd_event_default(&t->event); if (r < 0) { - log_error("error: sd_event_default() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sd_event_default() (%d): %m", r); goto error; } r = sigprocmask_many(SIG_BLOCK, SIGINT, SIGQUIT, SIGTERM, SIGWINCH, SIGCHLD, -1); if (r < 0) { - log_error("error: sigprocmask_many() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sigprocmask_many() (%d): %m", r); goto error; } r = sd_event_add_signal(t->event, NULL, SIGINT, NULL, NULL); if (r < 0) { - log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r); goto error; } r = sd_event_add_signal(t->event, NULL, SIGQUIT, NULL, NULL); if (r < 0) { - log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r); goto error; } r = sd_event_add_signal(t->event, NULL, SIGTERM, NULL, NULL); if (r < 0) { - log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r); goto error; } r = sd_event_add_signal(t->event, NULL, SIGWINCH, terminal_winch_fn, t); if (r < 0) { - log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r); goto error; } @@ -904,7 +892,7 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) { t->is_dirty = true; r = sd_event_add_time(t->event, &t->frame_timer, CLOCK_MONOTONIC, 0, 0, terminal_frame_timer_fn, t); if (r < 0) { - log_error("error: sd_event_add_time() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: sd_event_add_time() (%d): %m", r); goto error; } @@ -926,7 +914,7 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) { r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height); if (r < 0) { - log_error("error: term_screen_resize() (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: term_screen_resize() (%d): %m", r); goto error; } @@ -948,10 +936,9 @@ static int terminal_run(Terminal *t) { assert_return(t, -EINVAL); pid = pty_fork(&t->pty, t->event, terminal_pty_fn, t, t->output->in_width, t->output->in_height); - if (pid < 0) { - log_error("error: cannot fork PTY (%d): %s", pid, strerror(-pid)); - return pid; - } else if (pid == 0) { + if (pid < 0) + return log_error_errno(pid, "error: cannot fork PTY (%d): %m", pid); + else if (pid == 0) { /* child */ char **argv = (char*[]){ @@ -963,7 +950,7 @@ static int terminal_run(Terminal *t) { setenv("COLORTERM", "systemd-subterm", 1); execve(argv[0], argv, environ); - log_error("error: cannot exec %s (%d): %m", argv[0], -errno); + log_error_errno(errno, "error: cannot exec %s (%d): %m", argv[0], -errno); _exit(1); } @@ -990,7 +977,7 @@ int main(int argc, char *argv[]) { out: if (r < 0) - log_error("error: terminal failed (%d): %s", r, strerror(-r)); + log_error_errno(r, "error: terminal failed (%d): %m", r); terminal_free(t); return -r; }