mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 01:34:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			458 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			458 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Id: screen-display.c,v 1.16 2008-06-04 19:20:09 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"
 | 
						|
 | 
						|
/* Set a cell. */
 | 
						|
void
 | 
						|
screen_display_set_cell(
 | 
						|
    struct screen *s, u_int px, u_int py, u_char data, u_char attr, u_char colr)
 | 
						|
{
 | 
						|
	screen_set_cell(s, screen_x(s, px), screen_y(s, py), data, attr, colr);
 | 
						|
}
 | 
						|
 | 
						|
/* 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 != SCREEN_DEFATTR || s->colr != SCREEN_DEFCOLR) {
 | 
						|
		screen_display_fill_area(s, 0, py,
 | 
						|
		    screen_size_x(s), ny, SCREEN_DEFDATA, s->attr, s->colr);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* 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_char attr, u_char colr)
 | 
						|
{
 | 
						|
	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, colr);
 | 
						|
}
 | 
						|
 | 
						|
/* 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_colr = xrealloc(s->grid_colr, sy, sizeof *s->grid_colr);
 | 
						|
		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);
 | 
						|
		memmove(&s->grid_attr[py][px + nx], &s->grid_attr[py][px], mx);
 | 
						|
		memmove(&s->grid_colr[py][px + nx], &s->grid_colr[py][px], mx);
 | 
						|
	}
 | 
						|
 | 
						|
	memset(&s->grid_data[py][px], SCREEN_DEFDATA, nx);
 | 
						|
	memset(&s->grid_attr[py][px], s->attr, nx);
 | 
						|
	memset(&s->grid_colr[py][px], s->colr, 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_colr[py][px], &s->grid_colr[py][px + nx], mx);
 | 
						|
	}
 | 
						|
 | 
						|
	memset(&s->grid_data[py][screen_size_x(s) - nx], SCREEN_DEFDATA, nx);
 | 
						|
	memset(&s->grid_attr[py][screen_size_x(s) - nx], s->attr, nx);
 | 
						|
	memset(&s->grid_colr[py][screen_size_x(s) - nx], s->colr, 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_char	data, attr, colr;
 | 
						|
 | 
						|
	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, &colr);
 | 
						|
			screen_display_set_cell(dst, j, i, data, attr, colr);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |