Handle the '2' code for OSC.
[screen-lua.git] / src / display.c
blob87363ab665ada3fbee0e57fa6c0915a12859dc06
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
206 /*ARGSUSED*/
207 static int
208 BlankResize(wi, he)
209 int wi, he;
211 flayer->l_width = wi;
212 flayer->l_height = he;
213 return 0;
218 * Generate new display, start with a blank layer.
219 * The termcap arrays are not initialised here.
220 * The new display is placed in the displays list.
223 struct display *
224 MakeDisplay(uname, utty, term, fd, pid, Mode)
225 char *uname, *utty, *term;
226 int fd, pid;
227 struct mode *Mode;
229 struct acluser **u;
230 struct baud_values *b;
232 if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
233 return 0; /* could not find or add user */
235 #ifdef MULTI
236 if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
237 return 0;
238 #else
239 if (displays)
240 return 0;
241 bzero((char *)&TheDisplay, sizeof(TheDisplay));
242 display = &TheDisplay;
243 #endif
244 display->d_next = displays;
245 displays = display;
246 D_flow = 1;
247 D_nonblock = defnonblock;
248 D_userfd = fd;
249 D_readev.fd = D_writeev.fd = fd;
250 D_readev.type = EV_READ;
251 D_writeev.type = EV_WRITE;
252 D_readev.data = D_writeev.data = (char *)display;
253 D_readev.handler = disp_readev_fn;
254 D_writeev.handler = disp_writeev_fn;
255 evenq(&D_readev);
256 D_writeev.condpos = &D_obuflen;
257 D_writeev.condneg = &D_obuffree;
258 evenq(&D_writeev);
259 D_statusev.type = EV_TIMEOUT;
260 D_statusev.data = (char *)display;
261 D_statusev.handler = disp_status_fn;
262 D_hstatusev.type = EV_TIMEOUT;
263 D_hstatusev.data = (char *)display;
264 D_hstatusev.handler = disp_hstatus_fn;
265 D_blockedev.type = EV_TIMEOUT;
266 D_blockedev.data = (char *)display;
267 D_blockedev.handler = disp_blocked_fn;
268 D_blockedev.condpos = &D_obuffree;
269 D_blockedev.condneg = &D_obuflenmax;
270 D_hstatusev.handler = disp_hstatus_fn;
271 #ifdef MAPKEYS
272 D_mapev.type = EV_TIMEOUT;
273 D_mapev.data = (char *)display;
274 D_mapev.handler = disp_map_fn;
275 #endif
276 D_idleev.type = EV_TIMEOUT;
277 D_idleev.data = (char *)display;
278 D_idleev.handler = disp_idle_fn;
279 #ifdef BLANKER_PRG
280 D_blankerev.type = EV_READ;
281 D_blankerev.data = (char *)display;
282 D_blankerev.handler = disp_blanker_fn;
283 D_blankerev.fd = -1;
284 #endif
285 D_OldMode = *Mode;
286 D_status_obuffree = -1;
287 Resize_obuf(); /* Allocate memory for buffer */
288 D_obufmax = defobuflimit;
289 D_obuflenmax = D_obuflen - D_obufmax;
290 #ifdef AUTO_NUKE
291 D_auto_nuke = defautonuke;
292 #endif
293 D_obufp = D_obuf;
294 D_printfd = -1;
295 D_userpid = pid;
297 #ifdef POSIX
298 if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
299 D_dospeed = b->idx;
300 #else
301 # ifdef TERMIO
302 if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
303 D_dospeed = b->idx;
304 # else
305 D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
306 # endif
307 #endif
308 debug1("New displays ospeed = %d\n", D_dospeed);
310 strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
311 D_usertty[sizeof(D_usertty) - 1] = 0;
312 strncpy(D_termname, term, sizeof(D_termname) - 1);
313 D_termname[sizeof(D_termname) - 1] = 0;
314 D_user = *u;
315 D_processinput = ProcessInput;
316 D_mousetrack = defmousetrack;
317 return display;
321 void
322 FreeDisplay()
324 struct win *p;
325 #ifdef MULTI
326 struct display *d, **dp;
327 #endif
329 #ifdef FONT
330 FreeTransTable();
331 #endif
332 #ifdef BLANKER_PRG
333 KillBlanker();
334 #endif
335 if (D_userfd >= 0)
337 Flush(3);
338 if (!display)
339 return;
340 SetTTY(D_userfd, &D_OldMode);
341 fcntl(D_userfd, F_SETFL, 0);
343 freetty();
344 if (D_tentry)
345 free(D_tentry);
346 D_tentry = 0;
347 if (D_processinputdata)
348 free(D_processinputdata);
349 D_processinputdata = 0;
350 D_tcinited = 0;
351 evdeq(&D_hstatusev);
352 evdeq(&D_statusev);
353 evdeq(&D_readev);
354 evdeq(&D_writeev);
355 evdeq(&D_blockedev);
356 #ifdef MAPKEYS
357 evdeq(&D_mapev);
358 if (D_kmaps)
360 free(D_kmaps);
361 D_kmaps = 0;
362 D_aseqs = 0;
363 D_nseqs = 0;
364 D_seqp = 0;
365 D_seql = 0;
366 D_seqh = 0;
368 #endif
369 evdeq(&D_idleev);
370 #ifdef BLANKER_PRG
371 evdeq(&D_blankerev);
372 #endif
373 #ifdef HAVE_BRAILLE
374 if (bd.bd_dpy == display)
376 bd.bd_start_braille = 0;
377 StartBraille();
379 #endif
381 #ifdef MULTI
382 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
383 if (d == display)
384 break;
385 ASSERT(d);
386 if (D_status_lastmsg)
387 free(D_status_lastmsg);
388 if (D_obuf)
389 free(D_obuf);
390 *dp = display->d_next;
391 #else /* MULTI */
392 ASSERT(display == displays);
393 ASSERT(display == &TheDisplay);
394 displays = 0;
395 #endif /* MULTI */
397 while (D_canvas.c_slperp)
398 FreeCanvas(D_canvas.c_slperp);
399 D_cvlist = 0;
401 for (p = windows; p; p = p->w_next)
403 if (p->w_pdisplay == display)
404 p->w_pdisplay = 0;
405 if (p->w_lastdisp == display)
406 p->w_lastdisp = 0;
407 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
408 p->w_readev.condpos = p->w_readev.condneg = 0;
410 #ifdef ZMODEM
411 for (p = windows; p; p = p->w_next)
412 if (p->w_zdisplay == display)
413 zmodem_abort(p, 0);
414 #endif
415 if (D_mousetrack)
417 D_mousetrack = 0;
418 MouseMode(0);
420 #ifdef MULTI
421 free((char *)display);
422 #endif
423 display = 0;
427 * if the adaptflag is on, we keep the size of this display, else
428 * we may try to restore our old window sizes.
430 void
431 InitTerm(adapt)
432 int adapt;
434 ASSERT(display);
435 ASSERT(D_tcinited);
436 D_top = D_bot = -1;
437 AddCStr(D_IS);
438 AddCStr(D_TI);
439 /* Check for toggle */
440 if (D_IM && strcmp(D_IM, D_EI))
441 AddCStr(D_EI);
442 D_insert = 0;
443 #ifdef MAPKEYS
444 AddCStr(D_KS);
445 AddCStr(D_CCS);
446 #else
447 /* Check for toggle */
448 if (D_KS && strcmp(D_KS, D_KE))
449 AddCStr(D_KE);
450 if (D_CCS && strcmp(D_CCS, D_CCE))
451 AddCStr(D_CCE);
452 #endif
453 D_keypad = 0;
454 D_cursorkeys = 0;
455 AddCStr(D_ME);
456 AddCStr(D_EA);
457 AddCStr(D_CE0);
458 D_rend = mchar_null;
459 D_atyp = 0;
460 if (adapt == 0)
461 ResizeDisplay(D_defwidth, D_defheight);
462 ChangeScrollRegion(0, D_height - 1);
463 D_x = D_y = 0;
464 Flush(3);
465 ClearAll();
466 debug1("we %swant to adapt all our windows to the display\n",
467 (adapt) ? "" : "don't ");
468 /* In case the size was changed by a init sequence */
469 CheckScreenSize((adapt) ? 2 : 0);
472 void
473 FinitTerm()
475 ASSERT(display);
476 #ifdef BLANKER_PRG
477 KillBlanker();
478 #endif
479 if (D_tcinited)
481 ResizeDisplay(D_defwidth, D_defheight);
482 InsertMode(0);
483 ChangeScrollRegion(0, D_height - 1);
484 KeypadMode(0);
485 CursorkeysMode(0);
486 CursorVisibility(0);
487 if (D_mousetrack)
488 D_mousetrack = 0;
489 MouseMode(0);
490 SetRendition(&mchar_null);
491 SetFlow(FLOW_NOW);
492 #ifdef MAPKEYS
493 AddCStr(D_KE);
494 AddCStr(D_CCE);
495 #endif
496 if (D_hstatus)
497 ShowHStatus((char *)0);
498 #ifdef RXVT_OSC
499 ClearAllXtermOSC();
500 #endif
501 D_x = D_y = -1;
502 GotoPos(0, D_height - 1);
503 AddChar('\r');
504 AddChar('\n');
505 AddCStr(D_TE);
507 Flush(3);
511 static void
512 INSERTCHAR(c)
513 int c;
515 ASSERT(display);
516 if (!D_insert && D_x < D_width - 1)
518 if (D_IC || D_CIC)
520 if (D_IC)
521 AddCStr(D_IC);
522 else
523 AddCStr2(D_CIC, 1);
524 RAW_PUTCHAR(c);
525 return;
527 InsertMode(1);
528 if (!D_insert)
530 RefreshLine(D_y, D_x, D_width-1, 0);
531 return;
534 RAW_PUTCHAR(c);
537 void
538 PUTCHAR(c)
539 int c;
541 ASSERT(display);
542 if (D_insert && D_x < D_width - 1)
543 InsertMode(0);
544 RAW_PUTCHAR(c);
547 void
548 PUTCHARLP(c)
549 int c;
551 if (D_x < D_width - 1)
553 if (D_insert)
554 InsertMode(0);
555 RAW_PUTCHAR(c);
556 return;
558 if (D_CLP || D_y != D_bot)
560 int y = D_y;
561 RAW_PUTCHAR(c);
562 if (D_AM && !D_CLP)
563 GotoPos(D_width - 1, y);
564 return;
566 debug("PUTCHARLP: lp_missing!\n");
567 D_lp_missing = 1;
568 D_rend.image = c;
569 D_lpchar = D_rend;
570 #ifdef DW_CHARS
571 /* XXX -> PutChar ? */
572 if (D_mbcs)
574 D_lpchar.mbcs = c;
575 D_lpchar.image = D_mbcs;
576 D_mbcs = 0;
577 D_x--;
579 #endif
583 * RAW_PUTCHAR() is for all text that will be displayed.
584 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
587 STATIC void
588 RAW_PUTCHAR(c)
589 int c;
591 ASSERT(display);
593 #ifdef FONT
594 # ifdef UTF8
595 if (D_encoding == UTF8)
597 c = (c & 255) | (unsigned char)D_rend.font << 8;
598 # ifdef DW_CHARS
599 if (D_mbcs)
601 c = D_mbcs;
602 if (D_x == D_width)
603 D_x += D_AM ? 1 : -1;
604 D_mbcs = 0;
606 else if (utf8_isdouble(c))
608 D_mbcs = c;
609 D_x++;
610 return;
612 # endif
613 if (c < 32)
615 AddCStr2(D_CS0, '0');
616 AddChar(c + 0x5f);
617 AddCStr(D_CE0);
618 goto addedutf8;
620 AddUtf8(c);
621 goto addedutf8;
623 # endif
624 # ifdef DW_CHARS
625 if (is_dw_font(D_rend.font))
627 int t = c;
628 if (D_mbcs == 0)
630 D_mbcs = c;
631 D_x++;
632 return;
634 D_x--;
635 if (D_x == D_width - 1)
636 D_x += D_AM ? 1 : -1;
637 c = D_mbcs;
638 D_mbcs = t;
640 # endif
641 # if defined(ENCODINGS) && defined(DW_CHARS)
642 if (D_encoding)
643 c = PrepareEncodedChar(c);
644 # endif
645 # ifdef DW_CHARS
646 kanjiloop:
647 # endif
648 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
649 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
650 else
651 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
652 #else /* FONT */
653 AddChar(c);
654 #endif /* FONT */
656 #ifdef UTF8
657 addedutf8:
658 #endif
659 if (++D_x >= D_width)
661 if (D_AM == 0)
662 D_x = D_width - 1;
663 else if (!D_CLP || D_x > D_width)
665 D_x -= D_width;
666 if (D_y < D_height-1 && D_y != D_bot)
667 D_y++;
670 #ifdef DW_CHARS
671 if (D_mbcs)
673 c = D_mbcs;
674 D_mbcs = 0;
675 goto kanjiloop;
677 #endif
680 static int
681 DoAddChar(c)
682 int c;
684 /* this is for ESC-sequences only (AddChar is a macro) */
685 AddChar(c);
686 return c;
689 void
690 AddCStr(s)
691 char *s;
693 if (display && s && *s)
695 ospeed = D_dospeed;
696 tputs(s, 1, DoAddChar);
700 void
701 AddCStr2(s, c)
702 char *s;
703 int c;
705 if (display && s && *s)
707 ospeed = D_dospeed;
708 tputs(tgoto(s, 0, c), 1, DoAddChar);
713 /* Insert mode is a toggle on some terminals, so we need this hack:
715 void
716 InsertMode(on)
717 int on;
719 if (display && on != D_insert && D_IM)
721 D_insert = on;
722 if (on)
723 AddCStr(D_IM);
724 else
725 AddCStr(D_EI);
729 /* ...and maybe keypad application mode is a toggle, too:
731 void
732 KeypadMode(on)
733 int on;
735 #ifdef MAPKEYS
736 if (display)
737 D_keypad = on;
738 #else
739 if (display && D_keypad != on && D_KS)
741 D_keypad = on;
742 if (on)
743 AddCStr(D_KS);
744 else
745 AddCStr(D_KE);
747 #endif
750 void
751 CursorkeysMode(on)
752 int on;
754 #ifdef MAPKEYS
755 if (display)
756 D_cursorkeys = on;
757 #else
758 if (display && D_cursorkeys != on && D_CCS)
760 D_cursorkeys = on;
761 if (on)
762 AddCStr(D_CCS);
763 else
764 AddCStr(D_CCE);
766 #endif
769 void
770 ReverseVideo(on)
771 int on;
773 if (display && D_revvid != on && D_CVR)
775 D_revvid = on;
776 if (D_revvid)
777 AddCStr(D_CVR);
778 else
779 AddCStr(D_CVN);
783 void
784 CursorVisibility(v)
785 int v;
787 if (display && D_curvis != v)
789 if (D_curvis)
790 AddCStr(D_VE); /* do this always, just to be safe */
791 D_curvis = 0;
792 if (v == -1 && D_VI)
793 AddCStr(D_VI);
794 else if (v == 1 && D_VS)
795 AddCStr(D_VS);
796 else
797 return;
798 D_curvis = v;
802 void
803 MouseMode(mode)
804 int mode;
806 if (!display)
807 return;
809 if (mode < D_mousetrack)
810 mode = D_mousetrack;
812 if (D_mouse != mode)
814 char mousebuf[20];
815 if (!D_CXT)
816 return;
817 if (D_mouse)
819 sprintf(mousebuf, "\033[?%dl", D_mouse);
820 AddStr(mousebuf);
822 if (mode)
824 sprintf(mousebuf, "\033[?%dh", mode);
825 AddStr(mousebuf);
827 D_mouse = mode;
831 static int StrCost;
833 /* ARGSUSED */
834 static int
835 CountChars(c)
836 int c;
838 StrCost++;
839 return c;
843 CalcCost(s)
844 register char *s;
846 ASSERT(display);
847 if (s)
849 StrCost = 0;
850 ospeed = D_dospeed;
851 tputs(s, 1, CountChars);
852 return StrCost;
854 else
855 return EXPENSIVE;
858 static int
859 CallRewrite(y, xs, xe, doit)
860 int y, xs, xe, doit;
862 struct canvas *cv, *cvlist, *cvlnext;
863 struct viewport *vp;
864 struct layer *oldflayer;
865 int cost;
867 debug3("CallRewrite %d %d %d\n", y, xs, xe);
868 ASSERT(display);
869 ASSERT(xe >= xs);
871 vp = 0;
872 for (cv = D_cvlist; cv; cv = cv->c_next)
874 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
875 continue;
876 for (vp = cv->c_vplist; vp; vp = vp->v_next)
877 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
878 break;
879 if (vp)
880 break;
882 if (doit)
884 oldflayer = flayer;
885 flayer = cv->c_layer;
886 cvlist = flayer->l_cvlist;
887 cvlnext = cv->c_lnext;
888 flayer->l_cvlist = cv;
889 cv->c_lnext = 0;
890 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
891 flayer->l_cvlist = cvlist;
892 cv->c_lnext = cvlnext;
893 flayer = oldflayer;
894 return 0;
896 if (cv == 0 || cv->c_layer == 0)
897 return EXPENSIVE; /* not found or nothing on it */
898 if (xs < vp->v_xs || xe > vp->v_xe)
899 return EXPENSIVE; /* crosses viewport boundaries */
900 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
901 return EXPENSIVE; /* line not on layer */
902 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
903 return EXPENSIVE; /* line not on layer */
904 #ifdef UTF8
905 if (D_encoding == UTF8)
906 D_rend.font = 0;
907 #endif
908 oldflayer = flayer;
909 flayer = cv->c_layer;
910 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
911 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
912 flayer = oldflayer;
913 if (D_insert)
914 cost += D_EIcost + D_IMcost;
915 return cost;
919 void
920 GotoPos(x2, y2)
921 int x2, y2;
923 register int dy, dx, x1, y1;
924 register int costx, costy;
925 register int m;
926 register char *s;
927 int CMcost;
928 enum move_t xm = M_NONE, ym = M_NONE;
930 if (!display)
931 return;
933 x1 = D_x;
934 y1 = D_y;
936 if (x1 == D_width)
938 if (D_CLP && D_AM)
939 x1 = -1; /* don't know how the terminal treats this */
940 else
941 x1--;
943 if (x2 == D_width)
944 x2--;
945 dx = x2 - x1;
946 dy = y2 - y1;
947 if (dy == 0 && dx == 0)
948 return;
949 debug2("GotoPos (%d,%d)", x1, y1);
950 debug2(" -> (%d,%d)\n", x2, y2);
951 if (!D_MS) /* Safe to move ? */
952 SetRendition(&mchar_null);
953 if (y1 < 0 /* don't know the y position */
954 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
955 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
957 DoCM:
958 if (D_HO && !x2 && !y2)
959 AddCStr(D_HO);
960 else
961 AddCStr(tgoto(D_CM, x2, y2));
962 D_x = x2;
963 D_y = y2;
964 return;
967 /* some scrollregion implementations don't allow movements
968 * away from the region. sigh.
970 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
971 goto DoCM;
973 /* Calculate CMcost */
974 if (D_HO && !x2 && !y2)
975 s = D_HO;
976 else
977 s = tgoto(D_CM, x2, y2);
978 CMcost = CalcCost(s);
980 /* Calculate the cost to move the cursor to the right x position */
981 costx = EXPENSIVE;
982 if (x1 >= 0) /* relativ x positioning only if we know where we are */
984 if (dx > 0)
986 if (D_CRI && (dx > 1 || !D_ND))
988 costx = CalcCost(tgoto(D_CRI, 0, dx));
989 xm = M_CRI;
991 if ((m = D_NDcost * dx) < costx)
993 costx = m;
994 xm = M_RI;
996 /* Speedup: dx <= LayRewrite() */
997 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
999 costx = m;
1000 xm = M_RW;
1003 else if (dx < 0)
1005 if (D_CLE && (dx < -1 || !D_BC))
1007 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1008 xm = M_CLE;
1010 if ((m = -dx * D_LEcost) < costx)
1012 costx = m;
1013 xm = M_LE;
1016 else
1017 costx = 0;
1019 /* Speedup: LayRewrite() >= x2 */
1020 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1022 costx = m;
1023 xm = M_CR;
1026 /* Check if it is already cheaper to do CM */
1027 if (costx >= CMcost)
1028 goto DoCM;
1030 /* Calculate the cost to move the cursor to the right y position */
1031 costy = EXPENSIVE;
1032 if (dy > 0)
1034 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1036 costy = CalcCost(tgoto(D_CDO, 0, dy));
1037 ym = M_CDO;
1039 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1041 costy = m;
1042 ym = M_DO;
1045 else if (dy < 0)
1047 if (D_CUP && (dy < -1 || !D_UP))
1049 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1050 ym = M_CUP;
1052 if ((m = -dy * D_UPcost) < costy)
1054 costy = m;
1055 ym = M_UP;
1058 else
1059 costy = 0;
1061 /* Finally check if it is cheaper to do CM */
1062 if (costx + costy >= CMcost)
1063 goto DoCM;
1065 switch (xm)
1067 case M_LE:
1068 while (dx++ < 0)
1069 AddCStr(D_BC);
1070 break;
1071 case M_CLE:
1072 AddCStr2(D_CLE, -dx);
1073 break;
1074 case M_RI:
1075 while (dx-- > 0)
1076 AddCStr(D_ND);
1077 break;
1078 case M_CRI:
1079 AddCStr2(D_CRI, dx);
1080 break;
1081 case M_CR:
1082 AddCStr(D_CR);
1083 D_x = 0;
1084 x1 = 0;
1085 /* FALLTHROUGH */
1086 case M_RW:
1087 if (x1 < x2)
1088 (void) CallRewrite(y1, x1, x2 - 1, 1);
1089 break;
1090 default:
1091 break;
1094 switch (ym)
1096 case M_UP:
1097 while (dy++ < 0)
1098 AddCStr(D_UP);
1099 break;
1100 case M_CUP:
1101 AddCStr2(D_CUP, -dy);
1102 break;
1103 case M_DO:
1104 s = (x2 == 0) ? D_NL : D_DO;
1105 while (dy-- > 0)
1106 AddCStr(s);
1107 break;
1108 case M_CDO:
1109 AddCStr2(D_CDO, dy);
1110 break;
1111 default:
1112 break;
1114 D_x = x2;
1115 D_y = y2;
1118 void
1119 ClearAll()
1121 ASSERT(display);
1122 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1125 void
1126 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1127 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1129 int y, xxe;
1130 struct canvas *cv;
1131 struct viewport *vp;
1133 debug2("Clear %d,%d", x1, y1);
1134 debug2(" %d-%d", xs, xe);
1135 debug2(" %d,%d", x2, y2);
1136 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1137 ASSERT(display);
1138 if (x1 == D_width)
1139 x1--;
1140 if (x2 == D_width)
1141 x2--;
1142 if (xs == -1)
1143 xs = x1;
1144 if (xe == -1)
1145 xe = x2;
1146 if (D_UT) /* Safe to erase ? */
1147 SetRendition(&mchar_null);
1148 #ifdef COLOR
1149 if (D_BE)
1150 SetBackColor(bce);
1151 #endif
1152 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1154 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1155 D_lp_missing = 0;
1157 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1159 #ifdef AUTO_NUKE
1160 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1161 NukePending();
1162 #endif
1163 if (x1 == 0 && y1 == 0 && D_CL)
1165 AddCStr(D_CL);
1166 D_y = D_x = 0;
1167 return;
1170 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1171 * is also appropriate.
1173 if (D_CD && (y1 < y2 || !D_CE))
1175 GotoPos(x1, y1);
1176 AddCStr(D_CD);
1177 return;
1180 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1182 GotoPos(x1, y1);
1183 AddCStr(D_CCD);
1184 return;
1186 xxe = xe;
1187 for (y = y1; y <= y2; y++, x1 = xs)
1189 if (y == y2)
1190 xxe = x2;
1191 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1193 GotoPos(xxe, y);
1194 AddCStr(D_CB);
1195 continue;
1197 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1199 GotoPos(x1, y);
1200 AddCStr(D_CE);
1201 continue;
1203 if (uselayfn)
1205 vp = 0;
1206 for (cv = D_cvlist; cv; cv = cv->c_next)
1208 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1209 continue;
1210 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1211 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1212 break;
1213 if (vp)
1214 break;
1216 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1217 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1218 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1220 struct layer *oldflayer = flayer;
1221 struct canvas *cvlist, *cvlnext;
1222 flayer = cv->c_layer;
1223 cvlist = flayer->l_cvlist;
1224 cvlnext = cv->c_lnext;
1225 flayer->l_cvlist = cv;
1226 cv->c_lnext = 0;
1227 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1228 flayer->l_cvlist = cvlist;
1229 cv->c_lnext = cvlnext;
1230 flayer = oldflayer;
1231 continue;
1234 ClearLine((struct mline *)0, y, x1, xxe, bce);
1240 * if cur_only > 0, we only redisplay current line, as a full refresh is
1241 * too expensive over a low baud line.
1243 void
1244 Redisplay(cur_only)
1245 int cur_only;
1247 ASSERT(display);
1249 /* XXX do em all? */
1250 InsertMode(0);
1251 ChangeScrollRegion(0, D_height - 1);
1252 KeypadMode(0);
1253 CursorkeysMode(0);
1254 CursorVisibility(0);
1255 MouseMode(0);
1256 SetRendition(&mchar_null);
1257 SetFlow(FLOW_NOW);
1259 ClearAll();
1260 #ifdef RXVT_OSC
1261 RefreshXtermOSC();
1262 #endif
1263 if (cur_only > 0 && D_fore)
1264 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1265 else
1266 RefreshAll(1);
1267 RefreshHStatus();
1268 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1271 void
1272 RedisplayDisplays(cur_only)
1273 int cur_only;
1275 struct display *olddisplay = display;
1276 for (display = displays; display; display = display->d_next)
1277 Redisplay(cur_only);
1278 display = olddisplay;
1282 /* XXX: use oml! */
1283 void
1284 ScrollH(y, xs, xe, n, bce, oml)
1285 int y, xs, xe, n, bce;
1286 struct mline *oml;
1288 int i;
1290 if (n == 0)
1291 return;
1292 if (xe != D_width - 1)
1294 RefreshLine(y, xs, xe, 0);
1295 /* UpdateLine(oml, y, xs, xe); */
1296 return;
1298 GotoPos(xs, y);
1299 if (D_UT)
1300 SetRendition(&mchar_null);
1301 #ifdef COLOR
1302 if (D_BE)
1303 SetBackColor(bce);
1304 #endif
1305 if (n > 0)
1307 if (n >= xe - xs + 1)
1308 n = xe - xs + 1;
1309 if (D_CDC && !(n == 1 && D_DC))
1310 AddCStr2(D_CDC, n);
1311 else if (D_DC)
1313 for (i = n; i--; )
1314 AddCStr(D_DC);
1316 else
1318 RefreshLine(y, xs, xe, 0);
1319 /* UpdateLine(oml, y, xs, xe); */
1320 return;
1323 else
1325 if (-n >= xe - xs + 1)
1326 n = -(xe - xs + 1);
1327 if (!D_insert)
1329 if (D_CIC && !(n == -1 && D_IC))
1330 AddCStr2(D_CIC, -n);
1331 else if (D_IC)
1333 for (i = -n; i--; )
1334 AddCStr(D_IC);
1336 else if (D_IM)
1338 InsertMode(1);
1339 SetRendition(&mchar_null);
1340 #ifdef COLOR
1341 SetBackColor(bce);
1342 #endif
1343 for (i = -n; i--; )
1344 INSERTCHAR(' ');
1345 bce = 0; /* all done */
1347 else
1349 /* UpdateLine(oml, y, xs, xe); */
1350 RefreshLine(y, xs, xe, 0);
1351 return;
1354 else
1356 SetRendition(&mchar_null);
1357 #ifdef COLOR
1358 SetBackColor(bce);
1359 #endif
1360 for (i = -n; i--; )
1361 INSERTCHAR(' ');
1362 bce = 0; /* all done */
1365 if (bce && !D_BE)
1367 if (n > 0)
1368 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
1369 else
1370 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
1372 if (D_lp_missing && y == D_bot)
1374 if (n > 0)
1375 WriteLP(D_width - 1 - n, y);
1376 D_lp_missing = 0;
1380 void
1381 ScrollV(xs, ys, xe, ye, n, bce)
1382 int xs, ys, xe, ye, n, bce;
1384 int i;
1385 int up;
1386 int oldtop, oldbot;
1387 int alok, dlok, aldlfaster;
1388 int missy = 0;
1390 ASSERT(display);
1391 if (n == 0)
1392 return;
1393 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
1395 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
1396 return;
1398 if (xs > D_vpxmin || xe < D_vpxmax)
1400 RefreshArea(xs, ys, xe, ye, 0);
1401 return;
1404 if (D_lp_missing)
1406 if (D_bot > ye || D_bot < ys)
1407 missy = D_bot;
1408 else
1410 missy = D_bot - n;
1411 if (missy > ye || missy < ys)
1412 D_lp_missing = 0;
1416 up = 1;
1417 if (n < 0)
1419 up = 0;
1420 n = -n;
1422 if (n >= ye - ys + 1)
1423 n = ye - ys + 1;
1425 oldtop = D_top;
1426 oldbot = D_bot;
1427 if (ys < D_top || D_bot != ye)
1428 ChangeScrollRegion(ys, ye);
1429 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
1430 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
1431 if (D_top != ys && !(alok && dlok))
1432 ChangeScrollRegion(ys, ye);
1434 if (D_lp_missing &&
1435 (oldbot != D_bot ||
1436 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
1438 WriteLP(D_width - 1, oldbot);
1439 if (oldbot == D_bot) /* have scrolled */
1441 if (--n == 0)
1443 /* XXX
1444 ChangeScrollRegion(oldtop, oldbot);
1446 if (bce && !D_BE)
1447 ClearLine((struct mline *)0, ye, xs, xe, bce);
1448 return;
1453 if (D_UT)
1454 SetRendition(&mchar_null);
1455 #ifdef COLOR
1456 if (D_BE)
1457 SetBackColor(bce);
1458 #endif
1460 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
1462 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
1464 if (up)
1466 GotoPos(0, ye);
1467 for(i = n; i-- > 0; )
1468 AddCStr(D_NL); /* was SF, I think NL is faster */
1470 else
1472 GotoPos(0, ys);
1473 for(i = n; i-- > 0; )
1474 AddCStr(D_SR);
1477 else if (alok && dlok)
1479 if (up || ye != D_bot)
1481 GotoPos(0, up ? ys : ye+1-n);
1482 if (D_CDL && !(n == 1 && D_DL))
1483 AddCStr2(D_CDL, n);
1484 else
1485 for(i = n; i--; )
1486 AddCStr(D_DL);
1488 if (!up || ye != D_bot)
1490 GotoPos(0, up ? ye+1-n : ys);
1491 if (D_CAL && !(n == 1 && D_AL))
1492 AddCStr2(D_CAL, n);
1493 else
1494 for(i = n; i--; )
1495 AddCStr(D_AL);
1498 else
1500 RefreshArea(xs, ys, xe, ye, 0);
1501 return;
1503 if (bce && !D_BE)
1505 if (up)
1506 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
1507 else
1508 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
1510 if (D_lp_missing && missy != D_bot)
1511 WriteLP(D_width - 1, missy);
1512 /* XXX
1513 ChangeScrollRegion(oldtop, oldbot);
1514 if (D_lp_missing && missy != D_bot)
1515 WriteLP(D_width - 1, missy);
1519 void
1520 SetAttr(new)
1521 register int new;
1523 register int i, j, old, typ;
1525 if (!display || (old = D_rend.attr) == new)
1526 return;
1527 #ifdef COLORS16
1528 D_col16change = (old ^ new) & (A_BFG | A_BBG);
1529 new ^= D_col16change;
1530 if (old == new)
1531 return;
1532 #endif
1533 #if defined(TERMINFO) && defined(USE_SGR)
1534 if (D_SA)
1536 char *tparm();
1537 SetFont(ASCII);
1538 ospeed = D_dospeed;
1539 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
1540 new & A_DI, new & A_BD, 0 , 0 ,
1541 0), 1, DoAddChar);
1542 D_rend.attr = new;
1543 D_atyp = 0;
1544 # ifdef COLOR
1545 if (D_hascolor)
1546 rend_setdefault(&D_rend);
1547 # endif
1548 return;
1550 #endif
1551 D_rend.attr = new;
1552 typ = D_atyp;
1553 if ((new & old) != old)
1555 if ((typ & ATYP_U))
1556 AddCStr(D_UE);
1557 if ((typ & ATYP_S))
1558 AddCStr(D_SE);
1559 if ((typ & ATYP_M))
1561 AddCStr(D_ME);
1562 #ifdef COLOR
1563 /* ansi attrib handling: \E[m resets color, too */
1564 if (D_hascolor)
1565 rend_setdefault(&D_rend);
1566 #endif
1567 #ifdef FONT
1568 if (!D_CG0)
1570 /* D_ME may also reset the alternate charset */
1571 D_rend.font = 0;
1572 # ifdef ENCODINGS
1573 D_realfont = 0;
1574 # endif
1576 #endif
1578 old = 0;
1579 typ = 0;
1581 old ^= new;
1582 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
1584 if ((old & j) == 0)
1585 continue;
1586 old ^= j;
1587 if (D_attrtab[i])
1589 AddCStr(D_attrtab[i]);
1590 typ |= D_attrtyp[i];
1593 D_atyp = typ;
1596 #ifdef FONT
1597 void
1598 SetFont(new)
1599 int new;
1601 int old = D_rend.font;
1602 if (!display || old == new)
1603 return;
1604 D_rend.font = new;
1605 #ifdef ENCODINGS
1606 if (D_encoding && CanEncodeFont(D_encoding, new))
1607 return;
1608 if (new == D_realfont)
1609 return;
1610 D_realfont = new;
1611 #endif
1612 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
1613 D_xtable[(int)(unsigned char)new][256])
1615 AddCStr(D_xtable[(int)(unsigned char)new][256]);
1616 return;
1619 if (!D_CG0 && new != '0')
1621 new = ASCII;
1622 if (old == new)
1623 return;
1626 if (new == ASCII)
1627 AddCStr(D_CE0);
1628 #ifdef DW_CHARS
1629 else if (new < ' ')
1631 AddStr("\033$");
1632 if (new > 2)
1633 AddChar('(');
1634 AddChar(new + '@');
1636 #endif
1637 else
1638 AddCStr2(D_CS0, new);
1640 #endif
1642 #ifdef COLOR
1645 color256to16(jj)
1646 int jj;
1648 int min, max;
1649 int r, g, b;
1651 if (jj >= 232)
1653 jj = (jj - 232) / 6;
1654 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
1656 else if (jj >= 16)
1658 jj -= 16;
1659 r = jj / 36;
1660 g = (jj / 6) % 6;
1661 b = jj % 6;
1662 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
1663 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
1664 if (min == max)
1665 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
1666 else
1667 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
1668 min) / (max - min) | (max > 3 ? 8 : 0);
1670 return jj;
1673 #ifdef COLORS256
1675 color256to88(jj)
1676 int jj;
1678 int r, g, b;
1680 if (jj >= 232)
1681 return (jj - 232) / 3 + 80;
1682 if (jj >= 16)
1684 jj -= 16;
1685 r = jj / 36;
1686 g = (jj / 6) % 6;
1687 b = jj % 6;
1688 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
1690 return jj;
1692 #endif
1694 void
1695 SetColor(f, b)
1696 int f, b;
1698 int of, ob;
1699 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
1701 if (!display)
1702 return;
1704 of = rend_getfg(&D_rend);
1705 ob = rend_getbg(&D_rend);
1707 #ifdef COLORS16
1708 /* intense default not invented yet */
1709 if (f == 0x100)
1710 f = 0;
1711 if (b == 0x100)
1712 b = 0;
1713 #endif
1714 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
1715 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
1716 debug2("(%d %d", of, ob);
1717 debug2(" -> %d %d)\n", f, b);
1719 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
1721 if (D_OP)
1722 AddCStr(D_OP);
1723 else
1725 int oattr;
1726 oattr = D_rend.attr;
1727 AddCStr(D_ME ? D_ME : "\033[m");
1728 #ifdef FONT
1729 if (D_ME && !D_CG0)
1731 /* D_ME may also reset the alternate charset */
1732 D_rend.font = 0;
1733 # ifdef ENCODINGS
1734 D_realfont = 0;
1735 # endif
1737 #endif
1738 D_atyp = 0;
1739 D_rend.attr = 0;
1740 SetAttr(oattr);
1742 of = ob = 0;
1744 rend_setfg(&D_rend, f);
1745 rend_setbg(&D_rend, b);
1746 #ifdef COLORS16
1747 D_col16change = 0;
1748 #endif
1749 if (!D_hascolor)
1750 return;
1751 f = f ? coli2e(f) : -1;
1752 b = b ? coli2e(b) : -1;
1753 of = of ? coli2e(of) : -1;
1754 ob = ob ? coli2e(ob) : -1;
1755 #ifdef COLORS256
1756 if (f != of && f > 15 && D_CCO != 256)
1757 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
1758 if (f != of && f > 15 && D_CAF)
1760 AddCStr2(D_CAF, f);
1761 of = f;
1763 if (b != ob && b > 15 && D_CCO != 256)
1764 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
1765 if (b != ob && b > 15 && D_CAB)
1767 AddCStr2(D_CAB, b);
1768 ob = b;
1770 #endif
1771 if (f != of && f != (of | 8))
1773 if (f == -1)
1774 AddCStr("\033[39m"); /* works because AX is set */
1775 else if (D_CAF)
1776 AddCStr2(D_CAF, f & 7);
1777 else if (D_CSF)
1778 AddCStr2(D_CSF, sftrans[f & 7]);
1780 if (b != ob && b != (ob | 8))
1782 if (b == -1)
1783 AddCStr("\033[49m"); /* works because AX is set */
1784 else if (D_CAB)
1785 AddCStr2(D_CAB, b & 7);
1786 else if (D_CSB)
1787 AddCStr2(D_CSB, sftrans[b & 7]);
1789 #ifdef COLORS16
1790 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
1792 # ifdef TERMINFO
1793 AddCStr2("\033[9%p1%dm", f & 7);
1794 # else
1795 AddCStr2("\033[9%dm", f & 7);
1796 # endif
1798 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
1800 # ifdef TERMINFO
1801 AddCStr2("\033[10%p1%dm", b & 7);
1802 # else
1803 AddCStr2("\033[10%dm", b & 7);
1804 # endif
1806 #endif
1809 static void
1810 SetBackColor(new)
1811 int new;
1813 if (!display)
1814 return;
1815 SetColor(rend_getfg(&D_rend), new);
1817 #endif /* COLOR */
1819 void
1820 SetRendition(mc)
1821 struct mchar *mc;
1823 if (!display)
1824 return;
1825 #ifdef COLOR
1826 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
1828 static struct mchar mmc;
1829 int i;
1830 mmc = *mc;
1831 for (i = 0; i < 8; i++)
1832 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
1834 if (mc->color == 0 && attr2color[i][3])
1835 ApplyAttrColor(attr2color[i][3], &mmc);
1836 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
1837 ApplyAttrColor(attr2color[i][2], &mmc);
1838 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
1839 ApplyAttrColor(attr2color[i][1], &mmc);
1840 else
1841 ApplyAttrColor(attr2color[i][0], &mmc);
1843 mc = &mmc;
1844 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
1846 # ifdef COLORS16
1847 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
1849 int a = mc->attr;
1850 if ((mc->attr & A_BFG) && D_MD)
1851 a |= A_BD;
1852 if ((mc->attr & A_BBG) && D_MB)
1853 a |= A_BL;
1854 if (D_rend.attr != a)
1855 SetAttr(a);
1857 else
1858 # endif /* COLORS16 */
1859 #endif /* COLOR */
1860 if (D_rend.attr != mc->attr)
1861 SetAttr(mc->attr);
1863 #ifdef COLOR
1864 if (D_rend.color != mc->color
1865 # ifdef COLORS256
1866 || D_rend.colorx != mc->colorx
1867 # endif
1868 # ifdef COLORS16
1869 || D_col16change
1870 # endif
1872 SetColor(rend_getfg(mc), rend_getbg(mc));
1873 #endif
1874 #ifdef FONT
1875 if (D_rend.font != mc->font)
1876 SetFont(mc->font);
1877 #endif
1880 void
1881 SetRenditionMline(ml, x)
1882 struct mline *ml;
1883 int x;
1885 if (!display)
1886 return;
1887 #ifdef COLOR
1888 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
1890 struct mchar mc;
1891 copy_mline2mchar(&mc, ml, x);
1892 SetRendition(&mc);
1893 return;
1895 # ifdef COLORS16
1896 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
1898 int a = ml->attr[x];
1899 if ((ml->attr[x] & A_BFG) && D_MD)
1900 a |= A_BD;
1901 if ((ml->attr[x] & A_BBG) && D_MB)
1902 a |= A_BL;
1903 if (D_rend.attr != a)
1904 SetAttr(a);
1906 else
1907 # endif /* COLORS16 */
1908 #endif /* COLOR */
1909 if (D_rend.attr != ml->attr[x])
1910 SetAttr(ml->attr[x]);
1911 #ifdef COLOR
1912 if (D_rend.color != ml->color[x]
1913 # ifdef COLORS256
1914 || D_rend.colorx != ml->colorx[x]
1915 # endif
1916 # ifdef COLORS16
1917 || D_col16change
1918 # endif
1921 struct mchar mc;
1922 copy_mline2mchar(&mc, ml, x);
1923 SetColor(rend_getfg(&mc), rend_getbg(&mc));
1925 #endif
1926 #ifdef FONT
1927 if (D_rend.font != ml->font[x])
1928 SetFont(ml->font[x]);
1929 #endif
1932 void
1933 MakeStatus(msg)
1934 char *msg;
1936 register char *s, *t;
1937 register int max;
1939 if (!display)
1940 return;
1942 if (D_blocked)
1943 return;
1944 if (!D_tcinited)
1946 debug("tc not inited, just writing msg\n");
1947 if (D_processinputdata)
1948 return; /* XXX: better */
1949 AddStr(msg);
1950 AddStr("\r\n");
1951 Flush(0);
1952 return;
1954 if (!use_hardstatus || !D_HS)
1956 max = D_width;
1957 if (D_CLP == 0)
1958 max--;
1960 else
1961 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
1962 if (D_status)
1964 /* same message? */
1965 if (strcmp(msg, D_status_lastmsg) == 0)
1967 debug("same message - increase timeout");
1968 if (!D_status_obufpos)
1969 SetTimeout(&D_statusev, MsgWait);
1970 return;
1972 RemoveStatusMinWait();
1974 for (s = t = msg; *s && t - msg < max; ++s)
1975 if (*s == BELL)
1976 AddCStr(D_BL);
1977 else if ((unsigned char)*s >= ' ' && *s != 0177)
1978 *t++ = *s;
1979 *t = '\0';
1980 if (t == msg)
1981 return;
1982 if (t - msg >= D_status_buflen)
1984 char *buf;
1985 if (D_status_lastmsg)
1986 buf = realloc(D_status_lastmsg, t - msg + 1);
1987 else
1988 buf = malloc(t - msg + 1);
1989 if (buf)
1991 D_status_lastmsg = buf;
1992 D_status_buflen = t - msg + 1;
1995 if (t - msg < D_status_buflen)
1996 strcpy(D_status_lastmsg, msg);
1997 D_status_len = t - msg;
1998 D_status_lastx = D_x;
1999 D_status_lasty = D_y;
2000 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2002 D_status = STATUS_ON_WIN;
2003 debug1("using STATLINE %d\n", STATLINE);
2004 GotoPos(0, STATLINE);
2005 SetRendition(&mchar_so);
2006 InsertMode(0);
2007 AddStr(msg);
2008 if (D_status_len < max)
2010 /* Wayne Davison: add extra space for readability */
2011 D_status_len++;
2012 SetRendition(&mchar_null);
2013 AddChar(' ');
2014 if (D_status_len < max)
2016 D_status_len++;
2017 AddChar(' ');
2018 AddChar('\b');
2020 AddChar('\b');
2022 D_x = -1;
2024 else
2026 D_status = STATUS_ON_HS;
2027 ShowHStatus(msg);
2030 D_status_obufpos = D_obufp - D_obuf;
2031 ASSERT(D_status_obufpos > 0);
2033 if (D_status == STATUS_ON_WIN)
2035 struct display *olddisplay = display;
2036 struct layer *oldflayer = flayer;
2038 /* this is copied over from RemoveStatus() */
2039 D_status = 0;
2040 GotoPos(0, STATLINE);
2041 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2042 GotoPos(D_status_lastx, D_status_lasty);
2043 flayer = D_forecv ? D_forecv->c_layer : 0;
2044 if (flayer)
2045 LaySetCursor();
2046 display = olddisplay;
2047 flayer = oldflayer;
2048 D_status = STATUS_ON_WIN;
2052 void
2053 RemoveStatus()
2055 struct display *olddisplay;
2056 struct layer *oldflayer;
2057 int where;
2059 if (!display)
2060 return;
2061 if (!(where = D_status))
2062 return;
2064 debug("RemoveStatus\n");
2065 if (D_status_obuffree >= 0)
2067 D_obuflen = D_status_obuflen;
2068 D_obuffree = D_status_obuffree;
2069 D_status_obuffree = -1;
2071 D_status = 0;
2072 D_status_obufpos = 0;
2073 D_status_bell = 0;
2074 evdeq(&D_statusev);
2075 olddisplay = display;
2076 oldflayer = flayer;
2077 if (where == STATUS_ON_WIN)
2079 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2081 GotoPos(0, STATLINE);
2082 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2083 GotoPos(D_status_lastx, D_status_lasty);
2086 else
2087 RefreshHStatus();
2088 flayer = D_forecv ? D_forecv->c_layer : 0;
2089 if (flayer)
2090 LaySetCursor();
2091 display = olddisplay;
2092 flayer = oldflayer;
2095 /* Remove the status but make sure that it is seen for MsgMinWait ms */
2096 static void
2097 RemoveStatusMinWait()
2099 /* XXX: should flush output first if D_status_obufpos is set */
2100 if (!D_status_bell && !D_status_obufpos)
2102 struct timeval now;
2103 int ti;
2104 gettimeofday(&now, NULL);
2105 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2106 if (ti < MsgMinWait)
2107 DisplaySleep1000(MsgMinWait - ti, 0);
2109 RemoveStatus();
2112 /* refresh the display's hstatus line */
2113 void
2114 ShowHStatus(str)
2115 char *str;
2117 int l, ox, oy, max;
2119 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2120 return; /* sorry, in use */
2121 if (D_blocked)
2122 return;
2124 if (D_HS && D_has_hstatus == HSTATUS_HS)
2126 if (!D_hstatus && (str == 0 || *str == 0))
2127 return;
2128 debug("ShowHStatus: using HS\n");
2129 SetRendition(&mchar_null);
2130 InsertMode(0);
2131 if (D_hstatus)
2132 AddCStr(D_DS);
2133 D_hstatus = 0;
2134 if (str == 0 || *str == 0)
2135 return;
2136 AddCStr2(D_TS, 0);
2137 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2138 if ((int)strlen(str) > max)
2139 AddStrn(str, max);
2140 else
2141 AddStr(str);
2142 AddCStr(D_FS);
2143 D_hstatus = 1;
2145 else if (D_has_hstatus == HSTATUS_LASTLINE)
2147 debug("ShowHStatus: using last line\n");
2148 ox = D_x;
2149 oy = D_y;
2150 str = str ? str : "";
2151 l = strlen(str);
2152 if (l > D_width)
2153 l = D_width;
2154 GotoPos(0, D_height - 1);
2155 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2156 PutWinMsg(str, 0, l);
2157 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2158 while (l++ < D_width)
2159 PUTCHARLP(' ');
2160 if (l < D_width)
2161 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2162 if (ox != -1 && oy != -1)
2163 GotoPos(ox, oy);
2164 D_hstatus = *str ? 1 : 0;
2165 SetRendition(&mchar_null);
2167 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2169 debug("ShowHStatus: using message\n");
2170 Msg(0, "%s", str);
2176 * Refreshes the harstatus of the fore window. Shouldn't be here...
2178 void
2179 RefreshHStatus()
2181 char *buf;
2183 evdeq(&D_hstatusev);
2184 if (D_status == STATUS_ON_HS)
2185 return;
2186 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2187 if (buf && *buf)
2189 ShowHStatus(buf);
2190 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2191 evenq(&D_hstatusev);
2193 else
2194 ShowHStatus((char *)0);
2197 /*********************************************************************/
2199 * Here come the routines that refresh an arbitrary part of the screen.
2202 void
2203 RefreshAll(isblank)
2204 int isblank;
2206 struct canvas *cv;
2208 ASSERT(display);
2209 debug("Signalling full refresh!\n");
2210 for (cv = D_cvlist; cv; cv = cv->c_next)
2212 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2213 display = cv->c_display; /* just in case! */
2215 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2218 void
2219 RefreshArea(xs, ys, xe, ye, isblank)
2220 int xs, ys, xe, ye, isblank;
2222 int y;
2223 ASSERT(display);
2224 debug2("Refresh Area: %d,%d", xs, ys);
2225 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2226 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2228 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2229 isblank = 1;
2231 for (y = ys; y <= ye; y++)
2232 RefreshLine(y, xs, xe, isblank);
2235 void
2236 RefreshLine(y, from, to, isblank)
2237 int y, from, to, isblank;
2239 struct viewport *vp, *lvp;
2240 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2241 struct layer *oldflayer;
2242 int xx, yy, l;
2243 char *buf;
2244 struct win *p;
2246 ASSERT(display);
2248 debug2("RefreshLine %d %d", y, from);
2249 debug2(" %d %d\n", to, isblank);
2251 if (D_status == STATUS_ON_WIN && y == STATLINE)
2253 if (to >= D_status_len)
2254 D_status_len = to + 1;
2255 return; /* can't refresh status */
2258 /* The following check makes plenty of sense. Unfortunately,
2259 vte-based terminals (notably gnome-terminal) experience a quirk
2260 that causes the final line not to update properly when it falls outside
2261 the scroll region; clearing the line with D_CE avoids the glitch,
2262 so we'll disable this perfectly sensible shortcut until such a time
2263 as widespread vte installations lack the glitch.
2265 See http://bugzilla.gnome.org/show_bug.cgi?id=542087 for current
2266 status of the VTE bug report, and
2267 https://savannah.gnu.org/bugs/index.php?23699 for the history from
2268 the Savannah BTS. */
2269 #if 0
2270 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2272 RefreshHStatus();
2273 return;
2275 #endif
2277 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2279 GotoPos(from, y);
2280 if (D_UT || D_BE)
2281 SetRendition(&mchar_null);
2282 AddCStr(D_CE);
2283 isblank = 1;
2285 while (from <= to)
2287 lcv = 0;
2288 lvp = 0;
2289 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2291 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2293 p = Layer2Window(cv->c_layer);
2294 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
2295 if (cv->c_captev.timeout.tv_sec)
2296 evenq(&cv->c_captev);
2297 xx = to > cv->c_xe ? cv->c_xe : to;
2298 l = strlen(buf);
2299 GotoPos(from, y);
2300 SetRendition(&mchar_so);
2301 if (l > xx - cv->c_xs + 1)
2302 l = xx - cv->c_xs + 1;
2303 PutWinMsg(buf, from - cv->c_xs, l);
2304 from = cv->c_xs + l;
2305 for (; from <= xx; from++)
2306 PUTCHARLP(' ');
2307 break;
2309 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
2311 GotoPos(from, y);
2312 SetRendition(&mchar_so);
2313 PUTCHARLP(' ');
2314 from++;
2315 break;
2317 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
2318 continue;
2319 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
2320 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
2321 for (vp = cv->c_vplist; vp; vp = vp->v_next)
2323 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
2324 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
2325 /* find leftmost overlapping vp */
2326 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))
2328 lcv = cv;
2329 lvp = vp;
2333 if (cv)
2334 continue; /* we advanced from */
2335 if (lvp == 0)
2336 break;
2337 if (from < lvp->v_xs)
2339 if (!isblank)
2340 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
2341 from = lvp->v_xs;
2344 /* call LayRedisplayLine on canvas lcv viewport lvp */
2345 yy = y - lvp->v_yoff;
2346 xx = to < lvp->v_xe ? to : lvp->v_xe;
2348 if (lcv->c_layer && yy == lcv->c_layer->l_height)
2350 GotoPos(from, y);
2351 SetRendition(&mchar_blank);
2352 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
2354 PUTCHARLP('-');
2355 from++;
2357 if (from >= lvp->v_xe + 1)
2358 continue;
2360 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
2362 if (!isblank)
2363 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
2364 from = lvp->v_xe + 1;
2365 continue;
2368 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
2369 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
2370 oldflayer = flayer;
2371 flayer = lcv->c_layer;
2372 cvlist = flayer->l_cvlist;
2373 cvlnext = lcv->c_lnext;
2374 flayer->l_cvlist = lcv;
2375 lcv->c_lnext = 0;
2376 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
2377 flayer->l_cvlist = cvlist;
2378 lcv->c_lnext = cvlnext;
2379 flayer = oldflayer;
2381 from = xx + 1;
2383 if (!isblank && from <= to)
2384 DisplayLine(&mline_null, &mline_blank, y, from, to);
2387 /*********************************************************************/
2389 /* clear lp_missing by writing the char on the screen. The
2390 * position must be safe.
2392 static void
2393 WriteLP(x2, y2)
2394 int x2, y2;
2396 struct mchar oldrend;
2398 ASSERT(display);
2399 ASSERT(D_lp_missing);
2400 oldrend = D_rend;
2401 debug2("WriteLP(%d,%d)\n", x2, y2);
2402 #ifdef DW_CHARS
2403 if (D_lpchar.mbcs)
2405 if (x2 > 0)
2406 x2--;
2407 else
2408 D_lpchar = mchar_blank;
2410 #endif
2411 /* Can't use PutChar */
2412 GotoPos(x2, y2);
2413 SetRendition(&D_lpchar);
2414 PUTCHAR(D_lpchar.image);
2415 #ifdef DW_CHARS
2416 if (D_lpchar.mbcs)
2417 PUTCHAR(D_lpchar.mbcs);
2418 #endif
2419 D_lp_missing = 0;
2420 SetRendition(&oldrend);
2423 void
2424 ClearLine(oml, y, from, to, bce)
2425 struct mline *oml;
2426 int from, to, y, bce;
2428 int x;
2429 #ifdef COLOR
2430 struct mchar bcechar;
2431 #endif
2433 debug3("ClearLine %d,%d-%d\n", y, from, to);
2434 if (D_UT) /* Safe to erase ? */
2435 SetRendition(&mchar_null);
2436 #ifdef COLOR
2437 if (D_BE)
2438 SetBackColor(bce);
2439 #endif
2440 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
2442 GotoPos(to, y);
2443 AddCStr(D_CB);
2444 return;
2446 if (to == D_width - 1 && D_CE && (!bce || D_BE))
2448 GotoPos(from, y);
2449 AddCStr(D_CE);
2450 return;
2452 if (oml == 0)
2453 oml = &mline_null;
2454 #ifdef COLOR
2455 if (!bce)
2457 DisplayLine(oml, &mline_blank, y, from, to);
2458 return;
2460 bcechar = mchar_blank;
2461 rend_setbg(&bcechar, bce);
2462 for (x = from; x <= to; x++)
2463 copy_mchar2mline(&bcechar, &mline_old, x);
2464 DisplayLine(oml, &mline_old, y, from, to);
2465 #else
2466 DisplayLine(oml, &mline_blank, y, from, to);
2467 #endif
2470 void
2471 DisplayLine(oml, ml, y, from, to)
2472 struct mline *oml, *ml;
2473 int from, to, y;
2475 register int x;
2476 int last2flag = 0, delete_lp = 0;
2478 ASSERT(display);
2479 ASSERT(y >= 0 && y < D_height);
2480 ASSERT(from >= 0 && from < D_width);
2481 ASSERT(to >= 0 && to < D_width);
2482 if (!D_CLP && y == D_bot && to == D_width - 1)
2484 if (D_lp_missing || !cmp_mline(oml, ml, to))
2486 #ifdef DW_CHARS
2487 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
2488 #else
2489 if ((D_IC || D_IM) && from < to)
2490 #endif
2492 last2flag = 1;
2493 D_lp_missing = 0;
2494 to--;
2496 else
2498 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
2499 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
2500 copy_mline2mchar(&D_lpchar, ml, to);
2503 to--;
2505 #ifdef DW_CHARS
2506 if (D_mbcs)
2508 /* finish dw-char (can happen after a wrap) */
2509 debug("DisplayLine finishing kanji\n");
2510 SetRenditionMline(ml, from);
2511 PUTCHAR(ml->image[from]);
2512 from++;
2514 #endif
2515 for (x = from; x <= to; x++)
2517 #if 0 /* no longer needed */
2518 if (x || D_x != D_width || D_y != y - 1)
2519 #endif
2521 if (x < to || x != D_width - 1 || ml->image[x + 1])
2522 if (cmp_mline(oml, ml, x))
2523 continue;
2524 GotoPos(x, y);
2526 #ifdef DW_CHARS
2527 if (dw_right(ml, x, D_encoding))
2529 x--;
2530 debug1("DisplayLine on right side of dw char- x now %d\n", x);
2531 GotoPos(x, y);
2533 if (x == to && dw_left(ml, x, D_encoding))
2534 break; /* don't start new kanji */
2535 #endif
2536 SetRenditionMline(ml, x);
2537 PUTCHAR(ml->image[x]);
2538 #ifdef DW_CHARS
2539 if (dw_left(ml, x, D_encoding))
2540 PUTCHAR(ml->image[++x]);
2541 #endif
2543 #if 0 /* not needed any longer */
2544 /* compare != 0 because ' ' can happen when clipping occures */
2545 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
2546 GotoPos(0, y + 1);
2547 #endif
2548 if (last2flag)
2550 GotoPos(x, y);
2551 SetRenditionMline(ml, x + 1);
2552 PUTCHAR(ml->image[x + 1]);
2553 GotoPos(x, y);
2554 SetRenditionMline(ml, x);
2555 INSERTCHAR(ml->image[x]);
2557 else if (delete_lp)
2559 if (D_UT)
2560 SetRendition(&mchar_null);
2561 if (D_DC)
2562 AddCStr(D_DC);
2563 else if (D_CDC)
2564 AddCStr2(D_CDC, 1);
2565 else if (D_CE)
2566 AddCStr(D_CE);
2570 void
2571 PutChar(c, x, y)
2572 struct mchar *c;
2573 int x, y;
2575 GotoPos(x, y);
2576 SetRendition(c);
2577 PUTCHARLP(c->image);
2578 #ifdef DW_CHARS
2579 if (c->mbcs)
2581 # ifdef UTF8
2582 if (D_encoding == UTF8)
2583 D_rend.font = 0;
2584 # endif
2585 PUTCHARLP(c->mbcs);
2587 #endif
2590 void
2591 InsChar(c, x, xe, y, oml)
2592 struct mchar *c;
2593 int x, xe, y;
2594 struct mline *oml;
2596 GotoPos(x, y);
2597 if (y == D_bot && !D_CLP)
2599 if (x == D_width - 1)
2601 D_lp_missing = 1;
2602 D_lpchar = *c;
2603 return;
2605 if (xe == D_width - 1)
2606 D_lp_missing = 0;
2608 if (x == xe)
2610 SetRendition(c);
2611 PUTCHARLP(c->image);
2612 return;
2614 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
2616 RefreshLine(y, x, xe, 0);
2617 GotoPos(x + 1, y);
2618 /* UpdateLine(oml, y, x, xe); */
2619 return;
2621 InsertMode(1);
2622 if (!D_insert)
2624 #ifdef DW_CHARS
2625 if (c->mbcs && D_IC)
2626 AddCStr(D_IC);
2627 if (D_IC)
2628 AddCStr(D_IC);
2629 else
2630 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
2631 #else
2632 if (D_IC)
2633 AddCStr(D_IC);
2634 else
2635 AddCStr2(D_CIC, 1);
2636 #endif
2638 SetRendition(c);
2639 RAW_PUTCHAR(c->image);
2640 #ifdef DW_CHARS
2641 if (c->mbcs)
2643 # ifdef UTF8
2644 if (D_encoding == UTF8)
2645 D_rend.font = 0;
2646 # endif
2647 if (D_x == D_width - 1)
2648 PUTCHARLP(c->mbcs);
2649 else
2650 RAW_PUTCHAR(c->mbcs);
2652 #endif
2655 void
2656 WrapChar(c, x, y, xs, ys, xe, ye, ins)
2657 struct mchar *c;
2658 int x, y;
2659 int xs, ys, xe, ye;
2660 int ins;
2662 int bce;
2664 #ifdef COLOR
2665 bce = rend_getbg(c);
2666 #else
2667 bce = 0;
2668 #endif
2669 debug("WrapChar:");
2670 debug2(" x %d y %d", x, y);
2671 debug2(" Dx %d Dy %d", D_x, D_y);
2672 debug2(" xs %d ys %d", xs, ys);
2673 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
2674 if (xs != 0 || x != D_width || !D_AM)
2676 if (y == ye)
2677 ScrollV(xs, ys, xe, ye, 1, bce);
2678 else if (y < D_height - 1)
2679 y++;
2680 if (ins)
2681 InsChar(c, xs, xe, y, 0);
2682 else
2683 PutChar(c, xs, y);
2684 return;
2686 if (y == ye) /* we have to scroll */
2688 debug("- scrolling\n");
2689 ChangeScrollRegion(ys, ye);
2690 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
2692 debug("- have to call ScrollV\n");
2693 ScrollV(xs, ys, xe, ye, 1, bce);
2694 y--;
2697 else if (y == D_bot) /* remove unusable region? */
2698 ChangeScrollRegion(0, D_height - 1);
2699 if (D_x != D_width || D_y != y)
2701 if (D_CLP && y >= 0) /* don't even try if !LP */
2702 RefreshLine(y, D_width - 1, D_width - 1, 0);
2703 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
2704 if (D_x != D_width || D_y != y) /* sorry, no bonus */
2706 if (y == ye)
2707 ScrollV(xs, ys, xe, ye, 1, bce);
2708 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
2711 debug("- writeing new char");
2712 if (y != ye && y < D_height - 1)
2713 y++;
2714 if (ins != D_insert)
2715 InsertMode(ins);
2716 if (ins && !D_insert)
2718 InsChar(c, 0, xe, y, 0);
2719 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
2720 return;
2722 D_y = y;
2723 D_x = 0;
2724 SetRendition(c);
2725 RAW_PUTCHAR(c->image);
2726 #ifdef DW_CHARS
2727 if (c->mbcs)
2729 # ifdef UTF8
2730 if (D_encoding == UTF8)
2731 D_rend.font = 0;
2732 # endif
2733 RAW_PUTCHAR(c->mbcs);
2735 #endif
2736 debug2(" -> done (%d,%d)\n", D_x, D_y);
2740 ResizeDisplay(wi, he)
2741 int wi, he;
2743 ASSERT(display);
2744 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
2745 if (D_width == wi && D_height == he)
2747 debug("ResizeDisplay: No change\n");
2748 return 0;
2750 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
2752 debug("ResizeDisplay: using Z0/Z1\n");
2753 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
2754 ChangeScreenSize(wi, D_height, 0);
2755 return (he == D_height) ? 0 : -1;
2757 if (D_CWS)
2759 debug("ResizeDisplay: using WS\n");
2760 AddCStr(tgoto(D_CWS, wi, he));
2761 ChangeScreenSize(wi, he, 0);
2762 return 0;
2764 return -1;
2767 void
2768 ChangeScrollRegion(newtop, newbot)
2769 int newtop, newbot;
2771 if (display == 0)
2772 return;
2773 if (newtop == newbot)
2774 return; /* xterm etc can't do it */
2775 if (newtop == -1)
2776 newtop = 0;
2777 if (newbot == -1)
2778 newbot = D_height - 1;
2779 if (D_CS == 0)
2781 D_top = 0;
2782 D_bot = D_height - 1;
2783 return;
2785 if (D_top == newtop && D_bot == newbot)
2786 return;
2787 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
2788 AddCStr(tgoto(D_CS, newbot, newtop));
2789 D_top = newtop;
2790 D_bot = newbot;
2791 D_y = D_x = -1; /* Just in case... */
2794 #ifdef RXVT_OSC
2795 void
2796 SetXtermOSC(i, s)
2797 int i;
2798 char *s;
2800 static char oscs[] = "0;\000\00020;\00039;\00049;\000";
2802 ASSERT(display);
2803 if (!D_CXT)
2804 return;
2805 if (!s)
2806 s = "";
2807 if (!D_xtermosc[i] && !*s)
2808 return;
2809 if (i == 0 && !*s)
2810 s = "screen"; /* always set icon name */
2811 if (i == 1 && !*s)
2812 s = ""; /* no background */
2813 if (i == 2 && !*s)
2814 s = "black"; /* black text */
2815 if (i == 3 && !*s)
2816 s = "white"; /* on white background */
2817 D_xtermosc[i] = 1;
2818 AddStr("\033]");
2819 AddStr(oscs + i * 4);
2820 AddStr(s);
2821 AddChar(7);
2824 void
2825 ClearAllXtermOSC()
2827 int i;
2828 for (i = 3; i >= 0; i--)
2829 SetXtermOSC(i, 0);
2831 #endif
2834 * Output buffering routines
2837 void
2838 AddStr(str)
2839 char *str;
2841 register char c;
2843 ASSERT(display);
2845 #ifdef UTF8
2846 if (D_encoding == UTF8)
2848 while ((c = *str++))
2849 AddUtf8((unsigned char)c);
2850 return;
2852 #endif
2853 while ((c = *str++))
2854 AddChar(c);
2857 void
2858 AddStrn(str, n)
2859 char *str;
2860 int n;
2862 register char c;
2864 ASSERT(display);
2865 #ifdef UTF8
2866 if (D_encoding == UTF8)
2868 while ((c = *str++) && n-- > 0)
2869 AddUtf8((unsigned char)c);
2871 else
2872 #endif
2873 while ((c = *str++) && n-- > 0)
2874 AddChar(c);
2875 while (n-- > 0)
2876 AddChar(' ');
2879 void
2880 Flush(progress)
2881 int progress;
2883 register int l;
2884 int wr;
2885 register char *p;
2887 ASSERT(display);
2888 l = D_obufp - D_obuf;
2889 debug1("Flush(): %d\n", l);
2890 if (l == 0)
2891 return;
2892 ASSERT(l + D_obuffree == D_obuflen);
2893 if (D_userfd < 0)
2895 D_obuffree += l;
2896 D_obufp = D_obuf;
2897 return;
2899 p = D_obuf;
2900 if (!progress)
2902 if (fcntl(D_userfd, F_SETFL, 0))
2903 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
2905 while (l)
2907 if (progress)
2909 fd_set w;
2910 FD_ZERO(&w);
2911 FD_SET(D_userfd, &w);
2912 struct timeval t;
2913 t.tv_sec = progress;
2914 t.tv_usec = 0;
2915 wr = select(FD_SETSIZE, (fd_set *)0, &w, (fd_set *)0, &t);
2916 if (wr == -1)
2918 if (errno == EINTR)
2919 continue;
2920 debug1("Warning: select failed: %d\n", errno);
2921 break;
2923 if (wr == 0)
2925 /* no progress after 3 seconds. sorry. */
2926 debug1("Warning: no progress after %d seconds\n", progress);
2927 break;
2930 wr = write(D_userfd, p, l);
2931 if (wr <= 0)
2933 if (errno == EINTR)
2934 continue;
2935 debug1("Writing to display: %d\n", errno);
2936 break;
2938 D_obuffree += wr;
2939 p += wr;
2940 l -= wr;
2942 if (l)
2943 debug1("Warning: Flush could not write %d bytes\n", l);
2944 D_obuffree += l;
2945 D_obufp = D_obuf;
2946 if (!progress)
2948 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
2949 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
2951 if (D_blocked == 1)
2952 D_blocked = 0;
2953 D_blocked_fuzz = 0;
2956 void
2957 freetty()
2959 if (D_userfd >= 0)
2960 close(D_userfd);
2961 debug1("did freetty %d\n", D_userfd);
2962 D_userfd = -1;
2963 D_obufp = 0;
2964 D_obuffree = 0;
2965 if (D_obuf)
2966 free(D_obuf);
2967 D_obuf = 0;
2968 D_obuflen = 0;
2969 D_obuflenmax = -D_obufmax;
2970 D_blocked = 0;
2971 D_blocked_fuzz = 0;
2975 * Asynchronous output routines by
2976 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
2979 void
2980 Resize_obuf()
2982 register int ind;
2984 ASSERT(display);
2985 if (D_status_obuffree >= 0)
2987 ASSERT(D_obuffree == -1);
2988 RemoveStatusMinWait();
2989 if (--D_obuffree > 0) /* redo AddChar decrement */
2990 return;
2992 if (D_obuflen && D_obuf)
2994 ind = D_obufp - D_obuf;
2995 D_obuflen += GRAIN;
2996 D_obuffree += GRAIN;
2997 D_obuf = realloc(D_obuf, D_obuflen);
2999 else
3001 ind = 0;
3002 D_obuflen = GRAIN;
3003 D_obuffree = GRAIN;
3004 D_obuf = malloc(D_obuflen);
3006 if (!D_obuf)
3007 Panic(0, "Out of memory");
3008 D_obufp = D_obuf + ind;
3009 D_obuflenmax = D_obuflen - D_obufmax;
3010 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3013 void
3014 DisplaySleep1000(n, eat)
3015 int n;
3016 int eat;
3018 char buf;
3019 fd_set r;
3020 struct timeval t;
3022 if (n <= 0)
3023 return;
3024 if (!display)
3026 debug("DisplaySleep has no display sigh\n");
3027 sleep1000(n);
3028 return;
3030 t.tv_usec = (n % 1000) * 1000;
3031 t.tv_sec = n / 1000;
3032 FD_ZERO(&r);
3033 FD_SET(D_userfd, &r);
3034 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3036 debug("display activity stopped sleep\n");
3037 if (eat)
3038 read(D_userfd, &buf, 1);
3040 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3043 #ifdef AUTO_NUKE
3044 void
3045 NukePending()
3046 {/* Nuke pending output in current display, clear screen */
3047 register int len;
3048 int oldtop = D_top, oldbot = D_bot;
3049 struct mchar oldrend;
3050 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3051 int oldcurvis = D_curvis;
3052 int oldmouse = D_mouse;
3054 oldrend = D_rend;
3055 len = D_obufp - D_obuf;
3056 debug1("NukePending: nuking %d chars\n", len);
3058 /* Throw away any output that we can... */
3059 # ifdef POSIX
3060 tcflush(D_userfd, TCOFLUSH);
3061 # else
3062 # ifdef TCFLSH
3063 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3064 # endif
3065 # endif
3067 D_obufp = D_obuf;
3068 D_obuffree += len;
3069 D_top = D_bot = -1;
3070 AddCStr(D_IS);
3071 AddCStr(D_TI);
3072 /* Turn off all attributes. (Tim MacKenzie) */
3073 if (D_ME)
3074 AddCStr(D_ME);
3075 else
3077 #ifdef COLOR
3078 if (D_hascolor)
3079 AddStr("\033[m"); /* why is D_ME not set? */
3080 #endif
3081 AddCStr(D_SE);
3082 AddCStr(D_UE);
3084 /* Check for toggle */
3085 if (D_IM && strcmp(D_IM, D_EI))
3086 AddCStr(D_EI);
3087 D_insert = 0;
3088 /* Check for toggle */
3089 #ifdef MAPKEYS
3090 if (D_KS && strcmp(D_KS, D_KE))
3091 AddCStr(D_KS);
3092 if (D_CCS && strcmp(D_CCS, D_CCE))
3093 AddCStr(D_CCS);
3094 #else
3095 if (D_KS && strcmp(D_KS, D_KE))
3096 AddCStr(D_KE);
3097 D_keypad = 0;
3098 if (D_CCS && strcmp(D_CCS, D_CCE))
3099 AddCStr(D_CCE);
3100 D_cursorkeys = 0;
3101 #endif
3102 AddCStr(D_CE0);
3103 D_rend = mchar_null;
3104 D_atyp = 0;
3105 AddCStr(D_DS);
3106 D_hstatus = 0;
3107 AddCStr(D_VE);
3108 D_curvis = 0;
3109 ChangeScrollRegion(oldtop, oldbot);
3110 SetRendition(&oldrend);
3111 KeypadMode(oldkeypad);
3112 CursorkeysMode(oldcursorkeys);
3113 CursorVisibility(oldcurvis);
3114 MouseMode(oldmouse);
3115 if (D_CWS)
3117 debug("ResizeDisplay: using WS\n");
3118 AddCStr(tgoto(D_CWS, D_width, D_height));
3120 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3122 debug("ResizeDisplay: using Z0/Z1\n");
3123 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3126 #endif /* AUTO_NUKE */
3128 #ifdef linux
3129 /* linux' select can't handle flow control, so wait 100ms if
3130 * we get EAGAIN
3132 static void
3133 disp_writeev_eagain(ev, data)
3134 struct event *ev;
3135 char *data;
3137 display = (struct display *)data;
3138 evdeq(&D_writeev);
3139 D_writeev.type = EV_WRITE;
3140 D_writeev.handler = disp_writeev_fn;
3141 evenq(&D_writeev);
3143 #endif
3145 static void
3146 disp_writeev_fn(ev, data)
3147 struct event *ev;
3148 char *data;
3150 int len, size = OUTPUT_BLOCK_SIZE;
3152 display = (struct display *)data;
3153 len = D_obufp - D_obuf;
3154 if (len < size)
3155 size = len;
3156 if (D_status_obufpos && size > D_status_obufpos)
3157 size = D_status_obufpos;
3158 ASSERT(len >= 0);
3159 size = write(D_userfd, D_obuf, size);
3160 if (size >= 0)
3162 len -= size;
3163 if (len)
3165 bcopy(D_obuf + size, D_obuf, len);
3166 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3168 D_obufp -= size;
3169 D_obuffree += size;
3170 if (D_status_obufpos)
3172 D_status_obufpos -= size;
3173 if (!D_status_obufpos)
3175 debug("finished writing the status message\n");
3176 /* we're finished displaying the message! */
3177 if (D_status == STATUS_ON_WIN)
3179 /* setup continue trigger */
3180 D_status_obuflen = D_obuflen;
3181 D_status_obuffree = D_obuffree;
3182 /* setting obbuffree to 0 will make AddChar call
3183 * ResizeObuf */
3184 D_obuffree = D_obuflen = 0;
3186 gettimeofday(&D_status_time, NULL);
3187 SetTimeout(&D_statusev, MsgWait);
3188 evenq(&D_statusev);
3189 #ifdef HAVE_BRAILLE
3190 RefreshBraille(); /* let user see multiple Msg()s */
3191 #endif
3194 if (D_blocked_fuzz)
3196 D_blocked_fuzz -= size;
3197 if (D_blocked_fuzz < 0)
3198 D_blocked_fuzz = 0;
3200 if (D_blockedev.queued)
3202 if (D_obufp - D_obuf > D_obufmax / 2)
3204 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3205 SetTimeout(&D_blockedev, D_nonblock);
3207 else
3209 debug1("%s: deleting blocked timeout\n", D_usertty);
3210 evdeq(&D_blockedev);
3213 if (D_blocked == 1 && D_obuf == D_obufp)
3215 /* empty again, restart output */
3216 debug1("%s: buffer empty, unblocking\n", D_usertty);
3217 D_blocked = 0;
3218 Activate(D_fore ? D_fore->w_norefresh : 0);
3219 D_blocked_fuzz = D_obufp - D_obuf;
3222 else
3224 #ifdef linux
3225 /* linux flow control is badly broken */
3226 if (errno == EAGAIN)
3228 evdeq(&D_writeev);
3229 D_writeev.type = EV_TIMEOUT;
3230 D_writeev.handler = disp_writeev_eagain;
3231 SetTimeout(&D_writeev, 100);
3232 evenq(&D_writeev);
3234 #endif
3235 if (errno != EINTR && errno != EAGAIN)
3236 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3237 if (errno != EWOULDBLOCK)
3238 #endif
3239 Msg(errno, "Error writing output to display");
3243 static void
3244 disp_readev_fn(ev, data)
3245 struct event *ev;
3246 char *data;
3248 int size;
3249 char buf[IOSIZE];
3250 struct canvas *cv;
3252 display = (struct display *)data;
3254 /* Hmmmm... a bit ugly... */
3255 if (D_forecv)
3256 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3258 display = cv->c_display;
3259 if (D_status == STATUS_ON_WIN)
3260 RemoveStatus();
3263 display = (struct display *)data;
3264 if (D_fore == 0)
3265 size = IOSIZE;
3266 else
3268 #ifdef PSEUDOS
3269 if (W_UWP(D_fore))
3270 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3271 else
3272 #endif
3273 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3276 if (size > IOSIZE)
3277 size = IOSIZE;
3278 if (size <= 0)
3279 size = 1; /* Always allow one char for command keys */
3281 size = read(D_userfd, buf, size);
3282 if (size < 0)
3284 if (errno == EINTR || errno == EAGAIN)
3285 return;
3286 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3287 if (errno == EWOULDBLOCK)
3288 return;
3289 #endif
3290 debug1("Read error: %d - hangup!\n", errno);
3291 Hangup();
3292 sleep(1);
3293 return;
3295 else if (size == 0)
3297 debug("Found EOF - hangup!\n");
3298 Hangup();
3299 sleep(1);
3300 return;
3302 if (D_blocked == 4)
3304 D_blocked = 0;
3305 #ifdef BLANKER_PRG
3306 KillBlanker();
3307 #endif
3308 Activate(D_fore ? D_fore->w_norefresh : 0);
3309 ResetIdle();
3310 return;
3312 #ifdef ZMODEM
3313 if (D_blocked > 1) /* 2, 3 */
3315 char *bufp;
3316 struct win *p;
3318 flayer = 0;
3319 for (p = windows; p ; p = p->w_next)
3320 if (p->w_zdisplay == display)
3322 flayer = &p->w_layer;
3323 bufp = buf;
3324 while (size > 0)
3325 LayProcess(&bufp, &size);
3326 return;
3328 debug("zmodem window gone, deblocking display");
3329 zmodem_abort(0, display);
3331 #endif
3332 if (idletimo > 0)
3333 ResetIdle();
3334 if (D_fore)
3335 D_fore->w_lastdisp = display;
3336 if (D_mouse && D_forecv)
3338 unsigned char *bp = (unsigned char *)buf;
3339 int x, y, i = size;
3341 /* XXX this assumes that the string is read in as a whole... */
3342 for (i = size; i > 0; i--, bp++)
3344 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3346 bp++;
3347 i--;
3349 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3350 continue;
3351 x = bp[3] - 33;
3352 y = bp[4] - 33;
3353 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
3355 if (D_fore && D_fore->w_mouse)
3357 /* Send clicks only if the window is expecting clicks */
3358 x -= D_forecv->c_xoff;
3359 y -= D_forecv->c_yoff;
3360 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
3362 bp[3] = x + 33;
3363 bp[4] = y + 33;
3364 i -= 4;
3365 bp += 4;
3366 continue;
3370 else if (D_mousetrack && bp[2] == '#')
3372 /* 'focus' to the clicked region, only on mouse up */
3373 struct canvas *cv = FindCanvas(x, y);
3374 if (cv)
3376 SetForeCanvas(display, cv);
3377 /* XXX: Do we want to reset the input buffer? */
3380 if (bp[0] == '[')
3382 bcopy((char *)bp + 1, (char *)bp, i);
3383 bp--;
3384 size--;
3386 if (i > 5)
3387 bcopy((char *)bp + 5, (char *)bp, i - 5);
3388 bp--;
3389 i -= 4;
3390 size -= 5;
3393 #ifdef ENCODINGS
3394 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
3396 int i, j, c, enc;
3397 char buf2[IOSIZE * 2 + 10];
3398 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
3399 for (i = j = 0; i < size; i++)
3401 c = ((unsigned char *)buf)[i];
3402 c = DecodeChar(c, D_encoding, &D_decodestate);
3403 if (c == -2)
3404 i--; /* try char again */
3405 if (c < 0)
3406 continue;
3407 if (pastefont)
3409 int font = 0;
3410 j += EncodeChar(buf2 + j, c, enc, &font);
3411 j += EncodeChar(buf2 + j, -1, enc, &font);
3413 else
3414 j += EncodeChar(buf2 + j, c, enc, 0);
3415 if (j > (int)sizeof(buf2) - 10) /* just in case... */
3416 break;
3418 (*D_processinput)(buf2, j);
3419 return;
3421 #endif
3422 (*D_processinput)(buf, size);
3425 static void
3426 disp_status_fn(ev, data)
3427 struct event *ev;
3428 char *data;
3430 display = (struct display *)data;
3431 debug1("disp_status_fn for display %x\n", (int)display);
3432 if (D_status)
3433 RemoveStatus();
3436 static void
3437 disp_hstatus_fn(ev, data)
3438 struct event *ev;
3439 char *data;
3441 display = (struct display *)data;
3442 if (D_status == STATUS_ON_HS)
3444 SetTimeout(ev, 1);
3445 evenq(ev);
3446 return;
3448 RefreshHStatus();
3451 static void
3452 disp_blocked_fn(ev, data)
3453 struct event *ev;
3454 char *data;
3456 struct win *p;
3458 display = (struct display *)data;
3459 debug1("blocked timeout %s\n", D_usertty);
3460 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
3462 debug("stopping output to display\n");
3463 D_blocked = 1;
3464 /* re-enable all windows */
3465 for (p = windows; p; p = p->w_next)
3466 if (p->w_readev.condneg == &D_obuflenmax)
3468 debug1("freeing window #%d\n", p->w_number);
3469 p->w_readev.condpos = p->w_readev.condneg = 0;
3474 #ifdef MAPKEYS
3475 static void
3476 disp_map_fn(ev, data)
3477 struct event *ev;
3478 char *data;
3480 char *p;
3481 int l, i;
3482 unsigned char *q;
3483 display = (struct display *)data;
3484 debug("Flushing map sequence\n");
3485 if (!(l = D_seql))
3486 return;
3487 p = (char *)D_seqp - l;
3488 D_seqp = D_kmaps + 3;
3489 D_seql = 0;
3490 if ((q = D_seqh) != 0)
3492 D_seqh = 0;
3493 i = q[0] << 8 | q[1];
3494 i &= ~KMAP_NOTIMEOUT;
3495 debug1("Mapping former hit #%d - ", i);
3496 debug2("%d(%s) - ", q[2], q + 3);
3497 if (StuffKey(i))
3498 ProcessInput2((char *)q + 3, q[2]);
3499 if (display == 0)
3500 return;
3501 l -= q[2];
3502 p += q[2];
3504 else
3505 D_dontmap = 1;
3506 ProcessInput(p, l);
3508 #endif
3510 static void
3511 disp_idle_fn(ev, data)
3512 struct event *ev;
3513 char *data;
3515 struct display *olddisplay;
3516 display = (struct display *)data;
3517 debug("idle timeout\n");
3518 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
3519 return;
3520 olddisplay = display;
3521 flayer = D_forecv->c_layer;
3522 fore = D_fore;
3523 DoAction(&idleaction, -1);
3524 if (idleaction.nr == RC_BLANKER)
3525 return;
3526 for (display = displays; display; display = display->d_next)
3527 if (olddisplay == display)
3528 break;
3529 if (display)
3530 ResetIdle();
3533 void
3534 ResetIdle()
3536 if (idletimo > 0)
3538 SetTimeout(&D_idleev, idletimo);
3539 if (!D_idleev.queued)
3540 evenq(&D_idleev);
3542 else
3543 evdeq(&D_idleev);
3547 #ifdef BLANKER_PRG
3549 static void
3550 disp_blanker_fn(ev, data)
3551 struct event *ev;
3552 char *data;
3554 char buf[IOSIZE], *b;
3555 int size;
3557 display = (struct display *)data;
3558 size = read(D_blankerev.fd, buf, IOSIZE);
3559 if (size <= 0)
3561 evdeq(&D_blankerev);
3562 close(D_blankerev.fd);
3563 D_blankerev.fd = -1;
3564 return;
3566 for (b = buf; size; size--)
3567 AddChar(*b++);
3570 void
3571 KillBlanker()
3573 int oldtop = D_top, oldbot = D_bot;
3574 struct mchar oldrend;
3576 if (D_blankerev.fd == -1)
3577 return;
3578 if (D_blocked == 4)
3579 D_blocked = 0;
3580 evdeq(&D_blankerev);
3581 close(D_blankerev.fd);
3582 D_blankerev.fd = -1;
3583 Kill(D_blankerpid, SIGHUP);
3584 D_top = D_bot = -1;
3585 oldrend = D_rend;
3586 if (D_ME)
3588 AddCStr(D_ME);
3589 AddCStr(D_ME);
3591 else
3593 #ifdef COLOR
3594 if (D_hascolor)
3595 AddStr("\033[m\033[m"); /* why is D_ME not set? */
3596 #endif
3597 AddCStr(D_SE);
3598 AddCStr(D_UE);
3600 AddCStr(D_VE);
3601 AddCStr(D_CE0);
3602 D_rend = mchar_null;
3603 D_atyp = 0;
3604 D_curvis = 0;
3605 D_x = D_y = -1;
3606 ChangeScrollRegion(oldtop, oldbot);
3607 SetRendition(&oldrend);
3608 ClearAll();
3611 void
3612 RunBlanker(cmdv)
3613 char **cmdv;
3615 char *m;
3616 int pid;
3617 int slave = -1;
3618 char termname[30];
3619 #ifndef TIOCSWINSZ
3620 char libuf[20], cobuf[20];
3621 #endif
3622 char **np;
3624 strcpy(termname, "TERM=");
3625 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
3626 termname[sizeof(termname) - 1] = 0;
3627 KillBlanker();
3628 D_blankerpid = -1;
3629 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
3631 Msg(0, "OpenPty failed");
3632 return;
3634 #ifdef O_NOCTTY
3635 if (pty_preopen)
3637 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
3639 Msg(errno, "%s", m);
3640 close(D_blankerev.fd);
3641 D_blankerev.fd = -1;
3642 return;
3645 #endif
3646 switch (pid = (int)fork())
3648 case -1:
3649 Msg(errno, "fork");
3650 close(D_blankerev.fd);
3651 D_blankerev.fd = -1;
3652 return;
3653 case 0:
3654 displays = 0;
3655 #ifdef DEBUG
3656 if (dfp && dfp != stderr)
3658 fclose(dfp);
3659 dfp = 0;
3661 #endif
3662 if (setgid(real_gid) || setuid(real_uid))
3663 Panic(errno, "setuid/setgid");
3664 brktty(D_userfd);
3665 freetty();
3666 close(0);
3667 close(1);
3668 close(2);
3669 closeallfiles(slave);
3670 if (open(m, O_RDWR))
3671 Panic(errno, "Cannot open %s", m);
3672 dup(0);
3673 dup(0);
3674 if (slave != -1)
3675 close(slave);
3676 InitPTY(0);
3677 fgtty(0);
3678 SetTTY(0, &D_OldMode);
3679 np = NewEnv + 3;
3680 *np++ = NewEnv[0];
3681 *np++ = termname;
3682 #ifdef TIOCSWINSZ
3683 glwz.ws_col = D_width;
3684 glwz.ws_row = D_height;
3685 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
3686 #else
3687 sprintf(libuf, "LINES=%d", D_height);
3688 sprintf(cobuf, "COLUMNS=%d", D_width);
3689 *np++ = libuf;
3690 *np++ = cobuf;
3691 #endif
3692 #ifdef SIGPIPE
3693 signal(SIGPIPE, SIG_DFL);
3694 #endif
3695 display = 0;
3696 execvpe(*cmdv, cmdv, NewEnv + 3);
3697 Panic(errno, "%s", *cmdv);
3698 default:
3699 break;
3701 D_blankerpid = pid;
3702 evenq(&D_blankerev);
3703 D_blocked = 4;
3704 ClearAll();
3707 #endif /* BLANKER_PRG */