tty.c 43 KB

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