1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 *
26 ****************************************************************
27 */
28
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #ifndef sun
33 # include <sys/ioctl.h>
34 #endif
35
36 #include "config.h"
37 #include "screen.h"
38 #include "extern.h"
39 #include "braille.h"
40 #include "canvas.h"
41
42 /* CSI parsing status */
43 enum
44 {
45 CSI_PB=0, CSI_PX=1, CSI_PY=2, CSI_DONE=3,
46 CSI_ESC_SEEN, CSI_BEGIN, CSI_INACTIVE, CSI_INVALID
47 };
48
49 static int CountChars __P((int));
50 static int DoAddChar __P((int));
51 static int BlankResize __P((int, int));
52 static int CallRewrite __P((int, int, int, int));
53 static void disp_readev_fn __P((struct event *, char *));
54 static void disp_processinput __P((struct display *, unsigned char *, int));
55 static void disp_writeev_fn __P((struct event *, char *));
56 #ifdef linux
57 static void disp_writeev_eagain __P((struct event *, char *));
58 #endif
59 static void disp_status_fn __P((struct event *, char *));
60 static void disp_hstatus_fn __P((struct event *, char *));
61 static void disp_blocked_fn __P((struct event *, char *));
62 #ifdef MAPKEYS
63 static void disp_map_fn __P((struct event *, char *));
64 #endif
65 static void disp_idle_fn __P((struct event *, char *));
66 #ifdef BLANKER_PRG
67 static void disp_blanker_fn __P((struct event *, char *));
68 #endif
69 static void WriteLP __P((int, int));
70 static void INSERTCHAR __P((int));
71 static void RAW_PUTCHAR __P((int));
72 #ifdef COLOR
73 static void SetBackColor __P((int));
74 #endif
75 static void RemoveStatusMinWait __P((void));
76
77
78 extern struct layer *flayer;
79 extern struct win *windows, *fore;
80 extern struct LayFuncs WinLf;
81
82 extern int use_hardstatus;
83 extern int MsgWait, MsgMinWait;
84 extern const int Z0width, Z1width;
85 extern unsigned char *blank, *null;
86 extern struct mline mline_blank, mline_null, mline_old;
87 extern struct mchar mchar_null, mchar_blank, mchar_so;
88 extern struct NewWindow nwin_default;
89 extern struct action idleaction;
90
91 /* XXX shouldn't be here */
92 extern char *hstatusstring;
93 extern char *captionstring;
94
95 extern int pastefont;
96 extern int idletimo;
97
98 #ifdef BLANKER_PRG
99 extern int pty_preopen;
100 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
101 extern struct winsize glwz;
102 #endif
103 extern char **NewEnv;
104 extern int real_uid, real_gid;
105 extern int ServerSocket, eff_uid, eff_gid;
106 #endif
107
108 /*
109 * tputs needs this to calculate the padding
110 */
111 #ifndef NEED_OSPEED
112 extern
113 #endif /* NEED_OSPEED */
114 short ospeed;
115
116
117 struct display *display, *displays;
118 #ifdef COLOR
119 int attr2color[8][4];
120 int nattr2color;
121 #endif
122
123 #ifndef MULTI
124 struct display TheDisplay;
125 #endif
126
127 /*
128 * The default values
129 */
130 int defobuflimit = OBUF_MAX;
131 int defnonblock = -1;
132 int defmousetrack = 0;
133 #ifdef AUTO_NUKE
134 int defautonuke = 0;
135 #endif
136 int captionalways;
137 int hardstatusemu = HSTATUS_IGNORE;
138
139 int focusminwidth, focusminheight;
140
141 /*
142 * Default layer management
143 */
144
145 void
DefProcess(bufp,lenp)146 DefProcess(bufp, lenp)
147 char **bufp;
148 int *lenp;
149 {
150 *bufp += *lenp;
151 *lenp = 0;
152 }
153
154 void
DefRedisplayLine(y,xs,xe,isblank)155 DefRedisplayLine(y, xs, xe, isblank)
156 int y, xs, xe, isblank;
157 {
158 if (isblank == 0 && y >= 0)
159 DefClearLine(y, xs, xe, 0);
160 }
161
162 void
DefClearLine(y,xs,xe,bce)163 DefClearLine(y, xs, xe, bce)
164 int y, xs, xe, bce;
165 {
166 LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
167 }
168
169 /*ARGSUSED*/
170 int
DefRewrite(y,xs,xe,rend,doit)171 DefRewrite(y, xs, xe, rend, doit)
172 int y, xs, xe, doit;
173 struct mchar *rend;
174 {
175 return EXPENSIVE;
176 }
177
178 /*ARGSUSED*/
179 int
DefResize(wi,he)180 DefResize(wi, he)
181 int wi, he;
182 {
183 return -1;
184 }
185
186 void
DefRestore()187 DefRestore()
188 {
189 LAY_DISPLAYS(flayer, InsertMode(0));
190 /* ChangeScrollRegion(0, D_height - 1); */
191 LKeypadMode(flayer, 0);
192 LCursorkeysMode(flayer, 0);
193 LCursorVisibility(flayer, 0);
194 LMouseMode(flayer, 0);
195 LSetRendition(flayer, &mchar_null);
196 LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
197 }
198
199 /*
200 * Blank layer management
201 */
202
203 struct LayFuncs BlankLf =
204 {
205 DefProcess,
206 0,
207 DefRedisplayLine,
208 DefClearLine,
209 DefRewrite,
210 BlankResize,
211 DefRestore,
212 0
213 };
214
215 /*ARGSUSED*/
216 static int
BlankResize(wi,he)217 BlankResize(wi, he)
218 int wi, he;
219 {
220 flayer->l_width = wi;
221 flayer->l_height = he;
222 return 0;
223 }
224
225
226 /*
227 * Generate new display, start with a blank layer.
228 * The termcap arrays are not initialised here.
229 * The new display is placed in the displays list.
230 */
231
232 struct display *
MakeDisplay(uname,utty,term,fd,pid,Mode)233 MakeDisplay(uname, utty, term, fd, pid, Mode)
234 char *uname, *utty, *term;
235 int fd, pid;
236 struct mode *Mode;
237 {
238 struct acluser **u;
239 struct baud_values *b;
240
241 if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
242 return 0; /* could not find or add user */
243
244 #ifdef MULTI
245 if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
246 return 0;
247 #else
248 if (displays)
249 return 0;
250 bzero((char *)&TheDisplay, sizeof(TheDisplay));
251 display = &TheDisplay;
252 #endif
253 display->d_next = displays;
254 displays = display;
255 D_flow = 1;
256 D_nonblock = defnonblock;
257 D_userfd = fd;
258 D_readev.fd = D_writeev.fd = fd;
259 D_readev.type = EV_READ;
260 D_writeev.type = EV_WRITE;
261 D_readev.data = D_writeev.data = (char *)display;
262 D_readev.handler = disp_readev_fn;
263 D_writeev.handler = disp_writeev_fn;
264 evenq(&D_readev);
265 D_writeev.condpos = &D_obuflen;
266 D_writeev.condneg = &D_obuffree;
267 evenq(&D_writeev);
268 D_statusev.type = EV_TIMEOUT;
269 D_statusev.data = (char *)display;
270 D_statusev.handler = disp_status_fn;
271 D_hstatusev.type = EV_TIMEOUT;
272 D_hstatusev.data = (char *)display;
273 D_hstatusev.handler = disp_hstatus_fn;
274 D_blockedev.type = EV_TIMEOUT;
275 D_blockedev.data = (char *)display;
276 D_blockedev.handler = disp_blocked_fn;
277 D_blockedev.condpos = &D_obuffree;
278 D_blockedev.condneg = &D_obuflenmax;
279 D_hstatusev.handler = disp_hstatus_fn;
280 #ifdef MAPKEYS
281 D_mapev.type = EV_TIMEOUT;
282 D_mapev.data = (char *)display;
283 D_mapev.handler = disp_map_fn;
284 #endif
285 D_idleev.type = EV_TIMEOUT;
286 D_idleev.data = (char *)display;
287 D_idleev.handler = disp_idle_fn;
288 #ifdef BLANKER_PRG
289 D_blankerev.type = EV_READ;
290 D_blankerev.data = (char *)display;
291 D_blankerev.handler = disp_blanker_fn;
292 D_blankerev.fd = -1;
293 #endif
294 D_OldMode = *Mode;
295 D_status_obuffree = -1;
296 Resize_obuf(); /* Allocate memory for buffer */
297 D_obufmax = defobuflimit;
298 D_obuflenmax = D_obuflen - D_obufmax;
299 #ifdef AUTO_NUKE
300 D_auto_nuke = defautonuke;
301 #endif
302 D_obufp = D_obuf;
303 D_printfd = -1;
304 D_userpid = pid;
305
306 #ifdef POSIX
307 if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
308 D_dospeed = b->idx;
309 #else
310 # ifdef TERMIO
311 if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
312 D_dospeed = b->idx;
313 # else
314 D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
315 # endif
316 #endif
317 debug1("New displays ospeed = %d\n", D_dospeed);
318
319 strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
320 D_usertty[sizeof(D_usertty) - 1] = 0;
321 strncpy(D_termname, term, MAXTERMLEN);
322 D_termname[MAXTERMLEN] = 0;
323 D_user = *u;
324 D_processinput = ProcessInput;
325 D_mousetrack = defmousetrack;
326 return display;
327 }
328
329
330 void
FreeDisplay()331 FreeDisplay()
332 {
333 struct win *p;
334 #ifdef MULTI
335 struct display *d, **dp;
336 #endif
337
338 #ifdef FONT
339 FreeTransTable();
340 #endif
341 #ifdef BLANKER_PRG
342 KillBlanker();
343 #endif
344 if (D_userfd >= 0)
345 {
346 Flush(3);
347 if (!display)
348 return;
349 SetTTY(D_userfd, &D_OldMode);
350 fcntl(D_userfd, F_SETFL, 0);
351 }
352 freetty();
353 if (D_tentry)
354 free(D_tentry);
355 D_tentry = 0;
356 if (D_processinputdata)
357 free(D_processinputdata);
358 D_processinputdata = 0;
359 D_tcinited = 0;
360 evdeq(&D_hstatusev);
361 evdeq(&D_statusev);
362 evdeq(&D_readev);
363 evdeq(&D_writeev);
364 evdeq(&D_blockedev);
365 #ifdef MAPKEYS
366 evdeq(&D_mapev);
367 if (D_kmaps)
368 {
369 free(D_kmaps);
370 D_kmaps = 0;
371 D_aseqs = 0;
372 D_nseqs = 0;
373 D_seqp = 0;
374 D_seql = 0;
375 D_seqh = 0;
376 }
377 #endif
378 evdeq(&D_idleev);
379 #ifdef BLANKER_PRG
380 evdeq(&D_blankerev);
381 #endif
382 #ifdef HAVE_BRAILLE
383 if (bd.bd_dpy == display)
384 {
385 bd.bd_start_braille = 0;
386 StartBraille();
387 }
388 #endif
389
390 #ifdef MULTI
391 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
392 if (d == display)
393 break;
394 ASSERT(d);
395 if (D_status_lastmsg)
396 free(D_status_lastmsg);
397 if (D_obuf)
398 free(D_obuf);
399 *dp = display->d_next;
400 #else /* MULTI */
401 ASSERT(display == displays);
402 ASSERT(display == &TheDisplay);
403 displays = 0;
404 #endif /* MULTI */
405
406 while (D_canvas.c_slperp)
407 FreeCanvas(D_canvas.c_slperp);
408 D_cvlist = 0;
409
410 for (p = windows; p; p = p->w_next)
411 {
412 if (p->w_pdisplay == display)
413 p->w_pdisplay = 0;
414 if (p->w_lastdisp == display)
415 p->w_lastdisp = 0;
416 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
417 p->w_readev.condpos = p->w_readev.condneg = 0;
418 }
419 #ifdef ZMODEM
420 for (p = windows; p; p = p->w_next)
421 if (p->w_zdisplay == display)
422 zmodem_abort(p, 0);
423 #endif
424 if (D_mousetrack)
425 {
426 D_mousetrack = 0;
427 MouseMode(0);
428 }
429 #ifdef MULTI
430 free((char *)display);
431 #endif
432 display = 0;
433 }
434
435 /*
436 * if the adaptflag is on, we keep the size of this display, else
437 * we may try to restore our old window sizes.
438 */
439 void
InitTerm(adapt)440 InitTerm(adapt)
441 int adapt;
442 {
443 ASSERT(display);
444 ASSERT(D_tcinited);
445 D_top = D_bot = -1;
446 AddCStr(D_IS);
447 AddCStr(D_TI);
448 /* Check for toggle */
449 if (D_IM && strcmp(D_IM, D_EI))
450 AddCStr(D_EI);
451 D_insert = 0;
452 #ifdef MAPKEYS
453 AddCStr(D_KS);
454 AddCStr(D_CCS);
455 #else
456 /* Check for toggle */
457 if (D_KS && strcmp(D_KS, D_KE))
458 AddCStr(D_KE);
459 if (D_CCS && strcmp(D_CCS, D_CCE))
460 AddCStr(D_CCE);
461 #endif
462 D_keypad = 0;
463 D_cursorkeys = 0;
464 AddCStr(D_ME);
465 AddCStr(D_EA);
466 AddCStr(D_CE0);
467 D_rend = mchar_null;
468 D_atyp = 0;
469 if (adapt == 0)
470 ResizeDisplay(D_defwidth, D_defheight);
471 ChangeScrollRegion(0, D_height - 1);
472 D_x = D_y = 0;
473 Flush(3);
474 ClearAll();
475 debug1("we %swant to adapt all our windows to the display\n",
476 (adapt) ? "" : "don't ");
477 /* In case the size was changed by a init sequence */
478 CheckScreenSize((adapt) ? 2 : 0);
479 }
480
481 void
FinitTerm()482 FinitTerm()
483 {
484 ASSERT(display);
485 #ifdef BLANKER_PRG
486 KillBlanker();
487 #endif
488 if (D_tcinited)
489 {
490 ResizeDisplay(D_defwidth, D_defheight);
491 InsertMode(0);
492 ChangeScrollRegion(0, D_height - 1);
493 KeypadMode(0);
494 CursorkeysMode(0);
495 CursorVisibility(0);
496 if (D_mousetrack)
497 D_mousetrack = 0;
498 MouseMode(0);
499 ExtMouseMode(0);
500 SetRendition(&mchar_null);
501 SetFlow(FLOW_NOW);
502 #ifdef MAPKEYS
503 AddCStr(D_KE);
504 AddCStr(D_CCE);
505 #endif
506 if (D_hstatus)
507 ShowHStatus((char *)0);
508 #ifdef RXVT_OSC
509 ClearAllXtermOSC();
510 #endif
511 D_x = D_y = -1;
512 GotoPos(0, D_height - 1);
513 AddChar('\r');
514 AddChar('\n');
515 AddCStr(D_TE);
516 }
517 Flush(3);
518 }
519
520
521 static void
INSERTCHAR(c)522 INSERTCHAR(c)
523 int c;
524 {
525 ASSERT(display);
526 if (!D_insert && D_x < D_width - 1)
527 {
528 if (D_IC || D_CIC)
529 {
530 if (D_IC)
531 AddCStr(D_IC);
532 else
533 AddCStr2(D_CIC, 1);
534 RAW_PUTCHAR(c);
535 return;
536 }
537 InsertMode(1);
538 if (!D_insert)
539 {
540 RefreshLine(D_y, D_x, D_width-1, 0);
541 return;
542 }
543 }
544 RAW_PUTCHAR(c);
545 }
546
547 void
PUTCHAR(c)548 PUTCHAR(c)
549 int c;
550 {
551 ASSERT(display);
552 if (D_insert && D_x < D_width - 1)
553 InsertMode(0);
554 RAW_PUTCHAR(c);
555 }
556
557 void
PUTCHARLP(c)558 PUTCHARLP(c)
559 int c;
560 {
561 if (D_x < D_width - 1)
562 {
563 if (D_insert)
564 InsertMode(0);
565 RAW_PUTCHAR(c);
566 return;
567 }
568 if (D_CLP || D_y != D_bot)
569 {
570 int y = D_y;
571 RAW_PUTCHAR(c);
572 if (D_AM && !D_CLP)
573 GotoPos(D_width - 1, y);
574 return;
575 }
576 debug("PUTCHARLP: lp_missing!\n");
577 D_lp_missing = 1;
578 D_rend.image = c;
579 D_lpchar = D_rend;
580 #ifdef DW_CHARS
581 /* XXX -> PutChar ? */
582 if (D_mbcs)
583 {
584 D_lpchar.mbcs = c;
585 D_lpchar.image = D_mbcs;
586 D_mbcs = 0;
587 D_x--;
588 }
589 #endif
590 }
591
592 /*
593 * RAW_PUTCHAR() is for all text that will be displayed.
594 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
595 */
596
597 STATIC void
RAW_PUTCHAR(c)598 RAW_PUTCHAR(c)
599 int c;
600 {
601 ASSERT(display);
602
603 #ifdef FONT
604 # ifdef UTF8
605 if (D_encoding == UTF8)
606 {
607 c = (c & 255) | (unsigned char)D_rend.font << 8 | (unsigned char)D_rend.fontx << 16;
608 # ifdef DW_CHARS
609 if (D_mbcs)
610 {
611 c = D_mbcs;
612 if (D_x == D_width)
613 D_x += D_AM ? 1 : -1;
614 D_mbcs = 0;
615 }
616 else if (utf8_isdouble(c))
617 {
618 D_mbcs = c;
619 D_x++;
620 return;
621 }
622 # endif
623 if (c < 32)
624 {
625 AddCStr2(D_CS0, '0');
626 AddChar(c + 0x5f);
627 AddCStr(D_CE0);
628 goto addedutf8;
629 }
630 if (c < 0x80)
631 {
632 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
633 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
634 else
635 AddChar(c);
636 }
637 else
638 AddUtf8(c);
639 goto addedutf8;
640 }
641 # endif
642 # ifdef DW_CHARS
643 if (is_dw_font(D_rend.font))
644 {
645 int t = c;
646 if (D_mbcs == 0)
647 {
648 D_mbcs = c;
649 D_x++;
650 return;
651 }
652 D_x--;
653 if (D_x == D_width - 1)
654 D_x += D_AM ? 1 : -1;
655 c = D_mbcs;
656 D_mbcs = t;
657 }
658 # endif
659 # if defined(ENCODINGS) && defined(DW_CHARS)
660 if (D_encoding)
661 c = PrepareEncodedChar(c);
662 # endif
663 # ifdef DW_CHARS
664 kanjiloop:
665 # endif
666 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
667 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
668 else
669 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
670 #else /* FONT */
671 AddChar(c);
672 #endif /* FONT */
673
674 #ifdef UTF8
675 addedutf8:
676 #endif
677 if (++D_x >= D_width)
678 {
679 if (D_AM == 0)
680 D_x = D_width - 1;
681 else if (!D_CLP || D_x > D_width)
682 {
683 D_x -= D_width;
684 if (D_y < D_height-1 && D_y != D_bot)
685 D_y++;
686 }
687 }
688 #ifdef DW_CHARS
689 if (D_mbcs)
690 {
691 c = D_mbcs;
692 D_mbcs = 0;
693 goto kanjiloop;
694 }
695 #endif
696 }
697
698 static int
DoAddChar(c)699 DoAddChar(c)
700 int c;
701 {
702 /* this is for ESC-sequences only (AddChar is a macro) */
703 AddChar(c);
704 return c;
705 }
706
707 void
AddCStr(s)708 AddCStr(s)
709 char *s;
710 {
711 if (display && s && *s)
712 {
713 ospeed = D_dospeed;
714 tputs(s, 1, DoAddChar);
715 }
716 }
717
718 void
AddCStr2(s,c)719 AddCStr2(s, c)
720 char *s;
721 int c;
722 {
723 if (display && s && *s)
724 {
725 ospeed = D_dospeed;
726 tputs(tgoto(s, 0, c), 1, DoAddChar);
727 }
728 }
729
730
731 /* Insert mode is a toggle on some terminals, so we need this hack:
732 */
733 void
InsertMode(on)734 InsertMode(on)
735 int on;
736 {
737 if (display && on != D_insert && D_IM)
738 {
739 D_insert = on;
740 if (on)
741 AddCStr(D_IM);
742 else
743 AddCStr(D_EI);
744 }
745 }
746
747 /* ...and maybe keypad application mode is a toggle, too:
748 */
749 void
KeypadMode(on)750 KeypadMode(on)
751 int on;
752 {
753 #ifdef MAPKEYS
754 if (display)
755 D_keypad = on;
756 #else
757 if (display && D_keypad != on && D_KS)
758 {
759 D_keypad = on;
760 if (on)
761 AddCStr(D_KS);
762 else
763 AddCStr(D_KE);
764 }
765 #endif
766 }
767
768 void
CursorkeysMode(on)769 CursorkeysMode(on)
770 int on;
771 {
772 #ifdef MAPKEYS
773 if (display)
774 D_cursorkeys = on;
775 #else
776 if (display && D_cursorkeys != on && D_CCS)
777 {
778 D_cursorkeys = on;
779 if (on)
780 AddCStr(D_CCS);
781 else
782 AddCStr(D_CCE);
783 }
784 #endif
785 }
786
787 void
ReverseVideo(on)788 ReverseVideo(on)
789 int on;
790 {
791 if (display && D_revvid != on && D_CVR)
792 {
793 D_revvid = on;
794 if (D_revvid)
795 AddCStr(D_CVR);
796 else
797 AddCStr(D_CVN);
798 }
799 }
800
801 void
CursorVisibility(v)802 CursorVisibility(v)
803 int v;
804 {
805 if (display && D_curvis != v)
806 {
807 if (D_curvis)
808 AddCStr(D_VE); /* do this always, just to be safe */
809 D_curvis = 0;
810 if (v == -1 && D_VI)
811 AddCStr(D_VI);
812 else if (v == 1 && D_VS)
813 AddCStr(D_VS);
814 else
815 return;
816 D_curvis = v;
817 }
818 }
819
820 void
MouseMode(mode)821 MouseMode(mode)
822 int mode;
823 {
824 if (!display)
825 return;
826
827 if (mode < D_mousetrack)
828 mode = D_mousetrack;
829
830 if (D_mouse != mode)
831 {
832 char mousebuf[20];
833 if (!D_CXT)
834 return;
835 if (D_mouse)
836 {
837 sprintf(mousebuf, "\033[?%dl", D_mouse);
838 AddStr(mousebuf);
839 }
840 if (mode)
841 {
842 sprintf(mousebuf, "\033[?%dh", mode);
843 AddStr(mousebuf);
844 }
845 D_mouse = mode;
846 D_mouse_parse.state = CSI_INACTIVE;
847 }
848 }
849
850 void
ExtMouseMode(mode)851 ExtMouseMode(mode)
852 int mode;
853 {
854 if (display && D_extmouse != mode)
855 {
856 char mousebuf[20];
857 if (!D_CXT)
858 return;
859 if (D_extmouse)
860 {
861 sprintf(mousebuf, "\033[?%dl", D_extmouse);
862 AddStr(mousebuf);
863 }
864 if (mode)
865 {
866 sprintf(mousebuf, "\033[?%dh", mode);
867 AddStr(mousebuf);
868 }
869 D_extmouse = mode;
870 D_mouse_parse.state = CSI_INACTIVE;
871 }
872 }
873
874 static int StrCost;
875
876 /* ARGSUSED */
877 static int
CountChars(c)878 CountChars(c)
879 int c;
880 {
881 StrCost++;
882 return c;
883 }
884
885 int
CalcCost(s)886 CalcCost(s)
887 register char *s;
888 {
889 ASSERT(display);
890 if (s)
891 {
892 StrCost = 0;
893 ospeed = D_dospeed;
894 tputs(s, 1, CountChars);
895 return StrCost;
896 }
897 else
898 return EXPENSIVE;
899 }
900
901 static int
CallRewrite(y,xs,xe,doit)902 CallRewrite(y, xs, xe, doit)
903 int y, xs, xe, doit;
904 {
905 struct canvas *cv, *cvlist, *cvlnext;
906 struct viewport *vp;
907 struct layer *oldflayer;
908 int cost;
909
910 debug3("CallRewrite %d %d %d\n", y, xs, xe);
911 ASSERT(display);
912 ASSERT(xe >= xs);
913
914 vp = 0;
915 for (cv = D_cvlist; cv; cv = cv->c_next)
916 {
917 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
918 continue;
919 for (vp = cv->c_vplist; vp; vp = vp->v_next)
920 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
921 break;
922 if (vp)
923 break;
924 }
925 if (doit)
926 {
927 oldflayer = flayer;
928 flayer = cv->c_layer;
929 cvlist = flayer->l_cvlist;
930 cvlnext = cv->c_lnext;
931 flayer->l_cvlist = cv;
932 cv->c_lnext = 0;
933 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
934 flayer->l_cvlist = cvlist;
935 cv->c_lnext = cvlnext;
936 flayer = oldflayer;
937 return 0;
938 }
939 if (cv == 0 || cv->c_layer == 0)
940 return EXPENSIVE; /* not found or nothing on it */
941 if (xs < vp->v_xs || xe > vp->v_xe)
942 return EXPENSIVE; /* crosses viewport boundaries */
943 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
944 return EXPENSIVE; /* line not on layer */
945 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
946 return EXPENSIVE; /* line not on layer */
947 #ifdef UTF8
948 if (D_encoding == UTF8)
949 D_rend.font = 0;
950 #endif
951 oldflayer = flayer;
952 flayer = cv->c_layer;
953 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
954 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
955 flayer = oldflayer;
956 if (D_insert)
957 cost += D_EIcost + D_IMcost;
958 return cost;
959 }
960
961
962 void
GotoPos(x2,y2)963 GotoPos(x2, y2)
964 int x2, y2;
965 {
966 register int dy, dx, x1, y1;
967 register int costx, costy;
968 register int m;
969 register char *s;
970 int CMcost;
971 enum move_t xm = M_NONE, ym = M_NONE;
972
973 if (!display)
974 return;
975
976 x1 = D_x;
977 y1 = D_y;
978
979 if (x1 == D_width)
980 {
981 if (D_CLP && D_AM)
982 x1 = -1; /* don't know how the terminal treats this */
983 else
984 x1--;
985 }
986 if (x2 == D_width)
987 x2--;
988 dx = x2 - x1;
989 dy = y2 - y1;
990 if (dy == 0 && dx == 0)
991 return;
992 debug2("GotoPos (%d,%d)", x1, y1);
993 debug2(" -> (%d,%d)\n", x2, y2);
994 if (!D_MS) /* Safe to move ? */
995 SetRendition(&mchar_null);
996 if (y1 < 0 /* don't know the y position */
997 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
998 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
999 {
1000 DoCM:
1001 if (D_HO && !x2 && !y2)
1002 AddCStr(D_HO);
1003 else
1004 AddCStr(tgoto(D_CM, x2, y2));
1005 D_x = x2;
1006 D_y = y2;
1007 return;
1008 }
1009
1010 /* some scrollregion implementations don't allow movements
1011 * away from the region. sigh.
1012 */
1013 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1014 goto DoCM;
1015
1016 /* Calculate CMcost */
1017 if (D_HO && !x2 && !y2)
1018 s = D_HO;
1019 else
1020 s = tgoto(D_CM, x2, y2);
1021 CMcost = CalcCost(s);
1022
1023 /* Calculate the cost to move the cursor to the right x position */
1024 costx = EXPENSIVE;
1025 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1026 {
1027 if (dx > 0)
1028 {
1029 if (D_CRI && (dx > 1 || !D_ND))
1030 {
1031 costx = CalcCost(tgoto(D_CRI, 0, dx));
1032 xm = M_CRI;
1033 }
1034 if ((m = D_NDcost * dx) < costx)
1035 {
1036 costx = m;
1037 xm = M_RI;
1038 }
1039 /* Speedup: dx <= LayRewrite() */
1040 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1041 {
1042 costx = m;
1043 xm = M_RW;
1044 }
1045 }
1046 else if (dx < 0)
1047 {
1048 if (D_CLE && (dx < -1 || !D_BC))
1049 {
1050 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1051 xm = M_CLE;
1052 }
1053 if ((m = -dx * D_LEcost) < costx)
1054 {
1055 costx = m;
1056 xm = M_LE;
1057 }
1058 }
1059 else
1060 costx = 0;
1061 }
1062 /* Speedup: LayRewrite() >= x2 */
1063 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1064 {
1065 costx = m;
1066 xm = M_CR;
1067 }
1068
1069 /* Check if it is already cheaper to do CM */
1070 if (costx >= CMcost)
1071 goto DoCM;
1072
1073 /* Calculate the cost to move the cursor to the right y position */
1074 costy = EXPENSIVE;
1075 if (dy > 0)
1076 {
1077 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1078 {
1079 costy = CalcCost(tgoto(D_CDO, 0, dy));
1080 ym = M_CDO;
1081 }
1082 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1083 {
1084 costy = m;
1085 ym = M_DO;
1086 }
1087 }
1088 else if (dy < 0)
1089 {
1090 if (D_CUP && (dy < -1 || !D_UP))
1091 {
1092 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1093 ym = M_CUP;
1094 }
1095 if ((m = -dy * D_UPcost) < costy)
1096 {
1097 costy = m;
1098 ym = M_UP;
1099 }
1100 }
1101 else
1102 costy = 0;
1103
1104 /* Finally check if it is cheaper to do CM */
1105 if (costx + costy >= CMcost)
1106 goto DoCM;
1107
1108 switch (xm)
1109 {
1110 case M_LE:
1111 while (dx++ < 0)
1112 AddCStr(D_BC);
1113 break;
1114 case M_CLE:
1115 AddCStr2(D_CLE, -dx);
1116 break;
1117 case M_RI:
1118 while (dx-- > 0)
1119 AddCStr(D_ND);
1120 break;
1121 case M_CRI:
1122 AddCStr2(D_CRI, dx);
1123 break;
1124 case M_CR:
1125 AddCStr(D_CR);
1126 D_x = 0;
1127 x1 = 0;
1128 /* FALLTHROUGH */
1129 case M_RW:
1130 if (x1 < x2)
1131 (void) CallRewrite(y1, x1, x2 - 1, 1);
1132 break;
1133 default:
1134 break;
1135 }
1136
1137 switch (ym)
1138 {
1139 case M_UP:
1140 while (dy++ < 0)
1141 AddCStr(D_UP);
1142 break;
1143 case M_CUP:
1144 AddCStr2(D_CUP, -dy);
1145 break;
1146 case M_DO:
1147 s = (x2 == 0) ? D_NL : D_DO;
1148 while (dy-- > 0)
1149 AddCStr(s);
1150 break;
1151 case M_CDO:
1152 AddCStr2(D_CDO, dy);
1153 break;
1154 default:
1155 break;
1156 }
1157 D_x = x2;
1158 D_y = y2;
1159 }
1160
1161 void
ClearAll()1162 ClearAll()
1163 {
1164 ASSERT(display);
1165 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1166 }
1167
1168 void
ClearArea(x1,y1,xs,xe,x2,y2,bce,uselayfn)1169 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1170 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1171 {
1172 int y, xxe;
1173 struct canvas *cv;
1174 struct viewport *vp;
1175
1176 debug2("Clear %d,%d", x1, y1);
1177 debug2(" %d-%d", xs, xe);
1178 debug2(" %d,%d", x2, y2);
1179 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1180 ASSERT(display);
1181 if (x1 == D_width)
1182 x1--;
1183 if (x2 == D_width)
1184 x2--;
1185 if (xs == -1)
1186 xs = x1;
1187 if (xe == -1)
1188 xe = x2;
1189 if (D_UT) /* Safe to erase ? */
1190 SetRendition(&mchar_null);
1191 #ifdef COLOR
1192 if (D_BE)
1193 SetBackColor(bce);
1194 #endif
1195 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1196 {
1197 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1198 D_lp_missing = 0;
1199 }
1200 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1201 {
1202 #ifdef AUTO_NUKE
1203 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1204 NukePending();
1205 #endif
1206 if (x1 == 0 && y1 == 0 && D_CL)
1207 {
1208 AddCStr(D_CL);
1209 D_y = D_x = 0;
1210 return;
1211 }
1212 /*
1213 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1214 * is also appropriate.
1215 */
1216 if (D_CD && (y1 < y2 || !D_CE))
1217 {
1218 GotoPos(x1, y1);
1219 AddCStr(D_CD);
1220 return;
1221 }
1222 }
1223 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1224 {
1225 GotoPos(x1, y1);
1226 AddCStr(D_CCD);
1227 return;
1228 }
1229 xxe = xe;
1230 for (y = y1; y <= y2; y++, x1 = xs)
1231 {
1232 if (y == y2)
1233 xxe = x2;
1234 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1235 {
1236 GotoPos(xxe, y);
1237 AddCStr(D_CB);
1238 continue;
1239 }
1240 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1241 {
1242 GotoPos(x1, y);
1243 AddCStr(D_CE);
1244 continue;
1245 }
1246 if (uselayfn)
1247 {
1248 vp = 0;
1249 for (cv = D_cvlist; cv; cv = cv->c_next)
1250 {
1251 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1252 continue;
1253 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1254 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1255 break;
1256 if (vp)
1257 break;
1258 }
1259 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1260 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1261 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1262 {
1263 struct layer *oldflayer = flayer;
1264 struct canvas *cvlist, *cvlnext;
1265 flayer = cv->c_layer;
1266 cvlist = flayer->l_cvlist;
1267 cvlnext = cv->c_lnext;
1268 flayer->l_cvlist = cv;
1269 cv->c_lnext = 0;
1270 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1271 flayer->l_cvlist = cvlist;
1272 cv->c_lnext = cvlnext;
1273 flayer = oldflayer;
1274 continue;
1275 }
1276 }
1277 ClearLine((struct mline *)0, y, x1, xxe, bce);
1278 }
1279 }
1280
1281
1282 /*
1283 * if cur_only > 0, we only redisplay current line, as a full refresh is
1284 * too expensive over a low baud line.
1285 */
1286 void
Redisplay(cur_only)1287 Redisplay(cur_only)
1288 int cur_only;
1289 {
1290 ASSERT(display);
1291
1292 /* XXX do em all? */
1293 InsertMode(0);
1294 ChangeScrollRegion(0, D_height - 1);
1295 KeypadMode(0);
1296 CursorkeysMode(0);
1297 CursorVisibility(0);
1298 MouseMode(0);
1299 ExtMouseMode(0);
1300 SetRendition(&mchar_null);
1301 SetFlow(FLOW_NOW);
1302
1303 ClearAll();
1304 #ifdef RXVT_OSC
1305 RefreshXtermOSC();
1306 #endif
1307 if (cur_only > 0 && D_fore)
1308 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1309 else
1310 RefreshAll(1);
1311 RefreshHStatus();
1312 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1313 }
1314
1315 void
RedisplayDisplays(cur_only)1316 RedisplayDisplays(cur_only)
1317 int cur_only;
1318 {
1319 struct display *olddisplay = display;
1320 for (display = displays; display; display = display->d_next)
1321 Redisplay(cur_only);
1322 display = olddisplay;
1323 }
1324
1325
1326 /* XXX: use oml! */
1327 void
ScrollH(y,xs,xe,n,bce,oml)1328 ScrollH(y, xs, xe, n, bce, oml)
1329 int y, xs, xe, n, bce;
1330 struct mline *oml;
1331 {
1332 int i;
1333
1334 if (n == 0)
1335 return;
1336 if (xe != D_width - 1)
1337 {
1338 RefreshLine(y, xs, xe, 0);
1339 /* UpdateLine(oml, y, xs, xe); */
1340 return;
1341 }
1342 GotoPos(xs, y);
1343 if (D_UT)
1344 SetRendition(&mchar_null);
1345 #ifdef COLOR
1346 if (D_BE)
1347 SetBackColor(bce);
1348 #endif
1349 if (n > 0)
1350 {
1351 if (n >= xe - xs + 1)
1352 n = xe - xs + 1;
1353 if (D_CDC && !(n == 1 && D_DC))
1354 AddCStr2(D_CDC, n);
1355 else if (D_DC)
1356 {
1357 for (i = n; i--; )
1358 AddCStr(D_DC);
1359 }
1360 else
1361 {
1362 RefreshLine(y, xs, xe, 0);
1363 /* UpdateLine(oml, y, xs, xe); */
1364 return;
1365 }
1366 }
1367 else
1368 {
1369 if (-n >= xe - xs + 1)
1370 n = -(xe - xs + 1);
1371 if (!D_insert)
1372 {
1373 if (D_CIC && !(n == -1 && D_IC))
1374 AddCStr2(D_CIC, -n);
1375 else if (D_IC)
1376 {
1377 for (i = -n; i--; )
1378 AddCStr(D_IC);
1379 }
1380 else if (D_IM)
1381 {
1382 InsertMode(1);
1383 SetRendition(&mchar_null);
1384 #ifdef COLOR
1385 SetBackColor(bce);
1386 #endif
1387 for (i = -n; i--; )
1388 INSERTCHAR(' ');
1389 bce = 0; /* all done */
1390 }
1391 else
1392 {
1393 /* UpdateLine(oml, y, xs, xe); */
1394 RefreshLine(y, xs, xe, 0);
1395 return;
1396 }
1397 }
1398 else
1399 {
1400 SetRendition(&mchar_null);
1401 #ifdef COLOR
1402 SetBackColor(bce);
1403 #endif
1404 for (i = -n; i--; )
1405 INSERTCHAR(' ');
1406 bce = 0; /* all done */
1407 }
1408 }
1409 if (bce && !D_BE)
1410 {
1411 if (n > 0)
1412 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
1413 else
1414 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
1415 }
1416 if (D_lp_missing && y == D_bot)
1417 {
1418 if (n > 0)
1419 WriteLP(D_width - 1 - n, y);
1420 D_lp_missing = 0;
1421 }
1422 }
1423
1424 void
ScrollV(xs,ys,xe,ye,n,bce)1425 ScrollV(xs, ys, xe, ye, n, bce)
1426 int xs, ys, xe, ye, n, bce;
1427 {
1428 int i;
1429 int up;
1430 int oldbot;
1431 int alok, dlok, aldlfaster;
1432 int missy = 0;
1433
1434 ASSERT(display);
1435 if (n == 0)
1436 return;
1437 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
1438 {
1439 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
1440 return;
1441 }
1442 if (xs > D_vpxmin || xe < D_vpxmax)
1443 {
1444 RefreshArea(xs, ys, xe, ye, 0);
1445 return;
1446 }
1447
1448 if (D_lp_missing)
1449 {
1450 if (D_bot > ye || D_bot < ys)
1451 missy = D_bot;
1452 else
1453 {
1454 missy = D_bot - n;
1455 if (missy > ye || missy < ys)
1456 D_lp_missing = 0;
1457 }
1458 }
1459
1460 up = 1;
1461 if (n < 0)
1462 {
1463 up = 0;
1464 n = -n;
1465 }
1466 if (n >= ye - ys + 1)
1467 n = ye - ys + 1;
1468
1469 oldbot = D_bot;
1470 if (ys < D_top || D_bot != ye)
1471 ChangeScrollRegion(ys, ye);
1472 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
1473 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
1474 if (D_top != ys && !(alok && dlok))
1475 ChangeScrollRegion(ys, ye);
1476
1477 if (D_lp_missing &&
1478 (oldbot != D_bot ||
1479 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
1480 {
1481 WriteLP(D_width - 1, oldbot);
1482 if (oldbot == D_bot) /* have scrolled */
1483 {
1484 if (--n == 0)
1485 {
1486 /* XXX
1487 ChangeScrollRegion(oldtop, oldbot);
1488 */
1489 if (bce && !D_BE)
1490 ClearLine((struct mline *)0, ye, xs, xe, bce);
1491 return;
1492 }
1493 }
1494 }
1495
1496 if (D_UT)
1497 SetRendition(&mchar_null);
1498 #ifdef COLOR
1499 if (D_BE)
1500 SetBackColor(bce);
1501 #endif
1502
1503 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
1504
1505 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
1506 {
1507 if (up)
1508 {
1509 GotoPos(0, ye);
1510 for(i = n; i-- > 0; )
1511 AddCStr(D_NL); /* was SF, I think NL is faster */
1512 }
1513 else
1514 {
1515 GotoPos(0, ys);
1516 for(i = n; i-- > 0; )
1517 AddCStr(D_SR);
1518 }
1519 }
1520 else if (alok && dlok)
1521 {
1522 if (up || ye != D_bot)
1523 {
1524 GotoPos(0, up ? ys : ye+1-n);
1525 if (D_CDL && !(n == 1 && D_DL))
1526 AddCStr2(D_CDL, n);
1527 else
1528 for(i = n; i--; )
1529 AddCStr(D_DL);
1530 }
1531 if (!up || ye != D_bot)
1532 {
1533 GotoPos(0, up ? ye+1-n : ys);
1534 if (D_CAL && !(n == 1 && D_AL))
1535 AddCStr2(D_CAL, n);
1536 else
1537 for(i = n; i--; )
1538 AddCStr(D_AL);
1539 }
1540 }
1541 else
1542 {
1543 RefreshArea(xs, ys, xe, ye, 0);
1544 return;
1545 }
1546 if (bce && !D_BE)
1547 {
1548 if (up)
1549 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
1550 else
1551 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
1552 }
1553 if (D_lp_missing && missy != D_bot)
1554 WriteLP(D_width - 1, missy);
1555 /* XXX
1556 ChangeScrollRegion(oldtop, oldbot);
1557 if (D_lp_missing && missy != D_bot)
1558 WriteLP(D_width - 1, missy);
1559 */
1560 }
1561
1562 void
SetAttr(new)1563 SetAttr(new)
1564 register int new;
1565 {
1566 register int i, j, old, typ;
1567
1568 if (!display || (old = D_rend.attr) == new)
1569 return;
1570 #ifdef COLORS16
1571 D_col16change = (old ^ new) & (A_BFG | A_BBG);
1572 new ^= D_col16change;
1573 if (old == new)
1574 return;
1575 #endif
1576 #if defined(TERMINFO) && defined(USE_SGR)
1577 if (D_SA)
1578 {
1579 char *tparm();
1580 SetFont(ASCII);
1581 ospeed = D_dospeed;
1582 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
1583 new & A_DI, new & A_BD, 0 , 0 ,
1584 0), 1, DoAddChar);
1585 D_rend.attr = new;
1586 D_atyp = 0;
1587 # ifdef COLOR
1588 if (D_hascolor)
1589 rend_setdefault(&D_rend);
1590 # endif
1591 return;
1592 }
1593 #endif
1594 D_rend.attr = new;
1595 typ = D_atyp;
1596 if ((new & old) != old)
1597 {
1598 if ((typ & ATYP_U))
1599 AddCStr(D_UE);
1600 if ((typ & ATYP_S))
1601 AddCStr(D_SE);
1602 if ((typ & ATYP_M))
1603 {
1604 AddCStr(D_ME);
1605 #ifdef COLOR
1606 /* ansi attrib handling: \E[m resets color, too */
1607 if (D_hascolor)
1608 rend_setdefault(&D_rend);
1609 #endif
1610 #ifdef FONT
1611 if (!D_CG0)
1612 {
1613 /* D_ME may also reset the alternate charset */
1614 D_rend.font = 0;
1615 # ifdef ENCODINGS
1616 D_realfont = 0;
1617 # endif
1618 }
1619 #endif
1620 }
1621 old = 0;
1622 typ = 0;
1623 }
1624 old ^= new;
1625 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
1626 {
1627 if ((old & j) == 0)
1628 continue;
1629 old ^= j;
1630 if (D_attrtab[i])
1631 {
1632 AddCStr(D_attrtab[i]);
1633 typ |= D_attrtyp[i];
1634 }
1635 }
1636 D_atyp = typ;
1637 }
1638
1639 #ifdef FONT
1640 void
SetFont(new)1641 SetFont(new)
1642 int new;
1643 {
1644 int old = D_rend.font;
1645 if (!display || old == new)
1646 return;
1647 D_rend.font = new;
1648 #ifdef ENCODINGS
1649 if (D_encoding && CanEncodeFont(D_encoding, new))
1650 return;
1651 if (new == D_realfont)
1652 return;
1653 D_realfont = new;
1654 #endif
1655 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
1656 D_xtable[(int)(unsigned char)new][256])
1657 {
1658 AddCStr(D_xtable[(int)(unsigned char)new][256]);
1659 return;
1660 }
1661
1662 if (!D_CG0 && new != '0')
1663 {
1664 new = ASCII;
1665 if (old == new)
1666 return;
1667 }
1668
1669 if (new == ASCII)
1670 AddCStr(D_CE0);
1671 #ifdef DW_CHARS
1672 else if (new < ' ')
1673 {
1674 AddStr("\033$");
1675 if (new > 2)
1676 AddChar('(');
1677 AddChar(new + '@');
1678 }
1679 #endif
1680 else
1681 AddCStr2(D_CS0, new);
1682 }
1683 #endif
1684
1685 #ifdef COLOR
1686
1687 int
color256to16(jj)1688 color256to16(jj)
1689 int jj;
1690 {
1691 int min, max;
1692 int r, g, b;
1693
1694 if (jj >= 232)
1695 {
1696 jj = (jj - 232) / 6;
1697 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
1698 }
1699 else if (jj >= 16)
1700 {
1701 jj -= 16;
1702 r = jj / 36;
1703 g = (jj / 6) % 6;
1704 b = jj % 6;
1705 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
1706 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
1707 if (min == max)
1708 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
1709 else
1710 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
1711 min) / (max - min) | (max > 3 ? 8 : 0);
1712 }
1713 return jj;
1714 }
1715
1716 #ifdef COLORS256
1717 int
color256to88(jj)1718 color256to88(jj)
1719 int jj;
1720 {
1721 int r, g, b;
1722
1723 if (jj >= 232)
1724 return (jj - 232) / 3 + 80;
1725 if (jj >= 16)
1726 {
1727 jj -= 16;
1728 r = jj / 36;
1729 g = (jj / 6) % 6;
1730 b = jj % 6;
1731 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
1732 }
1733 return jj;
1734 }
1735 #endif
1736
1737 void
SetColor(f,b)1738 SetColor(f, b)
1739 int f, b;
1740 {
1741 int of, ob;
1742 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
1743
1744 if (!display)
1745 return;
1746
1747 of = rend_getfg(&D_rend);
1748 ob = rend_getbg(&D_rend);
1749
1750 #ifdef COLORS16
1751 /* intense default not invented yet */
1752 if (f == 0x100)
1753 f = 0;
1754 if (b == 0x100)
1755 b = 0;
1756 #endif
1757 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
1758 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
1759 debug2("(%d %d", of, ob);
1760 debug2(" -> %d %d)\n", f, b);
1761
1762 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
1763 {
1764 if (D_OP)
1765 AddCStr(D_OP);
1766 else
1767 {
1768 int oattr;
1769 oattr = D_rend.attr;
1770 AddCStr(D_ME ? D_ME : "\033[m");
1771 #ifdef FONT
1772 if (D_ME && !D_CG0)
1773 {
1774 /* D_ME may also reset the alternate charset */
1775 D_rend.font = 0;
1776 # ifdef ENCODINGS
1777 D_realfont = 0;
1778 # endif
1779 }
1780 #endif
1781 D_atyp = 0;
1782 D_rend.attr = 0;
1783 SetAttr(oattr);
1784 }
1785 of = ob = 0;
1786 }
1787 rend_setfg(&D_rend, f);
1788 rend_setbg(&D_rend, b);
1789 #ifdef COLORS16
1790 D_col16change = 0;
1791 #endif
1792 if (!D_hascolor)
1793 return;
1794 f = f ? coli2e(f) : -1;
1795 b = b ? coli2e(b) : -1;
1796 of = of ? coli2e(of) : -1;
1797 ob = ob ? coli2e(ob) : -1;
1798 #ifdef COLORS256
1799 if (f != of && f > 15 && D_CCO != 256)
1800 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
1801 if (f != of && f > 15 && D_CAF)
1802 {
1803 AddCStr2(D_CAF, f);
1804 of = f;
1805 }
1806 if (b != ob && b > 15 && D_CCO != 256)
1807 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
1808 if (b != ob && b > 15 && D_CAB)
1809 {
1810 AddCStr2(D_CAB, b);
1811 ob = b;
1812 }
1813 #endif
1814 if (f != of && f != (of | 8))
1815 {
1816 if (f == -1)
1817 AddCStr("\033[39m"); /* works because AX is set */
1818 else if (D_CAF)
1819 AddCStr2(D_CAF, f & 7);
1820 else if (D_CSF)
1821 AddCStr2(D_CSF, sftrans[f & 7]);
1822 }
1823 if (b != ob && b != (ob | 8))
1824 {
1825 if (b == -1)
1826 AddCStr("\033[49m"); /* works because AX is set */
1827 else if (D_CAB)
1828 AddCStr2(D_CAB, b & 7);
1829 else if (D_CSB)
1830 AddCStr2(D_CSB, sftrans[b & 7]);
1831 }
1832 #ifdef COLORS16
1833 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
1834 {
1835 # ifdef TERMINFO
1836 AddCStr2("\033[9%p1%dm", f & 7);
1837 # else
1838 AddCStr2("\033[9%dm", f & 7);
1839 # endif
1840 }
1841 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
1842 {
1843 # ifdef TERMINFO
1844 AddCStr2("\033[10%p1%dm", b & 7);
1845 # else
1846 AddCStr2("\033[10%dm", b & 7);
1847 # endif
1848 }
1849 #endif
1850 }
1851
1852 static void
SetBackColor(new)1853 SetBackColor(new)
1854 int new;
1855 {
1856 if (!display)
1857 return;
1858 SetColor(rend_getfg(&D_rend), new);
1859 }
1860 #endif /* COLOR */
1861
1862 void
SetRendition(mc)1863 SetRendition(mc)
1864 struct mchar *mc;
1865 {
1866 if (!display)
1867 return;
1868 #ifdef COLOR
1869 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
1870 {
1871 static struct mchar mmc;
1872 int i;
1873 mmc = *mc;
1874 for (i = 0; i < 8; i++)
1875 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
1876 {
1877 if (mc->color == 0 && attr2color[i][3])
1878 ApplyAttrColor(attr2color[i][3], &mmc);
1879 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
1880 ApplyAttrColor(attr2color[i][2], &mmc);
1881 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
1882 ApplyAttrColor(attr2color[i][1], &mmc);
1883 else
1884 ApplyAttrColor(attr2color[i][0], &mmc);
1885 }
1886 mc = &mmc;
1887 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
1888 }
1889 # ifdef COLORS16
1890 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
1891 {
1892 int a = mc->attr;
1893 if ((mc->attr & A_BFG) && D_MD)
1894 a |= A_BD;
1895 if ((mc->attr & A_BBG) && D_MB)
1896 a |= A_BL;
1897 if (D_rend.attr != a)
1898 SetAttr(a);
1899 }
1900 else
1901 # endif /* COLORS16 */
1902 #endif /* COLOR */
1903 if (D_rend.attr != mc->attr)
1904 SetAttr(mc->attr);
1905
1906 #ifdef COLOR
1907 if (D_rend.color != mc->color
1908 # ifdef COLORS256
1909 || D_rend.colorx != mc->colorx
1910 # endif
1911 # ifdef COLORS16
1912 || D_col16change
1913 # endif
1914 )
1915 SetColor(rend_getfg(mc), rend_getbg(mc));
1916 #endif
1917 #ifdef FONT
1918 if (D_rend.font != mc->font)
1919 SetFont(mc->font);
1920 #ifdef UTF8
1921 if (D_encoding == UTF8)
1922 D_rend.fontx = mc->fontx;
1923 #endif
1924 #endif
1925 }
1926
1927 void
SetRenditionMline(ml,x)1928 SetRenditionMline(ml, x)
1929 struct mline *ml;
1930 int x;
1931 {
1932 if (!display)
1933 return;
1934 #ifdef COLOR
1935 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
1936 {
1937 struct mchar mc;
1938 copy_mline2mchar(&mc, ml, x);
1939 SetRendition(&mc);
1940 return;
1941 }
1942 # ifdef COLORS16
1943 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
1944 {
1945 int a = ml->attr[x];
1946 if ((ml->attr[x] & A_BFG) && D_MD)
1947 a |= A_BD;
1948 if ((ml->attr[x] & A_BBG) && D_MB)
1949 a |= A_BL;
1950 if (D_rend.attr != a)
1951 SetAttr(a);
1952 }
1953 else
1954 # endif /* COLORS16 */
1955 #endif /* COLOR */
1956 if (D_rend.attr != ml->attr[x])
1957 SetAttr(ml->attr[x]);
1958 #ifdef COLOR
1959 if (D_rend.color != ml->color[x]
1960 # ifdef COLORS256
1961 || D_rend.colorx != ml->colorx[x]
1962 # endif
1963 # ifdef COLORS16
1964 || D_col16change
1965 # endif
1966 )
1967 {
1968 struct mchar mc;
1969 copy_mline2mchar(&mc, ml, x);
1970 SetColor(rend_getfg(&mc), rend_getbg(&mc));
1971 }
1972 #endif
1973 #ifdef FONT
1974 if (D_rend.font != ml->font[x])
1975 SetFont(ml->font[x]);
1976 #ifdef UTF8
1977 if (D_encoding == UTF8)
1978 D_rend.fontx = ml->fontx[x];
1979 #endif
1980 #endif
1981 }
1982
1983 void
MakeStatus(msg)1984 MakeStatus(msg)
1985 char *msg;
1986 {
1987 register char *s, *t;
1988 register int max;
1989
1990 if (!display)
1991 return;
1992
1993 if (D_blocked)
1994 return;
1995 if (!D_tcinited)
1996 {
1997 debug("tc not inited, just writing msg\n");
1998 if (D_processinputdata)
1999 return; /* XXX: better */
2000 AddStr(msg);
2001 AddStr("\r\n");
2002 Flush(0);
2003 return;
2004 }
2005 if (!use_hardstatus || !D_HS)
2006 {
2007 max = D_width;
2008 if (D_CLP == 0)
2009 max--;
2010 }
2011 else
2012 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2013 if (D_status)
2014 {
2015 /* same message? */
2016 if (strcmp(msg, D_status_lastmsg) == 0)
2017 {
2018 debug("same message - increase timeout");
2019 if (!D_status_obufpos)
2020 SetTimeout(&D_statusev, MsgWait);
2021 return;
2022 }
2023 RemoveStatusMinWait();
2024 }
2025 for (s = t = msg; *s && t - msg < max; ++s)
2026 if (*s == BELL)
2027 AddCStr(D_BL);
2028 else if ((unsigned char)*s >= ' ' && *s != 0177)
2029 *t++ = *s;
2030 *t = '\0';
2031 if (t == msg)
2032 return;
2033 if (t - msg >= D_status_buflen)
2034 {
2035 char *buf;
2036 if (D_status_lastmsg)
2037 buf = realloc(D_status_lastmsg, t - msg + 1);
2038 else
2039 buf = malloc(t - msg + 1);
2040 if (buf)
2041 {
2042 D_status_lastmsg = buf;
2043 D_status_buflen = t - msg + 1;
2044 }
2045 }
2046 if (t - msg < D_status_buflen)
2047 strcpy(D_status_lastmsg, msg);
2048 D_status_len = t - msg;
2049 D_status_lastx = D_x;
2050 D_status_lasty = D_y;
2051 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2052 {
2053 D_status = STATUS_ON_WIN;
2054 debug1("using STATLINE %d\n", STATLINE);
2055 GotoPos(0, STATLINE);
2056 SetRendition(&mchar_so);
2057 InsertMode(0);
2058 AddStr(msg);
2059 if (D_status_len < max)
2060 {
2061 /* Wayne Davison: add extra space for readability */
2062 D_status_len++;
2063 SetRendition(&mchar_null);
2064 AddChar(' ');
2065 if (D_status_len < max)
2066 {
2067 D_status_len++;
2068 AddChar(' ');
2069 AddChar('\b');
2070 }
2071 AddChar('\b');
2072 }
2073 D_x = -1;
2074 }
2075 else
2076 {
2077 D_status = STATUS_ON_HS;
2078 ShowHStatus(msg);
2079 }
2080
2081 D_status_obufpos = D_obufp - D_obuf;
2082 ASSERT(D_status_obufpos > 0);
2083
2084 if (D_status == STATUS_ON_WIN)
2085 {
2086 struct display *olddisplay = display;
2087 struct layer *oldflayer = flayer;
2088
2089 /* this is copied over from RemoveStatus() */
2090 D_status = 0;
2091 GotoPos(0, STATLINE);
2092 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2093 GotoPos(D_status_lastx, D_status_lasty);
2094 flayer = D_forecv ? D_forecv->c_layer : 0;
2095 if (flayer)
2096 LaySetCursor();
2097 display = olddisplay;
2098 flayer = oldflayer;
2099 D_status = STATUS_ON_WIN;
2100 }
2101 }
2102
2103 void
RemoveStatus()2104 RemoveStatus()
2105 {
2106 struct display *olddisplay;
2107 struct layer *oldflayer;
2108 int where;
2109
2110 if (!display)
2111 return;
2112 if (!(where = D_status))
2113 return;
2114
2115 debug("RemoveStatus\n");
2116 if (D_status_obuffree >= 0)
2117 {
2118 D_obuflen = D_status_obuflen;
2119 D_obuffree = D_status_obuffree;
2120 D_status_obuffree = -1;
2121 }
2122 D_status = 0;
2123 D_status_obufpos = 0;
2124 D_status_bell = 0;
2125 evdeq(&D_statusev);
2126 olddisplay = display;
2127 oldflayer = flayer;
2128 if (where == STATUS_ON_WIN)
2129 {
2130 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2131 {
2132 GotoPos(0, STATLINE);
2133 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2134 GotoPos(D_status_lastx, D_status_lasty);
2135 }
2136 }
2137 else
2138 RefreshHStatus();
2139 flayer = D_forecv ? D_forecv->c_layer : 0;
2140 if (flayer)
2141 LaySetCursor();
2142 display = olddisplay;
2143 flayer = oldflayer;
2144 }
2145
2146 /* Remove the status but make sure that it is seen for MsgMinWait ms */
2147 static void
RemoveStatusMinWait()2148 RemoveStatusMinWait()
2149 {
2150 /* XXX: should flush output first if D_status_obufpos is set */
2151 if (!D_status_bell && !D_status_obufpos)
2152 {
2153 struct timeval now;
2154 int ti;
2155 gettimeofday(&now, NULL);
2156 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2157 if (ti < MsgMinWait)
2158 DisplaySleep1000(MsgMinWait - ti, 0);
2159 }
2160 RemoveStatus();
2161 }
2162
2163 #ifdef UTF8
2164 static int
strlen_onscreen(unsigned char * c,unsigned char * end)2165 strlen_onscreen(unsigned char *c, unsigned char *end)
2166 {
2167 int len = 0;
2168 while (*c && (!end || c < end))
2169 {
2170 int v, dec = 0;
2171 do
2172 {
2173 v = FromUtf8(*c++, &dec);
2174 if (v == -2)
2175 c--;
2176 }
2177 while (v < 0 && (!end || c < end));
2178 if (!utf8_iscomb(v))
2179 {
2180 if (utf8_isdouble(v))
2181 len++;
2182 len++;
2183 }
2184 }
2185
2186 return len;
2187 }
2188
2189 static int
PrePutWinMsg(s,start,max)2190 PrePutWinMsg(s, start, max)
2191 char *s;
2192 int start, max;
2193 {
2194 /* Avoid double-encoding problem for a UTF-8 message on a UTF-8 locale.
2195 Ideally, this would not be necessary. But fixing it the Right Way will
2196 probably take way more time. So this will have to do for now. */
2197 if (D_encoding == UTF8)
2198 {
2199 int chars = strlen_onscreen((unsigned char *)(s + start), (unsigned char *)(s + max));
2200 D_encoding = 0;
2201 PutWinMsg(s, start, max + ((max - start) - chars)); /* Multibyte count */
2202 D_encoding = UTF8;
2203 D_x -= (max - chars); /* Yak! But this is necessary to count for
2204 the fact that not every byte represents a
2205 character. */
2206 return start + chars;
2207 }
2208 else
2209 {
2210 PutWinMsg(s, start, max);
2211 return max;
2212 }
2213 }
2214 #else
2215 static int
PrePutWinMsg(s,start,max)2216 PrePutWinMsg(s, start, max)
2217 char *s;
2218 int start, max;
2219 {
2220 PutWinMsg(s, start, max);
2221 return max;
2222 }
2223 #endif
2224
2225 /* refresh the display's hstatus line */
2226 void
ShowHStatus(str)2227 ShowHStatus(str)
2228 char *str;
2229 {
2230 int l, ox, oy, max;
2231
2232 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2233 return; /* sorry, in use */
2234 if (D_blocked)
2235 return;
2236
2237 if (D_HS && D_has_hstatus == HSTATUS_HS)
2238 {
2239 if (!D_hstatus && (str == 0 || *str == 0))
2240 return;
2241 debug("ShowHStatus: using HS\n");
2242 SetRendition(&mchar_null);
2243 InsertMode(0);
2244 if (D_hstatus)
2245 AddCStr(D_DS);
2246 D_hstatus = 0;
2247 if (str == 0 || *str == 0)
2248 return;
2249 AddCStr2(D_TS, 0);
2250 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2251 if ((int)strlen(str) > max)
2252 AddStrn(str, max);
2253 else
2254 AddStr(str);
2255 AddCStr(D_FS);
2256 D_hstatus = 1;
2257 }
2258 else if (D_has_hstatus == HSTATUS_LASTLINE)
2259 {
2260 debug("ShowHStatus: using last line\n");
2261 ox = D_x;
2262 oy = D_y;
2263 str = str ? str : "";
2264 l = strlen(str);
2265 if (l > D_width)
2266 l = D_width;
2267 GotoPos(0, D_height - 1);
2268 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2269 l = PrePutWinMsg(str, 0, l);
2270 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2271 while (l++ < D_width)
2272 PUTCHARLP(' ');
2273 if (l < D_width)
2274 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2275 if (ox != -1 && oy != -1)
2276 GotoPos(ox, oy);
2277 D_hstatus = *str ? 1 : 0;
2278 SetRendition(&mchar_null);
2279 }
2280 else if (D_has_hstatus == HSTATUS_FIRSTLINE)
2281 {
2282 debug("ShowHStatus: using first line\n");
2283 ox = D_x;
2284 oy = D_y;
2285 str = str ? str : "";
2286 l = strlen(str);
2287 if (l > D_width)
2288 l = D_width;
2289 GotoPos(0, 0);
2290 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2291 l = PrePutWinMsg(str, 0, l);
2292 if (!captionalways || (D_cvlist && !D_cvlist->c_next))
2293 while (l++ < D_width)
2294 PUTCHARLP(' ');
2295 if (l < D_width)
2296 ClearArea(l, 0, l, D_width - 1, D_width - 1, 0, 0, 0);
2297 if (ox != -1 && oy != -1)
2298 GotoPos(ox, oy);
2299 D_hstatus = *str ? 1 : 0;
2300 SetRendition(&mchar_null);
2301 }
2302 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2303 {
2304 debug("ShowHStatus: using message\n");
2305 Msg(0, "%s", str);
2306 }
2307 }
2308
2309
2310 /*
2311 * Refreshes the harstatus of the fore window. Shouldn't be here...
2312 */
2313 void
RefreshHStatus()2314 RefreshHStatus()
2315 {
2316 char *buf;
2317 #ifdef UTF8
2318 int extrabytes = strlen(hstatusstring) - strlen_onscreen(hstatusstring, NULL);
2319 #else
2320 int extrabytes = 0;
2321 #endif
2322 evdeq(&D_hstatusev);
2323 if (D_status == STATUS_ON_HS)
2324 return;
2325 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP + extrabytes, &D_hstatusev, 0);
2326 if (buf && *buf)
2327 {
2328 ShowHStatus(buf);
2329 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2330 evenq(&D_hstatusev);
2331 }
2332 else
2333 ShowHStatus((char *)0);
2334 }
2335
2336 /*********************************************************************/
2337 /*
2338 * Here come the routines that refresh an arbitrary part of the screen.
2339 */
2340
2341 void
RefreshAll(isblank)2342 RefreshAll(isblank)
2343 int isblank;
2344 {
2345 struct canvas *cv;
2346
2347 ASSERT(display);
2348 debug("Signalling full refresh!\n");
2349 for (cv = D_cvlist; cv; cv = cv->c_next)
2350 {
2351 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2352 display = cv->c_display; /* just in case! */
2353 }
2354 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2355 }
2356
2357 void
RefreshArea(xs,ys,xe,ye,isblank)2358 RefreshArea(xs, ys, xe, ye, isblank)
2359 int xs, ys, xe, ye, isblank;
2360 {
2361 int y;
2362 ASSERT(display);
2363 debug2("Refresh Area: %d,%d", xs, ys);
2364 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2365 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2366 {
2367 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2368 isblank = 1;
2369 }
2370 for (y = ys; y <= ye; y++)
2371 RefreshLine(y, xs, xe, isblank);
2372 }
2373
2374 void
RefreshLine(y,from,to,isblank)2375 RefreshLine(y, from, to, isblank)
2376 int y, from, to, isblank;
2377 {
2378 struct viewport *vp, *lvp;
2379 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2380 struct layer *oldflayer;
2381 int xx, yy, l;
2382 char *buf;
2383 struct win *p;
2384
2385 ASSERT(display);
2386
2387 debug2("RefreshLine %d %d", y, from);
2388 debug2(" %d %d\n", to, isblank);
2389
2390 if (D_status == STATUS_ON_WIN && y == STATLINE)
2391 {
2392 if (to >= D_status_len)
2393 D_status_len = to + 1;
2394 return; /* can't refresh status */
2395 }
2396
2397 if (isblank == 0 && D_CE && to == D_width - 1 && from < to && D_status != STATUS_ON_HS)
2398 {
2399 GotoPos(from, y);
2400 if (D_UT || D_BE)
2401 SetRendition(&mchar_null);
2402 AddCStr(D_CE);
2403 isblank = 1;
2404 }
2405
2406 if ((y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE) || (y == 0 && D_has_hstatus == HSTATUS_FIRSTLINE) )
2407 {
2408 RefreshHStatus();
2409 return;
2410 }
2411
2412 while (from <= to)
2413 {
2414 lcv = 0;
2415 lvp = 0;
2416 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2417 {
2418 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2419 {
2420 #ifdef UTF8
2421 int extrabytes = strlen(captionstring) - strlen_onscreen(captionstring, NULL);
2422 #else
2423 int extrabytes = 0;
2424 #endif
2425 p = Layer2Window(cv->c_layer);
2426 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP) + extrabytes, &cv->c_captev, 0);
2427 if (cv->c_captev.timeout.tv_sec)
2428 evenq(&cv->c_captev);
2429 xx = to > cv->c_xe ? cv->c_xe : to;
2430 l = strlen(buf);
2431 GotoPos(from, y);
2432 SetRendition(&mchar_so);
2433 if (l > xx - cv->c_xs + 1)
2434 l = xx - cv->c_xs + 1;
2435 l = PrePutWinMsg(buf, from - cv->c_xs, l + extrabytes);
2436 from = cv->c_xs + l;
2437 for (; from <= xx; from++)
2438 PUTCHARLP(' ');
2439 break;
2440 }
2441 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
2442 {
2443 GotoPos(from, y);
2444 SetRendition(&mchar_so);
2445 PUTCHARLP(' ');
2446 from++;
2447 break;
2448 }
2449 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
2450 continue;
2451 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
2452 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
2453 for (vp = cv->c_vplist; vp; vp = vp->v_next)
2454 {
2455 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
2456 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
2457 /* find leftmost overlapping vp */
2458 if (y >= vp->v_ys && y <= vp->v_ye && from <= vp->v_xe && to >= vp->v_xs && (lvp == 0 || lvp->v_xs > vp->v_xs))
2459 {
2460 lcv = cv;
2461 lvp = vp;
2462 }
2463 }
2464 }
2465 if (cv)
2466 continue; /* we advanced from */
2467 if (lvp == 0)
2468 break;
2469 if (from < lvp->v_xs)
2470 {
2471 if (!isblank)
2472 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
2473 from = lvp->v_xs;
2474 }
2475
2476 /* call LayRedisplayLine on canvas lcv viewport lvp */
2477 yy = y - lvp->v_yoff;
2478 xx = to < lvp->v_xe ? to : lvp->v_xe;
2479
2480 if (lcv->c_layer && lcv->c_xoff + lcv->c_layer->l_width == from)
2481 {
2482 GotoPos(from, y);
2483 SetRendition(&mchar_blank);
2484 PUTCHARLP('|');
2485 from++;
2486 }
2487 if (lcv->c_layer && yy == lcv->c_layer->l_height)
2488 {
2489 GotoPos(from, y);
2490 SetRendition(&mchar_blank);
2491 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
2492 {
2493 PUTCHARLP('-');
2494 from++;
2495 }
2496 if (from >= lvp->v_xe + 1)
2497 continue;
2498 }
2499 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
2500 {
2501 if (!isblank)
2502 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
2503 from = lvp->v_xe + 1;
2504 continue;
2505 }
2506
2507 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
2508 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
2509 oldflayer = flayer;
2510 flayer = lcv->c_layer;
2511 cvlist = flayer->l_cvlist;
2512 cvlnext = lcv->c_lnext;
2513 flayer->l_cvlist = lcv;
2514 lcv->c_lnext = 0;
2515 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
2516 flayer->l_cvlist = cvlist;
2517 lcv->c_lnext = cvlnext;
2518 flayer = oldflayer;
2519
2520 from = xx + 1;
2521 }
2522 if (!isblank && from <= to)
2523 DisplayLine(&mline_null, &mline_blank, y, from, to);
2524 }
2525
2526 /*********************************************************************/
2527
2528 /* clear lp_missing by writing the char on the screen. The
2529 * position must be safe.
2530 */
2531 static void
WriteLP(x2,y2)2532 WriteLP(x2, y2)
2533 int x2, y2;
2534 {
2535 struct mchar oldrend;
2536
2537 ASSERT(display);
2538 ASSERT(D_lp_missing);
2539 oldrend = D_rend;
2540 debug2("WriteLP(%d,%d)\n", x2, y2);
2541 #ifdef DW_CHARS
2542 if (D_lpchar.mbcs)
2543 {
2544 if (x2 > 0)
2545 x2--;
2546 else
2547 D_lpchar = mchar_blank;
2548 }
2549 #endif
2550 /* Can't use PutChar */
2551 GotoPos(x2, y2);
2552 SetRendition(&D_lpchar);
2553 PUTCHAR(D_lpchar.image);
2554 #ifdef DW_CHARS
2555 if (D_lpchar.mbcs)
2556 PUTCHAR(D_lpchar.mbcs);
2557 #endif
2558 D_lp_missing = 0;
2559 SetRendition(&oldrend);
2560 }
2561
2562 void
ClearLine(oml,y,from,to,bce)2563 ClearLine(oml, y, from, to, bce)
2564 struct mline *oml;
2565 int from, to, y, bce;
2566 {
2567 int x;
2568 #ifdef COLOR
2569 struct mchar bcechar;
2570 #endif
2571
2572 debug3("ClearLine %d,%d-%d\n", y, from, to);
2573 if (D_UT) /* Safe to erase ? */
2574 SetRendition(&mchar_null);
2575 #ifdef COLOR
2576 if (D_BE)
2577 SetBackColor(bce);
2578 #endif
2579 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
2580 {
2581 GotoPos(to, y);
2582 AddCStr(D_CB);
2583 return;
2584 }
2585 if (to == D_width - 1 && D_CE && (!bce || D_BE))
2586 {
2587 GotoPos(from, y);
2588 AddCStr(D_CE);
2589 return;
2590 }
2591 if (oml == 0)
2592 oml = &mline_null;
2593 #ifdef COLOR
2594 if (!bce)
2595 {
2596 DisplayLine(oml, &mline_blank, y, from, to);
2597 return;
2598 }
2599 bcechar = mchar_null;
2600 rend_setbg(&bcechar, bce);
2601 for (x = from; x <= to; x++)
2602 copy_mchar2mline(&bcechar, &mline_old, x);
2603 DisplayLine(oml, &mline_old, y, from, to);
2604 #else
2605 DisplayLine(oml, &mline_blank, y, from, to);
2606 #endif
2607 }
2608
2609 void
DisplayLine(oml,ml,y,from,to)2610 DisplayLine(oml, ml, y, from, to)
2611 struct mline *oml, *ml;
2612 int from, to, y;
2613 {
2614 register int x;
2615 int last2flag = 0, delete_lp = 0;
2616
2617 ASSERT(display);
2618 ASSERT(y >= 0 && y < D_height);
2619 ASSERT(from >= 0 && from < D_width);
2620 ASSERT(to >= 0 && to < D_width);
2621 if (!D_CLP && y == D_bot && to == D_width - 1)
2622 {
2623 if (D_lp_missing || !cmp_mline(oml, ml, to))
2624 {
2625 #ifdef DW_CHARS
2626 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
2627 #else
2628 if ((D_IC || D_IM) && from < to)
2629 #endif
2630 {
2631 last2flag = 1;
2632 D_lp_missing = 0;
2633 to--;
2634 }
2635 else
2636 {
2637 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
2638 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
2639 copy_mline2mchar(&D_lpchar, ml, to);
2640 }
2641 }
2642 to--;
2643 }
2644 #ifdef DW_CHARS
2645 if (D_mbcs)
2646 {
2647 /* finish dw-char (can happen after a wrap) */
2648 debug("DisplayLine finishing kanji\n");
2649 SetRenditionMline(ml, from);
2650 PUTCHAR(ml->image[from]);
2651 from++;
2652 }
2653 #endif
2654 for (x = from; x <= to; x++)
2655 {
2656 #if 0 /* no longer needed */
2657 if (x || D_x != D_width || D_y != y - 1)
2658 #endif
2659 {
2660 if (ml != NULL && (x < to || x != D_width - 1 || ml->image[x + 1]))
2661 if (cmp_mline(oml, ml, x))
2662 continue;
2663 GotoPos(x, y);
2664 }
2665 #ifdef DW_CHARS
2666 if (dw_right(ml, x, D_encoding))
2667 {
2668 x--;
2669 debug1("DisplayLine on right side of dw char- x now %d\n", x);
2670 GotoPos(x, y);
2671 }
2672 if (x == to && dw_left(ml, x, D_encoding))
2673 break; /* don't start new kanji */
2674 #endif
2675 SetRenditionMline(ml, x);
2676 PUTCHAR(ml->image[x]);
2677 #ifdef DW_CHARS
2678 if (dw_left(ml, x, D_encoding))
2679 PUTCHAR(ml->image[++x]);
2680 #endif
2681 }
2682 #if 0 /* not needed any longer */
2683 /* compare != 0 because ' ' can happen when clipping occures */
2684 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
2685 GotoPos(0, y + 1);
2686 #endif
2687 if (last2flag)
2688 {
2689 GotoPos(x, y);
2690 SetRenditionMline(ml, x + 1);
2691 PUTCHAR(ml->image[x + 1]);
2692 GotoPos(x, y);
2693 SetRenditionMline(ml, x);
2694 INSERTCHAR(ml->image[x]);
2695 }
2696 else if (delete_lp)
2697 {
2698 if (D_UT)
2699 SetRendition(&mchar_null);
2700 if (D_DC)
2701 AddCStr(D_DC);
2702 else if (D_CDC)
2703 AddCStr2(D_CDC, 1);
2704 else if (D_CE)
2705 AddCStr(D_CE);
2706 }
2707 }
2708
2709 void
PutChar(c,x,y)2710 PutChar(c, x, y)
2711 struct mchar *c;
2712 int x, y;
2713 {
2714 GotoPos(x, y);
2715 SetRendition(c);
2716 PUTCHARLP(c->image);
2717 #ifdef DW_CHARS
2718 if (c->mbcs)
2719 {
2720 # ifdef UTF8
2721 if (D_encoding == UTF8)
2722 D_rend.font = 0;
2723 # endif
2724 PUTCHARLP(c->mbcs);
2725 }
2726 #endif
2727 }
2728
2729 void
InsChar(c,x,xe,y,oml)2730 InsChar(c, x, xe, y, oml)
2731 struct mchar *c;
2732 int x, xe, y;
2733 struct mline *oml;
2734 {
2735 GotoPos(x, y);
2736 if (y == D_bot && !D_CLP)
2737 {
2738 if (x == D_width - 1)
2739 {
2740 D_lp_missing = 1;
2741 D_lpchar = *c;
2742 return;
2743 }
2744 if (xe == D_width - 1)
2745 D_lp_missing = 0;
2746 }
2747 if (x == xe)
2748 {
2749 SetRendition(c);
2750 PUTCHARLP(c->image);
2751 return;
2752 }
2753 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
2754 {
2755 RefreshLine(y, x, xe, 0);
2756 GotoPos(x + 1, y);
2757 /* UpdateLine(oml, y, x, xe); */
2758 return;
2759 }
2760 InsertMode(1);
2761 if (!D_insert)
2762 {
2763 #ifdef DW_CHARS
2764 if (c->mbcs && D_IC)
2765 AddCStr(D_IC);
2766 if (D_IC)
2767 AddCStr(D_IC);
2768 else
2769 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
2770 #else
2771 if (D_IC)
2772 AddCStr(D_IC);
2773 else
2774 AddCStr2(D_CIC, 1);
2775 #endif
2776 }
2777 SetRendition(c);
2778 RAW_PUTCHAR(c->image);
2779 #ifdef DW_CHARS
2780 if (c->mbcs)
2781 {
2782 # ifdef UTF8
2783 if (D_encoding == UTF8)
2784 D_rend.font = 0;
2785 # endif
2786 if (D_x == D_width - 1)
2787 PUTCHARLP(c->mbcs);
2788 else
2789 RAW_PUTCHAR(c->mbcs);
2790 }
2791 #endif
2792 }
2793
2794 void
WrapChar(c,x,y,xs,ys,xe,ye,ins)2795 WrapChar(c, x, y, xs, ys, xe, ye, ins)
2796 struct mchar *c;
2797 int x, y;
2798 int xs, ys, xe, ye;
2799 int ins;
2800 {
2801 int bce;
2802
2803 #ifdef COLOR
2804 bce = rend_getbg(c);
2805 #else
2806 bce = 0;
2807 #endif
2808 debug("WrapChar:");
2809 debug2(" x %d y %d", x, y);
2810 debug2(" Dx %d Dy %d", D_x, D_y);
2811 debug2(" xs %d ys %d", xs, ys);
2812 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
2813 if (xs != 0 || x != D_width || !D_AM)
2814 {
2815 if (y == ye)
2816 ScrollV(xs, ys, xe, ye, 1, bce);
2817 else if (y < D_height - 1)
2818 y++;
2819 if (ins)
2820 InsChar(c, xs, xe, y, 0);
2821 else
2822 PutChar(c, xs, y);
2823 return;
2824 }
2825 if (y == ye) /* we have to scroll */
2826 {
2827 debug("- scrolling\n");
2828 ChangeScrollRegion(ys, ye);
2829 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
2830 {
2831 debug("- have to call ScrollV\n");
2832 ScrollV(xs, ys, xe, ye, 1, bce);
2833 y--;
2834 }
2835 }
2836 else if (y == D_bot) /* remove unusable region? */
2837 ChangeScrollRegion(0, D_height - 1);
2838 if (D_x != D_width || D_y != y)
2839 {
2840 if (D_CLP && y >= 0) /* don't even try if !LP */
2841 RefreshLine(y, D_width - 1, D_width - 1, 0);
2842 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
2843 if (D_x != D_width || D_y != y) /* sorry, no bonus */
2844 {
2845 if (y == ye)
2846 ScrollV(xs, ys, xe, ye, 1, bce);
2847 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
2848 }
2849 }
2850 debug("- writeing new char");
2851 if (y != ye && y < D_height - 1)
2852 y++;
2853 if (ins != D_insert)
2854 InsertMode(ins);
2855 if (ins && !D_insert)
2856 {
2857 InsChar(c, 0, xe, y, 0);
2858 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
2859 return;
2860 }
2861 D_y = y;
2862 D_x = 0;
2863 SetRendition(c);
2864 RAW_PUTCHAR(c->image);
2865 #ifdef DW_CHARS
2866 if (c->mbcs)
2867 {
2868 # ifdef UTF8
2869 if (D_encoding == UTF8)
2870 D_rend.font = 0;
2871 # endif
2872 RAW_PUTCHAR(c->mbcs);
2873 }
2874 #endif
2875 debug2(" -> done (%d,%d)\n", D_x, D_y);
2876 }
2877
2878 int
ResizeDisplay(wi,he)2879 ResizeDisplay(wi, he)
2880 int wi, he;
2881 {
2882 ASSERT(display);
2883 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
2884 if (D_width == wi && D_height == he)
2885 {
2886 debug("ResizeDisplay: No change\n");
2887 return 0;
2888 }
2889 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
2890 {
2891 debug("ResizeDisplay: using Z0/Z1\n");
2892 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
2893 ChangeScreenSize(wi, D_height, 0);
2894 return (he == D_height) ? 0 : -1;
2895 }
2896 if (D_CWS)
2897 {
2898 debug("ResizeDisplay: using WS\n");
2899 AddCStr(tgoto(D_CWS, wi, he));
2900 ChangeScreenSize(wi, he, 0);
2901 return 0;
2902 }
2903 return -1;
2904 }
2905
2906 void
ChangeScrollRegion(newtop,newbot)2907 ChangeScrollRegion(newtop, newbot)
2908 int newtop, newbot;
2909 {
2910 if (display == 0)
2911 return;
2912 if (newtop == newbot)
2913 return; /* xterm etc can't do it */
2914 if (newtop == -1)
2915 newtop = 0;
2916 if (newbot == -1)
2917 newbot = D_height - 1;
2918 if (D_CS == 0)
2919 {
2920 D_top = 0;
2921 D_bot = D_height - 1;
2922 return;
2923 }
2924 if (D_top == newtop && D_bot == newbot)
2925 return;
2926 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
2927 AddCStr(tgoto(D_CS, newbot, newtop));
2928 D_top = newtop;
2929 D_bot = newbot;
2930 D_y = D_x = -1; /* Just in case... */
2931 }
2932
2933 #ifdef RXVT_OSC
2934 #define WT_FLAG "2" /* change to "0" to set both title and icon */
2935
2936 void
SetXtermOSC(i,s,t)2937 SetXtermOSC(i, s, t)
2938 int i;
2939 char *s;
2940 char *t;
2941 {
2942 static char *oscs[][2] = {
2943 { WT_FLAG ";", "screen" }, /* set window title */
2944 { "11;", ""}, /* background RGB */
2945 { "20;", "" }, /* background */
2946 { "39;", "black" }, /* default foreground (black?) */
2947 { "49;", "white" } /* default background (white?) */
2948 };
2949
2950 ASSERT(display);
2951 if (!D_CXT)
2952 return;
2953 if (!s)
2954 s = "";
2955 if (!D_xtermosc[i] && !*s)
2956 return;
2957 if (i == 0 && !D_xtermosc[0])
2958 AddStr("\033[22;" WT_FLAG "t"); /* stack titles (xterm patch #251) */
2959 if (!*s)
2960 s = oscs[i][1];
2961 D_xtermosc[i] = 1;
2962 AddStr("\033]");
2963 AddStr(oscs[i][0]);
2964 AddStr(s);
2965 AddStr(t);
2966 }
2967
2968 void
ClearAllXtermOSC()2969 ClearAllXtermOSC()
2970 {
2971 int i;
2972 for (i = 4; i >= 0; i--)
2973 SetXtermOSC(i, 0, "\a");
2974 if (D_xtermosc[0])
2975 AddStr("\033[23;" WT_FLAG "t"); /* unstack titles (xterm patch #251) */
2976 }
2977 #undef WT_FLAG
2978 #endif
2979
2980 /*
2981 * Output buffering routines
2982 */
2983
2984 void
AddStr(str)2985 AddStr(str)
2986 char *str;
2987 {
2988 register char c;
2989
2990 ASSERT(display);
2991
2992 #ifdef UTF8
2993 if (D_encoding == UTF8)
2994 {
2995 while ((c = *str++))
2996 AddUtf8((unsigned char)c);
2997 return;
2998 }
2999 #endif
3000 while ((c = *str++))
3001 AddChar(c);
3002 }
3003
3004 void
AddStrn(str,n)3005 AddStrn(str, n)
3006 char *str;
3007 int n;
3008 {
3009 register char c;
3010
3011 ASSERT(display);
3012 #ifdef UTF8
3013 if (D_encoding == UTF8)
3014 {
3015 while ((c = *str++) && n-- > 0)
3016 AddUtf8((unsigned char)c);
3017 }
3018 else
3019 #endif
3020 while ((c = *str++) && n-- > 0)
3021 AddChar(c);
3022 while (n-- > 0)
3023 AddChar(' ');
3024 }
3025
3026 void
Flush(progress)3027 Flush(progress)
3028 int progress;
3029 {
3030 register int l;
3031 int wr;
3032 register char *p;
3033
3034 ASSERT(display);
3035 l = D_obufp - D_obuf;
3036 debug1("Flush(): %d\n", l);
3037 if (l == 0)
3038 return;
3039 ASSERT(l + D_obuffree == D_obuflen);
3040 if (D_userfd < 0)
3041 {
3042 D_obuffree += l;
3043 D_obufp = D_obuf;
3044 return;
3045 }
3046 p = D_obuf;
3047 if (!progress)
3048 {
3049 if (fcntl(D_userfd, F_SETFL, 0))
3050 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3051 }
3052 while (l)
3053 {
3054 if (progress)
3055 {
3056 fd_set w;
3057 FD_ZERO(&w);
3058 FD_SET(D_userfd, &w);
3059 struct timeval t;
3060 t.tv_sec = progress;
3061 t.tv_usec = 0;
3062 wr = select(FD_SETSIZE, (fd_set *)0, &w, (fd_set *)0, &t);
3063 if (wr == -1)
3064 {
3065 if (errno == EINTR)
3066 continue;
3067 debug1("Warning: select failed: %d\n", errno);
3068 break;
3069 }
3070 if (wr == 0)
3071 {
3072 /* no progress after 3 seconds. sorry. */
3073 debug1("Warning: no progress after %d seconds\n", progress);
3074 break;
3075 }
3076 }
3077 wr = write(D_userfd, p, l);
3078 if (wr <= 0)
3079 {
3080 if (errno == EINTR)
3081 continue;
3082 debug1("Writing to display: %d\n", errno);
3083 break;
3084 }
3085 D_obuffree += wr;
3086 p += wr;
3087 l -= wr;
3088 }
3089 if (l)
3090 debug1("Warning: Flush could not write %d bytes\n", l);
3091 D_obuffree += l;
3092 D_obufp = D_obuf;
3093 if (!progress)
3094 {
3095 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3096 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3097 }
3098 if (D_blocked == 1)
3099 D_blocked = 0;
3100 D_blocked_fuzz = 0;
3101 }
3102
3103 void
freetty()3104 freetty()
3105 {
3106 if (D_userfd >= 0)
3107 close(D_userfd);
3108 debug1("did freetty %d\n", D_userfd);
3109 D_userfd = -1;
3110 D_obufp = 0;
3111 D_obuffree = 0;
3112 if (D_obuf)
3113 free(D_obuf);
3114 D_obuf = 0;
3115 D_obuflen = 0;
3116 D_obuflenmax = -D_obufmax;
3117 D_blocked = 0;
3118 D_blocked_fuzz = 0;
3119 }
3120
3121 /*
3122 * Asynchronous output routines by
3123 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3124 */
3125
3126 void
Resize_obuf()3127 Resize_obuf()
3128 {
3129 register int ind;
3130
3131 ASSERT(display);
3132 if (D_status_obuffree >= 0)
3133 {
3134 ASSERT(D_obuffree == -1);
3135 RemoveStatusMinWait();
3136 if (--D_obuffree > 0) /* redo AddChar decrement */
3137 return;
3138 }
3139 if (D_obuflen && D_obuf)
3140 {
3141 ind = D_obufp - D_obuf;
3142 D_obuflen += GRAIN;
3143 D_obuffree += GRAIN;
3144 D_obuf = realloc(D_obuf, D_obuflen);
3145 }
3146 else
3147 {
3148 ind = 0;
3149 D_obuflen = GRAIN;
3150 D_obuffree = GRAIN;
3151 D_obuf = malloc(D_obuflen);
3152 }
3153 if (!D_obuf)
3154 Panic(0, "Out of memory");
3155 D_obufp = D_obuf + ind;
3156 D_obuflenmax = D_obuflen - D_obufmax;
3157 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3158 }
3159
3160 void
DisplaySleep1000(n,eat)3161 DisplaySleep1000(n, eat)
3162 int n;
3163 int eat;
3164 {
3165 char buf;
3166 fd_set r;
3167 struct timeval t;
3168
3169 if (n <= 0)
3170 return;
3171 if (!display)
3172 {
3173 debug("DisplaySleep has no display sigh\n");
3174 sleep1000(n);
3175 return;
3176 }
3177 t.tv_usec = (n % 1000) * 1000;
3178 t.tv_sec = n / 1000;
3179 FD_ZERO(&r);
3180 FD_SET(D_userfd, &r);
3181 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3182 {
3183 debug("display activity stopped sleep\n");
3184 if (eat)
3185 read(D_userfd, &buf, 1);
3186 }
3187 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3188 }
3189
3190 #ifdef AUTO_NUKE
3191 void
NukePending()3192 NukePending()
3193 {/* Nuke pending output in current display, clear screen */
3194 register int len;
3195 int oldtop = D_top, oldbot = D_bot;
3196 struct mchar oldrend;
3197 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3198 int oldcurvis = D_curvis;
3199 int oldmouse = D_mouse;
3200 int oldextmouse = D_extmouse;
3201
3202 oldrend = D_rend;
3203 len = D_obufp - D_obuf;
3204 debug1("NukePending: nuking %d chars\n", len);
3205
3206 /* Throw away any output that we can... */
3207 # ifdef POSIX
3208 tcflush(D_userfd, TCOFLUSH);
3209 # else
3210 # ifdef TCFLSH
3211 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3212 # endif
3213 # endif
3214
3215 D_obufp = D_obuf;
3216 D_obuffree += len;
3217 D_top = D_bot = -1;
3218 AddCStr(D_IS);
3219 AddCStr(D_TI);
3220 /* Turn off all attributes. (Tim MacKenzie) */
3221 if (D_ME)
3222 AddCStr(D_ME);
3223 else
3224 {
3225 #ifdef COLOR
3226 if (D_hascolor)
3227 AddStr("\033[m"); /* why is D_ME not set? */
3228 #endif
3229 AddCStr(D_SE);
3230 AddCStr(D_UE);
3231 }
3232 /* Check for toggle */
3233 if (D_IM && strcmp(D_IM, D_EI))
3234 AddCStr(D_EI);
3235 D_insert = 0;
3236 /* Check for toggle */
3237 #ifdef MAPKEYS
3238 if (D_KS && strcmp(D_KS, D_KE))
3239 AddCStr(D_KS);
3240 if (D_CCS && strcmp(D_CCS, D_CCE))
3241 AddCStr(D_CCS);
3242 #else
3243 if (D_KS && strcmp(D_KS, D_KE))
3244 AddCStr(D_KE);
3245 D_keypad = 0;
3246 if (D_CCS && strcmp(D_CCS, D_CCE))
3247 AddCStr(D_CCE);
3248 D_cursorkeys = 0;
3249 #endif
3250 AddCStr(D_CE0);
3251 D_rend = mchar_null;
3252 D_atyp = 0;
3253 AddCStr(D_DS);
3254 D_hstatus = 0;
3255 AddCStr(D_VE);
3256 D_curvis = 0;
3257 ChangeScrollRegion(oldtop, oldbot);
3258 SetRendition(&oldrend);
3259 KeypadMode(oldkeypad);
3260 CursorkeysMode(oldcursorkeys);
3261 CursorVisibility(oldcurvis);
3262 MouseMode(oldmouse);
3263 ExtMouseMode(oldextmouse);
3264 if (D_CWS)
3265 {
3266 debug("ResizeDisplay: using WS\n");
3267 AddCStr(tgoto(D_CWS, D_width, D_height));
3268 }
3269 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3270 {
3271 debug("ResizeDisplay: using Z0/Z1\n");
3272 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3273 }
3274 }
3275 #endif /* AUTO_NUKE */
3276
3277 #ifdef linux
3278 /* linux' select can't handle flow control, so wait 100ms if
3279 * we get EAGAIN
3280 */
3281 static void
disp_writeev_eagain(ev,data)3282 disp_writeev_eagain(ev, data)
3283 struct event *ev;
3284 char *data;
3285 {
3286 display = (struct display *)data;
3287 evdeq(&D_writeev);
3288 D_writeev.type = EV_WRITE;
3289 D_writeev.handler = disp_writeev_fn;
3290 evenq(&D_writeev);
3291 }
3292 #endif
3293
3294 static void
disp_writeev_fn(ev,data)3295 disp_writeev_fn(ev, data)
3296 struct event *ev;
3297 char *data;
3298 {
3299 int len, size = OUTPUT_BLOCK_SIZE;
3300
3301 display = (struct display *)data;
3302 len = D_obufp - D_obuf;
3303 if (len < size)
3304 size = len;
3305 if (D_status_obufpos && size > D_status_obufpos)
3306 size = D_status_obufpos;
3307 ASSERT(len >= 0);
3308 size = write(D_userfd, D_obuf, size);
3309 if (size >= 0)
3310 {
3311 len -= size;
3312 if (len)
3313 {
3314 bcopy(D_obuf + size, D_obuf, len);
3315 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3316 }
3317 D_obufp -= size;
3318 D_obuffree += size;
3319 if (D_status_obufpos)
3320 {
3321 D_status_obufpos -= size;
3322 if (!D_status_obufpos)
3323 {
3324 debug("finished writing the status message\n");
3325 /* we're finished displaying the message! */
3326 if (D_status == STATUS_ON_WIN)
3327 {
3328 /* setup continue trigger */
3329 D_status_obuflen = D_obuflen;
3330 D_status_obuffree = D_obuffree;
3331 /* setting obbuffree to 0 will make AddChar call
3332 * ResizeObuf */
3333 D_obuffree = D_obuflen = 0;
3334 }
3335 gettimeofday(&D_status_time, NULL);
3336 SetTimeout(&D_statusev, MsgWait);
3337 evenq(&D_statusev);
3338 #ifdef HAVE_BRAILLE
3339 RefreshBraille(); /* let user see multiple Msg()s */
3340 #endif
3341 }
3342 }
3343 if (D_blocked_fuzz)
3344 {
3345 D_blocked_fuzz -= size;
3346 if (D_blocked_fuzz < 0)
3347 D_blocked_fuzz = 0;
3348 }
3349 if (D_blockedev.queued)
3350 {
3351 if (D_obufp - D_obuf > D_obufmax / 2)
3352 {
3353 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3354 SetTimeout(&D_blockedev, D_nonblock);
3355 }
3356 else
3357 {
3358 debug1("%s: deleting blocked timeout\n", D_usertty);
3359 evdeq(&D_blockedev);
3360 }
3361 }
3362 if (D_blocked == 1 && D_obuf == D_obufp)
3363 {
3364 /* empty again, restart output */
3365 debug1("%s: buffer empty, unblocking\n", D_usertty);
3366 D_blocked = 0;
3367 Activate(D_fore ? D_fore->w_norefresh : 0);
3368 D_blocked_fuzz = D_obufp - D_obuf;
3369 }
3370 }
3371 else
3372 {
3373 #ifdef linux
3374 /* linux flow control is badly broken */
3375 if (errno == EAGAIN)
3376 {
3377 evdeq(&D_writeev);
3378 D_writeev.type = EV_TIMEOUT;
3379 D_writeev.handler = disp_writeev_eagain;
3380 SetTimeout(&D_writeev, 100);
3381 evenq(&D_writeev);
3382 }
3383 #endif
3384 if (errno != EINTR && errno != EAGAIN)
3385 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3386 if (errno != EWOULDBLOCK)
3387 #endif
3388 Msg(errno, "Error writing output to display");
3389 }
3390 }
3391
3392 /* maximum mouse sequence length is SGR: ESC [ < b ; x ; y M */
3393 #define MAX_MOUSE_SEQUENCE (3+10+1+10+1+10+1)
3394
3395 static void
disp_readev_fn(ev,data)3396 disp_readev_fn(ev, data)
3397 struct event *ev;
3398 char *data;
3399 {
3400 /* We have to intercept mouse sequences in order to translate them
3401 * properly, and an incoming sequence could be spread over multiple
3402 * I/O reads. When this occurs, we buffer intermediate state in
3403 * D_mouse_params, and then use the reservation at the front of
3404 * bufspace to prepend the completed and translated mouse sequence.
3405 */
3406 int size;
3407 char bufspace[MAX_MOUSE_SEQUENCE + IOSIZE];
3408 unsigned char *buf = bufspace + MAX_MOUSE_SEQUENCE;
3409
3410 struct canvas *cv;
3411
3412 display = (struct display *)data;
3413
3414 /* Hmmmm... a bit ugly... */
3415 if (D_forecv)
3416 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3417 {
3418 display = cv->c_display;
3419 if (D_status == STATUS_ON_WIN)
3420 RemoveStatus();
3421 }
3422
3423 display = (struct display *)data;
3424 if (D_fore == 0)
3425 size = IOSIZE;
3426 else
3427 {
3428 #ifdef PSEUDOS
3429 if (W_UWP(D_fore))
3430 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3431 else
3432 #endif
3433 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3434 }
3435
3436 if (size > IOSIZE)
3437 size = IOSIZE;
3438 if (size <= 0)
3439 size = 1; /* Always allow one char for command keys */
3440
3441 size = read(D_userfd, buf, size);
3442 if (size < 0)
3443 {
3444 if (errno == EINTR || errno == EAGAIN)
3445 return;
3446 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3447 if (errno == EWOULDBLOCK)
3448 return;
3449 #endif
3450 debug1("Read error: %d - hangup!\n", errno);
3451 Hangup();
3452 sleep(1);
3453 return;
3454 }
3455 else if (size == 0)
3456 {
3457 debug("Found EOF - hangup!\n");
3458 Hangup();
3459 sleep(1);
3460 return;
3461 }
3462 if (D_blocked == 4)
3463 {
3464 D_blocked = 0;
3465 #ifdef BLANKER_PRG
3466 KillBlanker();
3467 #endif
3468 Activate(D_fore ? D_fore->w_norefresh : 0);
3469 ResetIdle();
3470 return;
3471 }
3472 #ifdef ZMODEM
3473 if (D_blocked > 1) /* 2, 3 */
3474 {
3475 char *bufp;
3476 struct win *p;
3477
3478 flayer = 0;
3479 for (p = windows; p ; p = p->w_next)
3480 if (p->w_zdisplay == display)
3481 {
3482 flayer = &p->w_layer;
3483 bufp = buf;
3484 while (size > 0)
3485 LayProcess(&bufp, &size);
3486 return;
3487 }
3488 debug("zmodem window gone, deblocking display");
3489 zmodem_abort(0, display);
3490 }
3491 #endif
3492 if (idletimo > 0)
3493 ResetIdle();
3494 if (D_fore)
3495 D_fore->w_lastdisp = display;
3496
3497 if (D_mouse && D_forecv)
3498 {
3499 unsigned char *bp = (unsigned char *)buf;
3500 unsigned char *end = bp + size;
3501 unsigned char *mark = NULL;
3502
3503 /* When mouse mode is enabled, buffer up incoming CSI until we
3504 * know whether it is a mouse sequence. If not a mouse event,
3505 * emit the CSI unchanged; if an invalid mouse event, swallow
3506 * it; otherwise, translate the sequence and emit it.
3507 *
3508 * Supported mouse events take two flavors.
3509 *
3510 * VT200: CSI M Cb Cx Cy
3511 * SGR: CSI < Ps ; Ps ; Ps M|m
3512 *
3513 * UTF-8 and UXRVT modes are explicitly rejected because they
3514 * introduce incompatibilities with other control sequences.
3515 *
3516 * NOTE: applications wishing to use SGR mode will normally
3517 * enable VT200 mode first as a fallback in case the terminal
3518 * does not support SGR mode. Thus, we must expect to receive
3519 * either mode's sequences when mouse mode is enabled. We will
3520 * dutifully translate whatever arrives, without attempting to
3521 * convert between modes on behalf of the application.
3522 */
3523 switch (D_mouse_parse.state)
3524 {
3525 case CSI_PY:
3526 case CSI_PX:
3527 case CSI_PB:
3528 /* Partial mouse sequence; do not restore suppressed
3529 * characters. We will emit a translated version (if valid)
3530 * or swallow them (otherwise).
3531 */
3532 break;
3533
3534 case CSI_BEGIN:
3535 /* Partial CSI; restore suppressed characters in case it
3536 * turns out not to be a mouse sequence after all.
3537 */
3538 *(--buf) = '[';
3539 ++size;
3540 /* fall through */
3541
3542 case CSI_ESC_SEEN:
3543 /* Escape character; restore it in case this turns out not
3544 * to be the start of a mouse sequence after all.
3545 */
3546 *(--buf) = '\033';
3547 ++size;
3548 break;
3549
3550 default:
3551 break;
3552 };
3553
3554 while (bp != end)
3555 {
3556 unsigned char c = *(bp++);
3557
3558 switch (D_mouse_parse.state)
3559 {
3560 case CSI_INACTIVE:
3561 if (c == '\033')
3562 {
3563 /* potential escape sequence */
3564 mark = bp-1;
3565 D_mouse_parse.state = CSI_ESC_SEEN;
3566 }
3567 break;
3568
3569 case CSI_ESC_SEEN:
3570 if (c == '[')
3571 {
3572 /* continue buffering an escape sequence */
3573 D_mouse_parse.state = CSI_BEGIN;
3574 }
3575 else
3576 D_mouse_parse.state = CSI_INACTIVE;
3577 break;
3578
3579 case CSI_BEGIN:
3580 if (c == 'M')
3581 {
3582 /* VT200 mouse sequence */
3583 D_mouse_parse.state = CSI_PB;
3584 D_mouse_parse.sgrmode = 0;
3585 }
3586 else if (c == '<')
3587 {
3588 /* SGR mouse sequence */
3589 D_mouse_parse.state = CSI_PB;
3590 D_mouse_parse.params[D_mouse_parse.state] = 0;
3591 D_mouse_parse.sgrmode = 1;
3592 }
3593 else
3594 D_mouse_parse.state = CSI_INACTIVE;
3595 break;
3596
3597 case CSI_PB:
3598 case CSI_PX:
3599 case CSI_PY:
3600 if (D_mouse_parse.sgrmode)
3601 {
3602 /* SGR mode: parse decimal numbers */
3603 if ('0' <= c && c <= '9')
3604 {
3605 D_mouse_parse.params[D_mouse_parse.state] *= 10;
3606 D_mouse_parse.params[D_mouse_parse.state] += c - '0';
3607 }
3608 else if (D_mouse_parse.state == CSI_PY)
3609 {
3610 if (c == 'M' || c == 'm')
3611 D_mouse_parse.state = CSI_DONE;
3612 else
3613 D_mouse_parse.state = CSI_INVALID;
3614 }
3615 else if (c == ';')
3616 {
3617 D_mouse_parse.state++;
3618 D_mouse_parse.params[D_mouse_parse.state] = 0;
3619 }
3620 else
3621 D_mouse_parse.state = CSI_INVALID;
3622 }
3623 else
3624 {
3625 /* VT200 mode: read raw binary values */
3626 D_mouse_parse.params[D_mouse_parse.state++] = c;
3627 }
3628 break;
3629
3630 default:
3631 break;
3632 }
3633
3634 if (D_mouse_parse.state == CSI_INVALID)
3635 {
3636 /* swallow invalid sequence, but emit whatever came before */
3637 if (buf < mark)
3638 disp_processinput(display, buf, mark-buf);
3639
3640 buf = bp;
3641 size = end - bp;
3642 D_mouse_parse.state = CSI_INACTIVE;
3643 }
3644 else if (D_mouse_parse.state == CSI_DONE)
3645 {
3646 /* emit whatever came before this sequence */
3647 if (buf < mark)
3648 disp_processinput(display, buf, mark-buf);
3649
3650 buf = bp;
3651 size = end - bp;
3652
3653 int x = D_mouse_parse.params[CSI_PX];
3654 int y = D_mouse_parse.params[CSI_PY];
3655 int bias = D_mouse_parse.sgrmode? 1 : 33;
3656
3657 x -= bias;
3658 y -= bias;
3659
3660 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
3661 {
3662 if ((D_fore && D_fore->w_mouse) || (D_mousetrack && D_forecv->c_layer->l_mode == 1))
3663 {
3664 /* Send clicks only if the window is expecting clicks */
3665 x -= D_forecv->c_xoff;
3666 y -= D_forecv->c_yoff;
3667
3668 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
3669 {
3670 char tmp[MAX_MOUSE_SEQUENCE+1];
3671 int n;
3672
3673 x += bias;
3674 y += bias;
3675
3676 if (D_mouse_parse.sgrmode)
3677 {
3678 n = snprintf(
3679 tmp, MAX_MOUSE_SEQUENCE, "\033[<%d;%d;%d%c",
3680 D_mouse_parse.params[CSI_PB], x, y, c);
3681 }
3682 else
3683 {
3684 n = snprintf(
3685 tmp, MAX_MOUSE_SEQUENCE, "\033[M%c%c%c",
3686 D_mouse_parse.params[CSI_PB], x, y);
3687 }
3688
3689 if (n > MAX_MOUSE_SEQUENCE)
3690 n = MAX_MOUSE_SEQUENCE;
3691
3692 /* emit sequence */
3693 buf -= n;
3694 size += n;
3695 memcpy(buf, tmp, n);
3696 }
3697 }
3698 }
3699 else if (D_mousetrack)
3700 {
3701 /* 'focus' to the clicked region, only on mouse up */
3702 int focus = 0;
3703 if (D_mouse_parse.sgrmode)
3704 focus = (c == 'm');
3705 else
3706 focus = (D_mouse_parse.params[CSI_PB] == '#');
3707
3708 struct canvas *cv = FindCanvas(x, y);
3709 if (focus && cv)
3710 {
3711 SetForeCanvas(display, cv);
3712 /* XXX: Do we want to reset the input buffer? */
3713 }
3714 }
3715
3716 D_mouse_parse.state = CSI_INACTIVE;
3717 }
3718 }
3719
3720 if (D_mouse_parse.state != CSI_INACTIVE)
3721 {
3722 /* suppress partial sequence at end */
3723 size = mark? mark - buf : 0;
3724 }
3725 }
3726
3727 if (size > 0)
3728 disp_processinput(display, buf, size);
3729 }
3730
3731 static void
disp_processinput(display,buf,size)3732 disp_processinput(display, buf, size)
3733 struct display* display;
3734 unsigned char* buf;
3735 int size;
3736 {
3737 #ifdef ENCODINGS
3738 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
3739 {
3740 int i, j, c, enc;
3741 char buf2[IOSIZE * 2 + 10];
3742 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
3743 for (i = j = 0; i < size; i++)
3744 {
3745 c = ((unsigned char *)buf)[i];
3746 c = DecodeChar(c, D_encoding, &D_decodestate);
3747 if (c == -2)
3748 i--; /* try char again */
3749 if (c < 0)
3750 continue;
3751 if (pastefont)
3752 {
3753 int font = 0;
3754 j += EncodeChar(buf2 + j, c, enc, &font);
3755 j += EncodeChar(buf2 + j, -1, enc, &font);
3756 }
3757 else
3758 j += EncodeChar(buf2 + j, c, enc, 0);
3759 if (j > (int)sizeof(buf2) - 10) /* just in case... */
3760 break;
3761 }
3762 (*D_processinput)(buf2, j);
3763 return;
3764 }
3765 #endif
3766 (*D_processinput)(buf, size);
3767 }
3768
3769 static void
disp_status_fn(ev,data)3770 disp_status_fn(ev, data)
3771 struct event *ev;
3772 char *data;
3773 {
3774 display = (struct display *)data;
3775 debug1("disp_status_fn for display %x\n", (int)display);
3776 if (D_status)
3777 RemoveStatus();
3778 }
3779
3780 static void
disp_hstatus_fn(ev,data)3781 disp_hstatus_fn(ev, data)
3782 struct event *ev;
3783 char *data;
3784 {
3785 display = (struct display *)data;
3786 if (D_status == STATUS_ON_HS)
3787 {
3788 SetTimeout(ev, 1);
3789 evenq(ev);
3790 return;
3791 }
3792 RefreshHStatus();
3793 }
3794
3795 static void
disp_blocked_fn(ev,data)3796 disp_blocked_fn(ev, data)
3797 struct event *ev;
3798 char *data;
3799 {
3800 struct win *p;
3801
3802 display = (struct display *)data;
3803 debug1("blocked timeout %s\n", D_usertty);
3804 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
3805 {
3806 debug("stopping output to display\n");
3807 D_blocked = 1;
3808 /* re-enable all windows */
3809 for (p = windows; p; p = p->w_next)
3810 if (p->w_readev.condneg == &D_obuflenmax)
3811 {
3812 debug1("freeing window #%d\n", p->w_number);
3813 p->w_readev.condpos = p->w_readev.condneg = 0;
3814 }
3815 }
3816 }
3817
3818 #ifdef MAPKEYS
3819 static void
disp_map_fn(ev,data)3820 disp_map_fn(ev, data)
3821 struct event *ev;
3822 char *data;
3823 {
3824 char *p;
3825 int l, i;
3826 unsigned char *q;
3827 display = (struct display *)data;
3828 debug("Flushing map sequence\n");
3829 if (!(l = D_seql))
3830 return;
3831 p = (char *)D_seqp - l;
3832 D_seqp = D_kmaps + 3;
3833 D_seql = 0;
3834 if ((q = D_seqh) != 0)
3835 {
3836 D_seqh = 0;
3837 i = q[0] << 8 | q[1];
3838 i &= ~KMAP_NOTIMEOUT;
3839 debug1("Mapping former hit #%d - ", i);
3840 debug2("%d(%s) - ", q[2], q + 3);
3841 if (StuffKey(i))
3842 ProcessInput2((char *)q + 3, q[2]);
3843 if (display == 0)
3844 return;
3845 l -= q[2];
3846 p += q[2];
3847 }
3848 else
3849 D_dontmap = 1;
3850 ProcessInput(p, l);
3851 }
3852 #endif
3853
3854 static void
disp_idle_fn(ev,data)3855 disp_idle_fn(ev, data)
3856 struct event *ev;
3857 char *data;
3858 {
3859 struct display *olddisplay;
3860 display = (struct display *)data;
3861 debug("idle timeout\n");
3862 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
3863 return;
3864 olddisplay = display;
3865 flayer = D_forecv->c_layer;
3866 fore = D_fore;
3867 DoAction(&idleaction, -1);
3868 if (idleaction.nr == RC_BLANKER)
3869 return;
3870 for (display = displays; display; display = display->d_next)
3871 if (olddisplay == display)
3872 break;
3873 if (display)
3874 ResetIdle();
3875 }
3876
3877 void
ResetIdle()3878 ResetIdle()
3879 {
3880 if (idletimo > 0)
3881 {
3882 SetTimeout(&D_idleev, idletimo);
3883 if (!D_idleev.queued)
3884 evenq(&D_idleev);
3885 }
3886 else
3887 evdeq(&D_idleev);
3888 }
3889
3890
3891 #ifdef BLANKER_PRG
3892
3893 static void
disp_blanker_fn(ev,data)3894 disp_blanker_fn(ev, data)
3895 struct event *ev;
3896 char *data;
3897 {
3898 char buf[IOSIZE], *b;
3899 int size;
3900
3901 display = (struct display *)data;
3902 size = read(D_blankerev.fd, buf, IOSIZE);
3903 if (size <= 0)
3904 {
3905 evdeq(&D_blankerev);
3906 close(D_blankerev.fd);
3907 D_blankerev.fd = -1;
3908 return;
3909 }
3910 for (b = buf; size; size--)
3911 AddChar(*b++);
3912 }
3913
3914 void
KillBlanker()3915 KillBlanker()
3916 {
3917 int oldtop = D_top, oldbot = D_bot;
3918 struct mchar oldrend;
3919
3920 if (D_blankerev.fd == -1)
3921 return;
3922 if (D_blocked == 4)
3923 D_blocked = 0;
3924 evdeq(&D_blankerev);
3925 close(D_blankerev.fd);
3926 D_blankerev.fd = -1;
3927 Kill(D_blankerpid, SIGHUP);
3928 D_top = D_bot = -1;
3929 oldrend = D_rend;
3930 if (D_ME)
3931 {
3932 AddCStr(D_ME);
3933 AddCStr(D_ME);
3934 }
3935 else
3936 {
3937 #ifdef COLOR
3938 if (D_hascolor)
3939 AddStr("\033[m\033[m"); /* why is D_ME not set? */
3940 #endif
3941 AddCStr(D_SE);
3942 AddCStr(D_UE);
3943 }
3944 AddCStr(D_VE);
3945 AddCStr(D_CE0);
3946 D_rend = mchar_null;
3947 D_atyp = 0;
3948 D_curvis = 0;
3949 D_x = D_y = -1;
3950 ChangeScrollRegion(oldtop, oldbot);
3951 SetRendition(&oldrend);
3952 ClearAll();
3953 }
3954
3955 void
RunBlanker(cmdv)3956 RunBlanker(cmdv)
3957 char **cmdv;
3958 {
3959 char *m;
3960 int pid;
3961 int slave = -1;
3962 int ptype = 0;
3963 char termname[MAXTERMLEN + 6];
3964 #ifndef TIOCSWINSZ
3965 char libuf[20], cobuf[20];
3966 #endif
3967 char **np;
3968
3969 strcpy(termname, "TERM=");
3970 strncpy(termname + 5, D_termname, MAXTERMLEN - 6);
3971 termname[sizeof(termname) - 1] = 0;
3972 KillBlanker();
3973 D_blankerpid = -1;
3974 if ((D_blankerev.fd = OpenDevice(cmdv, 0, &ptype, &m)) == -1)
3975 {
3976 Msg(0, "OpenDevice failed");
3977 return;
3978 }
3979 #ifdef O_NOCTTY
3980 if (pty_preopen)
3981 {
3982 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
3983 {
3984 Msg(errno, "%s", m);
3985 close(D_blankerev.fd);
3986 D_blankerev.fd = -1;
3987 return;
3988 }
3989 }
3990 #endif
3991 switch (pid = (int)fork())
3992 {
3993 case -1:
3994 Msg(errno, "fork");
3995 close(D_blankerev.fd);
3996 D_blankerev.fd = -1;
3997 close(slave);
3998 return;
3999 case 0:
4000 displays = 0;
4001 ServerSocket = -1;
4002 #ifdef SIGPIPE
4003 signal(SIGPIPE, SIG_DFL);
4004 #endif
4005 if (setgid(real_gid) || setuid(real_uid))
4006 Panic(errno, "setuid/setgid");
4007 eff_uid = real_uid;
4008 eff_gid = real_gid;
4009 brktty(D_userfd);
4010 freetty();
4011 #ifdef DEBUG
4012 if (dfp && dfp != stderr)
4013 fclose(dfp);
4014 #endif
4015 if (slave != -1)
4016 {
4017 close(0);
4018 dup(slave);
4019 close(slave);
4020 closeallfiles(D_blankerev.fd);
4021 slave = dup(0);
4022 }
4023 else
4024 closeallfiles(D_blankerev.fd);
4025 #ifdef DEBUG
4026 if (dfp)
4027 {
4028 char buf[256];
4029
4030 sprintf(buf, "%s/screen.blanker", DEBUGDIR);
4031 if ((dfp = fopen(buf, "a")) == 0)
4032 dfp = stderr;
4033 else
4034 (void) chmod(buf, 0666);
4035 }
4036 debug1("=== RunBlanker: pid %d\n", (int)getpid());
4037 #endif
4038 close(0);
4039 close(1);
4040 close(2);
4041 if (open(m, O_RDWR))
4042 Panic(errno, "Cannot open %s", m);
4043 dup(0);
4044 dup(0);
4045 close(D_blankerev.fd);
4046 if (slave != -1)
4047 close(slave);
4048 InitPTY(0);
4049 fgtty(0);
4050 SetTTY(0, &D_OldMode);
4051 np = NewEnv + 3;
4052 *np++ = NewEnv[0];
4053 *np++ = termname;
4054 #ifdef TIOCSWINSZ
4055 glwz.ws_col = D_width;
4056 glwz.ws_row = D_height;
4057 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4058 #else
4059 /* Always turn off nonblocking mode */
4060 (void)fcntl(0, F_SETFL, 0);
4061 sprintf(libuf, "LINES=%d", D_height);
4062 sprintf(cobuf, "COLUMNS=%d", D_width);
4063 *np++ = libuf;
4064 *np++ = cobuf;
4065 #endif
4066 debug1("calling execvpe %s\n", *cmdv);
4067 execvpe(*cmdv, cmdv, NewEnv + 3);
4068 debug1("exec error: %d\n", errno);
4069 Panic(errno, "Cannot exec '%s'", *cmdv);
4070 default:
4071 break;
4072 }
4073 D_blankerpid = pid;
4074 evenq(&D_blankerev);
4075 D_blocked = 4;
4076 ClearAll();
4077 close(slave);
4078 }
4079
4080 #endif /* BLANKER_PRG */
4081
4082
4083