Annotation of src/usr.bin/tmux/screen.c, Revision 1.3
1.3 ! nicm 1: /* $OpenBSD: screen.c,v 1.2 2009/06/03 19:33:04 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
1.3 ! nicm 21: #include <stdlib.h>
1.1 nicm 22: #include <string.h>
1.2 nicm 23: #include <vis.h>
1.1 nicm 24:
25: #include "tmux.h"
26:
27: void screen_resize_x(struct screen *, u_int);
28: void screen_resize_y(struct screen *, u_int);
29:
30: /* Create a new screen. */
31: void
32: screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
33: {
34: s->grid = grid_create(sx, sy, hlimit);
35:
36: s->title = xstrdup("");
37:
1.3 ! nicm 38: s->tabs = NULL;
! 39:
1.1 nicm 40: screen_reinit(s);
41: }
42:
43: /* Reinitialise screen. */
44: void
45: screen_reinit(struct screen *s)
46: {
47: s->cx = 0;
48: s->cy = 0;
49:
50: s->rupper = 0;
51: s->rlower = screen_size_y(s) - 1;
52:
53: s->mode = MODE_CURSOR;
1.3 ! nicm 54:
! 55: screen_reset_tabs(s);
1.1 nicm 56:
57: grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy - 1);
58:
59: screen_clear_selection(s);
60: }
61:
62: /* Destroy a screen. */
63: void
64: screen_free(struct screen *s)
65: {
66: xfree(s->title);
67: grid_destroy(s->grid);
68: }
69:
1.3 ! nicm 70: /* Reset tabs to default, eight spaces apart. */
! 71: void
! 72: screen_reset_tabs(struct screen *s)
! 73: {
! 74: u_int i;
! 75:
! 76: if (s->tabs != NULL)
! 77: xfree(s->tabs);
! 78:
! 79: if ((s->tabs = bit_alloc(screen_size_x(s))) == NULL)
! 80: fatal("bit_alloc failed");
! 81: for (i = 8; i < screen_size_x(s); i += 8)
! 82: bit_set(s->tabs, i);
! 83: }
! 84:
1.1 nicm 85: /* Set screen title. */
86: void
87: screen_set_title(struct screen *s, const char *title)
88: {
1.2 nicm 89: char tmp[BUFSIZ];
90:
91: strnvis(tmp, title, sizeof tmp, VIS_OCTAL|VIS_TAB|VIS_NL);
92:
1.1 nicm 93: xfree(s->title);
1.2 nicm 94: s->title = xstrdup(tmp);
1.1 nicm 95: }
96:
97: /* Resize screen. */
98: void
99: screen_resize(struct screen *s, u_int sx, u_int sy)
100: {
101: if (sx < 1)
102: sx = 1;
103: if (sy < 1)
104: sy = 1;
105:
1.3 ! nicm 106: if (sx != screen_size_x(s)) {
1.1 nicm 107: screen_resize_x(s, sx);
1.3 ! nicm 108:
! 109: /*
! 110: * It is unclear what should happen to tabs on resize. xterm
! 111: * seems to try and maintain them, rxvt resets them. Resetting
! 112: * is simpler and more reliable so let's do that.
! 113: */
! 114: screen_reset_tabs(s);
! 115: }
! 116:
1.1 nicm 117: if (sy != screen_size_y(s))
118: screen_resize_y(s, sy);
119: }
120:
121: void
122: screen_resize_x(struct screen *s, u_int sx)
123: {
124: struct grid *gd = s->grid;
125: const struct grid_cell *gc;
126: const struct grid_utf8 *gu;
127: u_int xx, yy;
128:
129: if (sx == 0)
130: fatalx("zero size");
131:
132: /* If getting larger, not much to do. */
133: if (sx > screen_size_x(s)) {
134: gd->sx = sx;
135: return;
136: }
137:
138: /* If getting smaller, nuke any data in lines over the new size. */
139: for (yy = gd->hsize; yy < gd->hsize + screen_size_y(s); yy++) {
140: /*
141: * If the character after the last is wide or padding, remove
142: * it and any leading padding.
143: */
144: gc = &grid_default_cell;
145: for (xx = sx; xx > 0; xx--) {
146: gc = grid_peek_cell(gd, xx - 1, yy);
147: if (!(gc->flags & GRID_FLAG_PADDING))
148: break;
149: grid_set_cell(gd, xx - 1, yy, &grid_default_cell);
150: }
151: if (xx > 0 && xx != sx && gc->flags & GRID_FLAG_UTF8) {
152: gu = grid_peek_utf8(gd, xx - 1, yy);
153: if (gu->width > 1) {
154: grid_set_cell(
155: gd, xx - 1, yy, &grid_default_cell);
156: }
157: }
158:
159: /* Reduce the line size. */
160: grid_reduce_line(gd, yy, sx);
161: }
162:
163: if (s->cx >= sx)
164: s->cx = sx - 1;
165: gd->sx = sx;
166: }
167:
168: void
169: screen_resize_y(struct screen *s, u_int sy)
170: {
171: struct grid *gd = s->grid;
172: u_int oy, yy, ny;
173:
174: if (sy == 0)
175: fatalx("zero size");
176:
177: /* Size decreasing. */
178: if (sy < screen_size_y(s)) {
179: oy = screen_size_y(s);
180:
181: if (s->cy != 0) {
182: /*
183: * The cursor is not at the start. Try to remove as
184: * many lines as possible from the top. (Up to the
185: * cursor line.)
186: */
187: ny = s->cy;
188: if (ny > oy - sy)
189: ny = oy - sy;
190:
191: grid_view_delete_lines(gd, 0, ny);
192:
193: s->cy -= ny;
194: oy -= ny;
195: }
196:
197: if (sy < oy) {
198: /* Remove any remaining lines from the bottom. */
199: grid_view_delete_lines(gd, sy, oy - sy);
200: if (s->cy >= sy)
201: s->cy = sy - 1;
202: }
203: }
204:
205: /* Resize line arrays. */
206: gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size);
207: gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data);
208: gd->usize = xrealloc(gd->usize, gd->hsize + sy, sizeof *gd->usize);
209: gd->udata = xrealloc(gd->udata, gd->hsize + sy, sizeof *gd->udata);
210:
211: /* Size increasing. */
212: if (sy > screen_size_y(s)) {
213: oy = screen_size_y(s);
214: for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) {
215: gd->size[yy] = 0;
216: gd->data[yy] = NULL;
217: gd->usize[yy] = 0;
218: gd->udata[yy] = NULL;
219: }
220: }
221:
222: gd->sy = sy;
223:
224: s->rupper = 0;
225: s->rlower = screen_size_y(s) - 1;
226: }
227:
228: /* Set selection. */
229: void
230: screen_set_selection(struct screen *s,
231: u_int sx, u_int sy, u_int ex, u_int ey, struct grid_cell *gc)
232: {
233: struct screen_sel *sel = &s->sel;
234:
235: memcpy(&sel->cell, gc, sizeof sel->cell);
236:
237: sel->flag = 1;
238: if (ey < sy || (sy == ey && ex < sx)) {
239: sel->sx = ex; sel->sy = ey;
240: sel->ex = sx; sel->ey = sy;
241: } else {
242: sel->sx = sx; sel->sy = sy;
243: sel->ex = ex; sel->ey = ey;
244: }
245: }
246:
247: /* Clear selection. */
248: void
249: screen_clear_selection(struct screen *s)
250: {
251: struct screen_sel *sel = &s->sel;
252:
253: sel->flag = 0;
254: }
255:
256: /* Check if cell in selection. */
257: int
258: screen_check_selection(struct screen *s, u_int px, u_int py)
259: {
260: struct screen_sel *sel = &s->sel;
261:
262: if (!sel->flag || py < sel->sy || py > sel->ey)
263: return (0);
264:
265: if (py == sel->sy && py == sel->ey) {
266: if (px < sel->sx || px > sel->ex)
267: return (0);
268: return (1);
269: }
270:
271: if ((py == sel->sy && px < sel->sx) || (py == sel->ey && px > sel->ex))
272: return (0);
273: return (1);
274: }