Bring back --with-sys-screenrc configure flag.
[screen-lua.git] / src / display.c
blob5fa11cb394a0cbcf7797c930626f983d1f88dfc9
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
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.
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.
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 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #ifndef sun
33 # include <sys/ioctl.h>
34 #endif
36 #include "config.h"
37 #include "screen.h"
38 #include "extern.h"
39 #include "braille.h"
40 #include "canvas.h"
42 static int CountChars __P((int));
43 static int DoAddChar __P((int));
44 static int BlankResize __P((int, int));
45 static int CallRewrite __P((int, int, int, int));
46 static void disp_readev_fn __P((struct event *, char *));
47 static void disp_writeev_fn __P((struct event *, char *));
48 #ifdef linux
49 static void disp_writeev_eagain __P((struct event *, char *));
50 #endif
51 static void disp_status_fn __P((struct event *, char *));
52 static void disp_hstatus_fn __P((struct event *, char *));
53 static void disp_blocked_fn __P((struct event *, char *));
54 static void cv_winid_fn __P((struct event *, char *));
55 #ifdef MAPKEYS
56 static void disp_map_fn __P((struct event *, char *));
57 #endif
58 static void disp_idle_fn __P((struct event *, char *));
59 #ifdef BLANKER_PRG
60 static void disp_blanker_fn __P((struct event *, char *));
61 #endif
62 static void WriteLP __P((int, int));
63 static void INSERTCHAR __P((int));
64 static void RAW_PUTCHAR __P((int));
65 #ifdef COLOR
66 static void SetBackColor __P((int));
67 #endif
68 static void RemoveStatusMinWait __P((void));
71 extern struct layer *flayer;
72 extern struct win *windows, *fore;
73 extern struct LayFuncs WinLf;
75 extern int use_hardstatus;
76 extern int MsgWait, MsgMinWait;
77 extern int Z0width, Z1width;
78 extern unsigned char *blank, *null;
79 extern struct mline mline_blank, mline_null, mline_old;
80 extern struct mchar mchar_null, mchar_blank, mchar_so;
81 extern struct NewWindow nwin_default;
82 extern struct action idleaction;
84 /* XXX shouldn't be here */
85 extern char *hstatusstring;
86 extern char *captionstring;
88 extern int pastefont;
89 extern int idletimo;
91 #ifdef BLANKER_PRG
92 extern int pty_preopen;
93 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
94 extern struct winsize glwz;
95 #endif
96 extern char **NewEnv;
97 extern int real_uid, real_gid;
98 #endif
101 * tputs needs this to calculate the padding
103 #ifndef NEED_OSPEED
104 extern
105 #endif /* NEED_OSPEED */
106 short ospeed;
109 struct display *display, *displays;
110 #ifdef COLOR
111 int attr2color[8][4];
112 int nattr2color;
113 #endif
115 #ifndef MULTI
116 struct display TheDisplay;
117 #endif
120 * The default values
122 int defobuflimit = OBUF_MAX;
123 int defnonblock = -1;
124 int defmousetrack = 0;
125 #ifdef AUTO_NUKE
126 int defautonuke = 0;
127 #endif
128 int captionalways;
129 int hardstatusemu = HSTATUS_IGNORE;
131 int focusminwidth, focusminheight;
134 * Default layer management
137 void
138 DefProcess(bufp, lenp)
139 char **bufp;
140 int *lenp;
142 *bufp += *lenp;
143 *lenp = 0;
146 void
147 DefRedisplayLine(y, xs, xe, isblank)
148 int y, xs, xe, isblank;
150 if (isblank == 0 && y >= 0)
151 DefClearLine(y, xs, xe, 0);
154 void
155 DefClearLine(y, xs, xe, bce)
156 int y, xs, xe, bce;
158 LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
161 /*ARGSUSED*/
163 DefRewrite(y, xs, xe, rend, doit)
164 int y, xs, xe, doit;
165 struct mchar *rend;
167 return EXPENSIVE;
170 /*ARGSUSED*/
172 DefResize(wi, he)
173 int wi, he;
175 return -1;
178 void
179 DefRestore()
181 LAY_DISPLAYS(flayer, InsertMode(0));
182 /* ChangeScrollRegion(0, D_height - 1); */
183 LKeypadMode(flayer, 0);
184 LCursorkeysMode(flayer, 0);
185 LCursorVisibility(flayer, 0);
186 LMouseMode(flayer, 0);
187 LSetRendition(flayer, &mchar_null);
188 LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
192 * Blank layer management
195 struct LayFuncs BlankLf =
197 DefProcess,
199 DefRedisplayLine,
200 DefClearLine,
201 DefRewrite,
202 BlankResize,
203 DefRestore,
207 /*ARGSUSED*/
208 static int
209 BlankResize(wi, he)
210 int wi, he;
212 flayer->l_width = wi;
213 flayer->l_height = he;
214 return 0;
219 * Generate new display, start with a blank layer.
220 * The termcap arrays are not initialised here.
221 * The new display is placed in the displays list.
224 struct display *
225 MakeDisplay(uname, utty, term, fd, pid, Mode)
226 char *uname, *utty, *term;
227 int fd, pid;
228 struct mode *Mode;
230 struct acluser **u;
231 struct baud_values *b;
233 if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
234 return 0; /* could not find or add user */
236 #ifdef MULTI
237 if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
238 return 0;
239 #else
240 if (displays)
241 return 0;
242 bzero((char *)&TheDisplay, sizeof(TheDisplay));
243 display = &TheDisplay;
244 #endif
245 display->d_next = displays;
246 displays = display;
247 D_flow = 1;
248 D_nonblock = defnonblock;
249 D_userfd = fd;
250 D_readev.fd = D_writeev.fd = fd;
251 D_readev.type = EV_READ;
252 D_writeev.type = EV_WRITE;
253 D_readev.data = D_writeev.data = (char *)display;
254 D_readev.handler = disp_readev_fn;
255 D_writeev.handler = disp_writeev_fn;
256 evenq(&D_readev);
257 D_writeev.condpos = &D_obuflen;
258 D_writeev.condneg = &D_obuffree;
259 evenq(&D_writeev);
260 D_statusev.type = EV_TIMEOUT;
261 D_statusev.data = (char *)display;
262 D_statusev.handler = disp_status_fn;
263 D_hstatusev.type = EV_TIMEOUT;
264 D_hstatusev.data = (char *)display;
265 D_hstatusev.handler = disp_hstatus_fn;
266 D_blockedev.type = EV_TIMEOUT;
267 D_blockedev.data = (char *)display;
268 D_blockedev.handler = disp_blocked_fn;
269 D_blockedev.condpos = &D_obuffree;
270 D_blockedev.condneg = &D_obuflenmax;
271 D_hstatusev.handler = disp_hstatus_fn;
272 #ifdef MAPKEYS
273 D_mapev.type = EV_TIMEOUT;
274 D_mapev.data = (char *)display;
275 D_mapev.handler = disp_map_fn;
276 #endif
277 D_idleev.type = EV_TIMEOUT;
278 D_idleev.data = (char *)display;
279 D_idleev.handler = disp_idle_fn;
280 #ifdef BLANKER_PRG
281 D_blankerev.type = EV_READ;
282 D_blankerev.data = (char *)display;
283 D_blankerev.handler = disp_blanker_fn;
284 D_blankerev.fd = -1;
285 #endif
286 D_OldMode = *Mode;
287 D_status_obuffree = -1;
288 Resize_obuf(); /* Allocate memory for buffer */
289 D_obufmax = defobuflimit;
290 D_obuflenmax = D_obuflen - D_obufmax;
291 #ifdef AUTO_NUKE
292 D_auto_nuke = defautonuke;
293 #endif
294 D_obufp = D_obuf;
295 D_printfd = -1;
296 D_userpid = pid;
298 #ifdef POSIX
299 if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
300 D_dospeed = b->idx;
301 #else
302 # ifdef TERMIO
303 if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
304 D_dospeed = b->idx;
305 # else
306 D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
307 # endif
308 #endif
309 debug1("New displays ospeed = %d\n", D_dospeed);
311 strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
312 D_usertty[sizeof(D_usertty) - 1] = 0;
313 strncpy(D_termname, term, sizeof(D_termname) - 1);
314 D_termname[sizeof(D_termname) - 1] = 0;
315 D_user = *u;
316 D_processinput = ProcessInput;
317 D_mousetrack = defmousetrack;
318 return display;
322 void
323 FreeDisplay()
325 struct win *p;
326 #ifdef MULTI
327 struct display *d, **dp;
328 #endif
330 #ifdef FONT
331 FreeTransTable();
332 #endif
333 #ifdef BLANKER_PRG
334 KillBlanker();
335 #endif
336 if (D_userfd >= 0)
338 Flush(3);
339 if (!display)
340 return;
341 SetTTY(D_userfd, &D_OldMode);
342 fcntl(D_userfd, F_SETFL, 0);
344 freetty();
345 if (D_tentry)
346 free(D_tentry);
347 D_tentry = 0;
348 if (D_processinputdata)
349 free(D_processinputdata);
350 D_processinputdata = 0;
351 D_tcinited = 0;
352 evdeq(&D_hstatusev);
353 evdeq(&D_statusev);
354 evdeq(&D_readev);
355 evdeq(&D_writeev);
356 evdeq(&D_blockedev);
357 #ifdef MAPKEYS
358 evdeq(&D_mapev);
359 if (D_kmaps)
361 free(D_kmaps);
362 D_kmaps = 0;
363 D_aseqs = 0;
364 D_nseqs = 0;
365 D_seqp = 0;
366 D_seql = 0;
367 D_seqh = 0;
369 #endif
370 evdeq(&D_idleev);
371 #ifdef BLANKER_PRG
372 evdeq(&D_blankerev);
373 #endif
374 #ifdef HAVE_BRAILLE
375 if (bd.bd_dpy == display)
377 bd.bd_start_braille = 0;
378 StartBraille();
380 #endif
382 #ifdef MULTI
383 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
384 if (d == display)
385 break;
386 ASSERT(d);
387 if (D_status_lastmsg)
388 free(D_status_lastmsg);
389 if (D_obuf)
390 free(D_obuf);
391 *dp = display->d_next;
392 #else /* MULTI */
393 ASSERT(display == displays);
394 ASSERT(display == &TheDisplay);
395 displays = 0;
396 #endif /* MULTI */
398 while (D_canvas.c_slperp)
399 FreeCanvas(D_canvas.c_slperp);
400 D_cvlist = 0;
402 for (p = windows; p; p = p->w_next)
404 if (p->w_pdisplay == display)
405 p->w_pdisplay = 0;
406 if (p->w_lastdisp == display)
407 p->w_lastdisp = 0;
408 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
409 p->w_readev.condpos = p->w_readev.condneg = 0;
411 #ifdef ZMODEM
412 for (p = windows; p; p = p->w_next)
413 if (p->w_zdisplay == display)
414 zmodem_abort(p, 0);
415 #endif
416 if (D_mousetrack)
418 D_mousetrack = 0;
419 MouseMode(0);
421 #ifdef MULTI
422 free((char *)display);
423 #endif
424 display = 0;
428 * if the adaptflag is on, we keep the size of this display, else
429 * we may try to restore our old window sizes.
431 void
432 InitTerm(adapt)
433 int adapt;
435 ASSERT(display);
436 ASSERT(D_tcinited);
437 D_top = D_bot = -1;
438 AddCStr(D_IS);
439 AddCStr(D_TI);
440 /* Check for toggle */
441 if (D_IM && strcmp(D_IM, D_EI))
442 AddCStr(D_EI);
443 D_insert = 0;
444 #ifdef MAPKEYS
445 AddCStr(D_KS);
446 AddCStr(D_CCS);
447 #else
448 /* Check for toggle */
449 if (D_KS && strcmp(D_KS, D_KE))
450 AddCStr(D_KE);
451 if (D_CCS && strcmp(D_CCS, D_CCE))
452 AddCStr(D_CCE);
453 #endif
454 D_keypad = 0;
455 D_cursorkeys = 0;
456 AddCStr(D_ME);
457 AddCStr(D_EA);
458 AddCStr(D_CE0);
459 D_rend = mchar_null;
460 D_atyp = 0;
461 if (adapt == 0)
462 ResizeDisplay(D_defwidth, D_defheight);
463 ChangeScrollRegion(0, D_height - 1);
464 D_x = D_y = 0;
465 Flush(3);
466 ClearAll();
467 debug1("we %swant to adapt all our windows to the display\n",
468 (adapt) ? "" : "don't ");
469 /* In case the size was changed by a init sequence */
470 CheckScreenSize((adapt) ? 2 : 0);
473 void
474 FinitTerm()
476 ASSERT(display);
477 #ifdef BLANKER_PRG
478 KillBlanker();
479 #endif
480 if (D_tcinited)
482 ResizeDisplay(D_defwidth, D_defheight);
483 InsertMode(0);
484 ChangeScrollRegion(0, D_height - 1);
485 KeypadMode(0);
486 CursorkeysMode(0);
487 CursorVisibility(0);
488 if (D_mousetrack)
489 D_mousetrack = 0;
490 MouseMode(0);
491 SetRendition(&mchar_null);
492 SetFlow(FLOW_NOW);
493 #ifdef MAPKEYS
494 AddCStr(D_KE);
495 AddCStr(D_CCE);
496 #endif
497 if (D_hstatus)
498 ShowHStatus((char *)0);
499 #ifdef RXVT_OSC
500 ClearAllXtermOSC();
501 #endif
502 D_x = D_y = -1;
503 GotoPos(0, D_height - 1);
504 AddChar('\r');
505 AddChar('\n');
506 AddCStr(D_TE);
508 Flush(3);
512 static void
513 INSERTCHAR(c)
514 int c;
516 ASSERT(display);
517 if (!D_insert && D_x < D_width - 1)
519 if (D_IC || D_CIC)
521 if (D_IC)
522 AddCStr(D_IC);
523 else
524 AddCStr2(D_CIC, 1);
525 RAW_PUTCHAR(c);
526 return;
528 InsertMode(1);
529 if (!D_insert)
531 RefreshLine(D_y, D_x, D_width-1, 0);
532 return;
535 RAW_PUTCHAR(c);
538 void
539 PUTCHAR(c)
540 int c;
542 ASSERT(display);
543 if (D_insert && D_x < D_width - 1)
544 InsertMode(0);
545 RAW_PUTCHAR(c);
548 void
549 PUTCHARLP(c)
550 int c;
552 if (D_x < D_width - 1)
554 if (D_insert)
555 InsertMode(0);
556 RAW_PUTCHAR(c);
557 return;
559 if (D_CLP || D_y != D_bot)
561 int y = D_y;
562 RAW_PUTCHAR(c);
563 if (D_AM && !D_CLP)
564 GotoPos(D_width - 1, y);
565 return;
567 debug("PUTCHARLP: lp_missing!\n");
568 D_lp_missing = 1;
569 D_rend.image = c;
570 D_lpchar = D_rend;
571 #ifdef DW_CHARS
572 /* XXX -> PutChar ? */
573 if (D_mbcs)
575 D_lpchar.mbcs = c;
576 D_lpchar.image = D_mbcs;
577 D_mbcs = 0;
578 D_x--;
580 #endif
584 * RAW_PUTCHAR() is for all text that will be displayed.
585 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
588 STATIC void
589 RAW_PUTCHAR(c)
590 int c;
592 ASSERT(display);
594 #ifdef FONT
595 # ifdef UTF8
596 if (D_encoding == UTF8)
598 c = (c & 255) | (unsigned char)D_rend.font << 8;
599 # ifdef DW_CHARS
600 if (D_mbcs)
602 c = D_mbcs;
603 if (D_x == D_width)
604 D_x += D_AM ? 1 : -1;
605 D_mbcs = 0;
607 else if (utf8_isdouble(c))
609 D_mbcs = c;
610 D_x++;
611 return;
613 # endif
614 if (c < 32)
616 AddCStr2(D_CS0, '0');
617 AddChar(c + 0x5f);
618 AddCStr(D_CE0);
619 goto addedutf8;
621 if (c < 0x80)
623 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
624 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
625 else
626 AddChar(c);
628 else
629 AddUtf8(c);
630 goto addedutf8;
632 # endif
633 # ifdef DW_CHARS
634 if (is_dw_font(D_rend.font))
636 int t = c;
637 if (D_mbcs == 0)
639 D_mbcs = c;
640 D_x++;
641 return;
643 D_x--;
644 if (D_x == D_width - 1)
645 D_x += D_AM ? 1 : -1;
646 c = D_mbcs;
647 D_mbcs = t;
649 # endif
650 # if defined(ENCODINGS) && defined(DW_CHARS)
651 if (D_encoding)
652 c = PrepareEncodedChar(c);
653 # endif
654 # ifdef DW_CHARS
655 kanjiloop:
656 # endif
657 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
658 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
659 else
660 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
661 #else /* FONT */
662 AddChar(c);
663 #endif /* FONT */
665 #ifdef UTF8
666 addedutf8:
667 #endif
668 if (++D_x >= D_width)
670 if (D_AM == 0)
671 D_x = D_width - 1;
672 else if (!D_CLP || D_x > D_width)
674 D_x -= D_width;
675 if (D_y < D_height-1 && D_y != D_bot)
676 D_y++;
679 #ifdef DW_CHARS
680 if (D_mbcs)
682 c = D_mbcs;
683 D_mbcs = 0;
684 goto kanjiloop;
686 #endif
689 static int
690 DoAddChar(c)
691 int c;
693 /* this is for ESC-sequences only (AddChar is a macro) */
694 AddChar(c);
695 return c;
698 void
699 AddCStr(s)
700 char *s;
702 if (display && s && *s)
704 ospeed = D_dospeed;
705 tputs(s, 1, DoAddChar);
709 void
710 AddCStr2(s, c)
711 char *s;
712 int c;
714 if (display && s && *s)
716 ospeed = D_dospeed;
717 tputs(tgoto(s, 0, c), 1, DoAddChar);
722 /* Insert mode is a toggle on some terminals, so we need this hack:
724 void
725 InsertMode(on)
726 int on;
728 if (display && on != D_insert && D_IM)
730 D_insert = on;
731 if (on)
732 AddCStr(D_IM);
733 else
734 AddCStr(D_EI);
738 /* ...and maybe keypad application mode is a toggle, too:
740 void
741 KeypadMode(on)
742 int on;
744 #ifdef MAPKEYS
745 if (display)
746 D_keypad = on;
747 #else
748 if (display && D_keypad != on && D_KS)
750 D_keypad = on;
751 if (on)
752 AddCStr(D_KS);
753 else
754 AddCStr(D_KE);
756 #endif
759 void
760 CursorkeysMode(on)
761 int on;
763 #ifdef MAPKEYS
764 if (display)
765 D_cursorkeys = on;
766 #else
767 if (display && D_cursorkeys != on && D_CCS)
769 D_cursorkeys = on;
770 if (on)
771 AddCStr(D_CCS);
772 else
773 AddCStr(D_CCE);
775 #endif
778 void
779 ReverseVideo(on)
780 int on;
782 if (display && D_revvid != on && D_CVR)
784 D_revvid = on;
785 if (D_revvid)
786 AddCStr(D_CVR);
787 else
788 AddCStr(D_CVN);
792 void
793 CursorVisibility(v)
794 int v;
796 if (display && D_curvis != v)
798 if (D_curvis)
799 AddCStr(D_VE); /* do this always, just to be safe */
800 D_curvis = 0;
801 if (v == -1 && D_VI)
802 AddCStr(D_VI);
803 else if (v == 1 && D_VS)
804 AddCStr(D_VS);
805 else
806 return;
807 D_curvis = v;
811 void
812 MouseMode(mode)
813 int mode;
815 if (!display)
816 return;
818 if (mode < D_mousetrack)
819 mode = D_mousetrack;
821 if (D_mouse != mode)
823 char mousebuf[20];
824 if (!D_CXT)
825 return;
826 if (D_mouse)
828 sprintf(mousebuf, "\033[?%dl", D_mouse);
829 AddStr(mousebuf);
831 if (mode)
833 sprintf(mousebuf, "\033[?%dh", mode);
834 AddStr(mousebuf);
836 D_mouse = mode;
840 static int StrCost;
842 /* ARGSUSED */
843 static int
844 CountChars(c)
845 int c;
847 StrCost++;
848 return c;
852 CalcCost(s)
853 register char *s;
855 ASSERT(display);
856 if (s)
858 StrCost = 0;
859 ospeed = D_dospeed;
860 tputs(s, 1, CountChars);
861 return StrCost;
863 else
864 return EXPENSIVE;
867 static int
868 CallRewrite(y, xs, xe, doit)
869 int y, xs, xe, doit;
871 struct canvas *cv, *cvlist, *cvlnext;
872 struct viewport *vp;
873 struct layer *oldflayer;
874 int cost;
876 debug3("CallRewrite %d %d %d\n", y, xs, xe);
877 ASSERT(display);
878 ASSERT(xe >= xs);
880 vp = 0;
881 for (cv = D_cvlist; cv; cv = cv->c_next)
883 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
884 continue;
885 for (vp = cv->c_vplist; vp; vp = vp->v_next)
886 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
887 break;
888 if (vp)
889 break;
891 if (doit)
893 oldflayer = flayer;
894 flayer = cv->c_layer;
895 cvlist = flayer->l_cvlist;
896 cvlnext = cv->c_lnext;
897 flayer->l_cvlist = cv;
898 cv->c_lnext = 0;
899 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
900 flayer->l_cvlist = cvlist;
901 cv->c_lnext = cvlnext;
902 flayer = oldflayer;
903 return 0;
905 if (cv == 0 || cv->c_layer == 0)
906 return EXPENSIVE; /* not found or nothing on it */
907 if (xs < vp->v_xs || xe > vp->v_xe)
908 return EXPENSIVE; /* crosses viewport boundaries */
909 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
910 return EXPENSIVE; /* line not on layer */
911 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
912 return EXPENSIVE; /* line not on layer */
913 #ifdef UTF8
914 if (D_encoding == UTF8)
915 D_rend.font = 0;
916 #endif
917 oldflayer = flayer;
918 flayer = cv->c_layer;
919 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
920 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
921 flayer = oldflayer;
922 if (D_insert)
923 cost += D_EIcost + D_IMcost;
924 return cost;
928 void
929 GotoPos(x2, y2)
930 int x2, y2;
932 register int dy, dx, x1, y1;
933 register int costx, costy;
934 register int m;
935 register char *s;
936 int CMcost;
937 enum move_t xm = M_NONE, ym = M_NONE;
939 if (!display)
940 return;
942 x1 = D_x;
943 y1 = D_y;
945 if (x1 == D_width)
947 if (D_CLP && D_AM)
948 x1 = -1; /* don't know how the terminal treats this */
949 else
950 x1--;
952 if (x2 == D_width)
953 x2--;
954 dx = x2 - x1;
955 dy = y2 - y1;
956 if (dy == 0 && dx == 0)
957 return;
958 debug2("GotoPos (%d,%d)", x1, y1);
959 debug2(" -> (%d,%d)\n", x2, y2);
960 if (!D_MS) /* Safe to move ? */
961 SetRendition(&mchar_null);
962 if (y1 < 0 /* don't know the y position */
963 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
964 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
966 DoCM:
967 if (D_HO && !x2 && !y2)
968 AddCStr(D_HO);
969 else
970 AddCStr(tgoto(D_CM, x2, y2));
971 D_x = x2;
972 D_y = y2;
973 return;
976 /* some scrollregion implementations don't allow movements
977 * away from the region. sigh.
979 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
980 goto DoCM;
982 /* Calculate CMcost */
983 if (D_HO && !x2 && !y2)
984 s = D_HO;
985 else
986 s = tgoto(D_CM, x2, y2);
987 CMcost = CalcCost(s);
989 /* Calculate the cost to move the cursor to the right x position */
990 costx = EXPENSIVE;
991 if (x1 >= 0) /* relativ x positioning only if we know where we are */
993 if (dx > 0)
995 if (D_CRI && (dx > 1 || !D_ND))
997 costx = CalcCost(tgoto(D_CRI, 0, dx));
998 xm = M_CRI;
1000 if ((m = D_NDcost * dx) < costx)
1002 costx = m;
1003 xm = M_RI;
1005 /* Speedup: dx <= LayRewrite() */
1006 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1008 costx = m;
1009 xm = M_RW;
1012 else if (dx < 0)
1014 if (D_CLE && (dx < -1 || !D_BC))
1016 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1017 xm = M_CLE;
1019 if ((m = -dx * D_LEcost) < costx)
1021 costx = m;
1022 xm = M_LE;
1025 else
1026 costx = 0;
1028 /* Speedup: LayRewrite() >= x2 */
1029 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1031 costx = m;
1032 xm = M_CR;
1035 /* Check if it is already cheaper to do CM */
1036 if (costx >= CMcost)
1037 goto DoCM;
1039 /* Calculate the cost to move the cursor to the right y position */
1040 costy = EXPENSIVE;
1041 if (dy > 0)
1043 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1045 costy = CalcCost(tgoto(D_CDO, 0, dy));
1046 ym = M_CDO;
1048 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1050 costy = m;
1051 ym = M_DO;
1054 else if (dy < 0)
1056 if (D_CUP && (dy < -1 || !D_UP))
1058 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1059 ym = M_CUP;
1061 if ((m = -dy * D_UPcost) < costy)
1063 costy = m;
1064 ym = M_UP;
1067 else
1068 costy = 0;
1070 /* Finally check if it is cheaper to do CM */
1071 if (costx + costy >= CMcost)
1072 goto DoCM;
1074 switch (xm)
1076 case M_LE:
1077 while (dx++ < 0)
1078 AddCStr(D_BC);
1079 break;
1080 case M_CLE:
1081 AddCStr2(D_CLE, -dx);
1082 break;
1083 case M_RI:
1084 while (dx-- > 0)
1085 AddCStr(D_ND);
1086 break;
1087 case M_CRI:
1088 AddCStr2(D_CRI, dx);
1089 break;
1090 case M_CR:
1091 AddCStr(D_CR);
1092 D_x = 0;
1093 x1 = 0;
1094 /* FALLTHROUGH */
1095 case M_RW:
1096 if (x1 < x2)
1097 (void) CallRewrite(y1, x1, x2 - 1, 1);
1098 break;
1099 default:
1100 break;
1103 switch (ym)
1105 case M_UP:
1106 while (dy++ < 0)
1107 AddCStr(D_UP);
1108 break;
1109 case M_CUP:
1110 AddCStr2(D_CUP, -dy);
1111 break;
1112 case M_DO:
1113 s = (x2 == 0) ? D_NL : D_DO;
1114 while (dy-- > 0)
1115 AddCStr(s);
1116 break;
1117 case M_CDO:
1118 AddCStr2(D_CDO, dy);
1119 break;
1120 default:
1121 break;
1123 D_x = x2;
1124 D_y = y2;
1127 void
1128 ClearAll()
1130 ASSERT(display);
1131 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1134 void
1135 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1136 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1138 int y, xxe;
1139 struct canvas *cv;
1140 struct viewport *vp;
1142 debug2("Clear %d,%d", x1, y1);
1143 debug2(" %d-%d", xs, xe);
1144 debug2(" %d,%d", x2, y2);
1145 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1146 ASSERT(display);
1147 if (x1 == D_width)
1148 x1--;
1149 if (x2 == D_width)
1150 x2--;
1151 if (xs == -1)
1152 xs = x1;
1153 if (xe == -1)
1154 xe = x2;
1155 if (D_UT) /* Safe to erase ? */
1156 SetRendition(&mchar_null);
1157 #ifdef COLOR
1158 if (D_BE)
1159 SetBackColor(bce);
1160 #endif
1161 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1163 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1164 D_lp_missing = 0;
1166 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1168 #ifdef AUTO_NUKE
1169 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1170 NukePending();
1171 #endif
1172 if (x1 == 0 && y1 == 0 && D_CL)
1174 AddCStr(D_CL);
1175 D_y = D_x = 0;
1176 return;
1179 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1180 * is also appropriate.
1182 if (D_CD && (y1 < y2 || !D_CE))
1184 GotoPos(x1, y1);
1185 AddCStr(D_CD);
1186 return;
1189 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1191 GotoPos(x1, y1);
1192 AddCStr(D_CCD);
1193 return;
1195 xxe = xe;
1196 for (y = y1; y <= y2; y++, x1 = xs)
1198 if (y == y2)
1199 xxe = x2;
1200 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1202 GotoPos(xxe, y);
1203 AddCStr(D_CB);
1204 continue;
1206 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1208 GotoPos(x1, y);
1209 AddCStr(D_CE);
1210 continue;
1212 if (uselayfn)
1214 vp = 0;
1215 for (cv = D_cvlist; cv; cv = cv->c_next)
1217 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1218 continue;
1219 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1220 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1221 break;
1222 if (vp)
1223 break;
1225 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1226 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1227 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1229 struct layer *oldflayer = flayer;
1230 struct canvas *cvlist, *cvlnext;
1231 flayer = cv->c_layer;
1232 cvlist = flayer->l_cvlist;
1233 cvlnext = cv->c_lnext;
1234 flayer->l_cvlist = cv;
1235 cv->c_lnext = 0;
1236 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1237 flayer->l_cvlist = cvlist;
1238 cv->c_lnext = cvlnext;
1239 flayer = oldflayer;
1240 continue;
1243 ClearLine((struct mline *)0, y, x1, xxe, bce);
1249 * if cur_only > 0, we only redisplay current line, as a full refresh is
1250 * too expensive over a low baud line.
1252 void
1253 Redisplay(cur_only)
1254 int cur_only;
1256 ASSERT(display);
1258 /* XXX do em all? */
1259 InsertMode(0);
1260 ChangeScrollRegion(0, D_height - 1);
1261 KeypadMode(0);
1262 CursorkeysMode(0);
1263 CursorVisibility(0);
1264 MouseMode(0);
1265 SetRendition(&mchar_null);
1266 SetFlow(FLOW_NOW);
1268 ClearAll();
1269 #ifdef RXVT_OSC
1270 RefreshXtermOSC();
1271 #endif
1272 if (cur_only > 0 && D_fore)
1273 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1274 else
1275 RefreshAll(1);
1276 RefreshHStatus();
1277 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1280 void
1281 RedisplayDisplays(cur_only)
1282 int cur_only;
1284 struct display *olddisplay = display;
1285 for (display = displays; display; display = display->d_next)
1286 Redisplay(cur_only);
1287 display = olddisplay;
1291 /* XXX: use oml! */
1292 void
1293 ScrollH(y, xs, xe, n, bce, oml)
1294 int y, xs, xe, n, bce;
1295 struct mline *oml;
1297 int i;
1299 if (n == 0)
1300 return;
1301 if (xe != D_width - 1)
1303 RefreshLine(y, xs, xe, 0);
1304 /* UpdateLine(oml, y, xs, xe); */
1305 return;
1307 GotoPos(xs, y);
1308 if (D_UT)
1309 SetRendition(&mchar_null);
1310 #ifdef COLOR
1311 if (D_BE)
1312 SetBackColor(bce);
1313 #endif
1314 if (n > 0)
1316 if (n >= xe - xs + 1)
1317 n = xe - xs + 1;
1318 if (D_CDC && !(n == 1 && D_DC))
1319 AddCStr2(D_CDC, n);
1320 else if (D_DC)
1322 for (i = n; i--; )
1323 AddCStr(D_DC);
1325 else
1327 RefreshLine(y, xs, xe, 0);
1328 /* UpdateLine(oml, y, xs, xe); */
1329 return;
1332 else
1334 if (-n >= xe - xs + 1)
1335 n = -(xe - xs + 1);
1336 if (!D_insert)
1338 if (D_CIC && !(n == -1 && D_IC))
1339 AddCStr2(D_CIC, -n);
1340 else if (D_IC)
1342 for (i = -n; i--; )
1343 AddCStr(D_IC);
1345 else if (D_IM)
1347 InsertMode(1);
1348 SetRendition(&mchar_null);
1349 #ifdef COLOR
1350 SetBackColor(bce);
1351 #endif
1352 for (i = -n; i--; )
1353 INSERTCHAR(' ');
1354 bce = 0; /* all done */
1356 else
1358 /* UpdateLine(oml, y, xs, xe); */
1359 RefreshLine(y, xs, xe, 0);
1360 return;
1363 else
1365 SetRendition(&mchar_null);
1366 #ifdef COLOR
1367 SetBackColor(bce);
1368 #endif
1369 for (i = -n; i--; )
1370 INSERTCHAR(' ');
1371 bce = 0; /* all done */
1374 if (bce && !D_BE)
1376 if (n > 0)
1377 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
1378 else
1379 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
1381 if (D_lp_missing && y == D_bot)
1383 if (n > 0)
1384 WriteLP(D_width - 1 - n, y);
1385 D_lp_missing = 0;
1389 void
1390 ScrollV(xs, ys, xe, ye, n, bce)
1391 int xs, ys, xe, ye, n, bce;
1393 int i;
1394 int up;
1395 int oldtop, oldbot;
1396 int alok, dlok, aldlfaster;
1397 int missy = 0;
1399 ASSERT(display);
1400 if (n == 0)
1401 return;
1402 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
1404 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
1405 return;
1407 if (xs > D_vpxmin || xe < D_vpxmax)
1409 RefreshArea(xs, ys, xe, ye, 0);
1410 return;
1413 if (D_lp_missing)
1415 if (D_bot > ye || D_bot < ys)
1416 missy = D_bot;
1417 else
1419 missy = D_bot - n;
1420 if (missy > ye || missy < ys)
1421 D_lp_missing = 0;
1425 up = 1;
1426 if (n < 0)
1428 up = 0;
1429 n = -n;
1431 if (n >= ye - ys + 1)
1432 n = ye - ys + 1;
1434 oldtop = D_top;
1435 oldbot = D_bot;
1436 if (ys < D_top || D_bot != ye)
1437 ChangeScrollRegion(ys, ye);
1438 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
1439 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
1440 if (D_top != ys && !(alok && dlok))
1441 ChangeScrollRegion(ys, ye);
1443 if (D_lp_missing &&
1444 (oldbot != D_bot ||
1445 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
1447 WriteLP(D_width - 1, oldbot);
1448 if (oldbot == D_bot) /* have scrolled */
1450 if (--n == 0)
1452 /* XXX
1453 ChangeScrollRegion(oldtop, oldbot);
1455 if (bce && !D_BE)
1456 ClearLine((struct mline *)0, ye, xs, xe, bce);
1457 return;
1462 if (D_UT)
1463 SetRendition(&mchar_null);
1464 #ifdef COLOR
1465 if (D_BE)
1466 SetBackColor(bce);
1467 #endif
1469 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
1471 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
1473 if (up)
1475 GotoPos(0, ye);
1476 for(i = n; i-- > 0; )
1477 AddCStr(D_NL); /* was SF, I think NL is faster */
1479 else
1481 GotoPos(0, ys);
1482 for(i = n; i-- > 0; )
1483 AddCStr(D_SR);
1486 else if (alok && dlok)
1488 if (up || ye != D_bot)
1490 GotoPos(0, up ? ys : ye+1-n);
1491 if (D_CDL && !(n == 1 && D_DL))
1492 AddCStr2(D_CDL, n);
1493 else
1494 for(i = n; i--; )
1495 AddCStr(D_DL);
1497 if (!up || ye != D_bot)
1499 GotoPos(0, up ? ye+1-n : ys);
1500 if (D_CAL && !(n == 1 && D_AL))
1501 AddCStr2(D_CAL, n);
1502 else
1503 for(i = n; i--; )
1504 AddCStr(D_AL);
1507 else
1509 RefreshArea(xs, ys, xe, ye, 0);
1510 return;
1512 if (bce && !D_BE)
1514 if (up)
1515 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
1516 else
1517 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
1519 if (D_lp_missing && missy != D_bot)
1520 WriteLP(D_width - 1, missy);
1521 /* XXX
1522 ChangeScrollRegion(oldtop, oldbot);
1523 if (D_lp_missing && missy != D_bot)
1524 WriteLP(D_width - 1, missy);
1528 void
1529 SetAttr(new)
1530 register int new;
1532 register int i, j, old, typ;
1534 if (!display || (old = D_rend.attr) == new)
1535 return;
1536 #ifdef COLORS16
1537 D_col16change = (old ^ new) & (A_BFG | A_BBG);
1538 new ^= D_col16change;
1539 if (old == new)
1540 return;
1541 #endif
1542 #if defined(TERMINFO) && defined(USE_SGR)
1543 if (D_SA)
1545 char *tparm();
1546 SetFont(ASCII);
1547 ospeed = D_dospeed;
1548 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
1549 new & A_DI, new & A_BD, 0 , 0 ,
1550 0), 1, DoAddChar);
1551 D_rend.attr = new;
1552 D_atyp = 0;
1553 # ifdef COLOR
1554 if (D_hascolor)
1555 rend_setdefault(&D_rend);
1556 # endif
1557 return;
1559 #endif
1560 D_rend.attr = new;
1561 typ = D_atyp;
1562 if ((new & old) != old)
1564 if ((typ & ATYP_U))
1565 AddCStr(D_UE);
1566 if ((typ & ATYP_S))
1567 AddCStr(D_SE);
1568 if ((typ & ATYP_M))
1570 AddCStr(D_ME);
1571 #ifdef COLOR
1572 /* ansi attrib handling: \E[m resets color, too */
1573 if (D_hascolor)
1574 rend_setdefault(&D_rend);
1575 #endif
1576 #ifdef FONT
1577 if (!D_CG0)
1579 /* D_ME may also reset the alternate charset */
1580 D_rend.font = 0;
1581 # ifdef ENCODINGS
1582 D_realfont = 0;
1583 # endif
1585 #endif
1587 old = 0;
1588 typ = 0;
1590 old ^= new;
1591 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
1593 if ((old & j) == 0)
1594 continue;
1595 old ^= j;
1596 if (D_attrtab[i])
1598 AddCStr(D_attrtab[i]);
1599 typ |= D_attrtyp[i];
1602 D_atyp = typ;
1605 #ifdef FONT
1606 void
1607 SetFont(new)
1608 int new;
1610 int old = D_rend.font;
1611 if (!display || old == new)
1612 return;
1613 D_rend.font = new;
1614 #ifdef ENCODINGS
1615 if (D_encoding && CanEncodeFont(D_encoding, new))
1616 return;
1617 if (new == D_realfont)
1618 return;
1619 D_realfont = new;
1620 #endif
1621 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
1622 D_xtable[(int)(unsigned char)new][256])
1624 AddCStr(D_xtable[(int)(unsigned char)new][256]);
1625 return;
1628 if (!D_CG0 && new != '0')
1630 new = ASCII;
1631 if (old == new)
1632 return;
1635 if (new == ASCII)
1636 AddCStr(D_CE0);
1637 #ifdef DW_CHARS
1638 else if (new < ' ')
1640 AddStr("\033$");
1641 if (new > 2)
1642 AddChar('(');
1643 AddChar(new + '@');
1645 #endif
1646 else
1647 AddCStr2(D_CS0, new);
1649 #endif
1651 #ifdef COLOR
1654 color256to16(jj)
1655 int jj;
1657 int min, max;
1658 int r, g, b;
1660 if (jj >= 232)
1662 jj = (jj - 232) / 6;
1663 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
1665 else if (jj >= 16)
1667 jj -= 16;
1668 r = jj / 36;
1669 g = (jj / 6) % 6;
1670 b = jj % 6;
1671 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
1672 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
1673 if (min == max)
1674 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
1675 else
1676 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
1677 min) / (max - min) | (max > 3 ? 8 : 0);
1679 return jj;
1682 #ifdef COLORS256
1684 color256to88(jj)
1685 int jj;
1687 int r, g, b;
1689 if (jj >= 232)
1690 return (jj - 232) / 3 + 80;
1691 if (jj >= 16)
1693 jj -= 16;
1694 r = jj / 36;
1695 g = (jj / 6) % 6;
1696 b = jj % 6;
1697 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
1699 return jj;
1701 #endif
1703 void
1704 SetColor(f, b)
1705 int f, b;
1707 int of, ob;
1708 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
1710 if (!display)
1711 return;
1713 of = rend_getfg(&D_rend);
1714 ob = rend_getbg(&D_rend);
1716 #ifdef COLORS16
1717 /* intense default not invented yet */
1718 if (f == 0x100)
1719 f = 0;
1720 if (b == 0x100)
1721 b = 0;
1722 #endif
1723 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
1724 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
1725 debug2("(%d %d", of, ob);
1726 debug2(" -> %d %d)\n", f, b);
1728 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
1730 if (D_OP)
1731 AddCStr(D_OP);
1732 else
1734 int oattr;
1735 oattr = D_rend.attr;
1736 AddCStr(D_ME ? D_ME : "\033[m");
1737 #ifdef FONT
1738 if (D_ME && !D_CG0)
1740 /* D_ME may also reset the alternate charset */
1741 D_rend.font = 0;
1742 # ifdef ENCODINGS
1743 D_realfont = 0;
1744 # endif
1746 #endif
1747 D_atyp = 0;
1748 D_rend.attr = 0;
1749 SetAttr(oattr);
1751 of = ob = 0;
1753 rend_setfg(&D_rend, f);
1754 rend_setbg(&D_rend, b);
1755 #ifdef COLORS16
1756 D_col16change = 0;
1757 #endif
1758 if (!D_hascolor)
1759 return;
1760 f = f ? coli2e(f) : -1;
1761 b = b ? coli2e(b) : -1;
1762 of = of ? coli2e(of) : -1;
1763 ob = ob ? coli2e(ob) : -1;
1764 #ifdef COLORS256
1765 if (f != of && f > 15 && D_CCO != 256)
1766 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
1767 if (f != of && f > 15 && D_CAF)
1769 AddCStr2(D_CAF, f);
1770 of = f;
1772 if (b != ob && b > 15 && D_CCO != 256)
1773 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
1774 if (b != ob && b > 15 && D_CAB)
1776 AddCStr2(D_CAB, b);
1777 ob = b;
1779 #endif
1780 if (f != of && f != (of | 8))
1782 if (f == -1)
1783 AddCStr("\033[39m"); /* works because AX is set */
1784 else if (D_CAF)
1785 AddCStr2(D_CAF, f & 7);
1786 else if (D_CSF)
1787 AddCStr2(D_CSF, sftrans[f & 7]);
1789 if (b != ob && b != (ob | 8))
1791 if (b == -1)
1792 AddCStr("\033[49m"); /* works because AX is set */
1793 else if (D_CAB)
1794 AddCStr2(D_CAB, b & 7);
1795 else if (D_CSB)
1796 AddCStr2(D_CSB, sftrans[b & 7]);
1798 #ifdef COLORS16
1799 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
1801 # ifdef TERMINFO
1802 AddCStr2("\033[9%p1%dm", f & 7);
1803 # else
1804 AddCStr2("\033[9%dm", f & 7);
1805 # endif
1807 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
1809 # ifdef TERMINFO
1810 AddCStr2("\033[10%p1%dm", b & 7);
1811 # else
1812 AddCStr2("\033[10%dm", b & 7);
1813 # endif
1815 #endif
1818 static void
1819 SetBackColor(new)
1820 int new;
1822 if (!display)
1823 return;
1824 SetColor(rend_getfg(&D_rend), new);
1826 #endif /* COLOR */
1828 void
1829 SetRendition(mc)
1830 struct mchar *mc;
1832 if (!display)
1833 return;
1834 #ifdef COLOR
1835 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
1837 static struct mchar mmc;
1838 int i;
1839 mmc = *mc;
1840 for (i = 0; i < 8; i++)
1841 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
1843 if (mc->color == 0 && attr2color[i][3])
1844 ApplyAttrColor(attr2color[i][3], &mmc);
1845 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
1846 ApplyAttrColor(attr2color[i][2], &mmc);
1847 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
1848 ApplyAttrColor(attr2color[i][1], &mmc);
1849 else
1850 ApplyAttrColor(attr2color[i][0], &mmc);
1852 mc = &mmc;
1853 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
1855 # ifdef COLORS16
1856 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
1858 int a = mc->attr;
1859 if ((mc->attr & A_BFG) && D_MD)
1860 a |= A_BD;
1861 if ((mc->attr & A_BBG) && D_MB)
1862 a |= A_BL;
1863 if (D_rend.attr != a)
1864 SetAttr(a);
1866 else
1867 # endif /* COLORS16 */
1868 #endif /* COLOR */
1869 if (D_rend.attr != mc->attr)
1870 SetAttr(mc->attr);
1872 #ifdef COLOR
1873 if (D_rend.color != mc->color
1874 # ifdef COLORS256
1875 || D_rend.colorx != mc->colorx
1876 # endif
1877 # ifdef COLORS16
1878 || D_col16change
1879 # endif
1881 SetColor(rend_getfg(mc), rend_getbg(mc));
1882 #endif
1883 #ifdef FONT
1884 if (D_rend.font != mc->font)
1885 SetFont(mc->font);
1886 #endif
1889 void
1890 SetRenditionMline(ml, x)
1891 struct mline *ml;
1892 int x;
1894 if (!display)
1895 return;
1896 #ifdef COLOR
1897 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
1899 struct mchar mc;
1900 copy_mline2mchar(&mc, ml, x);
1901 SetRendition(&mc);
1902 return;
1904 # ifdef COLORS16
1905 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
1907 int a = ml->attr[x];
1908 if ((ml->attr[x] & A_BFG) && D_MD)
1909 a |= A_BD;
1910 if ((ml->attr[x] & A_BBG) && D_MB)
1911 a |= A_BL;
1912 if (D_rend.attr != a)
1913 SetAttr(a);
1915 else
1916 # endif /* COLORS16 */
1917 #endif /* COLOR */
1918 if (D_rend.attr != ml->attr[x])
1919 SetAttr(ml->attr[x]);
1920 #ifdef COLOR
1921 if (D_rend.color != ml->color[x]
1922 # ifdef COLORS256
1923 || D_rend.colorx != ml->colorx[x]
1924 # endif
1925 # ifdef COLORS16
1926 || D_col16change
1927 # endif
1930 struct mchar mc;
1931 copy_mline2mchar(&mc, ml, x);
1932 SetColor(rend_getfg(&mc), rend_getbg(&mc));
1934 #endif
1935 #ifdef FONT
1936 if (D_rend.font != ml->font[x])
1937 SetFont(ml->font[x]);
1938 #endif
1941 void
1942 MakeStatus(msg)
1943 char *msg;
1945 register char *s, *t;
1946 register int max;
1948 if (!display)
1949 return;
1951 if (D_blocked)
1952 return;
1953 if (!D_tcinited)
1955 debug("tc not inited, just writing msg\n");
1956 if (D_processinputdata)
1957 return; /* XXX: better */
1958 AddStr(msg);
1959 AddStr("\r\n");
1960 Flush(0);
1961 return;
1963 if (!use_hardstatus || !D_HS)
1965 max = D_width;
1966 if (D_CLP == 0)
1967 max--;
1969 else
1970 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
1971 if (D_status)
1973 /* same message? */
1974 if (strcmp(msg, D_status_lastmsg) == 0)
1976 debug("same message - increase timeout");
1977 if (!D_status_obufpos)
1978 SetTimeout(&D_statusev, MsgWait);
1979 return;
1981 RemoveStatusMinWait();
1983 for (s = t = msg; *s && t - msg < max; ++s)
1984 if (*s == BELL)
1985 AddCStr(D_BL);
1986 else if ((unsigned char)*s >= ' ' && *s != 0177)
1987 *t++ = *s;
1988 *t = '\0';
1989 if (t == msg)
1990 return;
1991 if (t - msg >= D_status_buflen)
1993 char *buf;
1994 if (D_status_lastmsg)
1995 buf = realloc(D_status_lastmsg, t - msg + 1);
1996 else
1997 buf = malloc(t - msg + 1);
1998 if (buf)
2000 D_status_lastmsg = buf;
2001 D_status_buflen = t - msg + 1;
2004 if (t - msg < D_status_buflen)
2005 strcpy(D_status_lastmsg, msg);
2006 D_status_len = t - msg;
2007 D_status_lastx = D_x;
2008 D_status_lasty = D_y;
2009 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2011 D_status = STATUS_ON_WIN;
2012 debug1("using STATLINE %d\n", STATLINE);
2013 GotoPos(0, STATLINE);
2014 SetRendition(&mchar_so);
2015 InsertMode(0);
2016 AddStr(msg);
2017 if (D_status_len < max)
2019 /* Wayne Davison: add extra space for readability */
2020 D_status_len++;
2021 SetRendition(&mchar_null);
2022 AddChar(' ');
2023 if (D_status_len < max)
2025 D_status_len++;
2026 AddChar(' ');
2027 AddChar('\b');
2029 AddChar('\b');
2031 D_x = -1;
2033 else
2035 D_status = STATUS_ON_HS;
2036 ShowHStatus(msg);
2039 D_status_obufpos = D_obufp - D_obuf;
2040 ASSERT(D_status_obufpos > 0);
2042 if (D_status == STATUS_ON_WIN)
2044 struct display *olddisplay = display;
2045 struct layer *oldflayer = flayer;
2047 /* this is copied over from RemoveStatus() */
2048 D_status = 0;
2049 GotoPos(0, STATLINE);
2050 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2051 GotoPos(D_status_lastx, D_status_lasty);
2052 flayer = D_forecv ? D_forecv->c_layer : 0;
2053 if (flayer)
2054 LaySetCursor();
2055 display = olddisplay;
2056 flayer = oldflayer;
2057 D_status = STATUS_ON_WIN;
2061 void
2062 RemoveStatus()
2064 struct display *olddisplay;
2065 struct layer *oldflayer;
2066 int where;
2068 if (!display)
2069 return;
2070 if (!(where = D_status))
2071 return;
2073 debug("RemoveStatus\n");
2074 if (D_status_obuffree >= 0)
2076 D_obuflen = D_status_obuflen;
2077 D_obuffree = D_status_obuffree;
2078 D_status_obuffree = -1;
2080 D_status = 0;
2081 D_status_obufpos = 0;
2082 D_status_bell = 0;
2083 evdeq(&D_statusev);
2084 olddisplay = display;
2085 oldflayer = flayer;
2086 if (where == STATUS_ON_WIN)
2088 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2090 GotoPos(0, STATLINE);
2091 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2092 GotoPos(D_status_lastx, D_status_lasty);
2095 else
2096 RefreshHStatus();
2097 flayer = D_forecv ? D_forecv->c_layer : 0;
2098 if (flayer)
2099 LaySetCursor();
2100 display = olddisplay;
2101 flayer = oldflayer;
2104 /* Remove the status but make sure that it is seen for MsgMinWait ms */
2105 static void
2106 RemoveStatusMinWait()
2108 /* XXX: should flush output first if D_status_obufpos is set */
2109 if (!D_status_bell && !D_status_obufpos)
2111 struct timeval now;
2112 int ti;
2113 gettimeofday(&now, NULL);
2114 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2115 if (ti < MsgMinWait)
2116 DisplaySleep1000(MsgMinWait - ti, 0);
2118 RemoveStatus();
2121 #ifdef UTF8
2122 static int
2123 strlen_onscreen(unsigned char *c, unsigned char *end)
2125 int len = 0;
2126 char *s = c;
2127 while (*c && (!end || c < end))
2129 int v, dec = 0;
2132 v = FromUtf8(*c++, &dec);
2133 if (v == -2)
2134 c--;
2136 while (v < 0 && (!end || c < end));
2137 if (!utf8_iscomb(v))
2139 if (utf8_isdouble(v))
2140 len++;
2141 len++;
2145 return len;
2148 static int
2149 PrePutWinMsg(s, start, max)
2150 char *s;
2151 int start, max;
2153 /* Avoid double-encoding problem for a UTF-8 message on a UTF-8 locale.
2154 Ideally, this would not be necessary. But fixing it the Right Way will
2155 probably take way more time. So this will have to do for now. */
2156 if (D_encoding == UTF8)
2158 int chars = strlen_onscreen(s + start, s + max);
2159 D_encoding = 0;
2160 PutWinMsg(s, start, max);
2161 D_encoding = UTF8;
2162 D_x -= (max - chars); /* Yak! But this is necessary to count for
2163 the fact that not every byte represents a
2164 character. */
2165 return start + chars;
2167 else
2169 PutWinMsg(s, start, max);
2170 return max;
2173 #else
2174 static int
2175 PrePutWinMsg(s, start, max)
2176 char *s;
2177 int start, max;
2179 PutWinMsg(s, start, max);
2180 return max;
2182 #endif
2184 /* refresh the display's hstatus line */
2185 void
2186 ShowHStatus(str)
2187 char *str;
2189 int l, ox, oy, max;
2191 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2192 return; /* sorry, in use */
2193 if (D_blocked)
2194 return;
2196 if (D_HS && D_has_hstatus == HSTATUS_HS)
2198 if (!D_hstatus && (str == 0 || *str == 0))
2199 return;
2200 debug("ShowHStatus: using HS\n");
2201 SetRendition(&mchar_null);
2202 InsertMode(0);
2203 if (D_hstatus)
2204 AddCStr(D_DS);
2205 D_hstatus = 0;
2206 if (str == 0 || *str == 0)
2207 return;
2208 AddCStr2(D_TS, 0);
2209 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2210 if ((int)strlen(str) > max)
2211 AddStrn(str, max);
2212 else
2213 AddStr(str);
2214 AddCStr(D_FS);
2215 D_hstatus = 1;
2217 else if (D_has_hstatus == HSTATUS_LASTLINE)
2219 debug("ShowHStatus: using last line\n");
2220 ox = D_x;
2221 oy = D_y;
2222 str = str ? str : "";
2223 l = strlen(str);
2224 if (l > D_width)
2225 l = D_width;
2226 GotoPos(0, D_height - 1);
2227 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2228 l = PrePutWinMsg(str, 0, l);
2229 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2230 while (l++ < D_width)
2231 PUTCHARLP(' ');
2232 if (l < D_width)
2233 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2234 if (ox != -1 && oy != -1)
2235 GotoPos(ox, oy);
2236 D_hstatus = *str ? 1 : 0;
2237 SetRendition(&mchar_null);
2239 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2241 debug("ShowHStatus: using message\n");
2242 Msg(0, "%s", str);
2248 * Refreshes the harstatus of the fore window. Shouldn't be here...
2250 void
2251 RefreshHStatus()
2253 char *buf;
2255 evdeq(&D_hstatusev);
2256 if (D_status == STATUS_ON_HS)
2257 return;
2258 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2259 if (buf && *buf)
2261 ShowHStatus(buf);
2262 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2263 evenq(&D_hstatusev);
2265 else
2266 ShowHStatus((char *)0);
2269 /*********************************************************************/
2271 * Here come the routines that refresh an arbitrary part of the screen.
2274 void
2275 RefreshAll(isblank)
2276 int isblank;
2278 struct canvas *cv;
2280 ASSERT(display);
2281 debug("Signalling full refresh!\n");
2282 for (cv = D_cvlist; cv; cv = cv->c_next)
2284 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2285 display = cv->c_display; /* just in case! */
2287 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2290 void
2291 RefreshArea(xs, ys, xe, ye, isblank)
2292 int xs, ys, xe, ye, isblank;
2294 int y;
2295 ASSERT(display);
2296 debug2("Refresh Area: %d,%d", xs, ys);
2297 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2298 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2300 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2301 isblank = 1;
2303 for (y = ys; y <= ye; y++)
2304 RefreshLine(y, xs, xe, isblank);
2307 void
2308 RefreshLine(y, from, to, isblank)
2309 int y, from, to, isblank;
2311 struct viewport *vp, *lvp;
2312 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2313 struct layer *oldflayer;
2314 int xx, yy, l;
2315 char *buf;
2316 struct win *p;
2318 ASSERT(display);
2320 debug2("RefreshLine %d %d", y, from);
2321 debug2(" %d %d\n", to, isblank);
2323 if (D_status == STATUS_ON_WIN && y == STATLINE)
2325 if (to >= D_status_len)
2326 D_status_len = to + 1;
2327 return; /* can't refresh status */
2330 if (isblank == 0 && D_CE && to == D_width - 1 && from < to && D_status != STATUS_ON_HS)
2332 GotoPos(from, y);
2333 if (D_UT || D_BE)
2334 SetRendition(&mchar_null);
2335 AddCStr(D_CE);
2336 isblank = 1;
2339 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2341 RefreshHStatus();
2342 return;
2345 while (from <= to)
2347 lcv = 0;
2348 lvp = 0;
2349 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2351 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2353 p = Layer2Window(cv->c_layer);
2354 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
2355 if (cv->c_captev.timeout.tv_sec)
2356 evenq(&cv->c_captev);
2357 xx = to > cv->c_xe ? cv->c_xe : to;
2358 l = strlen(buf);
2359 GotoPos(from, y);
2360 SetRendition(&mchar_so);
2361 if (l > xx - cv->c_xs + 1)
2362 l = xx - cv->c_xs + 1;
2363 l = PrePutWinMsg(buf, from - cv->c_xs, l);
2364 from = cv->c_xs + l;
2365 for (; from <= xx; from++)
2366 PUTCHARLP(' ');
2367 break;
2369 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
2371 GotoPos(from, y);
2372 SetRendition(&mchar_so);
2373 PUTCHARLP(' ');
2374 from++;
2375 break;
2377 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
2378 continue;
2379 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
2380 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
2381 for (vp = cv->c_vplist; vp; vp = vp->v_next)
2383 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
2384 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
2385 /* find leftmost overlapping vp */
2386 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))
2388 lcv = cv;
2389 lvp = vp;
2393 if (cv)
2394 continue; /* we advanced from */
2395 if (lvp == 0)
2396 break;
2397 if (from < lvp->v_xs)
2399 if (!isblank)
2400 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
2401 from = lvp->v_xs;
2404 /* call LayRedisplayLine on canvas lcv viewport lvp */
2405 yy = y - lvp->v_yoff;
2406 xx = to < lvp->v_xe ? to : lvp->v_xe;
2408 if (lcv->c_layer && lcv->c_xoff + lcv->c_layer->l_width == from)
2410 GotoPos(from, y);
2411 SetRendition(&mchar_blank);
2412 PUTCHARLP('|');
2413 from++;
2415 if (lcv->c_layer && yy == lcv->c_layer->l_height)
2417 GotoPos(from, y);
2418 SetRendition(&mchar_blank);
2419 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
2421 PUTCHARLP('-');
2422 from++;
2424 if (from >= lvp->v_xe + 1)
2425 continue;
2427 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
2429 if (!isblank)
2430 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
2431 from = lvp->v_xe + 1;
2432 continue;
2435 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
2436 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
2437 oldflayer = flayer;
2438 flayer = lcv->c_layer;
2439 cvlist = flayer->l_cvlist;
2440 cvlnext = lcv->c_lnext;
2441 flayer->l_cvlist = lcv;
2442 lcv->c_lnext = 0;
2443 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
2444 flayer->l_cvlist = cvlist;
2445 lcv->c_lnext = cvlnext;
2446 flayer = oldflayer;
2448 from = xx + 1;
2450 if (!isblank && from <= to)
2451 DisplayLine(&mline_null, &mline_blank, y, from, to);
2454 /*********************************************************************/
2456 /* clear lp_missing by writing the char on the screen. The
2457 * position must be safe.
2459 static void
2460 WriteLP(x2, y2)
2461 int x2, y2;
2463 struct mchar oldrend;
2465 ASSERT(display);
2466 ASSERT(D_lp_missing);
2467 oldrend = D_rend;
2468 debug2("WriteLP(%d,%d)\n", x2, y2);
2469 #ifdef DW_CHARS
2470 if (D_lpchar.mbcs)
2472 if (x2 > 0)
2473 x2--;
2474 else
2475 D_lpchar = mchar_blank;
2477 #endif
2478 /* Can't use PutChar */
2479 GotoPos(x2, y2);
2480 SetRendition(&D_lpchar);
2481 PUTCHAR(D_lpchar.image);
2482 #ifdef DW_CHARS
2483 if (D_lpchar.mbcs)
2484 PUTCHAR(D_lpchar.mbcs);
2485 #endif
2486 D_lp_missing = 0;
2487 SetRendition(&oldrend);
2490 void
2491 ClearLine(oml, y, from, to, bce)
2492 struct mline *oml;
2493 int from, to, y, bce;
2495 int x;
2496 #ifdef COLOR
2497 struct mchar bcechar;
2498 #endif
2500 debug3("ClearLine %d,%d-%d\n", y, from, to);
2501 if (D_UT) /* Safe to erase ? */
2502 SetRendition(&mchar_null);
2503 #ifdef COLOR
2504 if (D_BE)
2505 SetBackColor(bce);
2506 #endif
2507 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
2509 GotoPos(to, y);
2510 AddCStr(D_CB);
2511 return;
2513 if (to == D_width - 1 && D_CE && (!bce || D_BE))
2515 GotoPos(from, y);
2516 AddCStr(D_CE);
2517 return;
2519 if (oml == 0)
2520 oml = &mline_null;
2521 #ifdef COLOR
2522 if (!bce)
2524 DisplayLine(oml, &mline_blank, y, from, to);
2525 return;
2527 bcechar = mchar_null;
2528 rend_setbg(&bcechar, bce);
2529 for (x = from; x <= to; x++)
2530 copy_mchar2mline(&bcechar, &mline_old, x);
2531 DisplayLine(oml, &mline_old, y, from, to);
2532 #else
2533 DisplayLine(oml, &mline_blank, y, from, to);
2534 #endif
2537 void
2538 DisplayLine(oml, ml, y, from, to)
2539 struct mline *oml, *ml;
2540 int from, to, y;
2542 register int x;
2543 int last2flag = 0, delete_lp = 0;
2545 ASSERT(display);
2546 ASSERT(y >= 0 && y < D_height);
2547 ASSERT(from >= 0 && from < D_width);
2548 ASSERT(to >= 0 && to < D_width);
2549 if (!D_CLP && y == D_bot && to == D_width - 1)
2551 if (D_lp_missing || !cmp_mline(oml, ml, to))
2553 #ifdef DW_CHARS
2554 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
2555 #else
2556 if ((D_IC || D_IM) && from < to)
2557 #endif
2559 last2flag = 1;
2560 D_lp_missing = 0;
2561 to--;
2563 else
2565 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
2566 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
2567 copy_mline2mchar(&D_lpchar, ml, to);
2570 to--;
2572 #ifdef DW_CHARS
2573 if (D_mbcs)
2575 /* finish dw-char (can happen after a wrap) */
2576 debug("DisplayLine finishing kanji\n");
2577 SetRenditionMline(ml, from);
2578 PUTCHAR(ml->image[from]);
2579 from++;
2581 #endif
2582 for (x = from; x <= to; x++)
2584 #if 0 /* no longer needed */
2585 if (x || D_x != D_width || D_y != y - 1)
2586 #endif
2588 if (x < to || x != D_width - 1 || ml->image[x + 1])
2589 if (cmp_mline(oml, ml, x))
2590 continue;
2591 GotoPos(x, y);
2593 #ifdef DW_CHARS
2594 if (dw_right(ml, x, D_encoding))
2596 x--;
2597 debug1("DisplayLine on right side of dw char- x now %d\n", x);
2598 GotoPos(x, y);
2600 if (x == to && dw_left(ml, x, D_encoding))
2601 break; /* don't start new kanji */
2602 #endif
2603 SetRenditionMline(ml, x);
2604 PUTCHAR(ml->image[x]);
2605 #ifdef DW_CHARS
2606 if (dw_left(ml, x, D_encoding))
2607 PUTCHAR(ml->image[++x]);
2608 #endif
2610 #if 0 /* not needed any longer */
2611 /* compare != 0 because ' ' can happen when clipping occures */
2612 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
2613 GotoPos(0, y + 1);
2614 #endif
2615 if (last2flag)
2617 GotoPos(x, y);
2618 SetRenditionMline(ml, x + 1);
2619 PUTCHAR(ml->image[x + 1]);
2620 GotoPos(x, y);
2621 SetRenditionMline(ml, x);
2622 INSERTCHAR(ml->image[x]);
2624 else if (delete_lp)
2626 if (D_UT)
2627 SetRendition(&mchar_null);
2628 if (D_DC)
2629 AddCStr(D_DC);
2630 else if (D_CDC)
2631 AddCStr2(D_CDC, 1);
2632 else if (D_CE)
2633 AddCStr(D_CE);
2637 void
2638 PutChar(c, x, y)
2639 struct mchar *c;
2640 int x, y;
2642 GotoPos(x, y);
2643 SetRendition(c);
2644 PUTCHARLP(c->image);
2645 #ifdef DW_CHARS
2646 if (c->mbcs)
2648 # ifdef UTF8
2649 if (D_encoding == UTF8)
2650 D_rend.font = 0;
2651 # endif
2652 PUTCHARLP(c->mbcs);
2654 #endif
2657 void
2658 InsChar(c, x, xe, y, oml)
2659 struct mchar *c;
2660 int x, xe, y;
2661 struct mline *oml;
2663 GotoPos(x, y);
2664 if (y == D_bot && !D_CLP)
2666 if (x == D_width - 1)
2668 D_lp_missing = 1;
2669 D_lpchar = *c;
2670 return;
2672 if (xe == D_width - 1)
2673 D_lp_missing = 0;
2675 if (x == xe)
2677 SetRendition(c);
2678 PUTCHARLP(c->image);
2679 return;
2681 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
2683 RefreshLine(y, x, xe, 0);
2684 GotoPos(x + 1, y);
2685 /* UpdateLine(oml, y, x, xe); */
2686 return;
2688 InsertMode(1);
2689 if (!D_insert)
2691 #ifdef DW_CHARS
2692 if (c->mbcs && D_IC)
2693 AddCStr(D_IC);
2694 if (D_IC)
2695 AddCStr(D_IC);
2696 else
2697 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
2698 #else
2699 if (D_IC)
2700 AddCStr(D_IC);
2701 else
2702 AddCStr2(D_CIC, 1);
2703 #endif
2705 SetRendition(c);
2706 RAW_PUTCHAR(c->image);
2707 #ifdef DW_CHARS
2708 if (c->mbcs)
2710 # ifdef UTF8
2711 if (D_encoding == UTF8)
2712 D_rend.font = 0;
2713 # endif
2714 if (D_x == D_width - 1)
2715 PUTCHARLP(c->mbcs);
2716 else
2717 RAW_PUTCHAR(c->mbcs);
2719 #endif
2722 void
2723 WrapChar(c, x, y, xs, ys, xe, ye, ins)
2724 struct mchar *c;
2725 int x, y;
2726 int xs, ys, xe, ye;
2727 int ins;
2729 int bce;
2731 #ifdef COLOR
2732 bce = rend_getbg(c);
2733 #else
2734 bce = 0;
2735 #endif
2736 debug("WrapChar:");
2737 debug2(" x %d y %d", x, y);
2738 debug2(" Dx %d Dy %d", D_x, D_y);
2739 debug2(" xs %d ys %d", xs, ys);
2740 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
2741 if (xs != 0 || x != D_width || !D_AM)
2743 if (y == ye)
2744 ScrollV(xs, ys, xe, ye, 1, bce);
2745 else if (y < D_height - 1)
2746 y++;
2747 if (ins)
2748 InsChar(c, xs, xe, y, 0);
2749 else
2750 PutChar(c, xs, y);
2751 return;
2753 if (y == ye) /* we have to scroll */
2755 debug("- scrolling\n");
2756 ChangeScrollRegion(ys, ye);
2757 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
2759 debug("- have to call ScrollV\n");
2760 ScrollV(xs, ys, xe, ye, 1, bce);
2761 y--;
2764 else if (y == D_bot) /* remove unusable region? */
2765 ChangeScrollRegion(0, D_height - 1);
2766 if (D_x != D_width || D_y != y)
2768 if (D_CLP && y >= 0) /* don't even try if !LP */
2769 RefreshLine(y, D_width - 1, D_width - 1, 0);
2770 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
2771 if (D_x != D_width || D_y != y) /* sorry, no bonus */
2773 if (y == ye)
2774 ScrollV(xs, ys, xe, ye, 1, bce);
2775 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
2778 debug("- writeing new char");
2779 if (y != ye && y < D_height - 1)
2780 y++;
2781 if (ins != D_insert)
2782 InsertMode(ins);
2783 if (ins && !D_insert)
2785 InsChar(c, 0, xe, y, 0);
2786 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
2787 return;
2789 D_y = y;
2790 D_x = 0;
2791 SetRendition(c);
2792 RAW_PUTCHAR(c->image);
2793 #ifdef DW_CHARS
2794 if (c->mbcs)
2796 # ifdef UTF8
2797 if (D_encoding == UTF8)
2798 D_rend.font = 0;
2799 # endif
2800 RAW_PUTCHAR(c->mbcs);
2802 #endif
2803 debug2(" -> done (%d,%d)\n", D_x, D_y);
2807 ResizeDisplay(wi, he)
2808 int wi, he;
2810 ASSERT(display);
2811 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
2812 if (D_width == wi && D_height == he)
2814 debug("ResizeDisplay: No change\n");
2815 return 0;
2817 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
2819 debug("ResizeDisplay: using Z0/Z1\n");
2820 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
2821 ChangeScreenSize(wi, D_height, 0);
2822 return (he == D_height) ? 0 : -1;
2824 if (D_CWS)
2826 debug("ResizeDisplay: using WS\n");
2827 AddCStr(tgoto(D_CWS, wi, he));
2828 ChangeScreenSize(wi, he, 0);
2829 return 0;
2831 return -1;
2834 void
2835 ChangeScrollRegion(newtop, newbot)
2836 int newtop, newbot;
2838 if (display == 0)
2839 return;
2840 if (newtop == newbot)
2841 return; /* xterm etc can't do it */
2842 if (newtop == -1)
2843 newtop = 0;
2844 if (newbot == -1)
2845 newbot = D_height - 1;
2846 if (D_CS == 0)
2848 D_top = 0;
2849 D_bot = D_height - 1;
2850 return;
2852 if (D_top == newtop && D_bot == newbot)
2853 return;
2854 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
2855 AddCStr(tgoto(D_CS, newbot, newtop));
2856 D_top = newtop;
2857 D_bot = newbot;
2858 D_y = D_x = -1; /* Just in case... */
2861 #ifdef RXVT_OSC
2862 #define WT_FLAG "2" /* change to "0" to set both title and icon */
2864 void
2865 SetXtermOSC(i, s)
2866 int i;
2867 char *s;
2869 static char *oscs[][2] = {
2870 { WT_FLAG ";", "screen" }, /* set window title */
2871 { "20;", "" }, /* background */
2872 { "39;", "black" }, /* default foreground (black?) */
2873 { "49;", "white" } /* default background (white?) */
2876 ASSERT(display);
2877 if (!D_CXT)
2878 return;
2879 if (!s)
2880 s = "";
2881 if (!D_xtermosc[i] && !*s)
2882 return;
2883 if (i == 0 && !D_xtermosc[0])
2884 AddStr("\033[22;" WT_FLAG "t"); /* stack titles (xterm patch #251) */
2885 if (!*s)
2886 s = oscs[i][1];
2887 D_xtermosc[i] = 1;
2888 AddStr("\033]");
2889 AddStr(oscs[i][0]);
2890 AddStr(s);
2891 AddChar(7);
2894 void
2895 ClearAllXtermOSC()
2897 int i;
2898 for (i = 3; i >= 0; i--)
2899 SetXtermOSC(i, 0);
2900 if (D_xtermosc[0])
2901 AddStr("\033[23;" WT_FLAG "t"); /* unstack titles (xterm patch #251) */
2903 #undef WT_FLAG
2904 #endif
2907 * Output buffering routines
2910 void
2911 AddStr(str)
2912 char *str;
2914 register char c;
2916 ASSERT(display);
2918 #ifdef UTF8
2919 if (D_encoding == UTF8)
2921 while ((c = *str++))
2922 AddUtf8((unsigned char)c);
2923 return;
2925 #endif
2926 while ((c = *str++))
2927 AddChar(c);
2930 void
2931 AddStrn(str, n)
2932 char *str;
2933 int n;
2935 register char c;
2937 ASSERT(display);
2938 #ifdef UTF8
2939 if (D_encoding == UTF8)
2941 while ((c = *str++) && n-- > 0)
2942 AddUtf8((unsigned char)c);
2944 else
2945 #endif
2946 while ((c = *str++) && n-- > 0)
2947 AddChar(c);
2948 while (n-- > 0)
2949 AddChar(' ');
2952 void
2953 Flush(progress)
2954 int progress;
2956 register int l;
2957 int wr;
2958 register char *p;
2960 ASSERT(display);
2961 l = D_obufp - D_obuf;
2962 debug1("Flush(): %d\n", l);
2963 if (l == 0)
2964 return;
2965 ASSERT(l + D_obuffree == D_obuflen);
2966 if (D_userfd < 0)
2968 D_obuffree += l;
2969 D_obufp = D_obuf;
2970 return;
2972 p = D_obuf;
2973 if (!progress)
2975 if (fcntl(D_userfd, F_SETFL, 0))
2976 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
2978 while (l)
2980 if (progress)
2982 fd_set w;
2983 FD_ZERO(&w);
2984 FD_SET(D_userfd, &w);
2985 struct timeval t;
2986 t.tv_sec = progress;
2987 t.tv_usec = 0;
2988 wr = select(FD_SETSIZE, (fd_set *)0, &w, (fd_set *)0, &t);
2989 if (wr == -1)
2991 if (errno == EINTR)
2992 continue;
2993 debug1("Warning: select failed: %d\n", errno);
2994 break;
2996 if (wr == 0)
2998 /* no progress after 3 seconds. sorry. */
2999 debug1("Warning: no progress after %d seconds\n", progress);
3000 break;
3003 wr = write(D_userfd, p, l);
3004 if (wr <= 0)
3006 if (errno == EINTR)
3007 continue;
3008 debug1("Writing to display: %d\n", errno);
3009 break;
3011 D_obuffree += wr;
3012 p += wr;
3013 l -= wr;
3015 if (l)
3016 debug1("Warning: Flush could not write %d bytes\n", l);
3017 D_obuffree += l;
3018 D_obufp = D_obuf;
3019 if (!progress)
3021 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3022 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3024 if (D_blocked == 1)
3025 D_blocked = 0;
3026 D_blocked_fuzz = 0;
3029 void
3030 freetty()
3032 if (D_userfd >= 0)
3033 close(D_userfd);
3034 debug1("did freetty %d\n", D_userfd);
3035 D_userfd = -1;
3036 D_obufp = 0;
3037 D_obuffree = 0;
3038 if (D_obuf)
3039 free(D_obuf);
3040 D_obuf = 0;
3041 D_obuflen = 0;
3042 D_obuflenmax = -D_obufmax;
3043 D_blocked = 0;
3044 D_blocked_fuzz = 0;
3048 * Asynchronous output routines by
3049 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3052 void
3053 Resize_obuf()
3055 register int ind;
3057 ASSERT(display);
3058 if (D_status_obuffree >= 0)
3060 ASSERT(D_obuffree == -1);
3061 RemoveStatusMinWait();
3062 if (--D_obuffree > 0) /* redo AddChar decrement */
3063 return;
3065 if (D_obuflen && D_obuf)
3067 ind = D_obufp - D_obuf;
3068 D_obuflen += GRAIN;
3069 D_obuffree += GRAIN;
3070 D_obuf = realloc(D_obuf, D_obuflen);
3072 else
3074 ind = 0;
3075 D_obuflen = GRAIN;
3076 D_obuffree = GRAIN;
3077 D_obuf = malloc(D_obuflen);
3079 if (!D_obuf)
3080 Panic(0, "Out of memory");
3081 D_obufp = D_obuf + ind;
3082 D_obuflenmax = D_obuflen - D_obufmax;
3083 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3086 void
3087 DisplaySleep1000(n, eat)
3088 int n;
3089 int eat;
3091 char buf;
3092 fd_set r;
3093 struct timeval t;
3095 if (n <= 0)
3096 return;
3097 if (!display)
3099 debug("DisplaySleep has no display sigh\n");
3100 sleep1000(n);
3101 return;
3103 t.tv_usec = (n % 1000) * 1000;
3104 t.tv_sec = n / 1000;
3105 FD_ZERO(&r);
3106 FD_SET(D_userfd, &r);
3107 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3109 debug("display activity stopped sleep\n");
3110 if (eat)
3111 read(D_userfd, &buf, 1);
3113 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3116 #ifdef AUTO_NUKE
3117 void
3118 NukePending()
3119 {/* Nuke pending output in current display, clear screen */
3120 register int len;
3121 int oldtop = D_top, oldbot = D_bot;
3122 struct mchar oldrend;
3123 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3124 int oldcurvis = D_curvis;
3125 int oldmouse = D_mouse;
3127 oldrend = D_rend;
3128 len = D_obufp - D_obuf;
3129 debug1("NukePending: nuking %d chars\n", len);
3131 /* Throw away any output that we can... */
3132 # ifdef POSIX
3133 tcflush(D_userfd, TCOFLUSH);
3134 # else
3135 # ifdef TCFLSH
3136 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3137 # endif
3138 # endif
3140 D_obufp = D_obuf;
3141 D_obuffree += len;
3142 D_top = D_bot = -1;
3143 AddCStr(D_IS);
3144 AddCStr(D_TI);
3145 /* Turn off all attributes. (Tim MacKenzie) */
3146 if (D_ME)
3147 AddCStr(D_ME);
3148 else
3150 #ifdef COLOR
3151 if (D_hascolor)
3152 AddStr("\033[m"); /* why is D_ME not set? */
3153 #endif
3154 AddCStr(D_SE);
3155 AddCStr(D_UE);
3157 /* Check for toggle */
3158 if (D_IM && strcmp(D_IM, D_EI))
3159 AddCStr(D_EI);
3160 D_insert = 0;
3161 /* Check for toggle */
3162 #ifdef MAPKEYS
3163 if (D_KS && strcmp(D_KS, D_KE))
3164 AddCStr(D_KS);
3165 if (D_CCS && strcmp(D_CCS, D_CCE))
3166 AddCStr(D_CCS);
3167 #else
3168 if (D_KS && strcmp(D_KS, D_KE))
3169 AddCStr(D_KE);
3170 D_keypad = 0;
3171 if (D_CCS && strcmp(D_CCS, D_CCE))
3172 AddCStr(D_CCE);
3173 D_cursorkeys = 0;
3174 #endif
3175 AddCStr(D_CE0);
3176 D_rend = mchar_null;
3177 D_atyp = 0;
3178 AddCStr(D_DS);
3179 D_hstatus = 0;
3180 AddCStr(D_VE);
3181 D_curvis = 0;
3182 ChangeScrollRegion(oldtop, oldbot);
3183 SetRendition(&oldrend);
3184 KeypadMode(oldkeypad);
3185 CursorkeysMode(oldcursorkeys);
3186 CursorVisibility(oldcurvis);
3187 MouseMode(oldmouse);
3188 if (D_CWS)
3190 debug("ResizeDisplay: using WS\n");
3191 AddCStr(tgoto(D_CWS, D_width, D_height));
3193 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3195 debug("ResizeDisplay: using Z0/Z1\n");
3196 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3199 #endif /* AUTO_NUKE */
3201 #ifdef linux
3202 /* linux' select can't handle flow control, so wait 100ms if
3203 * we get EAGAIN
3205 static void
3206 disp_writeev_eagain(ev, data)
3207 struct event *ev;
3208 char *data;
3210 display = (struct display *)data;
3211 evdeq(&D_writeev);
3212 D_writeev.type = EV_WRITE;
3213 D_writeev.handler = disp_writeev_fn;
3214 evenq(&D_writeev);
3216 #endif
3218 static void
3219 disp_writeev_fn(ev, data)
3220 struct event *ev;
3221 char *data;
3223 int len, size = OUTPUT_BLOCK_SIZE;
3225 display = (struct display *)data;
3226 len = D_obufp - D_obuf;
3227 if (len < size)
3228 size = len;
3229 if (D_status_obufpos && size > D_status_obufpos)
3230 size = D_status_obufpos;
3231 ASSERT(len >= 0);
3232 size = write(D_userfd, D_obuf, size);
3233 if (size >= 0)
3235 len -= size;
3236 if (len)
3238 bcopy(D_obuf + size, D_obuf, len);
3239 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3241 D_obufp -= size;
3242 D_obuffree += size;
3243 if (D_status_obufpos)
3245 D_status_obufpos -= size;
3246 if (!D_status_obufpos)
3248 debug("finished writing the status message\n");
3249 /* we're finished displaying the message! */
3250 if (D_status == STATUS_ON_WIN)
3252 /* setup continue trigger */
3253 D_status_obuflen = D_obuflen;
3254 D_status_obuffree = D_obuffree;
3255 /* setting obbuffree to 0 will make AddChar call
3256 * ResizeObuf */
3257 D_obuffree = D_obuflen = 0;
3259 gettimeofday(&D_status_time, NULL);
3260 SetTimeout(&D_statusev, MsgWait);
3261 evenq(&D_statusev);
3262 #ifdef HAVE_BRAILLE
3263 RefreshBraille(); /* let user see multiple Msg()s */
3264 #endif
3267 if (D_blocked_fuzz)
3269 D_blocked_fuzz -= size;
3270 if (D_blocked_fuzz < 0)
3271 D_blocked_fuzz = 0;
3273 if (D_blockedev.queued)
3275 if (D_obufp - D_obuf > D_obufmax / 2)
3277 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3278 SetTimeout(&D_blockedev, D_nonblock);
3280 else
3282 debug1("%s: deleting blocked timeout\n", D_usertty);
3283 evdeq(&D_blockedev);
3286 if (D_blocked == 1 && D_obuf == D_obufp)
3288 /* empty again, restart output */
3289 debug1("%s: buffer empty, unblocking\n", D_usertty);
3290 D_blocked = 0;
3291 Activate(D_fore ? D_fore->w_norefresh : 0);
3292 D_blocked_fuzz = D_obufp - D_obuf;
3295 else
3297 #ifdef linux
3298 /* linux flow control is badly broken */
3299 if (errno == EAGAIN)
3301 evdeq(&D_writeev);
3302 D_writeev.type = EV_TIMEOUT;
3303 D_writeev.handler = disp_writeev_eagain;
3304 SetTimeout(&D_writeev, 100);
3305 evenq(&D_writeev);
3307 #endif
3308 if (errno != EINTR && errno != EAGAIN)
3309 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3310 if (errno != EWOULDBLOCK)
3311 #endif
3312 Msg(errno, "Error writing output to display");
3316 static void
3317 disp_readev_fn(ev, data)
3318 struct event *ev;
3319 char *data;
3321 int size;
3322 char buf[IOSIZE];
3323 struct canvas *cv;
3325 display = (struct display *)data;
3327 /* Hmmmm... a bit ugly... */
3328 if (D_forecv)
3329 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3331 display = cv->c_display;
3332 if (D_status == STATUS_ON_WIN)
3333 RemoveStatus();
3336 display = (struct display *)data;
3337 if (D_fore == 0)
3338 size = IOSIZE;
3339 else
3341 #ifdef PSEUDOS
3342 if (W_UWP(D_fore))
3343 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3344 else
3345 #endif
3346 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3349 if (size > IOSIZE)
3350 size = IOSIZE;
3351 if (size <= 0)
3352 size = 1; /* Always allow one char for command keys */
3354 size = read(D_userfd, buf, size);
3355 if (size < 0)
3357 if (errno == EINTR || errno == EAGAIN)
3358 return;
3359 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3360 if (errno == EWOULDBLOCK)
3361 return;
3362 #endif
3363 debug1("Read error: %d - hangup!\n", errno);
3364 Hangup();
3365 sleep(1);
3366 return;
3368 else if (size == 0)
3370 debug("Found EOF - hangup!\n");
3371 Hangup();
3372 sleep(1);
3373 return;
3375 if (D_blocked == 4)
3377 D_blocked = 0;
3378 #ifdef BLANKER_PRG
3379 KillBlanker();
3380 #endif
3381 Activate(D_fore ? D_fore->w_norefresh : 0);
3382 ResetIdle();
3383 return;
3385 #ifdef ZMODEM
3386 if (D_blocked > 1) /* 2, 3 */
3388 char *bufp;
3389 struct win *p;
3391 flayer = 0;
3392 for (p = windows; p ; p = p->w_next)
3393 if (p->w_zdisplay == display)
3395 flayer = &p->w_layer;
3396 bufp = buf;
3397 while (size > 0)
3398 LayProcess(&bufp, &size);
3399 return;
3401 debug("zmodem window gone, deblocking display");
3402 zmodem_abort(0, display);
3404 #endif
3405 if (idletimo > 0)
3406 ResetIdle();
3407 if (D_fore)
3408 D_fore->w_lastdisp = display;
3409 if (D_mouse && D_forecv)
3411 unsigned char *bp = (unsigned char *)buf;
3412 int x, y, i = size;
3414 /* XXX this assumes that the string is read in as a whole... */
3415 for (i = size; i > 0; i--, bp++)
3417 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3419 bp++;
3420 i--;
3422 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3423 continue;
3424 x = bp[3] - 33;
3425 y = bp[4] - 33;
3426 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
3428 if ((D_fore && D_fore->w_mouse) || (D_mousetrack && D_forecv->c_layer->l_mode == 1))
3430 /* Send clicks only if the window is expecting clicks */
3431 x -= D_forecv->c_xoff;
3432 y -= D_forecv->c_yoff;
3433 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
3435 bp[3] = x + 33;
3436 bp[4] = y + 33;
3437 i -= 4;
3438 bp += 4;
3439 continue;
3443 else if (D_mousetrack && bp[2] == '#')
3445 /* 'focus' to the clicked region, only on mouse up */
3446 struct canvas *cv = FindCanvas(x, y);
3447 if (cv)
3449 SetForeCanvas(display, cv);
3450 /* XXX: Do we want to reset the input buffer? */
3453 if (bp[0] == '[')
3455 bcopy((char *)bp + 1, (char *)bp, i);
3456 bp--;
3457 size--;
3459 if (i > 5)
3460 bcopy((char *)bp + 5, (char *)bp, i - 5);
3461 bp--;
3462 i -= 4;
3463 size -= 5;
3466 #ifdef ENCODINGS
3467 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
3469 int i, j, c, enc;
3470 char buf2[IOSIZE * 2 + 10];
3471 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
3472 for (i = j = 0; i < size; i++)
3474 c = ((unsigned char *)buf)[i];
3475 c = DecodeChar(c, D_encoding, &D_decodestate);
3476 if (c == -2)
3477 i--; /* try char again */
3478 if (c < 0)
3479 continue;
3480 if (pastefont)
3482 int font = 0;
3483 j += EncodeChar(buf2 + j, c, enc, &font);
3484 j += EncodeChar(buf2 + j, -1, enc, &font);
3486 else
3487 j += EncodeChar(buf2 + j, c, enc, 0);
3488 if (j > (int)sizeof(buf2) - 10) /* just in case... */
3489 break;
3491 (*D_processinput)(buf2, j);
3492 return;
3494 #endif
3495 (*D_processinput)(buf, size);
3498 static void
3499 disp_status_fn(ev, data)
3500 struct event *ev;
3501 char *data;
3503 display = (struct display *)data;
3504 debug1("disp_status_fn for display %x\n", (int)display);
3505 if (D_status)
3506 RemoveStatus();
3509 static void
3510 disp_hstatus_fn(ev, data)
3511 struct event *ev;
3512 char *data;
3514 display = (struct display *)data;
3515 if (D_status == STATUS_ON_HS)
3517 SetTimeout(ev, 1);
3518 evenq(ev);
3519 return;
3521 RefreshHStatus();
3524 static void
3525 disp_blocked_fn(ev, data)
3526 struct event *ev;
3527 char *data;
3529 struct win *p;
3531 display = (struct display *)data;
3532 debug1("blocked timeout %s\n", D_usertty);
3533 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
3535 debug("stopping output to display\n");
3536 D_blocked = 1;
3537 /* re-enable all windows */
3538 for (p = windows; p; p = p->w_next)
3539 if (p->w_readev.condneg == &D_obuflenmax)
3541 debug1("freeing window #%d\n", p->w_number);
3542 p->w_readev.condpos = p->w_readev.condneg = 0;
3547 #ifdef MAPKEYS
3548 static void
3549 disp_map_fn(ev, data)
3550 struct event *ev;
3551 char *data;
3553 char *p;
3554 int l, i;
3555 unsigned char *q;
3556 display = (struct display *)data;
3557 debug("Flushing map sequence\n");
3558 if (!(l = D_seql))
3559 return;
3560 p = (char *)D_seqp - l;
3561 D_seqp = D_kmaps + 3;
3562 D_seql = 0;
3563 if ((q = D_seqh) != 0)
3565 D_seqh = 0;
3566 i = q[0] << 8 | q[1];
3567 i &= ~KMAP_NOTIMEOUT;
3568 debug1("Mapping former hit #%d - ", i);
3569 debug2("%d(%s) - ", q[2], q + 3);
3570 if (StuffKey(i))
3571 ProcessInput2((char *)q + 3, q[2]);
3572 if (display == 0)
3573 return;
3574 l -= q[2];
3575 p += q[2];
3577 else
3578 D_dontmap = 1;
3579 ProcessInput(p, l);
3581 #endif
3583 static void
3584 disp_idle_fn(ev, data)
3585 struct event *ev;
3586 char *data;
3588 struct display *olddisplay;
3589 display = (struct display *)data;
3590 debug("idle timeout\n");
3591 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
3592 return;
3593 olddisplay = display;
3594 flayer = D_forecv->c_layer;
3595 fore = D_fore;
3596 DoAction(&idleaction, -1);
3597 if (idleaction.nr == RC_BLANKER)
3598 return;
3599 for (display = displays; display; display = display->d_next)
3600 if (olddisplay == display)
3601 break;
3602 if (display)
3603 ResetIdle();
3606 void
3607 ResetIdle()
3609 if (idletimo > 0)
3611 SetTimeout(&D_idleev, idletimo);
3612 if (!D_idleev.queued)
3613 evenq(&D_idleev);
3615 else
3616 evdeq(&D_idleev);
3620 #ifdef BLANKER_PRG
3622 static void
3623 disp_blanker_fn(ev, data)
3624 struct event *ev;
3625 char *data;
3627 char buf[IOSIZE], *b;
3628 int size;
3630 display = (struct display *)data;
3631 size = read(D_blankerev.fd, buf, IOSIZE);
3632 if (size <= 0)
3634 evdeq(&D_blankerev);
3635 close(D_blankerev.fd);
3636 D_blankerev.fd = -1;
3637 return;
3639 for (b = buf; size; size--)
3640 AddChar(*b++);
3643 void
3644 KillBlanker()
3646 int oldtop = D_top, oldbot = D_bot;
3647 struct mchar oldrend;
3649 if (D_blankerev.fd == -1)
3650 return;
3651 if (D_blocked == 4)
3652 D_blocked = 0;
3653 evdeq(&D_blankerev);
3654 close(D_blankerev.fd);
3655 D_blankerev.fd = -1;
3656 Kill(D_blankerpid, SIGHUP);
3657 D_top = D_bot = -1;
3658 oldrend = D_rend;
3659 if (D_ME)
3661 AddCStr(D_ME);
3662 AddCStr(D_ME);
3664 else
3666 #ifdef COLOR
3667 if (D_hascolor)
3668 AddStr("\033[m\033[m"); /* why is D_ME not set? */
3669 #endif
3670 AddCStr(D_SE);
3671 AddCStr(D_UE);
3673 AddCStr(D_VE);
3674 AddCStr(D_CE0);
3675 D_rend = mchar_null;
3676 D_atyp = 0;
3677 D_curvis = 0;
3678 D_x = D_y = -1;
3679 ChangeScrollRegion(oldtop, oldbot);
3680 SetRendition(&oldrend);
3681 ClearAll();
3684 void
3685 RunBlanker(cmdv)
3686 char **cmdv;
3688 char *m;
3689 int pid;
3690 int slave = -1;
3691 char termname[30];
3692 #ifndef TIOCSWINSZ
3693 char libuf[20], cobuf[20];
3694 #endif
3695 char **np;
3697 strcpy(termname, "TERM=");
3698 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
3699 termname[sizeof(termname) - 1] = 0;
3700 KillBlanker();
3701 D_blankerpid = -1;
3702 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
3704 Msg(0, "OpenPty failed");
3705 return;
3707 #ifdef O_NOCTTY
3708 if (pty_preopen)
3710 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
3712 Msg(errno, "%s", m);
3713 close(D_blankerev.fd);
3714 D_blankerev.fd = -1;
3715 return;
3718 #endif
3719 switch (pid = (int)fork())
3721 case -1:
3722 Msg(errno, "fork");
3723 close(D_blankerev.fd);
3724 D_blankerev.fd = -1;
3725 return;
3726 case 0:
3727 displays = 0;
3728 #ifdef DEBUG
3729 if (dfp && dfp != stderr)
3731 fclose(dfp);
3732 dfp = 0;
3734 #endif
3735 if (setgid(real_gid) || setuid(real_uid))
3736 Panic(errno, "setuid/setgid");
3737 brktty(D_userfd);
3738 freetty();
3739 close(0);
3740 close(1);
3741 close(2);
3742 closeallfiles(slave);
3743 if (open(m, O_RDWR))
3744 Panic(errno, "Cannot open %s", m);
3745 dup(0);
3746 dup(0);
3747 if (slave != -1)
3748 close(slave);
3749 InitPTY(0);
3750 fgtty(0);
3751 SetTTY(0, &D_OldMode);
3752 np = NewEnv + 3;
3753 *np++ = NewEnv[0];
3754 *np++ = termname;
3755 #ifdef TIOCSWINSZ
3756 glwz.ws_col = D_width;
3757 glwz.ws_row = D_height;
3758 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
3759 #else
3760 sprintf(libuf, "LINES=%d", D_height);
3761 sprintf(cobuf, "COLUMNS=%d", D_width);
3762 *np++ = libuf;
3763 *np++ = cobuf;
3764 #endif
3765 #ifdef SIGPIPE
3766 signal(SIGPIPE, SIG_DFL);
3767 #endif
3768 display = 0;
3769 execvpe(*cmdv, cmdv, NewEnv + 3);
3770 Panic(errno, "%s", *cmdv);
3771 default:
3772 break;
3774 D_blankerpid = pid;
3775 evenq(&D_blankerev);
3776 D_blocked = 4;
3777 ClearAll();
3780 #endif /* BLANKER_PRG */