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