Implement display.idle_timeout interface, currently write-only
[screen-lua.git] / src / display.c
blobb00b2a9e3945a6e4c0bb55e33d9b13590cf14b4a
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"
41 static int CountChars __P((int));
42 static int DoAddChar __P((int));
43 static int BlankResize __P((int, int));
44 static int CallRewrite __P((int, int, int, int));
45 static void FreeCanvas __P((struct canvas *));
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 FreePerp __P((struct canvas *));
69 static struct canvas *AddPerp __P((struct canvas *));
72 extern struct layer *flayer;
73 extern struct win *windows, *fore;
74 extern struct LayFuncs WinLf;
76 extern int use_hardstatus;
77 extern int MsgWait, MsgMinWait;
78 extern int Z0width, Z1width;
79 extern unsigned char *blank, *null;
80 extern struct mline mline_blank, mline_null, mline_old;
81 extern struct mchar mchar_null, mchar_blank, mchar_so;
82 extern struct NewWindow nwin_default;
83 extern struct action idleaction;
85 /* XXX shouldn't be here */
86 extern char *hstatusstring;
87 extern char *captionstring;
89 extern int pastefont;
90 extern int idletimo;
92 #ifdef BLANKER_PRG
93 extern int pty_preopen;
94 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
95 extern struct winsize glwz;
96 #endif
97 extern char **NewEnv;
98 extern int real_uid, real_gid;
99 #endif
102 * tputs needs this to calculate the padding
104 #ifndef NEED_OSPEED
105 extern
106 #endif /* NEED_OSPEED */
107 short ospeed;
110 struct display *display, *displays;
111 #ifdef COLOR
112 int attr2color[8][4];
113 int nattr2color;
114 #endif
116 #ifndef MULTI
117 struct display TheDisplay;
118 #endif
121 * The default values
123 int defobuflimit = OBUF_MAX;
124 int defnonblock = -1;
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 return display;
320 void
321 FreeDisplay()
323 struct win *p;
324 #ifdef MULTI
325 struct display *d, **dp;
326 #endif
328 #ifdef FONT
329 FreeTransTable();
330 #endif
331 #ifdef BLANKER_PRG
332 KillBlanker();
333 #endif
334 if (D_userfd >= 0)
336 Flush();
337 if (!display)
338 return;
339 SetTTY(D_userfd, &D_OldMode);
340 fcntl(D_userfd, F_SETFL, 0);
342 freetty();
343 if (D_tentry)
344 free(D_tentry);
345 D_tentry = 0;
346 if (D_processinputdata)
347 free(D_processinputdata);
348 D_processinputdata = 0;
349 D_tcinited = 0;
350 evdeq(&D_hstatusev);
351 evdeq(&D_statusev);
352 evdeq(&D_readev);
353 evdeq(&D_writeev);
354 evdeq(&D_blockedev);
355 #ifdef MAPKEYS
356 evdeq(&D_mapev);
357 if (D_kmaps)
359 free(D_kmaps);
360 D_kmaps = 0;
361 D_aseqs = 0;
362 D_nseqs = 0;
363 D_seqp = 0;
364 D_seql = 0;
365 D_seqh = 0;
367 #endif
368 evdeq(&D_idleev);
369 #ifdef BLANKER_PRG
370 evdeq(&D_blankerev);
371 #endif
372 #ifdef HAVE_BRAILLE
373 if (bd.bd_dpy == display)
375 bd.bd_start_braille = 0;
376 StartBraille();
378 #endif
380 #ifdef MULTI
381 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
382 if (d == display)
383 break;
384 ASSERT(d);
385 if (D_status_lastmsg)
386 free(D_status_lastmsg);
387 if (D_obuf)
388 free(D_obuf);
389 *dp = display->d_next;
390 #else /* MULTI */
391 ASSERT(display == displays);
392 ASSERT(display == &TheDisplay);
393 displays = 0;
394 #endif /* MULTI */
396 while (D_canvas.c_slperp)
397 FreeCanvas(D_canvas.c_slperp);
398 D_cvlist = 0;
400 for (p = windows; p; p = p->w_next)
402 if (p->w_pdisplay == display)
403 p->w_pdisplay = 0;
404 if (p->w_lastdisp == display)
405 p->w_lastdisp = 0;
406 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
407 p->w_readev.condpos = p->w_readev.condneg = 0;
409 #ifdef ZMODEM
410 for (p = windows; p; p = p->w_next)
411 if (p->w_zdisplay == display)
412 zmodem_abort(p, 0);
413 #endif
414 #ifdef MULTI
415 free((char *)display);
416 #endif
417 display = 0;
420 static void
421 CanvasInitBlank(cv)
422 struct canvas *cv;
424 cv->c_blank.l_cvlist = cv;
425 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
426 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
427 cv->c_blank.l_x = cv->c_blank.l_y = 0;
428 cv->c_blank.l_layfn = &BlankLf;
429 cv->c_blank.l_data = 0;
430 cv->c_blank.l_next = 0;
431 cv->c_blank.l_bottom = &cv->c_blank;
432 cv->c_blank.l_blocking = 0;
433 cv->c_layer = &cv->c_blank;
437 MakeDefaultCanvas()
439 struct canvas *cv;
441 ASSERT(display);
442 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
443 return -1;
444 cv->c_xs = 0;
445 cv->c_xe = D_width - 1;
446 cv->c_ys = 0;
447 cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
448 debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
449 cv->c_xoff = 0;
450 cv->c_yoff = 0;
451 cv->c_next = 0;
452 cv->c_display = display;
453 cv->c_vplist = 0;
454 cv->c_slnext = 0;
455 cv->c_slprev = 0;
456 cv->c_slperp = 0;
457 cv->c_slweight = 1;
458 cv->c_slback = &D_canvas;
459 D_canvas.c_slperp = cv;
460 D_canvas.c_xs = cv->c_xs;
461 D_canvas.c_xe = cv->c_xe;
462 D_canvas.c_ys = cv->c_ys;
463 D_canvas.c_ye = cv->c_ye;
464 cv->c_slorient = SLICE_UNKN;
465 cv->c_captev.type = EV_TIMEOUT;
466 cv->c_captev.data = (char *)cv;
467 cv->c_captev.handler = cv_winid_fn;
469 CanvasInitBlank(cv);
470 cv->c_lnext = 0;
472 D_cvlist = cv;
473 RethinkDisplayViewports();
474 D_forecv = cv; /* default input focus */
475 return 0;
478 static struct canvas **
479 CreateCanvasChainRec(cv, cvp)
480 struct canvas *cv;
481 struct canvas **cvp;
483 for (; cv; cv = cv->c_slnext)
485 if (cv->c_slperp)
486 cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
487 else
489 *cvp = cv;
490 cvp = &cv->c_next;
493 return cvp;
496 void
497 RecreateCanvasChain()
499 struct canvas **cvp;
500 cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
501 *cvp = 0;
504 static void
505 FreeCanvas(cv)
506 struct canvas *cv;
508 struct viewport *vp, *nvp;
509 struct canvas **cvp;
510 struct win *p;
512 if (cv->c_slprev)
513 cv->c_slprev->c_slnext = cv->c_slnext;
514 if (cv->c_slnext)
515 cv->c_slnext->c_slprev = cv->c_slprev;
516 if (cv->c_slback && cv->c_slback->c_slperp == cv)
517 cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
518 if (cv->c_slperp)
520 while (cv->c_slperp)
521 FreeCanvas(cv->c_slperp);
522 free(cv);
523 return;
526 if (display)
528 if (D_forecv == cv)
529 D_forecv = 0;
530 /* remove from canvas chain as SetCanvasWindow might call
531 * some layer function */
532 for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
533 if (*cvp == cv)
535 *cvp = cv->c_next;
536 break;
539 p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
540 SetCanvasWindow(cv, 0);
541 if (p)
542 WindowChanged(p, 'u');
543 if (flayer == cv->c_layer)
544 flayer = 0;
545 for (vp = cv->c_vplist; vp; vp = nvp)
547 vp->v_canvas = 0;
548 nvp = vp->v_next;
549 vp->v_next = 0;
550 free(vp);
552 evdeq(&cv->c_captev);
553 free(cv);
557 CountCanvas(cv)
558 struct canvas *cv;
560 int num = 0;
561 for (; cv; cv = cv->c_slnext)
563 if (cv->c_slperp)
565 struct canvas *cvp;
566 int nump = 1, n;
567 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
568 if (cvp->c_slperp)
570 n = CountCanvas(cvp->c_slperp);
571 if (n > nump)
572 nump = n;
574 num += nump;
576 else
577 num++;
579 return num;
583 CountCanvasPerp(cv)
584 struct canvas *cv;
586 struct canvas *cvp;
587 int num = 1, n;
588 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
589 if (cvp->c_slperp)
591 n = CountCanvas(cvp->c_slperp);
592 if (n > num)
593 num = n;
595 return num;
598 void
599 EqualizeCanvas(cv, gflag)
600 struct canvas *cv;
601 int gflag;
603 struct canvas *cv2;
604 for (; cv; cv = cv->c_slnext)
606 if (cv->c_slperp && gflag)
608 cv->c_slweight = CountCanvasPerp(cv);
609 for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
610 if (cv2->c_slperp)
611 EqualizeCanvas(cv2->c_slperp, gflag);
613 else
614 cv->c_slweight = 1;
618 void
619 ResizeCanvas(cv)
620 struct canvas *cv;
622 struct canvas *cv2, *cvn, *fcv;
623 int nh, i, maxi, hh, m, w, wsum;
624 int need, got;
625 int xs, ys, xe, ye;
626 int focusmin = 0;
628 xs = cv->c_xs;
629 ys = cv->c_ys;
630 xe = cv->c_xe;
631 ye = cv->c_ye;
632 cv = cv->c_slperp;
633 debug2("ResizeCanvas: %d,%d", xs, ys);
634 debug2(" %d,%d\n", xe, ye);
635 if (cv == 0)
636 return;
637 if (cv->c_slorient == SLICE_UNKN)
639 ASSERT(!cv->c_slnext && !cv->c_slperp);
640 cv->c_xs = xs;
641 cv->c_xe = xe;
642 cv->c_ys = ys;
643 cv->c_ye = ye;
644 cv->c_xoff = cv->c_xs;
645 cv->c_yoff = cv->c_ys;
646 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
647 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
648 return;
651 fcv = 0;
652 if (focusminwidth || focusminheight)
654 debug("searching for focus canvas\n");
655 cv2 = D_forecv;
656 while (cv2->c_slback)
658 if (cv2->c_slback == cv->c_slback)
660 fcv = cv2;
661 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
662 if (focusmin > 0)
663 focusmin--;
664 else if (focusmin < 0)
665 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
666 debug1("found, focusmin=%d\n", focusmin);
668 cv2 = cv2->c_slback;
671 if (focusmin)
673 m = CountCanvas(cv) * 2;
674 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
675 nh -= m;
676 if (nh < 0)
677 nh = 0;
678 if (focusmin > nh)
679 focusmin = nh;
680 debug1("corrected to %d\n", focusmin);
683 /* pass 1: calculate weight sum */
684 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
686 debug1(" weight %d\n", cv2->c_slweight);
687 wsum += cv2->c_slweight;
689 debug1("wsum = %d\n", wsum);
690 if (wsum == 0)
691 wsum = 1;
692 w = wsum;
694 /* pass 2: calculate need/excess space */
695 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
696 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
698 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
699 if (cv2 == fcv)
700 m += focusmin;
701 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
702 w -= cv2->c_slweight;
703 nh -= hh;
704 debug2(" should %d min %d\n", hh, m);
705 if (hh <= m + 1)
706 need += m + 1 - hh;
707 else
708 got += hh - m - 1;
710 debug2("need: %d, got %d\n", need, got);
711 if (need > got)
712 need = got;
714 /* pass 3: distribute space */
715 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
716 i = cv->c_slorient == SLICE_VERT ? ys : xs;
717 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
718 w = wsum;
719 for (; cv; cv = cvn)
721 cvn = cv->c_slnext;
722 if (i > maxi)
724 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
726 cv->c_slprev->c_slorient = SLICE_UNKN;
727 if (!captionalways)
729 cv->c_slback->c_ye++;
730 cv->c_slprev->c_ye++;
733 SetCanvasWindow(cv, 0);
734 FreeCanvas(cv);
735 continue;
737 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
738 if (cv == fcv)
739 m += focusmin;
740 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
741 w -= cv->c_slweight;
742 nh -= hh;
743 debug2(" should %d min %d\n", hh, m);
744 if (hh <= m + 1)
746 hh = m + 1;
747 debug1(" -> %d\n", hh);
749 else
751 int hx = need * (hh - m - 1) / got;
752 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
753 got -= (hh - m - 1);
754 hh -= hx;
755 need -= hx;
756 debug2(" now need=%d got=%d\n", need, got);
758 ASSERT(hh >= m + 1);
759 /* hh is window size plus pation line */
760 if (i + hh > maxi + 2)
762 hh = maxi + 2 - i;
763 debug1(" not enough space, reducing to %d\n", hh);
765 if (i + hh == maxi + 1)
767 hh++;
768 debug(" incrementing as no other canvas will fit\n");
770 if (cv->c_slorient == SLICE_VERT)
772 cv->c_xs = xs;
773 cv->c_xe = xe;
774 cv->c_ys = i;
775 cv->c_ye = i + hh - 2;
776 cv->c_xoff = xs;
777 cv->c_yoff = i;
779 else
781 cv->c_xs = i;
782 cv->c_xe = i + hh - 2;
783 cv->c_ys = ys;
784 cv->c_ye = ye;
785 cv->c_xoff = i;
786 cv->c_yoff = ys;
788 cv->c_xoff = cv->c_xs;
789 cv->c_yoff = cv->c_ys;
790 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
791 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
792 if (cv->c_slperp)
794 ResizeCanvas(cv);
795 if (!cv->c_slperp->c_slnext)
797 debug("deleting perp node\n");
798 FreePerp(cv->c_slperp);
799 FreePerp(cv);
802 i += hh;
806 static struct canvas *
807 AddPerp(cv)
808 struct canvas *cv;
810 struct canvas *pcv;
811 debug("Creating new perp node\n");
813 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
814 return 0;
815 pcv->c_next = 0;
816 pcv->c_display = cv->c_display;
817 pcv->c_slnext = cv->c_slnext;
818 pcv->c_slprev = cv->c_slprev;
819 pcv->c_slperp = cv;
820 pcv->c_slback = cv->c_slback;
821 if (cv->c_slback && cv->c_slback->c_slperp == cv)
822 cv->c_slback->c_slperp = pcv;
823 pcv->c_slorient = cv->c_slorient;
824 pcv->c_xoff = 0;
825 pcv->c_yoff = 0;
826 pcv->c_xs = cv->c_xs;
827 pcv->c_xe = cv->c_xe;
828 pcv->c_ys = cv->c_ys;
829 pcv->c_ye = cv->c_ye;
830 if (pcv->c_slnext)
831 pcv->c_slnext->c_slprev = pcv;
832 if (pcv->c_slprev)
833 pcv->c_slprev->c_slnext = pcv;
834 pcv->c_slweight = cv->c_slweight;
835 CanvasInitBlank(pcv);
836 cv->c_slweight = 1;
837 cv->c_slnext = 0;
838 cv->c_slprev = 0;
839 cv->c_slperp = 0;
840 cv->c_slback = pcv;
841 cv->c_slorient = SLICE_UNKN;
842 return pcv;
845 static void
846 FreePerp(pcv)
847 struct canvas *pcv;
849 struct canvas *cv;
851 if (!pcv->c_slperp)
852 return;
853 cv = pcv->c_slperp;
854 cv->c_slprev = pcv->c_slprev;
855 if (cv->c_slprev)
856 cv->c_slprev->c_slnext = cv;
857 cv->c_slback = pcv->c_slback;
858 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
859 cv->c_slback->c_slperp = cv;
860 cv->c_slorient = pcv->c_slorient;
861 cv->c_slweight = pcv->c_slweight;
862 while (cv->c_slnext)
864 cv = cv->c_slnext;
865 cv->c_slorient = pcv->c_slorient;
866 cv->c_slback = pcv->c_slback;
867 cv->c_slweight = pcv->c_slweight;
869 cv->c_slnext = pcv->c_slnext;
870 if (cv->c_slnext)
871 cv->c_slnext->c_slprev = cv;
872 free(pcv);
876 AddCanvas(orient)
877 int orient;
879 struct canvas *cv;
880 int xs, xe, ys, ye;
881 int h, num;
883 cv = D_forecv;
884 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
886 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
887 if (!AddPerp(cv))
888 return -1;
890 cv = D_forecv;
891 xs = cv->c_slback->c_xs;
892 xe = cv->c_slback->c_xe;
893 ys = cv->c_slback->c_ys;
894 ye = cv->c_slback->c_ye;
895 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
896 ye--; /* need space for caption */
897 debug2("Adding Canvas to slice %d,%d ", xs, ys);
898 debug2("%d,%d\n", xe, ye);
900 num = CountCanvas(cv->c_slback->c_slperp) + 1;
901 debug1("Num = %d\n", num);
902 if (orient == SLICE_VERT)
903 h = ye - ys + 1;
904 else
905 h = xe - xs + 1;
907 h -= 2 * num - 1;
908 if (h < 0)
909 return -1; /* can't fit in */
911 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
912 return -1;
914 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
915 D_forecv->c_slorient = orient; /* in case it was UNKN */
916 cv->c_slnext = D_forecv->c_slnext;
917 cv->c_slprev = D_forecv;
918 D_forecv->c_slnext = cv;
919 if (cv->c_slnext)
920 cv->c_slnext->c_slprev = cv;
921 cv->c_slorient = orient;
922 cv->c_slback = D_forecv->c_slback;
924 cv->c_xs = xs;
925 cv->c_xe = xe;
926 cv->c_ys = ys;
927 cv->c_ye = ye;
928 cv->c_xoff = 0;
929 cv->c_yoff = 0;
930 cv->c_display = display;
931 cv->c_vplist = 0;
932 cv->c_captev.type = EV_TIMEOUT;
933 cv->c_captev.data = (char *)cv;
934 cv->c_captev.handler = cv_winid_fn;
936 CanvasInitBlank(cv);
937 cv->c_lnext = 0;
939 cv->c_next = 0;
941 cv = cv->c_slback;
942 EqualizeCanvas(cv->c_slperp, 0);
943 ResizeCanvas(cv);
944 RecreateCanvasChain();
945 RethinkDisplayViewports();
946 ResizeLayersToCanvases();
947 return 0;
950 void
951 RemCanvas()
953 int xs, xe, ys, ye;
954 struct canvas *cv;
956 debug("RemCanvas\n");
957 cv = D_forecv;
958 if (cv->c_slorient == SLICE_UNKN)
959 return;
960 while (cv->c_slprev)
961 cv = cv->c_slprev;
962 if (!cv->c_slnext)
963 return;
964 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
966 /* two canvases in slice, kill perp node */
967 cv = D_forecv;
968 debug("deleting perp node\n");
969 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
970 FreePerp(cv->c_slback);
972 xs = cv->c_slback->c_xs;
973 xe = cv->c_slback->c_xe;
974 ys = cv->c_slback->c_ys;
975 ye = cv->c_slback->c_ye;
976 /* free canvas */
977 cv = D_forecv;
978 D_forecv = cv->c_slprev;
979 if (!D_forecv)
980 D_forecv = cv->c_slnext;
981 FreeCanvas(cv);
983 cv = D_forecv;
984 while (D_forecv->c_slperp)
985 D_forecv = D_forecv->c_slperp;
987 /* if only one canvas left, set orient back to unknown */
988 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
990 cv->c_slorient = SLICE_UNKN;
991 if (!captionalways)
992 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
994 cv = cv->c_slback;
995 EqualizeCanvas(cv->c_slperp, 0);
996 ResizeCanvas(cv);
998 D_fore = Layer2Window(D_forecv->c_layer);
999 flayer = D_forecv->c_layer;
1001 RecreateCanvasChain();
1002 RethinkDisplayViewports();
1003 ResizeLayersToCanvases();
1006 void
1007 OneCanvas()
1009 struct canvas *cv = D_forecv, *ocv = 0;
1011 if (cv->c_slprev)
1013 ocv = cv->c_slprev;
1014 cv->c_slprev->c_slnext = cv->c_slnext;
1016 if (cv->c_slnext)
1018 ocv = cv->c_slnext;
1019 cv->c_slnext->c_slprev = cv->c_slprev;
1021 if (!ocv)
1022 return;
1023 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1024 cv->c_slback->c_slperp = ocv;
1025 cv->c_slorient = SLICE_UNKN;
1026 while (D_canvas.c_slperp)
1027 FreeCanvas(D_canvas.c_slperp);
1028 cv = D_forecv;
1029 D_canvas.c_slperp = cv;
1030 cv->c_slback = &D_canvas;
1031 cv->c_slnext = 0;
1032 cv->c_slprev = 0;
1033 ASSERT(!cv->c_slperp);
1034 if (!captionalways)
1035 D_canvas.c_ye++; /* caption line no longer needed */
1036 ResizeCanvas(&D_canvas);
1037 RecreateCanvasChain();
1038 RethinkDisplayViewports();
1039 ResizeLayersToCanvases();
1043 RethinkDisplayViewports()
1045 struct canvas *cv;
1046 struct viewport *vp, *vpn;
1048 /* free old viewports */
1049 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1051 for (vp = cv->c_vplist; vp; vp = vpn)
1053 vp->v_canvas = 0;
1054 vpn = vp->v_next;
1055 bzero((char *)vp, sizeof(*vp));
1056 free(vp);
1058 cv->c_vplist = 0;
1060 display->d_vpxmin = -1;
1061 display->d_vpxmax = -1;
1063 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1065 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1066 return -1;
1067 #ifdef HOLE
1068 vp->v_canvas = cv;
1069 vp->v_xs = cv->c_xs;
1070 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1071 vp->v_xe = cv->c_xe;
1072 vp->v_ye = cv->c_ye;
1073 vp->v_xoff = cv->c_xoff;
1074 vp->v_yoff = cv->c_yoff;
1075 vp->v_next = cv->c_vplist;
1076 cv->c_vplist = vp;
1078 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1079 return -1;
1080 vp->v_canvas = cv;
1081 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1082 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1083 vp->v_xe = cv->c_xe;
1084 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1085 vp->v_xoff = cv->c_xoff;
1086 vp->v_yoff = cv->c_yoff;
1087 vp->v_next = cv->c_vplist;
1088 cv->c_vplist = vp;
1090 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1091 return -1;
1092 vp->v_canvas = cv;
1093 vp->v_xs = cv->c_xs;
1094 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1095 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1096 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1097 vp->v_xoff = cv->c_xoff;
1098 vp->v_yoff = cv->c_yoff;
1099 vp->v_next = cv->c_vplist;
1100 cv->c_vplist = vp;
1102 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1103 return -1;
1104 vp->v_canvas = cv;
1105 vp->v_xs = cv->c_xs;
1106 vp->v_ys = cv->c_ys;
1107 vp->v_xe = cv->c_xe;
1108 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1109 vp->v_xoff = cv->c_xoff;
1110 vp->v_yoff = cv->c_yoff;
1111 vp->v_next = cv->c_vplist;
1112 cv->c_vplist = vp;
1113 #else
1114 vp->v_canvas = cv;
1115 vp->v_xs = cv->c_xs;
1116 vp->v_ys = cv->c_ys;
1117 vp->v_xe = cv->c_xe;
1118 vp->v_ye = cv->c_ye;
1119 vp->v_xoff = cv->c_xoff;
1120 vp->v_yoff = cv->c_yoff;
1121 vp->v_next = cv->c_vplist;
1122 cv->c_vplist = vp;
1123 #endif
1125 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1126 display->d_vpxmin = cv->c_xs;
1127 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1128 display->d_vpxmax = cv->c_xe;
1130 return 0;
1133 void
1134 RethinkViewportOffsets(cv)
1135 struct canvas *cv;
1137 struct viewport *vp;
1139 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1141 vp->v_xoff = cv->c_xoff;
1142 vp->v_yoff = cv->c_yoff;
1147 * if the adaptflag is on, we keep the size of this display, else
1148 * we may try to restore our old window sizes.
1150 void
1151 InitTerm(adapt)
1152 int adapt;
1154 ASSERT(display);
1155 ASSERT(D_tcinited);
1156 D_top = D_bot = -1;
1157 AddCStr(D_IS);
1158 AddCStr(D_TI);
1159 /* Check for toggle */
1160 if (D_IM && strcmp(D_IM, D_EI))
1161 AddCStr(D_EI);
1162 D_insert = 0;
1163 #ifdef MAPKEYS
1164 AddCStr(D_KS);
1165 AddCStr(D_CCS);
1166 #else
1167 /* Check for toggle */
1168 if (D_KS && strcmp(D_KS, D_KE))
1169 AddCStr(D_KE);
1170 if (D_CCS && strcmp(D_CCS, D_CCE))
1171 AddCStr(D_CCE);
1172 #endif
1173 D_keypad = 0;
1174 D_cursorkeys = 0;
1175 AddCStr(D_ME);
1176 AddCStr(D_EA);
1177 AddCStr(D_CE0);
1178 D_rend = mchar_null;
1179 D_atyp = 0;
1180 if (adapt == 0)
1181 ResizeDisplay(D_defwidth, D_defheight);
1182 ChangeScrollRegion(0, D_height - 1);
1183 D_x = D_y = 0;
1184 Flush();
1185 ClearAll();
1186 debug1("we %swant to adapt all our windows to the display\n",
1187 (adapt) ? "" : "don't ");
1188 /* In case the size was changed by a init sequence */
1189 CheckScreenSize((adapt) ? 2 : 0);
1192 void
1193 FinitTerm()
1195 ASSERT(display);
1196 #ifdef BLANKER_PRG
1197 KillBlanker();
1198 #endif
1199 if (D_tcinited)
1201 ResizeDisplay(D_defwidth, D_defheight);
1202 InsertMode(0);
1203 ChangeScrollRegion(0, D_height - 1);
1204 KeypadMode(0);
1205 CursorkeysMode(0);
1206 CursorVisibility(0);
1207 MouseMode(0);
1208 SetRendition(&mchar_null);
1209 SetFlow(FLOW_NOW);
1210 #ifdef MAPKEYS
1211 AddCStr(D_KE);
1212 AddCStr(D_CCE);
1213 #endif
1214 if (D_hstatus)
1215 ShowHStatus((char *)0);
1216 #ifdef RXVT_OSC
1217 ClearAllXtermOSC();
1218 #endif
1219 D_x = D_y = -1;
1220 GotoPos(0, D_height - 1);
1221 AddChar('\r');
1222 AddChar('\n');
1223 AddCStr(D_TE);
1225 Flush();
1229 static void
1230 INSERTCHAR(c)
1231 int c;
1233 ASSERT(display);
1234 if (!D_insert && D_x < D_width - 1)
1236 if (D_IC || D_CIC)
1238 if (D_IC)
1239 AddCStr(D_IC);
1240 else
1241 AddCStr2(D_CIC, 1);
1242 RAW_PUTCHAR(c);
1243 return;
1245 InsertMode(1);
1246 if (!D_insert)
1248 RefreshLine(D_y, D_x, D_width-1, 0);
1249 return;
1252 RAW_PUTCHAR(c);
1255 void
1256 PUTCHAR(c)
1257 int c;
1259 ASSERT(display);
1260 if (D_insert && D_x < D_width - 1)
1261 InsertMode(0);
1262 RAW_PUTCHAR(c);
1265 void
1266 PUTCHARLP(c)
1267 int c;
1269 if (D_x < D_width - 1)
1271 if (D_insert)
1272 InsertMode(0);
1273 RAW_PUTCHAR(c);
1274 return;
1276 if (D_CLP || D_y != D_bot)
1278 int y = D_y;
1279 RAW_PUTCHAR(c);
1280 if (D_AM && !D_CLP)
1281 GotoPos(D_width - 1, y);
1282 return;
1284 debug("PUTCHARLP: lp_missing!\n");
1285 D_lp_missing = 1;
1286 D_rend.image = c;
1287 D_lpchar = D_rend;
1288 #ifdef DW_CHARS
1289 /* XXX -> PutChar ? */
1290 if (D_mbcs)
1292 D_lpchar.mbcs = c;
1293 D_lpchar.image = D_mbcs;
1294 D_mbcs = 0;
1295 D_x--;
1297 #endif
1301 * RAW_PUTCHAR() is for all text that will be displayed.
1302 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1305 STATIC void
1306 RAW_PUTCHAR(c)
1307 int c;
1309 ASSERT(display);
1311 #ifdef FONT
1312 # ifdef UTF8
1313 if (D_encoding == UTF8)
1315 c = (c & 255) | (unsigned char)D_rend.font << 8;
1316 # ifdef DW_CHARS
1317 if (D_mbcs)
1319 c = D_mbcs;
1320 if (D_x == D_width)
1321 D_x += D_AM ? 1 : -1;
1322 D_mbcs = 0;
1324 else if (utf8_isdouble(c))
1326 D_mbcs = c;
1327 D_x++;
1328 return;
1330 # endif
1331 if (c < 32)
1333 AddCStr2(D_CS0, '0');
1334 AddChar(c + 0x5f);
1335 AddCStr(D_CE0);
1336 goto addedutf8;
1338 AddUtf8(c);
1339 goto addedutf8;
1341 # endif
1342 # ifdef DW_CHARS
1343 if (is_dw_font(D_rend.font))
1345 int t = c;
1346 if (D_mbcs == 0)
1348 D_mbcs = c;
1349 D_x++;
1350 return;
1352 D_x--;
1353 if (D_x == D_width - 1)
1354 D_x += D_AM ? 1 : -1;
1355 c = D_mbcs;
1356 D_mbcs = t;
1358 # endif
1359 # if defined(ENCODINGS) && defined(DW_CHARS)
1360 if (D_encoding)
1361 c = PrepareEncodedChar(c);
1362 # endif
1363 # ifdef DW_CHARS
1364 kanjiloop:
1365 # endif
1366 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1367 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1368 else
1369 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1370 #else /* FONT */
1371 AddChar(c);
1372 #endif /* FONT */
1374 #ifdef UTF8
1375 addedutf8:
1376 #endif
1377 if (++D_x >= D_width)
1379 if (D_AM == 0)
1380 D_x = D_width - 1;
1381 else if (!D_CLP || D_x > D_width)
1383 D_x -= D_width;
1384 if (D_y < D_height-1 && D_y != D_bot)
1385 D_y++;
1388 #ifdef DW_CHARS
1389 if (D_mbcs)
1391 c = D_mbcs;
1392 D_mbcs = 0;
1393 goto kanjiloop;
1395 #endif
1398 static int
1399 DoAddChar(c)
1400 int c;
1402 /* this is for ESC-sequences only (AddChar is a macro) */
1403 AddChar(c);
1404 return c;
1407 void
1408 AddCStr(s)
1409 char *s;
1411 if (display && s && *s)
1413 ospeed = D_dospeed;
1414 tputs(s, 1, DoAddChar);
1418 void
1419 AddCStr2(s, c)
1420 char *s;
1421 int c;
1423 if (display && s && *s)
1425 ospeed = D_dospeed;
1426 tputs(tgoto(s, 0, c), 1, DoAddChar);
1431 /* Insert mode is a toggle on some terminals, so we need this hack:
1433 void
1434 InsertMode(on)
1435 int on;
1437 if (display && on != D_insert && D_IM)
1439 D_insert = on;
1440 if (on)
1441 AddCStr(D_IM);
1442 else
1443 AddCStr(D_EI);
1447 /* ...and maybe keypad application mode is a toggle, too:
1449 void
1450 KeypadMode(on)
1451 int on;
1453 #ifdef MAPKEYS
1454 if (display)
1455 D_keypad = on;
1456 #else
1457 if (display && D_keypad != on && D_KS)
1459 D_keypad = on;
1460 if (on)
1461 AddCStr(D_KS);
1462 else
1463 AddCStr(D_KE);
1465 #endif
1468 void
1469 CursorkeysMode(on)
1470 int on;
1472 #ifdef MAPKEYS
1473 if (display)
1474 D_cursorkeys = on;
1475 #else
1476 if (display && D_cursorkeys != on && D_CCS)
1478 D_cursorkeys = on;
1479 if (on)
1480 AddCStr(D_CCS);
1481 else
1482 AddCStr(D_CCE);
1484 #endif
1487 void
1488 ReverseVideo(on)
1489 int on;
1491 if (display && D_revvid != on && D_CVR)
1493 D_revvid = on;
1494 if (D_revvid)
1495 AddCStr(D_CVR);
1496 else
1497 AddCStr(D_CVN);
1501 void
1502 CursorVisibility(v)
1503 int v;
1505 if (display && D_curvis != v)
1507 if (D_curvis)
1508 AddCStr(D_VE); /* do this always, just to be safe */
1509 D_curvis = 0;
1510 if (v == -1 && D_VI)
1511 AddCStr(D_VI);
1512 else if (v == 1 && D_VS)
1513 AddCStr(D_VS);
1514 else
1515 return;
1516 D_curvis = v;
1520 void
1521 MouseMode(mode)
1522 int mode;
1524 if (display && D_mouse != mode)
1526 char mousebuf[20];
1527 if (!D_CXT)
1528 return;
1529 if (D_mouse)
1531 sprintf(mousebuf, "\033[?%dl", D_mouse);
1532 AddStr(mousebuf);
1534 if (mode)
1536 sprintf(mousebuf, "\033[?%dh", mode);
1537 AddStr(mousebuf);
1539 D_mouse = mode;
1543 static int StrCost;
1545 /* ARGSUSED */
1546 static int
1547 CountChars(c)
1548 int c;
1550 StrCost++;
1551 return c;
1555 CalcCost(s)
1556 register char *s;
1558 ASSERT(display);
1559 if (s)
1561 StrCost = 0;
1562 ospeed = D_dospeed;
1563 tputs(s, 1, CountChars);
1564 return StrCost;
1566 else
1567 return EXPENSIVE;
1570 static int
1571 CallRewrite(y, xs, xe, doit)
1572 int y, xs, xe, doit;
1574 struct canvas *cv, *cvlist, *cvlnext;
1575 struct viewport *vp;
1576 struct layer *oldflayer;
1577 int cost;
1579 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1580 ASSERT(display);
1581 ASSERT(xe >= xs);
1583 vp = 0;
1584 for (cv = D_cvlist; cv; cv = cv->c_next)
1586 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1587 continue;
1588 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1589 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1590 break;
1591 if (vp)
1592 break;
1594 if (doit)
1596 oldflayer = flayer;
1597 flayer = cv->c_layer;
1598 cvlist = flayer->l_cvlist;
1599 cvlnext = cv->c_lnext;
1600 flayer->l_cvlist = cv;
1601 cv->c_lnext = 0;
1602 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1603 flayer->l_cvlist = cvlist;
1604 cv->c_lnext = cvlnext;
1605 flayer = oldflayer;
1606 return 0;
1608 if (cv == 0 || cv->c_layer == 0)
1609 return EXPENSIVE; /* not found or nothing on it */
1610 if (xs < vp->v_xs || xe > vp->v_xe)
1611 return EXPENSIVE; /* crosses viewport boundaries */
1612 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1613 return EXPENSIVE; /* line not on layer */
1614 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1615 return EXPENSIVE; /* line not on layer */
1616 #ifdef UTF8
1617 if (D_encoding == UTF8)
1618 D_rend.font = 0;
1619 #endif
1620 oldflayer = flayer;
1621 flayer = cv->c_layer;
1622 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1623 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1624 flayer = oldflayer;
1625 if (D_insert)
1626 cost += D_EIcost + D_IMcost;
1627 return cost;
1631 void
1632 GotoPos(x2, y2)
1633 int x2, y2;
1635 register int dy, dx, x1, y1;
1636 register int costx, costy;
1637 register int m;
1638 register char *s;
1639 int CMcost;
1640 enum move_t xm = M_NONE, ym = M_NONE;
1642 if (!display)
1643 return;
1645 x1 = D_x;
1646 y1 = D_y;
1648 if (x1 == D_width)
1650 if (D_CLP && D_AM)
1651 x1 = -1; /* don't know how the terminal treats this */
1652 else
1653 x1--;
1655 if (x2 == D_width)
1656 x2--;
1657 dx = x2 - x1;
1658 dy = y2 - y1;
1659 if (dy == 0 && dx == 0)
1660 return;
1661 debug2("GotoPos (%d,%d)", x1, y1);
1662 debug2(" -> (%d,%d)\n", x2, y2);
1663 if (!D_MS) /* Safe to move ? */
1664 SetRendition(&mchar_null);
1665 if (y1 < 0 /* don't know the y position */
1666 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1667 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1669 DoCM:
1670 if (D_HO && !x2 && !y2)
1671 AddCStr(D_HO);
1672 else
1673 AddCStr(tgoto(D_CM, x2, y2));
1674 D_x = x2;
1675 D_y = y2;
1676 return;
1679 /* some scrollregion implementations don't allow movements
1680 * away from the region. sigh.
1682 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1683 goto DoCM;
1685 /* Calculate CMcost */
1686 if (D_HO && !x2 && !y2)
1687 s = D_HO;
1688 else
1689 s = tgoto(D_CM, x2, y2);
1690 CMcost = CalcCost(s);
1692 /* Calculate the cost to move the cursor to the right x position */
1693 costx = EXPENSIVE;
1694 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1696 if (dx > 0)
1698 if (D_CRI && (dx > 1 || !D_ND))
1700 costx = CalcCost(tgoto(D_CRI, 0, dx));
1701 xm = M_CRI;
1703 if ((m = D_NDcost * dx) < costx)
1705 costx = m;
1706 xm = M_RI;
1708 /* Speedup: dx <= LayRewrite() */
1709 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1711 costx = m;
1712 xm = M_RW;
1715 else if (dx < 0)
1717 if (D_CLE && (dx < -1 || !D_BC))
1719 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1720 xm = M_CLE;
1722 if ((m = -dx * D_LEcost) < costx)
1724 costx = m;
1725 xm = M_LE;
1728 else
1729 costx = 0;
1731 /* Speedup: LayRewrite() >= x2 */
1732 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1734 costx = m;
1735 xm = M_CR;
1738 /* Check if it is already cheaper to do CM */
1739 if (costx >= CMcost)
1740 goto DoCM;
1742 /* Calculate the cost to move the cursor to the right y position */
1743 costy = EXPENSIVE;
1744 if (dy > 0)
1746 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1748 costy = CalcCost(tgoto(D_CDO, 0, dy));
1749 ym = M_CDO;
1751 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1753 costy = m;
1754 ym = M_DO;
1757 else if (dy < 0)
1759 if (D_CUP && (dy < -1 || !D_UP))
1761 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1762 ym = M_CUP;
1764 if ((m = -dy * D_UPcost) < costy)
1766 costy = m;
1767 ym = M_UP;
1770 else
1771 costy = 0;
1773 /* Finally check if it is cheaper to do CM */
1774 if (costx + costy >= CMcost)
1775 goto DoCM;
1777 switch (xm)
1779 case M_LE:
1780 while (dx++ < 0)
1781 AddCStr(D_BC);
1782 break;
1783 case M_CLE:
1784 AddCStr2(D_CLE, -dx);
1785 break;
1786 case M_RI:
1787 while (dx-- > 0)
1788 AddCStr(D_ND);
1789 break;
1790 case M_CRI:
1791 AddCStr2(D_CRI, dx);
1792 break;
1793 case M_CR:
1794 AddCStr(D_CR);
1795 D_x = 0;
1796 x1 = 0;
1797 /* FALLTHROUGH */
1798 case M_RW:
1799 if (x1 < x2)
1800 (void) CallRewrite(y1, x1, x2 - 1, 1);
1801 break;
1802 default:
1803 break;
1806 switch (ym)
1808 case M_UP:
1809 while (dy++ < 0)
1810 AddCStr(D_UP);
1811 break;
1812 case M_CUP:
1813 AddCStr2(D_CUP, -dy);
1814 break;
1815 case M_DO:
1816 s = (x2 == 0) ? D_NL : D_DO;
1817 while (dy-- > 0)
1818 AddCStr(s);
1819 break;
1820 case M_CDO:
1821 AddCStr2(D_CDO, dy);
1822 break;
1823 default:
1824 break;
1826 D_x = x2;
1827 D_y = y2;
1830 void
1831 ClearAll()
1833 ASSERT(display);
1834 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1837 void
1838 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1839 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1841 int y, xxe;
1842 struct canvas *cv;
1843 struct viewport *vp;
1845 debug2("Clear %d,%d", x1, y1);
1846 debug2(" %d-%d", xs, xe);
1847 debug2(" %d,%d", x2, y2);
1848 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1849 ASSERT(display);
1850 if (x1 == D_width)
1851 x1--;
1852 if (x2 == D_width)
1853 x2--;
1854 if (xs == -1)
1855 xs = x1;
1856 if (xe == -1)
1857 xe = x2;
1858 if (D_UT) /* Safe to erase ? */
1859 SetRendition(&mchar_null);
1860 #ifdef COLOR
1861 if (D_BE)
1862 SetBackColor(bce);
1863 #endif
1864 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1866 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1867 D_lp_missing = 0;
1869 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1871 #ifdef AUTO_NUKE
1872 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1873 NukePending();
1874 #endif
1875 if (x1 == 0 && y1 == 0 && D_CL)
1877 AddCStr(D_CL);
1878 D_y = D_x = 0;
1879 return;
1882 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1883 * is also appropriate.
1885 if (D_CD && (y1 < y2 || !D_CE))
1887 GotoPos(x1, y1);
1888 AddCStr(D_CD);
1889 return;
1892 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1894 GotoPos(x1, y1);
1895 AddCStr(D_CCD);
1896 return;
1898 xxe = xe;
1899 for (y = y1; y <= y2; y++, x1 = xs)
1901 if (y == y2)
1902 xxe = x2;
1903 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1905 GotoPos(xxe, y);
1906 AddCStr(D_CB);
1907 continue;
1909 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1911 GotoPos(x1, y);
1912 AddCStr(D_CE);
1913 continue;
1915 if (uselayfn)
1917 vp = 0;
1918 for (cv = D_cvlist; cv; cv = cv->c_next)
1920 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1921 continue;
1922 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1923 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1924 break;
1925 if (vp)
1926 break;
1928 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1929 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1930 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1932 struct layer *oldflayer = flayer;
1933 struct canvas *cvlist, *cvlnext;
1934 flayer = cv->c_layer;
1935 cvlist = flayer->l_cvlist;
1936 cvlnext = cv->c_lnext;
1937 flayer->l_cvlist = cv;
1938 cv->c_lnext = 0;
1939 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1940 flayer->l_cvlist = cvlist;
1941 cv->c_lnext = cvlnext;
1942 flayer = oldflayer;
1943 continue;
1946 ClearLine((struct mline *)0, y, x1, xxe, bce);
1952 * if cur_only > 0, we only redisplay current line, as a full refresh is
1953 * too expensive over a low baud line.
1955 void
1956 Redisplay(cur_only)
1957 int cur_only;
1959 ASSERT(display);
1961 /* XXX do em all? */
1962 InsertMode(0);
1963 ChangeScrollRegion(0, D_height - 1);
1964 KeypadMode(0);
1965 CursorkeysMode(0);
1966 CursorVisibility(0);
1967 MouseMode(0);
1968 SetRendition(&mchar_null);
1969 SetFlow(FLOW_NOW);
1971 ClearAll();
1972 #ifdef RXVT_OSC
1973 RefreshXtermOSC();
1974 #endif
1975 if (cur_only > 0 && D_fore)
1976 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1977 else
1978 RefreshAll(1);
1979 RefreshHStatus();
1980 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1983 void
1984 RedisplayDisplays(cur_only)
1985 int cur_only;
1987 struct display *olddisplay = display;
1988 for (display = displays; display; display = display->d_next)
1989 Redisplay(cur_only);
1990 display = olddisplay;
1994 /* XXX: use oml! */
1995 void
1996 ScrollH(y, xs, xe, n, bce, oml)
1997 int y, xs, xe, n, bce;
1998 struct mline *oml;
2000 int i;
2002 if (n == 0)
2003 return;
2004 if (xe != D_width - 1)
2006 RefreshLine(y, xs, xe, 0);
2007 /* UpdateLine(oml, y, xs, xe); */
2008 return;
2010 GotoPos(xs, y);
2011 if (D_UT)
2012 SetRendition(&mchar_null);
2013 #ifdef COLOR
2014 if (D_BE)
2015 SetBackColor(bce);
2016 #endif
2017 if (n > 0)
2019 if (n >= xe - xs + 1)
2020 n = xe - xs + 1;
2021 if (D_CDC && !(n == 1 && D_DC))
2022 AddCStr2(D_CDC, n);
2023 else if (D_DC)
2025 for (i = n; i--; )
2026 AddCStr(D_DC);
2028 else
2030 RefreshLine(y, xs, xe, 0);
2031 /* UpdateLine(oml, y, xs, xe); */
2032 return;
2035 else
2037 if (-n >= xe - xs + 1)
2038 n = -(xe - xs + 1);
2039 if (!D_insert)
2041 if (D_CIC && !(n == -1 && D_IC))
2042 AddCStr2(D_CIC, -n);
2043 else if (D_IC)
2045 for (i = -n; i--; )
2046 AddCStr(D_IC);
2048 else if (D_IM)
2050 InsertMode(1);
2051 SetRendition(&mchar_null);
2052 #ifdef COLOR
2053 SetBackColor(bce);
2054 #endif
2055 for (i = -n; i--; )
2056 INSERTCHAR(' ');
2057 bce = 0; /* all done */
2059 else
2061 /* UpdateLine(oml, y, xs, xe); */
2062 RefreshLine(y, xs, xe, 0);
2063 return;
2066 else
2068 SetRendition(&mchar_null);
2069 #ifdef COLOR
2070 SetBackColor(bce);
2071 #endif
2072 for (i = -n; i--; )
2073 INSERTCHAR(' ');
2074 bce = 0; /* all done */
2077 if (bce && !D_BE)
2079 if (n > 0)
2080 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2081 else
2082 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2084 if (D_lp_missing && y == D_bot)
2086 if (n > 0)
2087 WriteLP(D_width - 1 - n, y);
2088 D_lp_missing = 0;
2092 void
2093 ScrollV(xs, ys, xe, ye, n, bce)
2094 int xs, ys, xe, ye, n, bce;
2096 int i;
2097 int up;
2098 int oldtop, oldbot;
2099 int alok, dlok, aldlfaster;
2100 int missy = 0;
2102 ASSERT(display);
2103 if (n == 0)
2104 return;
2105 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2107 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2108 return;
2110 if (xs > D_vpxmin || xe < D_vpxmax)
2112 RefreshArea(xs, ys, xe, ye, 0);
2113 return;
2116 if (D_lp_missing)
2118 if (D_bot > ye || D_bot < ys)
2119 missy = D_bot;
2120 else
2122 missy = D_bot - n;
2123 if (missy > ye || missy < ys)
2124 D_lp_missing = 0;
2128 up = 1;
2129 if (n < 0)
2131 up = 0;
2132 n = -n;
2134 if (n >= ye - ys + 1)
2135 n = ye - ys + 1;
2137 oldtop = D_top;
2138 oldbot = D_bot;
2139 if (ys < D_top || D_bot != ye)
2140 ChangeScrollRegion(ys, ye);
2141 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2142 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2143 if (D_top != ys && !(alok && dlok))
2144 ChangeScrollRegion(ys, ye);
2146 if (D_lp_missing &&
2147 (oldbot != D_bot ||
2148 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2150 WriteLP(D_width - 1, oldbot);
2151 if (oldbot == D_bot) /* have scrolled */
2153 if (--n == 0)
2155 /* XXX
2156 ChangeScrollRegion(oldtop, oldbot);
2158 if (bce && !D_BE)
2159 ClearLine((struct mline *)0, ye, xs, xe, bce);
2160 return;
2165 if (D_UT)
2166 SetRendition(&mchar_null);
2167 #ifdef COLOR
2168 if (D_BE)
2169 SetBackColor(bce);
2170 #endif
2172 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2174 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2176 if (up)
2178 GotoPos(0, ye);
2179 for(i = n; i-- > 0; )
2180 AddCStr(D_NL); /* was SF, I think NL is faster */
2182 else
2184 GotoPos(0, ys);
2185 for(i = n; i-- > 0; )
2186 AddCStr(D_SR);
2189 else if (alok && dlok)
2191 if (up || ye != D_bot)
2193 GotoPos(0, up ? ys : ye+1-n);
2194 if (D_CDL && !(n == 1 && D_DL))
2195 AddCStr2(D_CDL, n);
2196 else
2197 for(i = n; i--; )
2198 AddCStr(D_DL);
2200 if (!up || ye != D_bot)
2202 GotoPos(0, up ? ye+1-n : ys);
2203 if (D_CAL && !(n == 1 && D_AL))
2204 AddCStr2(D_CAL, n);
2205 else
2206 for(i = n; i--; )
2207 AddCStr(D_AL);
2210 else
2212 RefreshArea(xs, ys, xe, ye, 0);
2213 return;
2215 if (bce && !D_BE)
2217 if (up)
2218 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2219 else
2220 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2222 if (D_lp_missing && missy != D_bot)
2223 WriteLP(D_width - 1, missy);
2224 /* XXX
2225 ChangeScrollRegion(oldtop, oldbot);
2226 if (D_lp_missing && missy != D_bot)
2227 WriteLP(D_width - 1, missy);
2231 void
2232 SetAttr(new)
2233 register int new;
2235 register int i, j, old, typ;
2237 if (!display || (old = D_rend.attr) == new)
2238 return;
2239 #ifdef COLORS16
2240 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2241 new ^= D_col16change;
2242 if (old == new)
2243 return;
2244 #endif
2245 #if defined(TERMINFO) && defined(USE_SGR)
2246 if (D_SA)
2248 char *tparm();
2249 SetFont(ASCII);
2250 ospeed = D_dospeed;
2251 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2252 new & A_DI, new & A_BD, 0 , 0 ,
2253 0), 1, DoAddChar);
2254 D_rend.attr = new;
2255 D_atyp = 0;
2256 # ifdef COLOR
2257 if (D_hascolor)
2258 rend_setdefault(&D_rend);
2259 # endif
2260 return;
2262 #endif
2263 D_rend.attr = new;
2264 typ = D_atyp;
2265 if ((new & old) != old)
2267 if ((typ & ATYP_U))
2268 AddCStr(D_UE);
2269 if ((typ & ATYP_S))
2270 AddCStr(D_SE);
2271 if ((typ & ATYP_M))
2273 AddCStr(D_ME);
2274 #ifdef COLOR
2275 /* ansi attrib handling: \E[m resets color, too */
2276 if (D_hascolor)
2277 rend_setdefault(&D_rend);
2278 #endif
2279 #ifdef FONT
2280 if (!D_CG0)
2282 /* D_ME may also reset the alternate charset */
2283 D_rend.font = 0;
2284 # ifdef ENCODINGS
2285 D_realfont = 0;
2286 # endif
2288 #endif
2290 old = 0;
2291 typ = 0;
2293 old ^= new;
2294 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2296 if ((old & j) == 0)
2297 continue;
2298 old ^= j;
2299 if (D_attrtab[i])
2301 AddCStr(D_attrtab[i]);
2302 typ |= D_attrtyp[i];
2305 D_atyp = typ;
2308 #ifdef FONT
2309 void
2310 SetFont(new)
2311 int new;
2313 int old = D_rend.font;
2314 if (!display || old == new)
2315 return;
2316 D_rend.font = new;
2317 #ifdef ENCODINGS
2318 if (D_encoding && CanEncodeFont(D_encoding, new))
2319 return;
2320 if (new == D_realfont)
2321 return;
2322 D_realfont = new;
2323 #endif
2324 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2325 D_xtable[(int)(unsigned char)new][256])
2327 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2328 return;
2331 if (!D_CG0 && new != '0')
2333 new = ASCII;
2334 if (old == new)
2335 return;
2338 if (new == ASCII)
2339 AddCStr(D_CE0);
2340 #ifdef DW_CHARS
2341 else if (new < ' ')
2343 AddStr("\033$");
2344 if (new > 2)
2345 AddChar('(');
2346 AddChar(new + '@');
2348 #endif
2349 else
2350 AddCStr2(D_CS0, new);
2352 #endif
2354 #ifdef COLOR
2357 color256to16(jj)
2358 int jj;
2360 int min, max;
2361 int r, g, b;
2363 if (jj >= 232)
2365 jj = (jj - 232) / 6;
2366 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2368 else if (jj >= 16)
2370 jj -= 16;
2371 r = jj / 36;
2372 g = (jj / 6) % 6;
2373 b = jj % 6;
2374 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2375 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2376 if (min == max)
2377 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2378 else
2379 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2380 min) / (max - min) | (max > 3 ? 8 : 0);
2382 return jj;
2385 #ifdef COLORS256
2387 color256to88(jj)
2388 int jj;
2390 int r, g, b;
2392 if (jj >= 232)
2393 return (jj - 232) / 3 + 80;
2394 if (jj >= 16)
2396 jj -= 16;
2397 r = jj / 36;
2398 g = (jj / 6) % 6;
2399 b = jj % 6;
2400 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2402 return jj;
2404 #endif
2406 void
2407 SetColor(f, b)
2408 int f, b;
2410 int of, ob;
2411 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2413 if (!display)
2414 return;
2416 of = rend_getfg(&D_rend);
2417 ob = rend_getbg(&D_rend);
2419 #ifdef COLORS16
2420 /* intense default not invented yet */
2421 if (f == 0x100)
2422 f = 0;
2423 if (b == 0x100)
2424 b = 0;
2425 #endif
2426 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2427 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2428 debug2("(%d %d", of, ob);
2429 debug2(" -> %d %d)\n", f, b);
2431 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2433 if (D_OP)
2434 AddCStr(D_OP);
2435 else
2437 int oattr;
2438 oattr = D_rend.attr;
2439 AddCStr(D_ME ? D_ME : "\033[m");
2440 #ifdef FONT
2441 if (D_ME && !D_CG0)
2443 /* D_ME may also reset the alternate charset */
2444 D_rend.font = 0;
2445 # ifdef ENCODINGS
2446 D_realfont = 0;
2447 # endif
2449 #endif
2450 D_atyp = 0;
2451 D_rend.attr = 0;
2452 SetAttr(oattr);
2454 of = ob = 0;
2456 rend_setfg(&D_rend, f);
2457 rend_setbg(&D_rend, b);
2458 #ifdef COLORS16
2459 D_col16change = 0;
2460 #endif
2461 if (!D_hascolor)
2462 return;
2463 f = f ? coli2e(f) : -1;
2464 b = b ? coli2e(b) : -1;
2465 of = of ? coli2e(of) : -1;
2466 ob = ob ? coli2e(ob) : -1;
2467 #ifdef COLORS256
2468 if (f != of && f > 15 && D_CCO != 256)
2469 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2470 if (f != of && f > 15 && D_CAF)
2472 AddCStr2(D_CAF, f);
2473 of = f;
2475 if (b != ob && b > 15 && D_CCO != 256)
2476 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2477 if (b != ob && b > 15 && D_CAB)
2479 AddCStr2(D_CAB, b);
2480 ob = b;
2482 #endif
2483 if (f != of && f != (of | 8))
2485 if (f == -1)
2486 AddCStr("\033[39m"); /* works because AX is set */
2487 else if (D_CAF)
2488 AddCStr2(D_CAF, f & 7);
2489 else if (D_CSF)
2490 AddCStr2(D_CSF, sftrans[f & 7]);
2492 if (b != ob && b != (ob | 8))
2494 if (b == -1)
2495 AddCStr("\033[49m"); /* works because AX is set */
2496 else if (D_CAB)
2497 AddCStr2(D_CAB, b & 7);
2498 else if (D_CSB)
2499 AddCStr2(D_CSB, sftrans[b & 7]);
2501 #ifdef COLORS16
2502 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2504 # ifdef TERMINFO
2505 AddCStr2("\033[9%p1%dm", f & 7);
2506 # else
2507 AddCStr2("\033[9%dm", f & 7);
2508 # endif
2510 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2512 # ifdef TERMINFO
2513 AddCStr2("\033[10%p1%dm", b & 7);
2514 # else
2515 AddCStr2("\033[10%dm", b & 7);
2516 # endif
2518 #endif
2521 static void
2522 SetBackColor(new)
2523 int new;
2525 if (!display)
2526 return;
2527 SetColor(rend_getfg(&D_rend), new);
2529 #endif /* COLOR */
2531 void
2532 SetRendition(mc)
2533 struct mchar *mc;
2535 if (!display)
2536 return;
2537 #ifdef COLOR
2538 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2540 static struct mchar mmc;
2541 int i;
2542 mmc = *mc;
2543 for (i = 0; i < 8; i++)
2544 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2546 if (mc->color == 0 && attr2color[i][3])
2547 ApplyAttrColor(attr2color[i][3], &mmc);
2548 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2549 ApplyAttrColor(attr2color[i][2], &mmc);
2550 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2551 ApplyAttrColor(attr2color[i][1], &mmc);
2552 else
2553 ApplyAttrColor(attr2color[i][0], &mmc);
2555 mc = &mmc;
2556 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2558 # ifdef COLORS16
2559 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2561 int a = mc->attr;
2562 if ((mc->attr & A_BFG) && D_MD)
2563 a |= A_BD;
2564 if ((mc->attr & A_BBG) && D_MB)
2565 a |= A_BL;
2566 if (D_rend.attr != a)
2567 SetAttr(a);
2569 else
2570 # endif /* COLORS16 */
2571 #endif /* COLOR */
2572 if (D_rend.attr != mc->attr)
2573 SetAttr(mc->attr);
2575 #ifdef COLOR
2576 if (D_rend.color != mc->color
2577 # ifdef COLORS256
2578 || D_rend.colorx != mc->colorx
2579 # endif
2580 # ifdef COLORS16
2581 || D_col16change
2582 # endif
2584 SetColor(rend_getfg(mc), rend_getbg(mc));
2585 #endif
2586 #ifdef FONT
2587 if (D_rend.font != mc->font)
2588 SetFont(mc->font);
2589 #endif
2592 void
2593 SetRenditionMline(ml, x)
2594 struct mline *ml;
2595 int x;
2597 if (!display)
2598 return;
2599 #ifdef COLOR
2600 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2602 struct mchar mc;
2603 copy_mline2mchar(&mc, ml, x);
2604 SetRendition(&mc);
2605 return;
2607 # ifdef COLORS16
2608 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2610 int a = ml->attr[x];
2611 if ((ml->attr[x] & A_BFG) && D_MD)
2612 a |= A_BD;
2613 if ((ml->attr[x] & A_BBG) && D_MB)
2614 a |= A_BL;
2615 if (D_rend.attr != a)
2616 SetAttr(a);
2618 else
2619 # endif /* COLORS16 */
2620 #endif /* COLOR */
2621 if (D_rend.attr != ml->attr[x])
2622 SetAttr(ml->attr[x]);
2623 #ifdef COLOR
2624 if (D_rend.color != ml->color[x]
2625 # ifdef COLORS256
2626 || D_rend.colorx != ml->colorx[x]
2627 # endif
2628 # ifdef COLORS16
2629 || D_col16change
2630 # endif
2633 struct mchar mc;
2634 copy_mline2mchar(&mc, ml, x);
2635 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2637 #endif
2638 #ifdef FONT
2639 if (D_rend.font != ml->font[x])
2640 SetFont(ml->font[x]);
2641 #endif
2644 void
2645 MakeStatus(msg)
2646 char *msg;
2648 register char *s, *t;
2649 register int max;
2651 if (!display)
2652 return;
2654 if (D_blocked)
2655 return;
2656 if (!D_tcinited)
2658 debug("tc not inited, just writing msg\n");
2659 if (D_processinputdata)
2660 return; /* XXX: better */
2661 AddStr(msg);
2662 AddStr("\r\n");
2663 Flush();
2664 return;
2666 if (!use_hardstatus || !D_HS)
2668 max = D_width;
2669 if (D_CLP == 0)
2670 max--;
2672 else
2673 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2674 if (D_status)
2676 /* same message? */
2677 if (strcmp(msg, D_status_lastmsg) == 0)
2679 debug("same message - increase timeout");
2680 SetTimeout(&D_statusev, MsgWait);
2681 return;
2683 if (!D_status_bell)
2685 struct timeval now;
2686 int ti;
2687 gettimeofday(&now, NULL);
2688 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2689 if (ti < MsgMinWait)
2690 DisplaySleep1000(MsgMinWait - ti, 0);
2692 RemoveStatus();
2694 for (s = t = msg; *s && t - msg < max; ++s)
2695 if (*s == BELL)
2696 AddCStr(D_BL);
2697 else if ((unsigned char)*s >= ' ' && *s != 0177)
2698 *t++ = *s;
2699 *t = '\0';
2700 if (t == msg)
2701 return;
2702 if (t - msg >= D_status_buflen)
2704 char *buf;
2705 if (D_status_lastmsg)
2706 buf = realloc(D_status_lastmsg, t - msg + 1);
2707 else
2708 buf = malloc(t - msg + 1);
2709 if (buf)
2711 D_status_lastmsg = buf;
2712 D_status_buflen = t - msg + 1;
2715 if (t - msg < D_status_buflen)
2716 strcpy(D_status_lastmsg, msg);
2717 D_status_len = t - msg;
2718 D_status_lastx = D_x;
2719 D_status_lasty = D_y;
2720 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2722 D_status = STATUS_ON_WIN;
2723 debug1("using STATLINE %d\n", STATLINE);
2724 GotoPos(0, STATLINE);
2725 SetRendition(&mchar_so);
2726 InsertMode(0);
2727 AddStr(msg);
2728 if (D_status_len < max)
2730 /* Wayne Davison: add extra space for readability */
2731 D_status_len++;
2732 SetRendition(&mchar_null);
2733 AddChar(' ');
2734 if (D_status_len < max)
2736 D_status_len++;
2737 AddChar(' ');
2738 AddChar('\b');
2740 AddChar('\b');
2742 D_x = -1;
2744 else
2746 D_status = STATUS_ON_HS;
2747 ShowHStatus(msg);
2749 Flush();
2750 if (!display)
2751 return;
2752 if (D_status == STATUS_ON_WIN)
2754 struct display *olddisplay = display;
2755 struct layer *oldflayer = flayer;
2757 ASSERT(D_obuffree == D_obuflen);
2758 /* this is copied over from RemoveStatus() */
2759 D_status = 0;
2760 GotoPos(0, STATLINE);
2761 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2762 GotoPos(D_status_lastx, D_status_lasty);
2763 flayer = D_forecv ? D_forecv->c_layer : 0;
2764 if (flayer)
2765 LaySetCursor();
2766 display = olddisplay;
2767 flayer = oldflayer;
2768 D_status_obuflen = D_obuflen;
2769 D_status_obuffree = D_obuffree;
2770 D_obuffree = D_obuflen = 0;
2771 D_status = STATUS_ON_WIN;
2773 gettimeofday(&D_status_time, NULL);
2774 SetTimeout(&D_statusev, MsgWait);
2775 evenq(&D_statusev);
2776 #ifdef HAVE_BRAILLE
2777 RefreshBraille(); /* let user see multiple Msg()s */
2778 #endif
2781 void
2782 RemoveStatus()
2784 struct display *olddisplay;
2785 struct layer *oldflayer;
2786 int where;
2788 if (!display)
2789 return;
2790 if (!(where = D_status))
2791 return;
2793 debug("RemoveStatus\n");
2794 if (D_status_obuffree >= 0)
2796 D_obuflen = D_status_obuflen;
2797 D_obuffree = D_status_obuffree;
2798 D_status_obuffree = -1;
2800 D_status = 0;
2801 D_status_bell = 0;
2802 evdeq(&D_statusev);
2803 olddisplay = display;
2804 oldflayer = flayer;
2805 if (where == STATUS_ON_WIN)
2807 if (captionalways || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))
2809 GotoPos(0, STATLINE);
2810 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2811 GotoPos(D_status_lastx, D_status_lasty);
2814 else
2815 RefreshHStatus();
2816 flayer = D_forecv ? D_forecv->c_layer : 0;
2817 if (flayer)
2818 LaySetCursor();
2819 display = olddisplay;
2820 flayer = oldflayer;
2823 /* refresh the display's hstatus line */
2824 void
2825 ShowHStatus(str)
2826 char *str;
2828 int l, ox, oy, max;
2830 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2831 return; /* sorry, in use */
2832 if (D_blocked)
2833 return;
2835 if (D_HS && D_has_hstatus == HSTATUS_HS)
2837 if (!D_hstatus && (str == 0 || *str == 0))
2838 return;
2839 debug("ShowHStatus: using HS\n");
2840 SetRendition(&mchar_null);
2841 InsertMode(0);
2842 if (D_hstatus)
2843 AddCStr(D_DS);
2844 D_hstatus = 0;
2845 if (str == 0 || *str == 0)
2846 return;
2847 AddCStr2(D_TS, 0);
2848 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2849 if ((int)strlen(str) > max)
2850 AddStrn(str, max);
2851 else
2852 AddStr(str);
2853 AddCStr(D_FS);
2854 D_hstatus = 1;
2856 else if (D_has_hstatus == HSTATUS_LASTLINE)
2858 debug("ShowHStatus: using last line\n");
2859 ox = D_x;
2860 oy = D_y;
2861 str = str ? str : "";
2862 l = strlen(str);
2863 if (l > D_width)
2864 l = D_width;
2865 GotoPos(0, D_height - 1);
2866 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2867 PutWinMsg(str, 0, l);
2868 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2869 while (l++ < D_width)
2870 PUTCHARLP(' ');
2871 if (l < D_width)
2872 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2873 if (ox != -1 && oy != -1)
2874 GotoPos(ox, oy);
2875 D_hstatus = *str ? 1 : 0;
2876 SetRendition(&mchar_null);
2878 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2880 debug("ShowHStatus: using message\n");
2881 Msg(0, "%s", str);
2887 * Refreshes the harstatus of the fore window. Shouldn't be here...
2889 void
2890 RefreshHStatus()
2892 char *buf;
2894 evdeq(&D_hstatusev);
2895 if (D_status == STATUS_ON_HS)
2896 return;
2897 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2898 if (buf && *buf)
2900 ShowHStatus(buf);
2901 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2902 evenq(&D_hstatusev);
2904 else
2905 ShowHStatus((char *)0);
2908 /*********************************************************************/
2910 * Here come the routines that refresh an arbitrary part of the screen.
2913 void
2914 RefreshAll(isblank)
2915 int isblank;
2917 struct canvas *cv;
2919 ASSERT(display);
2920 debug("Signalling full refresh!\n");
2921 for (cv = D_cvlist; cv; cv = cv->c_next)
2923 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2924 display = cv->c_display; /* just in case! */
2926 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2929 void
2930 RefreshArea(xs, ys, xe, ye, isblank)
2931 int xs, ys, xe, ye, isblank;
2933 int y;
2934 ASSERT(display);
2935 debug2("Refresh Area: %d,%d", xs, ys);
2936 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2937 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2939 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2940 isblank = 1;
2942 for (y = ys; y <= ye; y++)
2943 RefreshLine(y, xs, xe, isblank);
2946 void
2947 RefreshLine(y, from, to, isblank)
2948 int y, from, to, isblank;
2950 struct viewport *vp, *lvp;
2951 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2952 struct layer *oldflayer;
2953 int xx, yy, l;
2954 char *buf;
2955 struct win *p;
2957 ASSERT(display);
2959 debug2("RefreshLine %d %d", y, from);
2960 debug2(" %d %d\n", to, isblank);
2962 if (D_status == STATUS_ON_WIN && y == STATLINE)
2964 if (to >= D_status_len)
2965 D_status_len = to + 1;
2966 return; /* can't refresh status */
2969 /* The following check makes plenty of sense. Unfortunately,
2970 vte-based terminals (notably gnome-terminal) experience a quirk
2971 that causes the final line not to update properly when it falls outside
2972 the scroll region; clearing the line with D_CE avoids the glitch,
2973 so we'll disable this perfectly sensible shortcut until such a time
2974 as widespread vte installations lack the glitch.
2976 See http://bugzilla.gnome.org/show_bug.cgi?id=542087 for current
2977 status of the VTE bug report, and
2978 https://savannah.gnu.org/bugs/index.php?23699 for the history from
2979 the Savannah BTS. */
2980 #if 0
2981 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2983 RefreshHStatus();
2984 return;
2986 #endif
2988 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2990 GotoPos(from, y);
2991 if (D_UT || D_BE)
2992 SetRendition(&mchar_null);
2993 AddCStr(D_CE);
2994 isblank = 1;
2996 while (from <= to)
2998 lcv = 0;
2999 lvp = 0;
3000 for (cv = display->d_cvlist; cv; cv = cv->c_next)
3002 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
3004 p = Layer2Window(cv->c_layer);
3005 #ifdef SCRIPT
3006 /*FIXME: is it okey to bypass all the following code?*/
3007 if (trigger_sevent(&globalevents.processcaption, cv))
3008 continue;
3009 #endif
3010 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
3011 if (cv->c_captev.timeout.tv_sec)
3012 evenq(&cv->c_captev);
3013 xx = to > cv->c_xe ? cv->c_xe : to;
3014 l = strlen(buf);
3015 GotoPos(from, y);
3016 SetRendition(&mchar_so);
3017 if (l > xx - cv->c_xs + 1)
3018 l = xx - cv->c_xs + 1;
3019 PutWinMsg(buf, from - cv->c_xs, l);
3020 from = cv->c_xs + l;
3021 for (; from <= xx; from++)
3022 PUTCHARLP(' ');
3023 break;
3025 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
3027 GotoPos(from, y);
3028 SetRendition(&mchar_so);
3029 PUTCHARLP(' ');
3030 from++;
3031 break;
3033 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
3034 continue;
3035 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
3036 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
3037 for (vp = cv->c_vplist; vp; vp = vp->v_next)
3039 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
3040 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3041 /* find leftmost overlapping vp */
3042 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))
3044 lcv = cv;
3045 lvp = vp;
3049 if (cv)
3050 continue; /* we advanced from */
3051 if (lvp == 0)
3052 break;
3053 if (from < lvp->v_xs)
3055 if (!isblank)
3056 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3057 from = lvp->v_xs;
3060 /* call LayRedisplayLine on canvas lcv viewport lvp */
3061 yy = y - lvp->v_yoff;
3062 xx = to < lvp->v_xe ? to : lvp->v_xe;
3064 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3066 GotoPos(from, y);
3067 SetRendition(&mchar_blank);
3068 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3070 PUTCHARLP('-');
3071 from++;
3073 if (from >= lvp->v_xe + 1)
3074 continue;
3076 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3078 if (!isblank)
3079 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3080 from = lvp->v_xe + 1;
3081 continue;
3084 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3085 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3086 oldflayer = flayer;
3087 flayer = lcv->c_layer;
3088 cvlist = flayer->l_cvlist;
3089 cvlnext = lcv->c_lnext;
3090 flayer->l_cvlist = lcv;
3091 lcv->c_lnext = 0;
3092 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3093 flayer->l_cvlist = cvlist;
3094 lcv->c_lnext = cvlnext;
3095 flayer = oldflayer;
3097 from = xx + 1;
3099 if (!isblank && from <= to)
3100 DisplayLine(&mline_null, &mline_blank, y, from, to);
3103 /*********************************************************************/
3105 /* clear lp_missing by writing the char on the screen. The
3106 * position must be safe.
3108 static void
3109 WriteLP(x2, y2)
3110 int x2, y2;
3112 struct mchar oldrend;
3114 ASSERT(display);
3115 ASSERT(D_lp_missing);
3116 oldrend = D_rend;
3117 debug2("WriteLP(%d,%d)\n", x2, y2);
3118 #ifdef DW_CHARS
3119 if (D_lpchar.mbcs)
3121 if (x2 > 0)
3122 x2--;
3123 else
3124 D_lpchar = mchar_blank;
3126 #endif
3127 /* Can't use PutChar */
3128 GotoPos(x2, y2);
3129 SetRendition(&D_lpchar);
3130 PUTCHAR(D_lpchar.image);
3131 #ifdef DW_CHARS
3132 if (D_lpchar.mbcs)
3133 PUTCHAR(D_lpchar.mbcs);
3134 #endif
3135 D_lp_missing = 0;
3136 SetRendition(&oldrend);
3139 void
3140 ClearLine(oml, y, from, to, bce)
3141 struct mline *oml;
3142 int from, to, y, bce;
3144 int x;
3145 #ifdef COLOR
3146 struct mchar bcechar;
3147 #endif
3149 debug3("ClearLine %d,%d-%d\n", y, from, to);
3150 if (D_UT) /* Safe to erase ? */
3151 SetRendition(&mchar_null);
3152 #ifdef COLOR
3153 if (D_BE)
3154 SetBackColor(bce);
3155 #endif
3156 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3158 GotoPos(to, y);
3159 AddCStr(D_CB);
3160 return;
3162 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3164 GotoPos(from, y);
3165 AddCStr(D_CE);
3166 return;
3168 if (oml == 0)
3169 oml = &mline_null;
3170 #ifdef COLOR
3171 if (!bce)
3173 DisplayLine(oml, &mline_blank, y, from, to);
3174 return;
3176 bcechar = mchar_blank;
3177 rend_setbg(&bcechar, bce);
3178 for (x = from; x <= to; x++)
3179 copy_mchar2mline(&bcechar, &mline_old, x);
3180 DisplayLine(oml, &mline_old, y, from, to);
3181 #else
3182 DisplayLine(oml, &mline_blank, y, from, to);
3183 #endif
3186 void
3187 DisplayLine(oml, ml, y, from, to)
3188 struct mline *oml, *ml;
3189 int from, to, y;{
3191 register int x;
3192 int last2flag = 0, delete_lp = 0;
3194 ASSERT(display);
3195 ASSERT(y >= 0 && y < D_height);
3196 ASSERT(from >= 0 && from < D_width);
3197 ASSERT(to >= 0 && to < D_width);
3198 if (!D_CLP && y == D_bot && to == D_width - 1)
3200 if (D_lp_missing || !cmp_mline(oml, ml, to))
3202 #ifdef DW_CHARS
3203 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3204 #else
3205 if ((D_IC || D_IM) && from < to)
3206 #endif
3208 last2flag = 1;
3209 D_lp_missing = 0;
3210 to--;
3212 else
3214 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3215 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3216 copy_mline2mchar(&D_lpchar, ml, to);
3219 to--;
3221 #ifdef DW_CHARS
3222 if (D_mbcs)
3224 /* finish dw-char (can happen after a wrap) */
3225 debug("DisplayLine finishing kanji\n");
3226 SetRenditionMline(ml, from);
3227 PUTCHAR(ml->image[from]);
3228 from++;
3230 #endif
3231 for (x = from; x <= to; x++)
3233 #if 0 /* no longer needed */
3234 if (x || D_x != D_width || D_y != y - 1)
3235 #endif
3237 if (x < to || x != D_width - 1 || ml->image[x + 1])
3238 if (cmp_mline(oml, ml, x))
3239 continue;
3240 GotoPos(x, y);
3242 #ifdef DW_CHARS
3243 if (dw_right(ml, x, D_encoding))
3245 x--;
3246 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3247 GotoPos(x, y);
3249 if (x == to && dw_left(ml, x, D_encoding))
3250 break; /* don't start new kanji */
3251 #endif
3252 SetRenditionMline(ml, x);
3253 PUTCHAR(ml->image[x]);
3254 #ifdef DW_CHARS
3255 if (dw_left(ml, x, D_encoding))
3256 PUTCHAR(ml->image[++x]);
3257 #endif
3259 #if 0 /* not needed any longer */
3260 /* compare != 0 because ' ' can happen when clipping occures */
3261 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3262 GotoPos(0, y + 1);
3263 #endif
3264 if (last2flag)
3266 GotoPos(x, y);
3267 SetRenditionMline(ml, x + 1);
3268 PUTCHAR(ml->image[x + 1]);
3269 GotoPos(x, y);
3270 SetRenditionMline(ml, x);
3271 INSERTCHAR(ml->image[x]);
3273 else if (delete_lp)
3275 if (D_UT)
3276 SetRendition(&mchar_null);
3277 if (D_DC)
3278 AddCStr(D_DC);
3279 else if (D_CDC)
3280 AddCStr2(D_CDC, 1);
3281 else if (D_CE)
3282 AddCStr(D_CE);
3286 void
3287 PutChar(c, x, y)
3288 struct mchar *c;
3289 int x, y;
3291 GotoPos(x, y);
3292 SetRendition(c);
3293 PUTCHARLP(c->image);
3294 #ifdef DW_CHARS
3295 if (c->mbcs)
3297 # ifdef UTF8
3298 if (D_encoding == UTF8)
3299 D_rend.font = 0;
3300 # endif
3301 PUTCHARLP(c->mbcs);
3303 #endif
3306 void
3307 InsChar(c, x, xe, y, oml)
3308 struct mchar *c;
3309 int x, xe, y;
3310 struct mline *oml;
3312 GotoPos(x, y);
3313 if (y == D_bot && !D_CLP)
3315 if (x == D_width - 1)
3317 D_lp_missing = 1;
3318 D_lpchar = *c;
3319 return;
3321 if (xe == D_width - 1)
3322 D_lp_missing = 0;
3324 if (x == xe)
3326 SetRendition(c);
3327 PUTCHARLP(c->image);
3328 return;
3330 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3332 RefreshLine(y, x, xe, 0);
3333 GotoPos(x + 1, y);
3334 /* UpdateLine(oml, y, x, xe); */
3335 return;
3337 InsertMode(1);
3338 if (!D_insert)
3340 #ifdef DW_CHARS
3341 if (c->mbcs && D_IC)
3342 AddCStr(D_IC);
3343 if (D_IC)
3344 AddCStr(D_IC);
3345 else
3346 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3347 #else
3348 if (D_IC)
3349 AddCStr(D_IC);
3350 else
3351 AddCStr2(D_CIC, 1);
3352 #endif
3354 SetRendition(c);
3355 RAW_PUTCHAR(c->image);
3356 #ifdef DW_CHARS
3357 if (c->mbcs)
3359 # ifdef UTF8
3360 if (D_encoding == UTF8)
3361 D_rend.font = 0;
3362 # endif
3363 if (D_x == D_width - 1)
3364 PUTCHARLP(c->mbcs);
3365 else
3366 RAW_PUTCHAR(c->mbcs);
3368 #endif
3371 void
3372 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3373 struct mchar *c;
3374 int x, y;
3375 int xs, ys, xe, ye;
3376 int ins;
3378 int bce;
3380 #ifdef COLOR
3381 bce = rend_getbg(c);
3382 #else
3383 bce = 0;
3384 #endif
3385 debug("WrapChar:");
3386 debug2(" x %d y %d", x, y);
3387 debug2(" Dx %d Dy %d", D_x, D_y);
3388 debug2(" xs %d ys %d", xs, ys);
3389 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3390 if (xs != 0 || x != D_width || !D_AM)
3392 if (y == ye)
3393 ScrollV(xs, ys, xe, ye, 1, bce);
3394 else if (y < D_height - 1)
3395 y++;
3396 if (ins)
3397 InsChar(c, xs, xe, y, 0);
3398 else
3399 PutChar(c, xs, y);
3400 return;
3402 if (y == ye) /* we have to scroll */
3404 debug("- scrolling\n");
3405 ChangeScrollRegion(ys, ye);
3406 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3408 debug("- have to call ScrollV\n");
3409 ScrollV(xs, ys, xe, ye, 1, bce);
3410 y--;
3413 else if (y == D_bot) /* remove unusable region? */
3414 ChangeScrollRegion(0, D_height - 1);
3415 if (D_x != D_width || D_y != y)
3417 if (D_CLP && y >= 0) /* don't even try if !LP */
3418 RefreshLine(y, D_width - 1, D_width - 1, 0);
3419 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3420 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3422 if (y == ye)
3423 ScrollV(xs, ys, xe, ye, 1, bce);
3424 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3427 debug("- writeing new char");
3428 if (y != ye && y < D_height - 1)
3429 y++;
3430 if (ins != D_insert)
3431 InsertMode(ins);
3432 if (ins && !D_insert)
3434 InsChar(c, 0, xe, y, 0);
3435 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3436 return;
3438 D_y = y;
3439 D_x = 0;
3440 SetRendition(c);
3441 RAW_PUTCHAR(c->image);
3442 #ifdef DW_CHARS
3443 if (c->mbcs)
3445 # ifdef UTF8
3446 if (D_encoding == UTF8)
3447 D_rend.font = 0;
3448 # endif
3449 RAW_PUTCHAR(c->mbcs);
3451 #endif
3452 debug2(" -> done (%d,%d)\n", D_x, D_y);
3456 ResizeDisplay(wi, he)
3457 int wi, he;
3459 ASSERT(display);
3460 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3461 if (D_width == wi && D_height == he)
3463 debug("ResizeDisplay: No change\n");
3464 return 0;
3466 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3468 debug("ResizeDisplay: using Z0/Z1\n");
3469 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3470 ChangeScreenSize(wi, D_height, 0);
3471 return (he == D_height) ? 0 : -1;
3473 if (D_CWS)
3475 debug("ResizeDisplay: using WS\n");
3476 AddCStr(tgoto(D_CWS, wi, he));
3477 ChangeScreenSize(wi, he, 0);
3478 return 0;
3480 return -1;
3483 void
3484 ChangeScrollRegion(newtop, newbot)
3485 int newtop, newbot;
3487 if (display == 0)
3488 return;
3489 if (newtop == newbot)
3490 return; /* xterm etc can't do it */
3491 if (newtop == -1)
3492 newtop = 0;
3493 if (newbot == -1)
3494 newbot = D_height - 1;
3495 if (D_CS == 0)
3497 D_top = 0;
3498 D_bot = D_height - 1;
3499 return;
3501 if (D_top == newtop && D_bot == newbot)
3502 return;
3503 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3504 AddCStr(tgoto(D_CS, newbot, newtop));
3505 D_top = newtop;
3506 D_bot = newbot;
3507 D_y = D_x = -1; /* Just in case... */
3510 #ifdef RXVT_OSC
3511 void
3512 SetXtermOSC(i, s)
3513 int i;
3514 char *s;
3516 static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3518 ASSERT(display);
3519 if (!D_CXT)
3520 return;
3521 if (!s)
3522 s = "";
3523 if (!D_xtermosc[i] && !*s)
3524 return;
3525 if (i == 0 && !*s)
3526 s = "screen"; /* always set icon name */
3527 if (i == 1 && !*s)
3528 s = ""; /* no background */
3529 if (i == 2 && !*s)
3530 s = "black"; /* black text */
3531 if (i == 3 && !*s)
3532 s = "white"; /* on white background */
3533 D_xtermosc[i] = 1;
3534 AddStr("\033]");
3535 AddStr(oscs + i * 4);
3536 AddStr(s);
3537 AddChar(7);
3540 void
3541 ClearAllXtermOSC()
3543 int i;
3544 for (i = 3; i >= 0; i--)
3545 SetXtermOSC(i, 0);
3547 #endif
3550 * Output buffering routines
3553 void
3554 AddStr(str)
3555 char *str;
3557 register char c;
3559 ASSERT(display);
3561 #ifdef UTF8
3562 if (D_encoding == UTF8)
3564 while ((c = *str++))
3565 AddUtf8((unsigned char)c);
3566 return;
3568 #endif
3569 while ((c = *str++))
3570 AddChar(c);
3573 void
3574 AddStrn(str, n)
3575 char *str;
3576 int n;
3578 register char c;
3580 ASSERT(display);
3581 #ifdef UTF8
3582 if (D_encoding == UTF8)
3584 while ((c = *str++) && n-- > 0)
3585 AddUtf8((unsigned char)c);
3587 else
3588 #endif
3589 while ((c = *str++) && n-- > 0)
3590 AddChar(c);
3591 while (n-- > 0)
3592 AddChar(' ');
3595 void
3596 Flush()
3598 register int l;
3599 register char *p;
3601 ASSERT(display);
3602 l = D_obufp - D_obuf;
3603 debug1("Flush(): %d\n", l);
3604 if (l == 0)
3605 return;
3606 ASSERT(l + D_obuffree == D_obuflen);
3607 if (D_userfd < 0)
3609 D_obuffree += l;
3610 D_obufp = D_obuf;
3611 return;
3613 p = D_obuf;
3614 if (fcntl(D_userfd, F_SETFL, 0))
3615 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3616 while (l)
3618 register int wr;
3619 wr = write(D_userfd, p, l);
3620 if (wr <= 0)
3622 if (errno == EINTR)
3623 continue;
3624 debug1("Writing to display: %d\n", errno);
3625 wr = l;
3627 if (!display)
3628 return;
3629 D_obuffree += wr;
3630 p += wr;
3631 l -= wr;
3633 D_obuffree += l;
3634 D_obufp = D_obuf;
3635 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3636 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3637 if (D_blocked == 1)
3638 D_blocked = 0;
3639 D_blocked_fuzz = 0;
3642 void
3643 freetty()
3645 if (D_userfd >= 0)
3646 close(D_userfd);
3647 debug1("did freetty %d\n", D_userfd);
3648 D_userfd = -1;
3649 D_obufp = 0;
3650 D_obuffree = 0;
3651 if (D_obuf)
3652 free(D_obuf);
3653 D_obuf = 0;
3654 D_obuflen = 0;
3655 D_obuflenmax = -D_obufmax;
3656 D_blocked = 0;
3657 D_blocked_fuzz = 0;
3661 * Asynchronous output routines by
3662 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3665 void
3666 Resize_obuf()
3668 register int ind;
3670 ASSERT(display);
3671 if (D_status_obuffree >= 0)
3673 ASSERT(D_obuffree == -1);
3674 if (!D_status_bell)
3676 struct timeval now;
3677 int ti;
3678 gettimeofday(&now, NULL);
3679 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3680 if (ti < MsgMinWait)
3681 DisplaySleep1000(MsgMinWait - ti, 0);
3683 RemoveStatus();
3684 if (--D_obuffree > 0) /* redo AddChar decrement */
3685 return;
3687 if (D_obuflen && D_obuf)
3689 ind = D_obufp - D_obuf;
3690 D_obuflen += GRAIN;
3691 D_obuffree += GRAIN;
3692 D_obuf = realloc(D_obuf, D_obuflen);
3694 else
3696 ind = 0;
3697 D_obuflen = GRAIN;
3698 D_obuffree = GRAIN;
3699 D_obuf = malloc(D_obuflen);
3701 if (!D_obuf)
3702 Panic(0, "Out of memory");
3703 D_obufp = D_obuf + ind;
3704 D_obuflenmax = D_obuflen - D_obufmax;
3705 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3708 void
3709 DisplaySleep1000(n, eat)
3710 int n;
3711 int eat;
3713 char buf;
3714 fd_set r;
3715 struct timeval t;
3717 if (n <= 0)
3718 return;
3719 if (!display)
3721 debug("DisplaySleep has no display sigh\n");
3722 sleep1000(n);
3723 return;
3725 t.tv_usec = (n % 1000) * 1000;
3726 t.tv_sec = n / 1000;
3727 FD_ZERO(&r);
3728 FD_SET(D_userfd, &r);
3729 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3731 debug("display activity stopped sleep\n");
3732 if (eat)
3733 read(D_userfd, &buf, 1);
3735 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3738 #ifdef AUTO_NUKE
3739 void
3740 NukePending()
3741 {/* Nuke pending output in current display, clear screen */
3742 register int len;
3743 int oldtop = D_top, oldbot = D_bot;
3744 struct mchar oldrend;
3745 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3746 int oldcurvis = D_curvis;
3747 int oldmouse = D_mouse;
3749 oldrend = D_rend;
3750 len = D_obufp - D_obuf;
3751 debug1("NukePending: nuking %d chars\n", len);
3753 /* Throw away any output that we can... */
3754 # ifdef POSIX
3755 tcflush(D_userfd, TCOFLUSH);
3756 # else
3757 # ifdef TCFLSH
3758 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3759 # endif
3760 # endif
3762 D_obufp = D_obuf;
3763 D_obuffree += len;
3764 D_top = D_bot = -1;
3765 AddCStr(D_IS);
3766 AddCStr(D_TI);
3767 /* Turn off all attributes. (Tim MacKenzie) */
3768 if (D_ME)
3769 AddCStr(D_ME);
3770 else
3772 #ifdef COLOR
3773 if (D_hascolor)
3774 AddStr("\033[m"); /* why is D_ME not set? */
3775 #endif
3776 AddCStr(D_SE);
3777 AddCStr(D_UE);
3779 /* Check for toggle */
3780 if (D_IM && strcmp(D_IM, D_EI))
3781 AddCStr(D_EI);
3782 D_insert = 0;
3783 /* Check for toggle */
3784 #ifdef MAPKEYS
3785 if (D_KS && strcmp(D_KS, D_KE))
3786 AddCStr(D_KS);
3787 if (D_CCS && strcmp(D_CCS, D_CCE))
3788 AddCStr(D_CCS);
3789 #else
3790 if (D_KS && strcmp(D_KS, D_KE))
3791 AddCStr(D_KE);
3792 D_keypad = 0;
3793 if (D_CCS && strcmp(D_CCS, D_CCE))
3794 AddCStr(D_CCE);
3795 D_cursorkeys = 0;
3796 #endif
3797 AddCStr(D_CE0);
3798 D_rend = mchar_null;
3799 D_atyp = 0;
3800 AddCStr(D_DS);
3801 D_hstatus = 0;
3802 AddCStr(D_VE);
3803 D_curvis = 0;
3804 ChangeScrollRegion(oldtop, oldbot);
3805 SetRendition(&oldrend);
3806 KeypadMode(oldkeypad);
3807 CursorkeysMode(oldcursorkeys);
3808 CursorVisibility(oldcurvis);
3809 MouseMode(oldmouse);
3810 if (D_CWS)
3812 debug("ResizeDisplay: using WS\n");
3813 AddCStr(tgoto(D_CWS, D_width, D_height));
3815 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3817 debug("ResizeDisplay: using Z0/Z1\n");
3818 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3821 #endif /* AUTO_NUKE */
3823 #ifdef linux
3824 /* linux' select can't handle flow control, so wait 100ms if
3825 * we get EAGAIN
3827 static void
3828 disp_writeev_eagain(ev, data)
3829 struct event *ev;
3830 char *data;
3832 display = (struct display *)data;
3833 evdeq(&D_writeev);
3834 D_writeev.type = EV_WRITE;
3835 D_writeev.handler = disp_writeev_fn;
3836 evenq(&D_writeev);
3838 #endif
3840 static void
3841 disp_writeev_fn(ev, data)
3842 struct event *ev;
3843 char *data;
3845 int len, size = OUTPUT_BLOCK_SIZE;
3847 display = (struct display *)data;
3848 len = D_obufp - D_obuf;
3849 if (len < size)
3850 size = len;
3851 ASSERT(len >= 0);
3852 size = write(D_userfd, D_obuf, size);
3853 if (size >= 0)
3855 len -= size;
3856 if (len)
3858 bcopy(D_obuf + size, D_obuf, len);
3859 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3861 D_obufp -= size;
3862 D_obuffree += size;
3863 if (D_blocked_fuzz)
3865 D_blocked_fuzz -= size;
3866 if (D_blocked_fuzz < 0)
3867 D_blocked_fuzz = 0;
3869 if (D_blockedev.queued)
3871 if (D_obufp - D_obuf > D_obufmax / 2)
3873 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3874 SetTimeout(&D_blockedev, D_nonblock);
3876 else
3878 debug1("%s: deleting blocked timeout\n", D_usertty);
3879 evdeq(&D_blockedev);
3882 if (D_blocked == 1 && D_obuf == D_obufp)
3884 /* empty again, restart output */
3885 debug1("%s: buffer empty, unblocking\n", D_usertty);
3886 D_blocked = 0;
3887 Activate(D_fore ? D_fore->w_norefresh : 0);
3888 D_blocked_fuzz = D_obufp - D_obuf;
3891 else
3893 #ifdef linux
3894 /* linux flow control is badly broken */
3895 if (errno == EAGAIN)
3897 evdeq(&D_writeev);
3898 D_writeev.type = EV_TIMEOUT;
3899 D_writeev.handler = disp_writeev_eagain;
3900 SetTimeout(&D_writeev, 100);
3901 evenq(&D_writeev);
3903 #endif
3904 if (errno != EINTR && errno != EAGAIN)
3905 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3906 if (errno != EWOULDBLOCK)
3907 #endif
3908 Msg(errno, "Error writing output to display");
3912 static void
3913 disp_readev_fn(ev, data)
3914 struct event *ev;
3915 char *data;
3917 int size;
3918 char buf[IOSIZE];
3919 struct canvas *cv;
3921 display = (struct display *)data;
3923 /* Hmmmm... a bit ugly... */
3924 if (D_forecv)
3925 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3927 display = cv->c_display;
3928 if (D_status == STATUS_ON_WIN)
3929 RemoveStatus();
3932 display = (struct display *)data;
3933 if (D_fore == 0)
3934 size = IOSIZE;
3935 else
3937 #ifdef PSEUDOS
3938 if (W_UWP(D_fore))
3939 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3940 else
3941 #endif
3942 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3945 if (size > IOSIZE)
3946 size = IOSIZE;
3947 if (size <= 0)
3948 size = 1; /* Always allow one char for command keys */
3950 size = read(D_userfd, buf, size);
3951 if (size < 0)
3953 if (errno == EINTR || errno == EAGAIN)
3954 return;
3955 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3956 if (errno == EWOULDBLOCK)
3957 return;
3958 #endif
3959 debug1("Read error: %d - hangup!\n", errno);
3960 Hangup();
3961 sleep(1);
3962 return;
3964 else if (size == 0)
3966 debug("Found EOF - hangup!\n");
3967 Hangup();
3968 sleep(1);
3969 return;
3971 if (D_blocked == 4)
3973 D_blocked = 0;
3974 #ifdef BLANKER_PRG
3975 KillBlanker();
3976 #endif
3977 Activate(D_fore ? D_fore->w_norefresh : 0);
3978 ResetIdle();
3979 return;
3981 #ifdef ZMODEM
3982 if (D_blocked > 1) /* 2, 3 */
3984 char *bufp;
3985 struct win *p;
3987 flayer = 0;
3988 for (p = windows; p ; p = p->w_next)
3989 if (p->w_zdisplay == display)
3991 flayer = &p->w_layer;
3992 bufp = buf;
3993 while (size > 0)
3994 LayProcess(&bufp, &size);
3995 return;
3997 debug("zmodem window gone, deblocking display");
3998 zmodem_abort(0, display);
4000 #endif
4001 if (idletimo > 0)
4002 ResetIdle();
4003 if (D_fore)
4004 D_fore->w_lastdisp = display;
4005 if (D_mouse && D_forecv)
4007 unsigned char *bp = (unsigned char *)buf;
4008 int x, y, i = size;
4010 /* XXX this assumes that the string is read in as a whole... */
4011 for (i = size; i > 0; i--, bp++)
4013 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
4015 bp++;
4016 i--;
4018 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
4019 continue;
4020 x = bp[3] - 33;
4021 y = bp[4] - 33;
4022 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
4024 x -= D_forecv->c_xoff;
4025 y -= D_forecv->c_yoff;
4026 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
4028 bp[3] = x + 33;
4029 bp[4] = y + 33;
4030 i -= 4;
4031 bp += 4;
4032 continue;
4035 if (bp[0] == '[')
4037 bcopy((char *)bp + 1, (char *)bp, i);
4038 bp--;
4039 size--;
4041 if (i > 5)
4042 bcopy((char *)bp + 5, (char *)bp, i - 5);
4043 bp--;
4044 i -= 4;
4045 size -= 5;
4048 #ifdef ENCODINGS
4049 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4051 int i, j, c, enc;
4052 char buf2[IOSIZE * 2 + 10];
4053 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4054 for (i = j = 0; i < size; i++)
4056 c = ((unsigned char *)buf)[i];
4057 c = DecodeChar(c, D_encoding, &D_decodestate);
4058 if (c == -2)
4059 i--; /* try char again */
4060 if (c < 0)
4061 continue;
4062 if (pastefont)
4064 int font = 0;
4065 j += EncodeChar(buf2 + j, c, enc, &font);
4066 j += EncodeChar(buf2 + j, -1, enc, &font);
4068 else
4069 j += EncodeChar(buf2 + j, c, enc, 0);
4070 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4071 break;
4073 (*D_processinput)(buf2, j);
4074 return;
4076 #endif
4077 (*D_processinput)(buf, size);
4080 static void
4081 disp_status_fn(ev, data)
4082 struct event *ev;
4083 char *data;
4085 display = (struct display *)data;
4086 debug1("disp_status_fn for display %x\n", (int)display);
4087 if (D_status)
4088 RemoveStatus();
4091 static void
4092 disp_hstatus_fn(ev, data)
4093 struct event *ev;
4094 char *data;
4096 display = (struct display *)data;
4097 if (D_status == STATUS_ON_HS)
4099 SetTimeout(ev, 1);
4100 evenq(ev);
4101 return;
4103 RefreshHStatus();
4106 static void
4107 disp_blocked_fn(ev, data)
4108 struct event *ev;
4109 char *data;
4111 struct win *p;
4113 display = (struct display *)data;
4114 debug1("blocked timeout %s\n", D_usertty);
4115 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4117 debug("stopping output to display\n");
4118 D_blocked = 1;
4119 /* re-enable all windows */
4120 for (p = windows; p; p = p->w_next)
4121 if (p->w_readev.condneg == &D_obuflenmax)
4123 debug1("freeing window #%d\n", p->w_number);
4124 p->w_readev.condpos = p->w_readev.condneg = 0;
4129 static void
4130 cv_winid_fn(ev, data)
4131 struct event *ev;
4132 char *data;
4134 int ox, oy;
4135 struct canvas *cv = (struct canvas *)data;
4137 display = cv->c_display;
4138 if (D_status == STATUS_ON_WIN)
4140 SetTimeout(ev, 1);
4141 evenq(ev);
4142 return;
4144 ox = D_x;
4145 oy = D_y;
4146 if (cv->c_ye + 1 < D_height)
4147 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4148 if (ox != -1 && oy != -1)
4149 GotoPos(ox, oy);
4152 #ifdef MAPKEYS
4153 static void
4154 disp_map_fn(ev, data)
4155 struct event *ev;
4156 char *data;
4158 char *p;
4159 int l, i;
4160 unsigned char *q;
4161 display = (struct display *)data;
4162 debug("Flushing map sequence\n");
4163 if (!(l = D_seql))
4164 return;
4165 p = (char *)D_seqp - l;
4166 D_seqp = D_kmaps + 3;
4167 D_seql = 0;
4168 if ((q = D_seqh) != 0)
4170 D_seqh = 0;
4171 i = q[0] << 8 | q[1];
4172 i &= ~KMAP_NOTIMEOUT;
4173 debug1("Mapping former hit #%d - ", i);
4174 debug2("%d(%s) - ", q[2], q + 3);
4175 if (StuffKey(i))
4176 ProcessInput2((char *)q + 3, q[2]);
4177 if (display == 0)
4178 return;
4179 l -= q[2];
4180 p += q[2];
4182 else
4183 D_dontmap = 1;
4184 ProcessInput(p, l);
4186 #endif
4188 static void
4189 disp_idle_fn(ev, data)
4190 struct event *ev;
4191 char *data;
4193 struct display *olddisplay;
4194 display = (struct display *)data;
4195 #ifdef SCRIPT
4196 if (trigger_sevent(&display->d_sev.onidle, display))
4197 return;
4198 #endif
4199 debug("idle timeout\n");
4200 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4201 return;
4202 olddisplay = display;
4203 flayer = D_forecv->c_layer;
4204 fore = D_fore;
4205 DoAction(&idleaction, -1);
4206 if (idleaction.nr == RC_BLANKER)
4207 return;
4208 for (display = displays; display; display = display->d_next)
4209 if (olddisplay == display)
4210 break;
4211 if (display)
4212 ResetIdle();
4215 void
4216 ResetIdle()
4218 if (idletimo > 0)
4220 SetTimeout(&D_idleev, idletimo);
4221 if (!D_idleev.queued)
4222 evenq(&D_idleev);
4224 else
4225 evdeq(&D_idleev);
4229 #ifdef BLANKER_PRG
4231 static void
4232 disp_blanker_fn(ev, data)
4233 struct event *ev;
4234 char *data;
4236 char buf[IOSIZE], *b;
4237 int size;
4239 display = (struct display *)data;
4240 size = read(D_blankerev.fd, buf, IOSIZE);
4241 if (size <= 0)
4243 evdeq(&D_blankerev);
4244 close(D_blankerev.fd);
4245 D_blankerev.fd = -1;
4246 return;
4248 for (b = buf; size; size--)
4249 AddChar(*b++);
4252 void
4253 KillBlanker()
4255 int oldtop = D_top, oldbot = D_bot;
4256 struct mchar oldrend;
4258 if (D_blankerev.fd == -1)
4259 return;
4260 if (D_blocked == 4)
4261 D_blocked = 0;
4262 evdeq(&D_blankerev);
4263 close(D_blankerev.fd);
4264 D_blankerev.fd = -1;
4265 Kill(D_blankerpid, SIGHUP);
4266 D_top = D_bot = -1;
4267 oldrend = D_rend;
4268 if (D_ME)
4270 AddCStr(D_ME);
4271 AddCStr(D_ME);
4273 else
4275 #ifdef COLOR
4276 if (D_hascolor)
4277 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4278 #endif
4279 AddCStr(D_SE);
4280 AddCStr(D_UE);
4282 AddCStr(D_VE);
4283 AddCStr(D_CE0);
4284 D_rend = mchar_null;
4285 D_atyp = 0;
4286 D_curvis = 0;
4287 D_x = D_y = -1;
4288 ChangeScrollRegion(oldtop, oldbot);
4289 SetRendition(&oldrend);
4290 ClearAll();
4293 void
4294 RunBlanker(cmdv)
4295 char **cmdv;
4297 char *m;
4298 int pid;
4299 int slave = -1;
4300 char termname[30];
4301 #ifndef TIOCSWINSZ
4302 char libuf[20], cobuf[20];
4303 #endif
4304 char **np;
4306 strcpy(termname, "TERM=");
4307 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4308 termname[sizeof(termname) - 1] = 0;
4309 KillBlanker();
4310 D_blankerpid = -1;
4311 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4313 Msg(0, "OpenPty failed");
4314 return;
4316 #ifdef O_NOCTTY
4317 if (pty_preopen)
4319 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4321 Msg(errno, "%s", m);
4322 close(D_blankerev.fd);
4323 D_blankerev.fd = -1;
4324 return;
4327 #endif
4328 switch (pid = (int)fork())
4330 case -1:
4331 Msg(errno, "fork");
4332 close(D_blankerev.fd);
4333 D_blankerev.fd = -1;
4334 return;
4335 case 0:
4336 displays = 0;
4337 #ifdef DEBUG
4338 if (dfp && dfp != stderr)
4340 fclose(dfp);
4341 dfp = 0;
4343 #endif
4344 if (setgid(real_gid) || setuid(real_uid))
4345 Panic(errno, "setuid/setgid");
4346 brktty(D_userfd);
4347 freetty();
4348 close(0);
4349 close(1);
4350 close(2);
4351 closeallfiles(slave);
4352 if (open(m, O_RDWR))
4353 Panic(errno, "Cannot open %s", m);
4354 dup(0);
4355 dup(0);
4356 if (slave != -1)
4357 close(slave);
4358 InitPTY(0);
4359 fgtty(0);
4360 SetTTY(0, &D_OldMode);
4361 np = NewEnv + 3;
4362 *np++ = NewEnv[0];
4363 *np++ = termname;
4364 #ifdef TIOCSWINSZ
4365 glwz.ws_col = D_width;
4366 glwz.ws_row = D_height;
4367 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4368 #else
4369 sprintf(libuf, "LINES=%d", D_height);
4370 sprintf(cobuf, "COLUMNS=%d", D_width);
4371 *np++ = libuf;
4372 *np++ = cobuf;
4373 #endif
4374 #ifdef SIGPIPE
4375 signal(SIGPIPE, SIG_DFL);
4376 #endif
4377 display = 0;
4378 execvpe(*cmdv, cmdv, NewEnv + 3);
4379 Panic(errno, "%s", *cmdv);
4380 default:
4381 break;
4383 D_blankerpid = pid;
4384 evenq(&D_blankerev);
4385 D_blocked = 4;
4386 ClearAll();
4389 #endif
4391 struct layout *layouts;
4392 struct layout *laytab[MAXLAY];
4393 struct layout *layout_last, layout_last_marker;
4394 struct layout *layout_attach = &layout_last_marker;
4396 void
4397 FreeLayoutCv(cv)
4398 struct canvas *cv;
4400 struct canvas *cnext, *c = cv;
4401 for (; cv; cv = cnext)
4403 if (cv->c_slperp)
4405 FreeLayoutCv(cv->c_slperp);
4406 free(cv->c_slperp);
4407 cv->c_slperp = 0;
4409 cnext = cv->c_slnext;
4410 cv->c_slnext = 0;
4411 if (cv != c)
4412 free(cv);
4416 static void
4417 DupLayoutCv(cvf, cvt, save)
4418 struct canvas *cvf, *cvt;
4419 int save;
4421 while(cvf)
4423 cvt->c_slorient = cvf->c_slorient;
4424 cvt->c_slweight = cvf->c_slweight;
4425 if (cvf == D_forecv)
4426 D_forecv = cvt;
4427 if (!save)
4429 cvt->c_display = display;
4430 if (!cvf->c_slperp)
4432 cvt->c_captev.type = EV_TIMEOUT;
4433 cvt->c_captev.data = (char *)cvt;
4434 cvt->c_captev.handler = cv_winid_fn;
4435 cvt->c_blank.l_cvlist = 0;
4436 cvt->c_blank.l_layfn = &BlankLf;
4437 cvt->c_blank.l_bottom = &cvt->c_blank;
4439 cvt->c_layer = cvf->c_layer;
4441 else
4443 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4444 cvt->c_layer = p ? &p->w_layer : 0;
4446 if (cvf->c_slperp)
4448 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4449 cvt->c_slperp->c_slback = cvt;
4450 CanvasInitBlank(cvt->c_slperp);
4451 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4453 if (cvf->c_slnext)
4455 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4456 cvt->c_slnext->c_slprev = cvt;
4457 cvt->c_slnext->c_slback = cvt->c_slback;
4458 CanvasInitBlank(cvt->c_slnext);
4460 cvf = cvf->c_slnext;
4461 cvt = cvt->c_slnext;
4465 void
4466 PutWindowCv(cv)
4467 struct canvas *cv;
4469 struct win *p;
4470 for (; cv; cv = cv->c_slnext)
4472 if (cv->c_slperp)
4474 PutWindowCv(cv->c_slperp);
4475 continue;
4477 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4478 cv->c_layer = 0;
4479 SetCanvasWindow(cv, p);
4483 struct layout *
4484 CreateLayout(title, startat)
4485 char *title;
4486 int startat;
4488 struct layout *lay;
4489 int i;
4491 if (startat >= MAXLAY || startat < 0)
4492 startat = 0;
4493 for (i = startat; ;)
4495 if (!laytab[i])
4496 break;
4497 if (++i == MAXLAY)
4498 i = 0;
4499 if (i == startat)
4501 Msg(0, "No more layouts\n");
4502 return 0;
4505 lay = (struct layout *)calloc(1, sizeof(*lay));
4506 lay->lay_title = SaveStr(title);
4507 lay->lay_autosave = 1;
4508 lay->lay_number = i;
4509 laytab[i] = lay;
4510 lay->lay_next = layouts;
4511 layouts = lay;
4512 return lay;
4515 void
4516 SaveLayout(name, cv)
4517 char *name;
4518 struct canvas *cv;
4520 struct layout *lay;
4521 struct canvas *fcv;
4522 for (lay = layouts; lay; lay = lay->lay_next)
4523 if (!strcmp(lay->lay_title, name))
4524 break;
4525 if (lay)
4526 FreeLayoutCv(&lay->lay_canvas);
4527 else
4528 lay = CreateLayout(name, 0);
4529 if (!lay)
4530 return;
4531 fcv = D_forecv;
4532 DupLayoutCv(cv, &lay->lay_canvas, 1);
4533 lay->lay_forecv = D_forecv;
4534 D_forecv = fcv;
4535 D_layout = lay;
4538 void
4539 AutosaveLayout(lay)
4540 struct layout *lay;
4542 struct canvas *fcv;
4543 if (!lay || !lay->lay_autosave)
4544 return;
4545 FreeLayoutCv(&lay->lay_canvas);
4546 fcv = D_forecv;
4547 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4548 lay->lay_forecv = D_forecv;
4549 D_forecv = fcv;
4552 struct layout *
4553 FindLayout(name)
4554 char *name;
4556 struct layout *lay;
4557 char *s;
4558 int i;
4559 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4560 i = i * 10 + (*s - '0');
4561 if (!*s && s != name && i >= 0 && i < MAXLAY)
4562 return laytab[i];
4563 for (lay = layouts; lay; lay = lay->lay_next)
4564 if (!strcmp(lay->lay_title, name))
4565 break;
4566 return lay;
4569 void
4570 LoadLayout(lay, cv)
4571 struct layout *lay;
4572 struct canvas *cv;
4574 AutosaveLayout(D_layout);
4575 if (!lay)
4577 while (D_canvas.c_slperp)
4578 FreeCanvas(D_canvas.c_slperp);
4579 MakeDefaultCanvas();
4580 SetCanvasWindow(D_forecv, 0);
4581 D_layout = 0;
4582 return;
4584 while (D_canvas.c_slperp)
4585 FreeCanvas(D_canvas.c_slperp);
4586 D_cvlist = 0;
4587 D_forecv = lay->lay_forecv;
4588 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4589 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4590 ResizeCanvas(&D_canvas);
4591 RecreateCanvasChain();
4592 RethinkDisplayViewports();
4593 PutWindowCv(&D_canvas);
4594 ResizeLayersToCanvases();
4595 D_layout = lay;
4598 void
4599 NewLayout(title, startat)
4600 char *title;
4601 int startat;
4603 struct layout *lay;
4604 struct canvas *fcv;
4606 lay = CreateLayout(title, startat);
4607 if (!lay)
4608 return;
4609 LoadLayout(0, &D_canvas);
4610 fcv = D_forecv;
4611 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4612 lay->lay_forecv = D_forecv;
4613 D_forecv = fcv;
4614 D_layout = lay;
4615 lay->lay_autosave = 1;
4618 static char *
4619 AddLayoutsInfo(buf, len, where)
4620 char *buf;
4621 int len;
4622 int where;
4624 char *s, *ss, *t;
4625 struct layout *p, **pp;
4626 int l;
4628 s = ss = buf;
4629 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4631 if (pp - laytab == where && ss == buf)
4632 ss = s;
4633 if ((p = *pp) == 0)
4634 continue;
4635 t = p->lay_title;
4636 l = strlen(t);
4637 if (l > 20)
4638 l = 20;
4639 if (s - buf + l > len - 24)
4640 break;
4641 if (s > buf)
4643 *s++ = ' ';
4644 *s++ = ' ';
4646 sprintf(s, "%d", p->lay_number);
4647 if (p->lay_number == where)
4648 ss = s;
4649 s += strlen(s);
4650 if (display && p == D_layout)
4651 *s++ = '*';
4652 *s++ = ' ';
4653 strncpy(s, t, l);
4654 s += l;
4656 *s = 0;
4657 return ss;
4660 void
4661 ShowLayouts(where)
4662 int where;
4664 char buf[1024];
4665 char *s, *ss;
4667 if (!display)
4668 return;
4669 if (!layouts)
4671 Msg(0, "No layouts defined\n");
4672 return;
4674 if (where == -1 && D_layout)
4675 where = D_layout->lay_number;
4676 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4677 s = buf + strlen(buf);
4678 if (ss - buf > D_width / 2)
4680 ss -= D_width / 2;
4681 if (s - ss < D_width)
4683 ss = s - D_width;
4684 if (ss < buf)
4685 ss = buf;
4688 else
4689 ss = buf;
4690 Msg(0, "%s", ss);
4693 void
4694 RemoveLayout(lay)
4695 struct layout *lay;
4697 struct layout **layp = &layouts;
4699 for (; *layp; layp = &(*layp)->lay_next)
4701 if (*layp == lay)
4703 *layp = lay->lay_next;
4704 break;
4707 laytab[lay->lay_number] = (struct layout *)0;
4709 if (display && D_layout == lay)
4710 D_layout = (struct layout *)0;
4712 FreeLayoutCv(&lay->lay_canvas);
4714 if (lay->lay_title)
4715 free(lay->lay_title);
4716 free(lay);
4718 if (layouts)
4719 LoadLayout((display && D_layout) ? D_layout : *layp ? *layp : layouts,
4720 display ? &D_canvas : (struct canvas *)0);
4721 Activate(0);