From efe557313aef555b415fa2ea2c9a50c4404ed788 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Sep 2008 20:08:57 +0000 Subject: Internal screen data rewrite for better 256 colour/UTF-8 support. --- CHANGES | 12 +- GNUmakefile | 8 +- Makefile | 5 +- TODO | 125 +-------- cmd-list-windows.c | 23 +- grid-view.c | 199 ++++++++++++++ grid.c | 353 ++++++++++++++++++++++++ input.c | 362 +++++++++++++------------ log.c | 5 +- screen-display.c | 477 -------------------------------- screen-redraw.c | 118 ++++---- screen-write.c | 737 ++++++++++++++++++++++++++------------------------ screen.c | 365 ++++++------------------- server-msg.c | 6 +- server.c | 28 +- status.c | 127 ++++----- tmux.1 | 11 +- tmux.c | 12 +- tmux.h | 379 ++++++++++++-------------- tty.c | 780 ++++++++++++++++++++++++++++++++++++----------------- utf8.c | 133 ++++----- window-copy.c | 264 +++++++++--------- window-more.c | 39 +-- window-scroll.c | 63 +++-- 24 files changed, 2342 insertions(+), 2289 deletions(-) create mode 100644 grid-view.c create mode 100644 grid.c delete mode 100644 screen-display.c diff --git a/CHANGES b/CHANGES index c55af603..c6f2dff6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,13 @@ +25 September 2008 + +* Large internal rewrite to better support 256 colours and UTF-8. Screen data + is now stored as single two-way array of structures rather than as multiple + separate arrays. Also simplified a lot of code. + + Only external changes are three new flags, -2, -d and -u, which force tmux to + assume the terminal supports 256 colours, default colours (useful for + xterm-256color which lacks the AX flag), or UTF-8 respectively. + 10 September 2008 * Split off colour conversion code from screen code. @@ -664,4 +674,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.160 2008-09-10 18:59:29 nicm Exp $ +$Id: CHANGES,v 1.161 2008-09-25 20:08:51 nicm Exp $ diff --git a/GNUmakefile b/GNUmakefile index abc13121..b0e9dad3 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.39 2008-09-09 22:16:36 nicm Exp $ +# $Id: GNUmakefile,v 1.40 2008-09-25 20:08:51 nicm Exp $ .PHONY: clean @@ -12,7 +12,9 @@ DATE= $(shell date +%Y%m%d-%H%M) META?= \002 SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ - xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c screen-display.c \ + xmalloc.c xmalloc-debug.c input.c input-keys.c \ + screen.c screen-write.c screen-redraw.c \ + grid.c grid-view.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ key-string.c key-bindings.c resize.c arg.c mode-key.c \ cmd.c cmd-generic.c cmd-string.c \ @@ -31,7 +33,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \ cmd-respawn-window.c \ window-scroll.c window-more.c window-copy.c options.c paste.c \ - tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c utf8.c + tty.c tty-keys.c tty-write.c colour.c utf8.c CC?= gcc INCDIRS+= -I. -I- diff --git a/Makefile b/Makefile index 51334ace..2ada4b8d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.74 2008-09-10 18:59:29 nicm Exp $ +# $Id: Makefile,v 1.75 2008-09-25 20:08:51 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -17,7 +17,8 @@ META?= \002 # C-b SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ xmalloc.c xmalloc-debug.c input.c input-keys.c \ - screen.c screen-display.c screen-write.c screen-redraw.c \ + screen.c screen-write.c screen-redraw.c \ + grid.c grid-view.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ key-string.c key-bindings.c resize.c arg.c mode-key.c \ cmd.c cmd-generic.c cmd-string.c \ diff --git a/TODO b/TODO index 54311a6f..ac90869c 100644 --- a/TODO +++ b/TODO @@ -41,127 +41,10 @@ -- For 0.5 -------------------------------------------------------------------- -XXX -screen contains grid - -screen_write <-- write to TTY and to screen using close-to-ANSI functions -screen_redraw <-- write areas of screen to TTY -grid_view <-- write to viewable area of grid -grid <-- manipulate grid and history - -XXX -grid_view has ox,oy -XXX - -- FINISH UTF8: fix copy and paste -- SPLIT u_short attr into attr,flags? -- maybe rethink backend data structure? - - utf8 can be 1-4 bytes - - most common is 1 bytes - - there can be double-width characters which take n bytes but 2 columns on screen - - they are not only drawn as two characters, they also require two backspaces to remove -- three operations: - - simultaneously update screen and ttys - - redraw screen or section of screen to ttys - - write to ttys without updating screen - ---- -NEED to be able to: - resize screen - apply ops to both screen and tty simultaneously - both when parsing input and when eg scrolling history - draw on the top of the screen without modifying it - display arbitrary parts of the history - redraw arbitrary parts of the visible screen ---- -NEVER need to draw into the history - -split off grid manip: - 16-bit characters - 8-bit flags - 8-bit attributes - 8-bit fg colour - 8-bit bg colour - -struct grid_data { - struct grid_cell **data; - int *sizes; - - int sx; - int sy; - - int hsize; - int hlimit; -}; -struct grid_cell { - u_short data; - u_char attr; - u_char flags; - u_char fg; - u_char bg; -}; -const struct grid_default_cell = { 0x20, 0, 0, 8, 8 }; - -; grid logically split from -; -hlimit to 0 and 0 to sy - -; ALWAYS fill with default - -const struct grid_cell *grid_get(int x, int y); -void grid_set(int x, int y, const struct grid_cell *cell); - -void grid_resize() -void grid_shift() /* shift lines into history */ - -struct grid_view { - int ox; - int oy; - - int sx; - int sy; - - struct grid_data *gdata; - struct grid_view *parent; -}; - -struct grid_cell *grid_view_get_cell(int x, int y) -void grid_view_set_cell(int x, int y, const struct grid_cell *cell); - -int grid_view_absolute_x(int x); -int grid_view_absolute_y(int y); - -int grid_view_relative_x(int x); -int grid_view_relative_y(int y); - -void grid_view_delete_lines(int y, int ny) -void grid_view_insert_lines(int y, int ny) -void grid_view_clear_lines(int y, int ny) -void grid_view_fill_lines(int y, int ny, const struct grid_cell *cell) - -void grid_view_delete_cells(int x, int y, int nx) -void grid_view_insert_cells(int x, int y, int nx) -void grid_view_clear_cells(int x, int y, int nx) -void grid_view_fill_cells(int x, int nx, const struct grid_cell *cell) - -void grid_view_clear_area(int x, int y, int nx, int ny) -void grid_view_fill_area(int x, int y, int nx, int ny, const struct grid_cell *cell) - ---- - -screen has two (both grid_view): - base and overlay - ---- -screen_write writes into overlay if it exists and then base, also optionally to tty -screen_draw draws overlay + base to display ---- - ---- - -Would it be better to just expand char to 16-bits and use it as an index only -for >2-byte characters? or - better - don't support entire UTF range? only the BMP? -this would get rid of UTF table and limits, but still leave double-width character annoyances -also would double memory usage +TODO -- 2 fix window-*.c + 3 resizing + 4 audit for leftover/unused code + 5 next phase of tidying ---- 21:09 < merdely> NicM: if I run 'tmux attach -t main' and there is no tmux session named main, start a new one. diff --git a/cmd-list-windows.c b/cmd-list-windows.c index d3cf24c0..d5ae16e2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-windows.c,v 1.23 2008-09-09 22:16:36 nicm Exp $ */ +/* $Id: cmd-list-windows.c,v 1.24 2008-09-25 20:08:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -48,6 +48,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct winlink *wl; struct window *w; + struct grid_data *gd; u_int i; unsigned long long size; const char *name; @@ -57,27 +58,23 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; + gd = w->base.grid; size = 0; - for (i = 0; i < w->base.hsize; i++) - size += w->base.grid_size[i] * 3; - size += w->base.hsize * (sizeof *w->base.grid_data); - size += w->base.hsize * (sizeof *w->base.grid_attr); - size += w->base.hsize * (sizeof *w->base.grid_fg); - size += w->base.hsize * (sizeof *w->base.grid_bg); - size += w->base.hsize * (sizeof *w->base.grid_size); - + for (i = 0; i < gd->hsize; i++) + size += gd->size[i] * sizeof **gd->data; + size += gd->hsize * (sizeof *gd->data); + size += gd->hsize * (sizeof *gd->size); + if (w->fd != -1) name = ttyname(w->fd); else name = ""; ctx->print(ctx, - "%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes] " - "[UTF8 table %u/%u]", + "%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes]", wl->idx, w->name, w->base.title, name, screen_size_x(&w->base), screen_size_y(&w->base), - w->base.hsize, w->base.hlimit, size, - ARRAY_LENGTH(&w->base.utf8_table.array), UTF8_LIMIT); + gd->hsize, gd->hlimit, size); } if (ctx->cmdclient != NULL) diff --git a/grid-view.c b/grid-view.c new file mode 100644 index 00000000..434a2d06 --- /dev/null +++ b/grid-view.c @@ -0,0 +1,199 @@ +/* $Id: grid-view.c,v 1.1 2008-09-25 20:08:52 nicm Exp $ */ + +/* + * Copyright (c) 2008 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "tmux.h" + +/* + * Grid view functions. These work using coordinates relative to the visible + * screen area. + */ + +#define grid_view_x(gd, x) (x) +#define grid_view_y(gd, y) ((gd)->hsize + (y)) + +/* Get cell for reading. */ +const struct grid_cell * +grid_view_peek_cell(struct grid_data *gd, u_int px, u_int py) +{ + return (grid_peek_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Get cell for writing. */ +struct grid_cell * +grid_view_get_cell(struct grid_data *gd, u_int px, u_int py) +{ + return (grid_get_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Set cell. */ +void +grid_view_set_cell( + struct grid_data *gd, u_int px, u_int py, const struct grid_cell *gc) +{ + grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); +} + +/* Clear area. */ +void +grid_view_clear(struct grid_data *gd, u_int px, u_int py, u_int nx, u_int ny) +{ + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + grid_clear(gd, px, py, nx, ny); +} + +/* Fill area. */ +void +grid_view_fill(struct grid_data *gd, + const struct grid_cell *gc, u_int px, u_int py, u_int nx, u_int ny) +{ + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + grid_fill(gd, gc, px, py, nx, ny); +} + +/* Scroll region up. */ +void +grid_view_scroll_region_up(struct grid_data *gd, u_int rupper, u_int rlower) +{ + GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); + + if (rupper == 0 && rlower == gd->sy - 1) { + grid_scroll_line(gd); + return; + } + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); +} + +/* Scroll region down. */ +void +grid_view_scroll_region_down(struct grid_data *gd, u_int rupper, u_int rlower) +{ + GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + grid_move_lines(gd, rupper + 1, rupper, rlower - rupper); +} + +/* Insert lines. */ +void +grid_view_insert_lines(struct grid_data *gd, u_int py, u_int ny) +{ + u_int sy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + py = grid_view_y(gd, py); + + sy = grid_view_y(gd, gd->sy); + + grid_move_lines(gd, py + ny, py, sy - py - ny); +} + +/* Insert lines in region. */ +void +grid_view_insert_lines_region( + struct grid_data *gd, u_int rupper, u_int rlower, u_int py, u_int ny) +{ + GRID_DEBUG( + gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + py = grid_view_y(gd, py); + + grid_move_lines(gd, py + ny, py, (rlower + 1) - py - ny); +} + +/* Delete lines. */ +void +grid_view_delete_lines(struct grid_data *gd, u_int py, u_int ny) +{ + u_int sy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + py = grid_view_y(gd, py); + + sy = grid_view_y(gd, gd->sy); + + grid_move_lines(gd, py, py + ny, sy - py - ny); +} + +/* Delete lines inside scroll region. */ +void +grid_view_delete_lines_region( + struct grid_data *gd, u_int rupper, u_int rlower, u_int py, u_int ny) +{ + GRID_DEBUG( + gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + py = grid_view_y(gd, py); + + grid_move_lines(gd, py, py + ny, (rlower + 1) - py - ny); +} + +/* Insert characters. */ +void +grid_view_insert_cells(struct grid_data *gd, u_int px, u_int py, u_int nx) +{ + u_int sx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + + sx = grid_view_x(gd, gd->sx); + + grid_move_cells(gd, px + nx, px, py, (sx - 1) - (px + nx)); +} + +/* Delete characters. */ +void +grid_view_delete_cells(struct grid_data *gd, u_int px, u_int py, u_int nx) +{ + u_int sx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + + sx = grid_view_x(gd, gd->sx); + + grid_move_cells(gd, px, px + nx, py, (sx - 1) - (px + nx)); +} diff --git a/grid.c b/grid.c new file mode 100644 index 00000000..29e39a16 --- /dev/null +++ b/grid.c @@ -0,0 +1,353 @@ +/* $Id: grid.c,v 1.1 2008-09-25 20:08:52 nicm Exp $ */ + +/* + * Copyright (c) 2008 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "tmux.h" + +/* + * Grid data. This is the basic data structure that represents what is shown on + * screen. + * + * A grid is a grid of cells (struct grid_cell). It is sparse, in that cells + * are not allocated until they are written to. The grid is logically split + * into history and viewable data with the history starting at row (line) 0 and + * extending to (hsize - 1); from hsize to hsize + (sy - 1) is the viewable + * data. All functions in this file work on absolute coordinates, grid-view.c + * has functions which work on the screen data. + */ + +/* Default grid cell data. */ +const struct grid_cell grid_default_cell = { ' ', 0, 0, 8, 8 }; + +#define grid_check_x(gd, px) do { \ + if ((px) >= (gd)->sx) \ + log_fatalx("x out of range: %u", px); \ +} while (0) + +#define grid_check_y(gd, py) do { \ + if ((py) >= (gd)->hsize + (gd)->sy) \ + log_fatalx("y out of range: %u", py); \ +} while (0) + +#define grid_put_cell(gd, px, py, gc) do { \ + memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \ +} while (0) + +/* Create a new grid. */ +struct grid_data * +grid_create(u_int sx, u_int sy, u_int hlimit) +{ + struct grid_data *gd; + + gd = xmalloc(sizeof *gd); + gd->sx = sx; + gd->sy = sy; + + gd->hsize = 0; + gd->hlimit = hlimit; + + gd->size = xcalloc(gd->sy, sizeof *gd->size); + gd->data = xcalloc(gd->sy, sizeof *gd->data); + + return (gd); +} + +/* Destroy grid. */ +void +grid_destroy(struct grid_data *gd) +{ + u_int yy; + + for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) { + if (gd->data[yy] != NULL) + xfree(gd->data[yy]); + } + + if (gd->data != NULL) + xfree(gd->data); + if (gd->size != NULL) + xfree(gd->size); + xfree(gd); +} + +/* Scroll a line into the history. */ +void +grid_scroll_line(struct grid_data *gd) +{ + u_int yy; + + GRID_DEBUG(gd, ""); + + if (gd->hsize >= gd->hlimit - 1) { + /* If the limit is hit, free the bottom 10% and shift up. */ + yy = gd->hlimit / 10; + if (yy < 1) + yy = 1; + + grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); + gd->hsize -= yy; + } + + yy = gd->hsize + gd->sy; + gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size); + gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data); + + gd->data[yy] = NULL; + gd->size[yy] = 0; + + gd->hsize++; +} + +/* Reduce line to fit to cell. */ +void +grid_reduce_line(struct grid_data *gd, u_int py, u_int sx) +{ + if (sx >= gd->size[py]) + return; + + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + gd->size[py] = sx; +} + +/* Expand line to fit to cell. */ +void +grid_expand_line(struct grid_data *gd, u_int py, u_int sx) +{ + u_int xx; + + if (sx <= gd->size[py]) + return; + + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + for (xx = gd->size[py]; xx < sx; xx++) + grid_put_cell(gd, xx, py, &grid_default_cell); + gd->size[py] = sx; +} + +/* Get cell for reading. */ +const struct grid_cell * +grid_peek_cell(struct grid_data *gd, u_int px, u_int py) +{ + grid_check_x(gd, px); + grid_check_y(gd, py); + + if (px >= gd->size[py]) + return (&grid_default_cell); + return (&gd->data[py][px]); +} + +/* Get cell at relative position (for writing). */ +struct grid_cell * +grid_get_cell(struct grid_data *gd, u_int px, u_int py) +{ + grid_check_x(gd, px); + grid_check_y(gd, py); + + grid_expand_line(gd, py, px + 1); + return (&gd->data[py][px]); +} + +/* Set cell at relative position. */ +void +grid_set_cell( + struct grid_data *gd, u_int px, u_int py, const struct grid_cell *gc) +{ + grid_check_x(gd, px); + grid_check_y(gd, py); + + grid_expand_line(gd, py, px + 1); + grid_put_cell(gd, px, py, gc); +} + +/* + * Clear area. Note this is different from a fill as it just omits unallocated + * cells. + */ +void +grid_clear(struct grid_data *gd, u_int px, u_int py, u_int nx, u_int ny) +{ + u_int xx, yy; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + if (nx == 0 || ny == 0) + return; + + if (px == 0 && nx == gd->sx) { + grid_clear_lines(gd, py, ny); + return; + } + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->size[yy]) + break; + grid_put_cell(gd, xx, yy, &grid_default_cell); + } + } +} + +/* Fill area. */ +void +grid_fill(struct grid_data *gd, + const struct grid_cell *gc, u_int px, u_int py, u_int nx, u_int ny) +{ + u_int xx, yy; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + if (nx == 0 || ny == 0) + return; + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + grid_expand_line(gd, yy, xx + 1); + grid_put_cell(gd, xx, py, gc); + } + } +} + +/* Clear lines. This just frees and truncates the lines. */ +void +grid_clear_lines(struct grid_data *gd, u_int py, u_int ny) +{ + u_int yy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + if (ny == 0) + return; + + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + + for (yy = py; yy < py + ny; yy++) { + if (gd->data[yy] != NULL) { + xfree(gd->data[yy]); + gd->data[yy] = NULL; + gd->size[yy] = 0; + } + } +} + +/* Fill a group of lines. */ +void +grid_fill_lines( + struct grid_data *gd, const struct grid_cell *gc, u_int py, u_int ny) +{ + grid_fill(gd, gc, 0, py, gd->sx, ny); +} + +/* Move a group of lines. */ +void +grid_move_lines(struct grid_data *gd, u_int dy, u_int py, u_int ny) +{ + u_int yy; + + GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny); + + if (ny == 0 || py == dy) + return; + + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + grid_check_y(gd, dy); + grid_check_y(gd, dy + ny - 1); + + /* Free any lines which are being replaced. */ + for (yy = dy; yy < dy + ny; yy++) { + if (yy >= py && yy < py + ny) + continue; + grid_clear_lines(gd, yy, 1); + } + + memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data)); + memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size)); + + /* Wipe any lines that have been moved (without freeing them). */ + for (yy = py; yy < py + ny; yy++) { + if (yy >= dy && yy < dy + ny) + continue; + gd->data[yy] = NULL; + gd->size[yy] = 0; + } +} + +/* Clear a group of cells. */ +void +grid_clear_cells(struct grid_data *gd, u_int px, u_int py, u_int nx) +{ + u_int xx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + if (nx == 0) + return; + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->size[py]) + break; + grid_put_cell(gd, xx, py, &grid_default_cell); + } +} + +/* Move a group of cells. */ +void +grid_move_cells(struct grid_data *gd, u_int dx, u_int px, u_int py, u_int nx) +{ + u_int xx; + + GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx); + + if (nx == 0 || px == dx) + return; + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + + grid_expand_line(gd, py ,px + nx); + grid_expand_line(gd, py, dx + nx); + memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data)); + + /* Wipe any cells that have been moved. */ + for (xx = px; xx < px + nx; xx++) { + if (xx >= dx && xx < dx + nx) + continue; + memcpy( + &gd->data[py][xx], &grid_default_cell, sizeof **gd->data); + } +} + diff --git a/input.c b/input.c index a15f60cb..ada32df1 100644 --- a/input.c +++ b/input.c @@ -1,4 +1,4 @@ -/* $Id: input.c,v 1.58 2008-09-09 22:16:36 nicm Exp $ */ +/* $Id: input.c,v 1.59 2008-09-25 20:08:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -186,12 +186,20 @@ input_state(struct input_ctx *ictx, void *state) void input_init(struct window *w) { - ARRAY_INIT(&w->ictx.args); + struct input_ctx *ictx = &w->ictx; + + ARRAY_INIT(&ictx->args); - w->ictx.string_len = 0; - w->ictx.string_buf = NULL; + ictx->string_len = 0; + ictx->string_buf = NULL; - input_state(&w->ictx, input_state_first); + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + + memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); + ictx->saved_cx = 0; + ictx->saved_cy = 0; + + input_state(ictx, input_state_first); } void @@ -341,10 +349,9 @@ void input_state_title_next(u_char ch, struct input_ctx *ictx) { if (ch == '\007') { - if (ictx->string_type == STRING_TITLE) { - screen_write_set_title( - &ictx->ctx, input_get_string(ictx)); - } else + if (ictx->string_type == STRING_TITLE) + screen_set_title(ictx->ctx.s, input_get_string(ictx)); + else input_abort_string(ictx); input_state(ictx, input_state_first); return; @@ -490,59 +497,67 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx) void input_state_utf8(u_char ch, struct input_ctx *ictx) { + u_int value; + log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->utf8_buf.data[ictx->utf8_off++] = ch; + ictx->utf8_buf[ictx->utf8_off++] = ch; if (--ictx->utf8_len != 0) return; input_state(ictx, input_state_first); - screen_write_put_utf8(&ictx->ctx, &ictx->utf8_buf); + value = utf8_combine(ictx->utf8_buf); + if (value > 0xffff) /* non-BMP not supported */ + value = '_'; + + ictx->cell.data = value; + screen_write_cell(&ictx->ctx, &ictx->cell); } void input_handle_character(u_char ch, struct input_ctx *ictx) { - log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - if (ch > 0x7f) { /* - * UTF8 sequence. + * UTF-8 sequence. * * 11000010-11011111 C2-DF start of 2-byte sequence * 11100000-11101111 E0-EF start of 3-byte sequence * 11110000-11110100 F0-F4 start of 4-byte sequence */ - memset(&ictx->utf8_buf.data, 0xff, sizeof &ictx->utf8_buf.data); - ictx->utf8_buf.data[0] = ch; + memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf); + ictx->utf8_buf[0] = ch; ictx->utf8_off = 1; if (ch >= 0xc2 && ch <= 0xdf) { - log_debug2(":: u2"); + log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch); input_state(ictx, input_state_utf8); ictx->utf8_len = 1; + return; } if (ch >= 0xe0 && ch <= 0xef) { - log_debug2(":: u3"); + log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch); input_state(ictx, input_state_utf8); ictx->utf8_len = 2; + return; } if (ch >= 0xf0 && ch <= 0xf4) { - log_debug2(":: u4"); + log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch); input_state(ictx, input_state_utf8); ictx->utf8_len = 3; + return; } - return; } + log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - screen_write_put_character(&ictx->ctx, ch); + ictx->cell.data = ch; + screen_write_cell(&ictx->ctx, &ictx->cell); } void input_handle_c0_control(u_char ch, struct input_ctx *ictx) { struct screen *s = ictx->ctx.s; - u_short attr; log_debug2("-- c0 %zu: %hhu", ictx->off, ch); @@ -550,32 +565,31 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) case '\0': /* NUL */ break; case '\n': /* LF */ - screen_write_cursor_down_scroll(&ictx->ctx); + screen_write_linefeed(&ictx->ctx); break; case '\r': /* CR */ - screen_write_move_cursor(&ictx->ctx, 0, s->cy); + screen_write_carriagereturn(&ictx->ctx); break; case '\007': /* BELL */ ictx->w->flags |= WINDOW_BELL; break; case '\010': /* BS */ - screen_write_cursor_left(&ictx->ctx, 1); + screen_write_cursorleft(&ictx->ctx, 1); break; case '\011': /* TAB */ + /* XXX right? */ s->cx = ((s->cx / 8) * 8) + 8; - if (s->cx > screen_last_x(s)) { + if (s->cx > screen_size_x(s) - 1) { s->cx = 0; - screen_write_cursor_down(&ictx->ctx, 1); + screen_write_cursordown(&ictx->ctx, 1); } - screen_write_move_cursor(&ictx->ctx, s->cx, s->cy); + screen_write_cursormove(&ictx->ctx, s->cx, s->cy); break; case '\016': /* SO */ - attr = s->attr | ATTR_CHARSET; - screen_write_set_attributes(&ictx->ctx, attr, s->fg, s->bg); + ictx->cell.attr |= GRID_ATTR_CHARSET; break; case '\017': /* SI */ - attr = s->attr & ~ATTR_CHARSET; - screen_write_set_attributes(&ictx->ctx, attr, s->fg, s->bg); + ictx->cell.attr &= ~GRID_ATTR_CHARSET; break; default: log_debug("unknown c0: %hhu", ch); @@ -590,7 +604,7 @@ input_handle_c1_control(u_char ch, struct input_ctx *ictx) switch (ch) { case 'M': /* RI */ - screen_write_cursor_up_scroll(&ictx->ctx); + screen_write_reverseindex(&ictx->ctx); break; default: log_debug("unknown c1: %hhu", ch); @@ -607,27 +621,22 @@ input_handle_private_two(u_char ch, struct input_ctx *ictx) switch (ch) { case '=': /* DECKPAM */ - screen_write_set_mode(&ictx->ctx, MODE_KKEYPAD); + screen_write_kkeypadmode(&ictx->ctx, 1); log_debug("kkeypad on (application mode)"); break; case '>': /* DECKPNM */ - screen_write_clear_mode(&ictx->ctx, MODE_KKEYPAD); + screen_write_kkeypadmode(&ictx->ctx, 0); log_debug("kkeypad off (number mode)"); break; case '7': /* DECSC */ - s->saved_cx = s->cx; - s->saved_cy = s->cy; - s->saved_attr = s->attr; - s->saved_fg = s->fg; - s->saved_bg = s->bg; - s->mode |= MODE_SAVED; + memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); + ictx->saved_cx = s->cx; + ictx->saved_cy = s->cy; break; case '8': /* DECRC */ - if (!(s->mode & MODE_SAVED)) - break; - screen_write_set_attributes( - &ictx->ctx, s->saved_attr, s->saved_fg, s->saved_bg); - screen_write_move_cursor(&ictx->ctx, s->saved_cx, s->saved_cy); + memcpy(&ictx->cell, &ictx->saved_cell, sizeof ictx->cell); + screen_write_cursormove( + &ictx->ctx, ictx->saved_cx, ictx->saved_cy); break; default: log_debug("unknown p2: %hhu", ch); @@ -641,6 +650,21 @@ input_handle_standard_two(u_char ch, struct input_ctx *ictx) log_debug2("-- s2 %zu: %hhu (%c)", ictx->off, ch, ch); switch (ch) { + case 'c': /* RIS */ + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + + memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); + ictx->saved_cx = 0; + ictx->saved_cy = 0; + + screen_write_insertmode(&ictx->ctx, 0); + screen_write_kcursormode(&ictx->ctx, 0); + screen_write_kkeypadmode(&ictx->ctx, 0); + screen_write_mousemode(&ictx->ctx, 0); + + screen_write_clearscreen(&ictx->ctx); + screen_write_cursormove(&ictx->ctx, 0, 0); + break; case 'k': input_start_string(ictx, STRING_NAME); input_state(ictx, input_state_string_next); @@ -718,7 +742,7 @@ input_handle_sequence_cuu(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_up(&ictx->ctx, n); + screen_write_cursorup(&ictx->ctx, n); } void @@ -736,7 +760,7 @@ input_handle_sequence_cud(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_down(&ictx->ctx, n); + screen_write_cursordown(&ictx->ctx, n); } void @@ -754,7 +778,7 @@ input_handle_sequence_cuf(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_right(&ictx->ctx, n); + screen_write_cursorright(&ictx->ctx, n); } void @@ -772,7 +796,7 @@ input_handle_sequence_cub(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_left(&ictx->ctx, n); + screen_write_cursorleft(&ictx->ctx, n); } void @@ -790,7 +814,7 @@ input_handle_sequence_dch(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_delete_characters(&ictx->ctx, n); + screen_write_deletecharacter(&ictx->ctx, n); } void @@ -808,7 +832,7 @@ input_handle_sequence_dl(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_delete_lines(&ictx->ctx, n); + screen_write_deleteline(&ictx->ctx, n); } void @@ -826,7 +850,7 @@ input_handle_sequence_ich(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_insert_characters(&ictx->ctx, n); + screen_write_insertcharacter(&ictx->ctx, n); } void @@ -844,7 +868,7 @@ input_handle_sequence_il(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_insert_lines(&ictx->ctx, n); + screen_write_insertline(&ictx->ctx, n); } void @@ -863,7 +887,7 @@ input_handle_sequence_vpa(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_move_cursor(&ictx->ctx, s->cx, n - 1); + screen_write_cursormove(&ictx->ctx, s->cx, n - 1); } void @@ -882,7 +906,7 @@ input_handle_sequence_hpa(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_move_cursor(&ictx->ctx, n - 1, s->cy); + screen_write_cursormove(&ictx->ctx, n - 1, s->cy); } void @@ -904,7 +928,7 @@ input_handle_sequence_cup(struct input_ctx *ictx) if (m == 0) m = 1; - screen_write_move_cursor(&ictx->ctx, m - 1, n - 1); + screen_write_cursormove(&ictx->ctx, m - 1, n - 1); } void @@ -924,10 +948,13 @@ input_handle_sequence_ed(struct input_ctx *ictx) switch (n) { case 0: - screen_write_fill_end_of_screen(&ictx->ctx); + screen_write_clearendofscreen(&ictx->ctx); + break; + case 1: + screen_write_clearstartofscreen(&ictx->ctx); break; case 2: - screen_write_fill_screen(&ictx->ctx); + screen_write_clearscreen(&ictx->ctx); break; } } @@ -949,13 +976,13 @@ input_handle_sequence_el(struct input_ctx *ictx) switch (n) { case 0: - screen_write_fill_end_of_line(&ictx->ctx); + screen_write_clearendofline(&ictx->ctx); break; case 1: - screen_write_fill_start_of_line(&ictx->ctx); + screen_write_clearstartofline(&ictx->ctx); break; case 2: - screen_write_fill_line(&ictx->ctx); + screen_write_clearline(&ictx->ctx); break; } } @@ -973,15 +1000,15 @@ input_handle_sequence_sm(struct input_ctx *ictx) if (ictx->private == '?') { switch (n) { case 1: /* GATM */ - screen_write_set_mode(&ictx->ctx, MODE_KCURSOR); + screen_write_kcursormode(&ictx->ctx, 1); log_debug("kcursor on"); break; case 25: /* TCEM */ - screen_write_set_mode(&ictx->ctx, MODE_CURSOR); + screen_write_cursormode(&ictx->ctx, 1); log_debug("cursor on"); break; case 1000: - screen_write_set_mode(&ictx->ctx, MODE_MOUSE); + screen_write_mousemode(&ictx->ctx, 1); log_debug("mouse on"); break; default: @@ -991,7 +1018,7 @@ input_handle_sequence_sm(struct input_ctx *ictx) } else { switch (n) { case 4: /* IRM */ - screen_write_set_mode(&ictx->ctx, MODE_INSERT); + screen_write_insertmode(&ictx->ctx, 1); log_debug("insert on"); break; case 34: @@ -1017,15 +1044,15 @@ input_handle_sequence_rm(struct input_ctx *ictx) if (ictx->private == '?') { switch (n) { case 1: /* GATM */ - screen_write_clear_mode(&ictx->ctx, MODE_KCURSOR); + screen_write_kcursormode(&ictx->ctx, 0); log_debug("kcursor off"); break; case 25: /* TCEM */ - screen_write_clear_mode(&ictx->ctx, MODE_CURSOR); + screen_write_cursormode(&ictx->ctx, 0); log_debug("cursor off"); break; case 1000: - screen_write_clear_mode(&ictx->ctx, MODE_MOUSE); + screen_write_mousemode(&ictx->ctx, 0); log_debug("mouse off"); break; default: @@ -1035,7 +1062,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) } else if (ictx->private == '\0') { switch (n) { case 4: /* IRM */ - screen_write_clear_mode(&ictx->ctx, MODE_INSERT); + screen_write_insertmode(&ictx->ctx, 0); log_debug("insert off"); break; case 34: @@ -1093,118 +1120,107 @@ input_handle_sequence_decstbm(struct input_ctx *ictx) if (m == 0) m = screen_size_y(s); - screen_write_set_region(&ictx->ctx, n - 1, m - 1); + screen_write_scrollregion(&ictx->ctx, n - 1, m - 1); } void input_handle_sequence_sgr(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; - u_int i, n; - uint16_t m, o; - u_short attr; - u_char fg, bg; - - attr = s->attr; - fg = s->fg; - bg = s->bg; - - n = ARRAY_LENGTH(&ictx->args); - if (n == 0) { - attr = 0; - fg = 8; - bg = 8; - } else { - for (i = 0; i < n; i++) { - if (input_get_argument(ictx, i, &m, 0) != 0) - return; + struct grid_cell *gc = &ictx->cell; + u_int i; + uint16_t m, o; - if (m == 38 || m == 48) { - i++; - if (input_get_argument(ictx, i, &o, 0) != 0) - return; - if (o != 5) - continue; - - i++; - if (input_get_argument(ictx, i, &o, 0) != 0) - return; - if (m == 38) { - attr |= ATTR_FG256; - fg = o; - } else if (m == 48) { - attr |= ATTR_BG256; - bg = o; - } + if (ARRAY_LENGTH(&ictx->args) == 0) { + memcpy(gc, &grid_default_cell, sizeof *gc); + return; + } + + for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { + if (input_get_argument(ictx, i, &m, 0) != 0) + return; + + if (m == 38 || m == 48) { + i++; + if (input_get_argument(ictx, i, &o, 0) != 0) + return; + if (o != 5) continue; + + i++; + if (input_get_argument(ictx, i, &o, 0) != 0) + return; + if (m == 38) { + gc->flags |= GRID_FLAG_FG256; + gc->fg = o; + } else if (m == 48) { + gc->flags |= GRID_FLAG_BG256; + gc->bg = o; } + continue; + } - switch (m) { - case 0: - case 10: - attr &= ATTR_CHARSET; - fg = 8; - bg = 8; - break; - case 1: - attr |= ATTR_BRIGHT; - break; - case 2: - attr |= ATTR_DIM; - break; - case 3: - attr |= ATTR_ITALICS; - break; - case 4: - attr |= ATTR_UNDERSCORE; - break; - case 5: - attr |= ATTR_BLINK; - break; - case 7: - attr |= ATTR_REVERSE; - break; - case 8: - attr |= ATTR_HIDDEN; - break; - case 23: - attr &= ~ATTR_ITALICS; - break; - case 24: - attr &= ~ATTR_UNDERSCORE; - break; - case 30: - case 31: - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - attr &= ~ATTR_FG256; - fg = m - 30; - break; - case 39: - attr &= ~ATTR_FG256; - fg = 8; - break; - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - attr &= ~ATTR_BG256; - bg = m - 40; - break; - case 49: - attr &= ~ATTR_BG256; - bg = 8; - break; - } + switch (m) { + case 0: + case 10: + memcpy(gc, &grid_default_cell, sizeof *gc); + break; + case 1: + gc->attr |= GRID_ATTR_BRIGHT; + break; + case 2: + gc->attr |= GRID_ATTR_DIM; + break; + case 3: + gc->attr |= GRID_ATTR_ITALICS; + break; + case 4: + gc->attr |= GRID_ATTR_UNDERSCORE; + break; + case 5: + gc->attr |= GRID_ATTR_BLINK; + break; + case 7: + gc->attr |= GRID_ATTR_REVERSE; + break; + case 8: + gc->attr |= GRID_ATTR_HIDDEN; + break; + case 23: + gc->attr &= ~GRID_ATTR_ITALICS; + break; + case 24: + gc->attr &= ~GRID_ATTR_UNDERSCORE; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = m - 30; + break; + case 39: + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = 8; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = m - 40; + break; + case 49: + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = 8; + break; } } - screen_write_set_attributes(&ictx->ctx, attr, fg, bg); } diff --git a/log.c b/log.c index ac23e301..f81c2bb4 100644 --- a/log.c +++ b/log.c @@ -1,4 +1,4 @@ -/* $Id: log.c,v 1.5 2008-08-08 17:35:42 nicm Exp $ */ +/* $Id: log.c,v 1.6 2008-09-25 20:08:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -224,6 +224,9 @@ log_vfatal(const char *msg, va_list ap) } free(fmt); +#ifdef DEBUG + abort(); +#endif exit(1); } diff --git a/screen-display.c b/screen-display.c deleted file mode 100644 index 4760d8ee..00000000 --- a/screen-display.c +++ /dev/null @@ -1,477 +0,0 @@ -/* $Id: screen-display.c,v 1.21 2008-09-09 22:16:36 nicm Exp $ */ - -/* - * Copyright (c) 2007 Nicholas Marriott - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include - -#include "tmux.h" - -/* Get a cell. */ -void -screen_display_get_cell(struct screen *s, - u_int px, u_int py, u_char *data, u_short *attr, u_char *fg, u_char *bg) -{ - screen_get_cell( - s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg); -} - -/* Set a cell. */ -void -screen_display_set_cell(struct screen *s, - u_int px, u_int py, u_char data, u_short attr, u_char fg, u_char bg) -{ - screen_set_cell( - s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg); -} - -/* Create a region of lines. */ -void -screen_display_make_lines(struct screen *s, u_int py, u_int ny) -{ - if (ny == 0 || !screen_in_y(s, py) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - screen_make_lines(s, screen_y(s, py), ny); - if (s->attr != 0 || s->fg != 8 || s->bg != 8) { - screen_display_fill_area( - s, 0, py, screen_size_x(s), ny, ' ', s->attr, s->fg, s->bg); - } -} - -/* Free a region of lines. */ -void -screen_display_free_lines(struct screen *s, u_int py, u_int ny) -{ - if (ny == 0 || !screen_in_y(s, py) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - screen_free_lines(s, screen_y(s, py), ny); -} - -/* Move a set of lines. */ -void -screen_display_move_lines(struct screen *s, u_int dy, u_int py, u_int ny) -{ - if (ny == 0 || !screen_in_y(s, py) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG3(s, dy, py, ny); - return; - } - if (!screen_in_y(s, dy) || !screen_in_y(s, dy + ny - 1) || dy == py) { - SCREEN_DEBUG3(s, dy, py, ny); - return; - } - screen_move_lines(s, screen_y(s, dy), screen_y(s, py), ny); -} - -/* Fill a set of cells. */ -void -screen_display_fill_area(struct screen *s, u_int px, u_int py, - u_int nx, u_int ny, u_char data, u_short attr, u_char fg, u_char bg) -{ - if (nx == 0 || ny == 0) { - SCREEN_DEBUG4(s, px, py, nx, ny); - return; - } - if (!screen_in_x(s, px) || !screen_in_y(s, py)) { - SCREEN_DEBUG4(s, px, py, nx, ny); - return; - } - if (!screen_in_x(s, px + nx - 1) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG4(s, px, py, nx, ny); - return; - } - screen_fill_area( - s, screen_x(s, px), screen_y(s, py), nx, ny, data, attr, fg, bg); -} - -/* Scroll region up. */ -void -screen_display_scroll_region_up(struct screen *s) -{ - u_int ny, sy; - - /* - * If the region is the entire screen, this is easy-peasy. Allocate - * a new line and adjust the history size. - * XXX should this be done somewhere else? - */ - if (s->rupper == 0 && s->rlower == screen_last_y(s)) { - if (s->hsize == s->hlimit) { - /* If the limit is hit, free 10% and shift up. */ - ny = s->hlimit / 10; - if (ny < 1) - ny = 1; - - sy = screen_size_y(s) + s->hsize; - screen_free_lines(s, 0, ny); - screen_move_lines(s, 0, ny, sy - ny); - - s->hsize -= ny; - } - s->hsize++; - - sy = screen_size_y(s) + s->hsize; - s->grid_data = xrealloc(s->grid_data, sy, sizeof *s->grid_data); - s->grid_attr = xrealloc(s->grid_attr, sy, sizeof *s->grid_attr); - s->grid_fg = xrealloc(s->grid_fg, sy, sizeof *s->grid_fg); - s->grid_bg = xrealloc(s->grid_bg, sy, sizeof *s->grid_fg); - s->grid_size = xrealloc(s->grid_size, sy, sizeof *s->grid_size); - screen_display_make_lines(s, screen_last_y(s), 1); - return; - } - - /* - * Scroll scrolling region up: - * - delete rupper - * - move rupper + 1 to rlower to rupper - * - make new line at rlower - * - * Example: region is 12 to 24. - * rlower = 24, rupper = 12 - * screen_free_lines(s, 12, 1); - * screen_move_lines(s, 12, 13, 12); - * screen_make_lines(s, 24, 1); - */ - - screen_display_free_lines(s, s->rupper, 1); - - if (s->rupper != s->rlower) { - screen_display_move_lines(s, - s->rupper, s->rupper + 1, s->rlower - s->rupper); - } - - screen_display_make_lines(s, s->rlower, 1); -} - -/* Scroll region down. */ -void -screen_display_scroll_region_down(struct screen *s) -{ - /* - * Scroll scrolling region down: - * - delete rlower - * - move rupper to rlower - 1 to rupper + 1 - * - make new line at rupper - * - * Example: region is 12 to 24. - * rlower = 24, rupper = 12 - * screen_free_lines(s, 24, 1); - * screen_move_lines(s, 13, 12, 12); - * screen_make_lines(s, 12, 1); - */ - - screen_display_free_lines(s, s->rlower, 1); - - if (s->rupper != s->rlower) { - screen_display_move_lines(s, - s->rupper + 1, s->rupper, s->rlower - s->rupper); - } - - screen_display_make_lines(s, s->rupper, 1); -} - -/* Insert lines. */ -void -screen_display_insert_lines(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_y(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > screen_last_y(s)) - ny = screen_size_y(s) - py; - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - /* - * Insert range of ny lines at py: - * - Free ny lines from end of screen. - * - Move from py to end of screen - ny to py + ny. - * - Create ny lines at py. - * - * Example: insert 2 lines at 4. - * sy = 10, py = 4, ny = 2 - * screen_free_lines(s, 8, 2); - delete lines 8,9 - * screen_move_lines(s, 6, 4, 4); - move 4,5,6,7 to 6,7,8,9 - * screen_make_lines(s, 4, 2); - make lines 4,5 - */ - - screen_display_free_lines(s, screen_size_y(s) - ny, ny); - - if (py + ny != screen_size_y(s)) { - screen_display_move_lines( - s, py + ny, py, screen_size_y(s) - py - ny); - } - - screen_display_make_lines(s, py, ny); -} - -/* Insert lines in region. */ -void -screen_display_insert_lines_region(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_region(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > s->rlower) - ny = (s->rlower + 1) - py; - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - /* - * Insert range of ny lines at py: - * - Free ny lines from end of screen. - * - Move from py to end of screen - ny to py + ny. - * - Create ny lines at py. - * - * Example: insert 2 lines at 4. - * ryu = 11, ryl = 16, py = 13, ny = 2 - * screen_free_lines(s, 15, 2); - delete lines 15,16 - * screen_move_lines(s, 13, 15, 2);- move 13,14 to 15,16 - * screen_make_lines(s, 13, 2); - make lines 13,14 - */ - - screen_display_free_lines(s, (s->rlower + 1) - ny, ny); - - if (py + ny != s->rlower + 1) { - screen_display_move_lines( - s, py + ny, py, (s->rlower + 1) - py - ny); - } - - screen_display_make_lines(s, py, ny); -} - -/* Delete lines. */ -void -screen_display_delete_lines(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_y(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > screen_last_y(s)) - ny = screen_size_y(s) - py; - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - /* - * Delete range of ny lines at py: - * - Free ny lines at py. - * - Move from py + ny to end of screen to py. - * - Free and recreate last ny lines. - * - * Example: delete lines 3,4. - * sy = 10, py = 3, ny = 2 - * screen_free_lines(s, 3, 2); - delete lines 3,4 - * screen_move_lines(s, 3, 5, 5); - move 5,6,7,8,9 to 3 - * screen_make_lines(s, 8, 2); - make lines 8,9 - */ - - screen_display_free_lines(s, py, ny); - - if (py + ny != screen_size_y(s)) { - screen_display_move_lines( - s, py, py + ny, screen_size_y(s) - py - ny); - } - - screen_display_make_lines(s, screen_size_y(s) - ny, ny); -} - -/* Delete lines inside scroll region. */ -void -screen_display_delete_lines_region(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_region(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > s->rlower) - ny = (s->rlower + 1) - py; - if (ny == 0) - return; - - /* - * Delete range of ny lines at py: - * - Free ny lines at py. - * - Move from py + ny to end of region to py. - * - Free and recreate last ny lines. - * - * Example: delete lines 13,14. - * ryu = 11, ryl = 16, py = 13, ny = 2 - * screen_free_lines(s, 13, 2); - delete lines 13,14 - * screen_move_lines(s, 15, 16, 2);- move 15,16 to 13 - * screen_make_lines(s, 15, 16); - make lines 15,16 - */ - - screen_display_free_lines(s, py, ny); - - if (py + ny != s->rlower + 1) { - screen_display_move_lines( - s, py, py + ny, (s->rlower + 1) - py - ny); - } - - screen_display_make_lines(s, (s->rlower + 1) - ny, ny); -} - -/* Insert characters. */ -void -screen_display_insert_characters(struct screen *s, u_int px, u_int py, u_int nx) -{ - u_int mx; - - if (!screen_in_x(s, px) || !screen_in_y(s, py)) { - SCREEN_DEBUG3(s, px, py, nx); - return; - } - - if (px + nx > screen_last_x(s)) - nx = screen_last_x(s) - px; - - py = screen_y(s, py); - - /* XXX Cheat and make the line a full line. */ - if (s->grid_size[py] < screen_size_x(s)) - screen_expand_line(s, py, screen_size_x(s)); - - /* - * Inserting a range of nx at px. - * - * - Move sx - (px + nx) from px to px + nx. - * - Clear the range at px to px + nx. - */ - - if (px + nx != screen_last_x(s)) { - mx = screen_last_x(s) - (px + nx); - memmove(&s->grid_data[py][px + nx], - &s->grid_data[py][px], mx * sizeof **s->grid_data); - memmove(&s->grid_attr[py][px + nx], - &s->grid_attr[py][px], mx * sizeof **s->grid_attr); - memmove(&s->grid_fg[py][px + nx], - &s->grid_fg[py][px], mx * sizeof **s->grid_fg); - memmove(&s->grid_bg[py][px + nx], - &s->grid_bg[py][px], mx * sizeof **s->grid_bg); - } - - memset(&s->grid_data[py][px], ' ', nx); - memset(&s->grid_attr[py][px], s->attr, nx); - memset(&s->grid_fg[py][px], s->fg, nx); - memset(&s->grid_bg[py][px], s->bg, nx); -} - -/* Delete characters. */ -void -screen_display_delete_characters(struct screen *s, u_int px, u_int py, u_int nx) -{ - u_int mx; - - if (!screen_in_x(s, px) || !screen_in_y(s, py)) { - SCREEN_DEBUG3(s, px, py, nx); - return; - } - - if (px + nx > screen_last_x(s)) - nx = screen_last_x(s) - px; - - py = screen_y(s, py); - - /* XXX Cheat and make the line a full line. */ - if (s->grid_size[py] < screen_size_x(s)) - screen_expand_line(s, py, screen_size_x(s)); - - /* - * Deleting the range from px to px + nx. - * - * - Move sx - (px + nx) from px + nx to px. - * - Clear the range from sx - nx to sx. - */ - - if (px + nx != screen_last_x(s)) { - mx = screen_last_x(s) - (px + nx); - memmove(&s->grid_data[py][px], &s->grid_data[py][px + nx], mx); - memmove(&s->grid_attr[py][px], &s->grid_attr[py][px + nx], mx); - memmove(&s->grid_fg[py][px], &s->grid_fg[py][px + nx], mx); - memmove(&s->grid_bg[py][px], &s->grid_bg[py][px + nx], mx); - } - - memset(&s->grid_data[py][screen_size_x(s) - nx], ' ', nx); - memset(&s->grid_attr[py][screen_size_x(s) - nx], s->attr, nx); - memset(&s->grid_fg[py][screen_size_x(s) - nx], s->fg, nx); - memset(&s->grid_bg[py][screen_size_x(s) - nx], s->bg, nx); -} - -/* Fill cells from another screen, with an offset. */ -void -screen_display_copy_area(struct screen *dst, struct screen *src, - u_int px, u_int py, u_int nx, u_int ny, u_int ox, u_int oy) -{ - u_int i, j; - u_short attr; - u_char data, fg, bg; - - if (nx == 0 || ny == 0) { - SCREEN_DEBUG4(dst, px, py, nx, ny); - return; - } - if (!screen_in_x(dst, px) || !screen_in_y(dst, py)) { - SCREEN_DEBUG4(dst, px, py, nx, ny); - return; - } - if (!screen_in_x(dst, px + nx - 1) || !screen_in_y(dst, py + ny - 1)) { - SCREEN_DEBUG4(dst, px, py, nx, ny); - return; - } - - for (i = py; i < py + ny; i++) { - for (j = px; j < px + nx; j++) { - screen_get_cell(src, - screen_x(src, j) + ox, screen_y(src, i) - oy, - &data, &attr, &fg, &bg); - screen_display_set_cell(dst, j, i, data, attr, fg, bg); - } - } -} diff --git a/screen-redraw.c b/screen-redraw.c index a66aee45..7542d14e 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1,4 +1,4 @@ -/* $Id: screen-redraw.c,v 1.11 2008-09-08 22:03:54 nicm Exp $ */ +/* $Id: screen-redraw.c,v 1.12 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,9 +22,6 @@ #include "tmux.h" -void screen_redraw_get_cell(struct screen_redraw_ctx *, - u_int, u_int, u_char *, u_short *, u_char *, u_char *); - /* Initialise redrawing with a window. */ void screen_redraw_start_window(struct screen_redraw_ctx *ctx, struct window *w) @@ -66,16 +63,15 @@ screen_redraw_start(struct screen_redraw_ctx *ctx, * Save screen cursor position. Emulation of some TTY_* commands * requires this to be correct in the screen, so rather than having * a local copy and just manipulating it, save the screen's values, - * modify them during redraw, and restore them when finished. + * modify them during redraw, and restore them when finished. XXX. */ ctx->saved_cx = s->cx; ctx->saved_cy = s->cy; - ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg); - ctx->write(ctx->data, TTY_SCROLLREGION, 0, screen_last_y(s)); - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); - ctx->write(ctx->data, TTY_CURSOROFF); - ctx->write(ctx->data, TTY_MOUSEOFF); + ctx->write(ctx->data, TTY_SCROLLREGION, 0, screen_size_y(s) - 1); + ctx->write(ctx->data, TTY_CURSORMOVE, s->cx, s->cy); + ctx->write(ctx->data, TTY_CURSORMODE, 0); + ctx->write(ctx->data, TTY_MOUSEMODE, 0); } /* Finish redrawing. */ @@ -87,62 +83,38 @@ screen_redraw_stop(struct screen_redraw_ctx *ctx) s->cx = ctx->saved_cx; s->cy = ctx->saved_cy; - ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg); ctx->write(ctx->data, TTY_SCROLLREGION, s->rupper, s->rlower); - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); + ctx->write(ctx->data, TTY_CURSORMOVE, s->cx, s->cy); if (s->mode & MODE_CURSOR) - ctx->write(ctx->data, TTY_CURSORON); + ctx->write(ctx->data, TTY_CURSORMODE, 1); if (s->mode & MODE_MOUSE) - ctx->write(ctx->data, TTY_MOUSEON); + ctx->write(ctx->data, TTY_MOUSEMODE, 1); } -/* Get cell data. */ +/* Write character. */ void -screen_redraw_get_cell(struct screen_redraw_ctx *ctx, - u_int px, u_int py, u_char *data, u_short *attr, u_char *fg, u_char *bg) +screen_redraw_putc( + struct screen_redraw_ctx *ctx, struct grid_cell *gc, u_char ch) { - struct screen *s = ctx->s; - - screen_get_cell( - s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg); -} - -/* Move cursor. */ -void -screen_redraw_move_cursor(struct screen_redraw_ctx *ctx, u_int px, u_int py) -{ - if (px != ctx->s->cx || py != ctx->s->cy) { - ctx->s->cx = px; - ctx->s->cy = py; - ctx->write(ctx->data, TTY_CURSORMOVE, ctx->s->cy, ctx->s->cx); - } -} - -/* Set attributes. */ -void -screen_redraw_set_attributes( - struct screen_redraw_ctx *ctx, u_short attr, u_char fg, u_char bg) -{ - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, fg, bg); + gc->data = ch; + ctx->write(ctx->data, TTY_CELL, gc); + ctx->s->cx++; } /* Write string. */ -void printflike2 -screen_redraw_write_string(struct screen_redraw_ctx *ctx, const char *fmt, ...) +void printflike3 +screen_redraw_puts( + struct screen_redraw_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) { - va_list ap; - char *msg, *ptr; + va_list ap; + char *msg, *ptr; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); va_end(ap); - for (ptr = msg; *ptr != '\0'; ptr++) { - if (*ptr < 0x20) - continue; - ctx->write(ctx->data, TTY_CHARACTER, *ptr); - ctx->s->cx++; - } + for (ptr = msg; *ptr != '\0'; ptr++) + screen_redraw_putc(ctx, gc, (u_char) *ptr); xfree(msg); } @@ -151,41 +123,45 @@ screen_redraw_write_string(struct screen_redraw_ctx *ctx, const char *fmt, ...) void screen_redraw_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py) { - u_short attr; - u_char data, fg, bg; + const struct grid_cell *gc; + struct grid_cell hc; - screen_redraw_move_cursor(ctx, px, py); - screen_redraw_get_cell(ctx, px, py, &data, &attr, &fg, &bg); - - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, fg, bg); - ctx->write(ctx->data, TTY_CHARACTER, data); + if (px != ctx->s->cx || py != ctx->s->cy) { + ctx->s->cx = px; + ctx->s->cy = py; + ctx->write(ctx->data, TTY_CURSORMOVE, ctx->s->cx, ctx->s->cy); + } + gc = grid_view_peek_cell(ctx->s->grid, px, py); + if (screen_check_selection(ctx->s, px, py)) { + memcpy(&hc, gc, sizeof hc); + hc.attr |= GRID_ATTR_REVERSE; + ctx->write(ctx->data, TTY_CELL, &hc); + } else + ctx->write(ctx->data, TTY_CELL, gc); ctx->s->cx++; } -/* Redraw area of cells. */ +/* Draw set of lines. */ void -screen_redraw_area( - struct screen_redraw_ctx *ctx, u_int px, u_int py, u_int nx, u_int ny) +screen_redraw_lines(struct screen_redraw_ctx *ctx, u_int py, u_int ny) { u_int i, j; - for (i = py; i < py + ny; i++) { - for (j = px; j < px + nx; j++) - screen_redraw_cell(ctx, j, i); + for (j = py; j < py + ny; j++) { + for (i = 0; i < screen_size_x(ctx->s); i++) + screen_redraw_cell(ctx, i, j); } } -/* Draw set of lines. */ -void -screen_redraw_lines(struct screen_redraw_ctx *ctx, u_int py, u_int ny) -{ - screen_redraw_area(ctx, 0, py, screen_size_x(ctx->s), ny); -} - /* Draw set of columns. */ void screen_redraw_columns(struct screen_redraw_ctx *ctx, u_int px, u_int nx) { - screen_redraw_area(ctx, px, 0, nx, screen_size_y(ctx->s)); + u_int i, j; + + for (j = 0; j < screen_size_y(ctx->s); j++) { + for (i = px; i < px + nx; i++) + screen_redraw_cell(ctx, i, j); + } } diff --git a/screen-write.c b/screen-write.c index 35ac3a59..fa64f2a1 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.13 2008-09-09 22:16:36 nicm Exp $ */ +/* $Id: screen-write.c,v 1.14 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,17 +22,6 @@ #include "tmux.h" -#define screen_write_limit(s, v, lower, upper) do { \ - if (v < lower) { \ - v = lower; \ - SCREEN_DEBUG3(s, v, lower, upper); \ - } \ - if (v > upper) { \ - v = upper; \ - SCREEN_DEBUG3(s, v, lower, upper); \ - } \ -} while (0) - /* Initialise writing with a window. */ void screen_write_start_window(struct screen_write_ctx *ctx, struct window *w) @@ -71,520 +60,558 @@ screen_write_start(struct screen_write_ctx *ctx, ctx->s = s; if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSOROFF); + ctx->write(ctx->data, TTY_CURSORMODE, 0); } -/* Finalise writing. */ +/* Finish writing. */ void screen_write_stop(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; if (ctx->write != NULL && s->mode & MODE_CURSOR) - ctx->write(ctx->data, TTY_CURSORON); + ctx->write(ctx->data, TTY_CURSORMODE, 1); } -/* Set screen title. */ +/* Write character. */ void -screen_write_set_title(struct screen_write_ctx *ctx, char *title) +screen_write_putc( + struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch) { - struct screen *s = ctx->s; - - xfree(s->title); - s->title = title; + gc->data = ch; + screen_write_cell(ctx, gc); } -/* Put a character. */ -void -screen_write_put_character(struct screen_write_ctx *ctx, u_char ch) +/* Write string. */ +void printflike3 +screen_write_puts( + struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) { - struct screen *s = ctx->s; - u_short attr; - - if (s->cx == screen_size_x(s)) { - s->cx = 0; - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CHARACTER, '\r'); - screen_write_cursor_down_scroll(ctx); - } else if (!screen_in_x(s, s->cx) || !screen_in_y(s, s->cy)) { - SCREEN_DEBUG(s); - return; - } - attr = s->attr & ~(ATTR_UTF8|ATTR_PAD); + va_list ap; + char *msg, *ptr; - screen_display_set_cell(s, s->cx, s->cy, ch, attr, s->fg, s->bg); - s->cx++; + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CHARACTER, ch); + for (ptr = msg; *ptr != '\0'; ptr++) + screen_write_putc(ctx, gc, (u_char) *ptr); + + xfree(msg); } -/* Put a UTF8 character. */ +/* Copy from another screen. */ void -screen_write_put_utf8(struct screen_write_ctx *ctx, struct utf8_data *udat) +screen_write_copy(struct screen_write_ctx *ctx, + struct screen *src, u_int px, u_int py, u_int nx, u_int ny) { - struct screen *s = ctx->s; - u_char ch, ch2, fg, bg; - u_short attr, attr2; - int idx, wide; - u_int n; - - wide = 0; - if (udat->data[2] == 0xff) - n = ((udat->data[0] & 0x1f)<<6) + (udat->data[1] & 0x3f); - else if (udat->data[3] == 0xff) { - n = ((udat->data[0] & 0x0f)<<12) + - ((udat->data[1] & 0x3f)<<6) + (udat->data[2] & 0x3f); - } else - n = 0; - if ((n >= 0x1100 && n <= 0x115f) || n == 0x2329 || n == 0x232a || - (n >= 0x2e80 && n <= 0xa4cf && n != 0x303f) || - (n >= 0xac00 && n <= 0xd7a3) || (n >= 0xf900 && n <= 0xfaff) || - (n >= 0xfe10 && n <= 0xfe19) || (n >= 0xfe30 && n <= 0xfe6f) || - (n >= 0xff00 && n <= 0xff60) || (n >= 0xffe0 && n <= 0xffe6) || - (n >= 0x20000 && n <= 0x2fffd) || (n >= 0x30000 && n <= 0x3fffd)) - wide = 1; - - if (s->cx >= screen_size_x(s) - wide) { - s->cx = 0; - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CHARACTER, '\r'); - screen_write_cursor_down_scroll(ctx); - } else if (!screen_in_x(s, s->cx) || !screen_in_y(s, s->cy)) { - SCREEN_DEBUG(s); - return; - } - attr = s->attr & ~(ATTR_UTF8|ATTR_PAD); - - if ((idx = utf8_add(&s->utf8_table, udat)) == -1) - ch = '_'; - else { - utf8_pack(idx, &ch, &attr); - attr |= ATTR_UTF8; - } - - /* Remove padding before and after, if any. */ - screen_display_get_cell(s, s->cx, s->cy, &ch2, &attr2, &fg, &bg); - if (s->cx > 0 && (attr2 & ATTR_PAD)) - screen_display_set_cell(s, s->cx - 1, s->cy, ' ', 0, 8, 8); - if (s->cx < screen_last_x(s) && (attr2 & ATTR_UTF8)) { - screen_display_get_cell( - s, s->cx + 1, s->cy, &ch2, &attr2, &fg, &bg); - if (s->cx > 0 && (attr2 & ATTR_PAD)) { - screen_display_set_cell( - s, s->cx + 1, s->cy, ' ', 0, 8, 8); + struct screen *s = ctx->s; + struct grid_data *gd = src->grid; + const struct grid_cell *gc; + u_int xx, yy, cx, cy; + + cx = s->cx; + cy = s->cy; + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->sx || yy >= gd->hsize + gd->sy) + gc = &grid_default_cell; + else + gc = grid_peek_cell(gd, xx, yy); + screen_write_cell(ctx, gc); } - } - - screen_display_set_cell(s, s->cx, s->cy, ch, attr, s->fg, s->bg); - s->cx++; - - if (wide) { - screen_display_set_cell(s, s->cx, s->cy, ' ', ATTR_PAD, 8, 8); - s->cx++; - } - - if (ctx->write != NULL) { - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, s->fg, s->bg); - ctx->write(ctx->data, TTY_CHARACTER, ch); - ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg); + cy++; + screen_write_cursormove(ctx, cx, cy); } } -/* Put a string right-justified. */ -size_t printflike2 -screen_write_put_string_rjust( - struct screen_write_ctx *ctx, const char *fmt, ...) +/* Cursor up by ny. */ +void +screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) { struct screen *s = ctx->s; - va_list ap; - size_t size; - char *msg, *ptr; - va_start(ap, fmt); - size = vasprintf(&msg, fmt, ap); - va_end(ap); + if (ny > s->cy) + ny = s->cy; + if (ny == 0) + ny = 1; - ptr = msg; - if (size > screen_size_x(s)) { - ptr += size - screen_size_x(s); - size = screen_size_x(s); - } - screen_write_move_cursor(ctx, screen_size_x(s) - size, s->cy); - for (; *ptr != '\0'; ptr++) { - if (s->cx == screen_size_x(s)) - break; - screen_write_put_character(ctx, *ptr); - } + s->cy -= ny; - xfree(msg); - - return (size); + if (ctx != NULL) + ctx->write(ctx->data, TTY_CURSORUP, ny); } -/* Put a string, truncating at end of line. */ -void printflike2 -screen_write_put_string(struct screen_write_ctx *ctx, const char *fmt, ...) +/* Cursor down by ny. */ +void +screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) { struct screen *s = ctx->s; - va_list ap; - char *msg, *ptr; - va_start(ap, fmt); - vasprintf(&msg, fmt, ap); - va_end(ap); + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + ny = 1; + + s->cy += ny; - for (ptr = msg; *ptr != '\0'; ptr++) { - if (s->cx == screen_size_x(s)) - break; - screen_write_put_character(ctx, *ptr); - } - - xfree(msg); + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CURSORDOWN, ny); } -/* Set screen attributes. */ +/* Cursor right by nx. */ void -screen_write_set_attributes( - struct screen_write_ctx *ctx, u_short attr, u_char fg, u_char bg) +screen_write_cursorright(struct s