Internal screen data rewrite for better 256 colour/UTF-8 support.

This commit is contained in:
Nicholas Marriott 2008-09-25 20:08:57 +00:00
parent 9edb4d4b85
commit efe557313a
24 changed files with 2474 additions and 2421 deletions

12
CHANGES
View File

@ -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 $

View File

@ -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-

View File

@ -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 \

125
TODO
View File

@ -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.

View File

@ -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)

199
grid-view.c Normal file
View File

@ -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));
}

353
grid.c Normal file
View File

@ -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);
}
}

358
input.c
View File

@ -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;
w->ictx.string_len = 0;
w->ictx.string_buf = NULL;
ARRAY_INIT(&ictx->args);
input_state(&w->ictx, input_state_first);
ictx->string_len = 0;
ictx->string_buf = NULL;
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;
struct grid_cell *gc = &ictx->cell;
u_int i;
uint16_t m, o;
attr = s->attr;
fg = s->fg;
bg = s->bg;
if (ARRAY_LENGTH(&ictx->args) == 0) {
memcpy(gc, &grid_default_cell, sizeof *gc);
return;
}
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)
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 (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 (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);
}

5
log.c
View File

@ -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 <nicm@users.sourceforge.net>
@ -224,6 +224,9 @@ log_vfatal(const char *msg, va_list ap)
}
free(fmt);
#ifdef DEBUG
abort();
#endif
exit(1);
}

View File

@ -1,477 +0,0 @@
/* $Id: screen-display.c,v 1.21 2008-09-09 22:16:36 nicm Exp $ */
/*
* Copyright (c) 2007 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"
/* 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);
}
}
}

View File

@ -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 <nicm@users.sourceforge.net>
@ -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);
ctx->s->cx++;
}
/* Redraw area of cells. */
void
screen_redraw_area(
struct screen_redraw_ctx *ctx, u_int px, u_int py, u_int nx, 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);
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++;
}
/* 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);
u_int i, j;
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 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);
}
}

File diff suppressed because it is too large Load Diff

375
screen.c
View File

@ -1,4 +1,4 @@
/* $Id: screen.c,v 1.71 2008-09-10 19:15:04 nicm Exp $ */
/* $Id: screen.c,v 1.72 2008-09-25 20:08:54 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -22,90 +22,18 @@
#include "tmux.h"
/*
* Virtual screen.
*
* A screen is stored as three arrays of lines of 8-bit values, one for the
* actual characters (data), one for attributes and one for colours. Three
* seperate blocks means memset and friends can be used. Each array is y by x
* in size, row then column order. Sizes are 0-based. There is an additional
* array of u_ints with the size of each line.
*
* Each screen has a history starting at the beginning of the arrays and
* extending for hsize lines. Beyond that is the screen display of size
* dy:
*
* ----------- array base
* | |
* | history |
* ----------- array base + hsize
* | |
* | display |
* | |
* ----------- array base + hsize + dy
*
* The screen_x/screen_y macros are used to convert a cell on the displayed
* area to an absolute position in the arrays.
*
* Screen handling code is split into four files:
*
* screen.c: Creation/deletion, utility functions, and basic functions to
* manipulate the screen based on offsets from the base.
* screen-display.c: Basic functions for manipulating the displayed
* part of the screen. x,y coordinates passed to these
* are relative to the display. These are largely
* utility functions for screen-write.c.
* screen-redraw.c: Functions for redrawing all or part of a screen to
* one or more ttys. A context is filled via one of the
* screen_redraw_start* variants which sets up (removes
* cursor etc) and figures out which tty_write_* function
* to use to write to the terminals, then the other
* screen_redraw_* functions are used to draw the screen,
* and screen_redraw_stop used to reset the cursor and
* clean up. These are used when changing window and a
* few other bits (status line).
* screen-write.c: Functions for modifying (writing into) the screen and
* optionally simultaneously updating one or more ttys.
* These are used in much the same way as the redraw
* functions. These are used to update when parsing
* input from the window (input.c) and for the various
* other modes which maintain private screens.
*
* If you're thinking this all seems too complicated, that's because it is :-/.
*/
void screen_resize_x(struct screen *, u_int);
void screen_resize_y(struct screen *, u_int);
/* Create a new screen. */
void
screen_init(struct screen *s, u_int dx, u_int dy, u_int hlimit)
screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
{
s->dx = dx;
s->dy = dy;
s->cx = 0;
s->cy = 0;
s->grid = grid_create(sx, sy, hlimit);
s->rupper = 0;
s->rlower = s->dy - 1;
s->hsize = 0;
s->hlimit = hlimit;
s->attr = 0;
s->fg = 8;
s->bg = 8;
s->mode = MODE_CURSOR;
s->title = xstrdup("");
s->grid_data = xmalloc(dy * (sizeof *s->grid_data));
s->grid_attr = xmalloc(dy * (sizeof *s->grid_attr));
s->grid_fg = xmalloc(dy * (sizeof *s->grid_fg));
s->grid_bg = xmalloc(dy * (sizeof *s->grid_bg));
s->grid_size = xmalloc(dy * (sizeof *s->grid_size));
screen_make_lines(s, 0, dy);
utf8_init(&s->utf8_table, UTF8_LIMIT);
screen_clear_selection(s);
screen_reinit(s);
}
/* Reinitialise screen. */
@ -116,16 +44,13 @@ screen_reinit(struct screen *s)
s->cy = 0;
s->rupper = 0;
s->rlower = s->dy - 1;
s->attr = 0;
s->fg = 8;
s->bg = 8;
s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR;
screen_display_fill_area(s, 0, 0,
screen_size_x(s), screen_size_y(s), ' ', 0, 8, 8);
/* XXX */
grid_clear_lines(
s->grid, s->grid->hsize, s->grid->hsize + s->grid->sy - 1);
screen_clear_selection(s);
}
@ -134,245 +59,121 @@ screen_reinit(struct screen *s)
void
screen_free(struct screen *s)
{
utf8_free(&s->utf8_table);
xfree(s->title);
screen_free_lines(s, 0, s->dy + s->hsize);
xfree(s->grid_data);
xfree(s->grid_attr);
xfree(s->grid_fg);
xfree(s->grid_bg);
xfree(s->grid_size);
grid_destroy(s->grid);
}
/* Set screen title. */
void
screen_set_title(struct screen *s, const char *title)
{
xfree(s->title);
s->title = xstrdup(title);
}
/* Resize screen. */
void
screen_resize(struct screen *s, u_int sx, u_int sy)
{
u_int i, ox, oy, ny, my;
if (sx < 1)
sx = 1;
if (sy < 1)
sy = 1;
ox = s->dx;
oy = s->dy;
if (sx == ox && sy == oy)
if (sx != screen_size_x(s))
screen_resize_x(s, sx);
if (sy != screen_size_y(s))
screen_resize_y(s, sy);
}
void
screen_resize_x(struct screen *s, u_int sx)
{
struct grid_data *gd = s->grid;
const struct grid_cell *gc;
u_int xx, yy;
/* If getting larger, not much to do. */
if (sx > screen_size_x(s)) {
gd->sx = sx;
return;
/*
* X dimension.
*/
if (sx != ox) {
/*
* If getting smaller, nuke any data in lines over the new
* size.
*/
if (sx < ox) {
for (i = s->hsize; i < s->hsize + oy; i++) {
if (s->grid_size[i] > sx)
screen_reduce_line(s, i, sx);
}
}
if (s->cx >= sx)
s->cx = sx - 1;
s->dx = sx;
}
/*
* Y dimension.
*/
if (sy == oy)
return;
/* If getting smaller, nuke any data in lines over the new size. */
for (yy = gd->hsize; yy < gd->hsize + screen_size_y(s); yy++) {
/*
* If the character after the last is wide or padding, remove
* it and any leading padding.
*/
for (xx = sx; xx > 0; xx--) {
gc = grid_peek_cell(gd, xx - 1, yy);
if (!(gc->flags & GRID_FLAG_PADDING))
break;
grid_set_cell(gd, xx - 1, yy, &grid_default_cell);
}
if (xx > 0 && xx != sx && utf8_width(gc->data) != 1)
grid_set_cell(gd, xx - 1, yy, &grid_default_cell);
/* Reduce the line size. */
grid_reduce_line(gd, yy, sx);
}
if (s->cx >= sx)
s->cx = sx - 1;
gd->sx = sx;
}
void
screen_resize_y(struct screen *s, u_int sy)
{
struct grid_data *gd = s->grid;
u_int oy, yy, ny;
/* Size decreasing. */
if (sy < oy) {
ny = oy - sy;
if (sy < screen_size_y(s)) {
oy = screen_size_y(s);
if (s->cy != 0) {
/*
* The cursor is not at the start. Try to remove as
* many lines as possible from the top. (Up to the
* cursor line.)
*/
my = s->cy;
if (my > ny)
my = ny;
ny = s->cy;
if (ny > oy - sy)
ny = oy - sy;
screen_free_lines(s, s->hsize, my);
screen_move_lines(s, s->hsize, s->hsize + my, oy - my);
grid_view_delete_lines(gd, 0, ny);
s->cy -= my;
oy -= my;
s->cy -= ny;
oy -= ny;
}
ny = oy - sy;
if (ny > 0) {
/*
* Remove any remaining lines from the bottom.
*/
screen_free_lines(s, s->hsize + oy - ny, ny);
if (sy < oy) {
/* Remove any remaining lines from the bottom. */
grid_view_delete_lines(gd, sy, oy - sy);
if (s->cy >= sy)
s->cy = sy - 1;
}
}
/* Resize line arrays. */
ny = s->hsize + sy;
s->grid_data = xrealloc(s->grid_data, ny, sizeof *s->grid_data);
s->grid_attr = xrealloc(s->grid_attr, ny, sizeof *s->grid_attr);
s->grid_fg = xrealloc(s->grid_fg, ny, sizeof *s->grid_fg);
s->grid_bg = xrealloc(s->grid_bg, ny, sizeof *s->grid_bg);
s->grid_size = xrealloc(s->grid_size, ny, sizeof *s->grid_size);
s->dy = sy;
gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size);
gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data);
/* Size increasing. */
if (sy > oy)
screen_make_lines(s, s->hsize + oy, sy - oy);
if (sy > screen_size_y(s)) {
oy = screen_size_y(s);
for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) {
gd->size[yy] = 0;
gd->data[yy] = NULL;
}
}
gd->sy = sy;
s->rupper = 0;
s->rlower = s->dy - 1;
}
/* Expand line. */
void
screen_expand_line(struct screen *s, u_int py, u_int nx)
{
u_int ox;
ox = s->grid_size[py];
s->grid_size[py] = nx;
s->grid_data[py] = xrealloc(
s->grid_data[py], sizeof **s->grid_data, nx);
memset(&s->grid_data[py][ox], ' ', (nx - ox) * sizeof **s->grid_data);
s->grid_attr[py] = xrealloc(
s->grid_attr[py], sizeof **s->grid_attr, nx);
memset(&s->grid_attr[py][ox], 0, (nx - ox) * sizeof **s->grid_attr);
s->grid_fg[py] = xrealloc(
s->grid_fg[py], sizeof **s->grid_fg, nx);
memset(&s->grid_fg[py][ox], 8, (nx - ox) * sizeof **s->grid_fg);
s->grid_bg[py] = xrealloc(
s->grid_bg[py], sizeof **s->grid_bg, nx);
memset(&s->grid_bg[py][ox], 8, (nx - ox) * sizeof **s->grid_bg);
}
/* Reduce line. */
void
screen_reduce_line(struct screen *s, u_int py, u_int nx)
{
s->grid_size[py] = nx;
s->grid_data[py] = xrealloc(
s->grid_data[py], sizeof **s->grid_data, nx);
s->grid_attr[py] = xrealloc(
s->grid_attr[py], sizeof **s->grid_attr, nx);
s->grid_fg[py] = xrealloc(
s->grid_fg[py], sizeof **s->grid_fg, nx);
s->grid_bg[py] = xrealloc(
s->grid_bg[py], sizeof **s->grid_bg, nx);
}
/* Get cell. */
void
screen_get_cell(struct screen *s,
u_int cx, u_int cy, u_char *data, u_short *attr, u_char *fg, u_char *bg)
{
if (cx >= s->grid_size[cy]) {
*data = ' ';
*attr = 0;
*fg = 8;
*bg = 8;
} else {
*data = s->grid_data[cy][cx];
*attr = s->grid_attr[cy][cx];
*fg = s->grid_fg[cy][cx];
*bg = s->grid_bg[cy][cx];
}
if (screen_check_selection(s, cx, cy))
*attr |= ATTR_REVERSE;
}
/* Set a cell. */
void
screen_set_cell(struct screen *s,
u_int cx, u_int cy, u_char data, u_short attr, u_char fg, u_char bg)
{
if (cx >= s->grid_size[cy])
screen_expand_line(s, cy, cx + 1);
s->grid_data[cy][cx] = data;
s->grid_attr[cy][cx] = attr;
s->grid_fg[cy][cx] = fg;
s->grid_bg[cy][cx] = bg;
}
/* Create a range of lines. */
void
screen_make_lines(struct screen *s, u_int py, u_int ny)
{
u_int i;
for (i = py; i < py + ny; i++) {
s->grid_data[i] = NULL;
s->grid_attr[i] = NULL;
s->grid_fg[i] = NULL;
s->grid_bg[i] = NULL;
s->grid_size[i] = 0;
}
}
/* Free a range of ny lines at py. */
void
screen_free_lines(struct screen *s, u_int py, u_int ny)
{
u_int i;
for (i = py; i < py + ny; i++) {
if (s->grid_data[i] != NULL)
xfree(s->grid_data[i]);
s->grid_data[i] = NULL;
if (s->grid_attr[i] != NULL)
xfree(s->grid_attr[i]);
s->grid_attr[i] = NULL;
if (s->grid_fg[i] != NULL)
xfree(s->grid_fg[i]);
s->grid_fg[i] = NULL;
if (s->grid_bg[i] != NULL)
xfree(s->grid_bg[i]);
s->grid_bg[i] = NULL;
s->grid_size[i] = 0;
}
}
/* Move a range of lines. */
void
screen_move_lines(struct screen *s, u_int dy, u_int py, u_int ny)
{
memmove(
&s->grid_data[dy], &s->grid_data[py], ny * (sizeof *s->grid_data));
memmove(
&s->grid_attr[dy], &s->grid_attr[py], ny * (sizeof *s->grid_attr));
memmove(
&s->grid_fg[dy], &s->grid_fg[py], ny * (sizeof *s->grid_fg));
memmove(
&s->grid_bg[dy], &s->grid_bg[py], ny * (sizeof *s->grid_bg));
memmove(
&s->grid_size[dy], &s->grid_size[py], ny * (sizeof *s->grid_size));
}
/* Fill an area. */
void
screen_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)
{
u_int i, j;
for (i = py; i < py + ny; i++) {
for (j = px; j < px + nx; j++)
screen_set_cell(s, j, i, data, attr, fg, bg);
}
s->rlower = screen_size_y(s) - 1;
}
/* Set selection. */

View File

@ -1,4 +1,4 @@
/* $Id: server-msg.c,v 1.50 2008-09-09 22:16:37 nicm Exp $ */
/* $Id: server-msg.c,v 1.51 2008-09-25 20:08:54 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -189,6 +189,10 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c)
tty_init(&c->tty, data.tty, xstrdup(term));
if (data.flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data.flags & IDENTIFY_256COLOURS)
c->tty.term_flags |= TERM_256COLOURS;
if (data.flags & IDENTIFY_HASDEFAULTS)
c->tty.term_flags |= TERM_HASDEFAULTS;
xfree(term);
c->flags |= CLIENT_TERMINAL;

View File

@ -1,4 +1,4 @@
/* $Id: server.c,v 1.80 2008-09-10 19:15:04 nicm Exp $ */
/* $Id: server.c,v 1.81 2008-09-25 20:08:54 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -186,14 +186,14 @@ server_main(const char *srv_path, int srv_fd)
server_fill_clients(&pfd);
/* Do the poll. */
log_debug("polling %d fds", nfds);
/* log_debug("polling %d fds", nfds); */
if ((nfds = poll(pfds, nfds, 100)) == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
fatal("poll failed");
}
pfd = pfds;
log_debug("poll returned %d", nfds);
/* log_debug("poll returned %d", nfds); */
/* Handle server socket. */
#ifndef BROKEN_POLL
@ -271,7 +271,7 @@ server_fill_windows(struct pollfd **pfd)
(*pfd)->events = POLLIN;
if (BUFFER_USED(w->out) > 0)
(*pfd)->events |= POLLOUT;
log_debug("adding window %d (%d)", (*pfd)->fd, w->fd);
/* log_debug("adding window %d (%d)", (*pfd)->fd, w->fd); */
}
(*pfd)++;
}
@ -286,7 +286,7 @@ server_handle_windows(struct pollfd **pfd)
for (i = 0; i < ARRAY_LENGTH(&windows); i++) {
if ((w = ARRAY_ITEM(&windows, i)) != NULL && w->fd != -1) {
log_debug("testing window %d (%d)", (*pfd)->fd, w->fd);
/* log_debug("testing window %d (%d)", (*pfd)->fd, w->fd); */
if (buffer_poll(*pfd, w->in, w->out) != 0)
server_lost_window(w);
else
@ -303,6 +303,7 @@ server_check_redraw(struct client *c)
struct session *s;
struct screen_redraw_ctx ctx;
struct screen screen;
struct grid_cell gc;
u_int xx, yy, sx, sy;
char title[BUFSIZ];
int flags;
@ -344,8 +345,9 @@ server_check_redraw(struct client *c)
if (sx < xx)
screen_redraw_columns(&ctx, sx, xx - sx);
if (sy < yy) {
screen_fill_area(
&screen, 0, sy, xx, 1, '-', 0, 8, 8);
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.data = '-';
grid_view_fill(screen.grid, &gc, 0, sy, xx, 1);
screen_redraw_lines(&ctx, sy, yy - sy);
}
screen_redraw_stop(&ctx);
@ -423,7 +425,7 @@ server_fill_clients(struct pollfd **pfd)
(*pfd)->events = POLLIN;
if (BUFFER_USED(c->out) > 0)
(*pfd)->events |= POLLOUT;
log_debug("adding client %d (%d)", (*pfd)->fd, c->fd);
/* log_debug("adding client %d (%d)", (*pfd)->fd, c->fd); */
}
(*pfd)++;
@ -434,7 +436,7 @@ server_fill_clients(struct pollfd **pfd)
(*pfd)->events = POLLIN;
if (BUFFER_USED(c->tty.out) > 0)
(*pfd)->events |= POLLOUT;
log_debug("adding tty %d (%d)", (*pfd)->fd, c->tty.fd);
/* log_debug("adding tty %d (%d)", (*pfd)->fd, c->tty.fd); */
}
(*pfd)++;
}
@ -451,7 +453,7 @@ server_handle_clients(struct pollfd **pfd)
c = ARRAY_ITEM(&clients, i);
if (c != NULL) {
log_debug("testing client %d (%d)", (*pfd)->fd, c->fd);
/* log_debug("testing client %d (%d)", (*pfd)->fd, c->fd); */
if (buffer_poll(*pfd, c->in, c->out) != 0) {
server_lost_client(c);
(*pfd) += 2;
@ -462,7 +464,7 @@ server_handle_clients(struct pollfd **pfd)
(*pfd)++;
if (c != NULL && c->tty.fd != -1 && c->session != NULL) {
log_debug("testing tty %d (%d)", (*pfd)->fd, c->tty.fd);
/* log_debug("testing tty %d (%d)", (*pfd)->fd, c->tty.fd); */
if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0)
server_lost_client(c);
else
@ -594,12 +596,12 @@ server_handle_window(struct window *w)
action = options_get_number(&s->options, "bell-action");
switch (action) {
case BELL_ANY:
tty_write_session(s, TTY_CHARACTER, '\007');
tty_write_session(s, TTY_BELL);
break;
case BELL_CURRENT:
if (s->curw->window != w)
break;
tty_write_session(s, TTY_CHARACTER, '\007');
tty_write_session(s, TTY_BELL);
break;
}
update = 1;

135
status.c
View File

@ -1,4 +1,4 @@
/* $Id: status.c,v 1.45 2008-09-08 22:03:54 nicm Exp $ */
/* $Id: status.c,v 1.46 2008-09-25 20:08:54 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -25,7 +25,7 @@
#include "tmux.h"
size_t status_width(struct winlink *);
char *status_print(struct session *, struct winlink *, u_short *);
char *status_print(struct session *, struct winlink *, struct grid_cell *);
/* Draw status for client on the last lines of given context. */
void
@ -38,8 +38,7 @@ status_redraw(struct client *c)
char lbuf[BUFSIZ], rbuf[BUFSIZ];
size_t llen, rlen, offset, xx, yy;
size_t size, start, width;
u_short attr;
u_char fg, bg;
struct grid_cell gc;
struct tm *tm;
time_t t;
int larrow, rarrow;
@ -50,8 +49,8 @@ status_redraw(struct client *c)
if (gettimeofday(&c->status_timer, NULL) != 0)
fatal("gettimeofday");
fg = options_get_number(&s->options, "status-fg");
bg = options_get_number(&s->options, "status-bg");
gc.fg = options_get_number(&s->options, "status-fg");
gc.bg = options_get_number(&s->options, "status-bg");
yy = c->sy - 1;
if (yy == 0)
@ -138,24 +137,22 @@ draw:
/* Begin drawing and move to the starting position. */
screen_redraw_start_client(&ctx, c);
screen_redraw_set_attributes(&ctx, 0, fg, bg);
if (llen != 0) {
screen_redraw_move_cursor(&ctx, 0, yy);
screen_redraw_write_string(&ctx, "%s ", lbuf);
ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy);
screen_redraw_puts(&ctx, &gc, "%s ", lbuf);
if (larrow)
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
} else {
if (larrow)
screen_redraw_move_cursor(&ctx, 1, yy);
ctx.write(ctx.data, TTY_CURSORMOVE, 1, yy);
else
screen_redraw_move_cursor(&ctx, 0, yy);
ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy);
}
/* Draw each character in succession. */
offset = 0;
RB_FOREACH(wl, winlinks, &s->windows) {
text = status_print(s, wl, &attr);
screen_redraw_set_attributes(&ctx, attr, fg, bg);
text = status_print(s, wl, &gc);
if (larrow == 1 && offset < start) {
if (session_alert_has(s, wl, WINDOW_ACTIVITY))
@ -166,7 +163,7 @@ draw:
for (ptr = text; *ptr != '\0'; ptr++) {
if (offset >= start && offset < start + width)
ctx.write(ctx.data, TTY_CHARACTER, *ptr);
screen_redraw_putc(&ctx, &gc, *ptr);
offset++;
}
@ -177,10 +174,10 @@ draw:
rarrow = -1;
}
gc.attr &= ~GRID_ATTR_REVERSE;
if (offset < start + width) {
if (offset >= start) {
screen_redraw_set_attributes(&ctx, 0, fg, bg);
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
}
offset++;
}
@ -189,52 +186,50 @@ draw:
}
/* Fill the remaining space if any. */
screen_redraw_set_attributes(&ctx, 0, fg, bg);
while (offset++ < xx)
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
/* Draw the last item. */
if (rlen != 0) {
screen_redraw_move_cursor(&ctx, c->sx - rlen - 1, yy);
screen_redraw_write_string(&ctx, " %s", rbuf);
ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - rlen - 1, yy);
screen_redraw_puts(&ctx, &gc, " %s", rbuf);
}
/* Draw the arrows. */
if (larrow != 0) {
if (larrow == -1) {
screen_redraw_set_attributes(
&ctx, ATTR_REVERSE, fg, bg);
} else
screen_redraw_set_attributes(&ctx, 0, fg, bg);
if (llen != 0)
screen_redraw_move_cursor(&ctx, llen + 1, yy);
if (larrow == -1)
gc.attr |= GRID_ATTR_REVERSE;
else
screen_redraw_move_cursor(&ctx, 0, yy);
ctx.write(ctx.data, TTY_CHARACTER, '<');
gc.attr &= ~GRID_ATTR_REVERSE;
if (llen != 0)
ctx.write(ctx.data, TTY_CURSORMOVE, llen + 1, yy);
else
ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy);
screen_redraw_putc(&ctx, &gc, '<');
gc.attr &= ~GRID_ATTR_REVERSE;
}
if (rarrow != 0) {
if (rarrow == -1) {
screen_redraw_set_attributes(
&ctx, ATTR_REVERSE, fg, bg);
} else
screen_redraw_set_attributes(&ctx, 0, fg, bg);
if (rlen != 0)
screen_redraw_move_cursor(&ctx, c->sx - rlen - 2, yy);
if (rarrow == -1)
gc.attr |= GRID_ATTR_REVERSE;
else
screen_redraw_move_cursor(&ctx, c->sx - 1, yy);
ctx.write(ctx.data, TTY_CHARACTER, '>');
gc.attr &= ~GRID_ATTR_REVERSE;
if (rlen != 0)
ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - rlen - 2, yy);
else
ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - 1, yy);
screen_redraw_putc(&ctx, &gc, '>');
gc.attr &= ~GRID_ATTR_REVERSE;
}
screen_redraw_stop(&ctx);
return;
blank:
/* Just draw the whole line as blank. */
screen_redraw_start_client(&ctx, c);
screen_redraw_set_attributes(&ctx, 0, fg, bg);
screen_redraw_move_cursor(&ctx, 0, yy);
ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy);
for (offset = 0; offset < c->sx; offset++)
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
screen_redraw_stop(&ctx);
return;
@ -247,10 +242,9 @@ off:
screen_redraw_start_client(&ctx, c);
/* If the screen is too small, use blank. */
if (screen_size_y(c->session->curw->window->screen) < c->sy) {
screen_redraw_move_cursor(&ctx, 0, c->sy - 1);
screen_redraw_set_attributes(&ctx, 0, 8, 8);
ctx.write(ctx.data, TTY_CURSORMOVE, 0, c->sy - 1);
for (offset = 0; offset < c->sx; offset++)
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
} else
screen_redraw_lines(&ctx, c->sy - 1, 1);
screen_redraw_stop(&ctx);
@ -276,7 +270,7 @@ status_width(struct winlink *wl)
}
char *
status_print(struct session *s, struct winlink *wl, u_short *attr)
status_print(struct session *s, struct winlink *wl, struct grid_cell *gc)
{
char *text, flag;
@ -286,14 +280,14 @@ status_print(struct session *s, struct winlink *wl, u_short *attr)
if (wl == s->curw)
flag = '*';
*attr = 0;
gc->attr &= ~GRID_ATTR_REVERSE;
if (session_alert_has(s, wl, WINDOW_ACTIVITY)) {
flag = '#';
*attr = ATTR_REVERSE;
gc->attr |= GRID_ATTR_REVERSE;
}
if (session_alert_has(s, wl, WINDOW_BELL)) {
flag = '!';
*attr = ATTR_REVERSE;
gc->attr |= GRID_ATTR_REVERSE;
}
xasprintf(&text, "%d:%s%c", wl->idx, wl->window->name, flag);
@ -306,6 +300,7 @@ status_message_redraw(struct client *c)
{
struct screen_redraw_ctx ctx;
size_t xx, yy;
struct grid_cell gc;
if (c->sx == 0 || c->sy == 0)
return;
@ -315,16 +310,19 @@ status_message_redraw(struct client *c)
xx = c->sx;
yy = c->sy - 1;
screen_redraw_start_client(&ctx, c);
screen_redraw_set_attributes(&ctx, ATTR_REVERSE, 8, 8);
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.attr |= GRID_ATTR_REVERSE;
screen_redraw_move_cursor(&ctx, 0, yy);
screen_redraw_write_string(&ctx, "%.*s", (int) xx, c->message_string);
screen_redraw_start_client(&ctx, c);
ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy);
screen_redraw_puts(&ctx, &gc, "%.*s", (int) xx, c->message_string);
for (; xx < c->sx; xx++)
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
screen_redraw_stop(&ctx);
tty_write_client(c, TTY_CURSOROFF);
tty_write_client(c, TTY_CURSORMODE, 0);
}
/* Draw client prompt on status line of present else on last line. */
@ -334,6 +332,7 @@ status_prompt_redraw(struct client *c)
struct screen_redraw_ctx ctx;
size_t i, xx, yy, left, size, offset;
char ch;
struct grid_cell gc;
if (c->sx == 0 || c->sy == 0)
return;
@ -344,11 +343,13 @@ status_prompt_redraw(struct client *c)
xx = c->sx;
yy = c->sy - 1;
screen_redraw_start_client(&ctx, c);
screen_redraw_set_attributes(&ctx, ATTR_REVERSE, 8, 8);
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.attr |= GRID_ATTR_REVERSE;
screen_redraw_move_cursor(&ctx, 0, yy);
screen_redraw_write_string(&ctx, "%.*s", (int) xx, c->prompt_string);
screen_redraw_start_client(&ctx, c);
ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy);
screen_redraw_puts(&ctx, &gc, "%.*s", (int) xx, c->prompt_string);
left = c->sx - xx;
if (left != 0) {
@ -360,29 +361,29 @@ status_prompt_redraw(struct client *c)
left--;
size = left;
}
screen_redraw_write_string(
&ctx, "%.*s", (int) left, c->prompt_buffer + offset);
screen_redraw_puts(
&ctx, &gc, "%.*s", (int) left, c->prompt_buffer + offset);
for (i = xx + size; i < c->sx; i++) {
ctx.write(ctx.data, TTY_CHARACTER, ' ');
screen_redraw_putc(&ctx, &gc, ' ');
ctx.s->cx++;
}
}
/* Draw a fake cursor. */
screen_redraw_set_attributes(&ctx, 0, 8, 8);
screen_redraw_move_cursor(&ctx, xx + c->prompt_index - offset, yy);
ctx.write(ctx.data, TTY_CURSORMOVE, xx + c->prompt_index - offset, yy);
if (c->prompt_index == strlen(c->prompt_buffer))
ch = ' ';
else
ch = c->prompt_buffer[c->prompt_index];
if (ch == '\0')
ch = ' ';
tty_write_client(c, TTY_CHARACTER, ch);
gc.attr &= ~GRID_ATTR_REVERSE;
screen_redraw_putc(&ctx, &gc, ch);
screen_redraw_stop(&ctx);
tty_write_client(c, TTY_CURSOROFF);
tty_write_client(c, TTY_CURSORMODE, 0);
}
/* Handle keys in prompt. */

11
tmux.1
View File

@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.48 2008-06-30 18:27:14 nicm Exp $
.\" $Id: tmux.1,v 1.49 2008-09-25 20:08:56 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@ -668,6 +668,15 @@ maintain this maximum length.
Set the maximum number of lines held in window history.
This setting applies only to new windows - existing window histories are not
resized and retain the limit at the point they were created.
.It Xo Ic mode-keys
.Op Ic vi | Ic emacs
.Xc
Use
.Xr vi 1 -
or
.Xr emacs 1 -
style key bindings in scroll and copy modes.
Key bindings default to emacs.
.It Ic prefix Ar key
Set the current prefix key.
.It Xo Ic remain-by-default

12
tmux.c
View File

@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.75 2008-09-09 22:16:37 nicm Exp $ */
/* $Id: tmux.c,v 1.76 2008-09-25 20:08:56 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -62,7 +62,7 @@ __dead void
usage(void)
{
fprintf(stderr,
"usage: %s [-qVv] [-f file] [-S socket-path] [command [flags]]\n",
"usage: %s [-2dquVv] [-f file] [-S socket-path] [command [flags]]\n",
__progname);
exit(1);
}
@ -179,8 +179,11 @@ main(int argc, char **argv)
flags = 0;
path = NULL;
while ((opt = getopt(argc, argv, "f:qS:uVv")) != EOF) {
while ((opt = getopt(argc, argv, "2df:qS:uVv")) != EOF) {
switch (opt) {
case '2':
flags |= IDENTIFY_256COLOURS;
break;
case 'f':
cfg_file = xstrdup(optarg);
break;
@ -193,6 +196,9 @@ main(int argc, char **argv)
case 'u':
flags |= IDENTIFY_UTF8;
break;
case 'd':
flags |= IDENTIFY_HASDEFAULTS;
break;
case 'v':
debug_level++;
break;

379
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.188 2008-09-10 19:15:04 nicm Exp $ */
/* $Id: tmux.h,v 1.189 2008-09-25 20:08:56 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -19,7 +19,7 @@
#ifndef TMUX_H
#define TMUX_H
#define PROTOCOL_VERSION -2
#define PROTOCOL_VERSION -3
/* Shut up gcc warnings about empty if bodies. */
#define RB_AUGMENT(x) do {} while (0)
@ -321,28 +321,32 @@ struct buffer {
#define KEYC_KP4_2 (KEYC_OFFSET + 0x10f)
/* Output codes. */
#define TTY_CHARACTER 0
#define TTY_CURSORUP 1
#define TTY_CURSORDOWN 2
#define TTY_CURSORRIGHT 3
#define TTY_CURSORLEFT 4
#define TTY_INSERTCHARACTER 5
#define TTY_DELETECHARACTER 6
#define TTY_INSERTLINE 7
#define TTY_DELETELINE 8
#define TTY_CLEARLINE 9
#define TTY_CLEARENDOFLINE 10
#define TTY_CLEARSTARTOFLINE 11
#define TTY_CURSORMOVE 12
#define TTY_ATTRIBUTES 13
#define TTY_CURSOROFF 14
#define TTY_CURSORON 15
#define TTY_REVERSEINDEX 16
#define TTY_SCROLLREGION 17
#define TTY_INSERTON 18
#define TTY_INSERTOFF 19
#define TTY_MOUSEON 20
#define TTY_MOUSEOFF 21 /* XXX merge all on/off into 1 arg? */
#define TTY_CURSORUP 0
#define TTY_CURSORDOWN 1
#define TTY_CURSORRIGHT 2
#define TTY_CURSORLEFT 3
#define TTY_INSERTCHARACTER 4
#define TTY_DELETECHARACTER 5
#define TTY_INSERTLINE 6
#define TTY_DELETELINE 7
#define TTY_CLEARLINE 8
#define TTY_CLEARENDOFLINE 9
#define TTY_CLEARSTARTOFLINE 10
#define TTY_CURSORMOVE 11
#define TTY_CURSORMODE 12
#define TTY_REVERSEINDEX 13
#define TTY_SCROLLREGION 14
#define TTY_INSERTMODE 15
#define TTY_MOUSEMODE 16
#define TTY_LINEFEED 17
#define TTY_CARRIAGERETURN 18
#define TTY_BELL 19
#define TTY_KCURSORMODE 20
#define TTY_KKEYPADMODE 21
#define TTY_CLEARENDOFSCREEN 22
#define TTY_CLEARSTARTOFSCREEN 23
#define TTY_CLEARSCREEN 24
#define TTY_CELL 25
/* Message codes. */
enum hdrtype {
@ -376,6 +380,8 @@ struct msg_identify_data {
int version;
#define IDENTIFY_UTF8 0x1
#define IDENTIFY_256COLOURS 0x2
#define IDENTIFY_HASDEFAULTS 0x4
int flags;
u_int sx;
@ -389,45 +395,52 @@ struct msg_resize_data {
u_int sy;
};
/* UTF8 data. */
struct utf8_data {
u_char data[4];
};
struct utf8_table {
u_int limit;
ARRAY_DECL(, struct utf8_data) array;
};
#define UTF8_LIMIT ((1<<11) - 1)
/* Attributes. */
#define ATTR_BRIGHT 0x1
#define ATTR_DIM 0x2
#define ATTR_UNDERSCORE 0x4
#define ATTR_BLINK 0x8
#define ATTR_REVERSE 0x10
#define ATTR_HIDDEN 0x20
#define ATTR_ITALICS 0x40
#define ATTR_CHARSET 0x80 /* alternative character set */
#define ATTR_FG256 0x100
#define ATTR_BG256 0x200
#define ATTR_UTF8 0x400
#define ATTR_PAD 0x800
#define ATTR_UTF8b8 0x8000
#define ATTR_UTF8b9 0x4000
#define ATTR_UTF8b10 0x2000
#define ATTR_UTF8b11 0x1000
/* Modes. */
#define MODE_CURSOR 0x1
#define MODE_INSERT 0x2
#define MODE_KCURSOR 0x4
#define MODE_KKEYPAD 0x8
#define MODE_SAVED 0x10
#define MODE_MOUSE 0x20
#define MODE_MOUSE 0x10
/* Grid output. */
#define GRID_DEBUG(gd, fmt, ...) log_debug3("%s: (sx=%u, sy=%u, hsize=%u) " \
fmt, __func__, (gd)->sx, (gd)->sy, (gd)->hsize, ## __VA_ARGS__)
/* Grid attributes. */
#define GRID_ATTR_BRIGHT 0x1
#define GRID_ATTR_DIM 0x2
#define GRID_ATTR_UNDERSCORE 0x4
#define GRID_ATTR_BLINK 0x8
#define GRID_ATTR_REVERSE 0x10
#define GRID_ATTR_HIDDEN 0x20
#define GRID_ATTR_ITALICS 0x40
#define GRID_ATTR_CHARSET 0x80 /* alternative character set */
/* Grid flags. */
#define GRID_FLAG_FG256 0x1
#define GRID_FLAG_BG256 0x2
#define GRID_FLAG_PADDING 0x4
/* Grid cell. */
struct grid_cell {
u_short data;
u_char attr;
u_char flags;
u_char fg;
u_char bg;
} __packed;
/* Grid data. */
struct grid_data {
u_int sx;
u_int sy;
u_int hsize;
u_int hlimit;
u_int *size;
struct grid_cell **data;
};
/* Screen selection. */
struct screen_sel {
@ -444,34 +457,13 @@ struct screen_sel {
struct screen {
char *title;
u_char **grid_data;
u_short **grid_attr;
u_char **grid_fg;
u_char **grid_bg;
u_int *grid_size;
u_int dx; /* display x size */
u_int dy; /* display y size */
u_int hsize; /* history y size */
u_int hlimit; /* history y limit */
u_int rupper; /* scroll region top */
u_int rlower; /* scroll region bottom */
struct grid_data *grid; /* grid data */
u_int cx; /* cursor x */
u_int cy; /* cursor y */
u_short attr;
u_char fg;
u_char bg;
struct utf8_table utf8_table;
u_int saved_cx;
u_int saved_cy;
u_short saved_attr;
u_char saved_fg;
u_char saved_bg;
u_int rupper; /* scroll region top */
u_int rlower; /* scroll region bottom */
int mode;
@ -497,51 +489,11 @@ struct screen_write_ctx {
struct screen *s;
};
/* Screen display access macros. */
#define screen_x(s, x) (x)
#define screen_y(s, y) ((s)->hsize + y)
#define screen_last_x(s) ((s)->dx - 1)
#define screen_last_y(s) ((s)->dy - 1)
#define screen_size_x(s) ((s)->dx)
#define screen_size_y(s) ((s)->dy)
#define screen_in_x(s, x) ((x) < screen_size_x(s))
#define screen_in_y(s, y) ((y) < screen_size_y(s))
#define screen_in_region(s, y) ((y) >= (s)->rupper && (y) <= (s)->rlower)
/* These are inclusive... */
#define screen_left_x(s, x) ((x) + 1)
#define screen_right_x(s, x) \
((x) < screen_size_x(s) ? screen_size_x(s) - (x) : 0)
#define screen_above_y(s, y) ((y) + 1)
#define screen_below_y(s, y) \
((y) < screen_size_y(s) ? screen_size_y(s) - (y) : 0)
#define SCREEN_DEBUG(s) do { \
log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u", __func__, \
s->cx, s->cy, screen_size_x(s), screen_size_y(s)); \
} while (0)
#define SCREEN_DEBUG1(s, n) do { \
log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u", __func__, \
s->cx, s->cy, screen_size_x(s), screen_size_y(s), n); \
} while (0)
#define SCREEN_DEBUG2(s, n, m) do { \
log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u", __func__, \
s->cx, s->cy, screen_size_x(s), screen_size_y(s), n, m); \
} while (0)
#define SCREEN_DEBUG3(s, n, m, o) do { \
log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u o=%u", \
__func__, s->cx, s->cy, screen_size_x(s), screen_size_y(s), \
n, m, o); \
} while (0)
#define SCREEN_DEBUG4(s, n, m, o, p) do { \
log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u o=%u p=%u", \
__func__, s->cx, s->cy, screen_size_x(s), screen_size_y(s), \
n, m, o, p); \
} while (0)
/* Screen size. */
#define screen_size_x(s) ((s)->grid->sx)
#define screen_size_y(s) ((s)->grid->sy)
#define screen_hsize(s) ((s)->grid->hsize)
#define screen_hlimit(s) ((s)->grid->hlimit)
/* Input parser sequence argument. */
struct input_arg {
@ -558,6 +510,12 @@ struct input_ctx {
size_t len;
size_t off;
struct grid_cell cell; /* current cell data */
struct grid_cell saved_cell;
u_int saved_cx;
u_int saved_cy;
#define MAXSTRINGLEN 1024
u_char *string_buf;
size_t string_len;
@ -566,7 +524,7 @@ struct input_ctx {
#define STRING_NAME 1
#define STRING_IGNORE 2
struct utf8_data utf8_buf;
u_char utf8_buf[4];
u_int utf8_len;
u_int utf8_off;
@ -725,9 +683,7 @@ struct tty {
struct termios tio;
u_short attr;
u_char fg;
u_char bg;
struct grid_cell cell;
u_char acs[UCHAR_MAX + 1];
@ -737,6 +693,8 @@ struct tty {
#define TTY_UTF8 0x8
int flags;
int term_flags;
struct timeval key_timer;
size_t ksize; /* maximum key size */
@ -1175,65 +1133,85 @@ void input_key(struct window *, int);
const char *colour_tostring(u_char);
u_char colour_fromstring(const char *);
/* screen-display.c */
void screen_display_get_cell(struct screen *,
u_int, u_int, u_char *, u_short *, u_char *, u_char *);
void screen_display_set_cell(
struct screen *, u_int, u_int, u_char, u_short, u_char, u_char);
void screen_display_make_lines(struct screen *, u_int, u_int);
void screen_display_free_lines(struct screen *, u_int, u_int);
void screen_display_move_lines(struct screen *, u_int, u_int, u_int);
void screen_display_fill_area(struct screen *,
u_int, u_int, u_int, u_int, u_char, u_short, u_char, u_char);
void screen_display_scroll_region_up(struct screen *);
void screen_display_scroll_region_down(struct screen *);
void screen_display_insert_lines(struct screen *, u_int, u_int);
void screen_display_insert_lines_region(struct screen *, u_int, u_int);
void screen_display_delete_lines(struct screen *, u_int, u_int);
void screen_display_delete_lines_region(struct screen *, u_int, u_int);
void screen_display_insert_characters(struct screen *, u_int, u_int, u_int);
void screen_display_delete_characters(struct screen *, u_int, u_int, u_int);
void screen_display_copy_area(struct screen *, struct screen *,
u_int, u_int, u_int, u_int, u_int, u_int);
/* grid.c */
extern const struct grid_cell grid_default_cell;
struct grid_data *grid_create(u_int, u_int, u_int);
void grid_destroy(struct grid_data *);
void grid_reduce_line(struct grid_data *, u_int, u_int);
void grid_expand_line(struct grid_data *, u_int, u_int);
void grid_scroll_line(struct grid_data *);
const struct grid_cell *grid_peek_cell(struct grid_data *, u_int, u_int);
struct grid_cell *grid_get_cell(struct grid_data *, u_int, u_int);
void grid_set_cell(
struct grid_data *, u_int, u_int, const struct grid_cell *);
void grid_clear(struct grid_data *, u_int, u_int, u_int, u_int);
void grid_fill(struct grid_data *,
const struct grid_cell *, u_int, u_int, u_int, u_int);
void grid_fill_lines(
struct grid_data *, const struct grid_cell *, u_int, u_int);
void grid_clear_lines(struct grid_data *, u_int, u_int);
void grid_move_lines(struct grid_data *, u_int, u_int, u_int);
void grid_clear_cells(struct grid_data *, u_int, u_int, u_int);
void grid_move_cells(struct grid_data *, u_int, u_int, u_int, u_int);
/* grid-view.c */
const struct grid_cell *grid_view_peek_cell(struct grid_data *, u_int, u_int);
struct grid_cell *grid_view_get_cell(struct grid_data *, u_int, u_int);
void grid_view_set_cell(
struct grid_data *, u_int, u_int, const struct grid_cell *);
void grid_view_clear(struct grid_data *, u_int, u_int, u_int, u_int);
void grid_view_fill(struct grid_data *,
const struct grid_cell *, u_int, u_int, u_int, u_int);
void grid_view_scroll_region_up(struct grid_data *, u_int, u_int);
void grid_view_scroll_region_down(struct grid_data *, u_int, u_int);
void grid_view_insert_lines(struct grid_data *, u_int, u_int);
void grid_view_insert_lines_region(
struct grid_data *, u_int, u_int, u_int, u_int);
void grid_view_delete_lines(struct grid_data *, u_int, u_int);
void grid_view_delete_lines_region(
struct grid_data *, u_int, u_int, u_int, u_int);
void grid_view_insert_cells(struct grid_data *, u_int, u_int, u_int);
void grid_view_delete_cells(struct grid_data *, u_int, u_int, u_int);
/* screen-write.c */
void screen_write_start_window(struct screen_write_ctx *, struct window *);
void screen_write_start_client(struct screen_write_ctx *, struct client *);
void screen_write_start_session(
struct screen_write_ctx *, struct session *);
struct screen_write_ctx *, struct session *);
void screen_write_start(struct screen_write_ctx *,
struct screen *, void (*)(void *, int, ...), void *);
struct screen *, void (*)(void *, int, ...), void *);
void screen_write_stop(struct screen_write_ctx *);
void screen_write_set_title(struct screen_write_ctx *, char *);
void screen_write_put_character(struct screen_write_ctx *, u_char);
void screen_write_put_utf8(struct screen_write_ctx *, struct utf8_data *);
size_t printflike2 screen_write_put_string_rjust(
struct screen_write_ctx *, const char *, ...);
void printflike2 screen_write_put_string(
struct screen_write_ctx *, const char *, ...);
void screen_write_set_attributes(
struct screen_write_ctx *, u_short, u_char, u_char);
void screen_write_set_region(struct screen_write_ctx *, u_int, u_int);
void screen_write_cursor_up_scroll(struct screen_write_ctx *);
void screen_write_cursor_down_scroll(struct screen_write_ctx *);
void screen_write_cursor_up(struct screen_write_ctx *, u_int);
void screen_write_cursor_down(struct screen_write_ctx *, u_int);
void screen_write_cursor_left(struct screen_write_ctx *, u_int);
void screen_write_cursor_right(struct screen_write_ctx *, u_int);
void screen_write_delete_lines(struct screen_write_ctx *, u_int);
void screen_write_delete_characters(struct screen_write_ctx *, u_int);
void screen_write_insert_lines(struct screen_write_ctx *, u_int);
void screen_write_insert_characters(struct screen_write_ctx *, u_int);
void screen_write_move_cursor(struct screen_write_ctx *, u_int, u_int);
void screen_write_fill_end_of_screen(struct screen_write_ctx *);
void screen_write_fill_screen(struct screen_write_ctx *);
void screen_write_fill_end_of_line(struct screen_write_ctx *);
void screen_write_fill_start_of_line(struct screen_write_ctx *);
void screen_write_fill_line(struct screen_write_ctx *);
void screen_write_set_mode(struct screen_write_ctx *, int);
void screen_write_clear_mode(struct screen_write_ctx *, int);
void screen_write_copy_area(struct screen_write_ctx *,
struct screen *, u_int, u_int, u_int, u_int);
void printflike3 screen_write_puts(
struct screen_write_ctx *, struct grid_cell *, const char *, ...);
void screen_write_putc(
struct screen_write_ctx *, struct grid_cell *, u_char);
void screen_write_copy(struct screen_write_ctx *,
struct screen *, u_int, u_int, u_int, u_int);
void screen_write_cursorup(struct screen_write_ctx *, u_int);
void screen_write_cursordown(struct screen_write_ctx *, u_int);
void screen_write_cursorright(struct screen_write_ctx *, u_int);
void screen_write_cursorleft(struct screen_write_ctx *, u_int);
void screen_write_insertcharacter(struct screen_write_ctx *, u_int);
void screen_write_deletecharacter(struct screen_write_ctx *, u_int);
void screen_write_insertline(struct screen_write_ctx *, u_int);
void screen_write_deleteline(struct screen_write_ctx *, u_int);
void screen_write_clearline(struct screen_write_ctx *);
void screen_write_clearendofline(struct screen_write_ctx *);
void screen_write_clearstartofline(struct screen_write_ctx *);
void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int);
void screen_write_cursormode(struct screen_write_ctx *, int);
void screen_write_reverseindex(struct screen_write_ctx *);
void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int);
void screen_write_insertmode(struct screen_write_ctx *, int);
void screen_write_mousemode(struct screen_write_ctx *, int);
void screen_write_linefeed(struct screen_write_ctx *);
void screen_write_carriagereturn(struct screen_write_ctx *);
void screen_write_kcursormode(struct screen_write_ctx *, int);
void screen_write_kkeypadmode(struct screen_write_ctx *, int);
void screen_write_clearendofscreen(struct screen_write_ctx *);
void screen_write_clearstartofscreen(struct screen_write_ctx *);
void screen_write_clearscreen(struct screen_write_ctx *);
void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *);
/* screen-redraw.c */
void screen_redraw_start_window(struct screen_redraw_ctx *, struct window *);
@ -1243,14 +1221,11 @@ void screen_redraw_start_session(
void screen_redraw_start(struct screen_redraw_ctx *,
struct screen *, void (*)(void *, int, ...), void *);
void screen_redraw_stop(struct screen_redraw_ctx *);
void screen_redraw_move_cursor(struct screen_redraw_ctx *, u_int, u_int);
void screen_redraw_set_attributes(
struct screen_redraw_ctx *, u_short, u_char, u_char);
void printflike2 screen_redraw_write_string(
struct screen_redraw_ctx *, const char *, ...);
void printflike3 screen_redraw_puts(
struct screen_redraw_ctx *, struct grid_cell *, const char *, ...);
void screen_redraw_putc(
struct screen_redraw_ctx *, struct grid_cell *, u_char);
void screen_redraw_cell(struct screen_redraw_ctx *, u_int, u_int);
void screen_redraw_area(
struct screen_redraw_ctx *, u_int, u_int, u_int, u_int);
void screen_redraw_lines(struct screen_redraw_ctx *, u_int, u_int);
void screen_redraw_columns(struct screen_redraw_ctx *, u_int, u_int);
@ -1258,21 +1233,13 @@ void screen_redraw_columns(struct screen_redraw_ctx *, u_int, u_int);
void screen_init(struct screen *, u_int, u_int, u_int);
void screen_reinit(struct screen *);
void screen_free(struct screen *);
void screen_set_title(struct screen *, const char *);
void screen_resize(struct screen *, u_int, u_int);
void screen_expand_line(struct screen *, u_int, u_int);
void screen_reduce_line(struct screen *, u_int, u_int);
void screen_get_cell(struct screen *,
u_int, u_int, u_char *, u_short *, u_char *, u_char *);
void screen_set_cell(
struct screen *, u_int, u_int, u_char, u_short, u_char, u_char);
void screen_make_lines(struct screen *, u_int, u_int);
void screen_free_lines(struct screen *, u_int, u_int);
void screen_move_lines(struct screen *, u_int, u_int, u_int);
void screen_fill_area(struct screen *,
u_int, u_int, u_int, u_int, u_char, u_short, u_char, u_char);
void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int);
void screen_clear_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
void screen_display_copy_area(struct screen *, struct screen *,
u_int, u_int, u_int, u_int, u_int, u_int);
/* window.c */
extern struct windows windows;
@ -1328,13 +1295,9 @@ int session_select(struct session *, int);
int session_last(struct session *);
/* utf8.c */
void utf8_pack(int, u_char *, u_short *);
int utf8_unpack(u_char, u_short);
void utf8_init(struct utf8_table *, int);
void utf8_free(struct utf8_table *);
struct utf8_data *utf8_lookup(struct utf8_table *, int);
int utf8_search(struct utf8_table *, struct utf8_data *);
int utf8_add(struct utf8_table *, struct utf8_data *);
u_int utf8_combine(const u_char [4]);
void utf8_split(u_int, u_char [4]);
int utf8_width(u_int);
/* buffer.c */
struct buffer *buffer_create(size_t);

804
tty.c
View File

@ -1,4 +1,4 @@
/* $Id: tty.c,v 1.42 2008-09-23 17:54:35 nicm Exp $ */
/* $Id: tty.c,v 1.43 2008-09-25 20:08:56 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -39,10 +39,64 @@ void tty_raw(struct tty *, const char *);
void tty_puts(struct tty *, const char *);
void tty_putc(struct tty *, char);
void tty_attributes(struct tty *, u_short, u_char, u_char);
u_char tty_attributes_fg(struct tty *, u_char);
u_char tty_attributes_bg(struct tty *, u_char);
char tty_translate(char);
void tty_reset(struct tty *);
void tty_attributes(struct tty *, const struct grid_cell *);
void tty_attributes_fg(struct tty *, const struct grid_cell *);
void tty_attributes_bg(struct tty *, const struct grid_cell *);
void tty_cmd_cursorup(struct tty *, struct screen *, va_list);
void tty_cmd_cursordown(struct tty *, struct screen *, va_list);
void tty_cmd_cursorright(struct tty *, struct screen *, va_list);
void tty_cmd_cursorleft(struct tty *, struct screen *, va_list);
void tty_cmd_insertcharacter(struct tty *, struct screen *, va_list);
void tty_cmd_deletecharacter(struct tty *, struct screen *, va_list);
void tty_cmd_insertline(struct tty *, struct screen *, va_list);
void tty_cmd_deleteline(struct tty *, struct screen *, va_list);
void tty_cmd_clearline(struct tty *, struct screen *, va_list);
void tty_cmd_clearendofline(struct tty *, struct screen *, va_list);
void tty_cmd_clearstartofline(struct tty *, struct screen *, va_list);
void tty_cmd_cursormove(struct tty *, struct screen *, va_list);
void tty_cmd_cursormode(struct tty *, struct screen *, va_list);
void tty_cmd_reverseindex(struct tty *, struct screen *, va_list);
void tty_cmd_scrollregion(struct tty *, struct screen *, va_list);
void tty_cmd_insertmode(struct tty *, struct screen *, va_list);
void tty_cmd_mousemode(struct tty *, struct screen *, va_list);
void tty_cmd_linefeed(struct tty *, struct screen *, va_list);
void tty_cmd_carriagereturn(struct tty *, struct screen *, va_list);
void tty_cmd_bell(struct tty *, struct screen *, va_list);
void tty_cmd_clearendofscreen(struct tty *, struct screen *, va_list);
void tty_cmd_clearstartofscreen(struct tty *, struct screen *, va_list);
void tty_cmd_clearscreen(struct tty *, struct screen *, va_list);
void tty_cmd_cell(struct tty *, struct screen *, va_list);
void (*tty_cmds[])(struct tty *, struct screen *, va_list) = {
tty_cmd_cursorup,
tty_cmd_cursordown,
tty_cmd_cursorright,
tty_cmd_cursorleft,
tty_cmd_insertcharacter,
tty_cmd_deletecharacter,
tty_cmd_insertline,
tty_cmd_deleteline,
tty_cmd_clearline,
tty_cmd_clearendofline,
tty_cmd_clearstartofline,
tty_cmd_cursormove,
tty_cmd_cursormode,
tty_cmd_reverseindex,
tty_cmd_scrollregion,
tty_cmd_insertmode,
tty_cmd_mousemode,
tty_cmd_linefeed,
tty_cmd_carriagereturn,
tty_cmd_bell,
NULL,
NULL,
tty_cmd_clearendofscreen,
tty_cmd_clearstartofscreen,
tty_cmd_clearscreen,
tty_cmd_cell,
};
TAILQ_HEAD(, tty_term) tty_terms = TAILQ_HEAD_INITIALIZER(tty_terms);
@ -55,6 +109,7 @@ tty_init(struct tty *tty, char *path, char *term)
else
tty->termname = xstrdup(term);
tty->flags = 0;
tty->term_flags = 0;
}
int
@ -74,9 +129,9 @@ tty_open(struct tty *tty, char **cause)
if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1)
fatal("fcntl");
if (debug_level > 3) {
if (debug_level > 3)
tty->log_fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644);
} else
else
tty->log_fd = -1;
if ((tty->term = tty_find_term(tty->termname, tty->fd, cause)) == NULL)
@ -86,10 +141,7 @@ tty_open(struct tty *tty, char **cause)
tty->out = buffer_create(BUFSIZ);
tty->flags &= TTY_UTF8;
tty->attr = 0;
tty->fg = 8;
tty->bg = 8;
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell);
if (tcgetattr(tty->fd, &tty->tio) != 0)
fatal("tcgetattr failed");
@ -163,15 +215,17 @@ tty_close(struct tty *tty)
fatal("tcsetattr failed");
tty_raw(tty, tparm(change_scroll_region, 0, ws.ws_row - 1));
if (exit_alt_charset_mode != NULL)
tty_puts(tty, exit_alt_charset_mode);
if (exit_attribute_mode != NULL)
tty_raw(tty, exit_attribute_mode);
tty_raw(tty, clear_screen);
if (keypad_local != NULL)
tty_raw(tty, keypad_local);
if (exit_ca_mode != NULL)
tty_raw(tty, exit_ca_mode);
tty_raw(tty, clear_screen);
if (cursor_normal != NULL)
tty_raw(tty, cursor_normal);
if (exit_attribute_mode != NULL)
tty_raw(tty, exit_attribute_mode);
}
tty_free_term(tty->term);
@ -405,7 +459,7 @@ tty_puts(struct tty *tty, const char *s)
void
tty_putc(struct tty *tty, char ch)
{
if (tty->attr & ATTR_CHARSET)
if (tty->cell.attr & GRID_ATTR_CHARSET)
ch = tty_get_acs(tty, ch);
buffer_write8(tty->out, ch);
@ -429,10 +483,6 @@ tty_set_title(struct tty *tty, const char *title)
void
tty_vwrite(struct tty *tty, struct screen *s, int cmd, va_list ap)
{
struct utf8_data *udat;
char ch;
u_int i, ua, ub, uc;
if (tty->flags & TTY_FREEZE)
return;
@ -440,273 +490,493 @@ tty_vwrite(struct tty *tty, struct screen *s, int cmd, va_list ap)
return;
set_curterm(tty->term->term);
switch (cmd) {
case TTY_CHARACTER:
ch = va_arg(ap, int);
if (tty->attr & ATTR_PAD)
break;
if (tty_cmds[cmd] != NULL)
tty_cmds[cmd](tty, s, ap);
}
if ((tty->attr & ATTR_UTF8) && (tty->flags & TTY_UTF8)) {
udat = utf8_lookup(
&s->utf8_table, utf8_unpack(ch, tty->attr));
if (udat == NULL)
ch = '_';
else {
if (udat->data[0] == 0xff)
break;
tty_putc(tty, udat->data[0]);
if (udat->data[1] == 0xff)
break;
tty_putc(tty, udat->data[1]);
if (udat->data[2] == 0xff)
break;
tty_putc(tty, udat->data[2]);
if (udat->data[3] == 0xff)
break;
tty_putc(tty, udat->data[3]);
break;
}
} else if (tty->attr & ATTR_UTF8)
ch = '_';
void
tty_cmd_cursorup(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
switch (ch) {
case '\n': /* LF */
tty_putc(tty, '\n');
break;
case '\r': /* CR */
tty_puts(tty, carriage_return);
break;
case '\007': /* BEL */
if (bell != NULL)
tty_puts(tty, bell);
break;
case '\010': /* BS */
tty_puts(tty, cursor_left);
break;
default:
tty_putc(tty, ch);
break;
}
break;
case TTY_CURSORUP:
ua = va_arg(ap, u_int);
if (parm_up_cursor != NULL)
tty_puts(tty, tparm(parm_up_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_up);
}
break;
case TTY_CURSORDOWN:
ua = va_arg(ap, u_int);
if (parm_down_cursor != NULL)
tty_puts(tty, tparm(parm_down_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_down);
}
break;
case TTY_CURSORRIGHT:
ua = va_arg(ap, u_int);
if (parm_right_cursor != NULL)
tty_puts(tty, tparm(parm_right_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_right);
}
break;
case TTY_CURSORLEFT:
ua = va_arg(ap, u_int);
if (parm_left_cursor != NULL)
tty_puts(tty, tparm(parm_left_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_left);
}
break;
case TTY_CURSORMOVE:
ua = va_arg(ap, u_int);
ub = va_arg(ap, u_int);
tty_puts(tty, tparm(cursor_address, ua, ub));
break;
case TTY_CLEARENDOFLINE:
if (clr_eol != NULL)
tty_puts(tty, clr_eol);
else {
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
for (i = s->cx; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
break;
case TTY_CLEARSTARTOFLINE:
if (clr_bol != NULL)
tty_puts(tty, clr_bol);
else {
tty_puts(tty, tparm(cursor_address, s->cy, 0));
for (i = 0; i < s->cx + 1; i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
break;
case TTY_CLEARLINE:
if (clr_eol != NULL) {
tty_puts(tty, tparm(cursor_address, s->cy, 0));
tty_puts(tty, clr_eol);
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
} else {
tty_puts(tty, tparm(cursor_address, s->cy, 0));
for (i = 0; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
break;
case TTY_INSERTLINE:
ua = va_arg(ap, u_int);
if (parm_insert_line != NULL)
tty_puts(tty, tparm(parm_insert_line, ua));
else {
while (ua-- > 0)
tty_puts(tty, insert_line);
}
break;
case TTY_DELETELINE:
ua = va_arg(ap, u_int);
if (parm_delete_line != NULL)
tty_puts(tty, tparm(parm_delete_line, ua));
else {
while (ua-- > 0)
tty_puts(tty, delete_line);
}
break;
case TTY_INSERTCHARACTER:
ua = va_arg(ap, u_int);
if (parm_ich != NULL)
tty_puts(tty, tparm(parm_ich, ua));
else if (insert_character != NULL) {
while (ua-- > 0)
tty_puts(tty, insert_character);
} else if (enter_insert_mode != NULL) {
tty_puts(tty, enter_insert_mode);
while (ua-- > 0)
tty_putc(tty, ' ');
tty_puts(tty, exit_insert_mode);
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
break;
case TTY_DELETECHARACTER:
ua = va_arg(ap, u_int);
if (parm_dch != NULL)
tty_puts(tty, tparm(parm_dch, ua));
else if (delete_character != NULL) {
while (ua-- > 0)
tty_puts(tty, delete_character);
} else {
while (ua-- > 0)
tty_putc(tty, '\010');
}
break;
case TTY_CURSORON:
if (!(tty->flags & TTY_NOCURSOR) && cursor_normal != NULL)
tty_puts(tty, cursor_normal);
break;
case TTY_CURSOROFF:
if (cursor_invisible != NULL)
tty_puts(tty, cursor_invisible);
break;
case TTY_REVERSEINDEX:
tty_puts(tty, scroll_reverse);
break;
case TTY_SCROLLREGION:
ua = va_arg(ap, u_int);
ub = va_arg(ap, u_int);
tty_puts(tty, tparm(change_scroll_region, ua, ub));
break;
#if 0
case TTY_INSERTON:
if (enter_insert_mode != NULL)
tty_puts(tty, enter_insert_mode);
break;
case TTY_INSERTOFF:
if (exit_insert_mode != NULL)
tty_puts(tty, exit_insert_mode);
break;
#endif
case TTY_MOUSEOFF:
if (key_mouse != NULL)
tty_puts(tty, "\033[?1000l");
break;
case TTY_MOUSEON:
if (key_mouse != NULL)
tty_puts(tty, "\033[?1000h");
break;
case TTY_ATTRIBUTES:
ua = va_arg(ap, u_int);
ub = va_arg(ap, u_int);
uc = va_arg(ap, u_int);
tty_attributes(tty, ua, ub, uc);
break;
ua = va_arg(ap, u_int);
if (parm_up_cursor != NULL)
tty_puts(tty, tparm(parm_up_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_up);
}
}
void
tty_attributes(struct tty *tty, u_short attr, u_char fg, u_char bg)
tty_cmd_cursordown(struct tty *tty, unused struct screen *s, va_list ap)
{
if (attr == tty->attr && fg == tty->fg && bg == tty->bg)
u_int ua;
ua = va_arg(ap, u_int);
if (parm_down_cursor != NULL)
tty_puts(tty, tparm(parm_down_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_down);
}
}
void
tty_cmd_cursorright(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
ua = va_arg(ap, u_int);
if (parm_right_cursor != NULL)
tty_puts(tty, tparm(parm_right_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_right);
}
}
void
tty_cmd_cursorleft(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
ua = va_arg(ap, u_int);
if (parm_left_cursor != NULL)
tty_puts(tty, tparm(parm_left_cursor, ua));
else {
while (ua-- > 0)
tty_puts(tty, cursor_left);
}
}
void
tty_cmd_insertcharacter(struct tty *tty, struct screen *s, va_list ap)
{
u_int ua;
ua = va_arg(ap, u_int);
tty_reset(tty);
if (parm_ich != NULL)
tty_puts(tty, tparm(parm_ich, ua));
else if (insert_character != NULL) {
while (ua-- > 0)
tty_puts(tty, insert_character);
} else if (enter_insert_mode != NULL) {
tty_puts(tty, enter_insert_mode);
while (ua-- > 0)
tty_putc(tty, ' ');
tty_puts(tty, exit_insert_mode);
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
}
void
tty_cmd_deletecharacter(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
ua = va_arg(ap, u_int);
tty_reset(tty);
if (parm_dch != NULL)
tty_puts(tty, tparm(parm_dch, ua));
else if (delete_character != NULL) {
while (ua-- > 0)
tty_puts(tty, delete_character);
} else {
while (ua-- > 0)
tty_putc(tty, '\010');
}
}
void
tty_cmd_insertline(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
ua = va_arg(ap, u_int);
tty_reset(tty);
if (parm_insert_line != NULL)
tty_puts(tty, tparm(parm_insert_line, ua));
else {
while (ua-- > 0)
tty_puts(tty, insert_line);
}
}
void
tty_cmd_deleteline(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
ua = va_arg(ap, u_int);
tty_reset(tty);
if (parm_delete_line != NULL)
tty_puts(tty, tparm(parm_delete_line, ua));
else {
while (ua-- > 0)
tty_puts(tty, delete_line);
}
}
void
tty_cmd_clearline(struct tty *tty, struct screen *s, unused va_list ap)
{
u_int i;
tty_reset(tty);
if (clr_eol != NULL) {
tty_puts(tty, tparm(cursor_address, s->cy, 0));
tty_puts(tty, clr_eol);
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
} else {
tty_puts(tty, tparm(cursor_address, s->cy, 0));
for (i = 0; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
}
void
tty_cmd_clearendofline(struct tty *tty, struct screen *s, unused va_list ap)
{
u_int i;
tty_reset(tty);
if (clr_eol != NULL)
tty_puts(tty, clr_eol);
else {
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
for (i = s->cx; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
}
void
tty_cmd_clearstartofline(struct tty *tty, struct screen *s, unused va_list ap)
{
u_int i;
tty_reset(tty);
if (clr_bol != NULL)
tty_puts(tty, clr_bol);
else {
tty_puts(tty, tparm(cursor_address, s->cy, 0));
for (i = 0; i < s->cx + 1; i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
}
void
tty_cmd_cursormove(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua, ub;
ua = va_arg(ap, u_int);
ub = va_arg(ap, u_int);
tty_puts(tty, tparm(cursor_address, ub, ua));
}
void
tty_cmd_cursormode(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
if (cursor_normal == NULL || cursor_invisible == NULL)
return;
/* If any bits are being cleared, reset everything. */
if (tty->attr & ~attr) {
if ((tty->attr & ATTR_CHARSET) && exit_alt_charset_mode != NULL)
tty_puts(tty, exit_alt_charset_mode);
tty_puts(tty, exit_attribute_mode);
tty->fg = 8;
tty->bg = 8;
tty->attr = 0;
}
ua = va_arg(ap, int);
if (ua && !(tty->flags & TTY_NOCURSOR))
tty_puts(tty, cursor_normal);
else
tty_puts(tty, cursor_invisible);
}
/* Filter out attribute bits already set. */
attr &= ~tty->attr;
tty->attr |= attr;
void
tty_cmd_reverseindex(
struct tty *tty, unused struct screen *s, unused va_list ap)
{
tty_reset(tty);
tty_puts(tty, scroll_reverse);
}
void
tty_cmd_scrollregion(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua, ub;
ua = va_arg(ap, u_int);
ub = va_arg(ap, u_int);
tty_puts(tty, tparm(change_scroll_region, ua, ub));
}
void
tty_cmd_insertmode(unused struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
if (enter_insert_mode == NULL || exit_insert_mode == NULL)
return;
ua = va_arg(ap, int);
#if 0
if (ua)
tty_puts(tty, enter_insert_mode);
else
tty_puts(tty, exit_insert_mode);
#endif
}
void
tty_cmd_mousemode(struct tty *tty, unused struct screen *s, va_list ap)
{
u_int ua;
if (key_mouse == NULL)
return;
ua = va_arg(ap, int);
if (ua)
tty_puts(tty, "\033[?1000h");
else
tty_puts(tty, "\033[?1000l");
}
void
tty_cmd_linefeed(struct tty *tty, unused struct screen *s, unused va_list ap)
{
tty_reset(tty);
tty_putc(tty, '\n');
}
void
tty_cmd_carriagereturn(
struct tty *tty, unused struct screen *s, unused va_list ap)
{
tty_reset(tty);
if (carriage_return)
tty_puts(tty, carriage_return);
else
tty_putc(tty, '\r');
}
void
tty_cmd_bell(struct tty *tty, unused struct screen *s, unused va_list ap)
{
if (bell)
tty_puts(tty, bell);
}
void
tty_cmd_clearendofscreen(struct tty *tty, struct screen *s, unused va_list ap)
{
u_int i, j;
tty_reset(tty);
if (clr_eol != NULL) {
for (i = s->cy; i < screen_size_y(s); i++) {
tty_puts(tty, clr_eol);
tty_puts(tty, cursor_down);
}
} else {
for (i = s->cx; i < screen_size_y(s); i++)
tty_putc(tty, ' ');
for (j = s->cy; j < screen_size_y(s); j++) {
for (i = 0; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
}
}
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
void
tty_cmd_clearstartofscreen(struct tty *tty, struct screen *s, unused va_list ap)
{
u_int i, j;
tty_reset(tty);
tty_puts(tty, tparm(cursor_address, 0, 0));
if (clr_eol) {
for (i = 0; i < s->cy; i++)
tty_puts(tty, clr_eol);
tty_puts(tty, tparm(cursor_address, s->cy, 0));
} else {
for (j = 0; j < s->cy; j++) {
for (i = 0; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
}
}
for (i = 0; i < s->cx; i++)
tty_putc(tty, ' ');
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
void
tty_cmd_clearscreen(struct tty *tty, struct screen *s, unused va_list ap)
{
u_int i, j;
tty_reset(tty);
if (clr_eol) {
tty_puts(tty, tparm(cursor_address, 0, 0));
for (i = 0; i < screen_size_y(s); i++) {
tty_puts(tty, clr_eol);
tty_puts(tty, cursor_down);
}
} else {
tty_puts(tty, tparm(cursor_address, 0, 0));
for (j = 0; j < screen_size_y(s); j++) {
for (i = 0; i < screen_size_x(s); i++)
tty_putc(tty, ' ');
}
}
tty_puts(tty, tparm(cursor_address, s->cy, s->cx));
}
void
tty_cmd_cell(struct tty *tty, unused struct screen *s, va_list ap)
{
struct grid_cell *gc;
u_int i, width;
u_char out[4];
gc = va_arg(ap, struct grid_cell *);
/* If this is a padding character, do nothing. */
if (gc->flags & GRID_FLAG_PADDING)
return;
/* Handle special characters. Should never come into this function.*/
if (gc->data < 0x20 || gc->data == 0x7f)
return;
/* Set the attributes. */
if ((attr & ATTR_BRIGHT) && enter_bold_mode != NULL)
tty_attributes(tty, gc);
/* If not UTF8 multibyte, write directly. */
if (gc->data < 0xff) {
tty_putc(tty, gc->data);
return;
}
/* If the terminal doesn't support UTF8, write _s. */
if (!(tty->flags & TTY_UTF8)) {
width = utf8_width(gc->data);
while (width-- > 0)
tty_putc(tty, '_');
return;
}
/* Unpack UTF-8 and write it. */
utf8_split(gc->data, out);
for (i = 0; i < 4; i++) {
if (out[i] == 0xff)
break;
tty_putc(tty, out[i]);
}
}
void
tty_reset(struct tty *tty)
{
struct grid_cell *tc = &tty->cell;
tc->data = grid_default_cell.data;
if (memcmp(tc, &grid_default_cell, sizeof *tc) == 0)
return;
if (exit_alt_charset_mode != NULL && tc->attr & GRID_ATTR_CHARSET)
tty_puts(tty, exit_alt_charset_mode);
tty_puts(tty, exit_attribute_mode);
memcpy(tc, &grid_default_cell, sizeof *tc);
}
void
tty_attributes(struct tty *tty, const struct grid_cell *gc)
{
struct grid_cell *tc = &tty->cell;
u_char changed;
/* If any bits are being cleared, reset everything. */
if (tc->attr & ~gc->attr)
tty_reset(tty);
/* Filter out attribute bits already set. */
changed = gc->attr & ~tc->attr;
tc->attr = gc->attr;
/* Set the attributes. */
if ((changed & GRID_ATTR_BRIGHT) && enter_bold_mode != NULL)
tty_puts(tty, enter_bold_mode);
if ((attr & ATTR_DIM) && enter_dim_mode != NULL)
if ((changed & GRID_ATTR_DIM) && enter_dim_mode != NULL)
tty_puts(tty, enter_dim_mode);
if ((attr & ATTR_ITALICS) && enter_standout_mode != NULL)
if ((changed & GRID_ATTR_ITALICS) && enter_standout_mode != NULL)
tty_puts(tty, enter_standout_mode);
if ((attr & ATTR_UNDERSCORE) && enter_underline_mode != NULL)
if ((changed & GRID_ATTR_UNDERSCORE) && enter_underline_mode != NULL)
tty_puts(tty, enter_underline_mode);
if ((attr & ATTR_BLINK) && enter_blink_mode != NULL)
if ((changed & GRID_ATTR_BLINK) && enter_blink_mode != NULL)
tty_puts(tty, enter_blink_mode);
if ((attr & ATTR_REVERSE) && enter_reverse_mode != NULL)
if ((changed & GRID_ATTR_REVERSE) && enter_reverse_mode != NULL)
tty_puts(tty, enter_reverse_mode);
if ((attr & ATTR_HIDDEN) && enter_secure_mode != NULL)
if ((changed & GRID_ATTR_HIDDEN) && enter_secure_mode != NULL)
tty_puts(tty, enter_secure_mode);
if ((attr & ATTR_CHARSET) && enter_alt_charset_mode != NULL)
if ((changed & GRID_ATTR_CHARSET) && enter_alt_charset_mode != NULL)
tty_puts(tty, enter_alt_charset_mode);
/* Set foreground colour. */
if (fg != tty->fg || attr & ATTR_FG256)
tty->fg = tty_attributes_fg(tty, fg);
if (gc->fg != tc->fg ||
(gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) {
tty_attributes_fg(tty, gc);
tc->fg = gc->fg;
}
/* Set background colour. */
if (bg != tty->bg || attr & ATTR_BG256)
tty->bg = tty_attributes_bg(tty, bg);
if (gc->bg != tc->bg ||
(gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) {
tty_attributes_bg(tty, gc);
tc->bg = gc->bg;
}
}
u_char
tty_attributes_fg(struct tty *tty, u_char fg)
void
tty_attributes_fg(struct tty *tty, const struct grid_cell *gc)
{
char s[32];
u_char fg = gc->fg;
if (tty->attr & ATTR_FG256) {
if (tty->term->flags & TERM_256COLOURS) {
if (gc->flags & GRID_FLAG_FG256) {
if ((tty->term->flags & TERM_256COLOURS) ||
(tty->term_flags & TERM_256COLOURS)) {
xsnprintf(s, sizeof s, "\033[38;5;%hhum", fg);
tty_puts(tty, s);
return (fg);
return;
}
if (fg > 15)
@ -715,25 +985,28 @@ tty_attributes_fg(struct tty *tty, u_char fg)
fg -= 8;
}
if (fg == 8 && !(tty->term->flags & TERM_HASDEFAULTS))
if (fg == 8 &&
!(tty->term->flags & TERM_HASDEFAULTS) &&
!(tty->term_flags & TERM_HASDEFAULTS))
fg = 7;
if (fg == 8)
tty_puts(tty, "\033[39m");
else if (set_a_foreground != NULL)
tty_puts(tty, tparm(set_a_foreground, fg));
return (fg);
}
u_char
tty_attributes_bg(struct tty *tty, u_char bg)
void
tty_attributes_bg(struct tty *tty, const struct grid_cell *gc)
{
char s[32];
u_char bg = gc->bg;
if (tty->attr & ATTR_BG256) {
if (tty->term->flags & TERM_256COLOURS) {
if (gc->flags & GRID_FLAG_BG256) {
if ((tty->term->flags & TERM_256COLOURS) ||
(tty->term_flags & TERM_256COLOURS)) {
xsnprintf(s, sizeof s, "\033[48;5;%hhum", bg);
tty_puts(tty, s);
return (bg);
return;
}
if (bg > 15)
@ -742,11 +1015,12 @@ tty_attributes_bg(struct tty *tty, u_char bg)
bg -= 8;
}
if (bg == 8 && !(tty->term->flags & TERM_HASDEFAULTS))
if (bg == 8 &&
!(tty->term->flags & TERM_HASDEFAULTS) &&
!(tty->term_flags & TERM_HASDEFAULTS))
bg = 0;
if (bg == 8)
tty_puts(tty, "\033[49m");
else if (set_a_background != NULL)
tty_puts(tty, tparm(set_a_background, bg));
return (bg);
}

139
utf8.c
View File

@ -1,4 +1,4 @@
/* $Id: utf8.c,v 1.1 2008-09-09 22:16:37 nicm Exp $ */
/* $Id: utf8.c,v 1.2 2008-09-25 20:08:56 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -22,93 +22,66 @@
#include "tmux.h"
/*
* UTF8 data structures. Just crappy array + linear search for now.
*/
/* Pack UTF8 index into attr, data. */
void
utf8_pack(int idx, u_char *data, u_short *attr)
u_int
utf8_combine(const u_char data[4])
{
*data = idx & 0xff;
u_int uv;
*attr &= ~(ATTR_UTF8b8|ATTR_UTF8b9);
if (idx & 0x100)
*attr |= ATTR_UTF8b8;
if (idx & 0x200)
*attr |= ATTR_UTF8b9;
if (idx & 0x400)
*attr |= ATTR_UTF8b10;
if (idx & 0x800)
*attr |= ATTR_UTF8b11;
}
/* Unpack UTF8 index from attr, data. */
int
utf8_unpack(u_char data, u_short attr)
{
int idx;
idx = data;
if (attr & ATTR_UTF8b8)
idx |= 0x100;
if (attr & ATTR_UTF8b9)
idx |= 0x200;
if (attr & ATTR_UTF8b10)
idx |= 0x400;
if (attr & ATTR_UTF8b11)
idx |= 0x800;
return (idx);
}
void
utf8_init(struct utf8_table *utab, int limit)
{
utab->limit = limit;
ARRAY_INIT(&utab->array);
}
void
utf8_free(struct utf8_table *utab)
{
ARRAY_FREE(&utab->array);
}
struct utf8_data *
utf8_lookup(struct utf8_table *utab, int idx)
{
if (idx < 0 || idx >= (int) ARRAY_LENGTH(&utab->array))
return (NULL);
return (&ARRAY_ITEM(&utab->array, idx));
}
int
utf8_search(struct utf8_table *utab, struct utf8_data *udat)
{
u_int idx;
for (idx = 0; idx < ARRAY_LENGTH(&utab->array); idx++) {
if (memcmp(udat->data,
ARRAY_ITEM(&utab->array, idx).data, sizeof udat->data) == 0)
return (idx);
if (data[1] == 0xff)
uv = data[0];
else if (data[2] == 0xff) {
uv = data[1] & 0x3f;
uv |= (data[0] & 0x1f) << 6;
} else if (data[3] == 0xff) {
uv = data[2] & 0x3f;
uv |= (data[1] & 0x3f) << 6;
uv |= (data[0] & 0x0f) << 12;
} else {
uv = data[3] & 0x3f;
uv |= (data[2] & 0x3f) << 6;
uv |= (data[1] & 0x3f) << 12;
uv |= (data[0] & 0x3f) << 18;
}
return (uv);
}
void
utf8_split(u_int uv, u_char data[4])
{
memset(data, 0xff, sizeof data);
if (uv <= 0x7f)
data[0] = uv;
else if (uv > 0x7f && uv <= 0x7ff) {
data[0] = (uv >> 6) | 0xc0;
data[1] = (uv & 0x3f) | 0x80;
} else if (uv > 0x7ff && uv <= 0xffff) {
data[0] = (uv >> 12) | 0xe0;
data[1] = ((uv >> 6) & 0x3f) | 0x80;
data[2] = (uv & 0x3f) | 0x80;
} else if (uv > 0xffff && uv <= 0x10ffff) {
data[0] = (uv >> 18) | 0xf0;
data[1] = ((uv >> 12) & 0x3f) | 0x80;
data[2] = ((uv >> 6) & 0x3f) | 0x80;
data[3] = (uv & 0x3f) | 0x80;
}
return (-1);
}
int
utf8_add(struct utf8_table *utab, struct utf8_data *udat)
utf8_width(u_int uv)
{
int idx;
if (ARRAY_LENGTH(&utab->array) == utab->limit)
return (-1);
if ((idx = utf8_search(utab, udat)) != -1)
return (idx);
ARRAY_EXPAND(&utab->array, 1);
memcpy(
&ARRAY_LAST(&utab->array), udat, sizeof ARRAY_LAST(&utab->array));
return (ARRAY_LENGTH(&utab->array) - 1);
if ((uv >= 0x1100 && uv <= 0x115f) ||
uv == 0x2329 ||
uv == 0x232a ||
(uv >= 0x2e80 && uv <= 0xa4cf && uv != 0x303f) ||
(uv >= 0xac00 && uv <= 0xd7a3) ||
(uv >= 0xf900 && uv <= 0xfaff) ||
(uv >= 0xfe10 && uv <= 0xfe19) ||
(uv >= 0xfe30 && uv <= 0xfe6f) ||
(uv >= 0xff00 && uv <= 0xff60) ||
(uv >= 0xffe0 && uv <= 0xffe6) ||
(uv >= 0x20000 && uv <= 0x2fffd) ||
(uv >= 0x30000 && uv <= 0x3fffd))
return (2);
return (1);
}

View File

@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.30 2008-09-10 19:15:04 nicm Exp $ */
/* $Id: window-copy.c,v 1.31 2008-09-25 20:08:57 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -44,6 +44,7 @@ int window_copy_update_selection(struct window *);
void window_copy_copy_selection(struct window *, struct client *);
void window_copy_copy_line(
struct window *, char **, size_t *, u_int, u_int, u_int);
int window_copy_is_space(struct window *, u_int, u_int);
u_int window_copy_find_length(struct window *, u_int);
void window_copy_cursor_start_of_line(struct window *);
void window_copy_cursor_end_of_line(struct window *);
@ -58,10 +59,6 @@ void window_copy_scroll_right(struct window *, u_int);
void window_copy_scroll_up(struct window *, u_int);
void window_copy_scroll_down(struct window *, u_int);
const char *space_characters = " -_@";
#define window_copy_is_space(w, x, y) \
(strchr(space_characters, (w)->base.grid_data[y][x]) != NULL)
const struct window_mode window_copy_mode = {
window_copy_init,
window_copy_free,
@ -104,7 +101,7 @@ window_copy_init(struct window *w)
screen_write_start(&ctx, s, NULL, NULL);
for (i = 0; i < screen_size_y(s); i++)
window_copy_write_line(w, &ctx, i);
screen_write_move_cursor(&ctx, data->cx, data->cy);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
return (s);
@ -124,10 +121,12 @@ window_copy_resize(struct window *w, u_int sx, u_int sy)
{
struct window_copy_mode_data *data = w->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
screen_resize(s, sx, sy);
screen_display_copy_area(&data->screen, &w->base,
0, 0, screen_size_x(s), screen_size_y(s), data->ox, data->oy);
screen_write_start(&ctx, s, NULL, NULL);
window_copy_write_lines(w, &ctx, 0, screen_size_y(s) - 1);
screen_write_stop(&ctx);
window_copy_update_selection(w);
}
@ -156,8 +155,8 @@ window_copy_key(struct window *w, struct client *c, int key)
window_copy_cursor_down(w);
return;
case MODEKEY_PPAGE:
if (data->oy + screen_size_y(s) > w->base.hsize)
data->oy = w->base.hsize;
if (data->oy + screen_size_y(s) > screen_hsize(&w->base))
data->oy = screen_hsize(&w->base);
else
data->oy += screen_size_y(s);
window_copy_update_selection(w);
@ -202,44 +201,38 @@ window_copy_key(struct window *w, struct client *c, int key)
}
void
window_copy_write_line(
struct window *w, struct screen_write_ctx *ctx, u_int py)
window_copy_write_line(struct window *w, struct screen_write_ctx *ctx, u_int py)
{
struct window_copy_mode_data *data = w->modedata;
struct screen *s = &data->screen;
struct grid_cell gc;
char hdr[32];
size_t size;
if (py == 0) {
screen_write_set_attributes(
ctx, ATTR_BRIGHT|ATTR_REVERSE, 8, 8);
screen_write_move_cursor(ctx, 0, 0);
size = screen_write_put_string_rjust(
ctx, "[%u,%u/%u]", data->ox, data->oy, w->base.hsize);
screen_write_set_attributes(ctx, 0, 8, 8);
memcpy(&gc, &grid_default_cell, sizeof gc);
size = xsnprintf(hdr, sizeof hdr,
"[%u,%u/%u]", data->ox, data->oy, screen_hsize(&w->base));
gc.attr |= GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE;
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr);
gc.attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE);
} else
size = 0;
screen_write_move_cursor(ctx, 0, py);
screen_write_copy_area(
ctx, &w->base, screen_size_x(s) - size, 1, data->ox, data->oy);
screen_write_cursormove(ctx, 0, py);
screen_write_copy(ctx, &w->base, data->ox, (screen_hsize(&w->base) -
data->oy) + py, screen_size_x(s) - size, 1);
}
void
window_copy_write_lines(
struct window *w, struct screen_write_ctx *ctx, u_int py, u_int ny)
{
struct window_copy_mode_data *data = w->modedata;
struct screen *s = &data->screen;
u_int yy;
if (py == 0) {
window_copy_write_line(w, ctx, 0);
if (ny == 1)
return;
py++;
ny--;
}
screen_write_move_cursor(ctx, 0, py);
screen_write_copy_area(
ctx, &w->base, screen_size_x(s), ny, data->ox, data->oy);
for (yy = py; yy < py + ny; yy++)
window_copy_write_line(w, ctx, py);
}
void
@ -249,21 +242,19 @@ window_copy_write_column(
struct window_copy_mode_data *data = w->modedata;
struct screen *s = &data->screen;
screen_write_move_cursor(ctx, px, 0);
screen_write_copy_area(
ctx, &w->base, 1, screen_size_y(s), data->ox, data->oy);
screen_write_cursormove(ctx, px, 0);
screen_write_copy(ctx, &w->base,
data->ox, screen_hsize(&w->base) - data->oy, 1, screen_size_y(s));
}
void
window_copy_write_columns(
struct window *w, struct screen_write_ctx *ctx, u_int px, u_int nx)
{
struct window_copy_mode_data *data = w->modedata;
struct screen *s = &data->screen;
u_int xx;
screen_write_move_cursor(ctx, px, 0);
screen_write_copy_area(
ctx, &w->base, nx, screen_size_y(s), data->ox, data->oy);
for (xx = px; xx < px + nx; xx++)
window_copy_write_column(w, ctx, px);
}
void
@ -276,7 +267,7 @@ window_copy_redraw_lines(struct window *w, u_int py, u_int ny)
screen_write_start_window(&ctx, w);
for (i = py; i < py + ny; i++)
window_copy_write_line(w, &ctx, i);
screen_write_move_cursor(&ctx, data->cx, data->cy);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
@ -295,7 +286,7 @@ window_copy_update_cursor(struct window *w)
struct screen_write_ctx ctx;
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, data->cx, data->cy);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
@ -305,8 +296,8 @@ window_copy_start_selection(struct window *w)
struct window_copy_mode_data *data = w->modedata;
struct screen *s = &data->screen;
data->selx = screen_x(&w->base, data->cx) + data->ox;
data->sely = screen_y(&w->base, data->cy) - data->oy;
data->selx = data->cx + data->ox;
data->sely = screen_hsize(&w->base) + data->cy - data->oy;
s->sel.flag = 1;
window_copy_update_selection(w);
@ -323,8 +314,8 @@ window_copy_update_selection(struct window *w)
return (0);
/* Find top-left of screen. */
tx = screen_x(&w->base, 0) + data->ox;
ty = screen_y(&w->base, 0) - data->oy;
tx = data->ox;
ty = screen_hsize(&w->base) - data->oy;
/* Adjust the selection. */
sx = data->selx;
@ -333,28 +324,26 @@ window_copy_update_selection(struct window *w)
/* Above it. */
sx = 0;
sy = 0;
} else if (sy > ty + screen_last_y(s)) {
} else if (sy > ty + screen_size_y(s) - 1) {
/* Below it. */
sx = screen_last_x(s);
sy = screen_last_y(s);
sx = screen_size_x(s) - 1;
sy = screen_size_y(s) - 1;
} else if (sx < tx) {
/* To the left. */
sx = 0;
} else if (sx > tx + screen_last_x(s)) {
} else if (sx > tx + screen_size_x(s) - 1) {
/* To the right. */
sx = 0;
sy++;
if (sy > screen_last_y(s))
sy = screen_last_y(s);
if (sy > screen_size_y(s) - 1)
sy = screen_size_y(s) - 1;
} else {
sx -= tx;
sy -= ty;
}
sx = screen_x(s, sx);
sy = screen_x(s, sy);
sy = screen_hsize(s) + sy;
screen_set_selection(
s, sx, sy, screen_x(s, data->cx), screen_y(s, data->cy));
screen_set_selection(s, sx, sy, data->cx, screen_hsize(s) + data->cy);
return (1);
}
@ -381,8 +370,8 @@ window_copy_copy_selection(struct window *w, struct client *c)
*/
/* Find start and end. */
xx = screen_x(&w->base, data->cx) + data->ox;
yy = screen_y(&w->base, data->cy) - data->oy;
xx = data->cx + data->ox;
yy = screen_hsize(&w->base) + data->cy - data->oy;
if (xx < data->selx || (yy == data->sely && xx < data->selx)) {
sx = xx; sy = yy;
ex = data->selx; ey = data->sely;
@ -425,7 +414,8 @@ void
window_copy_copy_line(
struct window *w, char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
{
u_char i, xx;
const struct grid_cell *gc;
u_char i, j, xx, data[4];
if (sx > ex)
return;
@ -438,9 +428,15 @@ window_copy_copy_line(
if (sx < ex) {
for (i = sx; i < ex; i++) {
*buf = xrealloc(*buf, 1, (*off) + 1);
(*buf)[*off] = w->base.grid_data[sy][i];
(*off)++;
gc = grid_peek_cell(w->base.grid, i, sy);
utf8_split(gc->data, data);
*buf = xrealloc(*buf, 1, (*off) + 4);
for (j = 0; j < sizeof data; j++) {
if (data[j] == 0xff)
break;
(*buf)[(*off)++] = data[j];
}
}
}
@ -449,14 +445,33 @@ window_copy_copy_line(
(*off)++;
}
int
window_copy_is_space(struct window *w, u_int px, u_int py)
{
const struct grid_cell *gc;
const char *spaces = " -_@";
gc = grid_peek_cell(w->base.grid, px, py);
if (gc->flags & GRID_FLAG_PADDING)
return (0);
if (gc->data == 0x00 || gc->data > 0xff)
return (0);
return (strchr(spaces, gc->data) != NULL);
}
u_int
window_copy_find_length(struct window *w, u_int py)
{
u_int px;
const struct grid_cell *gc;
u_int px;
px = w->base.grid_size[py];
while (px > 0 && w->base.grid_data[py][px - 1] == ' ')
px = w->base.grid->size[py];
while (px > 0) {
gc = grid_peek_cell(w->base.grid, px - 1, py);
if (gc->data != 0x20)
break;
px--;
}
return (px);
}
@ -482,32 +497,32 @@ window_copy_cursor_end_of_line(struct window *w)
struct screen *s = &data->screen;
u_int px, py;
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(&w->base) + data->cy - data->oy;
px = window_copy_find_length(w, py);
/* On screen. */
if (px > data->ox && px <= data->ox + screen_last_x(s))
if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
data->cx = px - data->ox;
/* Off right of screen. */
if (px > data->ox + screen_last_x(s)) {
if (px > data->ox + screen_size_x(s) - 1) {
/* Move cursor to last and scroll screen. */
window_copy_scroll_left(w,
px - data->ox - screen_last_x(s));
data->cx = screen_last_x(s);
window_copy_scroll_left(
w, px - data->ox - (screen_size_x(s) - 1));
data->cx = screen_size_x(s) - 1;
}
/* Off left of screen. */
if (px <= data->ox) {
if (px < screen_last_x(s)) {
if (px < screen_size_x(s) - 1) {
/* Short enough to fit on screen. */
window_copy_scroll_right(w, data->ox);
data->cx = px;
} else {
/* Too long to fit on screen. */
window_copy_scroll_right(
w, data->ox - (px - screen_last_x(s)));
data->cx = screen_last_x(s);
w, data->ox - (px - (screen_size_x(s) - 1)));
data->cx = screen_size_x(s) - 1;
}
}
@ -544,7 +559,7 @@ window_copy_cursor_right(struct window *w)
struct window_copy_mode_data *data = w->modedata;
u_int px, py;
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(&w->base) + data->cy - data->oy;
px = window_copy_find_length(w, py);
if (data->cx >= px) {
@ -565,7 +580,7 @@ window_copy_cursor_up(struct window *w)
struct window_copy_mode_data *data = w->modedata;
u_int ox, oy, px, py;
oy = screen_y(&w->base, data->cy) - data->oy;
oy = screen_hsize(&w->base) + data->cy - data->oy;
ox = window_copy_find_length(w, oy);
if (data->cy == 0)
@ -578,7 +593,7 @@ window_copy_cursor_up(struct window *w)
window_copy_update_cursor(w);
}
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(&w->base) + data->cy - data->oy;
px = window_copy_find_length(w, py);
if (data->cx + data->ox >= px || data->cx + data->ox >= ox)
@ -592,10 +607,10 @@ window_copy_cursor_down(struct window *w)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_y(&w->base, data->cy) - data->oy;
oy = screen_hsize(&w->base) + data->cy - data->oy;
ox = window_copy_find_length(w, oy);
if (data->cy == screen_last_y(s))
if (data->cy == screen_size_y(s) - 1)
window_copy_scroll_up(w, 1);
else {
data->cy++;
@ -605,7 +620,7 @@ window_copy_cursor_down(struct window *w)
window_copy_update_cursor(w);
}
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(&w->base) + data->cy - data->oy;
px = window_copy_find_length(w, py);
if (data->cx + data->ox >= px || data->cx + data->ox >= ox)
@ -620,7 +635,7 @@ window_copy_cursor_next_word(struct window *w)
u_int px, py, xx, skip;
px = data->ox + data->cx;
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(&w->base) + data->cy - data->oy;
xx = window_copy_find_length(w, py);
skip = 1;
@ -638,7 +653,7 @@ window_copy_cursor_next_word(struct window *w)
}
while (px >= xx) {
if (data->cy == screen_last_y(s)) {
if (data->cy == screen_size_y(s) - 1) {
if (data->oy == 0)
goto out;
}
@ -646,7 +661,8 @@ window_copy_cursor_next_word(struct window *w)
px = 0;
window_copy_cursor_down(w);
py = screen_y(&w->base, data->cy) - data->oy;
py =screen_hsize(
&w->base) + data->cy - data->oy;
xx = window_copy_find_length(w, py);
}
}
@ -666,28 +682,28 @@ window_copy_cursor_next_word(struct window *w)
out:
/* On screen. */
if (px > data->ox && px <= data->ox + screen_last_x(s))
if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
data->cx = px - data->ox;
/* Off right of screen. */
if (px > data->ox + screen_last_x(s)) {
if (px > data->ox + screen_size_x(s) - 1) {
/* Move cursor to last and scroll screen. */
window_copy_scroll_left(w,
px - data->ox - screen_last_x(s));
data->cx = screen_last_x(s);
window_copy_scroll_left(
w, px - data->ox - (screen_size_x(s) - 1));
data->cx = screen_size_x(s) - 1;
}
/* Off left of screen. */
if (px <= data->ox) {
if (px < screen_last_x(s)) {
if (px < screen_size_x(s) - 1) {
/* Short enough to fit on screen. */
window_copy_scroll_right(w, data->ox);
data->cx = px;
} else {
/* Too long to fit on screen. */
window_copy_scroll_right(
w, data->ox - (px - screen_last_x(s)));
data->cx = screen_last_x(s);
w, data->ox - (px - (screen_size_x(s) - 1)));
data->cx = screen_size_x(s) - 1;
}
}
@ -705,7 +721,7 @@ window_copy_cursor_previous_word(struct window *w)
u_int ox, px, py, skip;
ox = px = data->ox + data->cx;
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(&w->base) + data->cy - data->oy;
skip = 1;
if (px != 0) {
@ -719,13 +735,15 @@ window_copy_cursor_previous_word(struct window *w)
break;
while (px == 0) {
if (data->cy == 0 && (w->base.hsize == 0 ||
data->oy >= w->base.hsize - 1))
if (data->cy == 0 &&
(screen_hsize(&w->base) == 0 ||
data->oy >= screen_hsize(&w->base) - 1))
goto out;
window_copy_cursor_up(w);
py = screen_y(&w->base, data->cy) - data->oy;
py = screen_hsize(
&w->base) + data->cy - data->oy;
px = window_copy_find_length(w, py);
}
goto out;
@ -746,28 +764,28 @@ window_copy_cursor_previous_word(struct window *w)
out:
/* On screen. */
if (px > data->ox && px <= data->ox + screen_last_x(s))
if (px > data->ox && px <= data->ox + screen_size_x(s) - 1)
data->cx = px - data->ox;
/* Off right of screen. */
if (px > data->ox + screen_last_x(s)) {
if (px > data->ox + screen_size_x(s) - 1) {
/* Move cursor to last and scroll screen. */
window_copy_scroll_left(w,
px - data->ox - screen_last_x(s));
data->cx = screen_last_x(s);
window_copy_scroll_left(
w, px - data->ox - (screen_size_x(s) - 1));
data->cx = screen_size_x(s) - 1;
}
/* Off left of screen. */
if (px <= data->ox) {
if (px < screen_last_x(s)) {
if (px < screen_size_x(s) - 1) {
/* Short enough to fit on screen. */
window_copy_scroll_right(w, data->ox);
data->cx = px;
} else {
/* Too long to fit on screen. */
window_copy_scroll_right(
w, data->ox - (px - screen_last_x(s)));
data->cx = screen_last_x(s);
w, data->ox - (px - (screen_size_x(s) - 1)));
data->cx = screen_size_x(s) - 1;
}
}
@ -794,8 +812,8 @@ window_copy_scroll_left(struct window *w, u_int nx)
screen_write_start_window(&ctx, w);
for (i = 1; i < screen_size_y(s); i++) {
screen_write_move_cursor(&ctx, 0, i);
screen_write_delete_characters(&ctx, nx);
screen_write_cursormove(&ctx, 0, i);
screen_write_deletecharacter(&ctx, nx);
}
window_copy_write_columns(w, &ctx, screen_size_x(s) - nx, nx);
window_copy_write_line(w, &ctx, 0);
@ -803,7 +821,7 @@ window_copy_scroll_left(struct window *w, u_int nx)
window_copy_update_selection(w);
window_copy_write_lines(w, &ctx, data->cy, 1);
}
screen_write_move_cursor(&ctx, data->cx, data->cy);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
@ -824,14 +842,14 @@ window_copy_scroll_right(struct window *w, u_int nx)
screen_write_start_window(&ctx, w);
for (i = 1; i < screen_size_y(s); i++) {
screen_write_move_cursor(&ctx, 0, i);
screen_write_insert_characters(&ctx, nx);
screen_write_cursormove(&ctx, 0, i);
screen_write_insertcharacter(&ctx, nx);
}
window_copy_write_columns(w, &ctx, 0, nx);
window_copy_write_line(w, &ctx, 0);
if (s->sel.flag)
window_copy_write_lines(w, &ctx, data->cy, 1);
screen_write_move_cursor(&ctx, data->cx, data->cy);
window_copy_write_line(w, &ctx, data->cy);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
@ -850,13 +868,13 @@ window_copy_scroll_up(struct window *w, u_int ny)
window_copy_update_selection(w);
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, 0, 0);
screen_write_delete_lines(&ctx, ny);
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, ny);
window_copy_write_lines(w, &ctx, screen_size_y(s) - ny, ny);
window_copy_write_line(w, &ctx, 0);
if (s->sel.flag && screen_size_y(s) > ny)
window_copy_write_lines(w, &ctx, screen_size_y(s) - ny - 1, 1);
screen_write_move_cursor(&ctx, data->cx, data->cy);
window_copy_write_line(w, &ctx, screen_size_y(s) - ny - 1);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
@ -867,24 +885,24 @@ window_copy_scroll_down(struct window *w, u_int ny)
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (ny > w->base.hsize)
if (ny > screen_hsize(&w->base))
return;
if (data->oy > w->base.hsize - ny)
ny = w->base.hsize - data->oy;
if (data->oy > screen_hsize(&w->base) - ny)
ny = screen_hsize(&w->base) - data->oy;
if (ny == 0)
return;
data->oy += ny;
window_copy_update_selection(w);
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, 0, 0);
screen_write_insert_lines(&ctx, ny);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, ny);
window_copy_write_lines(w, &ctx, 0, ny);
if (s->sel.flag && screen_size_y(s) > ny)
window_copy_write_lines(w, &ctx, ny, 1);
window_copy_write_line(w, &ctx, ny);
else if (ny == 1) /* nuke position */
window_copy_write_line(w, &ctx, 1);
screen_write_move_cursor(&ctx, data->cx, data->cy);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}

View File

@ -1,4 +1,4 @@
/* $Id: window-more.c,v 1.18 2008-09-10 19:15:04 nicm Exp $ */
/* $Id: window-more.c,v 1.19 2008-09-25 20:08:57 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -62,7 +62,7 @@ window_more_vadd(struct window *w, const char *fmt, va_list ap)
screen_write_start_window(&ctx, w);
size = ARRAY_LENGTH(&data->list) - 1;
if (size >= data->top && size <= data->top + screen_last_y(s)) {
if (size >= data->top && size <= data->top + screen_size_y(s) - 1) {
window_more_write_line(w, &ctx, size - data->top);
if (size != data->top)
window_more_write_line(w, &ctx, 0);
@ -164,27 +164,30 @@ window_more_write_line(struct window *w, struct screen_write_ctx *ctx, u_int py)
{
struct window_more_mode_data *data = w->modedata;
struct screen *s = &data->screen;
char *msg;
struct grid_cell gc;
char *msg, hdr[32];
size_t size;
memcpy(&gc, &grid_default_cell, sizeof gc);
if (py == 0) {
screen_write_set_attributes(
ctx, ATTR_BRIGHT|ATTR_REVERSE, 8, 8);
screen_write_move_cursor(ctx, 0, 0);
size = screen_write_put_string_rjust(
ctx, "[%u/%u]", data->top, ARRAY_LENGTH(&data->list));
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->top, ARRAY_LENGTH(&data->list));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
gc.attr |= GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE;
screen_write_puts(ctx, &gc, "%s", hdr);
gc.attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE);
} else
size = 0;
screen_write_set_attributes(ctx, 0, 8, 8);
screen_write_move_cursor(ctx, 0, py);
screen_write_cursormove(ctx, 0, py);
if (data->top + py < ARRAY_LENGTH(&data->list)) {
msg = ARRAY_ITEM(&data->list, data->top + py);
screen_write_put_string(
ctx, "%.*s", (int) (screen_size_x(s) - size), msg);
screen_write_puts(
ctx, &gc, "%.*s", (int) (screen_size_x(s) - size), msg);
}
while (s->cx < screen_size_x(s) - size)
screen_write_put_character(ctx, ' ');
screen_write_putc(ctx, &gc, ' ');
}
void
@ -212,8 +215,8 @@ window_more_scroll_up(struct window *w)
data->top--;
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, 0, 0);
screen_write_insert_lines(&ctx, 1);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 1);
window_more_write_line(w, &ctx, 0);
window_more_write_line(w, &ctx, 1);
screen_write_stop(&ctx);
@ -231,9 +234,9 @@ window_more_scroll_down(struct window *w)
data->top++;
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, 0, 0);
screen_write_delete_lines(&ctx, 1);
window_more_write_line(w, &ctx, screen_last_y(s));
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, 1);
window_more_write_line(w, &ctx, screen_size_y(s) - 1);
window_more_write_line(w, &ctx, 0);
screen_write_stop(&ctx);
}

View File

@ -1,4 +1,4 @@
/* $Id: window-scroll.c,v 1.23 2008-09-10 19:15:05 nicm Exp $ */
/* $Id: window-scroll.c,v 1.24 2008-09-25 20:08:57 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -90,10 +90,14 @@ window_scroll_resize(struct window *w, u_int sx, u_int sy)
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
screen_resize(s, sx, sy);
screen_display_copy_area(&data->screen, &w->base,
0, 0, screen_size_x(s), screen_size_y(s), data->ox, data->oy);
screen_write_start(&ctx, s, NULL, NULL);
for (i = 0; i < screen_size_y(s); i++)
window_scroll_write_line(w, &ctx, i);
screen_write_stop(&ctx);
}
void
@ -121,8 +125,8 @@ window_scroll_key(struct window *w, struct client *c, int key)
window_scroll_scroll_down(w);
break;
case MODEKEY_PPAGE:
if (data->oy + screen_size_y(s) > w->base.hsize)
data->oy = w->base.hsize;
if (data->oy + screen_size_y(s) > screen_hsize(&w->base))
data->oy = screen_hsize(&w->base);
else
data->oy += screen_size_y(s);
window_scroll_redraw_screen(w);
@ -145,19 +149,24 @@ window_scroll_write_line(
{
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &data->screen;
struct grid_cell gc;
char hdr[32];
size_t size;
if (py == 0) {
screen_write_set_attributes(
ctx, ATTR_BRIGHT|ATTR_REVERSE, 8, 8);
screen_write_move_cursor(ctx, 0, 0);
size = screen_write_put_string_rjust(
ctx, "[%u,%u/%u]", data->ox, data->oy, w->base.hsize);
memcpy(&gc, &grid_default_cell, sizeof gc);
size = xsnprintf(hdr, sizeof hdr,
"[%u,%u/%u]", data->ox, data->oy, screen_hsize(&w->base));
gc.attr |= GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE;
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr);
gc.attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE);
} else
size = 0;
screen_write_move_cursor(ctx, 0, py);
screen_write_copy_area(
ctx, &w->base, screen_size_x(s) - size, 1, data->ox, data->oy);
screen_write_cursormove(ctx, 0, py);
screen_write_copy(ctx, &w->base, data->ox, (screen_hsize(&w->base) -
data->oy) + py, screen_size_x(s) - size, 1);
}
void
@ -167,9 +176,9 @@ window_scroll_write_column(
struct window_scroll_mode_data *data = w->modedata;
struct screen *s = &data->screen;
screen_write_move_cursor(ctx, px, 0);
screen_write_copy_area(
ctx, &w->base, 1, screen_size_y(s), data->ox, data->oy);
screen_write_cursormove(ctx, px, 0);
screen_write_copy(ctx, &w->base, data->ox + px,
screen_hsize(&w->base) - data->oy, 1, screen_size_y(s));
}
void
@ -192,13 +201,13 @@ window_scroll_scroll_up(struct window *w)
struct window_scroll_mode_data *data = w->modedata;
struct screen_write_ctx ctx;
if (data->oy >= w->base.hsize)
if (data->oy >= screen_hsize(&w->base))
return;
data->oy++;
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, 0, 0);
screen_write_insert_lines(&ctx, 1);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 1);
window_scroll_write_line(w, &ctx, 0);
window_scroll_write_line(w, &ctx, 1);
screen_write_stop(&ctx);
@ -216,9 +225,9 @@ window_scroll_scroll_down(struct window *w)
data->oy--;
screen_write_start_window(&ctx, w);
screen_write_move_cursor(&ctx, 0, 0);
screen_write_delete_lines(&ctx, 1);
window_scroll_write_line(w, &ctx, screen_last_y(s));
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, 1);
window_scroll_write_line(w, &ctx, screen_size_y(s) - 1);
window_scroll_write_line(w, &ctx, 0);
screen_write_stop(&ctx);
}
@ -237,10 +246,10 @@ window_scroll_scroll_right(struct window *w)
screen_write_start_window(&ctx, w);
for (i = 1; i < screen_size_y(s); i++) {
screen_write_move_cursor(&ctx, 0, i);
screen_write_delete_characters(&ctx, 1);
screen_write_cursormove(&ctx, 0, i);
screen_write_deletecharacter(&ctx, 1);
}
window_scroll_write_column(w, &ctx, screen_last_x(s));
window_scroll_write_column(w, &ctx, screen_size_x(s) - 1);
window_scroll_write_line(w, &ctx, 0);
screen_write_stop(&ctx);
}
@ -259,8 +268,8 @@ window_scroll_scroll_left(struct window *w)
screen_write_start_window(&ctx, w);
for (i = 1; i < screen_size_y(s); i++) {
screen_write_move_cursor(&ctx, 0, i);
screen_write_insert_characters(&ctx, 1);
screen_write_cursormove(&ctx, 0, i);
screen_write_insertcharacter(&ctx, 1);
}
window_scroll_write_column(w, &ctx, 0);
window_scroll_write_line(w, &ctx, 0);