Annotation of src/usr.bin/tmux/screen.c, Revision 1.9
1.9 ! nicm 1: /* $OpenBSD: screen.c,v 1.8 2009/07/13 10:43:52 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:
1.6 nicm 57: grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy);
1.1 nicm 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:
126: if (sx == 0)
127: fatalx("zero size");
128:
1.7 nicm 129: /*
130: * Treat resizing horizontally simply: just ensure the cursor is
131: * on-screen and change the size. Don't bother to truncate any lines -
132: * then the data should be accessible if the size is then incrased.
133: *
134: * The only potential wrinkle is if UTF-8 double-width characters are
135: * left in the last column, but UTF-8 terminals should deal with this
136: * sanely.
137: */
1.1 nicm 138: if (s->cx >= sx)
139: s->cx = sx - 1;
140: gd->sx = sx;
141: }
142:
143: void
144: screen_resize_y(struct screen *s, u_int sy)
145: {
146: struct grid *gd = s->grid;
1.4 nicm 147: u_int needed, available, oldy, i;
1.1 nicm 148:
149: if (sy == 0)
150: fatalx("zero size");
1.4 nicm 151: oldy = screen_size_y(s);
152:
153: /*
154: * When resizing:
155: *
156: * If the height is decreasing, delete lines from the bottom until
157: * hitting the cursor, then push lines from the top into the history.
158: *
159: * When increasing, pull as many lines as possible from the history to
160: * the top, then fill the remaining with blanks at the bottom.
161: */
1.1 nicm 162:
163: /* Size decreasing. */
1.4 nicm 164: if (sy < oldy) {
165: needed = oldy - sy;
1.1 nicm 166:
1.4 nicm 167: /* Delete as many lines as possible from the bottom. */
168: available = oldy - 1 - s->cy;
169: if (available > 0) {
170: if (available > needed)
171: available = needed;
172: grid_view_delete_lines(gd, oldy - available, available);
1.1 nicm 173: }
1.4 nicm 174: needed -= available;
1.1 nicm 175:
1.4 nicm 176: /*
1.8 nicm 177: * Now just increase the history size, if possible, to take
178: * over the lines which are left. If history is off, delete
179: * lines from the top.
180: *
181: * XXX Should apply history limit?
1.4 nicm 182: */
1.8 nicm 183: available = s->cy;
184: if (gd->flags & GRID_HISTORY)
185: gd->hsize += needed;
1.9 ! nicm 186: else if (needed > 0 && available > 0) {
1.8 nicm 187: if (available > needed)
188: available = needed;
189: grid_view_delete_lines(gd, 0, available);
190: }
1.4 nicm 191: s->cy -= needed;
192: }
1.1 nicm 193:
194: /* Resize line arrays. */
195: gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size);
196: gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data);
197: gd->usize = xrealloc(gd->usize, gd->hsize + sy, sizeof *gd->usize);
198: gd->udata = xrealloc(gd->udata, gd->hsize + sy, sizeof *gd->udata);
199:
200: /* Size increasing. */
1.4 nicm 201: if (sy > oldy) {
202: needed = sy - oldy;
203:
1.8 nicm 204: /*
205: * Try to pull as much as possible out of the history, if is
206: * is enabled.
207: */
1.4 nicm 208: available = gd->hsize;
1.8 nicm 209: if (gd->flags & GRID_HISTORY && available > 0) {
1.4 nicm 210: if (available > needed)
211: available = needed;
212: gd->hsize -= available;
213: s->cy += available;
1.8 nicm 214: } else
215: available = 0;
1.4 nicm 216: needed -= available;
217:
218: /* Then fill the rest in with blanks. */
219: for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) {
1.5 nicm 220: gd->size[i] = 0;
221: gd->data[i] = NULL;
222: gd->usize[i] = 0;
223: gd->udata[i] = NULL;
1.1 nicm 224: }
225: }
226:
1.4 nicm 227: /* Set the new size, and reset the scroll region. */
1.1 nicm 228: gd->sy = sy;
229: s->rupper = 0;
230: s->rlower = screen_size_y(s) - 1;
231: }
232:
233: /* Set selection. */
234: void
235: screen_set_selection(struct screen *s,
236: u_int sx, u_int sy, u_int ex, u_int ey, struct grid_cell *gc)
237: {
238: struct screen_sel *sel = &s->sel;
239:
240: memcpy(&sel->cell, gc, sizeof sel->cell);
241:
242: sel->flag = 1;
243: if (ey < sy || (sy == ey && ex < sx)) {
244: sel->sx = ex; sel->sy = ey;
245: sel->ex = sx; sel->ey = sy;
246: } else {
247: sel->sx = sx; sel->sy = sy;
248: sel->ex = ex; sel->ey = ey;
249: }
250: }
251:
252: /* Clear selection. */
253: void
254: screen_clear_selection(struct screen *s)
255: {
256: struct screen_sel *sel = &s->sel;
257:
258: sel->flag = 0;
259: }
260:
261: /* Check if cell in selection. */
262: int
263: screen_check_selection(struct screen *s, u_int px, u_int py)
264: {
265: struct screen_sel *sel = &s->sel;
266:
267: if (!sel->flag || py < sel->sy || py > sel->ey)
268: return (0);
269:
270: if (py == sel->sy && py == sel->ey) {
271: if (px < sel->sx || px > sel->ex)
272: return (0);
273: return (1);
274: }
275:
276: if ((py == sel->sy && px < sel->sx) || (py == sel->ey && px > sel->ex))
277: return (0);
278: return (1);
279: }