Don't put an uninitialized string into the blanker environment.
[screen-lua.git] / src / display.c
blobaeea3944f5dcd1ba0b6f70f68c29ce2677df7682
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <signal.h>
26 #include <fcntl.h>
27 #ifndef sun
28 # include <sys/ioctl.h>
29 #endif
31 #include "config.h"
32 #include "screen.h"
33 #include "extern.h"
34 #include "braille.h"
36 static int CountChars __P((int));
37 static int DoAddChar __P((int));
38 static int BlankResize __P((int, int));
39 static int CallRewrite __P((int, int, int, int));
40 static void FreeCanvas __P((struct canvas *));
41 static void disp_readev_fn __P((struct event *, char *));
42 static void disp_writeev_fn __P((struct event *, char *));
43 #ifdef linux
44 static void disp_writeev_eagain __P((struct event *, char *));
45 #endif
46 static void disp_status_fn __P((struct event *, char *));
47 static void disp_hstatus_fn __P((struct event *, char *));
48 static void disp_blocked_fn __P((struct event *, char *));
49 static void cv_winid_fn __P((struct event *, char *));
50 #ifdef MAPKEYS
51 static void disp_map_fn __P((struct event *, char *));
52 #endif
53 static void disp_idle_fn __P((struct event *, char *));
54 #ifdef BLANKER_PRG
55 static void disp_blanker_fn __P((struct event *, char *));
56 #endif
57 static void WriteLP __P((int, int));
58 static void INSERTCHAR __P((int));
59 static void RAW_PUTCHAR __P((int));
60 #ifdef COLOR
61 static void SetBackColor __P((int));
62 #endif
63 static void FreePerp __P((struct canvas *));
64 static struct canvas *AddPerp __P((struct canvas *));
67 extern struct layer *flayer;
68 extern struct win *windows, *fore;
69 extern struct LayFuncs WinLf;
71 extern int use_hardstatus;
72 extern int MsgWait, MsgMinWait;
73 extern int Z0width, Z1width;
74 extern unsigned char *blank, *null;
75 extern struct mline mline_blank, mline_null, mline_old;
76 extern struct mchar mchar_null, mchar_blank, mchar_so;
77 extern struct NewWindow nwin_default;
78 extern struct action idleaction;
80 /* XXX shouldn't be here */
81 extern char *hstatusstring;
82 extern char *captionstring;
84 extern int pastefont;
85 extern int idletimo;
87 #ifdef BLANKER_PRG
88 extern int pty_preopen;
89 #if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
90 extern struct winsize glwz;
91 #endif
92 extern char **NewEnv;
93 extern int real_uid, real_gid;
94 #endif
97 * tputs needs this to calculate the padding
99 #ifndef NEED_OSPEED
100 extern
101 #endif /* NEED_OSPEED */
102 short ospeed;
105 struct display *display, *displays;
106 #ifdef COLOR
107 int attr2color[8][4];
108 int nattr2color;
109 #endif
111 #ifndef MULTI
112 struct display TheDisplay;
113 #endif
116 * The default values
118 int defobuflimit = OBUF_MAX;
119 int defnonblock = -1;
120 #ifdef AUTO_NUKE
121 int defautonuke = 0;
122 #endif
123 int captionalways;
124 int hardstatusemu = HSTATUS_IGNORE;
126 int focusminwidth, focusminheight;
129 * Default layer management
132 void
133 DefProcess(bufp, lenp)
134 char **bufp;
135 int *lenp;
137 *bufp += *lenp;
138 *lenp = 0;
141 void
142 DefRedisplayLine(y, xs, xe, isblank)
143 int y, xs, xe, isblank;
145 if (isblank == 0 && y >= 0)
146 DefClearLine(y, xs, xe, 0);
149 void
150 DefClearLine(y, xs, xe, bce)
151 int y, xs, xe, bce;
153 LClearLine(flayer, y, xs, xe, bce, (struct mline *)0);
156 /*ARGSUSED*/
158 DefRewrite(y, xs, xe, rend, doit)
159 int y, xs, xe, doit;
160 struct mchar *rend;
162 return EXPENSIVE;
165 /*ARGSUSED*/
167 DefResize(wi, he)
168 int wi, he;
170 return -1;
173 void
174 DefRestore()
176 LAY_DISPLAYS(flayer, InsertMode(0));
177 /* ChangeScrollRegion(0, D_height - 1); */
178 LKeypadMode(flayer, 0);
179 LCursorkeysMode(flayer, 0);
180 LCursorVisibility(flayer, 0);
181 LMouseMode(flayer, 0);
182 LSetRendition(flayer, &mchar_null);
183 LSetFlow(flayer, nwin_default.flowflag & FLOW_NOW);
187 * Blank layer management
190 struct LayFuncs BlankLf =
192 DefProcess,
194 DefRedisplayLine,
195 DefClearLine,
196 DefRewrite,
197 BlankResize,
198 DefRestore
201 /*ARGSUSED*/
202 static int
203 BlankResize(wi, he)
204 int wi, he;
206 flayer->l_width = wi;
207 flayer->l_height = he;
208 return 0;
213 * Generate new display, start with a blank layer.
214 * The termcap arrays are not initialised here.
215 * The new display is placed in the displays list.
218 struct display *
219 MakeDisplay(uname, utty, term, fd, pid, Mode)
220 char *uname, *utty, *term;
221 int fd, pid;
222 struct mode *Mode;
224 struct acluser **u;
225 struct baud_values *b;
227 if (!*(u = FindUserPtr(uname)) && UserAdd(uname, (char *)0, u))
228 return 0; /* could not find or add user */
230 #ifdef MULTI
231 if ((display = (struct display *)calloc(1, sizeof(*display))) == 0)
232 return 0;
233 #else
234 if (displays)
235 return 0;
236 bzero((char *)&TheDisplay, sizeof(TheDisplay));
237 display = &TheDisplay;
238 #endif
239 display->d_next = displays;
240 displays = display;
241 D_flow = 1;
242 D_nonblock = defnonblock;
243 D_userfd = fd;
244 D_readev.fd = D_writeev.fd = fd;
245 D_readev.type = EV_READ;
246 D_writeev.type = EV_WRITE;
247 D_readev.data = D_writeev.data = (char *)display;
248 D_readev.handler = disp_readev_fn;
249 D_writeev.handler = disp_writeev_fn;
250 evenq(&D_readev);
251 D_writeev.condpos = &D_obuflen;
252 D_writeev.condneg = &D_obuffree;
253 evenq(&D_writeev);
254 D_statusev.type = EV_TIMEOUT;
255 D_statusev.data = (char *)display;
256 D_statusev.handler = disp_status_fn;
257 D_hstatusev.type = EV_TIMEOUT;
258 D_hstatusev.data = (char *)display;
259 D_hstatusev.handler = disp_hstatus_fn;
260 D_blockedev.type = EV_TIMEOUT;
261 D_blockedev.data = (char *)display;
262 D_blockedev.handler = disp_blocked_fn;
263 D_blockedev.condpos = &D_obuffree;
264 D_blockedev.condneg = &D_obuflenmax;
265 D_hstatusev.handler = disp_hstatus_fn;
266 #ifdef MAPKEYS
267 D_mapev.type = EV_TIMEOUT;
268 D_mapev.data = (char *)display;
269 D_mapev.handler = disp_map_fn;
270 #endif
271 D_idleev.type = EV_TIMEOUT;
272 D_idleev.data = (char *)display;
273 D_idleev.handler = disp_idle_fn;
274 #ifdef BLANKER_PRG
275 D_blankerev.type = EV_READ;
276 D_blankerev.data = (char *)display;
277 D_blankerev.handler = disp_blanker_fn;
278 D_blankerev.fd = -1;
279 #endif
280 D_OldMode = *Mode;
281 D_status_obuffree = -1;
282 Resize_obuf(); /* Allocate memory for buffer */
283 D_obufmax = defobuflimit;
284 D_obuflenmax = D_obuflen - D_obufmax;
285 #ifdef AUTO_NUKE
286 D_auto_nuke = defautonuke;
287 #endif
288 D_obufp = D_obuf;
289 D_printfd = -1;
290 D_userpid = pid;
292 #ifdef POSIX
293 if ((b = lookup_baud((int)cfgetospeed(&D_OldMode.tio))))
294 D_dospeed = b->idx;
295 #else
296 # ifdef TERMIO
297 if ((b = lookup_baud(D_OldMode.tio.c_cflag & CBAUD)))
298 D_dospeed = b->idx;
299 # else
300 D_dospeed = (short)D_OldMode.m_ttyb.sg_ospeed;
301 # endif
302 #endif
303 debug1("New displays ospeed = %d\n", D_dospeed);
305 strncpy(D_usertty, utty, sizeof(D_usertty) - 1);
306 D_usertty[sizeof(D_usertty) - 1] = 0;
307 strncpy(D_termname, term, sizeof(D_termname) - 1);
308 D_termname[sizeof(D_termname) - 1] = 0;
309 D_user = *u;
310 D_processinput = ProcessInput;
311 return display;
315 void
316 FreeDisplay()
318 struct win *p;
319 #ifdef MULTI
320 struct display *d, **dp;
321 #endif
323 #ifdef FONT
324 FreeTransTable();
325 #endif
326 #ifdef BLANKER_PRG
327 KillBlanker();
328 #endif
329 if (D_userfd >= 0)
331 Flush();
332 if (!display)
333 return;
334 SetTTY(D_userfd, &D_OldMode);
335 fcntl(D_userfd, F_SETFL, 0);
337 freetty();
338 if (D_tentry)
339 free(D_tentry);
340 D_tentry = 0;
341 if (D_processinputdata)
342 free(D_processinputdata);
343 D_processinputdata = 0;
344 D_tcinited = 0;
345 evdeq(&D_hstatusev);
346 evdeq(&D_statusev);
347 evdeq(&D_readev);
348 evdeq(&D_writeev);
349 evdeq(&D_blockedev);
350 #ifdef MAPKEYS
351 evdeq(&D_mapev);
352 if (D_kmaps)
354 free(D_kmaps);
355 D_kmaps = 0;
356 D_aseqs = 0;
357 D_nseqs = 0;
358 D_seqp = 0;
359 D_seql = 0;
360 D_seqh = 0;
362 #endif
363 evdeq(&D_idleev);
364 #ifdef BLANKER_PRG
365 evdeq(&D_blankerev);
366 #endif
367 #ifdef HAVE_BRAILLE
368 if (bd.bd_dpy == display)
370 bd.bd_start_braille = 0;
371 StartBraille();
373 #endif
375 #ifdef MULTI
376 for (dp = &displays; (d = *dp) ; dp = &d->d_next)
377 if (d == display)
378 break;
379 ASSERT(d);
380 if (D_status_lastmsg)
381 free(D_status_lastmsg);
382 if (D_obuf)
383 free(D_obuf);
384 *dp = display->d_next;
385 #else /* MULTI */
386 ASSERT(display == displays);
387 ASSERT(display == &TheDisplay);
388 displays = 0;
389 #endif /* MULTI */
391 while (D_canvas.c_slperp)
392 FreeCanvas(D_canvas.c_slperp);
393 D_cvlist = 0;
395 for (p = windows; p; p = p->w_next)
397 if (p->w_pdisplay == display)
398 p->w_pdisplay = 0;
399 if (p->w_lastdisp == display)
400 p->w_lastdisp = 0;
401 if (p->w_readev.condneg == &D_status || p->w_readev.condneg == &D_obuflenmax)
402 p->w_readev.condpos = p->w_readev.condneg = 0;
404 #ifdef ZMODEM
405 for (p = windows; p; p = p->w_next)
406 if (p->w_zdisplay == display)
407 zmodem_abort(p, 0);
408 #endif
409 #ifdef MULTI
410 free((char *)display);
411 #endif
412 display = 0;
416 MakeDefaultCanvas()
418 struct canvas *cv;
420 ASSERT(display);
421 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
422 return -1;
423 cv->c_xs = 0;
424 cv->c_xe = D_width - 1;
425 cv->c_ys = 0;
426 cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
427 debug2("MakeDefaultCanvas 0,0 %d,%d\n", cv->c_xe, cv->c_ye);
428 cv->c_xoff = 0;
429 cv->c_yoff = 0;
430 cv->c_next = 0;
431 cv->c_display = display;
432 cv->c_vplist = 0;
433 cv->c_slnext = 0;
434 cv->c_slprev = 0;
435 cv->c_slperp = 0;
436 cv->c_slweight = 1;
437 cv->c_slback = &D_canvas;
438 D_canvas.c_slperp = cv;
439 D_canvas.c_xs = cv->c_xs;
440 D_canvas.c_xe = cv->c_xe;
441 D_canvas.c_ys = cv->c_ys;
442 D_canvas.c_ye = cv->c_ye;
443 cv->c_slorient = SLICE_UNKN;
444 cv->c_captev.type = EV_TIMEOUT;
445 cv->c_captev.data = (char *)cv;
446 cv->c_captev.handler = cv_winid_fn;
448 cv->c_blank.l_cvlist = cv;
449 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
450 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
451 cv->c_blank.l_x = cv->c_blank.l_y = 0;
452 cv->c_blank.l_layfn = &BlankLf;
453 cv->c_blank.l_data = 0;
454 cv->c_blank.l_next = 0;
455 cv->c_blank.l_bottom = &cv->c_blank;
456 cv->c_blank.l_blocking = 0;
457 cv->c_layer = &cv->c_blank;
458 cv->c_lnext = 0;
460 D_cvlist = cv;
461 RethinkDisplayViewports();
462 D_forecv = cv; /* default input focus */
463 return 0;
466 static struct canvas **
467 CreateCanvasChainRec(cv, cvp)
468 struct canvas *cv;
469 struct canvas **cvp;
471 for (; cv; cv = cv->c_slnext)
473 if (cv->c_slperp)
474 cvp = CreateCanvasChainRec(cv->c_slperp, cvp);
475 else
477 *cvp = cv;
478 cvp = &cv->c_next;
481 return cvp;
484 void
485 RecreateCanvasChain()
487 struct canvas **cvp;
488 cvp = CreateCanvasChainRec(D_canvas.c_slperp, &D_cvlist);
489 *cvp = 0;
492 static void
493 FreeCanvas(cv)
494 struct canvas *cv;
496 struct viewport *vp, *nvp;
497 struct canvas **cvp;
498 struct win *p;
500 if (cv->c_slprev)
501 cv->c_slprev->c_slnext = cv->c_slnext;
502 if (cv->c_slnext)
503 cv->c_slnext->c_slprev = cv->c_slprev;
504 if (cv->c_slback && cv->c_slback->c_slperp == cv)
505 cv->c_slback->c_slperp = cv->c_slnext ? cv->c_slnext : cv->c_slprev;
506 if (cv->c_slperp)
508 while (cv->c_slperp)
509 FreeCanvas(cv->c_slperp);
510 free(cv);
511 return;
514 if (display)
516 if (D_forecv == cv)
517 D_forecv = 0;
518 /* remove from canvas chain as SetCanvasWindow might call
519 * some layer function */
520 for (cvp = &D_cvlist; *cvp ; cvp = &(*cvp)->c_next)
521 if (*cvp == cv)
523 *cvp = cv->c_next;
524 break;
527 p = cv->c_layer ? Layer2Window(cv->c_layer) : 0;
528 SetCanvasWindow(cv, 0);
529 if (p)
530 WindowChanged(p, 'u');
531 if (flayer == cv->c_layer)
532 flayer = 0;
533 for (vp = cv->c_vplist; vp; vp = nvp)
535 vp->v_canvas = 0;
536 nvp = vp->v_next;
537 vp->v_next = 0;
538 free(vp);
540 evdeq(&cv->c_captev);
541 free(cv);
545 CountCanvas(cv)
546 struct canvas *cv;
548 int num = 0;
549 for (; cv; cv = cv->c_slnext)
551 if (cv->c_slperp)
553 struct canvas *cvp;
554 int nump = 1, n;
555 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
556 if (cvp->c_slperp)
558 n = CountCanvas(cvp->c_slperp);
559 if (n > nump)
560 nump = n;
562 num += nump;
564 else
565 num++;
567 return num;
571 CountCanvasPerp(cv)
572 struct canvas *cv;
574 struct canvas *cvp;
575 int num = 1, n;
576 for (cvp = cv->c_slperp; cvp; cvp = cvp->c_slnext)
577 if (cvp->c_slperp)
579 n = CountCanvas(cvp->c_slperp);
580 if (n > num)
581 num = n;
583 return num;
586 void
587 EqualizeCanvas(cv, gflag)
588 struct canvas *cv;
589 int gflag;
591 struct canvas *cv2;
592 for (; cv; cv = cv->c_slnext)
594 if (cv->c_slperp && gflag)
596 cv->c_slweight = CountCanvasPerp(cv);
597 for (cv2 = cv->c_slperp; cv2; cv2 = cv2->c_slnext)
598 if (cv2->c_slperp)
599 EqualizeCanvas(cv2->c_slperp, gflag);
601 else
602 cv->c_slweight = 1;
606 void
607 ResizeCanvas(cv)
608 struct canvas *cv;
610 struct canvas *cv2, *cvn, *fcv;
611 int nh, i, maxi, hh, m, w, wsum;
612 int need, got;
613 int xs, ys, xe, ye;
614 int focusmin = 0;
616 xs = cv->c_xs;
617 ys = cv->c_ys;
618 xe = cv->c_xe;
619 ye = cv->c_ye;
620 cv = cv->c_slperp;
621 debug2("ResizeCanvas: %d,%d", xs, ys);
622 debug2(" %d,%d\n", xe, ye);
623 if (cv == 0)
624 return;
625 if (cv->c_slorient == SLICE_UNKN)
627 ASSERT(!cv->c_slnext && !cv->c_slperp);
628 cv->c_xs = xs;
629 cv->c_xe = xe;
630 cv->c_ys = ys;
631 cv->c_ye = ye;
632 cv->c_xoff = cv->c_xs;
633 cv->c_yoff = cv->c_ys;
634 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
635 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
636 return;
639 fcv = 0;
640 if (focusminwidth || focusminheight)
642 debug("searching for focus canvas\n");
643 cv2 = D_forecv;
644 while (cv2->c_slback)
646 if (cv2->c_slback == cv->c_slback)
648 fcv = cv2;
649 focusmin = cv->c_slorient == SLICE_VERT ? focusminheight : focusminwidth;
650 if (focusmin > 0)
651 focusmin--;
652 else if (focusmin < 0)
653 focusmin = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
654 debug1("found, focusmin=%d\n", focusmin);
656 cv2 = cv2->c_slback;
659 if (focusmin)
661 m = CountCanvas(cv) * 2;
662 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
663 nh -= m;
664 if (nh < 0)
665 nh = 0;
666 if (focusmin > nh)
667 focusmin = nh;
668 debug1("corrected to %d\n", focusmin);
671 /* pass 1: calculate weight sum */
672 for (cv2 = cv, wsum = 0; cv2; cv2 = cv2->c_slnext)
674 debug1(" weight %d\n", cv2->c_slweight);
675 wsum += cv2->c_slweight;
677 debug1("wsum = %d\n", wsum);
678 if (wsum == 0)
679 wsum = 1;
680 w = wsum;
682 /* pass 2: calculate need/excess space */
683 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
684 for (cv2 = cv, need = got = 0; cv2; cv2 = cv2->c_slnext)
686 m = cv2->c_slperp ? CountCanvasPerp(cv2) * 2 - 1 : 1;
687 if (cv2 == fcv)
688 m += focusmin;
689 hh = cv2->c_slweight ? nh * cv2->c_slweight / w : 0;
690 w -= cv2->c_slweight;
691 nh -= hh;
692 debug2(" should %d min %d\n", hh, m);
693 if (hh <= m + 1)
694 need += m + 1 - hh;
695 else
696 got += hh - m - 1;
698 debug2("need: %d, got %d\n", need, got);
699 if (need > got)
700 need = got;
702 /* pass 3: distribute space */
703 nh = cv->c_slorient == SLICE_VERT ? ye - ys + 2 : xe - xs + 2;
704 i = cv->c_slorient == SLICE_VERT ? ys : xs;
705 maxi = cv->c_slorient == SLICE_VERT ? ye : xe;
706 w = wsum;
707 for (; cv; cv = cvn)
709 cvn = cv->c_slnext;
710 if (i > maxi)
712 if (cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slprev->c_slperp && !cv->c_slprev->c_slprev)
714 cv->c_slprev->c_slorient = SLICE_UNKN;
715 if (!captionalways)
717 cv->c_slback->c_ye++;
718 cv->c_slprev->c_ye++;
721 SetCanvasWindow(cv, 0);
722 FreeCanvas(cv);
723 continue;
725 m = cv->c_slperp ? CountCanvasPerp(cv) * 2 - 1 : 1;
726 if (cv == fcv)
727 m += focusmin;
728 hh = cv->c_slweight ? nh * cv->c_slweight / w : 0;
729 w -= cv->c_slweight;
730 nh -= hh;
731 debug2(" should %d min %d\n", hh, m);
732 if (hh <= m + 1)
734 hh = m + 1;
735 debug1(" -> %d\n", hh);
737 else
739 int hx = need * (hh - m - 1) / got;
740 debug3(" -> %d - %d = %d\n", hh, hx, hh - hx);
741 got -= (hh - m - 1);
742 hh -= hx;
743 need -= hx;
744 debug2(" now need=%d got=%d\n", need, got);
746 ASSERT(hh >= m + 1);
747 /* hh is window size plus pation line */
748 if (i + hh > maxi + 2)
750 hh = maxi + 2 - i;
751 debug1(" not enough space, reducing to %d\n", hh);
753 if (i + hh == maxi + 1)
755 hh++;
756 debug(" incrementing as no other canvas will fit\n");
758 if (cv->c_slorient == SLICE_VERT)
760 cv->c_xs = xs;
761 cv->c_xe = xe;
762 cv->c_ys = i;
763 cv->c_ye = i + hh - 2;
764 cv->c_xoff = xs;
765 cv->c_yoff = i;
767 else
769 cv->c_xs = i;
770 cv->c_xe = i + hh - 2;
771 cv->c_ys = ys;
772 cv->c_ye = ye;
773 cv->c_xoff = i;
774 cv->c_yoff = ys;
776 cv->c_xoff = cv->c_xs;
777 cv->c_yoff = cv->c_ys;
778 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
779 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
780 if (cv->c_slperp)
782 ResizeCanvas(cv);
783 if (!cv->c_slperp->c_slnext)
785 debug("deleting perp node\n");
786 FreePerp(cv->c_slperp);
787 FreePerp(cv);
790 i += hh;
794 static struct canvas *
795 AddPerp(cv)
796 struct canvas *cv;
798 struct canvas *pcv;
799 debug("Creating new perp node\n");
801 if ((pcv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
802 return 0;
803 pcv->c_next = 0;
804 pcv->c_display = cv->c_display;
805 pcv->c_slnext = cv->c_slnext;
806 pcv->c_slprev = cv->c_slprev;
807 pcv->c_slperp = cv;
808 pcv->c_slback = cv->c_slback;
809 if (cv->c_slback && cv->c_slback->c_slperp == cv)
810 cv->c_slback->c_slperp = pcv;
811 pcv->c_slorient = cv->c_slorient;
812 pcv->c_xoff = 0;
813 pcv->c_yoff = 0;
814 pcv->c_xs = cv->c_xs;
815 pcv->c_xe = cv->c_xe;
816 pcv->c_ys = cv->c_ys;
817 pcv->c_ye = cv->c_ye;
818 if (pcv->c_slnext)
819 pcv->c_slnext->c_slprev = pcv;
820 if (pcv->c_slprev)
821 pcv->c_slprev->c_slnext = pcv;
822 pcv->c_slweight = cv->c_slweight;
823 cv->c_slweight = 1;
824 cv->c_slnext = 0;
825 cv->c_slprev = 0;
826 cv->c_slperp = 0;
827 cv->c_slback = pcv;
828 cv->c_slorient = SLICE_UNKN;
829 return pcv;
832 static void
833 FreePerp(pcv)
834 struct canvas *pcv;
836 struct canvas *cv;
838 if (!pcv->c_slperp)
839 return;
840 cv = pcv->c_slperp;
841 cv->c_slprev = pcv->c_slprev;
842 if (cv->c_slprev)
843 cv->c_slprev->c_slnext = cv;
844 cv->c_slback = pcv->c_slback;
845 if (cv->c_slback && cv->c_slback->c_slperp == pcv)
846 cv->c_slback->c_slperp = cv;
847 cv->c_slorient = pcv->c_slorient;
848 cv->c_slweight = pcv->c_slweight;
849 while (cv->c_slnext)
851 cv = cv->c_slnext;
852 cv->c_slorient = pcv->c_slorient;
853 cv->c_slback = pcv->c_slback;
854 cv->c_slweight = pcv->c_slweight;
856 cv->c_slnext = pcv->c_slnext;
857 if (cv->c_slnext)
858 cv->c_slnext->c_slprev = cv;
859 free(pcv);
863 AddCanvas(orient)
864 int orient;
866 struct canvas *cv;
867 int xs, xe, ys, ye;
868 int h, num;
870 cv = D_forecv;
871 debug2("AddCanvas orient %d, forecv is %d\n", orient, cv->c_slorient);
873 if (cv->c_slorient != SLICE_UNKN && cv->c_slorient != orient)
874 if (!AddPerp(cv))
875 return -1;
877 cv = D_forecv;
878 xs = cv->c_slback->c_xs;
879 xe = cv->c_slback->c_xe;
880 ys = cv->c_slback->c_ys;
881 ye = cv->c_slback->c_ye;
882 if (!captionalways && cv == D_canvas.c_slperp && !cv->c_slnext)
883 ye--; /* need space for caption */
884 debug2("Adding Canvas to slice %d,%d ", xs, ys);
885 debug2("%d,%d\n", xe, ye);
887 num = CountCanvas(cv->c_slback->c_slperp) + 1;
888 debug1("Num = %d\n", num);
889 if (orient == SLICE_VERT)
890 h = ye - ys + 1;
891 else
892 h = xe - xs + 1;
894 h -= 2 * num - 1;
895 if (h < 0)
896 return -1; /* can't fit in */
898 if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
899 return -1;
901 D_forecv->c_slback->c_ye = ye; /* in case we modified it above */
902 D_forecv->c_slorient = orient; /* in case it was UNKN */
903 cv->c_slnext = D_forecv->c_slnext;
904 cv->c_slprev = D_forecv;
905 D_forecv->c_slnext = cv;
906 if (cv->c_slnext)
907 cv->c_slnext->c_slprev = cv;
908 cv->c_slorient = orient;
909 cv->c_slback = D_forecv->c_slback;
911 cv->c_xs = xs;
912 cv->c_xe = xe;
913 cv->c_ys = ys;
914 cv->c_ye = ye;
915 cv->c_xoff = 0;
916 cv->c_yoff = 0;
917 cv->c_display = display;
918 cv->c_vplist = 0;
919 cv->c_captev.type = EV_TIMEOUT;
920 cv->c_captev.data = (char *)cv;
921 cv->c_captev.handler = cv_winid_fn;
923 cv->c_blank.l_cvlist = cv;
924 cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
925 cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
926 cv->c_blank.l_x = cv->c_blank.l_y = 0;
927 cv->c_blank.l_layfn = &BlankLf;
928 cv->c_blank.l_data = 0;
929 cv->c_blank.l_next = 0;
930 cv->c_blank.l_bottom = &cv->c_blank;
931 cv->c_blank.l_blocking = 0;
932 cv->c_layer = &cv->c_blank;
933 cv->c_lnext = 0;
935 cv->c_next = 0;
937 cv = cv->c_slback;
938 EqualizeCanvas(cv->c_slperp, 0);
939 ResizeCanvas(cv);
940 RecreateCanvasChain();
941 RethinkDisplayViewports();
942 ResizeLayersToCanvases();
943 return 0;
946 void
947 RemCanvas()
949 int xs, xe, ys, ye;
950 struct canvas *cv;
952 debug("RemCanvas\n");
953 cv = D_forecv;
954 if (cv->c_slorient == SLICE_UNKN)
955 return;
956 while (cv->c_slprev)
957 cv = cv->c_slprev;
958 if (!cv->c_slnext)
959 return;
960 if (!cv->c_slnext->c_slnext && cv->c_slback->c_slback)
962 /* two canvases in slice, kill perp node */
963 cv = D_forecv;
964 debug("deleting perp node\n");
965 FreePerp(cv->c_slprev ? cv->c_slprev : cv->c_slnext);
966 FreePerp(cv->c_slback);
968 xs = cv->c_slback->c_xs;
969 xe = cv->c_slback->c_xe;
970 ys = cv->c_slback->c_ys;
971 ye = cv->c_slback->c_ye;
972 /* free canvas */
973 cv = D_forecv;
974 D_forecv = cv->c_slprev;
975 if (!D_forecv)
976 D_forecv = cv->c_slnext;
977 FreeCanvas(cv);
979 cv = D_forecv;
980 while (D_forecv->c_slperp)
981 D_forecv = D_forecv->c_slperp;
983 /* if only one canvas left, set orient back to unknown */
984 if (!cv->c_slnext && !cv->c_slprev && !cv->c_slback->c_slback && !cv->c_slperp)
986 cv->c_slorient = SLICE_UNKN;
987 if (!captionalways)
988 cv->c_slback->c_ye = ++ye; /* caption line no longer needed */
990 cv = cv->c_slback;
991 EqualizeCanvas(cv->c_slperp, 0);
992 ResizeCanvas(cv);
994 D_fore = Layer2Window(D_forecv->c_layer);
995 flayer = D_forecv->c_layer;
997 RecreateCanvasChain();
998 RethinkDisplayViewports();
999 ResizeLayersToCanvases();
1002 void
1003 OneCanvas()
1005 struct canvas *cv = D_forecv, *ocv = 0;
1007 if (cv->c_slprev)
1009 ocv = cv->c_slprev;
1010 cv->c_slprev->c_slnext = cv->c_slnext;
1012 if (cv->c_slnext)
1014 ocv = cv->c_slnext;
1015 cv->c_slnext->c_slprev = cv->c_slprev;
1017 if (!ocv)
1018 return;
1019 if (cv->c_slback && cv->c_slback->c_slperp == cv)
1020 cv->c_slback->c_slperp = ocv;
1021 cv->c_slorient = SLICE_UNKN;
1022 while (D_canvas.c_slperp)
1023 FreeCanvas(D_canvas.c_slperp);
1024 cv = D_forecv;
1025 D_canvas.c_slperp = cv;
1026 cv->c_slback = &D_canvas;
1027 cv->c_slnext = 0;
1028 cv->c_slprev = 0;
1029 ASSERT(!cv->c_slperp);
1030 if (!captionalways)
1031 D_canvas.c_ye++; /* caption line no longer needed */
1032 ResizeCanvas(&D_canvas);
1033 RecreateCanvasChain();
1034 RethinkDisplayViewports();
1035 ResizeLayersToCanvases();
1039 RethinkDisplayViewports()
1041 struct canvas *cv;
1042 struct viewport *vp, *vpn;
1044 /* free old viewports */
1045 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1047 for (vp = cv->c_vplist; vp; vp = vpn)
1049 vp->v_canvas = 0;
1050 vpn = vp->v_next;
1051 bzero((char *)vp, sizeof(*vp));
1052 free(vp);
1054 cv->c_vplist = 0;
1056 display->d_vpxmin = -1;
1057 display->d_vpxmax = -1;
1059 for (cv = display->d_cvlist; cv; cv = cv->c_next)
1061 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1062 return -1;
1063 #ifdef HOLE
1064 vp->v_canvas = cv;
1065 vp->v_xs = cv->c_xs;
1066 vp->v_ys = (cv->c_ys + cv->c_ye) / 2;
1067 vp->v_xe = cv->c_xe;
1068 vp->v_ye = cv->c_ye;
1069 vp->v_xoff = cv->c_xoff;
1070 vp->v_yoff = cv->c_yoff;
1071 vp->v_next = cv->c_vplist;
1072 cv->c_vplist = vp;
1074 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1075 return -1;
1076 vp->v_canvas = cv;
1077 vp->v_xs = (cv->c_xs + cv->c_xe) / 2;
1078 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1079 vp->v_xe = cv->c_xe;
1080 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1081 vp->v_xoff = cv->c_xoff;
1082 vp->v_yoff = cv->c_yoff;
1083 vp->v_next = cv->c_vplist;
1084 cv->c_vplist = vp;
1086 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1087 return -1;
1088 vp->v_canvas = cv;
1089 vp->v_xs = cv->c_xs;
1090 vp->v_ys = (3 * cv->c_ys + cv->c_ye) / 4;
1091 vp->v_xe = (3 * cv->c_xs + cv->c_xe) / 4 - 1;
1092 vp->v_ye = (cv->c_ys + cv->c_ye) / 2 - 1;
1093 vp->v_xoff = cv->c_xoff;
1094 vp->v_yoff = cv->c_yoff;
1095 vp->v_next = cv->c_vplist;
1096 cv->c_vplist = vp;
1098 if ((vp = (struct viewport *)malloc(sizeof *vp)) == 0)
1099 return -1;
1100 vp->v_canvas = cv;
1101 vp->v_xs = cv->c_xs;
1102 vp->v_ys = cv->c_ys;
1103 vp->v_xe = cv->c_xe;
1104 vp->v_ye = (3 * cv->c_ys + cv->c_ye) / 4 - 1;
1105 vp->v_xoff = cv->c_xoff;
1106 vp->v_yoff = cv->c_yoff;
1107 vp->v_next = cv->c_vplist;
1108 cv->c_vplist = vp;
1109 #else
1110 vp->v_canvas = cv;
1111 vp->v_xs = cv->c_xs;
1112 vp->v_ys = cv->c_ys;
1113 vp->v_xe = cv->c_xe;
1114 vp->v_ye = cv->c_ye;
1115 vp->v_xoff = cv->c_xoff;
1116 vp->v_yoff = cv->c_yoff;
1117 vp->v_next = cv->c_vplist;
1118 cv->c_vplist = vp;
1119 #endif
1121 if (cv->c_xs < display->d_vpxmin || display->d_vpxmin == -1)
1122 display->d_vpxmin = cv->c_xs;
1123 if (cv->c_xe > display->d_vpxmax || display->d_vpxmax == -1)
1124 display->d_vpxmax = cv->c_xe;
1126 return 0;
1129 void
1130 RethinkViewportOffsets(cv)
1131 struct canvas *cv;
1133 struct viewport *vp;
1135 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1137 vp->v_xoff = cv->c_xoff;
1138 vp->v_yoff = cv->c_yoff;
1143 * if the adaptflag is on, we keep the size of this display, else
1144 * we may try to restore our old window sizes.
1146 void
1147 InitTerm(adapt)
1148 int adapt;
1150 ASSERT(display);
1151 ASSERT(D_tcinited);
1152 D_top = D_bot = -1;
1153 AddCStr(D_TI);
1154 AddCStr(D_IS);
1155 /* Check for toggle */
1156 if (D_IM && strcmp(D_IM, D_EI))
1157 AddCStr(D_EI);
1158 D_insert = 0;
1159 #ifdef MAPKEYS
1160 AddCStr(D_KS);
1161 AddCStr(D_CCS);
1162 #else
1163 /* Check for toggle */
1164 if (D_KS && strcmp(D_KS, D_KE))
1165 AddCStr(D_KE);
1166 if (D_CCS && strcmp(D_CCS, D_CCE))
1167 AddCStr(D_CCE);
1168 #endif
1169 D_keypad = 0;
1170 D_cursorkeys = 0;
1171 AddCStr(D_ME);
1172 AddCStr(D_EA);
1173 AddCStr(D_CE0);
1174 D_rend = mchar_null;
1175 D_atyp = 0;
1176 if (adapt == 0)
1177 ResizeDisplay(D_defwidth, D_defheight);
1178 ChangeScrollRegion(0, D_height - 1);
1179 D_x = D_y = 0;
1180 Flush();
1181 ClearAll();
1182 debug1("we %swant to adapt all our windows to the display\n",
1183 (adapt) ? "" : "don't ");
1184 /* In case the size was changed by a init sequence */
1185 CheckScreenSize((adapt) ? 2 : 0);
1188 void
1189 FinitTerm()
1191 ASSERT(display);
1192 #ifdef BLANKER_PRG
1193 KillBlanker();
1194 #endif
1195 if (D_tcinited)
1197 ResizeDisplay(D_defwidth, D_defheight);
1198 InsertMode(0);
1199 ChangeScrollRegion(0, D_height - 1);
1200 KeypadMode(0);
1201 CursorkeysMode(0);
1202 CursorVisibility(0);
1203 MouseMode(0);
1204 SetRendition(&mchar_null);
1205 SetFlow(FLOW_NOW);
1206 #ifdef MAPKEYS
1207 AddCStr(D_KE);
1208 AddCStr(D_CCE);
1209 #endif
1210 if (D_hstatus)
1211 ShowHStatus((char *)0);
1212 #ifdef RXVT_OSC
1213 ClearAllXtermOSC();
1214 #endif
1215 D_x = D_y = -1;
1216 GotoPos(0, D_height - 1);
1217 AddChar('\r');
1218 AddChar('\n');
1219 AddCStr(D_TE);
1221 Flush();
1225 static void
1226 INSERTCHAR(c)
1227 int c;
1229 ASSERT(display);
1230 if (!D_insert && D_x < D_width - 1)
1232 if (D_IC || D_CIC)
1234 if (D_IC)
1235 AddCStr(D_IC);
1236 else
1237 AddCStr2(D_CIC, 1);
1238 RAW_PUTCHAR(c);
1239 return;
1241 InsertMode(1);
1242 if (!D_insert)
1244 RefreshLine(D_y, D_x, D_width-1, 0);
1245 return;
1248 RAW_PUTCHAR(c);
1251 void
1252 PUTCHAR(c)
1253 int c;
1255 ASSERT(display);
1256 if (D_insert && D_x < D_width - 1)
1257 InsertMode(0);
1258 RAW_PUTCHAR(c);
1261 void
1262 PUTCHARLP(c)
1263 int c;
1265 if (D_x < D_width - 1)
1267 if (D_insert)
1268 InsertMode(0);
1269 RAW_PUTCHAR(c);
1270 return;
1272 if (D_CLP || D_y != D_bot)
1274 int y = D_y;
1275 RAW_PUTCHAR(c);
1276 if (D_AM && !D_CLP)
1277 GotoPos(D_width - 1, y);
1278 return;
1280 debug("PUTCHARLP: lp_missing!\n");
1281 D_lp_missing = 1;
1282 D_rend.image = c;
1283 D_lpchar = D_rend;
1284 #ifdef DW_CHARS
1285 /* XXX -> PutChar ? */
1286 if (D_mbcs)
1288 D_lpchar.mbcs = c;
1289 D_lpchar.image = D_mbcs;
1290 D_mbcs = 0;
1291 D_x--;
1293 #endif
1297 * RAW_PUTCHAR() is for all text that will be displayed.
1298 * NOTE: charset Nr. 0 has a conversion table, but c1, c2, ... don't.
1301 STATIC void
1302 RAW_PUTCHAR(c)
1303 int c;
1305 ASSERT(display);
1307 #ifdef FONT
1308 # ifdef UTF8
1309 if (D_encoding == UTF8)
1311 c = (c & 255) | (unsigned char)D_rend.font << 8;
1312 # ifdef DW_CHARS
1313 if (D_mbcs)
1315 c = D_mbcs;
1316 if (D_x == D_width)
1317 D_x += D_AM ? 1 : -1;
1318 D_mbcs = 0;
1320 else if (utf8_isdouble(c))
1322 D_mbcs = c;
1323 D_x++;
1324 return;
1326 # endif
1327 if (c < 32)
1329 AddCStr2(D_CS0, '0');
1330 AddChar(c + 0x5f);
1331 AddCStr(D_CE0);
1332 goto addedutf8;
1334 AddUtf8(c);
1335 goto addedutf8;
1337 # endif
1338 # ifdef DW_CHARS
1339 if (is_dw_font(D_rend.font))
1341 int t = c;
1342 if (D_mbcs == 0)
1344 D_mbcs = c;
1345 D_x++;
1346 return;
1348 D_x--;
1349 if (D_x == D_width - 1)
1350 D_x += D_AM ? 1 : -1;
1351 c = D_mbcs;
1352 D_mbcs = t;
1354 # endif
1355 # if defined(ENCODINGS) && defined(DW_CHARS)
1356 if (D_encoding)
1357 c = PrepareEncodedChar(c);
1358 # endif
1359 # ifdef DW_CHARS
1360 kanjiloop:
1361 # endif
1362 if (D_xtable && D_xtable[(int)(unsigned char)D_rend.font] && D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c])
1363 AddStr(D_xtable[(int)(unsigned char)D_rend.font][(int)(unsigned char)c]);
1364 else
1365 AddChar(D_rend.font != '0' ? c : D_c0_tab[(int)(unsigned char)c]);
1366 #else /* FONT */
1367 AddChar(c);
1368 #endif /* FONT */
1370 #ifdef UTF8
1371 addedutf8:
1372 #endif
1373 if (++D_x >= D_width)
1375 if (D_AM == 0)
1376 D_x = D_width - 1;
1377 else if (!D_CLP || D_x > D_width)
1379 D_x -= D_width;
1380 if (D_y < D_height-1 && D_y != D_bot)
1381 D_y++;
1384 #ifdef DW_CHARS
1385 if (D_mbcs)
1387 c = D_mbcs;
1388 D_mbcs = 0;
1389 goto kanjiloop;
1391 #endif
1394 static int
1395 DoAddChar(c)
1396 int c;
1398 /* this is for ESC-sequences only (AddChar is a macro) */
1399 AddChar(c);
1400 return c;
1403 void
1404 AddCStr(s)
1405 char *s;
1407 if (display && s && *s)
1409 ospeed = D_dospeed;
1410 tputs(s, 1, DoAddChar);
1414 void
1415 AddCStr2(s, c)
1416 char *s;
1417 int c;
1419 if (display && s && *s)
1421 ospeed = D_dospeed;
1422 tputs(tgoto(s, 0, c), 1, DoAddChar);
1427 /* Insert mode is a toggle on some terminals, so we need this hack:
1429 void
1430 InsertMode(on)
1431 int on;
1433 if (display && on != D_insert && D_IM)
1435 D_insert = on;
1436 if (on)
1437 AddCStr(D_IM);
1438 else
1439 AddCStr(D_EI);
1443 /* ...and maybe keypad application mode is a toggle, too:
1445 void
1446 KeypadMode(on)
1447 int on;
1449 #ifdef MAPKEYS
1450 if (display)
1451 D_keypad = on;
1452 #else
1453 if (display && D_keypad != on && D_KS)
1455 D_keypad = on;
1456 if (on)
1457 AddCStr(D_KS);
1458 else
1459 AddCStr(D_KE);
1461 #endif
1464 void
1465 CursorkeysMode(on)
1466 int on;
1468 #ifdef MAPKEYS
1469 if (display)
1470 D_cursorkeys = on;
1471 #else
1472 if (display && D_cursorkeys != on && D_CCS)
1474 D_cursorkeys = on;
1475 if (on)
1476 AddCStr(D_CCS);
1477 else
1478 AddCStr(D_CCE);
1480 #endif
1483 void
1484 ReverseVideo(on)
1485 int on;
1487 if (display && D_revvid != on && D_CVR)
1489 D_revvid = on;
1490 if (D_revvid)
1491 AddCStr(D_CVR);
1492 else
1493 AddCStr(D_CVN);
1497 void
1498 CursorVisibility(v)
1499 int v;
1501 if (display && D_curvis != v)
1503 if (D_curvis)
1504 AddCStr(D_VE); /* do this always, just to be safe */
1505 D_curvis = 0;
1506 if (v == -1 && D_VI)
1507 AddCStr(D_VI);
1508 else if (v == 1 && D_VS)
1509 AddCStr(D_VS);
1510 else
1511 return;
1512 D_curvis = v;
1516 void
1517 MouseMode(mode)
1518 int mode;
1520 if (display && D_mouse != mode)
1522 char mousebuf[20];
1523 if (!D_CXT)
1524 return;
1525 if (D_mouse)
1527 sprintf(mousebuf, "\033[?%dl", D_mouse);
1528 AddStr(mousebuf);
1530 if (mode)
1532 sprintf(mousebuf, "\033[?%dh", mode);
1533 AddStr(mousebuf);
1535 D_mouse = mode;
1539 static int StrCost;
1541 /* ARGSUSED */
1542 static int
1543 CountChars(c)
1544 int c;
1546 StrCost++;
1547 return c;
1551 CalcCost(s)
1552 register char *s;
1554 ASSERT(display);
1555 if (s)
1557 StrCost = 0;
1558 ospeed = D_dospeed;
1559 tputs(s, 1, CountChars);
1560 return StrCost;
1562 else
1563 return EXPENSIVE;
1566 static int
1567 CallRewrite(y, xs, xe, doit)
1568 int y, xs, xe, doit;
1570 struct canvas *cv, *cvlist, *cvlnext;
1571 struct viewport *vp;
1572 struct layer *oldflayer;
1573 int cost;
1575 debug3("CallRewrite %d %d %d\n", y, xs, xe);
1576 ASSERT(display);
1577 ASSERT(xe >= xs);
1579 vp = 0;
1580 for (cv = D_cvlist; cv; cv = cv->c_next)
1582 if (y < cv->c_ys || y > cv->c_ye || xe < cv->c_xs || xs > cv->c_xe)
1583 continue;
1584 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1585 if (y >= vp->v_ys && y <= vp->v_ye && xe >= vp->v_xs && xs <= vp->v_xe)
1586 break;
1587 if (vp)
1588 break;
1590 if (doit)
1592 oldflayer = flayer;
1593 flayer = cv->c_layer;
1594 cvlist = flayer->l_cvlist;
1595 cvlnext = cv->c_lnext;
1596 flayer->l_cvlist = cv;
1597 cv->c_lnext = 0;
1598 LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 1);
1599 flayer->l_cvlist = cvlist;
1600 cv->c_lnext = cvlnext;
1601 flayer = oldflayer;
1602 return 0;
1604 if (cv == 0 || cv->c_layer == 0)
1605 return EXPENSIVE; /* not found or nothing on it */
1606 if (xs < vp->v_xs || xe > vp->v_xe)
1607 return EXPENSIVE; /* crosses viewport boundaries */
1608 if (y - vp->v_yoff < 0 || y - vp->v_yoff >= cv->c_layer->l_height)
1609 return EXPENSIVE; /* line not on layer */
1610 if (xs - vp->v_xoff < 0 || xe - vp->v_xoff >= cv->c_layer->l_width)
1611 return EXPENSIVE; /* line not on layer */
1612 #ifdef UTF8
1613 if (D_encoding == UTF8)
1614 D_rend.font = 0;
1615 #endif
1616 oldflayer = flayer;
1617 flayer = cv->c_layer;
1618 debug3("Calling Rewrite %d %d %d\n", y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff);
1619 cost = LayRewrite(y - vp->v_yoff, xs - vp->v_xoff, xe - vp->v_xoff, &D_rend, 0);
1620 flayer = oldflayer;
1621 if (D_insert)
1622 cost += D_EIcost + D_IMcost;
1623 return cost;
1627 void
1628 GotoPos(x2, y2)
1629 int x2, y2;
1631 register int dy, dx, x1, y1;
1632 register int costx, costy;
1633 register int m;
1634 register char *s;
1635 int CMcost;
1636 enum move_t xm = M_NONE, ym = M_NONE;
1638 if (!display)
1639 return;
1641 x1 = D_x;
1642 y1 = D_y;
1644 if (x1 == D_width)
1646 if (D_CLP && D_AM)
1647 x1 = -1; /* don't know how the terminal treats this */
1648 else
1649 x1--;
1651 if (x2 == D_width)
1652 x2--;
1653 dx = x2 - x1;
1654 dy = y2 - y1;
1655 if (dy == 0 && dx == 0)
1656 return;
1657 debug2("GotoPos (%d,%d)", x1, y1);
1658 debug2(" -> (%d,%d)\n", x2, y2);
1659 if (!D_MS) /* Safe to move ? */
1660 SetRendition(&mchar_null);
1661 if (y1 < 0 /* don't know the y position */
1662 || (y2 > D_bot && y1 <= D_bot) /* have to cross border */
1663 || (y2 < D_top && y1 >= D_top)) /* of scrollregion ? */
1665 DoCM:
1666 if (D_HO && !x2 && !y2)
1667 AddCStr(D_HO);
1668 else
1669 AddCStr(tgoto(D_CM, x2, y2));
1670 D_x = x2;
1671 D_y = y2;
1672 return;
1675 /* some scrollregion implementations don't allow movements
1676 * away from the region. sigh.
1678 if ((y1 > D_bot && y2 > y1) || (y1 < D_top && y2 < y1))
1679 goto DoCM;
1681 /* Calculate CMcost */
1682 if (D_HO && !x2 && !y2)
1683 s = D_HO;
1684 else
1685 s = tgoto(D_CM, x2, y2);
1686 CMcost = CalcCost(s);
1688 /* Calculate the cost to move the cursor to the right x position */
1689 costx = EXPENSIVE;
1690 if (x1 >= 0) /* relativ x positioning only if we know where we are */
1692 if (dx > 0)
1694 if (D_CRI && (dx > 1 || !D_ND))
1696 costx = CalcCost(tgoto(D_CRI, 0, dx));
1697 xm = M_CRI;
1699 if ((m = D_NDcost * dx) < costx)
1701 costx = m;
1702 xm = M_RI;
1704 /* Speedup: dx <= LayRewrite() */
1705 if (dx < costx && (m = CallRewrite(y1, x1, x2 - 1, 0)) < costx)
1707 costx = m;
1708 xm = M_RW;
1711 else if (dx < 0)
1713 if (D_CLE && (dx < -1 || !D_BC))
1715 costx = CalcCost(tgoto(D_CLE, 0, -dx));
1716 xm = M_CLE;
1718 if ((m = -dx * D_LEcost) < costx)
1720 costx = m;
1721 xm = M_LE;
1724 else
1725 costx = 0;
1727 /* Speedup: LayRewrite() >= x2 */
1728 if (x2 + D_CRcost < costx && (m = (x2 ? CallRewrite(y1, 0, x2 - 1, 0) : 0) + D_CRcost) < costx)
1730 costx = m;
1731 xm = M_CR;
1734 /* Check if it is already cheaper to do CM */
1735 if (costx >= CMcost)
1736 goto DoCM;
1738 /* Calculate the cost to move the cursor to the right y position */
1739 costy = EXPENSIVE;
1740 if (dy > 0)
1742 if (D_CDO && dy > 1) /* DO & NL are always != 0 */
1744 costy = CalcCost(tgoto(D_CDO, 0, dy));
1745 ym = M_CDO;
1747 if ((m = dy * ((x2 == 0) ? D_NLcost : D_DOcost)) < costy)
1749 costy = m;
1750 ym = M_DO;
1753 else if (dy < 0)
1755 if (D_CUP && (dy < -1 || !D_UP))
1757 costy = CalcCost(tgoto(D_CUP, 0, -dy));
1758 ym = M_CUP;
1760 if ((m = -dy * D_UPcost) < costy)
1762 costy = m;
1763 ym = M_UP;
1766 else
1767 costy = 0;
1769 /* Finally check if it is cheaper to do CM */
1770 if (costx + costy >= CMcost)
1771 goto DoCM;
1773 switch (xm)
1775 case M_LE:
1776 while (dx++ < 0)
1777 AddCStr(D_BC);
1778 break;
1779 case M_CLE:
1780 AddCStr2(D_CLE, -dx);
1781 break;
1782 case M_RI:
1783 while (dx-- > 0)
1784 AddCStr(D_ND);
1785 break;
1786 case M_CRI:
1787 AddCStr2(D_CRI, dx);
1788 break;
1789 case M_CR:
1790 AddCStr(D_CR);
1791 D_x = 0;
1792 x1 = 0;
1793 /* FALLTHROUGH */
1794 case M_RW:
1795 if (x1 < x2)
1796 (void) CallRewrite(y1, x1, x2 - 1, 1);
1797 break;
1798 default:
1799 break;
1802 switch (ym)
1804 case M_UP:
1805 while (dy++ < 0)
1806 AddCStr(D_UP);
1807 break;
1808 case M_CUP:
1809 AddCStr2(D_CUP, -dy);
1810 break;
1811 case M_DO:
1812 s = (x2 == 0) ? D_NL : D_DO;
1813 while (dy-- > 0)
1814 AddCStr(s);
1815 break;
1816 case M_CDO:
1817 AddCStr2(D_CDO, dy);
1818 break;
1819 default:
1820 break;
1822 D_x = x2;
1823 D_y = y2;
1826 void
1827 ClearAll()
1829 ASSERT(display);
1830 ClearArea(0, 0, 0, D_width - 1, D_width - 1, D_height - 1, 0, 0);
1833 void
1834 ClearArea(x1, y1, xs, xe, x2, y2, bce, uselayfn)
1835 int x1, y1, xs, xe, x2, y2, bce, uselayfn;
1837 int y, xxe;
1838 struct canvas *cv;
1839 struct viewport *vp;
1841 debug2("Clear %d,%d", x1, y1);
1842 debug2(" %d-%d", xs, xe);
1843 debug2(" %d,%d", x2, y2);
1844 debug2(" uselayfn=%d bce=%d\n", uselayfn, bce);
1845 ASSERT(display);
1846 if (x1 == D_width)
1847 x1--;
1848 if (x2 == D_width)
1849 x2--;
1850 if (xs == -1)
1851 xs = x1;
1852 if (xe == -1)
1853 xe = x2;
1854 if (D_UT) /* Safe to erase ? */
1855 SetRendition(&mchar_null);
1856 #ifdef COLOR
1857 if (D_BE)
1858 SetBackColor(bce);
1859 #endif
1860 if (D_lp_missing && y1 <= D_bot && xe >= D_width - 1)
1862 if (y2 > D_bot || (y2 == D_bot && x2 >= D_width - 1))
1863 D_lp_missing = 0;
1865 if (x2 == D_width - 1 && (xs == 0 || y1 == y2) && xe == D_width - 1 && y2 == D_height - 1 && (!bce || D_BE))
1867 #ifdef AUTO_NUKE
1868 if (x1 == 0 && y1 == 0 && D_auto_nuke)
1869 NukePending();
1870 #endif
1871 if (x1 == 0 && y1 == 0 && D_CL)
1873 AddCStr(D_CL);
1874 D_y = D_x = 0;
1875 return;
1878 * Workaround a hp700/22 terminal bug. Do not use CD where CE
1879 * is also appropriate.
1881 if (D_CD && (y1 < y2 || !D_CE))
1883 GotoPos(x1, y1);
1884 AddCStr(D_CD);
1885 return;
1888 if (x1 == 0 && xs == 0 && (xe == D_width - 1 || y1 == y2) && y1 == 0 && D_CCD && (!bce || D_BE))
1890 GotoPos(x1, y1);
1891 AddCStr(D_CCD);
1892 return;
1894 xxe = xe;
1895 for (y = y1; y <= y2; y++, x1 = xs)
1897 if (y == y2)
1898 xxe = x2;
1899 if (x1 == 0 && D_CB && (xxe != D_width - 1 || (D_x == xxe && D_y == y)) && (!bce || D_BE))
1901 GotoPos(xxe, y);
1902 AddCStr(D_CB);
1903 continue;
1905 if (xxe == D_width - 1 && D_CE && (!bce || D_BE))
1907 GotoPos(x1, y);
1908 AddCStr(D_CE);
1909 continue;
1911 if (uselayfn)
1913 vp = 0;
1914 for (cv = D_cvlist; cv; cv = cv->c_next)
1916 if (y < cv->c_ys || y > cv->c_ye || xxe < cv->c_xs || x1 > cv->c_xe)
1917 continue;
1918 for (vp = cv->c_vplist; vp; vp = vp->v_next)
1919 if (y >= vp->v_ys && y <= vp->v_ye && xxe >= vp->v_xs && x1 <= vp->v_xe)
1920 break;
1921 if (vp)
1922 break;
1924 if (cv && cv->c_layer && x1 >= vp->v_xs && xxe <= vp->v_xe &&
1925 y - vp->v_yoff >= 0 && y - vp->v_yoff < cv->c_layer->l_height &&
1926 xxe - vp->v_xoff >= 0 && x1 - vp->v_xoff < cv->c_layer->l_width)
1928 struct layer *oldflayer = flayer;
1929 struct canvas *cvlist, *cvlnext;
1930 flayer = cv->c_layer;
1931 cvlist = flayer->l_cvlist;
1932 cvlnext = cv->c_lnext;
1933 flayer->l_cvlist = cv;
1934 cv->c_lnext = 0;
1935 LayClearLine(y - vp->v_yoff, x1 - vp->v_xoff, xxe - vp->v_xoff, bce);
1936 flayer->l_cvlist = cvlist;
1937 cv->c_lnext = cvlnext;
1938 flayer = oldflayer;
1939 continue;
1942 ClearLine((struct mline *)0, y, x1, xxe, bce);
1948 * if cur_only > 0, we only redisplay current line, as a full refresh is
1949 * too expensive over a low baud line.
1951 void
1952 Redisplay(cur_only)
1953 int cur_only;
1955 ASSERT(display);
1957 /* XXX do em all? */
1958 InsertMode(0);
1959 ChangeScrollRegion(0, D_height - 1);
1960 KeypadMode(0);
1961 CursorkeysMode(0);
1962 CursorVisibility(0);
1963 MouseMode(0);
1964 SetRendition(&mchar_null);
1965 SetFlow(FLOW_NOW);
1967 ClearAll();
1968 #ifdef RXVT_OSC
1969 RefreshXtermOSC();
1970 #endif
1971 if (cur_only > 0 && D_fore)
1972 RefreshArea(0, D_fore->w_y, D_width - 1, D_fore->w_y, 1);
1973 else
1974 RefreshAll(1);
1975 RefreshHStatus();
1976 CV_CALL(D_forecv, LayRestore();LaySetCursor());
1979 void
1980 RedisplayDisplays(cur_only)
1981 int cur_only;
1983 struct display *olddisplay = display;
1984 for (display = displays; display; display = display->d_next)
1985 Redisplay(cur_only);
1986 display = olddisplay;
1990 /* XXX: use oml! */
1991 void
1992 ScrollH(y, xs, xe, n, bce, oml)
1993 int y, xs, xe, n, bce;
1994 struct mline *oml;
1996 int i;
1998 if (n == 0)
1999 return;
2000 if (xe != D_width - 1)
2002 RefreshLine(y, xs, xe, 0);
2003 /* UpdateLine(oml, y, xs, xe); */
2004 return;
2006 GotoPos(xs, y);
2007 if (D_UT)
2008 SetRendition(&mchar_null);
2009 #ifdef COLOR
2010 if (D_BE)
2011 SetBackColor(bce);
2012 #endif
2013 if (n > 0)
2015 if (n >= xe - xs + 1)
2016 n = xe - xs + 1;
2017 if (D_CDC && !(n == 1 && D_DC))
2018 AddCStr2(D_CDC, n);
2019 else if (D_DC)
2021 for (i = n; i--; )
2022 AddCStr(D_DC);
2024 else
2026 RefreshLine(y, xs, xe, 0);
2027 /* UpdateLine(oml, y, xs, xe); */
2028 return;
2031 else
2033 if (-n >= xe - xs + 1)
2034 n = -(xe - xs + 1);
2035 if (!D_insert)
2037 if (D_CIC && !(n == -1 && D_IC))
2038 AddCStr2(D_CIC, -n);
2039 else if (D_IC)
2041 for (i = -n; i--; )
2042 AddCStr(D_IC);
2044 else if (D_IM)
2046 InsertMode(1);
2047 SetRendition(&mchar_null);
2048 #ifdef COLOR
2049 SetBackColor(bce);
2050 #endif
2051 for (i = -n; i--; )
2052 INSERTCHAR(' ');
2053 bce = 0; /* all done */
2055 else
2057 /* UpdateLine(oml, y, xs, xe); */
2058 RefreshLine(y, xs, xe, 0);
2059 return;
2062 else
2064 SetRendition(&mchar_null);
2065 #ifdef COLOR
2066 SetBackColor(bce);
2067 #endif
2068 for (i = -n; i--; )
2069 INSERTCHAR(' ');
2070 bce = 0; /* all done */
2073 if (bce && !D_BE)
2075 if (n > 0)
2076 ClearLine((struct mline *)0, y, xe - n + 1, xe, bce);
2077 else
2078 ClearLine((struct mline *)0, y, xs, xs - n - 1, bce);
2080 if (D_lp_missing && y == D_bot)
2082 if (n > 0)
2083 WriteLP(D_width - 1 - n, y);
2084 D_lp_missing = 0;
2088 void
2089 ScrollV(xs, ys, xe, ye, n, bce)
2090 int xs, ys, xe, ye, n, bce;
2092 int i;
2093 int up;
2094 int oldtop, oldbot;
2095 int alok, dlok, aldlfaster;
2096 int missy = 0;
2098 ASSERT(display);
2099 if (n == 0)
2100 return;
2101 if (n >= ye - ys + 1 || -n >= ye - ys + 1)
2103 ClearArea(xs, ys, xs, xe, xe, ye, bce, 0);
2104 return;
2106 if (xs > D_vpxmin || xe < D_vpxmax)
2108 RefreshArea(xs, ys, xe, ye, 0);
2109 return;
2112 if (D_lp_missing)
2114 if (D_bot > ye || D_bot < ys)
2115 missy = D_bot;
2116 else
2118 missy = D_bot - n;
2119 if (missy > ye || missy < ys)
2120 D_lp_missing = 0;
2124 up = 1;
2125 if (n < 0)
2127 up = 0;
2128 n = -n;
2130 if (n >= ye - ys + 1)
2131 n = ye - ys + 1;
2133 oldtop = D_top;
2134 oldbot = D_bot;
2135 if (ys < D_top || D_bot != ye)
2136 ChangeScrollRegion(ys, ye);
2137 alok = (D_AL || D_CAL || (ys >= D_top && ye == D_bot && up));
2138 dlok = (D_DL || D_CDL || (ys >= D_top && ye == D_bot && !up));
2139 if (D_top != ys && !(alok && dlok))
2140 ChangeScrollRegion(ys, ye);
2142 if (D_lp_missing &&
2143 (oldbot != D_bot ||
2144 (oldbot == D_bot && up && D_top == ys && D_bot == ye)))
2146 WriteLP(D_width - 1, oldbot);
2147 if (oldbot == D_bot) /* have scrolled */
2149 if (--n == 0)
2151 /* XXX
2152 ChangeScrollRegion(oldtop, oldbot);
2154 if (bce && !D_BE)
2155 ClearLine((struct mline *)0, ye, xs, xe, bce);
2156 return;
2161 if (D_UT)
2162 SetRendition(&mchar_null);
2163 #ifdef COLOR
2164 if (D_BE)
2165 SetBackColor(bce);
2166 #endif
2168 aldlfaster = (n > 1 && ys >= D_top && ye == D_bot && ((up && D_CDL) || (!up && D_CAL)));
2170 if ((up || D_SR) && D_top == ys && D_bot == ye && !aldlfaster)
2172 if (up)
2174 GotoPos(0, ye);
2175 for(i = n; i-- > 0; )
2176 AddCStr(D_NL); /* was SF, I think NL is faster */
2178 else
2180 GotoPos(0, ys);
2181 for(i = n; i-- > 0; )
2182 AddCStr(D_SR);
2185 else if (alok && dlok)
2187 if (up || ye != D_bot)
2189 GotoPos(0, up ? ys : ye+1-n);
2190 if (D_CDL && !(n == 1 && D_DL))
2191 AddCStr2(D_CDL, n);
2192 else
2193 for(i = n; i--; )
2194 AddCStr(D_DL);
2196 if (!up || ye != D_bot)
2198 GotoPos(0, up ? ye+1-n : ys);
2199 if (D_CAL && !(n == 1 && D_AL))
2200 AddCStr2(D_CAL, n);
2201 else
2202 for(i = n; i--; )
2203 AddCStr(D_AL);
2206 else
2208 RefreshArea(xs, ys, xe, ye, 0);
2209 return;
2211 if (bce && !D_BE)
2213 if (up)
2214 ClearArea(xs, ye - n + 1, xs, xe, xe, ye, bce, 0);
2215 else
2216 ClearArea(xs, ys, xs, xe, xe, ys + n - 1, bce, 0);
2218 if (D_lp_missing && missy != D_bot)
2219 WriteLP(D_width - 1, missy);
2220 /* XXX
2221 ChangeScrollRegion(oldtop, oldbot);
2222 if (D_lp_missing && missy != D_bot)
2223 WriteLP(D_width - 1, missy);
2227 void
2228 SetAttr(new)
2229 register int new;
2231 register int i, j, old, typ;
2233 if (!display || (old = D_rend.attr) == new)
2234 return;
2235 #ifdef COLORS16
2236 D_col16change = (old ^ new) & (A_BFG | A_BBG);
2237 new ^= D_col16change;
2238 if (old == new)
2239 return;
2240 #endif
2241 #if defined(TERMINFO) && defined(USE_SGR)
2242 if (D_SA)
2244 char *tparm();
2245 SetFont(ASCII);
2246 ospeed = D_dospeed;
2247 tputs(tparm(D_SA, new & A_SO, new & A_US, new & A_RV, new & A_BL,
2248 new & A_DI, new & A_BD, 0 , 0 ,
2249 0), 1, DoAddChar);
2250 D_rend.attr = new;
2251 D_atyp = 0;
2252 # ifdef COLOR
2253 if (D_hascolor)
2254 rend_setdefault(&D_rend);
2255 # endif
2256 return;
2258 #endif
2259 D_rend.attr = new;
2260 typ = D_atyp;
2261 if ((new & old) != old)
2263 if ((typ & ATYP_U))
2264 AddCStr(D_UE);
2265 if ((typ & ATYP_S))
2266 AddCStr(D_SE);
2267 if ((typ & ATYP_M))
2269 AddCStr(D_ME);
2270 #ifdef COLOR
2271 /* ansi attrib handling: \E[m resets color, too */
2272 if (D_hascolor)
2273 rend_setdefault(&D_rend);
2274 #endif
2275 #ifdef FONT
2276 if (!D_CG0)
2278 /* D_ME may also reset the alternate charset */
2279 D_rend.font = 0;
2280 # ifdef ENCODINGS
2281 D_realfont = 0;
2282 # endif
2284 #endif
2286 old = 0;
2287 typ = 0;
2289 old ^= new;
2290 for (i = 0, j = 1; old && i < NATTR; i++, j <<= 1)
2292 if ((old & j) == 0)
2293 continue;
2294 old ^= j;
2295 if (D_attrtab[i])
2297 AddCStr(D_attrtab[i]);
2298 typ |= D_attrtyp[i];
2301 D_atyp = typ;
2304 #ifdef FONT
2305 void
2306 SetFont(new)
2307 int new;
2309 int old = D_rend.font;
2310 if (!display || old == new)
2311 return;
2312 D_rend.font = new;
2313 #ifdef ENCODINGS
2314 if (D_encoding && CanEncodeFont(D_encoding, new))
2315 return;
2316 if (new == D_realfont)
2317 return;
2318 D_realfont = new;
2319 #endif
2320 if (D_xtable && D_xtable[(int)(unsigned char)new] &&
2321 D_xtable[(int)(unsigned char)new][256])
2323 AddCStr(D_xtable[(int)(unsigned char)new][256]);
2324 return;
2327 if (!D_CG0 && new != '0')
2329 new = ASCII;
2330 if (old == new)
2331 return;
2334 if (new == ASCII)
2335 AddCStr(D_CE0);
2336 #ifdef DW_CHARS
2337 else if (new < ' ')
2339 AddStr("\033$");
2340 if (new > 2)
2341 AddChar('(');
2342 AddChar(new + '@');
2344 #endif
2345 else
2346 AddCStr2(D_CS0, new);
2348 #endif
2350 #ifdef COLOR
2353 color256to16(jj)
2354 int jj;
2356 int min, max;
2357 int r, g, b;
2359 if (jj >= 232)
2361 jj = (jj - 232) / 6;
2362 jj = (jj & 1) << 3 | (jj & 2 ? 7 : 0);
2364 else if (jj >= 16)
2366 jj -= 16;
2367 r = jj / 36;
2368 g = (jj / 6) % 6;
2369 b = jj % 6;
2370 min = r < g ? (r < b ? r : b) : (g < b ? g : b);
2371 max = r > g ? (r > b ? r : b) : (g > b ? g : b);
2372 if (min == max)
2373 jj = ((max + 1) & 2) << 2 | ((max + 1) & 4 ? 7 : 0);
2374 else
2375 jj = (b - min) / (max - min) << 2 | (g - min) / (max - min) << 1 | (r -
2376 min) / (max - min) | (max > 3 ? 8 : 0);
2378 return jj;
2381 #ifdef COLORS256
2383 color256to88(jj)
2384 int jj;
2386 int r, g, b;
2388 if (jj >= 232)
2389 return (jj - 232) / 3 + 80;
2390 if (jj >= 16)
2392 jj -= 16;
2393 r = jj / 36;
2394 g = (jj / 6) % 6;
2395 b = jj % 6;
2396 return ((r + 1) / 2) * 16 + ((g + 1) / 2) * 4 + ((b + 1) / 2) + 16;
2398 return jj;
2400 #endif
2402 void
2403 SetColor(f, b)
2404 int f, b;
2406 int of, ob;
2407 static unsigned char sftrans[8] = {0,4,2,6,1,5,3,7};
2409 if (!display)
2410 return;
2412 of = rend_getfg(&D_rend);
2413 ob = rend_getbg(&D_rend);
2415 #ifdef COLORS16
2416 /* intense default not invented yet */
2417 if (f == 0x100)
2418 f = 0;
2419 if (b == 0x100)
2420 b = 0;
2421 #endif
2422 debug2("SetColor %d %d", coli2e(of), coli2e(ob));
2423 debug2(" -> %d %d\n", coli2e(f), coli2e(b));
2424 debug2("(%d %d", of, ob);
2425 debug2(" -> %d %d)\n", f, b);
2427 if (!D_CAX && D_hascolor && ((f == 0 && f != of) || (b == 0 && b != ob)))
2429 if (D_OP)
2430 AddCStr(D_OP);
2431 else
2433 int oattr;
2434 oattr = D_rend.attr;
2435 AddCStr(D_ME ? D_ME : "\033[m");
2436 #ifdef FONT
2437 if (D_ME && !D_CG0)
2439 /* D_ME may also reset the alternate charset */
2440 D_rend.font = 0;
2441 # ifdef ENCODINGS
2442 D_realfont = 0;
2443 # endif
2445 #endif
2446 D_atyp = 0;
2447 D_rend.attr = 0;
2448 SetAttr(oattr);
2450 of = ob = 0;
2452 rend_setfg(&D_rend, f);
2453 rend_setbg(&D_rend, b);
2454 #ifdef COLORS16
2455 D_col16change = 0;
2456 #endif
2457 if (!D_hascolor)
2458 return;
2459 f = f ? coli2e(f) : -1;
2460 b = b ? coli2e(b) : -1;
2461 of = of ? coli2e(of) : -1;
2462 ob = ob ? coli2e(ob) : -1;
2463 #ifdef COLORS256
2464 if (f != of && f > 15 && D_CCO != 256)
2465 f = D_CCO == 88 && D_CAF ? color256to88(f) : color256to16(f);
2466 if (f != of && f > 15 && D_CAF)
2468 AddCStr2(D_CAF, f);
2469 of = f;
2471 if (b != ob && b > 15 && D_CCO != 256)
2472 b = D_CCO == 88 && D_CAB ? color256to88(b) : color256to16(b);
2473 if (b != ob && b > 15 && D_CAB)
2475 AddCStr2(D_CAB, b);
2476 ob = b;
2478 #endif
2479 if (f != of && f != (of | 8))
2481 if (f == -1)
2482 AddCStr("\033[39m"); /* works because AX is set */
2483 else if (D_CAF)
2484 AddCStr2(D_CAF, f & 7);
2485 else if (D_CSF)
2486 AddCStr2(D_CSF, sftrans[f & 7]);
2488 if (b != ob && b != (ob | 8))
2490 if (b == -1)
2491 AddCStr("\033[49m"); /* works because AX is set */
2492 else if (D_CAB)
2493 AddCStr2(D_CAB, b & 7);
2494 else if (D_CSB)
2495 AddCStr2(D_CSB, sftrans[b & 7]);
2497 #ifdef COLORS16
2498 if (f != of && D_CXT && (f & 8) != 0 && f != -1)
2500 # ifdef TERMINFO
2501 AddCStr2("\033[9%p1%dm", f & 7);
2502 # else
2503 AddCStr2("\033[9%dm", f & 7);
2504 # endif
2506 if (b != ob && D_CXT && (b & 8) != 0 && b != -1)
2508 # ifdef TERMINFO
2509 AddCStr2("\033[10%p1%dm", b & 7);
2510 # else
2511 AddCStr2("\033[10%dm", b & 7);
2512 # endif
2514 #endif
2517 static void
2518 SetBackColor(new)
2519 int new;
2521 if (!display)
2522 return;
2523 SetColor(rend_getfg(&D_rend), new);
2525 #endif /* COLOR */
2527 void
2528 SetRendition(mc)
2529 struct mchar *mc;
2531 if (!display)
2532 return;
2533 if (nattr2color && D_hascolor && (mc->attr & nattr2color) != 0)
2535 static struct mchar mmc;
2536 int i;
2537 mmc = *mc;
2538 for (i = 0; i < 8; i++)
2539 if (attr2color[i] && (mc->attr & (1 << i)) != 0)
2541 if (mc->color == 0 && attr2color[i][3])
2542 ApplyAttrColor(attr2color[i][3], &mmc);
2543 else if ((mc->color & 0x0f) == 0 && attr2color[i][2])
2544 ApplyAttrColor(attr2color[i][2], &mmc);
2545 else if ((mc->color & 0xf0) == 0 && attr2color[i][1])
2546 ApplyAttrColor(attr2color[i][1], &mmc);
2547 else
2548 ApplyAttrColor(attr2color[i][0], &mmc);
2550 mc = &mmc;
2551 debug2("SetRendition: mapped to %02x %02x\n", (unsigned char)mc->attr, 0x99 - (unsigned char)mc->color);
2553 if (D_hascolor && D_CC8 && (mc->attr & (A_BFG|A_BBG)))
2555 int a = mc->attr;
2556 if ((mc->attr & A_BFG) && D_MD)
2557 a |= A_BD;
2558 if ((mc->attr & A_BBG) && D_MB)
2559 a |= A_BL;
2560 if (D_rend.attr != a)
2561 SetAttr(a);
2563 else if (D_rend.attr != mc->attr)
2564 SetAttr(mc->attr);
2565 #ifdef COLOR
2566 if (D_rend.color != mc->color
2567 # ifdef COLORS256
2568 || D_rend.colorx != mc->colorx
2569 # endif
2570 # ifdef COLORS16
2571 || D_col16change
2572 # endif
2574 SetColor(rend_getfg(mc), rend_getbg(mc));
2575 #endif
2576 #ifdef FONT
2577 if (D_rend.font != mc->font)
2578 SetFont(mc->font);
2579 #endif
2582 void
2583 SetRenditionMline(ml, x)
2584 struct mline *ml;
2585 int x;
2587 if (!display)
2588 return;
2589 if (nattr2color && D_hascolor && (ml->attr[x] & nattr2color) != 0)
2591 struct mchar mc;
2592 copy_mline2mchar(&mc, ml, x);
2593 SetRendition(&mc);
2594 return;
2596 if (D_hascolor && D_CC8 && (ml->attr[x] & (A_BFG|A_BBG)))
2598 int a = ml->attr[x];
2599 if ((ml->attr[x] & A_BFG) && D_MD)
2600 a |= A_BD;
2601 if ((ml->attr[x] & A_BBG) && D_MB)
2602 a |= A_BL;
2603 if (D_rend.attr != a)
2604 SetAttr(a);
2606 else if (D_rend.attr != ml->attr[x])
2607 SetAttr(ml->attr[x]);
2608 #ifdef COLOR
2609 if (D_rend.color != ml->color[x]
2610 # ifdef COLORS256
2611 || D_rend.colorx != ml->colorx[x]
2612 # endif
2613 # ifdef COLORS16
2614 || D_col16change
2615 # endif
2618 struct mchar mc;
2619 copy_mline2mchar(&mc, ml, x);
2620 SetColor(rend_getfg(&mc), rend_getbg(&mc));
2622 #endif
2623 #ifdef FONT
2624 if (D_rend.font != ml->font[x])
2625 SetFont(ml->font[x]);
2626 #endif
2629 void
2630 MakeStatus(msg)
2631 char *msg;
2633 register char *s, *t;
2634 register int max;
2636 if (!display)
2637 return;
2639 if (D_blocked)
2640 return;
2641 if (!D_tcinited)
2643 debug("tc not inited, just writing msg\n");
2644 if (D_processinputdata)
2645 return; /* XXX: better */
2646 AddStr(msg);
2647 AddStr("\r\n");
2648 Flush();
2649 return;
2651 if (!use_hardstatus || !D_HS)
2653 max = D_width;
2654 if (D_CLP == 0)
2655 max--;
2657 else
2658 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2659 if (D_status)
2661 /* same message? */
2662 if (strcmp(msg, D_status_lastmsg) == 0)
2664 debug("same message - increase timeout");
2665 SetTimeout(&D_statusev, MsgWait);
2666 return;
2668 if (!D_status_bell)
2670 struct timeval now;
2671 int ti;
2672 gettimeofday(&now, NULL);
2673 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
2674 if (ti < MsgMinWait)
2675 DisplaySleep1000(MsgMinWait - ti, 0);
2677 RemoveStatus();
2679 for (s = t = msg; *s && t - msg < max; ++s)
2680 if (*s == BELL)
2681 AddCStr(D_BL);
2682 else if ((unsigned char)*s >= ' ' && *s != 0177)
2683 *t++ = *s;
2684 *t = '\0';
2685 if (t == msg)
2686 return;
2687 if (t - msg >= D_status_buflen)
2689 char *buf;
2690 if (D_status_lastmsg)
2691 buf = realloc(D_status_lastmsg, t - msg + 1);
2692 else
2693 buf = malloc(t - msg + 1);
2694 if (buf)
2696 D_status_lastmsg = buf;
2697 D_status_buflen = t - msg + 1;
2700 if (t - msg < D_status_buflen)
2701 strcpy(D_status_lastmsg, msg);
2702 D_status_len = t - msg;
2703 D_status_lastx = D_x;
2704 D_status_lasty = D_y;
2705 if (!use_hardstatus || D_has_hstatus == HSTATUS_IGNORE || D_has_hstatus == HSTATUS_MESSAGE)
2707 D_status = STATUS_ON_WIN;
2708 debug1("using STATLINE %d\n", STATLINE);
2709 GotoPos(0, STATLINE);
2710 SetRendition(&mchar_so);
2711 InsertMode(0);
2712 AddStr(msg);
2713 if (D_status_len < max)
2715 /* Wayne Davison: add extra space for readability */
2716 D_status_len++;
2717 SetRendition(&mchar_null);
2718 AddChar(' ');
2719 if (D_status_len < max)
2721 D_status_len++;
2722 AddChar(' ');
2723 AddChar('\b');
2725 AddChar('\b');
2727 D_x = -1;
2729 else
2731 D_status = STATUS_ON_HS;
2732 ShowHStatus(msg);
2734 Flush();
2735 if (!display)
2736 return;
2737 if (D_status == STATUS_ON_WIN)
2739 struct display *olddisplay = display;
2740 struct layer *oldflayer = flayer;
2742 ASSERT(D_obuffree == D_obuflen);
2743 /* this is copied over from RemoveStatus() */
2744 D_status = 0;
2745 GotoPos(0, STATLINE);
2746 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2747 GotoPos(D_status_lastx, D_status_lasty);
2748 flayer = D_forecv ? D_forecv->c_layer : 0;
2749 if (flayer)
2750 LaySetCursor();
2751 display = olddisplay;
2752 flayer = oldflayer;
2753 D_status_obuflen = D_obuflen;
2754 D_status_obuffree = D_obuffree;
2755 D_obuffree = D_obuflen = 0;
2756 D_status = STATUS_ON_WIN;
2758 gettimeofday(&D_status_time, NULL);
2759 SetTimeout(&D_statusev, MsgWait);
2760 evenq(&D_statusev);
2761 #ifdef HAVE_BRAILLE
2762 RefreshBraille(); /* let user see multiple Msg()s */
2763 #endif
2766 void
2767 RemoveStatus()
2769 struct display *olddisplay;
2770 struct layer *oldflayer;
2771 int where;
2773 if (!display)
2774 return;
2775 if (!(where = D_status))
2776 return;
2778 debug("RemoveStatus\n");
2779 if (D_status_obuffree >= 0)
2781 D_obuflen = D_status_obuflen;
2782 D_obuffree = D_status_obuffree;
2783 D_status_obuffree = -1;
2785 D_status = 0;
2786 D_status_bell = 0;
2787 evdeq(&D_statusev);
2788 olddisplay = display;
2789 oldflayer = flayer;
2790 if (where == STATUS_ON_WIN)
2792 GotoPos(0, STATLINE);
2793 RefreshLine(STATLINE, 0, D_status_len - 1, 0);
2794 GotoPos(D_status_lastx, D_status_lasty);
2796 else
2797 RefreshHStatus();
2798 flayer = D_forecv ? D_forecv->c_layer : 0;
2799 if (flayer)
2800 LaySetCursor();
2801 display = olddisplay;
2802 flayer = oldflayer;
2805 /* refresh the display's hstatus line */
2806 void
2807 ShowHStatus(str)
2808 char *str;
2810 int l, ox, oy, max;
2812 if (D_status == STATUS_ON_WIN && D_has_hstatus == HSTATUS_LASTLINE && STATLINE == D_height-1)
2813 return; /* sorry, in use */
2814 if (D_blocked)
2815 return;
2817 if (D_HS && D_has_hstatus == HSTATUS_HS)
2819 if (!D_hstatus && (str == 0 || *str == 0))
2820 return;
2821 debug("ShowHStatus: using HS\n");
2822 SetRendition(&mchar_null);
2823 InsertMode(0);
2824 if (D_hstatus)
2825 AddCStr(D_DS);
2826 D_hstatus = 0;
2827 if (str == 0 || *str == 0)
2828 return;
2829 AddCStr2(D_TS, 0);
2830 max = D_WS > 0 ? D_WS : (D_width - !D_CLP);
2831 if ((int)strlen(str) > max)
2832 AddStrn(str, max);
2833 else
2834 AddStr(str);
2835 AddCStr(D_FS);
2836 D_hstatus = 1;
2838 else if (D_has_hstatus == HSTATUS_LASTLINE)
2840 debug("ShowHStatus: using last line\n");
2841 ox = D_x;
2842 oy = D_y;
2843 str = str ? str : "";
2844 l = strlen(str);
2845 if (l > D_width)
2846 l = D_width;
2847 GotoPos(0, D_height - 1);
2848 SetRendition(captionalways || D_cvlist == 0 || D_cvlist->c_next ? &mchar_null: &mchar_so);
2849 PutWinMsg(str, 0, l);
2850 if (!captionalways && D_cvlist && !D_cvlist->c_next)
2851 while (l++ < D_width)
2852 PUTCHARLP(' ');
2853 if (l < D_width)
2854 ClearArea(l, D_height - 1, l, D_width - 1, D_width - 1, D_height - 1, 0, 0);
2855 if (ox != -1 && oy != -1)
2856 GotoPos(ox, oy);
2857 D_hstatus = *str ? 1 : 0;
2858 SetRendition(&mchar_null);
2860 else if (str && *str && D_has_hstatus == HSTATUS_MESSAGE)
2862 debug("ShowHStatus: using message\n");
2863 Msg(0, "%s", str);
2869 * Refreshes the harstatus of the fore window. Shouldn't be here...
2871 void
2872 RefreshHStatus()
2874 char *buf;
2876 evdeq(&D_hstatusev);
2877 if (D_status == STATUS_ON_HS)
2878 return;
2879 buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
2880 if (buf && *buf)
2882 ShowHStatus(buf);
2883 if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
2884 evenq(&D_hstatusev);
2886 else
2887 ShowHStatus((char *)0);
2890 /*********************************************************************/
2892 * Here come the routines that refresh an arbitrary part of the screen.
2895 void
2896 RefreshAll(isblank)
2897 int isblank;
2899 struct canvas *cv;
2901 ASSERT(display);
2902 debug("Signalling full refresh!\n");
2903 for (cv = D_cvlist; cv; cv = cv->c_next)
2905 CV_CALL(cv, LayRedisplayLine(-1, -1, -1, isblank));
2906 display = cv->c_display; /* just in case! */
2908 RefreshArea(0, 0, D_width - 1, D_height - 1, isblank);
2911 void
2912 RefreshArea(xs, ys, xe, ye, isblank)
2913 int xs, ys, xe, ye, isblank;
2915 int y;
2916 ASSERT(display);
2917 debug2("Refresh Area: %d,%d", xs, ys);
2918 debug3(" - %d,%d (isblank=%d)\n", xe, ye, isblank);
2919 if (!isblank && xs == 0 && xe == D_width - 1 && ye == D_height - 1 && (ys == 0 || D_CD))
2921 ClearArea(xs, ys, xs, xe, xe, ye, 0, 0);
2922 isblank = 1;
2924 for (y = ys; y <= ye; y++)
2925 RefreshLine(y, xs, xe, isblank);
2928 void
2929 RefreshLine(y, from, to, isblank)
2930 int y, from, to, isblank;
2932 struct viewport *vp, *lvp;
2933 struct canvas *cv, *lcv, *cvlist, *cvlnext;
2934 struct layer *oldflayer;
2935 int xx, yy, l;
2936 char *buf;
2937 struct win *p;
2939 ASSERT(display);
2941 debug2("RefreshLine %d %d", y, from);
2942 debug2(" %d %d\n", to, isblank);
2944 if (D_status == STATUS_ON_WIN && y == STATLINE)
2946 if (to >= D_status_len)
2947 D_status_len = to + 1;
2948 return; /* can't refresh status */
2951 /* The following check makes plenty of sense. Unfortunately,
2952 vte-based terminals (notably gnome-terminal) experience a quirk
2953 that causes the final line not to update properly when it falls outside
2954 the scroll region; clearing the line with D_CE avoids the glitch,
2955 so we'll disable this perfectly sensible shortcut until such a time
2956 as widespread vte installations lack the glitch.
2958 See http://bugzilla.gnome.org/show_bug.cgi?id=542087 for current
2959 status of the VTE bug report, and
2960 https://savannah.gnu.org/bugs/index.php?23699 for the history from
2961 the Savannah BTS. */
2962 #if 0
2963 if (y == D_height - 1 && D_has_hstatus == HSTATUS_LASTLINE)
2965 RefreshHStatus();
2966 return;
2968 #endif
2970 if (isblank == 0 && D_CE && to == D_width - 1 && from < to)
2972 GotoPos(from, y);
2973 if (D_UT || D_BE)
2974 SetRendition(&mchar_null);
2975 AddCStr(D_CE);
2976 isblank = 1;
2978 while (from <= to)
2980 lcv = 0;
2981 lvp = 0;
2982 for (cv = display->d_cvlist; cv; cv = cv->c_next)
2984 if (y == cv->c_ye + 1 && from >= cv->c_xs && from <= cv->c_xe)
2986 p = Layer2Window(cv->c_layer);
2987 buf = MakeWinMsgEv(captionstring, p, '%', cv->c_xe - cv->c_xs + (cv->c_xe + 1 < D_width || D_CLP), &cv->c_captev, 0);
2988 if (cv->c_captev.timeout.tv_sec)
2989 evenq(&cv->c_captev);
2990 xx = to > cv->c_xe ? cv->c_xe : to;
2991 l = strlen(buf);
2992 GotoPos(from, y);
2993 SetRendition(&mchar_so);
2994 if (l > xx - cv->c_xs + 1)
2995 l = xx - cv->c_xs + 1;
2996 PutWinMsg(buf, from - cv->c_xs, l);
2997 from = cv->c_xs + l;
2998 for (; from <= xx; from++)
2999 PUTCHARLP(' ');
3000 break;
3002 if (from == cv->c_xe + 1 && y >= cv->c_ys && y <= cv->c_ye + 1)
3004 GotoPos(from, y);
3005 SetRendition(&mchar_so);
3006 PUTCHARLP(' ');
3007 from++;
3008 break;
3010 if (y < cv->c_ys || y > cv->c_ye || to < cv->c_xs || from > cv->c_xe)
3011 continue;
3012 debug2("- canvas hit: %d %d", cv->c_xs, cv->c_ys);
3013 debug2(" %d %d\n", cv->c_xe, cv->c_ye);
3014 for (vp = cv->c_vplist; vp; vp = vp->v_next)
3016 debug2(" - vp: %d %d", vp->v_xs, vp->v_ys);
3017 debug2(" %d %d\n", vp->v_xe, vp->v_ye);
3018 /* find leftmost overlapping vp */
3019 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))
3021 lcv = cv;
3022 lvp = vp;
3026 if (cv)
3027 continue; /* we advanced from */
3028 if (lvp == 0)
3029 break;
3030 if (from < lvp->v_xs)
3032 if (!isblank)
3033 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xs - 1);
3034 from = lvp->v_xs;
3037 /* call LayRedisplayLine on canvas lcv viewport lvp */
3038 yy = y - lvp->v_yoff;
3039 xx = to < lvp->v_xe ? to : lvp->v_xe;
3041 if (lcv->c_layer && yy == lcv->c_layer->l_height)
3043 GotoPos(from, y);
3044 SetRendition(&mchar_blank);
3045 while (from <= lvp->v_xe && from - lvp->v_xoff < lcv->c_layer->l_width)
3047 PUTCHARLP('-');
3048 from++;
3050 if (from >= lvp->v_xe + 1)
3051 continue;
3053 if (lcv->c_layer == 0 || yy >= lcv->c_layer->l_height || from - lvp->v_xoff >= lcv->c_layer->l_width)
3055 if (!isblank)
3056 DisplayLine(&mline_null, &mline_blank, y, from, lvp->v_xe);
3057 from = lvp->v_xe + 1;
3058 continue;
3061 if (xx - lvp->v_xoff >= lcv->c_layer->l_width)
3062 xx = lcv->c_layer->l_width + lvp->v_xoff - 1;
3063 oldflayer = flayer;
3064 flayer = lcv->c_layer;
3065 cvlist = flayer->l_cvlist;
3066 cvlnext = lcv->c_lnext;
3067 flayer->l_cvlist = lcv;
3068 lcv->c_lnext = 0;
3069 LayRedisplayLine(yy, from - lvp->v_xoff, xx - lvp->v_xoff, isblank);
3070 flayer->l_cvlist = cvlist;
3071 lcv->c_lnext = cvlnext;
3072 flayer = oldflayer;
3074 from = xx + 1;
3076 if (!isblank && from <= to)
3077 DisplayLine(&mline_null, &mline_blank, y, from, to);
3080 /*********************************************************************/
3082 /* clear lp_missing by writing the char on the screen. The
3083 * position must be safe.
3085 static void
3086 WriteLP(x2, y2)
3087 int x2, y2;
3089 struct mchar oldrend;
3091 ASSERT(display);
3092 ASSERT(D_lp_missing);
3093 oldrend = D_rend;
3094 debug2("WriteLP(%d,%d)\n", x2, y2);
3095 #ifdef DW_CHARS
3096 if (D_lpchar.mbcs)
3098 if (x2 > 0)
3099 x2--;
3100 else
3101 D_lpchar = mchar_blank;
3103 #endif
3104 /* Can't use PutChar */
3105 GotoPos(x2, y2);
3106 SetRendition(&D_lpchar);
3107 PUTCHAR(D_lpchar.image);
3108 #ifdef DW_CHARS
3109 if (D_lpchar.mbcs)
3110 PUTCHAR(D_lpchar.mbcs);
3111 #endif
3112 D_lp_missing = 0;
3113 SetRendition(&oldrend);
3116 void
3117 ClearLine(oml, y, from, to, bce)
3118 struct mline *oml;
3119 int from, to, y, bce;
3121 int x;
3122 #ifdef COLOR
3123 struct mchar bcechar;
3124 #endif
3126 debug3("ClearLine %d,%d-%d\n", y, from, to);
3127 if (D_UT) /* Safe to erase ? */
3128 SetRendition(&mchar_null);
3129 #ifdef COLOR
3130 if (D_BE)
3131 SetBackColor(bce);
3132 #endif
3133 if (from == 0 && D_CB && (to != D_width - 1 || (D_x == to && D_y == y)) && (!bce || D_BE))
3135 GotoPos(to, y);
3136 AddCStr(D_CB);
3137 return;
3139 if (to == D_width - 1 && D_CE && (!bce || D_BE))
3141 GotoPos(from, y);
3142 AddCStr(D_CE);
3143 return;
3145 if (oml == 0)
3146 oml = &mline_null;
3147 #ifdef COLOR
3148 if (!bce)
3150 DisplayLine(oml, &mline_blank, y, from, to);
3151 return;
3153 bcechar = mchar_blank;
3154 rend_setbg(&bcechar, bce);
3155 for (x = from; x <= to; x++)
3156 copy_mchar2mline(&bcechar, &mline_old, x);
3157 DisplayLine(oml, &mline_old, y, from, to);
3158 #else
3159 DisplayLine(oml, &mline_blank, y, from, to);
3160 #endif
3163 void
3164 DisplayLine(oml, ml, y, from, to)
3165 struct mline *oml, *ml;
3166 int from, to, y;{
3168 register int x;
3169 int last2flag = 0, delete_lp = 0;
3171 ASSERT(display);
3172 ASSERT(y >= 0 && y < D_height);
3173 ASSERT(from >= 0 && from < D_width);
3174 ASSERT(to >= 0 && to < D_width);
3175 if (!D_CLP && y == D_bot && to == D_width - 1)
3177 if (D_lp_missing || !cmp_mline(oml, ml, to))
3179 #ifdef DW_CHARS
3180 if ((D_IC || D_IM) && from < to && !dw_left(ml, to, D_encoding))
3181 #else
3182 if ((D_IC || D_IM) && from < to)
3183 #endif
3185 last2flag = 1;
3186 D_lp_missing = 0;
3187 to--;
3189 else
3191 delete_lp = !cmp_mchar_mline(&mchar_blank, oml, to) && (D_CE || D_DC || D_CDC);
3192 D_lp_missing = !cmp_mchar_mline(&mchar_blank, ml, to);
3193 copy_mline2mchar(&D_lpchar, ml, to);
3196 to--;
3198 #ifdef DW_CHARS
3199 if (D_mbcs)
3201 /* finish dw-char (can happen after a wrap) */
3202 debug("DisplayLine finishing kanji\n");
3203 SetRenditionMline(ml, from);
3204 PUTCHAR(ml->image[from]);
3205 from++;
3207 #endif
3208 for (x = from; x <= to; x++)
3210 #if 0 /* no longer needed */
3211 if (x || D_x != D_width || D_y != y - 1)
3212 #endif
3214 if (x < to || x != D_width - 1 || ml->image[x + 1])
3215 if (cmp_mline(oml, ml, x))
3216 continue;
3217 GotoPos(x, y);
3219 #ifdef DW_CHARS
3220 if (dw_right(ml, x, D_encoding))
3222 x--;
3223 debug1("DisplayLine on right side of dw char- x now %d\n", x);
3224 GotoPos(x, y);
3226 if (x == to && dw_left(ml, x, D_encoding))
3227 break; /* don't start new kanji */
3228 #endif
3229 SetRenditionMline(ml, x);
3230 PUTCHAR(ml->image[x]);
3231 #ifdef DW_CHARS
3232 if (dw_left(ml, x, D_encoding))
3233 PUTCHAR(ml->image[++x]);
3234 #endif
3236 #if 0 /* not needed any longer */
3237 /* compare != 0 because ' ' can happen when clipping occures */
3238 if (to == D_width - 1 && y < D_height - 1 && D_x == D_width && ml->image[to + 1])
3239 GotoPos(0, y + 1);
3240 #endif
3241 if (last2flag)
3243 GotoPos(x, y);
3244 SetRenditionMline(ml, x + 1);
3245 PUTCHAR(ml->image[x + 1]);
3246 GotoPos(x, y);
3247 SetRenditionMline(ml, x);
3248 INSERTCHAR(ml->image[x]);
3250 else if (delete_lp)
3252 if (D_UT)
3253 SetRendition(&mchar_null);
3254 if (D_DC)
3255 AddCStr(D_DC);
3256 else if (D_CDC)
3257 AddCStr2(D_CDC, 1);
3258 else if (D_CE)
3259 AddCStr(D_CE);
3263 void
3264 PutChar(c, x, y)
3265 struct mchar *c;
3266 int x, y;
3268 GotoPos(x, y);
3269 SetRendition(c);
3270 PUTCHARLP(c->image);
3271 #ifdef DW_CHARS
3272 if (c->mbcs)
3274 # ifdef UTF8
3275 if (D_encoding == UTF8)
3276 D_rend.font = 0;
3277 # endif
3278 PUTCHARLP(c->mbcs);
3280 #endif
3283 void
3284 InsChar(c, x, xe, y, oml)
3285 struct mchar *c;
3286 int x, xe, y;
3287 struct mline *oml;
3289 GotoPos(x, y);
3290 if (y == D_bot && !D_CLP)
3292 if (x == D_width - 1)
3294 D_lp_missing = 1;
3295 D_lpchar = *c;
3296 return;
3298 if (xe == D_width - 1)
3299 D_lp_missing = 0;
3301 if (x == xe)
3303 SetRendition(c);
3304 PUTCHARLP(c->image);
3305 return;
3307 if (!(D_IC || D_CIC || D_IM) || xe != D_width - 1)
3309 RefreshLine(y, x, xe, 0);
3310 GotoPos(x + 1, y);
3311 /* UpdateLine(oml, y, x, xe); */
3312 return;
3314 InsertMode(1);
3315 if (!D_insert)
3317 #ifdef DW_CHARS
3318 if (c->mbcs && D_IC)
3319 AddCStr(D_IC);
3320 if (D_IC)
3321 AddCStr(D_IC);
3322 else
3323 AddCStr2(D_CIC, c->mbcs ? 2 : 1);
3324 #else
3325 if (D_IC)
3326 AddCStr(D_IC);
3327 else
3328 AddCStr2(D_CIC, 1);
3329 #endif
3331 SetRendition(c);
3332 RAW_PUTCHAR(c->image);
3333 #ifdef DW_CHARS
3334 if (c->mbcs)
3336 # ifdef UTF8
3337 if (D_encoding == UTF8)
3338 D_rend.font = 0;
3339 # endif
3340 if (D_x == D_width - 1)
3341 PUTCHARLP(c->mbcs);
3342 else
3343 RAW_PUTCHAR(c->mbcs);
3345 #endif
3348 void
3349 WrapChar(c, x, y, xs, ys, xe, ye, ins)
3350 struct mchar *c;
3351 int x, y;
3352 int xs, ys, xe, ye;
3353 int ins;
3355 int bce;
3357 #ifdef COLOR
3358 bce = rend_getbg(c);
3359 #else
3360 bce = 0;
3361 #endif
3362 debug("WrapChar:");
3363 debug2(" x %d y %d", x, y);
3364 debug2(" Dx %d Dy %d", D_x, D_y);
3365 debug2(" xs %d ys %d", xs, ys);
3366 debug3(" xe %d ye %d ins %d\n", xe, ye, ins);
3367 if (xs != 0 || x != D_width || !D_AM)
3369 if (y == ye)
3370 ScrollV(xs, ys, xe, ye, 1, bce);
3371 else if (y < D_height - 1)
3372 y++;
3373 if (ins)
3374 InsChar(c, xs, xe, y, 0);
3375 else
3376 PutChar(c, xs, y);
3377 return;
3379 if (y == ye) /* we have to scroll */
3381 debug("- scrolling\n");
3382 ChangeScrollRegion(ys, ye);
3383 if (D_bot != y || D_x != D_width || (!bce && !D_BE))
3385 debug("- have to call ScrollV\n");
3386 ScrollV(xs, ys, xe, ye, 1, bce);
3387 y--;
3390 else if (y == D_bot) /* remove unusable region? */
3391 ChangeScrollRegion(0, D_height - 1);
3392 if (D_x != D_width || D_y != y)
3394 if (D_CLP && y >= 0) /* don't even try if !LP */
3395 RefreshLine(y, D_width - 1, D_width - 1, 0);
3396 debug2("- refresh last char -> x,y now %d,%d\n", D_x, D_y);
3397 if (D_x != D_width || D_y != y) /* sorry, no bonus */
3399 if (y == ye)
3400 ScrollV(xs, ys, xe, ye, 1, bce);
3401 GotoPos(xs, y == ye || y == D_height - 1 ? y : y + 1);
3404 debug("- writeing new char");
3405 if (y != ye && y < D_height - 1)
3406 y++;
3407 if (ins != D_insert)
3408 InsertMode(ins);
3409 if (ins && !D_insert)
3411 InsChar(c, 0, xe, y, 0);
3412 debug2(" -> done with insert (%d,%d)\n", D_x, D_y);
3413 return;
3415 D_y = y;
3416 D_x = 0;
3417 SetRendition(c);
3418 RAW_PUTCHAR(c->image);
3419 #ifdef DW_CHARS
3420 if (c->mbcs)
3422 # ifdef UTF8
3423 if (D_encoding == UTF8)
3424 D_rend.font = 0;
3425 # endif
3426 RAW_PUTCHAR(c->mbcs);
3428 #endif
3429 debug2(" -> done (%d,%d)\n", D_x, D_y);
3433 ResizeDisplay(wi, he)
3434 int wi, he;
3436 ASSERT(display);
3437 debug2("ResizeDisplay: to (%d,%d).\n", wi, he);
3438 if (D_width == wi && D_height == he)
3440 debug("ResizeDisplay: No change\n");
3441 return 0;
3443 if (D_width != wi && (D_height == he || !D_CWS) && D_CZ0 && (wi == Z0width || wi == Z1width))
3445 debug("ResizeDisplay: using Z0/Z1\n");
3446 AddCStr(wi == Z0width ? D_CZ0 : D_CZ1);
3447 ChangeScreenSize(wi, D_height, 0);
3448 return (he == D_height) ? 0 : -1;
3450 if (D_CWS)
3452 debug("ResizeDisplay: using WS\n");
3453 AddCStr(tgoto(D_CWS, wi, he));
3454 ChangeScreenSize(wi, he, 0);
3455 return 0;
3457 return -1;
3460 void
3461 ChangeScrollRegion(newtop, newbot)
3462 int newtop, newbot;
3464 if (display == 0)
3465 return;
3466 if (newtop == newbot)
3467 return; /* xterm etc can't do it */
3468 if (newtop == -1)
3469 newtop = 0;
3470 if (newbot == -1)
3471 newbot = D_height - 1;
3472 if (D_CS == 0)
3474 D_top = 0;
3475 D_bot = D_height - 1;
3476 return;
3478 if (D_top == newtop && D_bot == newbot)
3479 return;
3480 debug2("ChangeScrollRegion: (%d - %d)\n", newtop, newbot);
3481 AddCStr(tgoto(D_CS, newbot, newtop));
3482 D_top = newtop;
3483 D_bot = newbot;
3484 D_y = D_x = -1; /* Just in case... */
3487 #ifdef RXVT_OSC
3488 void
3489 SetXtermOSC(i, s)
3490 int i;
3491 char *s;
3493 static char oscs[] = "1;\000\00020;\00039;\00049;\000";
3495 ASSERT(display);
3496 if (!D_CXT)
3497 return;
3498 if (!s)
3499 s = "";
3500 if (!D_xtermosc[i] && !*s)
3501 return;
3502 if (i == 0 && !*s)
3503 s = "screen"; /* always set icon name */
3504 if (i == 1 && !*s)
3505 s = ""; /* no background */
3506 if (i == 2 && !*s)
3507 s = "black"; /* black text */
3508 if (i == 3 && !*s)
3509 s = "white"; /* on white background */
3510 D_xtermosc[i] = 1;
3511 AddStr("\033]");
3512 AddStr(oscs + i * 4);
3513 AddStr(s);
3514 AddChar(7);
3517 void
3518 ClearAllXtermOSC()
3520 int i;
3521 for (i = 3; i >= 0; i--)
3522 SetXtermOSC(i, 0);
3524 #endif
3527 * Output buffering routines
3530 void
3531 AddStr(str)
3532 char *str;
3534 register char c;
3536 ASSERT(display);
3538 #ifdef UTF8
3539 if (D_encoding == UTF8)
3541 while ((c = *str++))
3542 AddUtf8((unsigned char)c);
3543 return;
3545 #endif
3546 while ((c = *str++))
3547 AddChar(c);
3550 void
3551 AddStrn(str, n)
3552 char *str;
3553 int n;
3555 register char c;
3557 ASSERT(display);
3558 #ifdef UTF8
3559 if (D_encoding == UTF8)
3561 while ((c = *str++) && n-- > 0)
3562 AddUtf8((unsigned char)c);
3564 else
3565 #endif
3566 while ((c = *str++) && n-- > 0)
3567 AddChar(c);
3568 while (n-- > 0)
3569 AddChar(' ');
3572 void
3573 Flush()
3575 register int l;
3576 register char *p;
3578 ASSERT(display);
3579 l = D_obufp - D_obuf;
3580 debug1("Flush(): %d\n", l);
3581 if (l == 0)
3582 return;
3583 ASSERT(l + D_obuffree == D_obuflen);
3584 if (D_userfd < 0)
3586 D_obuffree += l;
3587 D_obufp = D_obuf;
3588 return;
3590 p = D_obuf;
3591 if (fcntl(D_userfd, F_SETFL, 0))
3592 debug1("Warning: BLOCK fcntl failed: %d\n", errno);
3593 while (l)
3595 register int wr;
3596 wr = write(D_userfd, p, l);
3597 if (wr <= 0)
3599 if (errno == EINTR)
3600 continue;
3601 debug1("Writing to display: %d\n", errno);
3602 wr = l;
3604 if (!display)
3605 return;
3606 D_obuffree += wr;
3607 p += wr;
3608 l -= wr;
3610 D_obuffree += l;
3611 D_obufp = D_obuf;
3612 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
3613 debug1("Warning: NBLOCK fcntl failed: %d\n", errno);
3614 if (D_blocked == 1)
3615 D_blocked = 0;
3616 D_blocked_fuzz = 0;
3619 void
3620 freetty()
3622 if (D_userfd >= 0)
3623 close(D_userfd);
3624 debug1("did freetty %d\n", D_userfd);
3625 D_userfd = -1;
3626 D_obufp = 0;
3627 D_obuffree = 0;
3628 if (D_obuf)
3629 free(D_obuf);
3630 D_obuf = 0;
3631 D_obuflen = 0;
3632 D_obuflenmax = -D_obufmax;
3633 D_blocked = 0;
3634 D_blocked_fuzz = 0;
3638 * Asynchronous output routines by
3639 * Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
3642 void
3643 Resize_obuf()
3645 register int ind;
3647 ASSERT(display);
3648 if (D_status_obuffree >= 0)
3650 ASSERT(D_obuffree == -1);
3651 if (!D_status_bell)
3653 struct timeval now;
3654 int ti;
3655 gettimeofday(&now, NULL);
3656 ti = (now.tv_sec - D_status_time.tv_sec) * 1000 + (now.tv_usec - D_status_time.tv_usec) / 1000;
3657 if (ti < MsgMinWait)
3658 DisplaySleep1000(MsgMinWait - ti, 0);
3660 RemoveStatus();
3661 if (--D_obuffree > 0) /* redo AddChar decrement */
3662 return;
3664 if (D_obuflen && D_obuf)
3666 ind = D_obufp - D_obuf;
3667 D_obuflen += GRAIN;
3668 D_obuffree += GRAIN;
3669 D_obuf = realloc(D_obuf, D_obuflen);
3671 else
3673 ind = 0;
3674 D_obuflen = GRAIN;
3675 D_obuffree = GRAIN;
3676 D_obuf = malloc(D_obuflen);
3678 if (!D_obuf)
3679 Panic(0, "Out of memory");
3680 D_obufp = D_obuf + ind;
3681 D_obuflenmax = D_obuflen - D_obufmax;
3682 debug1("ResizeObuf: resized to %d\n", D_obuflen);
3685 void
3686 DisplaySleep1000(n, eat)
3687 int n;
3688 int eat;
3690 char buf;
3691 fd_set r;
3692 struct timeval t;
3694 if (n <= 0)
3695 return;
3696 if (!display)
3698 debug("DisplaySleep has no display sigh\n");
3699 sleep1000(n);
3700 return;
3702 t.tv_usec = (n % 1000) * 1000;
3703 t.tv_sec = n / 1000;
3704 FD_ZERO(&r);
3705 FD_SET(D_userfd, &r);
3706 if (select(FD_SETSIZE, &r, (fd_set *)0, (fd_set *)0, &t) > 0)
3708 debug("display activity stopped sleep\n");
3709 if (eat)
3710 read(D_userfd, &buf, 1);
3712 debug2("DisplaySleep(%d) ending, eat was %d\n", n, eat);
3715 #ifdef AUTO_NUKE
3716 void
3717 NukePending()
3718 {/* Nuke pending output in current display, clear screen */
3719 register int len;
3720 int oldtop = D_top, oldbot = D_bot;
3721 struct mchar oldrend;
3722 int oldkeypad = D_keypad, oldcursorkeys = D_cursorkeys;
3723 int oldcurvis = D_curvis;
3724 int oldmouse = D_mouse;
3726 oldrend = D_rend;
3727 len = D_obufp - D_obuf;
3728 debug1("NukePending: nuking %d chars\n", len);
3730 /* Throw away any output that we can... */
3731 # ifdef POSIX
3732 tcflush(D_userfd, TCOFLUSH);
3733 # else
3734 # ifdef TCFLSH
3735 (void) ioctl(D_userfd, TCFLSH, (char *) 1);
3736 # endif
3737 # endif
3739 D_obufp = D_obuf;
3740 D_obuffree += len;
3741 D_top = D_bot = -1;
3742 AddCStr(D_TI);
3743 AddCStr(D_IS);
3744 /* Turn off all attributes. (Tim MacKenzie) */
3745 if (D_ME)
3746 AddCStr(D_ME);
3747 else
3749 #ifdef COLOR
3750 if (D_hascolor)
3751 AddStr("\033[m"); /* why is D_ME not set? */
3752 #endif
3753 AddCStr(D_SE);
3754 AddCStr(D_UE);
3756 /* Check for toggle */
3757 if (D_IM && strcmp(D_IM, D_EI))
3758 AddCStr(D_EI);
3759 D_insert = 0;
3760 /* Check for toggle */
3761 #ifdef MAPKEYS
3762 if (D_KS && strcmp(D_KS, D_KE))
3763 AddCStr(D_KS);
3764 if (D_CCS && strcmp(D_CCS, D_CCE))
3765 AddCStr(D_CCS);
3766 #else
3767 if (D_KS && strcmp(D_KS, D_KE))
3768 AddCStr(D_KE);
3769 D_keypad = 0;
3770 if (D_CCS && strcmp(D_CCS, D_CCE))
3771 AddCStr(D_CCE);
3772 D_cursorkeys = 0;
3773 #endif
3774 AddCStr(D_CE0);
3775 D_rend = mchar_null;
3776 D_atyp = 0;
3777 AddCStr(D_DS);
3778 D_hstatus = 0;
3779 AddCStr(D_VE);
3780 D_curvis = 0;
3781 ChangeScrollRegion(oldtop, oldbot);
3782 SetRendition(&oldrend);
3783 KeypadMode(oldkeypad);
3784 CursorkeysMode(oldcursorkeys);
3785 CursorVisibility(oldcurvis);
3786 MouseMode(oldmouse);
3787 if (D_CWS)
3789 debug("ResizeDisplay: using WS\n");
3790 AddCStr(tgoto(D_CWS, D_width, D_height));
3792 else if (D_CZ0 && (D_width == Z0width || D_width == Z1width))
3794 debug("ResizeDisplay: using Z0/Z1\n");
3795 AddCStr(D_width == Z0width ? D_CZ0 : D_CZ1);
3798 #endif /* AUTO_NUKE */
3800 #ifdef linux
3801 /* linux' select can't handle flow control, so wait 100ms if
3802 * we get EAGAIN
3804 static void
3805 disp_writeev_eagain(ev, data)
3806 struct event *ev;
3807 char *data;
3809 display = (struct display *)data;
3810 evdeq(&D_writeev);
3811 D_writeev.type = EV_WRITE;
3812 D_writeev.handler = disp_writeev_fn;
3813 evenq(&D_writeev);
3815 #endif
3817 static void
3818 disp_writeev_fn(ev, data)
3819 struct event *ev;
3820 char *data;
3822 int len, size = OUTPUT_BLOCK_SIZE;
3824 display = (struct display *)data;
3825 len = D_obufp - D_obuf;
3826 if (len < size)
3827 size = len;
3828 ASSERT(len >= 0);
3829 size = write(D_userfd, D_obuf, size);
3830 if (size >= 0)
3832 len -= size;
3833 if (len)
3835 bcopy(D_obuf + size, D_obuf, len);
3836 debug2("ASYNC: wrote %d - remaining %d\n", size, len);
3838 D_obufp -= size;
3839 D_obuffree += size;
3840 if (D_blocked_fuzz)
3842 D_blocked_fuzz -= size;
3843 if (D_blocked_fuzz < 0)
3844 D_blocked_fuzz = 0;
3846 if (D_blockedev.queued)
3848 if (D_obufp - D_obuf > D_obufmax / 2)
3850 debug2("%s: resetting timeout to %g secs\n", D_usertty, D_nonblock/1000.);
3851 SetTimeout(&D_blockedev, D_nonblock);
3853 else
3855 debug1("%s: deleting blocked timeout\n", D_usertty);
3856 evdeq(&D_blockedev);
3859 if (D_blocked == 1 && D_obuf == D_obufp)
3861 /* empty again, restart output */
3862 debug1("%s: buffer empty, unblocking\n", D_usertty);
3863 D_blocked = 0;
3864 Activate(D_fore ? D_fore->w_norefresh : 0);
3865 D_blocked_fuzz = D_obufp - D_obuf;
3868 else
3870 #ifdef linux
3871 /* linux flow control is badly broken */
3872 if (errno == EAGAIN)
3874 evdeq(&D_writeev);
3875 D_writeev.type = EV_TIMEOUT;
3876 D_writeev.handler = disp_writeev_eagain;
3877 SetTimeout(&D_writeev, 100);
3878 evenq(&D_writeev);
3880 #endif
3881 if (errno != EINTR && errno != EAGAIN)
3882 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3883 if (errno != EWOULDBLOCK)
3884 #endif
3885 Msg(errno, "Error writing output to display");
3889 static void
3890 disp_readev_fn(ev, data)
3891 struct event *ev;
3892 char *data;
3894 int size;
3895 char buf[IOSIZE];
3896 struct canvas *cv;
3898 display = (struct display *)data;
3900 /* Hmmmm... a bit ugly... */
3901 if (D_forecv)
3902 for (cv = D_forecv->c_layer->l_cvlist; cv; cv = cv->c_lnext)
3904 display = cv->c_display;
3905 if (D_status == STATUS_ON_WIN)
3906 RemoveStatus();
3909 display = (struct display *)data;
3910 if (D_fore == 0)
3911 size = IOSIZE;
3912 else
3914 #ifdef PSEUDOS
3915 if (W_UWP(D_fore))
3916 size = sizeof(D_fore->w_pwin->p_inbuf) - D_fore->w_pwin->p_inlen;
3917 else
3918 #endif
3919 size = sizeof(D_fore->w_inbuf) - D_fore->w_inlen;
3922 if (size > IOSIZE)
3923 size = IOSIZE;
3924 if (size <= 0)
3925 size = 1; /* Always allow one char for command keys */
3927 size = read(D_userfd, buf, size);
3928 if (size < 0)
3930 if (errno == EINTR || errno == EAGAIN)
3931 return;
3932 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
3933 if (errno == EWOULDBLOCK)
3934 return;
3935 #endif
3936 debug1("Read error: %d - hangup!\n", errno);
3937 Hangup();
3938 sleep(1);
3939 return;
3941 else if (size == 0)
3943 debug("Found EOF - hangup!\n");
3944 Hangup();
3945 sleep(1);
3946 return;
3948 if (D_blocked == 4)
3950 D_blocked = 0;
3951 #ifdef BLANKER_PRG
3952 KillBlanker();
3953 #endif
3954 Activate(D_fore ? D_fore->w_norefresh : 0);
3955 ResetIdle();
3956 return;
3958 #ifdef ZMODEM
3959 if (D_blocked > 1) /* 2, 3 */
3961 char *bufp;
3962 struct win *p;
3964 flayer = 0;
3965 for (p = windows; p ; p = p->w_next)
3966 if (p->w_zdisplay == display)
3968 flayer = &p->w_layer;
3969 bufp = buf;
3970 while (size > 0)
3971 LayProcess(&bufp, &size);
3972 return;
3974 debug("zmodem window gone, deblocking display");
3975 zmodem_abort(0, display);
3977 #endif
3978 if (idletimo > 0)
3979 ResetIdle();
3980 if (D_fore)
3981 D_fore->w_lastdisp = display;
3982 if (D_mouse && D_forecv)
3984 unsigned char *bp = (unsigned char *)buf;
3985 int x, y, i = size;
3987 /* XXX this assumes that the string is read in as a whole... */
3988 for (i = size; i > 0; i--, bp++)
3990 if (i > 5 && bp[0] == 033 && bp[1] == '[' && bp[2] == 'M')
3992 bp++;
3993 i--;
3995 else if (i < 5 || bp[0] != 0233 || bp[1] != 'M')
3996 continue;
3997 x = bp[3] - 33;
3998 y = bp[4] - 33;
3999 if (x >= D_forecv->c_xs && x <= D_forecv->c_xe && y >= D_forecv->c_ys && y <= D_forecv->c_ye)
4001 x -= D_forecv->c_xoff;
4002 y -= D_forecv->c_yoff;
4003 if (x >= 0 && x < D_forecv->c_layer->l_width && y >= 0 && y < D_forecv->c_layer->l_height)
4005 bp[3] = x + 33;
4006 bp[4] = y + 33;
4007 i -= 4;
4008 bp += 4;
4009 continue;
4012 if (bp[0] == '[')
4014 bcopy((char *)bp + 1, (char *)bp, i);
4015 bp--;
4016 size--;
4018 if (i > 5)
4019 bcopy((char *)bp + 5, (char *)bp, i - 5);
4020 bp--;
4021 i -= 4;
4022 size -= 5;
4025 #ifdef ENCODINGS
4026 if (D_encoding != (D_forecv ? D_forecv->c_layer->l_encoding : 0))
4028 int i, j, c, enc;
4029 char buf2[IOSIZE * 2 + 10];
4030 enc = D_forecv ? D_forecv->c_layer->l_encoding : 0;
4031 for (i = j = 0; i < size; i++)
4033 c = ((unsigned char *)buf)[i];
4034 c = DecodeChar(c, D_encoding, &D_decodestate);
4035 if (c == -2)
4036 i--; /* try char again */
4037 if (c < 0)
4038 continue;
4039 if (pastefont)
4041 int font = 0;
4042 j += EncodeChar(buf2 + j, c, enc, &font);
4043 j += EncodeChar(buf2 + j, -1, enc, &font);
4045 else
4046 j += EncodeChar(buf2 + j, c, enc, 0);
4047 if (j > (int)sizeof(buf2) - 10) /* just in case... */
4048 break;
4050 (*D_processinput)(buf2, j);
4051 return;
4053 #endif
4054 (*D_processinput)(buf, size);
4057 static void
4058 disp_status_fn(ev, data)
4059 struct event *ev;
4060 char *data;
4062 display = (struct display *)data;
4063 debug1("disp_status_fn for display %x\n", (int)display);
4064 if (D_status)
4065 RemoveStatus();
4068 static void
4069 disp_hstatus_fn(ev, data)
4070 struct event *ev;
4071 char *data;
4073 display = (struct display *)data;
4074 if (D_status == STATUS_ON_HS)
4076 SetTimeout(ev, 1);
4077 evenq(ev);
4078 return;
4080 RefreshHStatus();
4083 static void
4084 disp_blocked_fn(ev, data)
4085 struct event *ev;
4086 char *data;
4088 struct win *p;
4090 display = (struct display *)data;
4091 debug1("blocked timeout %s\n", D_usertty);
4092 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
4094 debug("stopping output to display\n");
4095 D_blocked = 1;
4096 /* re-enable all windows */
4097 for (p = windows; p; p = p->w_next)
4098 if (p->w_readev.condneg == &D_obuflenmax)
4100 debug1("freeing window #%d\n", p->w_number);
4101 p->w_readev.condpos = p->w_readev.condneg = 0;
4106 static void
4107 cv_winid_fn(ev, data)
4108 struct event *ev;
4109 char *data;
4111 int ox, oy;
4112 struct canvas *cv = (struct canvas *)data;
4114 display = cv->c_display;
4115 if (D_status == STATUS_ON_WIN)
4117 SetTimeout(ev, 1);
4118 evenq(ev);
4119 return;
4121 ox = D_x;
4122 oy = D_y;
4123 if (cv->c_ye + 1 < D_height)
4124 RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
4125 if (ox != -1 && oy != -1)
4126 GotoPos(ox, oy);
4129 #ifdef MAPKEYS
4130 static void
4131 disp_map_fn(ev, data)
4132 struct event *ev;
4133 char *data;
4135 char *p;
4136 int l, i;
4137 unsigned char *q;
4138 display = (struct display *)data;
4139 debug("Flushing map sequence\n");
4140 if (!(l = D_seql))
4141 return;
4142 p = (char *)D_seqp - l;
4143 D_seqp = D_kmaps + 3;
4144 D_seql = 0;
4145 if ((q = D_seqh) != 0)
4147 D_seqh = 0;
4148 i = q[0] << 8 | q[1];
4149 i &= ~KMAP_NOTIMEOUT;
4150 debug1("Mapping former hit #%d - ", i);
4151 debug2("%d(%s) - ", q[2], q + 3);
4152 if (StuffKey(i))
4153 ProcessInput2((char *)q + 3, q[2]);
4154 if (display == 0)
4155 return;
4156 l -= q[2];
4157 p += q[2];
4159 else
4160 D_dontmap = 1;
4161 ProcessInput(p, l);
4163 #endif
4165 static void
4166 disp_idle_fn(ev, data)
4167 struct event *ev;
4168 char *data;
4170 struct display *olddisplay;
4171 display = (struct display *)data;
4172 debug("idle timeout\n");
4173 if (idletimo <= 0 || idleaction.nr == RC_ILLEGAL)
4174 return;
4175 olddisplay = display;
4176 flayer = D_forecv->c_layer;
4177 fore = D_fore;
4178 DoAction(&idleaction, -1);
4179 if (idleaction.nr == RC_BLANKER)
4180 return;
4181 for (display = displays; display; display = display->d_next)
4182 if (olddisplay == display)
4183 break;
4184 if (display)
4185 ResetIdle();
4188 void
4189 ResetIdle()
4191 if (idletimo > 0)
4193 SetTimeout(&D_idleev, idletimo);
4194 if (!D_idleev.queued)
4195 evenq(&D_idleev);
4197 else
4198 evdeq(&D_idleev);
4202 #ifdef BLANKER_PRG
4204 static void
4205 disp_blanker_fn(ev, data)
4206 struct event *ev;
4207 char *data;
4209 char buf[IOSIZE], *b;
4210 int size;
4212 display = (struct display *)data;
4213 size = read(D_blankerev.fd, buf, IOSIZE);
4214 if (size <= 0)
4216 evdeq(&D_blankerev);
4217 close(D_blankerev.fd);
4218 D_blankerev.fd = -1;
4219 return;
4221 for (b = buf; size; size--)
4222 AddChar(*b++);
4225 void
4226 KillBlanker()
4228 int oldtop = D_top, oldbot = D_bot;
4229 struct mchar oldrend;
4231 if (D_blankerev.fd == -1)
4232 return;
4233 if (D_blocked == 4)
4234 D_blocked = 0;
4235 evdeq(&D_blankerev);
4236 close(D_blankerev.fd);
4237 D_blankerev.fd = -1;
4238 Kill(D_blankerpid, SIGHUP);
4239 D_top = D_bot = -1;
4240 oldrend = D_rend;
4241 if (D_ME)
4243 AddCStr(D_ME);
4244 AddCStr(D_ME);
4246 else
4248 #ifdef COLOR
4249 if (D_hascolor)
4250 AddStr("\033[m\033[m"); /* why is D_ME not set? */
4251 #endif
4252 AddCStr(D_SE);
4253 AddCStr(D_UE);
4255 AddCStr(D_VE);
4256 AddCStr(D_CE0);
4257 D_rend = mchar_null;
4258 D_atyp = 0;
4259 D_curvis = 0;
4260 D_x = D_y = -1;
4261 ChangeScrollRegion(oldtop, oldbot);
4262 SetRendition(&oldrend);
4263 ClearAll();
4266 void
4267 RunBlanker(cmdv)
4268 char **cmdv;
4270 char *m;
4271 int pid;
4272 int slave = -1;
4273 char termname[30];
4274 #ifndef TIOCSWINSZ
4275 char libuf[20], cobuf[20];
4276 #endif
4277 char **np;
4279 strcpy(termname, "TERM=");
4280 strncpy(termname + 5, D_termname, sizeof(termname) - 6);
4281 termname[sizeof(termname) - 1] = 0;
4282 KillBlanker();
4283 D_blankerpid = -1;
4284 if ((D_blankerev.fd = OpenPTY(&m)) == -1)
4286 Msg(0, "OpenPty failed");
4287 return;
4289 #ifdef O_NOCTTY
4290 if (pty_preopen)
4292 if ((slave = open(m, O_RDWR|O_NOCTTY)) == -1)
4294 Msg(errno, "%s", m);
4295 close(D_blankerev.fd);
4296 D_blankerev.fd = -1;
4297 return;
4300 #endif
4301 switch (pid = (int)fork())
4303 case -1:
4304 Msg(errno, "fork");
4305 close(D_blankerev.fd);
4306 D_blankerev.fd = -1;
4307 return;
4308 case 0:
4309 displays = 0;
4310 #ifdef DEBUG
4311 if (dfp && dfp != stderr)
4312 fclose(dfp);
4313 #endif
4314 if (setgid(real_gid) || setuid(real_uid))
4315 Panic(errno, "setuid/setgid");
4316 brktty(D_userfd);
4317 freetty();
4318 close(0);
4319 close(1);
4320 close(2);
4321 closeallfiles(slave);
4322 if (open(m, O_RDWR))
4323 Panic(errno, "Cannot open %s", m);
4324 dup(0);
4325 dup(0);
4326 if (slave != -1)
4327 close(slave);
4328 InitPTY(0);
4329 fgtty(0);
4330 SetTTY(0, &D_OldMode);
4331 np = NewEnv + 3;
4332 *np++ = NewEnv[0];
4333 *np++ = termname;
4334 #ifdef TIOCSWINSZ
4335 glwz.ws_col = D_width;
4336 glwz.ws_row = D_height;
4337 (void)ioctl(0, TIOCSWINSZ, (char *)&glwz);
4338 #else
4339 sprintf(libuf, "LINES=%d", D_height);
4340 sprintf(cobuf, "COLUMNS=%d", D_width);
4341 *np++ = libuf;
4342 *np++ = cobuf;
4343 #endif
4344 #ifdef SIGPIPE
4345 signal(SIGPIPE, SIG_DFL);
4346 #endif
4347 display = 0;
4348 execvpe(*cmdv, cmdv, NewEnv + 3);
4349 Panic(errno, *cmdv);
4350 default:
4351 break;
4353 D_blankerpid = pid;
4354 evenq(&D_blankerev);
4355 D_blocked = 4;
4356 ClearAll();
4359 #endif
4361 struct layout *layouts;
4362 struct layout *laytab[MAXLAY];
4363 struct layout *layout_last, layout_last_marker;
4364 struct layout *layout_attach = &layout_last_marker;
4366 void
4367 FreeLayoutCv(cv)
4368 struct canvas *cv;
4370 struct canvas *cnext, *c = cv;
4371 for (; cv; cv = cnext)
4373 if (cv->c_slperp)
4375 FreeLayoutCv(cv->c_slperp);
4376 free(cv->c_slperp);
4377 cv->c_slperp = 0;
4379 cnext = cv->c_slnext;
4380 cv->c_slnext = 0;
4381 if (cv != c)
4382 free(cv);
4386 static void
4387 DupLayoutCv(cvf, cvt, save)
4388 struct canvas *cvf, *cvt;
4389 int save;
4391 while(cvf)
4393 cvt->c_slorient = cvf->c_slorient;
4394 cvt->c_slweight = cvf->c_slweight;
4395 if (cvf == D_forecv)
4396 D_forecv = cvt;
4397 if (!save)
4399 cvt->c_display = display;
4400 if (!cvf->c_slperp)
4402 cvt->c_captev.type = EV_TIMEOUT;
4403 cvt->c_captev.data = (char *)cvt;
4404 cvt->c_captev.handler = cv_winid_fn;
4405 cvt->c_blank.l_cvlist = 0;
4406 cvt->c_blank.l_layfn = &BlankLf;
4407 cvt->c_blank.l_bottom = &cvt->c_blank;
4409 cvt->c_layer = cvf->c_layer;
4411 else
4413 struct win *p = cvf->c_layer ? Layer2Window(cvf->c_layer) : 0;
4414 cvt->c_layer = p ? &p->w_layer : 0;
4416 if (cvf->c_slperp)
4418 cvt->c_slperp = (struct canvas *)calloc(1, sizeof(struct canvas));
4419 cvt->c_slperp->c_slback = cvt;
4420 DupLayoutCv(cvf->c_slperp, cvt->c_slperp, save);
4422 if (cvf->c_slnext)
4424 cvt->c_slnext = (struct canvas *)calloc(1, sizeof(struct canvas));
4425 cvt->c_slnext->c_slprev = cvt;
4426 cvt->c_slnext->c_slback = cvt->c_slback;
4428 cvf = cvf->c_slnext;
4429 cvt = cvt->c_slnext;
4433 void
4434 PutWindowCv(cv)
4435 struct canvas *cv;
4437 struct win *p;
4438 for (; cv; cv = cv->c_slnext)
4440 if (cv->c_slperp)
4442 PutWindowCv(cv->c_slperp);
4443 continue;
4445 p = cv->c_layer ? (struct win *)cv->c_layer->l_data : 0;
4446 cv->c_layer = 0;
4447 SetCanvasWindow(cv, p);
4451 struct layout *
4452 CreateLayout(title, startat)
4453 char *title;
4454 int startat;
4456 struct layout *lay;
4457 int i;
4459 if (startat >= MAXLAY || startat < 0)
4460 startat = 0;
4461 for (i = startat; ;)
4463 if (!laytab[i])
4464 break;
4465 if (++i == MAXLAY)
4466 i = 0;
4467 if (i == startat)
4469 Msg(0, "No more layouts\n");
4470 return 0;
4473 lay = (struct layout *)calloc(1, sizeof(*lay));
4474 lay->lay_title = SaveStr(title);
4475 lay->lay_autosave = 1;
4476 lay->lay_number = i;
4477 laytab[i] = lay;
4478 lay->lay_next = layouts;
4479 layouts = lay;
4480 return lay;
4483 void
4484 SaveLayout(name, cv)
4485 char *name;
4486 struct canvas *cv;
4488 struct layout *lay;
4489 struct canvas *fcv;
4490 for (lay = layouts; lay; lay = lay->lay_next)
4491 if (!strcmp(lay->lay_title, name))
4492 break;
4493 if (lay)
4494 FreeLayoutCv(&lay->lay_canvas);
4495 else
4496 lay = CreateLayout(name, 0);
4497 if (!lay)
4498 return;
4499 fcv = D_forecv;
4500 DupLayoutCv(cv, &lay->lay_canvas, 1);
4501 lay->lay_forecv = D_forecv;
4502 D_forecv = fcv;
4503 D_layout = lay;
4506 void
4507 AutosaveLayout(lay)
4508 struct layout *lay;
4510 struct canvas *fcv;
4511 if (!lay || !lay->lay_autosave)
4512 return;
4513 FreeLayoutCv(&lay->lay_canvas);
4514 fcv = D_forecv;
4515 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4516 lay->lay_forecv = D_forecv;
4517 D_forecv = fcv;
4520 struct layout *
4521 FindLayout(name)
4522 char *name;
4524 struct layout *lay;
4525 char *s;
4526 int i;
4527 for (i = 0, s = name; *s >= '0' && *s <= '9'; s++)
4528 i = i * 10 + (*s - '0');
4529 if (!*s && s != name && i >= 0 && i < MAXLAY)
4530 return laytab[i];
4531 for (lay = layouts; lay; lay = lay->lay_next)
4532 if (!strcmp(lay->lay_title, name))
4533 break;
4534 return lay;
4537 void
4538 LoadLayout(lay, cv)
4539 struct layout *lay;
4540 struct canvas *cv;
4542 AutosaveLayout(D_layout);
4543 if (!lay)
4545 while (D_canvas.c_slperp)
4546 FreeCanvas(D_canvas.c_slperp);
4547 MakeDefaultCanvas();
4548 SetCanvasWindow(D_forecv, 0);
4549 D_layout = 0;
4550 return;
4552 while (D_canvas.c_slperp)
4553 FreeCanvas(D_canvas.c_slperp);
4554 D_cvlist = 0;
4555 D_forecv = lay->lay_forecv;
4556 DupLayoutCv(&lay->lay_canvas, &D_canvas, 0);
4557 D_canvas.c_ye = D_height - 1 - ((D_canvas.c_slperp && D_canvas.c_slperp->c_slnext) || captionalways) - (D_has_hstatus == HSTATUS_LASTLINE);
4558 ResizeCanvas(&D_canvas);
4559 RecreateCanvasChain();
4560 RethinkDisplayViewports();
4561 PutWindowCv(&D_canvas);
4562 ResizeLayersToCanvases();
4563 D_layout = lay;
4566 void
4567 NewLayout(title, startat)
4568 char *title;
4569 int startat;
4571 struct layout *lay;
4572 struct canvas *fcv;
4574 lay = CreateLayout(title, startat);
4575 if (!lay)
4576 return;
4577 LoadLayout(0, &D_canvas);
4578 fcv = D_forecv;
4579 DupLayoutCv(&D_canvas, &lay->lay_canvas, 1);
4580 lay->lay_forecv = D_forecv;
4581 D_forecv = fcv;
4582 D_layout = lay;
4583 lay->lay_autosave = 1;
4586 static char *
4587 AddLayoutsInfo(buf, len, where)
4588 char *buf;
4589 int len;
4590 int where;
4592 char *s, *ss, *t;
4593 struct layout *p, **pp;
4594 int l;
4596 s = ss = buf;
4597 for (pp = laytab; pp < laytab + MAXLAY; pp++)
4599 if (pp - laytab == where && ss == buf)
4600 ss = s;
4601 if ((p = *pp) == 0)
4602 continue;
4603 t = p->lay_title;
4604 l = strlen(t);
4605 if (l > 20)
4606 l = 20;
4607 if (s - buf + l > len - 24)
4608 break;
4609 if (s > buf)
4611 *s++ = ' ';
4612 *s++ = ' ';
4614 sprintf(s, "%d", p->lay_number);
4615 if (p->lay_number == where)
4616 ss = s;
4617 s += strlen(s);
4618 if (display && p == D_layout)
4619 *s++ = '*';
4620 *s++ = ' ';
4621 strncpy(s, t, l);
4622 s += l;
4624 *s = 0;
4625 return ss;
4628 void
4629 ShowLayouts(where)
4630 int where;
4632 char buf[1024];
4633 char *s, *ss;
4635 if (!display)
4636 return;
4637 if (!layouts)
4639 Msg(0, "No layouts defined\n");
4640 return;
4642 if (where == -1 && D_layout)
4643 where = D_layout->lay_number;
4644 ss = AddLayoutsInfo(buf, sizeof(buf), where);
4645 s = buf + strlen(buf);
4646 if (ss - buf > D_width / 2)
4648 ss -= D_width / 2;
4649 if (s - ss < D_width)
4651 ss = s - D_width;
4652 if (ss < buf)
4653 ss = buf;
4656 else
4657 ss = buf;
4658 Msg(0, "%s", ss);