1 |
|
|
/* $OpenBSD: tty.c,v 1.205 2016/07/15 00:49:08 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> |
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 |
|
|
#include <sys/ioctl.h> |
21 |
|
|
|
22 |
|
|
#include <netinet/in.h> |
23 |
|
|
|
24 |
|
|
#include <errno.h> |
25 |
|
|
#include <fcntl.h> |
26 |
|
|
#include <resolv.h> |
27 |
|
|
#include <stdlib.h> |
28 |
|
|
#include <string.h> |
29 |
|
|
#include <termios.h> |
30 |
|
|
#include <unistd.h> |
31 |
|
|
|
32 |
|
|
#include "tmux.h" |
33 |
|
|
|
34 |
|
|
static int tty_log_fd = -1; |
35 |
|
|
|
36 |
|
|
void tty_read_callback(struct bufferevent *, void *); |
37 |
|
|
void tty_error_callback(struct bufferevent *, short, void *); |
38 |
|
|
|
39 |
|
|
static int tty_client_ready(struct client *, struct window_pane *); |
40 |
|
|
|
41 |
|
|
void tty_set_italics(struct tty *); |
42 |
|
|
int tty_try_colour(struct tty *, int, const char *); |
43 |
|
|
|
44 |
|
|
void tty_colours(struct tty *, const struct grid_cell *); |
45 |
|
|
void tty_check_fg(struct tty *, struct grid_cell *); |
46 |
|
|
void tty_check_bg(struct tty *, struct grid_cell *); |
47 |
|
|
void tty_colours_fg(struct tty *, const struct grid_cell *); |
48 |
|
|
void tty_colours_bg(struct tty *, const struct grid_cell *); |
49 |
|
|
|
50 |
|
|
int tty_large_region(struct tty *, const struct tty_ctx *); |
51 |
|
|
int tty_fake_bce(const struct tty *, const struct window_pane *); |
52 |
|
|
void tty_redraw_region(struct tty *, const struct tty_ctx *); |
53 |
|
|
void tty_emulate_repeat(struct tty *, enum tty_code_code, enum tty_code_code, |
54 |
|
|
u_int); |
55 |
|
|
void tty_repeat_space(struct tty *, u_int); |
56 |
|
|
void tty_cell(struct tty *, const struct grid_cell *, |
57 |
|
|
const struct window_pane *); |
58 |
|
|
void tty_default_colours(struct grid_cell *, const struct window_pane *); |
59 |
|
|
|
60 |
|
|
#define tty_use_acs(tty) \ |
61 |
|
|
(tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) |
62 |
|
|
|
63 |
|
|
#define tty_pane_full_width(tty, ctx) \ |
64 |
|
|
((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) |
65 |
|
|
|
66 |
|
|
void |
67 |
|
|
tty_create_log(void) |
68 |
|
|
{ |
69 |
|
|
char name[64]; |
70 |
|
|
|
71 |
|
|
xsnprintf(name, sizeof name, "tmux-out-%ld.log", (long)getpid()); |
72 |
|
|
|
73 |
|
|
tty_log_fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644); |
74 |
|
|
if (tty_log_fd != -1 && fcntl(tty_log_fd, F_SETFD, FD_CLOEXEC) == -1) |
75 |
|
|
fatal("fcntl failed"); |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
int |
79 |
|
|
tty_init(struct tty *tty, struct client *c, int fd, char *term) |
80 |
|
|
{ |
81 |
|
|
char *path; |
82 |
|
|
|
83 |
|
|
if (!isatty(fd)) |
84 |
|
|
return (-1); |
85 |
|
|
|
86 |
|
|
memset(tty, 0, sizeof *tty); |
87 |
|
|
|
88 |
|
|
if (term == NULL || *term == '\0') |
89 |
|
|
tty->termname = xstrdup("unknown"); |
90 |
|
|
else |
91 |
|
|
tty->termname = xstrdup(term); |
92 |
|
|
tty->fd = fd; |
93 |
|
|
tty->client = c; |
94 |
|
|
|
95 |
|
|
if ((path = ttyname(fd)) == NULL) |
96 |
|
|
return (-1); |
97 |
|
|
tty->path = xstrdup(path); |
98 |
|
|
tty->cstyle = 0; |
99 |
|
|
tty->ccolour = xstrdup(""); |
100 |
|
|
|
101 |
|
|
tty->flags = 0; |
102 |
|
|
tty->term_flags = 0; |
103 |
|
|
|
104 |
|
|
return (0); |
105 |
|
|
} |
106 |
|
|
|
107 |
|
|
int |
108 |
|
|
tty_resize(struct tty *tty) |
109 |
|
|
{ |
110 |
|
|
struct winsize ws; |
111 |
|
|
u_int sx, sy; |
112 |
|
|
|
113 |
|
|
if (ioctl(tty->fd, TIOCGWINSZ, &ws) != -1) { |
114 |
|
|
sx = ws.ws_col; |
115 |
|
|
if (sx == 0) |
116 |
|
|
sx = 80; |
117 |
|
|
sy = ws.ws_row; |
118 |
|
|
if (sy == 0) |
119 |
|
|
sy = 24; |
120 |
|
|
} else { |
121 |
|
|
sx = 80; |
122 |
|
|
sy = 24; |
123 |
|
|
} |
124 |
|
|
if (!tty_set_size(tty, sx, sy)) |
125 |
|
|
return (0); |
126 |
|
|
|
127 |
|
|
tty->cx = UINT_MAX; |
128 |
|
|
tty->cy = UINT_MAX; |
129 |
|
|
|
130 |
|
|
tty->rupper = UINT_MAX; |
131 |
|
|
tty->rlower = UINT_MAX; |
132 |
|
|
|
133 |
|
|
/* |
134 |
|
|
* If the terminal has been started, reset the actual scroll region and |
135 |
|
|
* cursor position, as this may not have happened. |
136 |
|
|
*/ |
137 |
|
|
if (tty->flags & TTY_STARTED) { |
138 |
|
|
tty_cursor(tty, 0, 0); |
139 |
|
|
tty_region(tty, 0, tty->sy - 1); |
140 |
|
|
} |
141 |
|
|
|
142 |
|
|
return (1); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
int |
146 |
|
|
tty_set_size(struct tty *tty, u_int sx, u_int sy) { |
147 |
|
|
if (sx == tty->sx && sy == tty->sy) |
148 |
|
|
return (0); |
149 |
|
|
tty->sx = sx; |
150 |
|
|
tty->sy = sy; |
151 |
|
|
return (1); |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
int |
155 |
|
|
tty_open(struct tty *tty, char **cause) |
156 |
|
|
{ |
157 |
|
|
tty->term = tty_term_find(tty->termname, tty->fd, cause); |
158 |
|
|
if (tty->term == NULL) { |
159 |
|
|
tty_close(tty); |
160 |
|
|
return (-1); |
161 |
|
|
} |
162 |
|
|
tty->flags |= TTY_OPENED; |
163 |
|
|
|
164 |
|
|
tty->flags &= ~(TTY_NOCURSOR|TTY_FREEZE|TTY_TIMER); |
165 |
|
|
|
166 |
|
|
tty->event = bufferevent_new(tty->fd, tty_read_callback, NULL, |
167 |
|
|
tty_error_callback, tty); |
168 |
|
|
|
169 |
|
|
tty_start_tty(tty); |
170 |
|
|
|
171 |
|
|
tty_keys_build(tty); |
172 |
|
|
|
173 |
|
|
return (0); |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
void |
177 |
|
|
tty_read_callback(__unused struct bufferevent *bufev, void *data) |
178 |
|
|
{ |
179 |
|
|
struct tty *tty = data; |
180 |
|
|
|
181 |
|
|
while (tty_keys_next(tty)) |
182 |
|
|
; |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
void |
186 |
|
|
tty_error_callback(__unused struct bufferevent *bufev, __unused short what, |
187 |
|
|
__unused void *data) |
188 |
|
|
{ |
189 |
|
|
} |
190 |
|
|
|
191 |
|
|
void |
192 |
|
|
tty_init_termios(int fd, struct termios *orig_tio, struct bufferevent *bufev) |
193 |
|
|
{ |
194 |
|
|
struct termios tio; |
195 |
|
|
|
196 |
|
|
if (fd == -1 || tcgetattr(fd, orig_tio) != 0) |
197 |
|
|
return; |
198 |
|
|
|
199 |
|
|
setblocking(fd, 0); |
200 |
|
|
|
201 |
|
|
if (bufev != NULL) |
202 |
|
|
bufferevent_enable(bufev, EV_READ|EV_WRITE); |
203 |
|
|
|
204 |
|
|
memcpy(&tio, orig_tio, sizeof tio); |
205 |
|
|
tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP); |
206 |
|
|
tio.c_iflag |= IGNBRK; |
207 |
|
|
tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET); |
208 |
|
|
tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL| |
209 |
|
|
ECHOPRT|ECHOKE|ISIG); |
210 |
|
|
tio.c_cc[VMIN] = 1; |
211 |
|
|
tio.c_cc[VTIME] = 0; |
212 |
|
|
if (tcsetattr(fd, TCSANOW, &tio) == 0) |
213 |
|
|
tcflush(fd, TCIOFLUSH); |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
void |
217 |
|
|
tty_start_tty(struct tty *tty) |
218 |
|
|
{ |
219 |
|
|
tty_init_termios(tty->fd, &tty->tio, tty->event); |
220 |
|
|
|
221 |
|
|
tty_putcode(tty, TTYC_SMCUP); |
222 |
|
|
|
223 |
|
|
tty_putcode(tty, TTYC_SGR0); |
224 |
|
|
memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); |
225 |
|
|
|
226 |
|
|
tty_putcode(tty, TTYC_RMKX); |
227 |
|
|
if (tty_use_acs(tty)) |
228 |
|
|
tty_putcode(tty, TTYC_ENACS); |
229 |
|
|
tty_putcode(tty, TTYC_CLEAR); |
230 |
|
|
|
231 |
|
|
tty_putcode(tty, TTYC_CNORM); |
232 |
|
|
if (tty_term_has(tty->term, TTYC_KMOUS)) |
233 |
|
|
tty_puts(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l"); |
234 |
|
|
|
235 |
|
|
if (tty_term_flag(tty->term, TTYC_XT)) { |
236 |
|
|
if (options_get_number(global_options, "focus-events")) { |
237 |
|
|
tty->flags |= TTY_FOCUS; |
238 |
|
|
tty_puts(tty, "\033[?1004h"); |
239 |
|
|
} |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
tty->cx = UINT_MAX; |
243 |
|
|
tty->cy = UINT_MAX; |
244 |
|
|
|
245 |
|
|
tty->rlower = UINT_MAX; |
246 |
|
|
tty->rupper = UINT_MAX; |
247 |
|
|
|
248 |
|
|
tty->mode = MODE_CURSOR; |
249 |
|
|
|
250 |
|
|
tty->flags |= TTY_STARTED; |
251 |
|
|
|
252 |
|
|
tty_force_cursor_colour(tty, ""); |
253 |
|
|
|
254 |
|
|
tty->mouse_drag_flag = 0; |
255 |
|
|
tty->mouse_drag_update = NULL; |
256 |
|
|
tty->mouse_drag_release = NULL; |
257 |
|
|
} |
258 |
|
|
|
259 |
|
|
void |
260 |
|
|
tty_stop_tty(struct tty *tty) |
261 |
|
|
{ |
262 |
|
|
struct winsize ws; |
263 |
|
|
|
264 |
|
|
if (!(tty->flags & TTY_STARTED)) |
265 |
|
|
return; |
266 |
|
|
tty->flags &= ~TTY_STARTED; |
267 |
|
|
|
268 |
|
|
bufferevent_disable(tty->event, EV_READ|EV_WRITE); |
269 |
|
|
|
270 |
|
|
/* |
271 |
|
|
* Be flexible about error handling and try not kill the server just |
272 |
|
|
* because the fd is invalid. Things like ssh -t can easily leave us |
273 |
|
|
* with a dead tty. |
274 |
|
|
*/ |
275 |
|
|
if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) |
276 |
|
|
return; |
277 |
|
|
if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) |
278 |
|
|
return; |
279 |
|
|
|
280 |
|
|
tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); |
281 |
|
|
if (tty_use_acs(tty)) |
282 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); |
283 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); |
284 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); |
285 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); |
286 |
|
|
if (tty_term_has(tty->term, TTYC_SS) && tty->cstyle != 0) { |
287 |
|
|
if (tty_term_has(tty->term, TTYC_SE)) |
288 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_SE)); |
289 |
|
|
else |
290 |
|
|
tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0)); |
291 |
|
|
} |
292 |
|
|
if (tty->mode & MODE_BRACKETPASTE) |
293 |
|
|
tty_raw(tty, "\033[?2004l"); |
294 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); |
295 |
|
|
|
296 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); |
297 |
|
|
if (tty_term_has(tty->term, TTYC_KMOUS)) |
298 |
|
|
tty_raw(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l"); |
299 |
|
|
|
300 |
|
|
if (tty_term_flag(tty->term, TTYC_XT)) { |
301 |
|
|
if (tty->flags & TTY_FOCUS) { |
302 |
|
|
tty->flags &= ~TTY_FOCUS; |
303 |
|
|
tty_raw(tty, "\033[?1004l"); |
304 |
|
|
} |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); |
308 |
|
|
|
309 |
|
|
setblocking(tty->fd, 1); |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
void |
313 |
|
|
tty_close(struct tty *tty) |
314 |
|
|
{ |
315 |
|
|
if (event_initialized(&tty->key_timer)) |
316 |
|
|
evtimer_del(&tty->key_timer); |
317 |
|
|
tty_stop_tty(tty); |
318 |
|
|
|
319 |
|
|
if (tty->flags & TTY_OPENED) { |
320 |
|
|
bufferevent_free(tty->event); |
321 |
|
|
|
322 |
|
|
tty_term_free(tty->term); |
323 |
|
|
tty_keys_free(tty); |
324 |
|
|
|
325 |
|
|
tty->flags &= ~TTY_OPENED; |
326 |
|
|
} |
327 |
|
|
|
328 |
|
|
if (tty->fd != -1) { |
329 |
|
|
close(tty->fd); |
330 |
|
|
tty->fd = -1; |
331 |
|
|
} |
332 |
|
|
} |
333 |
|
|
|
334 |
|
|
void |
335 |
|
|
tty_free(struct tty *tty) |
336 |
|
|
{ |
337 |
|
|
tty_close(tty); |
338 |
|
|
|
339 |
|
|
free(tty->ccolour); |
340 |
|
|
free(tty->path); |
341 |
|
|
free(tty->termname); |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
void |
345 |
|
|
tty_raw(struct tty *tty, const char *s) |
346 |
|
|
{ |
347 |
|
|
ssize_t n, slen; |
348 |
|
|
u_int i; |
349 |
|
|
|
350 |
|
|
slen = strlen(s); |
351 |
|
|
for (i = 0; i < 5; i++) { |
352 |
|
|
n = write(tty->fd, s, slen); |
353 |
|
|
if (n >= 0) { |
354 |
|
|
s += n; |
355 |
|
|
slen -= n; |
356 |
|
|
if (slen == 0) |
357 |
|
|
break; |
358 |
|
|
} else if (n == -1 && errno != EAGAIN) |
359 |
|
|
break; |
360 |
|
|
usleep(100); |
361 |
|
|
} |
362 |
|
|
} |
363 |
|
|
|
364 |
|
|
void |
365 |
|
|
tty_putcode(struct tty *tty, enum tty_code_code code) |
366 |
|
|
{ |
367 |
|
|
tty_puts(tty, tty_term_string(tty->term, code)); |
368 |
|
|
} |
369 |
|
|
|
370 |
|
|
void |
371 |
|
|
tty_putcode1(struct tty *tty, enum tty_code_code code, int a) |
372 |
|
|
{ |
373 |
|
|
if (a < 0) |
374 |
|
|
return; |
375 |
|
|
tty_puts(tty, tty_term_string1(tty->term, code, a)); |
376 |
|
|
} |
377 |
|
|
|
378 |
|
|
void |
379 |
|
|
tty_putcode2(struct tty *tty, enum tty_code_code code, int a, int b) |
380 |
|
|
{ |
381 |
|
|
if (a < 0 || b < 0) |
382 |
|
|
return; |
383 |
|
|
tty_puts(tty, tty_term_string2(tty->term, code, a, b)); |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
void |
387 |
|
|
tty_putcode_ptr1(struct tty *tty, enum tty_code_code code, const void *a) |
388 |
|
|
{ |
389 |
|
|
if (a != NULL) |
390 |
|
|
tty_puts(tty, tty_term_ptr1(tty->term, code, a)); |
391 |
|
|
} |
392 |
|
|
|
393 |
|
|
void |
394 |
|
|
tty_putcode_ptr2(struct tty *tty, enum tty_code_code code, const void *a, |
395 |
|
|
const void *b) |
396 |
|
|
{ |
397 |
|
|
if (a != NULL && b != NULL) |
398 |
|
|
tty_puts(tty, tty_term_ptr2(tty->term, code, a, b)); |
399 |
|
|
} |
400 |
|
|
|
401 |
|
|
void |
402 |
|
|
tty_puts(struct tty *tty, const char *s) |
403 |
|
|
{ |
404 |
|
|
if (*s == '\0') |
405 |
|
|
return; |
406 |
|
|
bufferevent_write(tty->event, s, strlen(s)); |
407 |
|
|
|
408 |
|
|
if (tty_log_fd != -1) |
409 |
|
|
write(tty_log_fd, s, strlen(s)); |
410 |
|
|
} |
411 |
|
|
|
412 |
|
|
void |
413 |
|
|
tty_putc(struct tty *tty, u_char ch) |
414 |
|
|
{ |
415 |
|
|
const char *acs; |
416 |
|
|
u_int sx; |
417 |
|
|
|
418 |
|
|
if (tty->cell.attr & GRID_ATTR_CHARSET) { |
419 |
|
|
acs = tty_acs_get(tty, ch); |
420 |
|
|
if (acs != NULL) |
421 |
|
|
bufferevent_write(tty->event, acs, strlen(acs)); |
422 |
|
|
else |
423 |
|
|
bufferevent_write(tty->event, &ch, 1); |
424 |
|
|
} else |
425 |
|
|
bufferevent_write(tty->event, &ch, 1); |
426 |
|
|
|
427 |
|
|
if (ch >= 0x20 && ch != 0x7f) { |
428 |
|
|
sx = tty->sx; |
429 |
|
|
if (tty->term->flags & TERM_EARLYWRAP) |
430 |
|
|
sx--; |
431 |
|
|
|
432 |
|
|
if (tty->cx >= sx) { |
433 |
|
|
tty->cx = 1; |
434 |
|
|
if (tty->cy != tty->rlower) |
435 |
|
|
tty->cy++; |
436 |
|
|
} else |
437 |
|
|
tty->cx++; |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
if (tty_log_fd != -1) |
441 |
|
|
write(tty_log_fd, &ch, 1); |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
void |
445 |
|
|
tty_putn(struct tty *tty, const void *buf, size_t len, u_int width) |
446 |
|
|
{ |
447 |
|
|
bufferevent_write(tty->event, buf, len); |
448 |
|
|
if (tty_log_fd != -1) |
449 |
|
|
write(tty_log_fd, buf, len); |
450 |
|
|
tty->cx += width; |
451 |
|
|
} |
452 |
|
|
|
453 |
|
|
void |
454 |
|
|
tty_set_italics(struct tty *tty) |
455 |
|
|
{ |
456 |
|
|
const char *s; |
457 |
|
|
|
458 |
|
|
if (tty_term_has(tty->term, TTYC_SITM)) { |
459 |
|
|
s = options_get_string(global_options, "default-terminal"); |
460 |
|
|
if (strcmp(s, "screen") != 0 && strncmp(s, "screen-", 7) != 0) { |
461 |
|
|
tty_putcode(tty, TTYC_SITM); |
462 |
|
|
return; |
463 |
|
|
} |
464 |
|
|
} |
465 |
|
|
tty_putcode(tty, TTYC_SMSO); |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
void |
469 |
|
|
tty_set_title(struct tty *tty, const char *title) |
470 |
|
|
{ |
471 |
|
|
if (!tty_term_has(tty->term, TTYC_TSL) || |
472 |
|
|
!tty_term_has(tty->term, TTYC_FSL)) |
473 |
|
|
return; |
474 |
|
|
|
475 |
|
|
tty_putcode(tty, TTYC_TSL); |
476 |
|
|
tty_puts(tty, title); |
477 |
|
|
tty_putcode(tty, TTYC_FSL); |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
void |
481 |
|
|
tty_force_cursor_colour(struct tty *tty, const char *ccolour) |
482 |
|
|
{ |
483 |
|
|
if (*ccolour == '\0') |
484 |
|
|
tty_putcode(tty, TTYC_CR); |
485 |
|
|
else |
486 |
|
|
tty_putcode_ptr1(tty, TTYC_CS, ccolour); |
487 |
|
|
free(tty->ccolour); |
488 |
|
|
tty->ccolour = xstrdup(ccolour); |
489 |
|
|
} |
490 |
|
|
|
491 |
|
|
void |
492 |
|
|
tty_update_mode(struct tty *tty, int mode, struct screen *s) |
493 |
|
|
{ |
494 |
|
|
int changed; |
495 |
|
|
|
496 |
|
|
if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0) |
497 |
|
|
tty_force_cursor_colour(tty, s->ccolour); |
498 |
|
|
|
499 |
|
|
if (tty->flags & TTY_NOCURSOR) |
500 |
|
|
mode &= ~MODE_CURSOR; |
501 |
|
|
|
502 |
|
|
changed = mode ^ tty->mode; |
503 |
|
|
if (changed & MODE_BLINKING) { |
504 |
|
|
if (tty_term_has(tty->term, TTYC_CVVIS)) |
505 |
|
|
tty_putcode(tty, TTYC_CVVIS); |
506 |
|
|
else |
507 |
|
|
tty_putcode(tty, TTYC_CNORM); |
508 |
|
|
changed |= MODE_CURSOR; |
509 |
|
|
} |
510 |
|
|
if (changed & MODE_CURSOR) { |
511 |
|
|
if (mode & MODE_CURSOR) |
512 |
|
|
tty_putcode(tty, TTYC_CNORM); |
513 |
|
|
else |
514 |
|
|
tty_putcode(tty, TTYC_CIVIS); |
515 |
|
|
} |
516 |
|
|
if (s != NULL && tty->cstyle != s->cstyle) { |
517 |
|
|
if (tty_term_has(tty->term, TTYC_SS)) { |
518 |
|
|
if (s->cstyle == 0 && |
519 |
|
|
tty_term_has(tty->term, TTYC_SE)) |
520 |
|
|
tty_putcode(tty, TTYC_SE); |
521 |
|
|
else |
522 |
|
|
tty_putcode1(tty, TTYC_SS, s->cstyle); |
523 |
|
|
} |
524 |
|
|
tty->cstyle = s->cstyle; |
525 |
|
|
} |
526 |
|
|
if (changed & ALL_MOUSE_MODES) { |
527 |
|
|
if (mode & ALL_MOUSE_MODES) { |
528 |
|
|
/* |
529 |
|
|
* Enable the SGR (1006) extension unconditionally, as |
530 |
|
|
* this is safe from misinterpretation. Do it in this |
531 |
|
|
* order, because in some terminals it's the last one |
532 |
|
|
* that takes effect and SGR is the preferred one. |
533 |
|
|
*/ |
534 |
|
|
tty_puts(tty, "\033[?1006h"); |
535 |
|
|
if (mode & MODE_MOUSE_BUTTON) |
536 |
|
|
tty_puts(tty, "\033[?1002h"); |
537 |
|
|
else if (mode & MODE_MOUSE_STANDARD) |
538 |
|
|
tty_puts(tty, "\033[?1000h"); |
539 |
|
|
} else { |
540 |
|
|
if (tty->mode & MODE_MOUSE_BUTTON) |
541 |
|
|
tty_puts(tty, "\033[?1002l"); |
542 |
|
|
else if (tty->mode & MODE_MOUSE_STANDARD) |
543 |
|
|
tty_puts(tty, "\033[?1000l"); |
544 |
|
|
tty_puts(tty, "\033[?1006l"); |
545 |
|
|
} |
546 |
|
|
} |
547 |
|
|
if (changed & MODE_KKEYPAD) { |
548 |
|
|
if (mode & MODE_KKEYPAD) |
549 |
|
|
tty_putcode(tty, TTYC_SMKX); |
550 |
|
|
else |
551 |
|
|
tty_putcode(tty, TTYC_RMKX); |
552 |
|
|
} |
553 |
|
|
if (changed & MODE_BRACKETPASTE) { |
554 |
|
|
if (mode & MODE_BRACKETPASTE) |
555 |
|
|
tty_puts(tty, "\033[?2004h"); |
556 |
|
|
else |
557 |
|
|
tty_puts(tty, "\033[?2004l"); |
558 |
|
|
} |
559 |
|
|
tty->mode = mode; |
560 |
|
|
} |
561 |
|
|
|
562 |
|
|
void |
563 |
|
|
tty_emulate_repeat(struct tty *tty, enum tty_code_code code, |
564 |
|
|
enum tty_code_code code1, u_int n) |
565 |
|
|
{ |
566 |
|
|
if (tty_term_has(tty->term, code)) |
567 |
|
|
tty_putcode1(tty, code, n); |
568 |
|
|
else { |
569 |
|
|
while (n-- > 0) |
570 |
|
|
tty_putcode(tty, code1); |
571 |
|
|
} |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
void |
575 |
|
|
tty_repeat_space(struct tty *tty, u_int n) |
576 |
|
|
{ |
577 |
|
|
while (n-- > 0) |
578 |
|
|
tty_putc(tty, ' '); |
579 |
|
|
} |
580 |
|
|
|
581 |
|
|
/* |
582 |
|
|
* Is the region large enough to be worth redrawing once later rather than |
583 |
|
|
* probably several times now? Currently yes if it is more than 50% of the |
584 |
|
|
* pane. |
585 |
|
|
*/ |
586 |
|
|
int |
587 |
|
|
tty_large_region(__unused struct tty *tty, const struct tty_ctx *ctx) |
588 |
|
|
{ |
589 |
|
|
struct window_pane *wp = ctx->wp; |
590 |
|
|
|
591 |
|
|
return (ctx->orlower - ctx->orupper >= screen_size_y(wp->screen) / 2); |
592 |
|
|
} |
593 |
|
|
|
594 |
|
|
/* |
595 |
|
|
* Return if BCE is needed but the terminal doesn't have it - it'll need to be |
596 |
|
|
* emulated. |
597 |
|
|
*/ |
598 |
|
|
int |
599 |
|
|
tty_fake_bce(const struct tty *tty, const struct window_pane *wp) |
600 |
|
|
{ |
601 |
|
|
struct grid_cell gc; |
602 |
|
|
|
603 |
|
|
memcpy(&gc, &grid_default_cell, sizeof gc); |
604 |
|
|
if (wp != NULL) |
605 |
|
|
tty_default_colours(&gc, wp); |
606 |
|
|
|
607 |
|
|
if (gc.bg == 8) |
608 |
|
|
return (0); |
609 |
|
|
return (!tty_term_flag(tty->term, TTYC_BCE)); |
610 |
|
|
} |
611 |
|
|
|
612 |
|
|
/* |
613 |
|
|
* Redraw scroll region using data from screen (already updated). Used when |
614 |
|
|
* CSR not supported, or window is a pane that doesn't take up the full |
615 |
|
|
* width of the terminal. |
616 |
|
|
*/ |
617 |
|
|
void |
618 |
|
|
tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) |
619 |
|
|
{ |
620 |
|
|
struct window_pane *wp = ctx->wp; |
621 |
|
|
struct screen *s = wp->screen; |
622 |
|
|
u_int i; |
623 |
|
|
|
624 |
|
|
/* |
625 |
|
|
* If region is large, schedule a window redraw. In most cases this is |
626 |
|
|
* likely to be followed by some more scrolling. |
627 |
|
|
*/ |
628 |
|
|
if (tty_large_region(tty, ctx)) { |
629 |
|
|
wp->flags |= PANE_REDRAW; |
630 |
|
|
return; |
631 |
|
|
} |
632 |
|
|
|
633 |
|
|
if (ctx->ocy < ctx->orupper || ctx->ocy > ctx->orlower) { |
634 |
|
|
for (i = ctx->ocy; i < screen_size_y(s); i++) |
635 |
|
|
tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff); |
636 |
|
|
} else { |
637 |
|
|
for (i = ctx->orupper; i <= ctx->orlower; i++) |
638 |
|
|
tty_draw_pane(tty, wp, i, ctx->xoff, ctx->yoff); |
639 |
|
|
} |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
void |
643 |
|
|
tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox, |
644 |
|
|
u_int oy) |
645 |
|
|
{ |
646 |
|
|
tty_draw_line(tty, wp, wp->screen, py, ox, oy); |
647 |
|
|
} |
648 |
|
|
|
649 |
|
|
void |
650 |
|
|
tty_draw_line(struct tty *tty, const struct window_pane *wp, |
651 |
|
|
struct screen *s, u_int py, u_int ox, u_int oy) |
652 |
|
|
{ |
653 |
|
|
struct grid_cell gc; |
654 |
|
|
struct grid_line *gl; |
655 |
|
|
u_int i, sx; |
656 |
|
|
int flags; |
657 |
|
|
|
658 |
|
|
flags = tty->flags & TTY_NOCURSOR; |
659 |
|
|
tty->flags |= TTY_NOCURSOR; |
660 |
|
|
tty_update_mode(tty, tty->mode, s); |
661 |
|
|
|
662 |
|
|
sx = screen_size_x(s); |
663 |
|
|
if (sx > s->grid->linedata[s->grid->hsize + py].cellsize) |
664 |
|
|
sx = s->grid->linedata[s->grid->hsize + py].cellsize; |
665 |
|
|
if (sx > tty->sx) |
666 |
|
|
sx = tty->sx; |
667 |
|
|
|
668 |
|
|
/* |
669 |
|
|
* Don't move the cursor to the start position if it will wrap there |
670 |
|
|
* itself. |
671 |
|
|
*/ |
672 |
|
|
gl = NULL; |
673 |
|
|
if (py != 0) |
674 |
|
|
gl = &s->grid->linedata[s->grid->hsize + py - 1]; |
675 |
|
|
if (oy + py == 0 || gl == NULL || !(gl->flags & GRID_LINE_WRAPPED) || |
676 |
|
|
tty->cx < tty->sx || ox != 0 || |
677 |
|
|
(oy + py != tty->cy + 1 && tty->cy != s->rlower + oy)) |
678 |
|
|
tty_cursor(tty, ox, oy + py); |
679 |
|
|
|
680 |
|
|
for (i = 0; i < sx; i++) { |
681 |
|
|
grid_view_get_cell(s->grid, i, py, &gc); |
682 |
|
|
tty_cell(tty, &gc, wp); |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
if (sx < tty->sx) { |
686 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
687 |
|
|
|
688 |
|
|
tty_cursor(tty, ox + sx, oy + py); |
689 |
|
|
if (sx != screen_size_x(s) && |
690 |
|
|
ox + screen_size_x(s) >= tty->sx && |
691 |
|
|
tty_term_has(tty->term, TTYC_EL) && |
692 |
|
|
!tty_fake_bce(tty, wp)) |
693 |
|
|
tty_putcode(tty, TTYC_EL); |
694 |
|
|
else |
695 |
|
|
tty_repeat_space(tty, screen_size_x(s) - sx); |
696 |
|
|
} |
697 |
|
|
|
698 |
|
|
tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags; |
699 |
|
|
tty_update_mode(tty, tty->mode, s); |
700 |
|
|
} |
701 |
|
|
|
702 |
|
|
static int |
703 |
|
|
tty_client_ready(struct client *c, struct window_pane *wp) |
704 |
|
|
{ |
705 |
|
|
if (c->session == NULL || c->tty.term == NULL) |
706 |
|
|
return (0); |
707 |
|
|
if (c->flags & CLIENT_SUSPENDED) |
708 |
|
|
return (0); |
709 |
|
|
if (c->tty.flags & TTY_FREEZE) |
710 |
|
|
return (0); |
711 |
|
|
if (c->session->curw->window != wp->window) |
712 |
|
|
return (0); |
713 |
|
|
return (1); |
714 |
|
|
} |
715 |
|
|
|
716 |
|
|
void |
717 |
|
|
tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *), |
718 |
|
|
struct tty_ctx *ctx) |
719 |
|
|
{ |
720 |
|
|
struct window_pane *wp = ctx->wp; |
721 |
|
|
struct client *c; |
722 |
|
|
|
723 |
|
|
/* wp can be NULL if updating the screen but not the terminal. */ |
724 |
|
|
if (wp == NULL) |
725 |
|
|
return; |
726 |
|
|
|
727 |
|
|
if (wp->window->flags & WINDOW_REDRAW || wp->flags & PANE_REDRAW) |
728 |
|
|
return; |
729 |
|
|
if (!window_pane_visible(wp) || wp->flags & PANE_DROP) |
730 |
|
|
return; |
731 |
|
|
|
732 |
|
|
TAILQ_FOREACH(c, &clients, entry) { |
733 |
|
|
if (!tty_client_ready(c, wp)) |
734 |
|
|
continue; |
735 |
|
|
|
736 |
|
|
ctx->xoff = wp->xoff; |
737 |
|
|
ctx->yoff = wp->yoff; |
738 |
|
|
if (status_at_line(c) == 0) |
739 |
|
|
ctx->yoff++; |
740 |
|
|
|
741 |
|
|
cmdfn(&c->tty, ctx); |
742 |
|
|
} |
743 |
|
|
} |
744 |
|
|
|
745 |
|
|
void |
746 |
|
|
tty_cmd_insertcharacter(struct tty *tty, const struct tty_ctx *ctx) |
747 |
|
|
{ |
748 |
|
|
struct window_pane *wp = ctx->wp; |
749 |
|
|
|
750 |
|
|
if (!tty_pane_full_width(tty, ctx)) { |
751 |
|
|
tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); |
752 |
|
|
return; |
753 |
|
|
} |
754 |
|
|
|
755 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
756 |
|
|
|
757 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
758 |
|
|
|
759 |
|
|
if (!tty_fake_bce(tty, wp) && (tty_term_has(tty->term, TTYC_ICH) || |
760 |
|
|
tty_term_has(tty->term, TTYC_ICH1))) |
761 |
|
|
tty_emulate_repeat(tty, TTYC_ICH, TTYC_ICH1, ctx->num); |
762 |
|
|
else |
763 |
|
|
tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); |
764 |
|
|
} |
765 |
|
|
|
766 |
|
|
void |
767 |
|
|
tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) |
768 |
|
|
{ |
769 |
|
|
struct window_pane *wp = ctx->wp; |
770 |
|
|
|
771 |
|
|
if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, wp) || |
772 |
|
|
(!tty_term_has(tty->term, TTYC_DCH) && |
773 |
|
|
!tty_term_has(tty->term, TTYC_DCH1))) { |
774 |
|
|
tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); |
775 |
|
|
return; |
776 |
|
|
} |
777 |
|
|
|
778 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
779 |
|
|
|
780 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
781 |
|
|
|
782 |
|
|
if (tty_term_has(tty->term, TTYC_DCH) || |
783 |
|
|
tty_term_has(tty->term, TTYC_DCH1)) |
784 |
|
|
tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); |
785 |
|
|
} |
786 |
|
|
|
787 |
|
|
void |
788 |
|
|
tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx) |
789 |
|
|
{ |
790 |
|
|
u_int i; |
791 |
|
|
|
792 |
|
|
tty_attributes(tty, &grid_default_cell, ctx->wp); |
793 |
|
|
|
794 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
795 |
|
|
|
796 |
|
|
if (tty_term_has(tty->term, TTYC_ECH) && !tty_fake_bce(tty, ctx->wp)) |
797 |
|
|
tty_putcode1(tty, TTYC_ECH, ctx->num); |
798 |
|
|
else { |
799 |
|
|
for (i = 0; i < ctx->num; i++) |
800 |
|
|
tty_putc(tty, ' '); |
801 |
|
|
} |
802 |
|
|
} |
803 |
|
|
|
804 |
|
|
void |
805 |
|
|
tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) |
806 |
|
|
{ |
807 |
|
|
if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) || |
808 |
|
|
!tty_term_has(tty->term, TTYC_CSR) || |
809 |
|
|
!tty_term_has(tty->term, TTYC_IL1)) { |
810 |
|
|
tty_redraw_region(tty, ctx); |
811 |
|
|
return; |
812 |
|
|
} |
813 |
|
|
|
814 |
|
|
tty_attributes(tty, &grid_default_cell, ctx->wp); |
815 |
|
|
|
816 |
|
|
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); |
817 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
818 |
|
|
|
819 |
|
|
tty_emulate_repeat(tty, TTYC_IL, TTYC_IL1, ctx->num); |
820 |
|
|
} |
821 |
|
|
|
822 |
|
|
void |
823 |
|
|
tty_cmd_deleteline(struct tty *tty, const struct tty_ctx *ctx) |
824 |
|
|
{ |
825 |
|
|
if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) || |
826 |
|
|
!tty_term_has(tty->term, TTYC_CSR) || |
827 |
|
|
!tty_term_has(tty->term, TTYC_DL1)) { |
828 |
|
|
tty_redraw_region(tty, ctx); |
829 |
|
|
return; |
830 |
|
|
} |
831 |
|
|
|
832 |
|
|
tty_attributes(tty, &grid_default_cell, ctx->wp); |
833 |
|
|
|
834 |
|
|
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); |
835 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
836 |
|
|
|
837 |
|
|
tty_emulate_repeat(tty, TTYC_DL, TTYC_DL1, ctx->num); |
838 |
|
|
} |
839 |
|
|
|
840 |
|
|
void |
841 |
|
|
tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) |
842 |
|
|
{ |
843 |
|
|
struct window_pane *wp = ctx->wp; |
844 |
|
|
struct screen *s = wp->screen; |
845 |
|
|
|
846 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
847 |
|
|
|
848 |
|
|
tty_cursor_pane(tty, ctx, 0, ctx->ocy); |
849 |
|
|
|
850 |
|
|
if (tty_pane_full_width(tty, ctx) && !tty_fake_bce(tty, wp) && |
851 |
|
|
tty_term_has(tty->term, TTYC_EL)) |
852 |
|
|
tty_putcode(tty, TTYC_EL); |
853 |
|
|
else |
854 |
|
|
tty_repeat_space(tty, screen_size_x(s)); |
855 |
|
|
} |
856 |
|
|
|
857 |
|
|
void |
858 |
|
|
tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) |
859 |
|
|
{ |
860 |
|
|
struct window_pane *wp = ctx->wp; |
861 |
|
|
struct screen *s = wp->screen; |
862 |
|
|
|
863 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
864 |
|
|
|
865 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
866 |
|
|
|
867 |
|
|
if (tty_pane_full_width(tty, ctx) && |
868 |
|
|
tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) |
869 |
|
|
tty_putcode(tty, TTYC_EL); |
870 |
|
|
else |
871 |
|
|
tty_repeat_space(tty, screen_size_x(s) - ctx->ocx); |
872 |
|
|
} |
873 |
|
|
|
874 |
|
|
void |
875 |
|
|
tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) |
876 |
|
|
{ |
877 |
|
|
tty_attributes(tty, &grid_default_cell, ctx->wp); |
878 |
|
|
|
879 |
|
|
if (ctx->xoff == 0 && tty_term_has(tty->term, TTYC_EL1) && |
880 |
|
|
!tty_fake_bce(tty, ctx->wp)) { |
881 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
882 |
|
|
tty_putcode(tty, TTYC_EL1); |
883 |
|
|
} else { |
884 |
|
|
tty_cursor_pane(tty, ctx, 0, ctx->ocy); |
885 |
|
|
tty_repeat_space(tty, ctx->ocx + 1); |
886 |
|
|
} |
887 |
|
|
} |
888 |
|
|
|
889 |
|
|
void |
890 |
|
|
tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) |
891 |
|
|
{ |
892 |
|
|
if (ctx->ocy != ctx->orupper) |
893 |
|
|
return; |
894 |
|
|
|
895 |
|
|
if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, ctx->wp) || |
896 |
|
|
!tty_term_has(tty->term, TTYC_CSR) || |
897 |
|
|
!tty_term_has(tty->term, TTYC_RI)) { |
898 |
|
|
tty_redraw_region(tty, ctx); |
899 |
|
|
return; |
900 |
|
|
} |
901 |
|
|
|
902 |
|
|
tty_attributes(tty, &grid_default_cell, ctx->wp); |
903 |
|
|
|
904 |
|
|
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); |
905 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->orupper); |
906 |
|
|
|
907 |
|
|
tty_putcode(tty, TTYC_RI); |
908 |
|
|
} |
909 |
|
|
|
910 |
|
|
void |
911 |
|
|
tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) |
912 |
|
|
{ |
913 |
|
|
struct window_pane *wp = ctx->wp; |
914 |
|
|
|
915 |
|
|
if (ctx->ocy != ctx->orlower) |
916 |
|
|
return; |
917 |
|
|
|
918 |
|
|
if (!tty_pane_full_width(tty, ctx) || tty_fake_bce(tty, wp) || |
919 |
|
|
!tty_term_has(tty->term, TTYC_CSR)) { |
920 |
|
|
if (tty_large_region(tty, ctx)) |
921 |
|
|
wp->flags |= PANE_REDRAW; |
922 |
|
|
else |
923 |
|
|
tty_redraw_region(tty, ctx); |
924 |
|
|
return; |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
/* |
928 |
|
|
* If this line wrapped naturally (ctx->num is nonzero), don't do |
929 |
|
|
* anything - the cursor can just be moved to the last cell and wrap |
930 |
|
|
* naturally. |
931 |
|
|
*/ |
932 |
|
|
if (ctx->num && !(tty->term->flags & TERM_EARLYWRAP)) |
933 |
|
|
return; |
934 |
|
|
|
935 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
936 |
|
|
|
937 |
|
|
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); |
938 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
939 |
|
|
|
940 |
|
|
tty_putc(tty, '\n'); |
941 |
|
|
} |
942 |
|
|
|
943 |
|
|
void |
944 |
|
|
tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) |
945 |
|
|
{ |
946 |
|
|
struct window_pane *wp = ctx->wp; |
947 |
|
|
struct screen *s = wp->screen; |
948 |
|
|
u_int i, j; |
949 |
|
|
|
950 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
951 |
|
|
|
952 |
|
|
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); |
953 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
954 |
|
|
|
955 |
|
|
if (tty_pane_full_width(tty, ctx) && |
956 |
|
|
tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) { |
957 |
|
|
tty_putcode(tty, TTYC_EL); |
958 |
|
|
if (ctx->ocy != screen_size_y(s) - 1) { |
959 |
|
|
tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); |
960 |
|
|
for (i = ctx->ocy + 1; i < screen_size_y(s); i++) { |
961 |
|
|
tty_putcode(tty, TTYC_EL); |
962 |
|
|
if (i == screen_size_y(s) - 1) |
963 |
|
|
continue; |
964 |
|
|
tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); |
965 |
|
|
tty->cy++; |
966 |
|
|
} |
967 |
|
|
} |
968 |
|
|
} else { |
969 |
|
|
tty_repeat_space(tty, screen_size_x(s) - ctx->ocx); |
970 |
|
|
for (j = ctx->ocy + 1; j < screen_size_y(s); j++) { |
971 |
|
|
tty_cursor_pane(tty, ctx, 0, j); |
972 |
|
|
tty_repeat_space(tty, screen_size_x(s)); |
973 |
|
|
} |
974 |
|
|
} |
975 |
|
|
} |
976 |
|
|
|
977 |
|
|
void |
978 |
|
|
tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) |
979 |
|
|
{ |
980 |
|
|
struct window_pane *wp = ctx->wp; |
981 |
|
|
struct screen *s = wp->screen; |
982 |
|
|
u_int i, j; |
983 |
|
|
|
984 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
985 |
|
|
|
986 |
|
|
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); |
987 |
|
|
tty_cursor_pane(tty, ctx, 0, 0); |
988 |
|
|
|
989 |
|
|
if (tty_pane_full_width(tty, ctx) && |
990 |
|
|
tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) { |
991 |
|
|
for (i = 0; i < ctx->ocy; i++) { |
992 |
|
|
tty_putcode(tty, TTYC_EL); |
993 |
|
|
tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); |
994 |
|
|
tty->cy++; |
995 |
|
|
} |
996 |
|
|
} else { |
997 |
|
|
for (j = 0; j < ctx->ocy; j++) { |
998 |
|
|
tty_cursor_pane(tty, ctx, 0, j); |
999 |
|
|
tty_repeat_space(tty, screen_size_x(s)); |
1000 |
|
|
} |
1001 |
|
|
} |
1002 |
|
|
tty_repeat_space(tty, ctx->ocx + 1); |
1003 |
|
|
} |
1004 |
|
|
|
1005 |
|
|
void |
1006 |
|
|
tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) |
1007 |
|
|
{ |
1008 |
|
|
struct window_pane *wp = ctx->wp; |
1009 |
|
|
struct screen *s = wp->screen; |
1010 |
|
|
u_int i, j; |
1011 |
|
|
|
1012 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
1013 |
|
|
|
1014 |
|
|
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); |
1015 |
|
|
tty_cursor_pane(tty, ctx, 0, 0); |
1016 |
|
|
|
1017 |
|
|
if (tty_pane_full_width(tty, ctx) && |
1018 |
|
|
tty_term_has(tty->term, TTYC_EL) && !tty_fake_bce(tty, wp)) { |
1019 |
|
|
for (i = 0; i < screen_size_y(s); i++) { |
1020 |
|
|
tty_putcode(tty, TTYC_EL); |
1021 |
|
|
if (i != screen_size_y(s) - 1) { |
1022 |
|
|
tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); |
1023 |
|
|
tty->cy++; |
1024 |
|
|
} |
1025 |
|
|
} |
1026 |
|
|
} else { |
1027 |
|
|
for (j = 0; j < screen_size_y(s); j++) { |
1028 |
|
|
tty_cursor_pane(tty, ctx, 0, j); |
1029 |
|
|
tty_repeat_space(tty, screen_size_x(s)); |
1030 |
|
|
} |
1031 |
|
|
} |
1032 |
|
|
} |
1033 |
|
|
|
1034 |
|
|
void |
1035 |
|
|
tty_cmd_alignmenttest(struct tty *tty, const struct tty_ctx *ctx) |
1036 |
|
|
{ |
1037 |
|
|
struct window_pane *wp = ctx->wp; |
1038 |
|
|
struct screen *s = wp->screen; |
1039 |
|
|
u_int i, j; |
1040 |
|
|
|
1041 |
|
|
tty_attributes(tty, &grid_default_cell, wp); |
1042 |
|
|
|
1043 |
|
|
tty_region_pane(tty, ctx, 0, screen_size_y(s) - 1); |
1044 |
|
|
|
1045 |
|
|
for (j = 0; j < screen_size_y(s); j++) { |
1046 |
|
|
tty_cursor_pane(tty, ctx, 0, j); |
1047 |
|
|
for (i = 0; i < screen_size_x(s); i++) |
1048 |
|
|
tty_putc(tty, 'E'); |
1049 |
|
|
} |
1050 |
|
|
} |
1051 |
|
|
|
1052 |
|
|
void |
1053 |
|
|
tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) |
1054 |
|
|
{ |
1055 |
|
|
struct window_pane *wp = ctx->wp; |
1056 |
|
|
struct screen *s = wp->screen; |
1057 |
|
|
u_int cx, width; |
1058 |
|
|
|
1059 |
|
|
if (ctx->ocy == ctx->orlower) |
1060 |
|
|
tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); |
1061 |
|
|
|
1062 |
|
|
/* Is the cursor in the very last position? */ |
1063 |
|
|
width = ctx->cell->data.width; |
1064 |
|
|
if (ctx->ocx > wp->sx - width) { |
1065 |
|
|
if (ctx->xoff != 0 || wp->sx != tty->sx) { |
1066 |
|
|
/* |
1067 |
|
|
* The pane doesn't fill the entire line, the linefeed |
1068 |
|
|
* will already have happened, so just move the cursor. |
1069 |
|
|
*/ |
1070 |
|
|
if (ctx->ocy != wp->yoff + wp->screen->rlower) |
1071 |
|
|
tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); |
1072 |
|
|
else |
1073 |
|
|
tty_cursor_pane(tty, ctx, 0, ctx->ocy); |
1074 |
|
|
} else if (tty->cx < tty->sx) { |
1075 |
|
|
/* |
1076 |
|
|
* The cursor isn't in the last position already, so |
1077 |
|
|
* move as far left as possible and redraw the last |
1078 |
|
|
* cell to move into the last position. |
1079 |
|
|
*/ |
1080 |
|
|
cx = screen_size_x(s) - ctx->last_cell.data.width; |
1081 |
|
|
tty_cursor_pane(tty, ctx, cx, ctx->ocy); |
1082 |
|
|
tty_cell(tty, &ctx->last_cell, wp); |
1083 |
|
|
} |
1084 |
|
|
} else |
1085 |
|
|
tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); |
1086 |
|
|
|
1087 |
|
|
tty_cell(tty, ctx->cell, wp); |
1088 |
|
|
} |
1089 |
|
|
|
1090 |
|
|
void |
1091 |
|
|
tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) |
1092 |
|
|
{ |
1093 |
|
|
struct window_pane *wp = ctx->wp; |
1094 |
|
|
|
1095 |
|
|
/* |
1096 |
|
|
* Cannot rely on not being a partial character, so just redraw the |
1097 |
|
|
* whole line. |
1098 |
|
|
*/ |
1099 |
|
|
tty_draw_pane(tty, wp, ctx->ocy, ctx->xoff, ctx->yoff); |
1100 |
|
|
} |
1101 |
|
|
|
1102 |
|
|
void |
1103 |
|
|
tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx) |
1104 |
|
|
{ |
1105 |
|
|
char *buf; |
1106 |
|
|
size_t off; |
1107 |
|
|
|
1108 |
|
|
if (!tty_term_has(tty->term, TTYC_MS)) |
1109 |
|
|
return; |
1110 |
|
|
|
1111 |
|
|
off = 4 * ((ctx->num + 2) / 3) + 1; /* storage for base64 */ |
1112 |
|
|
buf = xmalloc(off); |
1113 |
|
|
|
1114 |
|
|
b64_ntop(ctx->ptr, ctx->num, buf, off); |
1115 |
|
|
tty_putcode_ptr2(tty, TTYC_MS, "", buf); |
1116 |
|
|
|
1117 |
|
|
free(buf); |
1118 |
|
|
} |
1119 |
|
|
|
1120 |
|
|
void |
1121 |
|
|
tty_cmd_rawstring(struct tty *tty, const struct tty_ctx *ctx) |
1122 |
|
|
{ |
1123 |
|
|
u_int i; |
1124 |
|
|
u_char *str = ctx->ptr; |
1125 |
|
|
|
1126 |
|
|
for (i = 0; i < ctx->num; i++) |
1127 |
|
|
tty_putc(tty, str[i]); |
1128 |
|
|
|
1129 |
|
|
tty->cx = tty->cy = UINT_MAX; |
1130 |
|
|
tty->rupper = tty->rlower = UINT_MAX; |
1131 |
|
|
|
1132 |
|
|
tty_attributes(tty, &grid_default_cell, ctx->wp); |
1133 |
|
|
tty_cursor(tty, 0, 0); |
1134 |
|
|
} |
1135 |
|
|
|
1136 |
|
|
void |
1137 |
|
|
tty_cell(struct tty *tty, const struct grid_cell *gc, |
1138 |
|
|
const struct window_pane *wp) |
1139 |
|
|
{ |
1140 |
|
|
u_int i; |
1141 |
|
|
|
1142 |
|
|
/* Skip last character if terminal is stupid. */ |
1143 |
|
|
if (tty->term->flags & TERM_EARLYWRAP && |
1144 |
|
|
tty->cy == tty->sy - 1 && tty->cx == tty->sx - 1) |
1145 |
|
|
return; |
1146 |
|
|
|
1147 |
|
|
/* If this is a padding character, do nothing. */ |
1148 |
|
|
if (gc->flags & GRID_FLAG_PADDING) |
1149 |
|
|
return; |
1150 |
|
|
|
1151 |
|
|
/* Set the attributes. */ |
1152 |
|
|
tty_attributes(tty, gc, wp); |
1153 |
|
|
|
1154 |
|
|
/* Get the cell and if ASCII write with putc to do ACS translation. */ |
1155 |
|
|
if (gc->data.size == 1) { |
1156 |
|
|
if (*gc->data.data < 0x20 || *gc->data.data == 0x7f) |
1157 |
|
|
return; |
1158 |
|
|
tty_putc(tty, *gc->data.data); |
1159 |
|
|
return; |
1160 |
|
|
} |
1161 |
|
|
|
1162 |
|
|
/* If not UTF-8, write _. */ |
1163 |
|
|
if (!(tty->flags & TTY_UTF8)) { |
1164 |
|
|
for (i = 0; i < gc->data.width; i++) |
1165 |
|
|
tty_putc(tty, '_'); |
1166 |
|
|
return; |
1167 |
|
|
} |
1168 |
|
|
|
1169 |
|
|
/* Write the data. */ |
1170 |
|
|
tty_putn(tty, gc->data.data, gc->data.size, gc->data.width); |
1171 |
|
|
} |
1172 |
|
|
|
1173 |
|
|
void |
1174 |
|
|
tty_reset(struct tty *tty) |
1175 |
|
|
{ |
1176 |
|
|
struct grid_cell *gc = &tty->cell; |
1177 |
|
|
|
1178 |
|
|
if (grid_cells_equal(gc, &grid_default_cell)) |
1179 |
|
|
return; |
1180 |
|
|
|
1181 |
|
|
if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty)) |
1182 |
|
|
tty_putcode(tty, TTYC_RMACS); |
1183 |
|
|
tty_putcode(tty, TTYC_SGR0); |
1184 |
|
|
memcpy(gc, &grid_default_cell, sizeof *gc); |
1185 |
|
|
} |
1186 |
|
|
|
1187 |
|
|
/* Set region inside pane. */ |
1188 |
|
|
void |
1189 |
|
|
tty_region_pane(struct tty *tty, const struct tty_ctx *ctx, u_int rupper, |
1190 |
|
|
u_int rlower) |
1191 |
|
|
{ |
1192 |
|
|
tty_region(tty, ctx->yoff + rupper, ctx->yoff + rlower); |
1193 |
|
|
} |
1194 |
|
|
|
1195 |
|
|
/* Set region at absolute position. */ |
1196 |
|
|
void |
1197 |
|
|
tty_region(struct tty *tty, u_int rupper, u_int rlower) |
1198 |
|
|
{ |
1199 |
|
|
if (tty->rlower == rlower && tty->rupper == rupper) |
1200 |
|
|
return; |
1201 |
|
|
if (!tty_term_has(tty->term, TTYC_CSR)) |
1202 |
|
|
return; |
1203 |
|
|
|
1204 |
|
|
tty->rupper = rupper; |
1205 |
|
|
tty->rlower = rlower; |
1206 |
|
|
|
1207 |
|
|
/* |
1208 |
|
|
* Some terminals (such as PuTTY) do not correctly reset the cursor to |
1209 |
|
|
* 0,0 if it is beyond the last column (they do not reset their wrap |
1210 |
|
|
* flag so further output causes a line feed). As a workaround, do an |
1211 |
|
|
* explicit move to 0 first. |
1212 |
|
|
*/ |
1213 |
|
|
if (tty->cx >= tty->sx) |
1214 |
|
|
tty_cursor(tty, 0, tty->cy); |
1215 |
|
|
|
1216 |
|
|
tty_putcode2(tty, TTYC_CSR, tty->rupper, tty->rlower); |
1217 |
|
|
tty_cursor(tty, 0, 0); |
1218 |
|
|
} |
1219 |
|
|
|
1220 |
|
|
/* Move cursor inside pane. */ |
1221 |
|
|
void |
1222 |
|
|
tty_cursor_pane(struct tty *tty, const struct tty_ctx *ctx, u_int cx, u_int cy) |
1223 |
|
|
{ |
1224 |
|
|
tty_cursor(tty, ctx->xoff + cx, ctx->yoff + cy); |
1225 |
|
|
} |
1226 |
|
|
|
1227 |
|
|
/* Move cursor to absolute position. */ |
1228 |
|
|
void |
1229 |
|
|
tty_cursor(struct tty *tty, u_int cx, u_int cy) |
1230 |
|
|
{ |
1231 |
|
|
struct tty_term *term = tty->term; |
1232 |
|
|
u_int thisx, thisy; |
1233 |
|
|
int change; |
1234 |
|
|
|
1235 |
|
|
if (cx > tty->sx - 1) |
1236 |
|
|
cx = tty->sx - 1; |
1237 |
|
|
|
1238 |
|
|
thisx = tty->cx; |
1239 |
|
|
thisy = tty->cy; |
1240 |
|
|
|
1241 |
|
|
/* No change. */ |
1242 |
|
|
if (cx == thisx && cy == thisy) |
1243 |
|
|
return; |
1244 |
|
|
|
1245 |
|
|
/* Very end of the line, just use absolute movement. */ |
1246 |
|
|
if (thisx > tty->sx - 1) |
1247 |
|
|
goto absolute; |
1248 |
|
|
|
1249 |
|
|
/* Move to home position (0, 0). */ |
1250 |
|
|
if (cx == 0 && cy == 0 && tty_term_has(term, TTYC_HOME)) { |
1251 |
|
|
tty_putcode(tty, TTYC_HOME); |
1252 |
|
|
goto out; |
1253 |
|
|
} |
1254 |
|
|
|
1255 |
|
|
/* Zero on the next line. */ |
1256 |
|
|
if (cx == 0 && cy == thisy + 1 && thisy != tty->rlower) { |
1257 |
|
|
tty_putc(tty, '\r'); |
1258 |
|
|
tty_putc(tty, '\n'); |
1259 |
|
|
goto out; |
1260 |
|
|
} |
1261 |
|
|
|
1262 |
|
|
/* Moving column or row. */ |
1263 |
|
|
if (cy == thisy) { |
1264 |
|
|
/* |
1265 |
|
|
* Moving column only, row staying the same. |
1266 |
|
|
*/ |
1267 |
|
|
|
1268 |
|
|
/* To left edge. */ |
1269 |
|
|
if (cx == 0) { |
1270 |
|
|
tty_putc(tty, '\r'); |
1271 |
|
|
goto out; |
1272 |
|
|
} |
1273 |
|
|
|
1274 |
|
|
/* One to the left. */ |
1275 |
|
|
if (cx == thisx - 1 && tty_term_has(term, TTYC_CUB1)) { |
1276 |
|
|
tty_putcode(tty, TTYC_CUB1); |
1277 |
|
|
goto out; |
1278 |
|
|
} |
1279 |
|
|
|
1280 |
|
|
/* One to the right. */ |
1281 |
|
|
if (cx == thisx + 1 && tty_term_has(term, TTYC_CUF1)) { |
1282 |
|
|
tty_putcode(tty, TTYC_CUF1); |
1283 |
|
|
goto out; |
1284 |
|
|
} |
1285 |
|
|
|
1286 |
|
|
/* Calculate difference. */ |
1287 |
|
|
change = thisx - cx; /* +ve left, -ve right */ |
1288 |
|
|
|
1289 |
|
|
/* |
1290 |
|
|
* Use HPA if change is larger than absolute, otherwise move |
1291 |
|
|
* the cursor with CUB/CUF. |
1292 |
|
|
*/ |
1293 |
|
|
if ((u_int) abs(change) > cx && tty_term_has(term, TTYC_HPA)) { |
1294 |
|
|
tty_putcode1(tty, TTYC_HPA, cx); |
1295 |
|
|
goto out; |
1296 |
|
|
} else if (change > 0 && tty_term_has(term, TTYC_CUB)) { |
1297 |
|
|
if (change == 2 && tty_term_has(term, TTYC_CUB1)) { |
1298 |
|
|
tty_putcode(tty, TTYC_CUB1); |
1299 |
|
|
tty_putcode(tty, TTYC_CUB1); |
1300 |
|
|
goto out; |
1301 |
|
|
} |
1302 |
|
|
tty_putcode1(tty, TTYC_CUB, change); |
1303 |
|
|
goto out; |
1304 |
|
|
} else if (change < 0 && tty_term_has(term, TTYC_CUF)) { |
1305 |
|
|
tty_putcode1(tty, TTYC_CUF, -change); |
1306 |
|
|
goto out; |
1307 |
|
|
} |
1308 |
|
|
} else if (cx == thisx) { |
1309 |
|
|
/* |
1310 |
|
|
* Moving row only, column staying the same. |
1311 |
|
|
*/ |
1312 |
|
|
|
1313 |
|
|
/* One above. */ |
1314 |
|
|
if (thisy != tty->rupper && |
1315 |
|
|
cy == thisy - 1 && tty_term_has(term, TTYC_CUU1)) { |
1316 |
|
|
tty_putcode(tty, TTYC_CUU1); |
1317 |
|
|
goto out; |
1318 |
|
|
} |
1319 |
|
|
|
1320 |
|
|
/* One below. */ |
1321 |
|
|
if (thisy != tty->rlower && |
1322 |
|
|
cy == thisy + 1 && tty_term_has(term, TTYC_CUD1)) { |
1323 |
|
|
tty_putcode(tty, TTYC_CUD1); |
1324 |
|
|
goto out; |
1325 |
|
|
} |
1326 |
|
|
|
1327 |
|
|
/* Calculate difference. */ |
1328 |
|
|
change = thisy - cy; /* +ve up, -ve down */ |
1329 |
|
|
|
1330 |
|
|
/* |
1331 |
|
|
* Try to use VPA if change is larger than absolute or if this |
1332 |
|
|
* change would cross the scroll region, otherwise use CUU/CUD. |
1333 |
|
|
*/ |
1334 |
|
|
if ((u_int) abs(change) > cy || |
1335 |
|
|
(change < 0 && cy - change > tty->rlower) || |
1336 |
|
|
(change > 0 && cy - change < tty->rupper)) { |
1337 |
|
|
if (tty_term_has(term, TTYC_VPA)) { |
1338 |
|
|
tty_putcode1(tty, TTYC_VPA, cy); |
1339 |
|
|
goto out; |
1340 |
|
|
} |
1341 |
|
|
} else if (change > 0 && tty_term_has(term, TTYC_CUU)) { |
1342 |
|
|
tty_putcode1(tty, TTYC_CUU, change); |
1343 |
|
|
goto out; |
1344 |
|
|
} else if (change < 0 && tty_term_has(term, TTYC_CUD)) { |
1345 |
|
|
tty_putcode1(tty, TTYC_CUD, -change); |
1346 |
|
|
goto out; |
1347 |
|
|
} |
1348 |
|
|
} |
1349 |
|
|
|
1350 |
|
|
absolute: |
1351 |
|
|
/* Absolute movement. */ |
1352 |
|
|
tty_putcode2(tty, TTYC_CUP, cy, cx); |
1353 |
|
|
|
1354 |
|
|
out: |
1355 |
|
|
tty->cx = cx; |
1356 |
|
|
tty->cy = cy; |
1357 |
|
|
} |
1358 |
|
|
|
1359 |
|
|
void |
1360 |
|
|
tty_attributes(struct tty *tty, const struct grid_cell *gc, |
1361 |
|
|
const struct window_pane *wp) |
1362 |
|
|
{ |
1363 |
|
|
struct grid_cell *tc = &tty->cell, gc2; |
1364 |
|
|
u_char changed; |
1365 |
|
|
|
1366 |
|
|
memcpy(&gc2, gc, sizeof gc2); |
1367 |
|
|
if (wp != NULL) |
1368 |
|
|
tty_default_colours(&gc2, wp); |
1369 |
|
|
|
1370 |
|
|
/* |
1371 |
|
|
* If no setab, try to use the reverse attribute as a best-effort for a |
1372 |
|
|
* non-default background. This is a bit of a hack but it doesn't do |
1373 |
|
|
* any serious harm and makes a couple of applications happier. |
1374 |
|
|
*/ |
1375 |
|
|
if (!tty_term_has(tty->term, TTYC_SETAB)) { |
1376 |
|
|
if (gc2.attr & GRID_ATTR_REVERSE) { |
1377 |
|
|
if (gc2.fg != 7 && gc2.fg != 8) |
1378 |
|
|
gc2.attr &= ~GRID_ATTR_REVERSE; |
1379 |
|
|
} else { |
1380 |
|
|
if (gc2.bg != 0 && gc2.bg != 8) |
1381 |
|
|
gc2.attr |= GRID_ATTR_REVERSE; |
1382 |
|
|
} |
1383 |
|
|
} |
1384 |
|
|
|
1385 |
|
|
/* Fix up the colours if necessary. */ |
1386 |
|
|
tty_check_fg(tty, &gc2); |
1387 |
|
|
tty_check_bg(tty, &gc2); |
1388 |
|
|
|
1389 |
|
|
/* If any bits are being cleared, reset everything. */ |
1390 |
|
|
if (tc->attr & ~gc2.attr) |
1391 |
|
|
tty_reset(tty); |
1392 |
|
|
|
1393 |
|
|
/* |
1394 |
|
|
* Set the colours. This may call tty_reset() (so it comes next) and |
1395 |
|
|
* may add to (NOT remove) the desired attributes by changing new_attr. |
1396 |
|
|
*/ |
1397 |
|
|
tty_colours(tty, &gc2); |
1398 |
|
|
|
1399 |
|
|
/* Filter out attribute bits already set. */ |
1400 |
|
|
changed = gc2.attr & ~tc->attr; |
1401 |
|
|
tc->attr = gc2.attr; |
1402 |
|
|
|
1403 |
|
|
/* Set the attributes. */ |
1404 |
|
|
if (changed & GRID_ATTR_BRIGHT) |
1405 |
|
|
tty_putcode(tty, TTYC_BOLD); |
1406 |
|
|
if (changed & GRID_ATTR_DIM) |
1407 |
|
|
tty_putcode(tty, TTYC_DIM); |
1408 |
|
|
if (changed & GRID_ATTR_ITALICS) |
1409 |
|
|
tty_set_italics(tty); |
1410 |
|
|
if (changed & GRID_ATTR_UNDERSCORE) |
1411 |
|
|
tty_putcode(tty, TTYC_SMUL); |
1412 |
|
|
if (changed & GRID_ATTR_BLINK) |
1413 |
|
|
tty_putcode(tty, TTYC_BLINK); |
1414 |
|
|
if (changed & GRID_ATTR_REVERSE) { |
1415 |
|
|
if (tty_term_has(tty->term, TTYC_REV)) |
1416 |
|
|
tty_putcode(tty, TTYC_REV); |
1417 |
|
|
else if (tty_term_has(tty->term, TTYC_SMSO)) |
1418 |
|
|
tty_putcode(tty, TTYC_SMSO); |
1419 |
|
|
} |
1420 |
|
|
if (changed & GRID_ATTR_HIDDEN) |
1421 |
|
|
tty_putcode(tty, TTYC_INVIS); |
1422 |
|
|
if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty)) |
1423 |
|
|
tty_putcode(tty, TTYC_SMACS); |
1424 |
|
|
} |
1425 |
|
|
|
1426 |
|
|
void |
1427 |
|
|
tty_colours(struct tty *tty, const struct grid_cell *gc) |
1428 |
|
|
{ |
1429 |
|
|
struct grid_cell *tc = &tty->cell; |
1430 |
|
|
int have_ax; |
1431 |
|
|
|
1432 |
|
|
/* No changes? Nothing is necessary. */ |
1433 |
|
|
if (gc->fg == tc->fg && gc->bg == tc->bg) |
1434 |
|
|
return; |
1435 |
|
|
|
1436 |
|
|
/* |
1437 |
|
|
* Is either the default colour? This is handled specially because the |
1438 |
|
|
* best solution might be to reset both colours to default, in which |
1439 |
|
|
* case if only one is default need to fall onward to set the other |
1440 |
|
|
* colour. |
1441 |
|
|
*/ |
1442 |
|
|
if (gc->fg == 8 || gc->bg == 8) { |
1443 |
|
|
/* |
1444 |
|
|
* If don't have AX but do have op, send sgr0 (op can't |
1445 |
|
|
* actually be used because it is sometimes the same as sgr0 |
1446 |
|
|
* and sometimes isn't). This resets both colours to default. |
1447 |
|
|
* |
1448 |
|
|
* Otherwise, try to set the default colour only as needed. |
1449 |
|
|
*/ |
1450 |
|
|
have_ax = tty_term_flag(tty->term, TTYC_AX); |
1451 |
|
|
if (!have_ax && tty_term_has(tty->term, TTYC_OP)) |
1452 |
|
|
tty_reset(tty); |
1453 |
|
|
else { |
1454 |
|
|
if (gc->fg == 8 && tc->fg != 8) { |
1455 |
|
|
if (have_ax) |
1456 |
|
|
tty_puts(tty, "\033[39m"); |
1457 |
|
|
else if (tc->fg != 7) |
1458 |
|
|
tty_putcode1(tty, TTYC_SETAF, 7); |
1459 |
|
|
tc->fg = 8; |
1460 |
|
|
} |
1461 |
|
|
if (gc->bg == 8 && tc->bg != 8) { |
1462 |
|
|
if (have_ax) |
1463 |
|
|
tty_puts(tty, "\033[49m"); |
1464 |
|
|
else if (tc->bg != 0) |
1465 |
|
|
tty_putcode1(tty, TTYC_SETAB, 0); |
1466 |
|
|
tc->bg = 8; |
1467 |
|
|
} |
1468 |
|
|
} |
1469 |
|
|
} |
1470 |
|
|
|
1471 |
|
|
/* Set the foreground colour. */ |
1472 |
|
|
if (gc->fg != 8 && gc->fg != tc->fg) |
1473 |
|
|
tty_colours_fg(tty, gc); |
1474 |
|
|
|
1475 |
|
|
/* |
1476 |
|
|
* Set the background colour. This must come after the foreground as |
1477 |
|
|
* tty_colour_fg() can call tty_reset(). |
1478 |
|
|
*/ |
1479 |
|
|
if (gc->bg != 8 && gc->bg != tc->bg) |
1480 |
|
|
tty_colours_bg(tty, gc); |
1481 |
|
|
} |
1482 |
|
|
|
1483 |
|
|
void |
1484 |
|
|
tty_check_fg(struct tty *tty, struct grid_cell *gc) |
1485 |
|
|
{ |
1486 |
|
|
u_char r, g, b; |
1487 |
|
|
u_int colours; |
1488 |
|
|
|
1489 |
|
|
/* Is this a 24-bit colour? */ |
1490 |
|
|
if (gc->fg & COLOUR_FLAG_RGB) { |
1491 |
|
|
/* Not a 24-bit terminal? Translate to 256-colour palette. */ |
1492 |
|
|
if (!tty_term_flag(tty->term, TTYC_TC)) { |
1493 |
|
|
colour_split_rgb(gc->fg, &r, &g, &b); |
1494 |
|
|
gc->fg = colour_find_rgb(r, g, b); |
1495 |
|
|
} else |
1496 |
|
|
return; |
1497 |
|
|
} |
1498 |
|
|
colours = tty_term_number(tty->term, TTYC_COLORS); |
1499 |
|
|
|
1500 |
|
|
/* Is this a 256-colour colour? */ |
1501 |
|
|
if (gc->fg & COLOUR_FLAG_256) { |
1502 |
|
|
/* And not a 256 colour mode? */ |
1503 |
|
|
if (!(tty->term->flags & TERM_256COLOURS) && |
1504 |
|
|
!(tty->term_flags & TERM_256COLOURS)) { |
1505 |
|
|
gc->fg = colour_256to16(gc->fg); |
1506 |
|
|
if (gc->fg & 8) { |
1507 |
|
|
gc->fg &= 7; |
1508 |
|
|
if (colours >= 16) |
1509 |
|
|
gc->fg += 90; |
1510 |
|
|
else |
1511 |
|
|
gc->attr |= GRID_ATTR_BRIGHT; |
1512 |
|
|
} else |
1513 |
|
|
gc->attr &= ~GRID_ATTR_BRIGHT; |
1514 |
|
|
} |
1515 |
|
|
return; |
1516 |
|
|
} |
1517 |
|
|
|
1518 |
|
|
/* Is this an aixterm colour? */ |
1519 |
|
|
if (gc->fg >= 90 && gc->fg <= 97 && colours < 16) { |
1520 |
|
|
gc->fg -= 90; |
1521 |
|
|
gc->attr |= GRID_ATTR_BRIGHT; |
1522 |
|
|
} |
1523 |
|
|
} |
1524 |
|
|
|
1525 |
|
|
void |
1526 |
|
|
tty_check_bg(struct tty *tty, struct grid_cell *gc) |
1527 |
|
|
{ |
1528 |
|
|
u_char r, g, b; |
1529 |
|
|
u_int colours; |
1530 |
|
|
|
1531 |
|
|
/* Is this a 24-bit colour? */ |
1532 |
|
|
if (gc->bg & COLOUR_FLAG_RGB) { |
1533 |
|
|
/* Not a 24-bit terminal? Translate to 256-colour palette. */ |
1534 |
|
|
if (!tty_term_flag(tty->term, TTYC_TC)) { |
1535 |
|
|
colour_split_rgb(gc->bg, &r, &g, &b); |
1536 |
|
|
gc->bg = colour_find_rgb(r, g, b); |
1537 |
|
|
} else |
1538 |
|
|
return; |
1539 |
|
|
} |
1540 |
|
|
colours = tty_term_number(tty->term, TTYC_COLORS); |
1541 |
|
|
|
1542 |
|
|
/* Is this a 256-colour colour? */ |
1543 |
|
|
if (gc->bg & COLOUR_FLAG_256) { |
1544 |
|
|
/* |
1545 |
|
|
* And not a 256 colour mode? Translate to 16-colour |
1546 |
|
|
* palette. Bold background doesn't exist portably, so just |
1547 |
|
|
* discard the bold bit if set. |
1548 |
|
|
*/ |
1549 |
|
|
if (!(tty->term->flags & TERM_256COLOURS) && |
1550 |
|
|
!(tty->term_flags & TERM_256COLOURS)) { |
1551 |
|
|
gc->bg = colour_256to16(gc->bg); |
1552 |
|
|
if (gc->bg & 8) { |
1553 |
|
|
gc->bg &= 7; |
1554 |
|
|
if (colours >= 16) |
1555 |
|
|
gc->fg += 90; |
1556 |
|
|
} |
1557 |
|
|
} |
1558 |
|
|
return; |
1559 |
|
|
} |
1560 |
|
|
|
1561 |
|
|
/* Is this an aixterm colour? */ |
1562 |
|
|
if (gc->bg >= 90 && gc->bg <= 97 && colours < 16) |
1563 |
|
|
gc->bg -= 90; |
1564 |
|
|
} |
1565 |
|
|
|
1566 |
|
|
void |
1567 |
|
|
tty_colours_fg(struct tty *tty, const struct grid_cell *gc) |
1568 |
|
|
{ |
1569 |
|
|
struct grid_cell *tc = &tty->cell; |
1570 |
|
|
char s[32]; |
1571 |
|
|
|
1572 |
|
|
/* Is this a 24-bit or 256-colour colour? */ |
1573 |
|
|
if (gc->fg & COLOUR_FLAG_RGB || |
1574 |
|
|
gc->fg & COLOUR_FLAG_256) { |
1575 |
|
|
if (tty_try_colour(tty, gc->fg, "38") == 0) |
1576 |
|
|
goto save_fg; |
1577 |
|
|
/* Should not get here, already converted in tty_check_fg. */ |
1578 |
|
|
return; |
1579 |
|
|
} |
1580 |
|
|
|
1581 |
|
|
/* Is this an aixterm bright colour? */ |
1582 |
|
|
if (gc->fg >= 90 && gc->fg <= 97) { |
1583 |
|
|
xsnprintf(s, sizeof s, "\033[%dm", gc->fg); |
1584 |
|
|
tty_puts(tty, s); |
1585 |
|
|
goto save_fg; |
1586 |
|
|
} |
1587 |
|
|
|
1588 |
|
|
/* Otherwise set the foreground colour. */ |
1589 |
|
|
tty_putcode1(tty, TTYC_SETAF, gc->fg); |
1590 |
|
|
|
1591 |
|
|
save_fg: |
1592 |
|
|
/* Save the new values in the terminal current cell. */ |
1593 |
|
|
tc->fg = gc->fg; |
1594 |
|
|
} |
1595 |
|
|
|
1596 |
|
|
void |
1597 |
|
|
tty_colours_bg(struct tty *tty, const struct grid_cell *gc) |
1598 |
|
|
{ |
1599 |
|
|
struct grid_cell *tc = &tty->cell; |
1600 |
|
|
char s[32]; |
1601 |
|
|
|
1602 |
|
|
/* Is this a 24-bit or 256-colour colour? */ |
1603 |
|
|
if (gc->bg & COLOUR_FLAG_RGB || |
1604 |
|
|
gc->bg & COLOUR_FLAG_256) { |
1605 |
|
|
if (tty_try_colour(tty, gc->bg, "48") == 0) |
1606 |
|
|
goto save_bg; |
1607 |
|
|
/* Should not get here, already converted in tty_check_bg. */ |
1608 |
|
|
return; |
1609 |
|
|
} |
1610 |
|
|
|
1611 |
|
|
/* Is this an aixterm bright colour? */ |
1612 |
|
|
if (gc->bg >= 90 && gc->bg <= 97) { |
1613 |
|
|
xsnprintf(s, sizeof s, "\033[%dm", gc->bg + 10); |
1614 |
|
|
tty_puts(tty, s); |
1615 |
|
|
goto save_bg; |
1616 |
|
|
} |
1617 |
|
|
|
1618 |
|
|
/* Otherwise set the background colour. */ |
1619 |
|
|
tty_putcode1(tty, TTYC_SETAB, gc->bg); |
1620 |
|
|
|
1621 |
|
|
save_bg: |
1622 |
|
|
/* Save the new values in the terminal current cell. */ |
1623 |
|
|
tc->bg = gc->bg; |
1624 |
|
|
} |
1625 |
|
|
|
1626 |
|
|
int |
1627 |
|
|
tty_try_colour(struct tty *tty, int colour, const char *type) |
1628 |
|
|
{ |
1629 |
|
|
u_char r, g, b; |
1630 |
|
|
char s[32]; |
1631 |
|
|
|
1632 |
|
|
if (colour & COLOUR_FLAG_256) { |
1633 |
|
|
/* |
1634 |
|
|
* If the user has specified -2 to the client, setaf and setab |
1635 |
|
|
* may not work (or they may not want to use them), so send the |
1636 |
|
|
* usual sequence. |
1637 |
|
|
*/ |
1638 |
|
|
if (tty->term_flags & TERM_256COLOURS) |
1639 |
|
|
goto fallback_256; |
1640 |
|
|
|
1641 |
|
|
/* |
1642 |
|
|
* If the terminfo entry has 256 colours and setaf and setab |
1643 |
|
|
* exist, assume that they work correctly. |
1644 |
|
|
*/ |
1645 |
|
|
if (tty->term->flags & TERM_256COLOURS) { |
1646 |
|
|
if (*type == '3') { |
1647 |
|
|
if (!tty_term_has(tty->term, TTYC_SETAF)) |
1648 |
|
|
goto fallback_256; |
1649 |
|
|
tty_putcode1(tty, TTYC_SETAF, colour & 0xff); |
1650 |
|
|
} else { |
1651 |
|
|
if (!tty_term_has(tty->term, TTYC_SETAB)) |
1652 |
|
|
goto fallback_256; |
1653 |
|
|
tty_putcode1(tty, TTYC_SETAB, colour & 0xff); |
1654 |
|
|
} |
1655 |
|
|
return (0); |
1656 |
|
|
} |
1657 |
|
|
goto fallback_256; |
1658 |
|
|
} |
1659 |
|
|
|
1660 |
|
|
if (colour & COLOUR_FLAG_RGB) { |
1661 |
|
|
if (!tty_term_flag(tty->term, TTYC_TC)) |
1662 |
|
|
return (-1); |
1663 |
|
|
|
1664 |
|
|
colour_split_rgb(colour & 0xffffff, &r, &g, &b); |
1665 |
|
|
xsnprintf(s, sizeof s, "\033[%s;2;%hhu;%hhu;%hhum", type, |
1666 |
|
|
r, g, b); |
1667 |
|
|
tty_puts(tty, s); |
1668 |
|
|
return (0); |
1669 |
|
|
} |
1670 |
|
|
|
1671 |
|
|
return (-1); |
1672 |
|
|
|
1673 |
|
|
fallback_256: |
1674 |
|
|
xsnprintf(s, sizeof s, "\033[%s;5;%dm", type, colour & 0xff); |
1675 |
|
|
tty_puts(tty, s); |
1676 |
|
|
return (0); |
1677 |
|
|
} |
1678 |
|
|
|
1679 |
|
|
void |
1680 |
|
|
tty_default_colours(struct grid_cell *gc, const struct window_pane *wp) |
1681 |
|
|
{ |
1682 |
|
|
struct window *w = wp->window; |
1683 |
|
|
struct options *oo = w->options; |
1684 |
|
|
const struct grid_cell *agc, *pgc, *wgc; |
1685 |
|
|
|
1686 |
|
|
if (w->flags & WINDOW_STYLECHANGED) { |
1687 |
|
|
w->flags &= ~WINDOW_STYLECHANGED; |
1688 |
|
|
agc = options_get_style(oo, "window-active-style"); |
1689 |
|
|
memcpy(&w->active_style, agc, sizeof w->active_style); |
1690 |
|
|
wgc = options_get_style(oo, "window-style"); |
1691 |
|
|
memcpy(&w->style, wgc, sizeof w->style); |
1692 |
|
|
} else { |
1693 |
|
|
agc = &w->active_style; |
1694 |
|
|
wgc = &w->style; |
1695 |
|
|
} |
1696 |
|
|
pgc = &wp->colgc; |
1697 |
|
|
|
1698 |
|
|
if (gc->fg == 8) { |
1699 |
|
|
if (pgc->fg != 8) |
1700 |
|
|
gc->fg = pgc->fg; |
1701 |
|
|
else if (wp == w->active && agc->fg != 8) |
1702 |
|
|
gc->fg = agc->fg; |
1703 |
|
|
else |
1704 |
|
|
gc->fg = wgc->fg; |
1705 |
|
|
} |
1706 |
|
|
|
1707 |
|
|
if (gc->bg == 8) { |
1708 |
|
|
if (pgc->bg != 8) |
1709 |
|
|
gc->bg = pgc->bg; |
1710 |
|
|
else if (wp == w->active && agc->bg != 8) |
1711 |
|
|
gc->bg = agc->bg; |
1712 |
|
|
else |
1713 |
|
|
gc->bg = wgc->bg; |
1714 |
|
|
} |
1715 |
|
|
} |