diff options
-rw-r--r-- | CHANGES | 12 | ||||
-rw-r--r-- | GNUmakefile | 8 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | TODO | 125 | ||||
-rw-r--r-- | cmd-list-windows.c | 23 | ||||
-rw-r--r-- | grid-view.c | 199 | ||||
-rw-r--r-- | grid.c | 353 | ||||
-rw-r--r-- | input.c | 362 | ||||
-rw-r--r-- | log.c | 5 | ||||
-rw-r--r-- | screen-display.c | 477 | ||||
-rw-r--r-- | screen-redraw.c | 118 | ||||
-rw-r--r-- | screen-write.c | 737 | ||||
-rw-r--r-- | screen.c | 365 | ||||
-rw-r--r-- | server-msg.c | 6 | ||||
-rw-r--r-- | server.c | 28 | ||||
-rw-r--r-- | status.c | 127 | ||||
-rw-r--r-- | tmux.1 | 11 | ||||
-rw-r--r-- | tmux.c | 12 | ||||
-rw-r--r-- | tmux.h | 379 | ||||
-rw-r--r-- | tty.c | 780 | ||||
-rw-r--r-- | utf8.c | 133 | ||||
-rw-r--r-- | window-copy.c | 264 | ||||
-rw-r--r-- | window-more.c | 39 | ||||
-rw-r--r-- | window-scroll.c | 63 |
24 files changed, 2342 insertions, 2289 deletions
@@ -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- @@ -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 \ @@ -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 <nicm@users.sourceforge.net> @@ -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 <nicm@users.sourceforge.net> + * + * 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 <sys/types.h> + +#include <string.h> + +#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)); +} @@ -0,0 +1,353 @@ +/* $Id: grid.c,v 1.1 2008-09-25 20:08:52 nicm Exp $ */ + +/* + * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> + * + * 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 <sys/types.h> + +#include <string.h> + +#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); + } +} + @@ -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 <nicm@users.sourceforge.net> @@ -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); |